feat: better cmake support (#21)

* feat: CMakeSettings.json

* chore: remove visual studio stuff
chore: move .clang-format to main directory

* feat: new file structure, easier to implement as a submodule within existing projects

* chore: we actually include some code now...

* chore: remove prebuilt libraries (oops)

* feat: new shader building script using cmake

* chore: add debug postfix specifier

* fix: forgot that windows builds use 4J_Render_PC for the render library

* fix: didn't add the output directory (where shaders are saved to) to the include directories of 4J_Render
This commit is contained in:
gsds
2026-04-21 02:07:59 -04:00
committed by GitHub
parent 576f038dd0
commit e0ae7b1ec1
111 changed files with 1802 additions and 1458 deletions
+177
View File
@@ -0,0 +1,177 @@
/*
MIT License
Copyright (c) 2026 Patoke
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "4J_Input.h"
#include "INP_Keyboard.h"
#include "INP_Main.h"
C_4JInput InputManager;
CKeyboard InternalKeyboard;
void C_4JInput::Initialise(int iInputStateC, unsigned char ucMapC, unsigned char ucActionC, unsigned char ucMenuActionC)
{
InternalInputManager.Initialise(iInputStateC, ucMapC, ucActionC, ucMenuActionC);
}
void C_4JInput::Tick(void)
{
InternalInputManager.Tick();
}
void C_4JInput::SetDeadzoneAndMovementRange(unsigned int uiDeadzone, unsigned int uiMovementRangeMax)
{
InternalInputManager.SetDeadzoneAndMovementRange(uiDeadzone, uiMovementRangeMax);
}
void C_4JInput::SetGameJoypadMaps(unsigned char ucMap, unsigned char ucAction, unsigned int uiActionVal)
{
InternalInputManager.SetGameJoypadMaps(ucMap, ucAction, uiActionVal);
}
unsigned int C_4JInput::GetGameJoypadMaps(unsigned char ucMap, unsigned char ucAction)
{
return InternalInputManager.GetGameJoypadMaps(ucMap, ucAction);
}
void C_4JInput::SetJoypadMapVal(int iPad, unsigned char ucMap)
{
InternalInputManager.SetJoypadMapVal(iPad, ucMap);
}
unsigned char C_4JInput::GetJoypadMapVal(int iPad)
{
return InternalInputManager.GetJoypadMapVal(iPad);
}
void C_4JInput::SetJoypadSensitivity(int iPad, float fSensitivity)
{
InternalInputManager.SetJoypadSensitivity(iPad, fSensitivity);
}
unsigned int C_4JInput::GetValue(int iPad, unsigned char ucAction, bool bRepeat)
{
return InternalInputManager.GetValue(iPad, ucAction, bRepeat);
}
bool C_4JInput::ButtonPressed(int iPad, unsigned char ucAction)
{
return InternalInputManager.ButtonPressed(iPad, ucAction);
}
bool C_4JInput::ButtonReleased(int iPad, unsigned char ucAction)
{
return InternalInputManager.ButtonReleased(iPad, ucAction);
}
bool C_4JInput::ButtonDown(int iPad, unsigned char ucAction)
{
return InternalInputManager.ButtonDown(iPad, ucAction);
}
void C_4JInput::SetJoypadStickAxisMap(int iPad, unsigned int uiFrom, unsigned int uiTo)
{
InternalInputManager.SetJoypadStickAxisMap(iPad, uiFrom, uiTo);
}
void C_4JInput::SetJoypadStickTriggerMap(int iPad, unsigned int uiFrom, unsigned int uiTo)
{
InternalInputManager.SetJoypadStickTriggerMap(iPad, uiFrom, uiTo);
}
void C_4JInput::SetKeyRepeatRate(float fRepeatDelaySecs, float fRepeatRateSecs)
{
InternalInputManager.SetKeyRepeatRate(fRepeatDelaySecs, fRepeatRateSecs);
}
void C_4JInput::SetDebugSequence(const char *chSequenceA, int (*Func)(LPVOID), LPVOID lpParam)
{
InternalInputManager.SetDebugSequence(chSequenceA, Func, lpParam);
}
FLOAT C_4JInput::GetIdleSeconds(int iPad)
{
return InternalInputManager.GetIdleSeconds(iPad);
}
bool C_4JInput::IsPadConnected(int iPad)
{
return InternalInputManager.IsPadConnected(iPad);
}
float C_4JInput::GetJoypadStick_LX(int iPad, bool bCheckMenuDisplay)
{
return InternalInputManager.GetJoypadStick_LX(iPad, bCheckMenuDisplay);
}
float C_4JInput::GetJoypadStick_LY(int iPad, bool bCheckMenuDisplay)
{
return InternalInputManager.GetJoypadStick_LY(iPad, bCheckMenuDisplay);
}
float C_4JInput::GetJoypadStick_RX(int iPad, bool bCheckMenuDisplay)
{
return InternalInputManager.GetJoypadStick_RX(iPad, bCheckMenuDisplay);
}
float C_4JInput::GetJoypadStick_RY(int iPad, bool bCheckMenuDisplay)
{
return InternalInputManager.GetJoypadStick_RY(iPad, bCheckMenuDisplay);
}
unsigned char C_4JInput::GetJoypadLTrigger(int iPad, bool bCheckMenuDisplay)
{
return InternalInputManager.GetJoypadLTrigger(iPad, bCheckMenuDisplay);
}
unsigned char C_4JInput::GetJoypadRTrigger(int iPad, bool bCheckMenuDisplay)
{
return InternalInputManager.GetJoypadRTrigger(iPad, bCheckMenuDisplay);
}
void C_4JInput::SetMenuDisplayed(int iPad, bool bVal)
{
InternalInputManager.SetMenuDisplayed(iPad, bVal);
}
EKeyboardResult C_4JInput::RequestKeyboard(LPCWSTR Title, LPCWSTR Text, DWORD dwPad, UINT uiMaxChars, int (*Func)(LPVOID, const bool), LPVOID lpParam,
C_4JInput::EKeyboardMode eMode)
{
return InternalKeyboard.RequestKeyboard(Title, Text, dwPad, uiMaxChars, Func, lpParam, eMode);
}
void C_4JInput::GetText(uint16_t *UTF16String)
{
InternalKeyboard.GetText(UTF16String);
}
bool C_4JInput::VerifyStrings(WCHAR **pwStringA, int iStringC, int (*Func)(LPVOID, STRING_VERIFY_RESPONSE *), LPVOID lpParam)
{
return true;
}
void C_4JInput::CancelQueuedVerifyStrings(int (*Func)(LPVOID, STRING_VERIFY_RESPONSE *), LPVOID lpParam) {}
void C_4JInput::CancelAllVerifyInProgress(void) {}
// bool C_4JInput::InputDetected(DWORD dwUserIndex,WCHAR *pwchInput) {}
@@ -0,0 +1,134 @@
/*
MIT License
Copyright (c) 2026 Patoke
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "INP_ForceFeedback.h"
void CForceFeedback::Initialise(int iInputStateC, unsigned char ucMapC, unsigned char ucActionC, unsigned char ucMenuActionC)
{
m_Effects = new FF_EFFECT[MAX_EFFECTS];
m_EffectC = 0;
LARGE_INTEGER qwTicksPerSec;
QueryPerformanceFrequency(&qwTicksPerSec);
m_TicksPerSecond = qwTicksPerSec.LowPart;
m_unkBool = 0;
}
void CForceFeedback::RumbleEnable(int iQuadrant, bool bRumbleEnabled) {}
void CForceFeedback::CreateEffect(void)
{
assert(m_EffectC < MAX_EFFECTS);
FF_EFFECT *pEffect = &m_Effects[m_EffectC];
pEffect->m_uiDurationMs = 5;
pEffect->m_uiMagnitude = 500;
pEffect->m_uiEffectType = 0;
pEffect->dword18 = 10;
pEffect->dword18 = 100;
m_EffectC++;
}
void CForceFeedback::AddEffectInstance(unsigned int uiEffect)
{
FF_EFFECT_INSTANCE *pEffectInst = new FF_EFFECT_INSTANCE();
pEffectInst->m_Effect = &m_Effects[uiEffect];
pEffectInst->m_uiInst = 0;
m_EffectList.AddToTail(pEffectInst);
}
void CForceFeedback::SetEffectInstanceState(unsigned int uiEffectInstance, unsigned int uiState)
{
int iCount = 0;
LinkedList::_LL_NODE *pNode;
for (pNode = m_EffectList.m_Head;; pNode = pNode->m_Next)
{
if ((iCount++) == uiEffectInstance)
break;
}
pNode->GetDataAs<FF_EFFECT_INSTANCE>()->m_bIsActive = true;
}
void CForceFeedback::ProcessEventInstance(FF_EFFECT_INSTANCE *pEffectInst) {}
void CForceFeedback::PauseEventInstance(FF_EFFECT_INSTANCE *pEffectInst) {}
void CForceFeedback::AddRumble(unsigned int uiPad, WORD leftMotorSpeed, WORD rightMotorSpeed, float fSeconds)
{
RUMBLE_EFFECT *pRumble = new RUMBLE_EFFECT();
LARGE_INTEGER qwCurrentTime;
QueryPerformanceCounter(&qwCurrentTime);
pRumble->m_TimeLeft = (m_TicksPerSecond * fSeconds) + qwCurrentTime.QuadPart;
pRumble->m_RumbleData.wLeftMotorSpeed = leftMotorSpeed;
pRumble->m_RumbleData.wRightMotorSpeed = rightMotorSpeed;
pRumble->m_Pad = uiPad;
m_RumbleList.AddToTail(pRumble);
}
void CForceFeedback::Tick(void)
{
for (LinkedList::_LL_NODE *pEffectNode = m_EffectList.m_Head; pEffectNode; pEffectNode = pEffectNode->m_Next)
{
if (pEffectNode->GetDataAs<FF_EFFECT_INSTANCE>()->m_bIsActive)
{
ProcessEventInstance(pEffectNode->GetDataAs<FF_EFFECT_INSTANCE>());
}
}
LARGE_INTEGER qwCurrentTime;
QueryPerformanceCounter(&qwCurrentTime);
LinkedList::_LL_NODE *pRumbleNode = m_RumbleList.m_Head;
while (pRumbleNode)
{
if (pRumbleNode->GetDataAs<RUMBLE_EFFECT>()->m_TimeLeft <= qwCurrentTime.QuadPart)
{
RUMBLE_EFFECT *pRumble = pRumbleNode->GetDataAs<RUMBLE_EFFECT>();
pRumble->m_RumbleData.wLeftMotorSpeed = 0;
pRumble->m_RumbleData.wRightMotorSpeed = 0;
XInputSetState(pRumble->m_Pad, &pRumble->m_RumbleData);
m_RumbleList.RemoveNode(pRumbleNode);
LinkedList::_LL_NODE *pTemp = pRumbleNode;
pRumbleNode = pRumbleNode->m_Next;
delete pTemp->GetDataAs<RUMBLE_EFFECT>();
delete pTemp;
}
else
{
XInputSetState(pRumbleNode->GetDataAs<RUMBLE_EFFECT>()->m_Pad, &pRumbleNode->GetDataAs<RUMBLE_EFFECT>()->m_RumbleData);
pRumbleNode = pRumbleNode->m_Next;
}
}
}
@@ -0,0 +1,46 @@
/*
MIT License
Copyright (c) 2026 Patoke
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "INP_Keyboard.h"
void CKeyboard::Tick(void) {}
EKeyboardResult CKeyboard::RequestKeyboard(LPCWSTR Title, LPCWSTR Text, DWORD dwPad, UINT uiMaxChars, int (*Func)(LPVOID, const bool), LPVOID lpParam,
C_4JInput::EKeyboardMode eMode)
{
ClearGlobalText();
SeedEditBox();
Func(lpParam, C_4JInput::EKeyboardMode_Numeric);
return EKeyboard_ResultAccept;
}
void CKeyboard::GetText(uint16_t *UTF16String)
{
uint16_t *keyString = GetGlobalText();
for (unsigned int index = 0; keyString[index] && index < 0x200; index++)
{
UTF16String[index] = keyString[index];
}
}
+762
View File
@@ -0,0 +1,762 @@
/*
MIT License
Copyright (c) 2026 Patoke
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "INP_Main.h"
CInput InternalInputManager;
CInput::CInput()
{
m_ForceFeedback = CForceFeedback();
m_Keyboard = CKeyboard();
m_uiSigninJoypadMask = 0;
for (int i = 0; i < 4; ++i)
m_bIsMenuDisplayed[i] = 0;
InitTime();
m_fRepeatDelaySecs = 0.5f;
m_fRepeatRateSecs = 0.8f;
m_sDebugSequenceName = 0;
m_uiDebugSequenceIndex = 0;
m_pDebugSequenceFn = 0;
}
void CInput::Initialise(int iInputStateC, unsigned char ucMapC, unsigned char ucActionC, unsigned char ucMenuActionC)
{
assert(iInputStateC > 0);
assert(ucMapC > 0);
assert(ucActionC > 0);
ZeroMemory(m_Joypads, sizeof(m_Joypads));
m_ucInputStateC = iInputStateC;
m_iDeadzone = 0x2710;
m_iMovementRangeMax = 0x7FFF;
m_iEffectiveRange = m_iMovementRangeMax - m_iDeadzone;
m_iHalfRange = m_iEffectiveRange / 2;
m_fEffectiveRange = (float)m_iEffectiveRange;
for (int i = 0; i < MAX_JOYPADS; i++)
{
m_Joypads[i].m_pInputStates = new XINPUT_STATE[m_ucInputStateC];
m_Joypads[i].m_ucInputStateIndex = -1;
m_Joypads[i].m_pfLeftThumbXAxisMap = &m_Joypads[i].m_fNormalizedLeftThumbX;
m_Joypads[i].m_pfLeftThumbYAxisMap = &m_Joypads[i].m_fNormalizedLeftThumbY;
m_Joypads[i].m_pfRightThumbXAxisMap = &m_Joypads[i].m_fNormalizedRightThumbX;
m_Joypads[i].m_pfRightThumbYAxisMap = &m_Joypads[i].m_fNormalizedRightThumbY;
m_Joypads[i].m_pucLeftTriggerAxisMap = &m_Joypads[i].m_ucLeftTriggerState;
m_Joypads[i].m_pucRightTriggerAxisMap = &m_Joypads[i].m_ucRightTriggerState;
m_Joypads[i].m_fSensitivity = 1.0f;
}
m_JoypadMap = (unsigned int **)operator new[](ucMapC * sizeof(int *));
for (int i = 0; i < ucMapC; i++)
{
m_JoypadMap[i] = (unsigned int *)operator new[](ucActionC * sizeof(int));
}
m_ucJoypadMapC = ucMapC;
m_ucJoypadMapActionC = ucActionC;
m_ucMenuActionC = ucMenuActionC;
m_bJoypadMapArrayIsSetup = false;
m_ForceFeedback.Initialise(iInputStateC, ucMapC, ucActionC, ucMenuActionC);
}
void CInput::Tick(void)
{
UpdateJoypads();
m_ForceFeedback.Tick();
m_Keyboard.Tick();
}
void CInput::SetJoypadValues(JOYPAD *pThisPad)
{
XINPUT_GAMEPAD *pGamePad = &pThisPad->m_pInputStates[pThisPad->m_ucInputStateIndex].Gamepad;
if (pGamePad->bLeftTrigger > 0x7Fu)
{
pThisPad->m_uiButtons |= _360_JOY_BUTTON_LT;
}
if (pGamePad->bRightTrigger > 0x7Fu)
{
pThisPad->m_uiButtons |= _360_JOY_BUTTON_RT;
}
if ((pGamePad->wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) != 0)
{
pThisPad->m_uiButtons |= _360_JOY_BUTTON_RB;
}
if ((pGamePad->wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) != 0)
{
pThisPad->m_uiButtons |= _360_JOY_BUTTON_LB;
}
if ((pGamePad->wButtons & XINPUT_GAMEPAD_A) != 0)
{
pThisPad->m_uiButtons |= _360_JOY_BUTTON_A;
}
if ((pGamePad->wButtons & XINPUT_GAMEPAD_B) != 0)
{
pThisPad->m_uiButtons |= _360_JOY_BUTTON_B;
}
if ((pGamePad->wButtons & XINPUT_GAMEPAD_X) != 0)
{
pThisPad->m_uiButtons |= _360_JOY_BUTTON_X;
}
if ((pGamePad->wButtons & XINPUT_GAMEPAD_Y) != 0)
{
pThisPad->m_uiButtons |= _360_JOY_BUTTON_Y;
}
if ((pGamePad->wButtons & XINPUT_GAMEPAD_START) != 0)
{
pThisPad->m_uiButtons |= _360_JOY_BUTTON_START;
}
if ((pGamePad->wButtons & XINPUT_GAMEPAD_BACK) != 0)
{
pThisPad->m_uiButtons |= _360_JOY_BUTTON_BACK;
}
if ((pGamePad->wButtons & XINPUT_GAMEPAD_LEFT_THUMB) != 0)
{
pThisPad->m_uiButtons |= _360_JOY_BUTTON_RTHUMB;
}
if ((pGamePad->wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) != 0)
{
pThisPad->m_uiButtons |= _360_JOY_BUTTON_LTHUMB;
}
if ((pGamePad->wButtons & XINPUT_GAMEPAD_DPAD_UP) != 0)
{
pThisPad->m_uiButtons |= _360_JOY_BUTTON_DPAD_UP;
}
if ((pGamePad->wButtons & XINPUT_GAMEPAD_DPAD_DOWN) != 0)
{
pThisPad->m_uiButtons |= _360_JOY_BUTTON_DPAD_DOWN;
}
if ((pGamePad->wButtons & XINPUT_GAMEPAD_DPAD_LEFT) != 0)
{
pThisPad->m_uiButtons |= _360_JOY_BUTTON_DPAD_LEFT;
}
if ((pGamePad->wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) != 0)
{
pThisPad->m_uiButtons |= _360_JOY_BUTTON_DPAD_RIGHT;
}
if (pGamePad->sThumbLX > m_iHalfRange + m_iDeadzone)
{
pThisPad->m_uiButtons |= _360_JOY_BUTTON_LSTICK_RIGHT;
}
if (pGamePad->sThumbLX < -m_iDeadzone - m_iHalfRange)
{
pThisPad->m_uiButtons |= _360_JOY_BUTTON_LSTICK_LEFT;
}
if (pGamePad->sThumbRY < -m_iDeadzone - m_iHalfRange)
{
pThisPad->m_uiButtons |= _360_JOY_BUTTON_RSTICK_DOWN;
}
if (pGamePad->sThumbRY > m_iHalfRange + m_iDeadzone)
{
pThisPad->m_uiButtons |= _360_JOY_BUTTON_RSTICK_UP;
}
if (pGamePad->sThumbRX > m_iHalfRange + m_iDeadzone)
{
pThisPad->m_uiButtons |= _360_JOY_BUTTON_RSTICK_RIGHT;
}
if (pGamePad->sThumbRX < -m_iDeadzone - m_iHalfRange)
{
pThisPad->m_uiButtons |= _360_JOY_BUTTON_RSTICK_LEFT;
}
if (pGamePad->sThumbLY < -m_iDeadzone - m_iHalfRange)
{
pThisPad->m_uiButtons |= _360_JOY_BUTTON_LSTICK_DOWN;
}
if (pGamePad->sThumbLY > m_iHalfRange + m_iDeadzone)
{
pThisPad->m_uiButtons |= _360_JOY_BUTTON_LSTICK_UP;
}
pThisPad->m_ucLeftTriggerState = pGamePad->bLeftTrigger;
pThisPad->m_ucRightTriggerState = pGamePad->bRightTrigger;
if (pGamePad->sThumbRX <= m_iDeadzone)
{
if (pGamePad->sThumbRX >= -m_iDeadzone)
pThisPad->m_iRightThumbX = 0;
else
pThisPad->m_iRightThumbX = m_iDeadzone + pGamePad->sThumbRX;
}
else
{
pThisPad->m_iRightThumbX = pGamePad->sThumbRX - m_iDeadzone;
}
if (pGamePad->sThumbRY <= m_iDeadzone)
{
if (pGamePad->sThumbRY >= -m_iDeadzone)
pThisPad->m_iRightThumbY = 0;
else
pThisPad->m_iRightThumbY = m_iDeadzone + pGamePad->sThumbRY;
}
else
{
pThisPad->m_iRightThumbY = pGamePad->sThumbRY - m_iDeadzone;
}
if (pGamePad->sThumbLX <= m_iDeadzone)
{
if (pGamePad->sThumbLX >= -m_iDeadzone)
pThisPad->m_iLeftThumbX = 0;
else
pThisPad->m_iLeftThumbX = m_iDeadzone + pGamePad->sThumbLX;
}
else
{
pThisPad->m_iLeftThumbX = pGamePad->sThumbLX - m_iDeadzone;
}
if (pGamePad->sThumbLY <= m_iDeadzone)
{
if (pGamePad->sThumbLY >= -m_iDeadzone)
pThisPad->m_iLeftThumbY = 0;
else
pThisPad->m_iLeftThumbY = m_iDeadzone + pGamePad->sThumbLY;
}
else
{
pThisPad->m_iLeftThumbY = pGamePad->sThumbLY - m_iDeadzone;
}
pThisPad->m_iNormalizedLeftThumbX = pThisPad->m_iLeftThumbX / m_iEffectiveRange;
pThisPad->m_iNormalizedLeftThumbY = pThisPad->m_iLeftThumbY / m_iEffectiveRange;
pThisPad->m_iNormalizedRightThumbX = pThisPad->m_iRightThumbX / m_iEffectiveRange;
pThisPad->m_iNormalizedRightThumbY = pThisPad->m_iRightThumbY / m_iEffectiveRange;
pThisPad->m_fNormalizedLeftThumbX = pThisPad->m_iLeftThumbX / m_fEffectiveRange;
pThisPad->m_fNormalizedLeftThumbY = pThisPad->m_iLeftThumbY / m_fEffectiveRange;
pThisPad->m_fNormalizedRightThumbX = pThisPad->m_iRightThumbX / m_fEffectiveRange;
pThisPad->m_fNormalizedRightThumbY = pThisPad->m_iRightThumbY / m_fEffectiveRange;
}
void CInput::SetDeadzoneAndMovementRange(unsigned int uiDeadzone, unsigned int uiMovementRangeMax)
{
m_iDeadzone = uiDeadzone;
m_iMovementRangeMax = uiMovementRangeMax;
m_iEffectiveRange = uiMovementRangeMax - uiDeadzone;
m_iHalfRange = m_iEffectiveRange / 2;
}
void CInput::SetJoypadSensitivity(int iPad, float fSensitivity)
{
m_Joypads[iPad].m_fSensitivity = fSensitivity;
}
void CInput::SetGameJoypadMaps(unsigned char ucMap, unsigned char ucAction, unsigned int uiActionVal)
{
assert(ucMap < m_ucJoypadMapC);
assert(ucAction < m_ucJoypadMapActionC);
m_JoypadMap[ucMap][ucAction] = uiActionVal;
}
unsigned int CInput::GetGameJoypadMaps(unsigned char ucMap, unsigned char ucAction)
{
assert(ucMap < m_ucJoypadMapC);
assert(ucAction < m_ucJoypadMapActionC);
return m_JoypadMap[ucMap][ucAction];
}
void CInput::SetJoypadMapVal(int iPad, unsigned char ucMap)
{
m_bJoypadMapArrayIsSetup = true;
m_Joypads[iPad].m_ucMappingValue = ucMap;
}
unsigned char CInput::GetJoypadMapVal(int iPad)
{
return m_Joypads[iPad].m_ucMappingValue;
}
void CInput::SetJoypadStickAxisMap(int iPad, unsigned int uiFrom, unsigned int uiTo)
{
float *pfTo = nullptr;
switch (uiTo)
{
case AXIS_MAP_LX:
pfTo = &m_Joypads[iPad].m_fNormalizedLeftThumbX;
break;
case AXIS_MAP_LY:
pfTo = &m_Joypads[iPad].m_fNormalizedLeftThumbY;
break;
case AXIS_MAP_RX:
pfTo = &m_Joypads[iPad].m_fNormalizedRightThumbX;
break;
case AXIS_MAP_RY:
pfTo = &m_Joypads[iPad].m_fNormalizedRightThumbY;
break;
}
switch (uiFrom)
{
case AXIS_MAP_LX:
m_Joypads[iPad].m_pfLeftThumbXAxisMap = pfTo;
break;
case AXIS_MAP_LY:
m_Joypads[iPad].m_pfLeftThumbYAxisMap = pfTo;
break;
case AXIS_MAP_RX:
m_Joypads[iPad].m_pfRightThumbXAxisMap = pfTo;
break;
case AXIS_MAP_RY:
m_Joypads[iPad].m_pfRightThumbYAxisMap = pfTo;
break;
}
}
void CInput::SetJoypadStickTriggerMap(int iPad, unsigned int uiFrom, unsigned int uiTo)
{
unsigned char *pucTo = nullptr;
switch (uiTo)
{
case TRIGGER_MAP_0:
pucTo = &m_Joypads[iPad].m_ucRightTriggerState;
break;
case TRIGGER_MAP_1:
pucTo = &m_Joypads[iPad].m_ucLeftTriggerState;
break;
}
switch (uiFrom)
{
case TRIGGER_MAP_0:
m_Joypads[iPad].m_pucRightTriggerAxisMap = pucTo;
break;
case TRIGGER_MAP_1:
m_Joypads[iPad].m_pucLeftTriggerAxisMap = pucTo;
break;
}
}
bool CInput::IsPadConnected(int iPad)
{
return m_Joypads[iPad].m_bIsConnected;
}
void CInput::SetSigninJoypadMask(unsigned int mask)
{
m_uiSigninJoypadMask = mask;
}
unsigned int CInput::GetValue(int iPad, unsigned char ucAction, bool bRepeat)
{
if (m_bIsMenuDisplayed[iPad] && ucAction > this->m_ucMenuActionC)
{
return 0;
}
unsigned char ucMap = this->m_Joypads[iPad].m_ucMappingValue;
unsigned int uiVal = this->m_JoypadMap[ucMap][ucAction] & this->m_Joypads[iPad].m_uiButtons;
if (!uiVal || !bRepeat)
{
return uiVal;
}
int iKeyVal = 0;
for (int iKey = this->m_JoypadMap[ucMap][ucAction]; (iKey & 1) == 0; iKey >>= 1)
{
iKeyVal++;
}
if (m_fRepeatDelaySecs <= m_Timers[iPad][iKeyVal].m_fTotalHoldTime || m_Timers[iPad][iKeyVal].m_bInitialPressHandled)
{
if (m_Timers[iPad][iKeyVal].m_fTotalHoldTime < m_fRepeatDelaySecs)
{
return 0;
}
else if (m_Timers[iPad][iKeyVal].m_fLastRepeatTime == 0.0f)
{
m_Timers[iPad][iKeyVal].m_fLastRepeatTime = m_fRepeatDelaySecs;
return uiVal;
}
else if ((m_Timers[iPad][iKeyVal].m_fTotalHoldTime - m_Timers[iPad][iKeyVal].m_fLastRepeatTime) <= m_fRepeatRateSecs)
{
return 0;
}
else
{
m_Timers[iPad][iKeyVal].m_fLastRepeatTime = m_Timers[iPad][iKeyVal].m_fLastRepeatTime + m_fRepeatRateSecs;
return uiVal;
}
}
else
{
m_Timers[iPad][iKeyVal].m_bInitialPressHandled = true;
return uiVal;
}
}
bool CInput::IsSet(int iPad, unsigned char ucAction)
{
return (!m_bIsMenuDisplayed[iPad] || ucAction <= m_ucMenuActionC) &&
(m_JoypadMap[m_Joypads[iPad].m_ucMappingValue][ucAction] & m_Joypads[iPad].m_uiButtons) != 0;
}
bool CInput::ButtonPressed(int iPad, unsigned char ucAction)
{
if (ucAction == 255)
{
return m_Joypads[iPad].m_uiButtonsPressed != 0;
}
if (m_bIsMenuDisplayed[iPad] && ucAction > m_ucMenuActionC)
{
return 0;
}
return (m_JoypadMap[m_Joypads[iPad].m_ucMappingValue][ucAction] & m_Joypads[iPad].m_uiButtonsPressed) != 0;
}
bool CInput::ButtonReleased(int iPad, unsigned char ucAction)
{
return (!m_bIsMenuDisplayed[iPad] || ucAction <= m_ucMenuActionC) &&
(m_JoypadMap[m_Joypads[iPad].m_ucMappingValue][ucAction] & m_Joypads[iPad].m_uiButtonsReleased) != 0;
}
bool CInput::ButtonDown(int iPad, unsigned char ucAction)
{
if (ucAction == 255)
{
return m_Joypads[iPad].m_uiButtons != 0;
}
if (m_bIsMenuDisplayed[iPad] && ucAction > m_ucMenuActionC)
{
return 0;
}
return (m_JoypadMap[m_Joypads[iPad].m_ucMappingValue][ucAction] & m_Joypads[iPad].m_uiButtons) != 0;
}
float CInput::GetJoypadStick_Menu_LX(unsigned char ucPad)
{
return m_Joypads[ucPad].m_iNormalizedLeftThumbX;
}
float CInput::GetJoypadStick_Menu_LY(unsigned char ucPad)
{
return m_Joypads[ucPad].m_iNormalizedLeftThumbY;
}
float CInput::GetJoypadStick_Menu_RX(unsigned char ucPad)
{
return m_Joypads[ucPad].m_iNormalizedRightThumbX;
}
float CInput::GetJoypadStick_Menu_RY(unsigned char ucPad)
{
return m_Joypads[ucPad].m_iNormalizedRightThumbY;
}
unsigned char CInput::GetJoypadLTrigger_Menu(unsigned char ucPad)
{
return m_Joypads[ucPad].m_ucLeftTriggerState;
}
unsigned char CInput::GetJoypadRTrigger_Menu(unsigned char ucPad)
{
return m_Joypads[ucPad].m_ucRightTriggerState;
}
float CInput::GetJoypadStick_LX(int iPad, bool bCheckMenuDisplay)
{
if (bCheckMenuDisplay && m_bIsMenuDisplayed[iPad])
{
return 0.0f;
}
return *m_Joypads[iPad].m_pfLeftThumbXAxisMap * m_Joypads[iPad].m_fSensitivity;
}
float CInput::GetJoypadStick_LY(int iPad, bool bCheckMenuDisplay)
{
if (bCheckMenuDisplay && m_bIsMenuDisplayed[iPad])
{
return 0.0f;
}
return *m_Joypads[iPad].m_pfLeftThumbYAxisMap * m_Joypads[iPad].m_fSensitivity;
}
float CInput::GetJoypadStick_RX(int iPad, bool bCheckMenuDisplay)
{
if (bCheckMenuDisplay && m_bIsMenuDisplayed[iPad])
{
return 0.0f;
}
return *m_Joypads[iPad].m_pfRightThumbXAxisMap * m_Joypads[iPad].m_fSensitivity;
}
float CInput::GetJoypadStick_RY(int iPad, bool bCheckMenuDisplay)
{
if (bCheckMenuDisplay && m_bIsMenuDisplayed[iPad])
{
return 0.0f;
}
return *m_Joypads[iPad].m_pfRightThumbYAxisMap * m_Joypads[iPad].m_fSensitivity;
}
unsigned char CInput::GetJoypadLTrigger(int iPad, bool bCheckMenuDisplay)
{
if (bCheckMenuDisplay && m_bIsMenuDisplayed[iPad])
{
return 0;
}
return *m_Joypads[iPad].m_pucLeftTriggerAxisMap;
}
unsigned char CInput::GetJoypadRTrigger(int iPad, bool bCheckMenuDisplay)
{
if (bCheckMenuDisplay && m_bIsMenuDisplayed[iPad])
{
return 0;
}
return *m_Joypads[iPad].m_pucRightTriggerAxisMap;
}
void CInput::SetMenuDisplayed(int iPad, bool bVal)
{
m_bIsMenuDisplayed[iPad] = bVal;
}
void CInput::SetKeyRepeatRate(float fRepeatDelaySecs, float fRepeatRateSecs)
{
m_fRepeatDelaySecs = fRepeatDelaySecs;
m_fRepeatRateSecs = fRepeatRateSecs;
}
void CInput::SetDebugSequence(const char *chSequenceA, int (*Func)(LPVOID), LPVOID lpParam)
{
int iLen = strlen(chSequenceA);
m_sDebugSequenceName = (char *)operator new[](iLen);
strcpy(m_sDebugSequenceName, chSequenceA);
m_pDebugSequenceFn = Func;
m_pDebugSequenceParam = lpParam;
}
FLOAT CInput::GetIdleSeconds(int iPad)
{
LARGE_INTEGER qwDeltaTime;
QueryPerformanceCounter(&qwDeltaTime);
LARGE_INTEGER fElapsedTime = this->m_LastActivityTime[iPad];
uint64_t qwNewTime = qwDeltaTime.QuadPart - fElapsedTime.QuadPart;
return this->m_fTickToSeconds * (qwDeltaTime.LowPart - fElapsedTime.LowPart);
}
bool CInput::UpdateJoypads()
{
assert(m_bJoypadMapArrayIsSetup);
for (int i = 0; i < MAX_JOYPADS; i++)
{
JOYPAD *pThisPad = &m_Joypads[i];
pThisPad->m_uiOldButtons = pThisPad->m_uiButtons;
pThisPad->m_uiButtons = 0;
pThisPad->m_iRightThumbY = 0;
pThisPad->m_iRightThumbX = 0;
pThisPad->m_iLeftThumbY = 0;
pThisPad->m_iLeftThumbX = 0;
pThisPad->m_ucLeftTriggerState = 0;
pThisPad->m_ucRightTriggerState = 0;
}
for (int i = 0; i < MAX_JOYPADS; i++)
{
if (!m_Joypads[i].m_bIsDisabled)
{
JOYPAD *pThisPad = &m_Joypads[i];
bool bOldIsConnected = pThisPad->m_bIsConnected;
pThisPad->m_ucInputStateIndex = pThisPad->m_ucInputStateIndex++;
if (pThisPad->m_ucInputStateIndex == m_ucInputStateC)
{
pThisPad->m_ucInputStateIndex = 0;
}
pThisPad->m_bIsConnected = XInputGetState(i, &pThisPad->m_pInputStates[pThisPad->m_ucInputStateIndex]) == 0;
bool bWasConnected = bOldIsConnected && !pThisPad->m_bIsConnected;
pThisPad->m_bWasConnected = bWasConnected;
bool bHasConnected = !bOldIsConnected && pThisPad->m_bIsConnected;
pThisPad->m_bHasConnected = bHasConnected;
if (pThisPad->m_bIsConnected)
{
SetJoypadValues(pThisPad);
pThisPad->m_uiButtonsPressed = ~pThisPad->m_uiOldButtons & pThisPad->m_uiButtons;
pThisPad->m_uiButtonsReleased = ~pThisPad->m_uiButtons & pThisPad->m_uiOldButtons;
for (int bit = 0; bit < 24; ++bit)
{
if ((pThisPad->m_uiButtonsPressed & (1 << bit)) != 0)
{
GetStartTime(i, bit);
}
else if ((pThisPad->m_uiButtons & (1 << bit)) != 0)
{
UpdateTime(i, bit);
}
}
}
else if (pThisPad->m_bWasConnected)
{
ClearJoypadValues(pThisPad);
}
if (m_pDebugSequenceFn && (pThisPad->m_uiButtonsPressed & (_360_JOY_BUTTON_A | _360_JOY_BUTTON_B | _360_JOY_BUTTON_X | _360_JOY_BUTTON_Y |
_360_JOY_BUTTON_RB | _360_JOY_BUTTON_LB)) != 0)
{
char chSeq;
if ((pThisPad->m_uiButtonsPressed & _360_JOY_BUTTON_A) == _360_JOY_BUTTON_A)
{
chSeq = 'A';
}
else if ((pThisPad->m_uiButtonsPressed & _360_JOY_BUTTON_B) == _360_JOY_BUTTON_B)
{
chSeq = 'B';
}
else if ((pThisPad->m_uiButtonsPressed & _360_JOY_BUTTON_X) == _360_JOY_BUTTON_X)
{
chSeq = 'X';
}
else if ((pThisPad->m_uiButtonsPressed & _360_JOY_BUTTON_Y) == _360_JOY_BUTTON_Y)
{
chSeq = 'Y';
}
else if ((pThisPad->m_uiButtonsPressed & _360_JOY_BUTTON_LB) == _360_JOY_BUTTON_LB)
{
chSeq = 'L';
}
else if ((pThisPad->m_uiButtonsPressed & _360_JOY_BUTTON_RB) == _360_JOY_BUTTON_RB)
{
chSeq = 'R';
}
if (m_sDebugSequenceName[m_uiDebugSequenceIndex] == chSeq)
{
if (!m_sDebugSequenceName[m_uiDebugSequenceIndex++])
{
m_uiDebugSequenceIndex = 0;
(m_pDebugSequenceFn)(m_pDebugSequenceParam);
}
}
else
{
m_uiDebugSequenceIndex = 0;
}
}
}
}
return true;
}
void CInput::ClearJoypadValues(JOYPAD *pThisPad)
{
pThisPad->m_uiButtonsPressed = 0;
pThisPad->m_uiButtonsReleased = 0;
pThisPad->m_uiButtons = 0;
pThisPad->m_ucLeftTriggerState = 0;
pThisPad->m_ucRightTriggerState = 0;
pThisPad->m_iRightThumbX = 0;
pThisPad->m_iRightThumbY = 0;
pThisPad->m_iLeftThumbX = 0;
pThisPad->m_iLeftThumbY = 0;
pThisPad->m_iNormalizedLeftThumbX = 0;
pThisPad->m_iNormalizedLeftThumbY = 0;
pThisPad->m_iNormalizedRightThumbX = 0;
pThisPad->m_iNormalizedRightThumbY = 0;
pThisPad->m_fNormalizedLeftThumbX = 0.0f;
pThisPad->m_fNormalizedLeftThumbY = 0.0f;
pThisPad->m_fNormalizedRightThumbX = 0.0f;
pThisPad->m_fNormalizedRightThumbY = 0.0f;
}
void CInput::InitTime(void)
{
LARGE_INTEGER qwTicksPerSec;
QueryPerformanceFrequency(&qwTicksPerSec);
m_fTickToSeconds = 1.0 / (float)(int)qwTicksPerSec.LowPart;
for (int i = 0; i < MAX_JOYPADS; i++)
{
m_LastActivityTime[i].QuadPart = 0;
}
}
void CInput::GetStartTime(int iPad, int iKey)
{
QueryPerformanceCounter(&m_Timers[iPad][iKey].m_qwStartTime);
m_Timers[iPad][iKey].m_qwTotalHoldTicks.QuadPart = 0;
m_Timers[iPad][iKey].m_fTotalHoldTime = 0;
m_Timers[iPad][iKey].m_fLastRepeatTime = 0;
m_Timers[iPad][iKey].m_bInitialPressHandled = false;
m_LastActivityTime[iPad].QuadPart = m_Timers[iPad][iKey].m_qwStartTime.QuadPart;
}
void CInput::UpdateTime(int iPad, int iKey)
{
LARGE_INTEGER qwDeltaTime;
QueryPerformanceCounter(&qwDeltaTime);
uint64_t qwNewTime = qwDeltaTime.QuadPart - m_Timers[iPad][iKey].m_qwStartTime.QuadPart;
m_Timers[iPad][iKey].m_qwTotalHoldTicks.QuadPart += qwNewTime;
m_Timers[iPad][iKey].m_qwStartTime = qwDeltaTime;
m_Timers[iPad][iKey].m_fTotalHoldTime = m_Timers[iPad][iKey].m_fTotalHoldTime + (m_fTickToSeconds * qwNewTime);
m_LastActivityTime[iPad].QuadPart = m_Timers[iPad][iKey].m_qwStartTime.QuadPart;
}
@@ -0,0 +1,25 @@
/*
MIT License
Copyright (c) 2026 Patoke
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "INP_StringCheck.h"
+126
View File
@@ -0,0 +1,126 @@
/*
MIT License
Copyright (c) 2026 Patoke
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "LinkedList.h"
LinkedList::LinkedList()
{
this->m_NodeC = 0;
this->m_Head = nullptr;
this->m_Tail = nullptr;
}
void LinkedList::AddToHead(void *pvData)
{
_LL_NODE *pNode = new _LL_NODE();
pNode->m_pvData = pvData;
if (!m_Tail)
{
m_Tail = pNode;
}
if (m_Head)
{
m_Head->m_Prev = pNode;
pNode->m_Next = m_Head;
}
m_Head = pNode;
m_NodeC++;
}
void LinkedList::AddToTail(void *pvData)
{
_LL_NODE *pNode = new _LL_NODE();
pNode->m_pvData = pvData;
if (!m_Head)
{
m_Head = pNode;
}
if (m_Tail)
{
m_Tail->m_Next = pNode;
pNode->m_Prev = m_Tail;
}
pNode->m_Next = nullptr;
pNode->m_Prev = m_Tail;
m_Tail = pNode;
m_NodeC++;
}
void LinkedList::RemoveNode(_LL_NODE *pNodeToRemove)
{
_LL_NODE *pCurrentNode;
for (pCurrentNode = m_Head; pCurrentNode != pNodeToRemove; pCurrentNode = pCurrentNode->m_Next)
{
;
}
if (pCurrentNode == m_Head)
{
m_Head = m_Head->m_Next;
}
else
{
pCurrentNode->m_Prev->m_Next = pCurrentNode->m_Next;
if (pCurrentNode->m_Next)
{
pCurrentNode->m_Next->m_Prev = pCurrentNode->m_Prev;
}
}
m_NodeC--;
}
LinkedList::_LL_NODE *LinkedList::RemoveHeadNode()
{
_LL_NODE *pHeadNode = m_Head;
if (m_NodeC > 0)
{
m_Head = m_Head->m_Next;
m_NodeC--;
}
return pHeadNode;
}
void LinkedList::ClearList()
{
while (true)
{
_LL_NODE *pHeadNode = RemoveHeadNode();
if (!pHeadNode)
{
break;
}
delete pHeadNode;
}
}
+25
View File
@@ -0,0 +1,25 @@
/*
MIT License
Copyright (c) 2026 Patoke
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "stdafx.h"