Add switch rumble and motion feedbacks

This commit is contained in:
h0neybadger 2021-01-11 20:03:28 +01:00
commit acf15480f2
7 changed files with 255 additions and 100 deletions

View file

@ -69,12 +69,6 @@ class PSRemotePlay : public brls::View
// to send gamepad inputs // to send gamepad inputs
Host *host; Host *host;
brls::Label *label; brls::Label *label;
ChiakiControllerState state = {0};
// FPS calculation
// double base_time;
// int frame_counter = 0;
// int fps = 0;
public: public:
PSRemotePlay(Host *host); PSRemotePlay(Host *host);
~PSRemotePlay(); ~PSRemotePlay();

View file

@ -54,7 +54,9 @@ class Host
std::function<void()> chiaki_regist_event_type_finished_success = nullptr; std::function<void()> chiaki_regist_event_type_finished_success = nullptr;
std::function<void()> chiaki_event_connected_cb = nullptr; std::function<void()> chiaki_event_connected_cb = nullptr;
std::function<void(bool)> chiaki_even_login_pin_request_cb = nullptr; std::function<void(bool)> chiaki_even_login_pin_request_cb = nullptr;
std::function<void(uint8_t, uint8_t)> chiaki_event_rumble_cb = nullptr;
std::function<void(ChiakiQuitEvent *)> chiaki_event_quit_cb = nullptr; std::function<void(ChiakiQuitEvent *)> chiaki_event_quit_cb = nullptr;
std::function<void(ChiakiControllerState *)> io_read_controller_cb = nullptr;
// internal state // internal state
bool discovered = false; bool discovered = false;
@ -73,6 +75,7 @@ class Host
std::string server_nickname; std::string server_nickname;
ChiakiTarget target = CHIAKI_TARGET_PS4_UNKNOWN; ChiakiTarget target = CHIAKI_TARGET_PS4_UNKNOWN;
ChiakiDiscoveryHostState state = CHIAKI_DISCOVERY_HOST_STATE_UNKNOWN; ChiakiDiscoveryHostState state = CHIAKI_DISCOVERY_HOST_STATE_UNKNOWN;
ChiakiControllerState controller_state = {0};
// mac address = 48 bits // mac address = 48 bits
uint8_t server_mac[6] = {0}; uint8_t server_mac[6] = {0};
@ -96,7 +99,7 @@ class Host
int FiniSession(); int FiniSession();
void StopSession(); void StopSession();
void StartSession(); void StartSession();
void SendFeedbackState(ChiakiControllerState *); void SendFeedbackState();
void RegistCB(ChiakiRegistEvent *); void RegistCB(ChiakiRegistEvent *);
void ConnectionEventCB(ChiakiEvent *); void ConnectionEventCB(ChiakiEvent *);
bool GetVideoResolution(int *ret_width, int *ret_height); bool GetVideoResolution(int *ret_width, int *ret_height);
@ -110,7 +113,9 @@ class Host
void SetRegistEventTypeFinishedSuccess(std::function<void()> chiaki_regist_event_type_finished_success); void SetRegistEventTypeFinishedSuccess(std::function<void()> chiaki_regist_event_type_finished_success);
void SetEventConnectedCallback(std::function<void()> chiaki_event_connected_cb); void SetEventConnectedCallback(std::function<void()> chiaki_event_connected_cb);
void SetEventLoginPinRequestCallback(std::function<void(bool)> chiaki_even_login_pin_request_cb); void SetEventLoginPinRequestCallback(std::function<void(bool)> chiaki_even_login_pin_request_cb);
void SetEventRumbleCallback(std::function<void(uint8_t, uint8_t)> chiaki_event_rumble_cb);
void SetEventQuitCallback(std::function<void(ChiakiQuitEvent *)> chiaki_event_quit_cb); void SetEventQuitCallback(std::function<void(ChiakiQuitEvent *)> chiaki_event_quit_cb);
void SetReadControllerCallback(std::function<void(ChiakiControllerState *)> io_read_controller_cb);
bool IsRegistered(); bool IsRegistered();
bool IsDiscovered(); bool IsDiscovered();
bool IsReady(); bool IsReady();

