diff --git a/font/Font.h b/font/Font.h index 251fca0..d52f535 100644 --- a/font/Font.h +++ b/font/Font.h @@ -186,6 +186,14 @@ void font_from_file( memcpy(font->glyphs, pos, font->glyph_count * sizeof(Glyph)); + #if OPENGL + for (int32 i = 0; i < font->glyph_count; ++i) { + float temp = font->glyphs[i].coords.y1; + font->glyphs[i].coords.y1 = 1.0f - font->glyphs[i].coords.y2; + font->glyphs[i].coords.y2 = 1.0f - temp; + } + #endif + SWAP_ENDIAN_LITTLE_SIMD( (int32 *) font->glyphs, (int32 *) font->glyphs, diff --git a/hash/GeneralHash.h b/hash/GeneralHash.h index a5fc284..be8c1f4 100644 --- a/hash/GeneralHash.h +++ b/hash/GeneralHash.h @@ -105,107 +105,4 @@ uint32 hash_ejb(const char* str) return h % PRIME2; } -// CONSTEXPR - -constexpr -uint64 hash_djb2_const(const char* key) { - uint64 hash = 5381; - int32 c; - - while ((c = *key++)) { - hash = ((hash << 5) + hash) + c; - } - - return hash; -} - -constexpr -uint64 hash_sdbm_const(const byte* key) -{ - uint64 hash = 0; - int32 c; - - while (c = *key++) { - hash = c + (hash << 6) + (hash << 16) - hash; - } - - return hash; -} - -constexpr -uint64 hash_lose_lose_const(const byte* key) -{ - uint64 hash = 0; - int32 c; - - while (c = *key++) { - hash += c; - } - - return hash; -} - -constexpr -uint64 hash_polynomial_rolling_const(const char* str) { - const int32 p = 31; - const int32 m = 1000000009; - uint64 hash = 0; - uint64 p_pow = 1; - - while (*str) { - hash = (hash + (*str - 'a' + 1) * p_pow) % m; - p_pow = (p_pow * p) % m; - str++; - } - - return hash; -} - -constexpr -uint64 hash_fnv1a_const(const char* str) { - const uint64 FNV_OFFSET_BASIS = 14695981039346656037UL; - const uint64 FNV_PRIME = 1099511628211UL; - uint64 hash = FNV_OFFSET_BASIS; - - while (*str) { - hash ^= (byte) *str; - hash *= FNV_PRIME; - str++; - } - - return hash; -} - -constexpr -uint32 hash_oat_const(const char* str) -{ - uint32 h = 0; - - while(*str) { - h += *str++; - h += (h << 10); - h ^= (h >> 6); - } - - h += (h << 3); - h ^= (h >> 11); - h += (h << 15); - - return h; -} - -constexpr -uint32 hash_ejb_const(const char* str) -{ - const uint32 PRIME1 = 37; - const uint32 PRIME2 = 1048583; - uint32 h = 0; - - while (*str) { - h = h * PRIME1 ^ (*str++ - ' '); - } - - return h % PRIME2; -} - #endif \ No newline at end of file diff --git a/image/Image.h b/image/Image.h index fef1705..e5ffa0b 100644 --- a/image/Image.h +++ b/image/Image.h @@ -24,7 +24,7 @@ struct Image { uint32 width; uint32 height; - uint32 pixel_count; + uint32 pixel_count; // @question Do we even need this? // Image settings bool has_alpha; diff --git a/input/Input.h b/input/Input.h index 21512ce..020cdec 100644 --- a/input/Input.h +++ b/input/Input.h @@ -13,6 +13,7 @@ #include "../utils/BitUtils.h" #include "../memory/BufferMemory.h" #include "ControllerInput.h" +#include "InputConnectionType.h" // How many concurrent mouse/secondary input device presses to we recognize #define MAX_MOUSE_PRESSES 3 @@ -50,6 +51,7 @@ #ifdef _WIN32 #include + #include #endif typedef void (*InputCallback)(void* data); @@ -117,14 +119,18 @@ struct InputState { struct Input { // Device - bool is_connected; + InputConnectionType connection_type; #ifdef _WIN32 // @question maybe replace with id?! // -> remove _WIN32 section? HANDLE handle_keyboard; HANDLE handle_mouse; - HANDLE handle_controller; + + // @todo support all three versions + int32 controller_id; // used by XInput + HANDLE handle_controller; // used by raw input controller + LPDIRECTINPUTDEVICE8* direct_controller; // used by direct input controller #endif bool state_change_button; diff --git a/input/InputConnectionType.h b/input/InputConnectionType.h new file mode 100644 index 0000000..88879ee --- /dev/null +++ b/input/InputConnectionType.h @@ -0,0 +1,21 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_PLATFORM_WIN32_INPUT_CONNECTION_TYPE_H +#define TOS_PLATFORM_WIN32_INPUT_CONNECTION_TYPE_H + +// Important, since some connection protocols differ between for example USB and Bluetooth (see Playstation DualSense) +enum InputConnectionType { + INPUT_CONNECTION_TYPE_NONE, + INPUT_CONNECTION_TYPE_USB, + INPUT_CONNECTION_TYPE_BLUETOOTH, + INPUT_CONNECTION_TYPE_WIRELESS, +}; + + +#endif \ No newline at end of file diff --git a/models/settings/Settings.h b/models/settings/Settings.h index fe2c52b..90c47fb 100644 --- a/models/settings/Settings.h +++ b/models/settings/Settings.h @@ -16,6 +16,7 @@ #if _WIN32 #include + #include "../../platform/win32/input/controller/ControllerHandler.h" #else __linux__ #include #define MAX_PATH PATH_MAX @@ -352,6 +353,8 @@ struct CSettings { byte game_interact_radius = 1; // Game pad settings + byte input_device_types = SETTING_INPUT_DEVICE_TYPE_MOUSE_KEYBOARD; + byte input_controller_handler = CONTROLLER_HANDLER_TYPE_AUTO; byte stick_left_deadzone = 0; byte stick_right_deadzone = 0; diff --git a/models/settings/setting_types.h b/models/settings/setting_types.h index 41f5343..6601423 100644 --- a/models/settings/setting_types.h +++ b/models/settings/setting_types.h @@ -78,4 +78,7 @@ #define SETTING_UI_VISIBILITY_DEBUG 2 #define SETTING_UI_VISIBILITY_WIREFRAME 4 +#define SETTING_INPUT_DEVICE_TYPE_MOUSE_KEYBOARD 1 +#define SETTING_INPUT_DEVICE_TYPE_CONTROLLER 2 + #endif \ No newline at end of file diff --git a/platform/win32/input/DirectInput.h b/platform/win32/input/DirectInput.h index e69de29..edc7505 100644 --- a/platform/win32/input/DirectInput.h +++ b/platform/win32/input/DirectInput.h @@ -0,0 +1,129 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_PLATFORM_WIN32_INPUT_DIRECTINPUT_H +#define TOS_PLATFORM_WIN32_INPUT_DIRECTINPUT_H + +#include +#include "../../../input/Input.h" +#include "../../../input/ControllerInput.h" +#include "../../../stdlib/Types.h" + +BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE* instance, void* pDevicePtr) +{ + LPDIRECTINPUT8 pDirectInput = (LPDIRECTINPUT8)pDevicePtr; + LPDIRECTINPUTDEVICE8* pDIDevice = (LPDIRECTINPUTDEVICE8*)pDevicePtr; + + if (SUCCEEDED(pDirectInput->CreateDevice(instance->guidInstance, pDIDevice, NULL))) { + return DIENUM_STOP; + } + + return DIENUM_CONTINUE; +} + +int32 directinput_init_controllers(HWND hwnd, Input* __restrict states) +{ + LPDIRECTINPUT8* pDirectInput = NULL; + HRESULT hr; + + // Initialize DirectInput interface if it’s not already initialized + hr = DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)pDirectInput, NULL); + if (FAILED(hr)) { + return 0; + } + + // Enumerate devices to find a connected game controller + hr = (*pDirectInput)->EnumDevices(DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, states->direct_controller, DIEDFL_ATTACHEDONLY); + if (FAILED(hr) || *states->direct_controller == NULL) { + return 0; + } + + // Set data format for the device to use the joystick state format + hr = (*states->direct_controller)->SetDataFormat(&c_dfDIJoystick2); + if (FAILED(hr)) { + (*states->direct_controller)->Release(); + *states->direct_controller = NULL; + return 0; + } + + // Set the cooperative level for the device + hr = (*states->direct_controller)->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_EXCLUSIVE); + if (FAILED(hr)) { + (*states->direct_controller)->Release(); + *states->direct_controller = NULL; + return 0; + } + + // Acquire the device for use + hr = (*states->direct_controller)->Acquire(); + if (FAILED(hr)) { + (*states->direct_controller)->Release(); + *states->direct_controller = NULL; + return 0; + } + + return 1; +} + +inline void input_map_directinput(ControllerInput* controller, LPDIRECTINPUTDEVICE8 pDIDevice) +{ + if (FAILED(pDIDevice->Poll())) { + if (FAILED(pDIDevice->Acquire())) { + return; + } + } + + // Define a buffer for DirectInput state + DIJOYSTATE2 controller_state; + if (FAILED(pDIDevice->GetDeviceState(sizeof(DIJOYSTATE2), &controller_state))) { + return; + } + + controller->button[CONTROLLER_BUTTON_DPAD_UP] = (controller_state.rgdwPOV[0] == 0) ? 127 : 0; + controller->button[CONTROLLER_BUTTON_DPAD_RIGHT] = (controller_state.rgdwPOV[0] == 9000) ? 127 : 0; + controller->button[CONTROLLER_BUTTON_DPAD_DOWN] = (controller_state.rgdwPOV[0] == 18000) ? 127 : 0; + controller->button[CONTROLLER_BUTTON_DPAD_LEFT] = (controller_state.rgdwPOV[0] == 27000) ? 127 : 0; + + controller->button[CONTROLLER_BUTTON_OTHER_0] = (controller_state.rgbButtons[7] & 0x80) ? 127 : 0; // Start + controller->button[CONTROLLER_BUTTON_OTHER_1] = (controller_state.rgbButtons[6] & 0x80) ? 127 : 0; // Back + + controller->button[CONTROLLER_BUTTON_SHOULDER_RIGHT_BUTTON] = (controller_state.rgbButtons[5] & 0x80) ? 127 : 0; + controller->button[CONTROLLER_BUTTON_SHOULDER_LEFT_BUTTON] = (controller_state.rgbButtons[4] & 0x80) ? 127 : 0; + + controller->button[CONTROLLER_BUTTON_SHOULDER_RIGHT_TRIGGER] = controller_state.lZ > 0 ? controller_state.lZ : 0; + controller->is_analog[CONTROLLER_BUTTON_SHOULDER_RIGHT_TRIGGER] = true; + + controller->button[CONTROLLER_BUTTON_SHOULDER_LEFT_TRIGGER] = controller_state.lZ < 0 ? -controller_state.lZ : 0; + controller->is_analog[CONTROLLER_BUTTON_SHOULDER_LEFT_TRIGGER] = true; + + controller->button[CONTROLLER_BUTTON_T] = (controller_state.rgbButtons[3] & 0x80) ? 127 : 0; + controller->button[CONTROLLER_BUTTON_C] = (controller_state.rgbButtons[1] & 0x80) ? 127 : 0; + controller->button[CONTROLLER_BUTTON_X] = (controller_state.rgbButtons[0] & 0x80) ? 127 : 0; + controller->button[CONTROLLER_BUTTON_S] = (controller_state.rgbButtons[2] & 0x80) ? 127 : 0; + + controller->button[CONTROLLER_BUTTON_STICK_LEFT_HORIZONTAL] = controller_state.lX; + controller->button[CONTROLLER_BUTTON_STICK_LEFT_VERTICAL] = controller_state.lY; + controller->is_analog[CONTROLLER_BUTTON_STICK_LEFT_HORIZONTAL] = true; + controller->is_analog[CONTROLLER_BUTTON_STICK_LEFT_VERTICAL] = true; + controller->button[CONTROLLER_BUTTON_STICK_LEFT_BUTTON] = (controller_state.rgbButtons[8] & 0x80) ? 127 : 0; + + controller->button[CONTROLLER_BUTTON_STICK_RIGHT_HORIZONTAL] = controller_state.lRx; + controller->button[CONTROLLER_BUTTON_STICK_RIGHT_VERTICAL] = controller_state.lRy; + controller->is_analog[CONTROLLER_BUTTON_STICK_RIGHT_HORIZONTAL] = true; + controller->is_analog[CONTROLLER_BUTTON_STICK_RIGHT_VERTICAL] = true; + controller->button[CONTROLLER_BUTTON_STICK_RIGHT_BUTTON] = (controller_state.rgbButtons[9] & 0x80) ? 127 : 0; + + controller->button[CONTROLLER_BUTTON_OTHER_2] = (controller_state.rgbButtons[10] & 0x80) ? 127 : 0; + controller->button[CONTROLLER_BUTTON_OTHER_3] = (controller_state.rgbButtons[11] & 0x80) ? 127 : 0; + controller->button[CONTROLLER_BUTTON_OTHER_4] = (controller_state.rgbButtons[12] & 0x80) ? 127 : 0; + controller->button[CONTROLLER_BUTTON_OTHER_5] = (controller_state.rgbButtons[13] & 0x80) ? 127 : 0; + controller->button[CONTROLLER_BUTTON_OTHER_6] = (controller_state.rgbButtons[14] & 0x80) ? 127 : 0; + controller->button[CONTROLLER_BUTTON_OTHER_7] = (controller_state.rgbButtons[15] & 0x80) ? 127 : 0; +} + +#endif \ No newline at end of file diff --git a/platform/win32/input/RawInput.h b/platform/win32/input/RawInput.h index 62f9e18..e727be0 100644 --- a/platform/win32/input/RawInput.h +++ b/platform/win32/input/RawInput.h @@ -32,7 +32,7 @@ // Even if it is nowhere documented (at least not to our knowledge) the GetRawInputDeviceInfoA, GetRawInputBuffer functions requried // aligned memory. So far we only figured out that 4 bytes works, maybe this needs to be 8 in the future?! -int input_raw_init(HWND hwnd, Input* __restrict states, RingMemory* ring) +int rawinput_init_mousekeyboard(HWND hwnd, Input* __restrict states, RingMemory* ring) { uint32 device_count; GetRawInputDeviceList(NULL, &device_count, sizeof(RAWINPUTDEVICELIST)); @@ -66,7 +66,7 @@ int input_raw_init(HWND hwnd, Input* __restrict states, RingMemory* ring) } states[mouse_found].handle_mouse = pRawInputDeviceList[i].hDevice; - states[mouse_found].is_connected = true; + states[mouse_found].connection_type = INPUT_CONNECTION_TYPE_USB; // Mouse rid[0].usUsagePage = 0x01; // @todo doesn't work with 0x05 for games? @@ -85,7 +85,7 @@ int input_raw_init(HWND hwnd, Input* __restrict states, RingMemory* ring) } states[keyboard_found].handle_keyboard = pRawInputDeviceList[i].hDevice; - states[keyboard_found].is_connected = true; + states[keyboard_found].connection_type = INPUT_CONNECTION_TYPE_USB; // Keyboard rid[0].usUsagePage = 0x01; // @todo doesn't work with 0x05 for games? @@ -98,6 +98,40 @@ int input_raw_init(HWND hwnd, Input* __restrict states, RingMemory* ring) ASSERT_SIMPLE(false); } } break; + } + } + + return i; +} + +int rawinput_init_controllers(HWND hwnd, Input* __restrict states, RingMemory* ring) +{ + uint32 device_count; + GetRawInputDeviceList(NULL, &device_count, sizeof(RAWINPUTDEVICELIST)); + PRAWINPUTDEVICELIST pRawInputDeviceList = (PRAWINPUTDEVICELIST) ring_get_memory(ring, sizeof(RAWINPUTDEVICELIST) * device_count, 4); + device_count = GetRawInputDeviceList(pRawInputDeviceList, &device_count, sizeof(RAWINPUTDEVICELIST)); + + // We always want at least one empty input device slot + // @todo Change so that we store the actual number of devices + if (device_count == 0) { + return 0; + } + + uint32 cb_size = 256; + + int32 mouse_found = 0; + int32 keyboard_found = 0; + int32 controller_found = 0; + + int32 i; + for (i = 0; i < device_count; ++i) { + cb_size = sizeof(RID_DEVICE_INFO); + RID_DEVICE_INFO rdi; + GetRawInputDeviceInfoA(pRawInputDeviceList[i].hDevice, RIDI_DEVICEINFO, &rdi, &cb_size); + + RAWINPUTDEVICE rid[1]; + + switch (rdi.dwType) { case RIM_TYPEHID: { if (rdi.hid.usUsage == 0x05) { if (states[controller_found].handle_controller != NULL) { @@ -105,7 +139,8 @@ int input_raw_init(HWND hwnd, Input* __restrict states, RingMemory* ring) } states[controller_found].handle_controller = pRawInputDeviceList[i].hDevice; - states[controller_found].is_connected = true; + // @bug This is not always true, how to check? + states[controller_found].connection_type = INPUT_CONNECTION_TYPE_USB; // Gamepad rid[0].usUsagePage = 0x01; @@ -123,7 +158,8 @@ int input_raw_init(HWND hwnd, Input* __restrict states, RingMemory* ring) } states[controller_found].handle_controller = pRawInputDeviceList[i].hDevice; - states[controller_found].is_connected = true; + // @bug This is not always true, how to check? + states[controller_found].connection_type = INPUT_CONNECTION_TYPE_USB; // Joystick rid[0].usUsagePage = 0x01; @@ -155,11 +191,11 @@ void input_mouse_position(HWND hwnd, v2_int32* pos) } } -int32 input_raw_handle(RAWINPUT* __restrict raw, Input* states, int state_count, uint64 time) +int32 input_raw_handle(RAWINPUT* __restrict raw, Input* states, int32 state_count, uint64 time) { int32 input_count = 0; - uint32 i = 0; + int32 i = 0; if (raw->header.dwType == RIM_TYPEMOUSE) { // @performance Change so we can directly access the correct state (maybe map handle address to index?) while (i < state_count @@ -168,7 +204,7 @@ int32 input_raw_handle(RAWINPUT* __restrict raw, Input* states, int state_count, ++i; } - if (i >= state_count || !states[i].is_connected) { + if (i >= state_count || !states[i].connection_type) { return 0; } @@ -273,7 +309,7 @@ int32 input_raw_handle(RAWINPUT* __restrict raw, Input* states, int state_count, ++i; } - if (i >= state_count || !states[i].is_connected) { + if (i >= state_count || !states[i].connection_type) { return 0; } @@ -294,27 +330,28 @@ int32 input_raw_handle(RAWINPUT* __restrict raw, Input* states, int state_count, states[i].state_change_button = true; } else if (raw->header.dwType == RIM_TYPEHID) { if (raw->header.dwSize > sizeof(RAWINPUT)) { - // @todo Find a way to handle most common controllers - // DualSense - // Xbox - // @performance This shouldn't be done every time, it should be polling based // Controllers often CONSTANTLY send data -> really bad - // Maybe we can add timer usage + // Maybe we can add timer usage instead of polling? while (i < state_count && states[i].handle_controller != raw->header.hDevice ) { ++i; } - if (i >= state_count || !states[i].is_connected + if (i >= state_count || !states[i].connection_type || time - states[i].time_last_input_check < 5 ) { return 0; } + // @todo Find a way to handle most common controllers + // DualSense + // Xbox + // Xinput + // Best way would probably to define the controller type in the input ControllerInput controller = {}; - input_map_dualshock4(&controller, raw->data.hid.bRawData); + input_map_dualshock4(&controller, states[i].connection_type, raw->data.hid.bRawData); input_set_controller_state(&states[i], &controller, time); states[i].time_last_input_check = time; diff --git a/platform/win32/input/XInput.h b/platform/win32/input/XInput.h index 5160d06..cf36247 100644 --- a/platform/win32/input/XInput.h +++ b/platform/win32/input/XInput.h @@ -56,7 +56,7 @@ void xinput_load() { } // END: Dynamically load XInput -ControllerInput* init_controllers() +ControllerInput* xinput_init_controllers() { uint32 c = 0; for (uint32 controller_index = 0; controller_index < XUSER_MAX_COUNT; ++controller_index) { @@ -85,49 +85,45 @@ ControllerInput* init_controllers() return controllers; } -void handle_controller_input(ControllerInput* states) +inline +void input_map_xinput(ControllerInput* controller, int32 controller_id) { - /* - uint32 controller_index = 0; - while(states[controller_index].is_connected) { - XINPUT_STATE controller_state; - if (XInputGetState(controller_index, &controller_state) != ERROR_SUCCESS) { - ++controller_index; - - continue; - } - - - states[controller_index].up = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP; - states[controller_index].down = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN; - states[controller_index].left = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT; - states[controller_index].right = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT; - states[controller_index].button[6] = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_START; - states[controller_index].button[7] = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_BACK; - - states[controller_index].button[4] = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER; - states[controller_index].button[5] = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER; - - states[controller_index].trigger[0] = controller_state.Gamepad.bLeftTrigger; - states[controller_index].trigger[1] = controller_state.Gamepad.bRightTrigger; - - states[controller_index].button[0] = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_A; - states[controller_index].button[1] = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_B; - states[controller_index].button[2] = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_X; - states[controller_index].button[3] = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_Y; - - states[controller_index].stickl_x = controller_state.Gamepad.sThumbLX; - states[controller_index].stickl_y = controller_state.Gamepad.sThumbLY; - states[controller_index].stickl_press = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB; - - states[controller_index].stickr_x = controller_state.Gamepad.sThumbRX; - states[controller_index].stickr_y = controller_state.Gamepad.sThumbRY; - states[controller_index].stickr_press = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB; - - - ++controller_index; + XINPUT_STATE controller_state; + if (XInputGetState(controller_id, &controller_state) != ERROR_SUCCESS) { + return; } - */ + + controller->button[CONTROLLER_BUTTON_DPAD_LEFT] = (controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) * 127; + controller->button[CONTROLLER_BUTTON_DPAD_RIGHT] = (controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) * 127; + controller->button[CONTROLLER_BUTTON_DPAD_UP] = (controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) * 127; + controller->button[CONTROLLER_BUTTON_DPAD_DOWN] = (controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) * 127; + + controller->button[CONTROLLER_BUTTON_OTHER_0] = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_START; + controller->button[CONTROLLER_BUTTON_OTHER_1] = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_BACK; + + controller->button[CONTROLLER_BUTTON_SHOULDER_RIGHT_BUTTON] = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER ? 1: 0; + controller->button[CONTROLLER_BUTTON_SHOULDER_LEFT_BUTTON] = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER ? 1: 0; + + controller->button[CONTROLLER_BUTTON_SHOULDER_RIGHT_TRIGGER] = controller_state.Gamepad.bRightTrigger; + controller->is_analog[CONTROLLER_BUTTON_SHOULDER_RIGHT_TRIGGER] = true; + + controller->button[CONTROLLER_BUTTON_SHOULDER_LEFT_TRIGGER] = controller_state.Gamepad.bLeftTrigger; + controller->is_analog[CONTROLLER_BUTTON_SHOULDER_LEFT_TRIGGER] = true; + + controller->button[CONTROLLER_BUTTON_T] = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_Y ? 1: 0; + controller->button[CONTROLLER_BUTTON_C] = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_B ? 1: 0; + controller->button[CONTROLLER_BUTTON_X] = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_A ? 1: 0; + controller->button[CONTROLLER_BUTTON_S] = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_X ? 1: 0; + + controller->button[CONTROLLER_BUTTON_STICK_LEFT_HORIZONTAL] = (byte) OMS_MIN(controller_state.Gamepad.sThumbLX, 127); + controller->button[CONTROLLER_BUTTON_STICK_LEFT_VERTICAL] = (byte) OMS_MIN(controller_state.Gamepad.sThumbLY, 127); + controller->is_analog[CONTROLLER_BUTTON_STICK_LEFT_VERTICAL] = true; + controller->button[CONTROLLER_BUTTON_STICK_LEFT_BUTTON] = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB; + + controller->button[CONTROLLER_BUTTON_STICK_RIGHT_HORIZONTAL] = (byte) OMS_MIN(controller_state.Gamepad.sThumbRX, 127); + controller->button[CONTROLLER_BUTTON_STICK_RIGHT_VERTICAL] = (byte) OMS_MIN(controller_state.Gamepad.sThumbRY, 127); + controller->is_analog[CONTROLLER_BUTTON_STICK_RIGHT_VERTICAL] = true; + controller->button[CONTROLLER_BUTTON_STICK_RIGHT_BUTTON] = controller_state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB; } #endif \ No newline at end of file diff --git a/platform/win32/input/controller/ControllerHandler.h b/platform/win32/input/controller/ControllerHandler.h new file mode 100644 index 0000000..55fca04 --- /dev/null +++ b/platform/win32/input/controller/ControllerHandler.h @@ -0,0 +1,21 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_PLATFORM_WIN32_INPUT_CONTROLLER_HANDLER_H +#define TOS_PLATFORM_WIN32_INPUT_CONTROLLER_HANDLER_H + +enum ControllerHandlerType { + CONTROLLER_HANDLER_TYPE_AUTO, // Automatically picks a handler based on the device info and hard coded preferences + CONTROLLER_HANDLER_TYPE_XINPUT, + CONTROLLER_HANDLER_TYPE_DIRECTINPUT, + CONTROLLER_HANDLER_TYPE_RAWINPUT_DS, + CONTROLLER_HANDLER_TYPE_RAWINPUT_DS4, + CONTROLLER_HANDLER_TYPE_RAWINPUT_XBOXS, +}; + +#endif \ No newline at end of file diff --git a/platform/win32/input/controller/DualSense.h b/platform/win32/input/controller/DualSense.h index e69de29..7a10d12 100644 --- a/platform/win32/input/controller/DualSense.h +++ b/platform/win32/input/controller/DualSense.h @@ -0,0 +1,142 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + * @see https://dsremap.readthedocs.io/en/latest/reverse.html + */ +#ifndef TOS_PLATFORM_WIN32_INPUT_CONTROLLER_DUALSENSE_H +#define TOS_PLATFORM_WIN32_INPUT_CONTROLLER_DUALSENSE_H + +#include "../../../../stdlib/Types.h" +#include "../../../../input/ControllerInput.h" +#include "../../../../input/InputConnectionType.h" +#include "../../../../utils/BitUtils.h" +#include "../../../../utils/MathUtils.h" + +// @bug bluetooth and USB have different formats?! +// https://github.com/nondebug/dualsense +inline +void input_map_dualsense(ControllerInput* controller, InputConnectionType connection_type, byte* data) +{ + // 0 is not the origin -> need to shift + ++data; + + controller->button[CONTROLLER_BUTTON_STICK_LEFT_HORIZONTAL] = *data++; + controller->button[CONTROLLER_BUTTON_STICK_LEFT_HORIZONTAL] = OMS_MIN(controller->button[CONTROLLER_BUTTON_STICK_LEFT_HORIZONTAL] - 128, 127); + controller->is_analog[CONTROLLER_BUTTON_STICK_LEFT_HORIZONTAL] = true; + + controller->button[CONTROLLER_BUTTON_STICK_LEFT_VERTICAL] = *data++; + controller->button[CONTROLLER_BUTTON_STICK_LEFT_VERTICAL] = OMS_MIN(controller->button[CONTROLLER_BUTTON_STICK_LEFT_VERTICAL] - 128, 127); + controller->is_analog[CONTROLLER_BUTTON_STICK_LEFT_VERTICAL] = true; + + controller->button[CONTROLLER_BUTTON_STICK_RIGHT_HORIZONTAL] = *data++; + controller->button[CONTROLLER_BUTTON_STICK_RIGHT_HORIZONTAL] = OMS_MIN(controller->button[CONTROLLER_BUTTON_STICK_RIGHT_HORIZONTAL] - 128, 127); + controller->is_analog[CONTROLLER_BUTTON_STICK_RIGHT_HORIZONTAL] = true; + + controller->button[CONTROLLER_BUTTON_STICK_RIGHT_VERTICAL] = *data++; + controller->button[CONTROLLER_BUTTON_STICK_RIGHT_VERTICAL] = OMS_MIN(controller->button[CONTROLLER_BUTTON_STICK_RIGHT_VERTICAL] - 128, 127); + controller->is_analog[CONTROLLER_BUTTON_STICK_RIGHT_VERTICAL] = true; + + if (connection_type == INPUT_CONNECTION_TYPE_USB) { + controller->button[CONTROLLER_BUTTON_SHOULDER_LEFT_TRIGGER] = *data++; + controller->is_analog[CONTROLLER_BUTTON_SHOULDER_LEFT_TRIGGER] = true; + + controller->button[CONTROLLER_BUTTON_SHOULDER_RIGHT_TRIGGER] = *data++; + controller->is_analog[CONTROLLER_BUTTON_SHOULDER_RIGHT_TRIGGER] = true; + + // Some counter + ++data; + } + + controller->button[CONTROLLER_BUTTON_T] = BITS_GET_8_L2R(*data, 0, 1); + controller->button[CONTROLLER_BUTTON_C] = BITS_GET_8_L2R(*data, 1, 1); + controller->button[CONTROLLER_BUTTON_X] = BITS_GET_8_L2R(*data, 2, 1); + controller->button[CONTROLLER_BUTTON_S] = BITS_GET_8_L2R(*data, 3, 1); + + uint32 d_pad_state = BITS_GET_8_L2R(*data, 4, 4); + if (d_pad_state == 8) { + controller->button[CONTROLLER_BUTTON_DPAD_LEFT] = 0; + controller->button[CONTROLLER_BUTTON_DPAD_RIGHT] = 0; + controller->button[CONTROLLER_BUTTON_DPAD_UP] = 0; + controller->button[CONTROLLER_BUTTON_DPAD_DOWN] = 0; + } else if (d_pad_state == 0) { + controller->button[CONTROLLER_BUTTON_DPAD_LEFT] = 0; + controller->button[CONTROLLER_BUTTON_DPAD_RIGHT] = 0; + controller->button[CONTROLLER_BUTTON_DPAD_UP] = 127; + controller->button[CONTROLLER_BUTTON_DPAD_DOWN] = 0; + } else if (d_pad_state == 1) { + controller->button[CONTROLLER_BUTTON_DPAD_LEFT] = 0; + controller->button[CONTROLLER_BUTTON_DPAD_RIGHT] = 127; + controller->button[CONTROLLER_BUTTON_DPAD_UP] = 127; + controller->button[CONTROLLER_BUTTON_DPAD_DOWN] = 0; + } else if (d_pad_state == 2) { + controller->button[CONTROLLER_BUTTON_DPAD_LEFT] = 0; + controller->button[CONTROLLER_BUTTON_DPAD_RIGHT] = 127; + controller->button[CONTROLLER_BUTTON_DPAD_UP] = 0; + controller->button[CONTROLLER_BUTTON_DPAD_DOWN] = 0; + } else if (d_pad_state == 3) { + controller->button[CONTROLLER_BUTTON_DPAD_LEFT] = 0; + controller->button[CONTROLLER_BUTTON_DPAD_RIGHT] = 127; + controller->button[CONTROLLER_BUTTON_DPAD_UP] = 0; + controller->button[CONTROLLER_BUTTON_DPAD_DOWN] = 127; + } else if (d_pad_state == 4) { + controller->button[CONTROLLER_BUTTON_DPAD_LEFT] = 0; + controller->button[CONTROLLER_BUTTON_DPAD_RIGHT] = 0; + controller->button[CONTROLLER_BUTTON_DPAD_UP] = 0; + controller->button[CONTROLLER_BUTTON_DPAD_DOWN] = 127; + } else if (d_pad_state == 5) { + controller->button[CONTROLLER_BUTTON_DPAD_LEFT] = 127; + controller->button[CONTROLLER_BUTTON_DPAD_RIGHT] = 0; + controller->button[CONTROLLER_BUTTON_DPAD_UP] = 0; + controller->button[CONTROLLER_BUTTON_DPAD_DOWN] = 127; + } else if (d_pad_state == 6) { + controller->button[CONTROLLER_BUTTON_DPAD_LEFT] = 127; + controller->button[CONTROLLER_BUTTON_DPAD_RIGHT] = 0; + controller->button[CONTROLLER_BUTTON_DPAD_UP] = 0; + controller->button[CONTROLLER_BUTTON_DPAD_DOWN] = 0; + } else if (d_pad_state == 7) { + controller->button[CONTROLLER_BUTTON_DPAD_LEFT] = 127; + controller->button[CONTROLLER_BUTTON_DPAD_RIGHT] = 0; + controller->button[CONTROLLER_BUTTON_DPAD_UP] = 127; + controller->button[CONTROLLER_BUTTON_DPAD_DOWN] = 0; + } + + ++data; + + controller->button[CONTROLLER_BUTTON_STICK_RIGHT_BUTTON] = BITS_GET_8_L2R(*data, 0, 1); + controller->button[CONTROLLER_BUTTON_STICK_LEFT_BUTTON] = BITS_GET_8_L2R(*data, 1, 1); + + controller->button[CONTROLLER_BUTTON_OTHER_0] = BITS_GET_8_L2R(*data, 2, 1); // option + controller->button[CONTROLLER_BUTTON_OTHER_1] = BITS_GET_8_L2R(*data, 3, 1); // share + + controller->button[CONTROLLER_BUTTON_SHOULDER_RIGHT_BUTTON] = BITS_GET_8_L2R(*data, 6, 1); + controller->button[CONTROLLER_BUTTON_SHOULDER_LEFT_BUTTON] = BITS_GET_8_L2R(*data, 7, 1); + + ++data; + + controller->button[CONTROLLER_BUTTON_OTHER_2] = BITS_GET_8_L2R(*data, 5, 1); // mute + controller->button[CONTROLLER_BUTTON_OTHER_3] = BITS_GET_8_L2R(*data, 6, 1); // tpad + controller->button[CONTROLLER_BUTTON_OTHER_4] = BITS_GET_8_L2R(*data, 7, 1); // ps + + ++data; + + if (connection_type == INPUT_CONNECTION_TYPE_BLUETOOTH) { + controller->button[CONTROLLER_BUTTON_SHOULDER_LEFT_TRIGGER] = *data++; + controller->is_analog[CONTROLLER_BUTTON_SHOULDER_LEFT_TRIGGER] = true; + + controller->button[CONTROLLER_BUTTON_SHOULDER_RIGHT_TRIGGER] = *data++; + controller->is_analog[CONTROLLER_BUTTON_SHOULDER_RIGHT_TRIGGER] = true; + } + + data += 22; + + // @question pure guess + controller->gyro_x = *data++; + controller->gyro_y = *data++; + controller->gyro_z = *data++; +} + +#endif \ No newline at end of file diff --git a/platform/win32/input/controller/DualShock4.h b/platform/win32/input/controller/DualShock4.h index 020ded4..c2d1a7f 100644 --- a/platform/win32/input/controller/DualShock4.h +++ b/platform/win32/input/controller/DualShock4.h @@ -5,20 +5,28 @@ * @license OMS License 2.0 * @version 1.0.0 * @link https://jingga.app + * @see https://dsremap.readthedocs.io/en/latest/reverse.html */ #ifndef TOS_PLATFORM_WIN32_INPUT_CONTROLLER_DUALSHOCK4_H #define TOS_PLATFORM_WIN32_INPUT_CONTROLLER_DUALSHOCK4_H #include "../../../../stdlib/Types.h" #include "../../../../input/ControllerInput.h" +#include "../../../../input/InputConnectionType.h" #include "../../../../utils/BitUtils.h" +#include "../../../../utils/MathUtils.h" inline -void input_map_dualshock4(ControllerInput* controller, byte* data) +void input_map_dualshock4(ControllerInput* controller, InputConnectionType connection_type, byte* data) { + // 0 is not the origin -> need to shift ++data; - // 0 is not the origin -> need to shift + // @question Do we even need this? This might not be send on Windows + if (connection_type == INPUT_CONNECTION_TYPE_BLUETOOTH) { + ++data; + } + controller->button[CONTROLLER_BUTTON_STICK_LEFT_HORIZONTAL] = *data++; controller->button[CONTROLLER_BUTTON_STICK_LEFT_HORIZONTAL] = OMS_MIN(controller->button[CONTROLLER_BUTTON_STICK_LEFT_HORIZONTAL] - 128, 127); controller->is_analog[CONTROLLER_BUTTON_STICK_LEFT_HORIZONTAL] = true; diff --git a/utils/BitUtils.h b/utils/BitUtils.h index 319555f..1315ae5 100644 --- a/utils/BitUtils.h +++ b/utils/BitUtils.h @@ -33,6 +33,7 @@ #define BIT_UNSET_R2L(num, pos) ((num) & ~((uint32) 1 << (pos))) #define BIT_FLIP_R2L(num, pos) ((num) ^ ((uint32) 1 << (pos))) #define BIT_SET_TO_R2L(num, pos, x) ((num) & ~((uint32) 1 << (pos)) | ((uint32) (x) << (pos))) +// @performance Try to use this version over the L2R version for performance reasons #define BITS_GET_8_R2L(num, pos, to_read) (((num) >> (pos)) & ((1U << (to_read)) - 1)) #define BITS_GET_16_R2L(num, pos, to_read) (((num) >> (pos)) & ((1U << (to_read)) - 1)) #define BITS_GET_32_R2L(num, pos, to_read) (((num) >> (pos)) & ((1U << (to_read)) - 1))