From d3171f89f393d30ec507cdc0118a770fcbb8937f Mon Sep 17 00:00:00 2001 From: igor725 Date: Sat, 27 Apr 2024 02:22:04 +0300 Subject: [PATCH] Multiple users support --- .vscode/c_cpp_properties.json | 2 +- .vscode/settings.json | 8 + .vscode/tasks.json | 40 ++--- Makefile | 8 +- README.md | 60 +------ input/build.bat | 16 +- input/controller.cpp | 55 +++--- input/controller.h | 4 +- input/main.cpp | 306 +++++++++++++++++++++------------- 9 files changed, 271 insertions(+), 228 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index ec32c44..02d739c 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -4,7 +4,7 @@ "name": "Win32", "includePath": [ "${workspaceFolder}/**", - "C:/OpenOrbis/PS4Toolchain/include/**" + "C:/OpenOrbis/PS4Toolchain/include/**" ], "compilerPath": "clang.exe", "cStandard": "c17", diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..b0d1cdc --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "C_Cpp.formatting": "clangFormat", + "C_Cpp.clang_format_fallbackStyle": "LLVM", + "C_Cpp.default.cppStandard": "c++20", + "C_Cpp.autoAddFileAssociations": false, + "editor.tabSize": 2, + "editor.insertSpaces": true, +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 65641ad..9337153 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,21 +1,23 @@ { - "version": "2.0.0", - "tasks": [ - { - "label": "Build", - "type": "shell", - "command": "build.bat", - "options": { - "cwd": "${workspaceRoot}/input" - }, - "args": [ - "x64\\Debug\\" - ], - "problemMatcher": ["$gcc"], - "group": { - "kind": "build", - "isDefault": true - } - } - ] + "version": "2.0.0", + "tasks": [ + { + "label": "Build", + "type": "shell", + "command": "build.bat", + "options": { + "cwd": "${workspaceRoot}/input" + }, + "args": [ + "x64\\Debug\\" + ], + "problemMatcher": [ + "$gcc" + ], + "group": { + "kind": "build", + "isDefault": true + } + } + ] } diff --git a/Makefile b/Makefile index 14ba1c4..6483b26 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ # Package metadata. -TITLE := OpenOrbis Input Sample -VERSION := 1.02 -TITLE_ID := BREW00084 -CONTENT_ID := IV0000-BREW00084_00-CONTROLREX000000 +TITLE := PS4 Test Input System +VERSION := 1.1 +TITLE_ID := DDRM00001 +CONTENT_ID := IV0000-DDRM00001_00-PS4INPUTSY000000 # Libraries linked into the ELF. LIBS := -lc -lkernel -lc++ -lSceVideoOut -lScePad -lSceUserService diff --git a/README.md b/README.md index d665b3a..9d82dc7 100644 --- a/README.md +++ b/README.md @@ -1,53 +1,13 @@ # PS4 Input -This project contains example code for getting controller input from the DualShock 4 (DS4) controller. If a button or multiple buttons are pushed, they will be highlighted on the screen over the controller graphic. The original project can be found [here](https://github.com/OpenOrbis/OpenOrbis-PS4-Toolchain/tree/master/samples/input). - -- **Title ID**: BREW00084 -- **Content ID**: IV0000-BREW00084_00-CONTROLREX000000 - - -## Directory structure -``` -root -|-- assets - |-- images // Images for drawing in the application - |-- circle.png - |-- controller.png - |-- dpad-down.png - |-- dpad-left.png - |-- dpad-right.png - |-- dpad-up.png - |-- l1.png - |-- l2.png - |-- r1.png - |-- r2.png - |-- square.png - |-- start.png - |-- thumbstick.png - |-- thumbstick_pr.png - |-- touchpad.png - |-- triangle.png - |-- x.png -|-- input - |-- build.bat // Batch file for building on Windows - |-- controller.cpp // Controller class and helper methods - |-- controller.h // Controller class header - |-- main.cpp // main source file -|-- sce_module // Dependency modules for the pkg - |-- libSceFios2.prx - |-- libc.prx -|-- sce_sys // Package materials (metadata) - |-- about - |-- right.prx - |-- icon0.png - |-- param.sfo -|-- eboot.bin // final eboot (not present until built) -|-- Makefile // Make rules for building on Linux -|-- pkg.gp4 // Package project file -``` -The ELF, Orbis ELF (OELF), and object files will all be stored in the intermediate directory `x64/Debug`. The final eboot.bin file will be found in the root directory. - +This application allows you to test your PS4 gamepads (or your input system implementation if you are making an PS4 emulator). It's based on OpenOrbis Input Sample, original project can be found [here](https://github.com/OpenOrbis/OpenOrbis-PS4-Toolchain/tree/master/samples/input). +## New features +- Left and right stick position tracking +- Haptic feedback on `L2`/`R2` trigger press +- Switching the lightbar color by pressing `Triangle` +- Mulitple users support (Press `Options` button on the gamepad to switch to it) +- TouchPad reading ## Libraries used @@ -59,17 +19,14 @@ The ELF, Orbis ELF (OELF), and object files will all be stored in the intermedia - libSceUserService - ## Building -On Linux, a makefile has been included for building. - To build this project, the developer will need clang, which is provided in the toolchain. The `OO_PS4_TOOLCHAIN` environment variable will also need to be set to the root directory of the SDK installation. __Windows__ Run the batch file from command prompt or powershell with the following command: ``` -.\build.bat .\x64\Debug "input" +.\build.bat .\x64\Debug ``` __Linux__ @@ -79,7 +36,6 @@ make ``` - ## Author(s) - Specter diff --git a/input/build.bat b/input/build.bat index 10c55cb..6d2c025 100644 --- a/input/build.bat +++ b/input/build.bat @@ -1,11 +1,11 @@ SETLOCAL EnableDelayedExpansion Rem Package information -set PKG_TITLE="OpenOrbis Input Sample" -set PKG_VERSION="1.02" +set PKG_TITLE="PS4 Test Input System" +set PKG_VERSION="1.1" set PKG_ASSETS="assets" -set PKG_TITLE_ID="BREW00084" -set PKG_CONTENT_ID="IV0000-%PKG_TITLE_ID%_00-CONTROLREX000000" +set PKG_TITLE_ID="DDRM00001" +set PKG_CONTENT_ID="IV0000-%PKG_TITLE_ID%_00-PS4INPUTSY000000" Rem Libraries to link in set libraries=-lc -lkernel -lc++ -lSceVideoOut -lScePad -lSceUserService @@ -26,12 +26,16 @@ set compilerPP=clang++ Rem Compile object files for all the source files for %%f in (*.c) do ( %compiler% --target=x86_64-pc-freebsd12-elf -fPIC -funwind-tables -I"%OO_PS4_TOOLCHAIN%\\include" -I"%OO_PS4_TOOLCHAIN%\\include\\c++\\v1" %extra_flags% -c -o %intdir%\%%~nf.o %%~nf.c - if NOT ERRORLEVEL 0 exit 1 + set failed=1 + if errorlevel 0 if not errorlevel 1 set "failed=" + if defined failed exit 1 ) for %%f in (*.cpp) do ( %compilerPP% --target=x86_64-pc-freebsd12-elf -fPIC -funwind-tables -I"%OO_PS4_TOOLCHAIN%\\include" -I"%OO_PS4_TOOLCHAIN%\\include\\c++\\v1" %extra_flags% -c -o %intdir%\%%~nf.o %%~nf.cpp - if NOT ERRORLEVEL 0 exit 1 + set failed=1 + if errorlevel 0 if not errorlevel 1 set "failed=" + if defined failed exit 1 ) Rem Get a list of object files for linking diff --git a/input/controller.cpp b/input/controller.cpp index 48ce8bf..409d4bb 100644 --- a/input/controller.cpp +++ b/input/controller.cpp @@ -1,17 +1,14 @@ #include "controller.h" #include "log.h" -Controller::Controller() { - this->currPadColor = 0; - this->padColors[0] = {0xff, 0xff, 0xff, 0xff}; - this->padColors[1] = {0x00, 0xff, 0x00, 0xff}; - this->padColors[2] = {0xff, 0x00, 0x00, 0xff}; - this->padColors[3] = {0x00, 0x00, 0xff, 0xff}; - this->padColors[4] = {0xff, 0xff, 0x00, 0xff}; - this->padColors[5] = {0xff, 0x00, 0xff, 0xff}; - this->padColors[6] = {0x00, 0xff, 0xff, 0xff}; - this->padColors[7] = {0xff, 0xff, 0xff, 0xff}; -} +static OrbisPadColor padColors[8] = { + {0xff, 0xff, 0xff, 0xff}, {0x00, 0xff, 0x00, 0xff}, + {0xff, 0x00, 0x00, 0xff}, {0x00, 0x00, 0xff, 0xff}, + {0xff, 0xff, 0x00, 0xff}, {0xff, 0x00, 0xff, 0xff}, + {0x00, 0xff, 0xff, 0xff}, {0xff, 0xff, 0xff, 0xff}, +}; + +Controller::Controller() { this->currPadColor = 0; } Controller::~Controller() {} @@ -22,17 +19,8 @@ bool Controller::Init(int controllerUserID) { return false; } - // Get the user ID - if (controllerUserID < 0) { - OrbisUserServiceInitializeParams param; - param.priority = ORBIS_KERNEL_PRIO_FIFO_LOWEST; - sceUserServiceInitialize(¶m); - sceUserServiceGetInitialUser(&this->userID); - } else { - this->userID = controllerUserID; - } - // Open a handle for the controller + this->userID = controllerUserID; this->pad = scePadOpen(this->userID, 0, 0, NULL); if (this->pad < 0) { @@ -40,7 +28,7 @@ bool Controller::Init(int controllerUserID) { return false; } - scePadSetLightBar(this->pad, &this->padColors[this->currPadColor]); + scePadSetLightBar(this->pad, &padColors[this->currPadColor]); scePadGetControllerInformation(this->pad, &padInfo); if (scePadSetMotionSensorState(this->pad, true) != ORBIS_OK) { @@ -55,13 +43,20 @@ void Controller::setButtonState(int state) { this->buttonState = state; } -bool Controller::CheckButtonsPressed(int stateToCheck) { - scePadReadState(this->pad, &this->padData); - setButtonState(this->padData.buttons); - +void Controller::UpdateTriggersFeedback() { OrbisPadVibeParam pv{.lgMotor = this->padData.analogButtons.r2, .smMotor = this->padData.analogButtons.l2}; scePadSetVibration(this->pad, &pv); +} + +void Controller::ResetTriggersFeedback() { + OrbisPadVibeParam pv{.lgMotor = 0, .smMotor = 0}; + scePadSetVibration(this->pad, &pv); +} + +bool Controller::CheckButtonsPressed(int stateToCheck) { + scePadReadState(this->pad, &this->padData); + setButtonState(this->padData.buttons); if (stateToCheck & ORBIS_PAD_BUTTON_TRIANGLE && !(this->buttonState & ORBIS_PAD_BUTTON_TRIANGLE)) @@ -183,11 +178,13 @@ bool Controller::TouchpadPressed() { return CheckButtonsPressed(ORBIS_PAD_BUTTON_TOUCH_PAD); } +OrbisPadColor Controller::GetColor() { return padColors[this->currPadColor]; } + OrbisPadColor Controller::NextColor() { if (scePadSetLightBar( - this->pad, &this->padColors[this->currPadColor = - (this->currPadColor + 1) % 7]) == 0) - return this->padColors[this->currPadColor]; + this->pad, + &padColors[this->currPadColor = (this->currPadColor + 1) % 7]) == 0) + return padColors[this->currPadColor]; return {0x00, 0x00, 0x00, 0x00}; } diff --git a/input/controller.h b/input/controller.h index cd64ff2..b63fef0 100644 --- a/input/controller.h +++ b/input/controller.h @@ -11,7 +11,6 @@ class Controller { int buttonState; int currPadColor; OrbisPadData padData; - OrbisPadColor padColors[8]; OrbisPadInformation padInfo; void setButtonState(int state); @@ -22,6 +21,8 @@ class Controller { bool Init(int controllerUserID); + void ResetTriggersFeedback(); + void UpdateTriggersFeedback(); bool CheckButtonsPressed(int stateToCheck); bool TrianglePressed(); @@ -45,6 +46,7 @@ class Controller { void ReadSticks(float *leftx, float *lefty, float *rightx, float *righty); void ReadGyro(vec_float4 *data); void ResetOrientation(); + OrbisPadColor GetColor(); OrbisPadColor NextColor(); }; diff --git a/input/main.cpp b/input/main.cpp index 6469b1d..5da4429 100644 --- a/input/main.cpp +++ b/input/main.cpp @@ -42,150 +42,224 @@ static void repaintBar(PNG *png, OrbisPadColor newColor) { prevColor = newColorU32; } -int main(void) { - // No buffering - setvbuf(stdout, NULL, _IONBF, 0); - - // Create a 2D scene - DEBUGLOG << "Creating a scene"; - auto scene = new Scene2D(FRAME_WIDTH, FRAME_HEIGHT, FRAME_DEPTH); - if (!scene->Init(0xC000000, 2)) { - DEBUGLOG << "Failed to initialize 2D scene"; - for (;;) - ; - } - // Create a controller - DEBUGLOG << "Initializing controller"; - auto controller = new Controller(); - if (!controller->Init(-1)) { - DEBUGLOG << "Failed to initialize controller"; - for (;;) - ; - } - - int tpw, tph; - controller->GetTouchPadResolution(&tpw, &tph); - - // Create PNG instances for all the sprites - auto controllerBackground = new PNG("/app0/assets/images/controller.png"); - auto thumbstick_pr = new PNG("/app0/assets/images/thumbstick_pr.png"); - auto thumbstick = new PNG("/app0/assets/images/thumbstick.png"); - auto touchpad = new PNG("/app0/assets/images/touchpad.png"); - auto dpadUp = new PNG("/app0/assets/images/dpad-up.png"); - auto dpadRight = new PNG("/app0/assets/images/dpad-right.png"); - auto dpadDown = new PNG("/app0/assets/images/dpad-down.png"); - auto dpadLeft = new PNG("/app0/assets/images/dpad-left.png"); - auto triangleBtn = new PNG("/app0/assets/images/triangle.png"); - auto circleBtn = new PNG("/app0/assets/images/circle.png"); - auto xBtn = new PNG("/app0/assets/images/x.png"); - auto squareBtn = new PNG("/app0/assets/images/square.png"); - auto startBtn = new PNG("/app0/assets/images/start.png"); - auto l1Trigger = new PNG("/app0/assets/images/l1.png"); - auto l2Trigger = new PNG("/app0/assets/images/l2.png"); - auto r1Trigger = new PNG("/app0/assets/images/r1.png"); - auto r2Trigger = new PNG("/app0/assets/images/r2.png"); +static void drawControllerData(Scene2D *scene, Controller *controller) { + if (controller == nullptr || scene == nullptr) + return; - DEBUGLOG << "Entering draw loop..."; - // Draw loop - for (;;) { - controllerBackground->Draw(scene, 0, 0); + static auto backgrd = new PNG("/app0/assets/images/controller.png"); + static auto thumbstick_pr = new PNG("/app0/assets/images/thumbstick_pr.png"); + static auto thumbstick = new PNG("/app0/assets/images/thumbstick.png"); + static auto touchpad = new PNG("/app0/assets/images/touchpad.png"); + static auto dpadUp = new PNG("/app0/assets/images/dpad-up.png"); + static auto dpadRight = new PNG("/app0/assets/images/dpad-right.png"); + static auto dpadDown = new PNG("/app0/assets/images/dpad-down.png"); + static auto dpadLeft = new PNG("/app0/assets/images/dpad-left.png"); + static auto triangleBtn = new PNG("/app0/assets/images/triangle.png"); + static auto circleBtn = new PNG("/app0/assets/images/circle.png"); + static auto xBtn = new PNG("/app0/assets/images/x.png"); + static auto squareBtn = new PNG("/app0/assets/images/square.png"); + static auto startBtn = new PNG("/app0/assets/images/start.png"); + static auto l1Trigger = new PNG("/app0/assets/images/l1.png"); + static auto l2Trigger = new PNG("/app0/assets/images/l2.png"); + static auto r1Trigger = new PNG("/app0/assets/images/r1.png"); + static auto r2Trigger = new PNG("/app0/assets/images/r2.png"); + + backgrd->Draw(scene, 0, 0); + + { static bool released = true; - if (controller->TrianglePressed()) { triangleBtn->Draw(scene, 1187, 359); released = false; } else if (released == false) { - repaintBar(controllerBackground, controller->NextColor()); + repaintBar(backgrd, controller->NextColor()); released = true; } + } - if (controller->CirclePressed()) { - circleBtn->Draw(scene, 1244, 416); - } + { + static Controller *prevController = controller; - if (controller->XPressed()) { - xBtn->Draw(scene, 1187, 472); - controller->ResetOrientation(); + if (prevController != controller) { + repaintBar(backgrd, controller->GetColor()); + prevController = controller; } + } - if (controller->SquarePressed()) { - squareBtn->Draw(scene, 1131, 416); - } + if (controller->CirclePressed()) { + circleBtn->Draw(scene, 1244, 416); + } - if (controller->L1Pressed()) { - l1Trigger->Draw(scene, 653, 139); - } + if (controller->XPressed()) { + xBtn->Draw(scene, 1187, 472); + controller->ResetOrientation(); + } - if (float str; controller->L2Pressed(&str)) { - scene->DrawRectangle(653, 255, str * 113, 10, Color{0xff, 0x00, 0x00}); - l2Trigger->Draw(scene, 653, 181); - } + if (controller->SquarePressed()) { + squareBtn->Draw(scene, 1131, 416); + } - if (controller->R1Pressed()) { - r1Trigger->Draw(scene, 1150, 139); - } + if (controller->L1Pressed()) { + l1Trigger->Draw(scene, 653, 139); + } - if (float str; controller->R2Pressed(&str)) { - scene->DrawRectangle(1150, 255, str * 113, 10, Color{0x00, 0x00, 0xff}); - r2Trigger->Draw(scene, 1150, 181); - } + if (float str; controller->L2Pressed(&str)) { + scene->DrawRectangle(653, 255, str * 113, 10, Color{0xff, 0x00, 0x00}); + l2Trigger->Draw(scene, 653, 181); + } - if (controller->StartPressed()) { - startBtn->Draw(scene, 1094, 334); - } + if (controller->R1Pressed()) { + r1Trigger->Draw(scene, 1150, 139); + } - if (controller->DpadUpPressed()) { - dpadUp->Draw(scene, 687, 377); - } + if (float str; controller->R2Pressed(&str)) { + scene->DrawRectangle(1150, 255, str * 113, 10, Color{0x00, 0x00, 0xff}); + r2Trigger->Draw(scene, 1150, 181); + } - if (controller->DpadRightPressed()) { - dpadRight->Draw(scene, 722, 422); - } + if (controller->StartPressed()) { + startBtn->Draw(scene, 1094, 334); + } - if (controller->DpadDownPressed()) { - dpadDown->Draw(scene, 687, 458); - } + if (controller->DpadUpPressed()) { + dpadUp->Draw(scene, 687, 377); + } + + if (controller->DpadRightPressed()) { + dpadRight->Draw(scene, 722, 422); + } + + if (controller->DpadDownPressed()) { + dpadDown->Draw(scene, 687, 458); + } + + if (controller->DpadLeftPressed()) { + dpadLeft->Draw(scene, 641, 422); + } + + if (controller->TouchpadPressed()) { + touchpad->Draw(scene, 854, 323); + } + + int tpw, tph; + controller->GetTouchPadResolution(&tpw, &tph); - if (controller->DpadLeftPressed()) { - dpadLeft->Draw(scene, 641, 422); + OrbisPadTouch *f = nullptr; + if (int fingers = controller->ReadFingers(&f)) { + for (int i = 0; i < fingers; ++i) { + auto fx = ((float)f[i].x / tpw) * 211, fy = ((float)f[i].y / tph) * 138; + scene->DrawRectangle(850 + fx, 318 + fy, 10, 10, Color{0xFF, 0x00, 0x00}); } + } + + vec_float4 q; + controller->ReadGyro(&q); + + scene->DrawRectangle(20, + MAX(0, MIN(FRAME_HEIGHT, (FRAME_HEIGHT / 2) - q.x * 40)), + 15, 10, Color{0xFF, 0x00, 0x00}); + scene->DrawRectangle(40, + MAX(0, MIN(FRAME_HEIGHT, (FRAME_HEIGHT / 2) - q.y * 40)), + 15, 10, Color{0xFF, 0x00, 0x00}); + scene->DrawRectangle(60, + MAX(0, MIN(FRAME_HEIGHT, (FRAME_HEIGHT / 2) - q.z * 40)), + 15, 10, Color{0xFF, 0x00, 0x00}); + scene->DrawRectangle(80, + MAX(0, MIN(FRAME_HEIGHT, (FRAME_HEIGHT / 2) - q.w * 40)), + 15, 10, Color{0xFF, 0x00, 0x00}); + + float lx, ly, rx, ry; + controller->ReadSticks(&lx, &ly, &rx, &ry); + (controller->L3Pressed() ? thumbstick_pr : thumbstick) + ->Draw(scene, 780 + 20 * lx, 512 + 20 * ly); + (controller->R3Pressed() ? thumbstick_pr : thumbstick) + ->Draw(scene, 1037 + 20 * rx, 512 + 20 * ry); +} + +int main(void) { + // No buffering + setvbuf(stdout, NULL, _IONBF, 0); - if (controller->TouchpadPressed()) { - touchpad->Draw(scene, 854, 323); + OrbisUserServiceInitializeParams param; + param.priority = ORBIS_KERNEL_PRIO_FIFO_LOWEST; + sceUserServiceInitialize(¶m); + + Controller *conts[ORBIS_USER_SERVICE_MAX_LOGIN_USERS] = {nullptr, nullptr, + nullptr, nullptr}; + int32_t currentUserId = -1; + + // Create a 2D scene + DEBUGLOG << "Creating a scene"; + auto scene = new Scene2D(FRAME_WIDTH, FRAME_HEIGHT, FRAME_DEPTH); + if (!scene->Init(0xC000000, 2)) { + DEBUGLOG << "Failed to initialize 2D scene"; + for (;;) + ; + } + // Create a controller + DEBUGLOG << "Initializing controller for initial user"; + sceUserServiceGetInitialUser(¤tUserId); + conts[currentUserId] = new Controller(); + if (!conts[currentUserId]->Init(currentUserId)) { + DEBUGLOG << "Failed to initialize controller"; + for (;;) + ; + } + + // Create PNG instances for all the sprites + + DEBUGLOG << "Entering draw loop..."; + // Draw loop + for (;;) { + if (currentUserId != -1) { + conts[currentUserId]->UpdateTriggersFeedback(); + drawControllerData(scene, conts[currentUserId]); } - OrbisPadTouch *f = nullptr; - if (int fingers = controller->ReadFingers(&f)) { - for (int i = 0; i < fingers; ++i) { - auto fx = ((float)f[i].x / tpw) * 211, fy = ((float)f[i].y / tph) * 138; - scene->DrawRectangle(850 + fx, 318 + fy, 10, 10, - Color{0xFF, 0x00, 0x00}); + int ubox_center_x = FRAME_WIDTH / 2, + ubox_center_y = (FRAME_HEIGHT / 2) - 32; + + static int ubox_item_size = 16; + static int ubox_item_pad = 5; + static int ubox_item_paddedsize = ubox_item_size + ubox_item_pad; + int ubox_full_width = + ubox_item_paddedsize * ORBIS_USER_SERVICE_MAX_LOGIN_USERS; + + int ubox_curr_x = ubox_center_x - (ubox_full_width / 2); + + OrbisUserServiceLoginUserIdList list; + if (sceUserServiceGetLoginUserIdList(&list) == ORBIS_OK) { + for (int i = 0; i < ORBIS_USER_SERVICE_MAX_LOGIN_USERS; ++i) { + Color boxColor = {0xFF, 0x00, 0x00}; + + if (list.userId[i] != -1 /* USER_SERVICE_USER_ID_INVALID */) { + const auto uid = list.userId[i]; + if (conts[uid] == nullptr) { + DEBUGLOG << "Initializing controller for new user"; + conts[uid] = new Controller(); + if (!conts[uid]->Init(uid)) { + DEBUGLOG << "Failed to initialize controller"; + for (;;) + ; + } + } + + if (currentUserId != uid && conts[uid]->StartPressed()) { + DEBUGLOG << "Switching user..."; + conts[currentUserId]->ResetTriggersFeedback(); + currentUserId = uid; + } + + if (currentUserId == uid) + boxColor = {0x00, 0xFF, 0x00}; + } + + scene->DrawRectangle(ubox_curr_x, ubox_center_y, ubox_item_size, + ubox_item_size, boxColor); + ubox_curr_x += ubox_item_paddedsize; } } - vec_float4 q; - controller->ReadGyro(&q); - - scene->DrawRectangle( - 20, MAX(0, MIN(FRAME_HEIGHT, (FRAME_HEIGHT / 2) - q.x * 40)), 15, 10, - Color{0xFF, 0x00, 0x00}); - scene->DrawRectangle( - 40, MAX(0, MIN(FRAME_HEIGHT, (FRAME_HEIGHT / 2) - q.y * 40)), 15, 10, - Color{0xFF, 0x00, 0x00}); - scene->DrawRectangle( - 60, MAX(0, MIN(FRAME_HEIGHT, (FRAME_HEIGHT / 2) - q.z * 40)), 15, 10, - Color{0xFF, 0x00, 0x00}); - scene->DrawRectangle( - 80, MAX(0, MIN(FRAME_HEIGHT, (FRAME_HEIGHT / 2) - q.w * 40)), 15, 10, - Color{0xFF, 0x00, 0x00}); - - float lx, ly, rx, ry; - controller->ReadSticks(&lx, &ly, &rx, &ry); - (controller->L3Pressed() ? thumbstick_pr : thumbstick) - ->Draw(scene, 780 + 20 * lx, 512 + 20 * ly); - (controller->R3Pressed() ? thumbstick_pr : thumbstick) - ->Draw(scene, 1037 + 20 * rx, 512 + 20 * ry); - // Submit the frame buffer scene->SubmitFlip(frameID); scene->FrameWait(frameID);