View file

@ -28,6 +28,12 @@ Omit khrplatform: False
Reproducible: False Reproducible: False
*/ */
#ifdef __SWITCH__
#include <switch.h>
#else
#include <iostream>
#endif
#include <mutex> #include <mutex>
extern "C" extern "C"
{ {
@ -65,6 +71,11 @@ class IO
SDL_AudioDeviceID sdl_audio_device_id = 0; SDL_AudioDeviceID sdl_audio_device_id = 0;
SDL_Event sdl_event; SDL_Event sdl_event;
SDL_Joystick *sdl_joystick_ptr[SDL_JOYSTICK_COUNT] = {0}; SDL_Joystick *sdl_joystick_ptr[SDL_JOYSTICK_COUNT] = {0};
#ifdef __SWITCH__
PadState pad;
HidSixAxisSensorHandle sixaxis_handles[4];
HidVibrationDeviceHandle vibration_handles[2][2];
#endif
GLuint vao; GLuint vao;
GLuint vbo; GLuint vbo;
GLuint tex[PLANES_COUNT]; GLuint tex[PLANES_COUNT];
@ -86,7 +97,7 @@ class IO
void SetOpenGlYUVPixels(AVFrame *frame); void SetOpenGlYUVPixels(AVFrame *frame);
bool ReadGameKeys(SDL_Event *event, ChiakiControllerState *state); bool ReadGameKeys(SDL_Event *event, ChiakiControllerState *state);
bool ReadGameTouchScreen(ChiakiControllerState *state); bool ReadGameTouchScreen(ChiakiControllerState *state);
bool ReadGameSixAxis(ChiakiControllerState *state);
public: public:
// singleton configuration // singleton configuration
IO(const IO&) = delete; IO(const IO&) = delete;
@ -100,9 +111,11 @@ class IO
void AudioCB(int16_t *buf, size_t samples_count); void AudioCB(int16_t *buf, size_t samples_count);
bool InitVideo(int video_width, int video_height, int screen_width, int screen_height); bool InitVideo(int video_width, int video_height, int screen_width, int screen_height);
bool FreeVideo(); bool FreeVideo();
bool InitJoystick(); bool InitController();
bool FreeJoystick(); bool FreeController();
bool MainLoop(ChiakiControllerState *state); bool MainLoop();
void UpdateControllerState(ChiakiControllerState *state);
void SetRumble(uint8_t left, uint8_t right);
}; };
#endif //CHIAKI_IO_H #endif //CHIAKI_IO_H

View file

@ -42,6 +42,9 @@ HostInterface::HostInterface(Host *host)
// when the host is connected // when the host is connected
this->host->SetEventConnectedCallback(std::bind(&HostInterface::Stream, this)); this->host->SetEventConnectedCallback(std::bind(&HostInterface::Stream, this));
this->host->SetEventQuitCallback(std::bind(&HostInterface::CloseStream, this, std::placeholders::_1)); this->host->SetEventQuitCallback(std::bind(&HostInterface::CloseStream, this, std::placeholders::_1));
// allow host to update controller state
this->host->SetEventRumbleCallback(std::bind(&IO::SetRumble, this->io, std::placeholders::_1, std::placeholders::_2));
this->host->SetReadControllerCallback(std::bind(&IO::UpdateControllerState, this->io, std::placeholders::_1));
} }
HostInterface::~HostInterface() HostInterface::~HostInterface()
@ -245,7 +248,7 @@ MainApplication::MainApplication(DiscoveryManager *discoverymanager)
MainApplication::~MainApplication() MainApplication::~MainApplication()
{ {
this->discoverymanager->SetService(false); this->discoverymanager->SetService(false);
//this->io->FreeJoystick(); this->io->FreeController();
this->io->FreeVideo(); this->io->FreeVideo();
} }
@ -264,16 +267,15 @@ bool MainApplication::Load()
// init chiaki gl after borealis // init chiaki gl after borealis
// let borealis manage the main screen/window // let borealis manage the main screen/window
if(!io->InitVideo(0, 0, SCREEN_W, SCREEN_H)) if(!io->InitVideo(0, 0, SCREEN_W, SCREEN_H))
{ {
brls::Logger::error("Failed to initiate Video"); brls::Logger::error("Failed to initiate Video");
} }
brls::Logger::info("Load sdl joysticks"); brls::Logger::info("Load sdl/hid controller");
if(!io->InitJoystick()) if(!io->InitController())
{ {
brls::Logger::error("Faled to initiate Joysticks"); brls::Logger::error("Faled to initiate Controller");
} }
// Create a view // Create a view
@ -541,38 +543,12 @@ PSRemotePlay::PSRemotePlay(Host *host)
: host(host) : host(host)
{ {
this->io = IO::GetInstance(); this->io = IO::GetInstance();
// store joycon/touchpad keys
for(int x = 0; x < CHIAKI_CONTROLLER_TOUCHES_MAX; x++)
// start touchpad as "untouched"
this->state.touches[x].id = -1;
// this->base_time=glfwGetTime();
} }
void PSRemotePlay::draw(NVGcontext *vg, int x, int y, unsigned width, unsigned height, brls::Style *style, brls::FrameContext *ctx) void PSRemotePlay::draw(NVGcontext *vg, int x, int y, unsigned width, unsigned height, brls::Style *style, brls::FrameContext *ctx)
{ {
this->io->MainLoop(&this->state); this->io->MainLoop();
this->host->SendFeedbackState(&this->state); this->host->SendFeedbackState();
// FPS calculation
// this->frame_counter += 1;
// double frame_time = glfwGetTime();
// if((frame_time - base_time) >= 1.0)
// {
// base_time += 1;
// //printf("FPS: %d\n", this->frame_counter);
// this->fps = this->frame_counter;
// this->frame_counter = 0;
// }
// nvgBeginPath(vg);
// nvgFillColor(vg, nvgRGBA(255,192,0,255));
// nvgFontFaceId(vg, ctx->fontStash->regular);
// nvgFontSize(vg, style->Label.smallFontSize);
// nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
// char fps_str[9] = {0};
// sprintf(fps_str, "FPS: %000d", this->fps);
// nvgText(vg, 5,10, fps_str, NULL);
} }
PSRemotePlay::~PSRemotePlay() PSRemotePlay::~PSRemotePlay()

View file

@ -156,9 +156,17 @@ int Host::InitSession(IO *user)
// audio setting_cb and frame_cb // audio setting_cb and frame_cb
chiaki_opus_decoder_set_cb(&this->opus_decoder, InitAudioCB, AudioCB, user); chiaki_opus_decoder_set_cb(&this->opus_decoder, InitAudioCB, AudioCB, user);
chiaki_opus_decoder_get_sink(&this->opus_decoder, &audio_sink); chiaki_opus_decoder_get_sink(&this->opus_decoder, &audio_sink);
chiaki_session_set_audio_sink(&(this->session), &audio_sink); chiaki_session_set_audio_sink(&this->session, &audio_sink);
chiaki_session_set_video_sample_cb(&(this->session), VideoCB, user); chiaki_session_set_video_sample_cb(&this->session, VideoCB, user);
chiaki_session_set_event_cb(&(this->session), EventCB, this); chiaki_session_set_event_cb(&this->session, EventCB, this);
// init controller states
chiaki_controller_state_set_idle(&this->controller_state);
for(int x = 0; x < CHIAKI_CONTROLLER_TOUCHES_MAX; x++)
// start touchpad as "untouched"
this->controller_state.touches[x].id = -1;
return 0; return 0;
} }
@ -189,10 +197,13 @@ void Host::StartSession()
} }
} }
void Host::SendFeedbackState(ChiakiControllerState *state) void Host::SendFeedbackState()
{ {
// send controller/joystick key // send controller/joystick key
chiaki_session_set_controller_state(&this->session, state); if(this->io_read_controller_cb != nullptr)
this->io_read_controller_cb(&this->controller_state);
chiaki_session_set_controller_state(&this->session, &this->controller_state);
} }
void Host::ConnectionEventCB(ChiakiEvent *event) void Host::ConnectionEventCB(ChiakiEvent *event)
@ -209,6 +220,11 @@ void Host::ConnectionEventCB(ChiakiEvent *event)
if(this->chiaki_even_login_pin_request_cb != nullptr) if(this->chiaki_even_login_pin_request_cb != nullptr)
this->chiaki_even_login_pin_request_cb(event->login_pin_request.pin_incorrect); this->chiaki_even_login_pin_request_cb(event->login_pin_request.pin_incorrect);
break; break;
case CHIAKI_EVENT_RUMBLE:
CHIAKI_LOGD(this->log, "EventCB CHIAKI_EVENT_RUMBLE");
if(this->chiaki_event_rumble_cb != nullptr)
this->chiaki_event_rumble_cb(event->rumble.left, event->rumble.right);
break;
case CHIAKI_EVENT_QUIT: case CHIAKI_EVENT_QUIT:
CHIAKI_LOGI(this->log, "EventCB CHIAKI_EVENT_QUIT"); CHIAKI_LOGI(this->log, "EventCB CHIAKI_EVENT_QUIT");
if(this->chiaki_event_quit_cb != nullptr) if(this->chiaki_event_quit_cb != nullptr)
@ -352,6 +368,16 @@ void Host::SetEventQuitCallback(std::function<void(ChiakiQuitEvent *)> chiaki_ev
this->chiaki_event_quit_cb = chiaki_event_quit_cb; this->chiaki_event_quit_cb = chiaki_event_quit_cb;
} }
void Host::SetEventRumbleCallback(std::function<void(uint8_t, uint8_t)> chiaki_event_rumble_cb)
{
this->chiaki_event_rumble_cb = chiaki_event_rumble_cb;
}
void Host::SetReadControllerCallback(std::function<void(ChiakiControllerState *)> io_read_controller_cb)
{
this->io_read_controller_cb = io_read_controller_cb;
}
bool Host::IsRegistered() bool Host::IsRegistered()
{ {
return this->registered; return this->registered;

View file

@ -1,11 +1,5 @@
// SPDX-License-Identifier: LicenseRef-AGPL-3.0-only-OpenSSL // SPDX-License-Identifier: LicenseRef-AGPL-3.0-only-OpenSSL
#ifdef __SWITCH__
#include <switch.h>
#else
#include <iostream>
#endif
#include "io.h" #include "io.h"
#include "settings.h" #include "settings.h"
@ -345,22 +339,23 @@ bool IO::FreeVideo()
return ret; return ret;
} }
bool IO::ReadGameTouchScreen(ChiakiControllerState *state) bool IO::ReadGameTouchScreen(ChiakiControllerState *chiaki_state)
{ {
#ifdef __SWITCH__ #ifdef __SWITCH__
hidScanInput(); HidTouchScreenState sw_state = {0};
int touch_count = hidTouchCount();
bool ret = false; bool ret = false;
if(!touch_count) if(!hidGetTouchScreenStates(&sw_state, 1) || sw_state.count == 0)
{ {
// flush state
chiaki_state->buttons &= ~CHIAKI_CONTROLLER_BUTTON_TOUCHPAD; // touchscreen release
for(int i = 0; i < CHIAKI_CONTROLLER_TOUCHES_MAX; i++) for(int i = 0; i < CHIAKI_CONTROLLER_TOUCHES_MAX; i++)
{ {
if(state->touches[i].id != -1) if(chiaki_state->touches[i].id != -1)
{ {
state->touches[i].x = 0; chiaki_state->touches[i].x = 0;
state->touches[i].y = 0; chiaki_state->touches[i].y = 0;
state->touches[i].id = -1; chiaki_state->touches[i].id = -1;
state->buttons &= ~CHIAKI_CONTROLLER_BUTTON_TOUCHPAD; // touchscreen release
// the state changed // the state changed
ret = true; ret = true;
} }
@ -368,32 +363,25 @@ bool IO::ReadGameTouchScreen(ChiakiControllerState *state)
return ret; return ret;
} }
touchPosition touch; // scale switch screen to the PS trackpad
for(int i = 0; i < touch_count && i < CHIAKI_CONTROLLER_TOUCHES_MAX; i++) for(int i = 0; i < sw_state.count && i < CHIAKI_CONTROLLER_TOUCHES_MAX; i++)
{ {
hidTouchRead(&touch, i);
// 1280×720 px (16:9) // 1280×720 px (16:9)
// ps4 controller aspect ratio looks closer to 29:10 // ps4 controller aspect ratio looks closer to 29:10
uint16_t x = touch.px * (DS4_TRACKPAD_MAX_X / SWITCH_TOUCHSCREEN_MAX_X); uint16_t x = sw_state.touches[i].x * (DS4_TRACKPAD_MAX_X / SWITCH_TOUCHSCREEN_MAX_X);
uint16_t y = touch.py * (DS4_TRACKPAD_MAX_Y / SWITCH_TOUCHSCREEN_MAX_Y); uint16_t y = sw_state.touches[i].y * (DS4_TRACKPAD_MAX_Y / SWITCH_TOUCHSCREEN_MAX_Y);
// use nintendo switch border's 5% to // use nintendo switch border's 5% to
if(x <= (SWITCH_TOUCHSCREEN_MAX_X * 0.05) || x >= (SWITCH_TOUCHSCREEN_MAX_X * 0.95) || y <= (SWITCH_TOUCHSCREEN_MAX_Y * 0.05) || y >= (SWITCH_TOUCHSCREEN_MAX_Y * 0.95)) if(x <= (SWITCH_TOUCHSCREEN_MAX_X * 0.05) || x >= (SWITCH_TOUCHSCREEN_MAX_X * 0.95) || y <= (SWITCH_TOUCHSCREEN_MAX_Y * 0.05) || y >= (SWITCH_TOUCHSCREEN_MAX_Y * 0.95))
{ chiaki_state->buttons |= CHIAKI_CONTROLLER_BUTTON_TOUCHPAD; // touchscreen
state->buttons |= CHIAKI_CONTROLLER_BUTTON_TOUCHPAD; // touchscreen
// printf("CHIAKI_CONTROLLER_BUTTON_TOUCHPAD\n");
}
else else
{ chiaki_state->buttons &= ~CHIAKI_CONTROLLER_BUTTON_TOUCHPAD; // touchscreen release
state->buttons &= ~CHIAKI_CONTROLLER_BUTTON_TOUCHPAD; // touchscreen release
}
state->touches[i].x = x; chiaki_state->touches[i].x = x;
state->touches[i].y = y; chiaki_state->touches[i].y = y;
state->touches[i].id = i; chiaki_state->touches[i].id = i;
// printf("[point_id=%d] px=%03d, py=%03d, dx=%03d, dy=%03d, angle=%03d\n", // printf("[point_id=%d] x=%03d, y=%03d\n", i, x, y);
// i, touch.px, touch.py, touch.dx, touch.dy, touch.angle);
ret = true; ret = true;
} }
return ret; return ret;
@ -402,14 +390,127 @@ bool IO::ReadGameTouchScreen(ChiakiControllerState *state)
#endif #endif
} }
void IO::SetRumble(uint8_t left, uint8_t right)
{
#ifdef __SWITCH__
Result rc = 0;
HidVibrationValue vibration_values[] = {
{
.amp_low = 0.0f,
.freq_low = 160.0f,
.amp_high = 0.0f,
.freq_high = 320.0f,
},
{
.amp_low = 0.0f,
.freq_low = 160.0f,
.amp_high = 0.0f,
.freq_high = 320.0f,
}};
int target_device = padIsHandheld(&pad) ? 0 : 1;
if(left > 0)
{
// SDL_HapticRumblePlay(this->sdl_haptic_ptr[0], left / 100, 5000);
vibration_values[0].amp_low = (float)left / (float)100;
vibration_values[0].amp_high = (float)left / (float)100;
vibration_values[0].freq_low *= (float)left / (float)100;
vibration_values[0].freq_high *= (float)left / (float)100;
}
if(right > 0)
{
// SDL_HapticRumblePlay(this->sdl_haptic_ptr[1], right / 100, 5000);
vibration_values[1].amp_low = (float)right / (float)100;
vibration_values[1].amp_high = (float)right / (float)100;
vibration_values[1].freq_low *= (float)left / (float)100;
vibration_values[1].freq_high *= (float)left / (float)100;
}
// printf("left ptr %p amp_low %f amp_high %f freq_low %f freq_high %f\n",
// &vibration_values[0],
// vibration_values[0].amp_low,
// vibration_values[0].amp_high,
// vibration_values[0].freq_low,
// vibration_values[0].freq_high);
// printf("right ptr %p amp_low %f amp_high %f freq_low %f freq_high %f\n",
// &vibration_values[1],
// vibration_values[1].amp_low,
// vibration_values[1].amp_high,
// vibration_values[1].freq_low,
// vibration_values[1].freq_high);
rc = hidSendVibrationValues(this->vibration_handles[target_device], vibration_values, 2);
if(R_FAILED(rc))
CHIAKI_LOGE(this->log, "hidSendVibrationValues() returned: 0x%x", rc);
#endif
}
bool IO::ReadGameSixAxis(ChiakiControllerState *state)
{
#ifdef __SWITCH__
// Read from the correct sixaxis handle depending on the current input style
HidSixAxisSensorState sixaxis = {0};
uint64_t style_set = padGetStyleSet(&pad);
if(style_set & HidNpadStyleTag_NpadHandheld)
hidGetSixAxisSensorStates(this->sixaxis_handles[0], &sixaxis, 1);
else if(style_set & HidNpadStyleTag_NpadFullKey)
hidGetSixAxisSensorStates(this->sixaxis_handles[1], &sixaxis, 1);
else if(style_set & HidNpadStyleTag_NpadJoyDual)
{
// For JoyDual, read from either the Left or Right Joy-Con depending on which is/are connected
u64 attrib = padGetAttributes(&pad);
if(attrib & HidNpadAttribute_IsLeftConnected)
hidGetSixAxisSensorStates(this->sixaxis_handles[2], &sixaxis, 1);
else if(attrib & HidNpadAttribute_IsRightConnected)
hidGetSixAxisSensorStates(this->sixaxis_handles[3], &sixaxis, 1);
}
// printf("Acceleration: x=% .4f, y=% .4f, z=% .4f\n", sixaxis.acceleration.x, sixaxis.acceleration.y, sixaxis.acceleration.z);
// printf("Angular velocity: x=% .4f, y=% .4f, z=% .4f\n", sixaxis.angular_velocity.x, sixaxis.angular_velocity.y, sixaxis.angular_velocity.z);
// printf("Angle: x=% .4f, y=% .4f, z=% .4f\n", sixaxis.angle.x, sixaxis.angle.y, sixaxis.angle.z);
// printf("Direction matrix:\n"
// " [ % .4f, % .4f, % .4f ]\n"
// " [ % .4f, % .4f, % .4f ]\n"
// " [ % .4f, % .4f, % .4f ]\n",
// sixaxis.direction.direction[0][0], sixaxis.direction.direction[1][0], sixaxis.direction.direction[2][0],
// sixaxis.direction.direction[0][1], sixaxis.direction.direction[1][1], sixaxis.direction.direction[2][1],
// sixaxis.direction.direction[0][2], sixaxis.direction.direction[1][2], sixaxis.direction.direction[2][2]);
state->gyro_x = sixaxis.angular_velocity.x;
state->gyro_y = sixaxis.angular_velocity.y;
state->gyro_z = sixaxis.angular_velocity.z;
state->accel_x = sixaxis.acceleration.x;
state->accel_y = sixaxis.acceleration.y;
state->accel_z = sixaxis.acceleration.z;
// thank you @thestr4ng3r for the hint
// https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles#Euler_angles_to_quaternion_conversion
double cy = cos(sixaxis.angle.z * 0.5);
double sy = sin(sixaxis.angle.z * 0.5);
double cp = cos(sixaxis.angle.y * 0.5);
double sp = sin(sixaxis.angle.y * 0.5);
double cr = cos(sixaxis.angle.x * 0.5);
double sr = sin(sixaxis.angle.x * 0.5);
state->orient_x = sr * cp * cy - cr * sp * sy;
state->orient_y = cr * sp * cy + sr * cp * sy;
state->orient_z = cr * cp * sy - sr * sp * cy;
state->orient_w = cr * cp * cy + sr * sp * sy;
return true;
#else
return false;
#endif
}
bool IO::ReadGameKeys(SDL_Event *event, ChiakiControllerState *state) bool IO::ReadGameKeys(SDL_Event *event, ChiakiControllerState *state)
{ {
// return true if an event changed (gamepad input) // return true if an event changed (gamepad input)
// TODO // TODO
// share vs PS button // share vs PS button
// Gyro ?
// rumble ?
bool ret = true; bool ret = true;
switch(event->type) switch(event->type)
{ {
@ -620,7 +721,7 @@ bool IO::InitOpenGlTextures()
D(glGenTextures(PLANES_COUNT, this->tex)); D(glGenTextures(PLANES_COUNT, this->tex));
D(glGenBuffers(PLANES_COUNT, this->pbo)); D(glGenBuffers(PLANES_COUNT, this->pbo));
uint8_t uv_default[] = { 0x7f, 0x7f }; uint8_t uv_default[] = {0x7f, 0x7f};
for(int i = 0; i < PLANES_COUNT; i++) for(int i = 0; i < PLANES_COUNT; i++)
{ {
D(glBindTexture(GL_TEXTURE_2D, this->tex[i])); D(glBindTexture(GL_TEXTURE_2D, this->tex[i]));
@ -633,7 +734,7 @@ bool IO::InitOpenGlTextures()
D(glUseProgram(this->prog)); D(glUseProgram(this->prog));
// bind only as many planes as we need // bind only as many planes as we need
const char *plane_names[] = { "plane1", "plane2", "plane3" }; const char *plane_names[] = {"plane1", "plane2", "plane3"};
for(int i = 0; i < PLANES_COUNT; i++) for(int i = 0; i < PLANES_COUNT; i++)
D(glUniform1i(glGetUniformLocation(this->prog, plane_names[i]), i)); D(glUniform1i(glGetUniformLocation(this->prog, plane_names[i]), i));
@ -786,7 +887,7 @@ inline void IO::OpenGlDraw()
D(glFinish()); D(glFinish());
} }
bool IO::InitJoystick() bool IO::InitController()
{ {
// https://github.com/switchbrew/switch-examples/blob/master/graphics/sdl2/sdl2-simple/source/main.cpp#L57 // https://github.com/switchbrew/switch-examples/blob/master/graphics/sdl2/sdl2-simple/source/main.cpp#L57
// open CONTROLLER_PLAYER_1 and CONTROLLER_PLAYER_2 // open CONTROLLER_PLAYER_1 and CONTROLLER_PLAYER_2
@ -800,24 +901,64 @@ bool IO::InitJoystick()
CHIAKI_LOGE(this->log, "SDL_JoystickOpen: %s\n", SDL_GetError()); CHIAKI_LOGE(this->log, "SDL_JoystickOpen: %s\n", SDL_GetError());
return false; return false;
} }
// this->sdl_haptic_ptr[i] = SDL_HapticOpenFromJoystick(sdl_joystick_ptr[i]);
// SDL_HapticRumbleInit(this->sdl_haptic_ptr[i]);
// if(sdl_haptic_ptr[i] == nullptr)
// {
// CHIAKI_LOGE(this->log, "SDL_HapticRumbleInit: %s\n", SDL_GetError());
// }
} }
#ifdef __SWITCH__
Result rc = 0;
// Configure our supported input layout: a single player with standard controller styles
padConfigureInput(1, HidNpadStyleSet_NpadStandard);
// Initialize the default gamepad (which reads handheld mode inputs as well as the first connected controller)
padInitializeDefault(&this->pad);
// touchpad
hidInitializeTouchScreen();
// It's necessary to initialize these separately as they all have different handle values
hidGetSixAxisSensorHandles(&this->sixaxis_handles[0], 1, HidNpadIdType_Handheld, HidNpadStyleTag_NpadHandheld);
hidGetSixAxisSensorHandles(&this->sixaxis_handles[1], 1, HidNpadIdType_No1, HidNpadStyleTag_NpadFullKey);
hidGetSixAxisSensorHandles(&this->sixaxis_handles[2], 2, HidNpadIdType_No1, HidNpadStyleTag_NpadJoyDual);
hidStartSixAxisSensor(this->sixaxis_handles[0]);
hidStartSixAxisSensor(this->sixaxis_handles[1]);
hidStartSixAxisSensor(this->sixaxis_handles[2]);
hidStartSixAxisSensor(this->sixaxis_handles[3]);
rc = hidInitializeVibrationDevices(this->vibration_handles[0], 2, HidNpadIdType_Handheld, HidNpadStyleTag_NpadHandheld);
if(R_FAILED(rc))
CHIAKI_LOGE(this->log, "hidInitializeVibrationDevices() HidNpadIdType_Handheld returned: 0x%x", rc);
rc = hidInitializeVibrationDevices(this->vibration_handles[1], 2, HidNpadIdType_No1, HidNpadStyleTag_NpadJoyDual);
if(R_FAILED(rc))
CHIAKI_LOGE(this->log, "hidInitializeVibrationDevices() HidNpadIdType_No1 returned: 0x%x", rc);
#endif
return true; return true;
} }
bool IO::FreeJoystick() bool IO::FreeController()
{ {
for(int i = 0; i < SDL_JOYSTICK_COUNT; i++) for(int i = 0; i < SDL_JOYSTICK_COUNT; i++)
{ {
if(SDL_JoystickGetAttached(sdl_joystick_ptr[i])) SDL_JoystickClose(this->sdl_joystick_ptr[i]);
SDL_JoystickClose(sdl_joystick_ptr[i]); // SDL_HapticClose(this->sdl_haptic_ptr[i]);
} }
#ifdef __SWITCH__
hidStopSixAxisSensor(this->sixaxis_handles[0]);
hidStopSixAxisSensor(this->sixaxis_handles[1]);
hidStopSixAxisSensor(this->sixaxis_handles[2]);
hidStopSixAxisSensor(this->sixaxis_handles[3]);
#endif
return true; return true;
} }
bool IO::MainLoop(ChiakiControllerState *state) void IO::UpdateControllerState(ChiakiControllerState *state)
{ {
D(glUseProgram(this->prog)); #ifdef __SWITCH__
padUpdate(&this->pad);
#endif
// handle SDL events // handle SDL events
while(SDL_PollEvent(&this->sdl_event)) while(SDL_PollEvent(&this->sdl_event))
{ {
@ -825,11 +966,17 @@ bool IO::MainLoop(ChiakiControllerState *state)
switch(this->sdl_event.type) switch(this->sdl_event.type)
{ {
case SDL_QUIT: case SDL_QUIT:
return false; this->quit = true;
} }
} }
ReadGameTouchScreen(state); ReadGameTouchScreen(state);
ReadGameSixAxis(state);
}
bool IO::MainLoop()
{
D(glUseProgram(this->prog));
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

View file

@ -83,12 +83,6 @@ extern "C" void userAppInit()
// load socket custom config // load socket custom config
socketInitialize(&g_chiakiSocketInitConfig); socketInitialize(&g_chiakiSocketInitConfig);
setsysInitialize(); setsysInitialize();
// padConfigureInput(1, HidNpadStyleSet_NpadStandard);
// PadState pad;
// padInitializeDefault(&pad);
//hidInitializeTouchScreen();
} }
extern "C" void userAppExit() extern "C" void userAppExit()
@ -126,7 +120,7 @@ int main(int argc, char *argv[])
return 1; return 1;
} }
CHIAKI_LOGI(log, "Loading SDL audio / joystick"); CHIAKI_LOGI(log, "Loading SDL audio / joystick / haptic");
if(SDL_Init(SDL_INIT_AUDIO | SDL_INIT_JOYSTICK)) if(SDL_Init(SDL_INIT_AUDIO | SDL_INIT_JOYSTICK))
{ {
CHIAKI_LOGE(log, "SDL initialization failed: %s", SDL_GetError()); CHIAKI_LOGE(log, "SDL initialization failed: %s", SDL_GetError());