Day 17 complete

This commit is contained in:
Edward R. Gonzalez 2023-09-22 02:16:40 -04:00
parent 100cf96d4f
commit 5902aec2bf
9 changed files with 502 additions and 300 deletions

43
.vscode/settings.json vendored
View File

@ -33,7 +33,48 @@
"mutex": "cpp", "mutex": "cpp",
"system_error": "cpp", "system_error": "cpp",
"ios": "cpp", "ios": "cpp",
"xiosbase": "cpp" "xiosbase": "cpp",
"atomic": "cpp",
"bitset": "cpp",
"charconv": "cpp",
"forward_list": "cpp",
"fstream": "cpp",
"istream": "cpp",
"map": "cpp",
"ostream": "cpp",
"sstream": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"thread": "cpp",
"unordered_map": "cpp",
"xlocale": "cpp",
"xlocinfo": "cpp",
"xtree": "cpp",
"bit": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"condition_variable": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"locale": "cpp",
"new": "cpp",
"stdexcept": "cpp",
"typeinfo": "cpp",
"xfacet": "cpp",
"xlocbuf": "cpp",
"xlocmes": "cpp",
"xlocmon": "cpp",
"xlocnum": "cpp",
"xloctime": "cpp"
}, },
"C_Cpp.intelliSenseEngineFallback": "disabled", "C_Cpp.intelliSenseEngineFallback": "disabled",
"C_Cpp.errorSquiggles": "enabled", "C_Cpp.errorSquiggles": "enabled",

13
docs/Day 017.md Normal file
View File

@ -0,0 +1,13 @@
# Day 17
Talks about functional programming. Mostly an emphasis of not abusing global state fields or constricting the interface a state may be musted from. With the 'ideal' if performance is not heavily impacted is to use a pure function.
Like I said in Day 14 however I do want to setup a less stack-spam way to pass around data for ergonomics, so instead I'll be using static analysis with gencpp to make sure they are only used in the correct places (there will be a list of function names that are allowed to use the global state, and if it is used in any other function it will throw an error, preventing handmade from compiling).
I wish Casey used the `GetAsyncKeyState` instead of this window messaging.
(I'll be using it, not a fan of getting input callbacks from the window)
I didn't do iteration accross all controllers, I'll worry about that when I setup multiple players.
When it comes to the "controller stick averaging" and abstracting that to actions (like he did) hes bleeding into what should really be an input system with bounded actions, but he doesn't want to make an input system (so its just rapid hardcoding).
I'll do the averaging on the platform layer (for now) since it simple, but like said previously, I will not be allowing the engine layer to abstract what API devices are assigned to a "controller".

View File

@ -141,10 +141,11 @@ void update_and_render( InputState* input, OffscreenBuffer* back_buffer, SoundBu
#endif #endif
EngineState* state = rcast( EngineState*, memory->Persistent ); EngineState* state = rcast( EngineState*, memory->Persistent );
do_once_start do_once_start
assert( sizeof(EngineState) <= memory->PersistentSize ); assert( sizeof(EngineState) <= memory->PersistentSize );
state->ToneVolume = 3000; state->ToneVolume = 1000;
state->WaveToneHz = 262; state->WaveToneHz = 262;
state->WavePeriod = sound_buffer->SamplesPerSecond / state->WaveToneHz; state->WavePeriod = sound_buffer->SamplesPerSecond / state->WaveToneHz;
@ -168,127 +169,107 @@ void update_and_render( InputState* input, OffscreenBuffer* back_buffer, SoundBu
ControllerState* controller = & input->Controllers[0]; ControllerState* controller = & input->Controllers[0];
// Abstracting the actionables as booleans and processing within this scope
// for now until proper callbacks for input bindings are setup.
b32 move_up = false;
b32 move_down = false;
b32 move_left = false;
b32 move_right = false;
b32 action_up = false;
b32 action_down = false;
b32 action_left = false;
b32 action_right = false;
f32 analog_threshold = 0.5f;
b32 raise_volume = false;
b32 lower_volume = false;
b32 raise_tone_hz = false;
b32 lower_tone_hz = false;
b32 toggle_wave_tone = false;
if ( controller->DSPad ) if ( controller->DSPad )
{ {
DualsensePadState* pad = controller->DSPad; DualsensePadState* pad = controller->DSPad;
x_offset += pad->DPad.Right.State; move_right |= pad->DPad.Right.EndedDown || pad->Stick.Left.X.End > analog_threshold;
x_offset -= pad->DPad.Left.State; move_left |= pad->DPad.Left.EndedDown || pad->Stick.Left.X.End < -analog_threshold;
y_offset += pad->DPad.Down.State; move_up |= pad->DPad.Up.EndedDown || pad->Stick.Left.Y.End > analog_threshold;
y_offset -= pad->DPad.Up.State; move_down |= pad->DPad.Down.EndedDown || pad->Stick.Left.Y.End < -analog_threshold;
x_offset += scast(u32, pad->Stick.Left.X.End); raise_volume |= pad->Triangle.EndedDown;
y_offset += scast(u32, pad->Stick.Left.Y.End); lower_volume |= pad->Circle.EndedDown;
if ( pad->Triangle.State ) raise_tone_hz |= pad->Square.EndedDown;
{ lower_tone_hz |= pad->X.EndedDown;
state->ToneVolume += 10;
}
if ( pad->Circle.State )
{
state->ToneVolume -= 10;
}
if ( pad->Square.State ) toggle_wave_tone |= pad->Options.EndedDown;
{
state->WaveToneHz += 1;
state->WavePeriod = sound_buffer->SamplesPerSecond / state->WaveToneHz;
}
if ( pad->X.State )
{
state->WaveToneHz -= 1;
state->WavePeriod = sound_buffer->SamplesPerSecond / state->WaveToneHz;
}
if ( pad->Options.State )
{
wave_switch ^= true;
}
if ( pad->Share.State )
{
// TODO(Ed) : Add rumble test
}
} }
if ( controller->XPad ) if ( controller->XPad )
{ {
XInputPadState* pad = controller->XPad; XInputPadState* pad = controller->XPad;
x_offset += pad->DPad.Right.State; move_right |= pad->DPad.Right.EndedDown || pad->Stick.Left.X.End > analog_threshold;
x_offset -= pad->DPad.Left.State; move_left |= pad->DPad.Left.EndedDown || pad->Stick.Left.X.End < -analog_threshold;
y_offset -= pad->DPad.Down.State; move_up |= pad->DPad.Up.EndedDown || pad->Stick.Left.Y.End > analog_threshold;
y_offset += pad->DPad.Up.State; move_down |= pad->DPad.Down.EndedDown || pad->Stick.Left.Y.End < -analog_threshold;
x_offset += scast(u32, pad->Stick.Left.X.End); raise_volume |= pad->Y.EndedDown;
y_offset += scast(u32, pad->Stick.Left.Y.End); lower_volume |= pad->B.EndedDown;
if ( pad->Y.State ) raise_tone_hz |= pad->X.EndedDown;
{ lower_tone_hz |= pad->A.EndedDown;
state->ToneVolume += 10;
}
if ( pad->B.State )
{
state->ToneVolume -= 10;
}
if ( pad->X.State ) toggle_wave_tone |= pad->Start.EndedDown;
{
state->WaveToneHz += 1;
state->WavePeriod = sound_buffer->SamplesPerSecond / state->WaveToneHz;
}
if ( pad->A.State )
{
state->WaveToneHz -= 1;
state->WavePeriod = sound_buffer->SamplesPerSecond / state->WaveToneHz;
}
if ( pad->Start.State )
{
wave_switch ^= true;
}
if ( pad->Back.State )
{
// TODO(Ed) : Add rumble test
}
} }
if ( controller->Keyboard ) if ( controller->Keyboard )
{ {
KeyboardState* keyboard = controller->Keyboard; KeyboardState* keyboard = controller->Keyboard;
x_offset += keyboard->D.State; move_right |= keyboard->D.EndedDown;
x_offset -= keyboard->A.State; move_left |= keyboard->A.EndedDown;
y_offset += keyboard->W.State; move_up |= keyboard->W.EndedDown;
y_offset -= keyboard->S.State; move_down |= keyboard->S.EndedDown;
if ( keyboard->Esc.State ) raise_volume |= keyboard->Up.EndedDown;
{ lower_volume |= keyboard->Down.EndedDown;
// TODO : Add exit game
}
if ( keyboard->Space.State ) raise_tone_hz |= keyboard->Right.EndedDown;
{ lower_tone_hz |= keyboard->Left.EndedDown;
wave_switch ^= true;
}
if ( keyboard->Up.State ) toggle_wave_tone |= keyboard->Space.EndedDown;
{ }
state->ToneVolume += 10;
} x_offset += move_right;
if ( keyboard->Down.State ) x_offset -= move_left;
{ y_offset += move_down;
state->ToneVolume -= 10; y_offset -= move_up;
}
if ( keyboard->Left.State ) if ( raise_volume )
{ {
state->WaveToneHz -= 1; state->ToneVolume += 10;
state->WavePeriod = sound_buffer->SamplesPerSecond / state->WaveToneHz; }
} if ( lower_volume )
if ( keyboard->Right.State ) {
{ state->ToneVolume -= 10;
state->WaveToneHz += 1; }
state->WavePeriod = sound_buffer->SamplesPerSecond / state->WaveToneHz;
} if ( raise_tone_hz )
{
state->WaveToneHz += 1;
state->WavePeriod = sound_buffer->SamplesPerSecond / state->WaveToneHz;
}
if ( lower_tone_hz )
{
state->WaveToneHz -= 1;
state->WavePeriod = sound_buffer->SamplesPerSecond / state->WaveToneHz;
}
if ( toggle_wave_tone )
{
wave_switch ^= true;
} }
// TODO(Ed) : Allow sample offsets here for more robust platform options // TODO(Ed) : Allow sample offsets here for more robust platform options

View File

@ -56,7 +56,7 @@ struct SoundBuffer
struct DigitalBtn struct DigitalBtn
{ {
s32 HalfTransitions; s32 HalfTransitions;
b32 State; b32 EndedDown;
}; };
#define DigitalBtn_Up 0 #define DigitalBtn_Up 0
#define DigitalBtn_Down 1 #define DigitalBtn_Down 1
@ -67,6 +67,9 @@ struct AnalogAxis
f32 End; f32 End;
f32 Min; f32 Min;
f32 Max; f32 Max;
// Platform doesn't provide this, we process in the engine layer.
f32 Average;
}; };
struct AnalogStick struct AnalogStick
@ -75,20 +78,24 @@ struct AnalogStick
AnalogAxis Y; AnalogAxis Y;
}; };
struct KeyboardState union KeyboardState
{ {
DigitalBtn Q; DigitalBtn Keys[12];
DigitalBtn E; struct {
DigitalBtn W; DigitalBtn Q;
DigitalBtn A; DigitalBtn E;
DigitalBtn S; DigitalBtn W;
DigitalBtn D; DigitalBtn A;
DigitalBtn Esc; DigitalBtn S;
DigitalBtn Up; DigitalBtn D;
DigitalBtn Down; DigitalBtn Escape;
DigitalBtn Left; DigitalBtn Backspace;
DigitalBtn Right; DigitalBtn Up;
DigitalBtn Space; DigitalBtn Down;
DigitalBtn Left;
DigitalBtn Right;
DigitalBtn Space;
};
}; };
struct MousesState struct MousesState
@ -128,11 +135,6 @@ struct XInputPadState
DigitalBtn RightShoulder; DigitalBtn RightShoulder;
}; };
}; };
b32 using_analog()
{
return true;
};
}; };
struct DualsensePadState struct DualsensePadState
@ -165,11 +167,6 @@ struct DualsensePadState
DigitalBtn R1; DigitalBtn R1;
}; };
}; };
b32 using_analog()
{
return true;
};
}; };
struct ControllerState struct ControllerState
@ -185,10 +182,76 @@ struct InputState
ControllerState Controllers[4]; ControllerState Controllers[4];
}; };
b32 input_using_analog(); using InputBindCallback = void( void* );
using InputBindCallback_DigitalBtn = void( engine::DigitalBtn* Button );
using InputBindCallback_AnalogAxis = void( engine::AnalogAxis* Axis );
using InputBindCallback_AnalogStick = void( engine::AnalogStick* Stick );
struct InputMode
{
InputBindCallback* Binds;
s32 NumBinds;
char _PAD_[4];
};
void input_mode_pop( InputMode* mode );
void input_mode_pop( InputMode* mode );
// Needs a contextual reference to four things: // Needs a contextual reference to four things:
// Timing, Input, Bitmap Buffer, Sound Buffer // Timing, Input, Bitmap Buffer, Sound Buffer
void update_and_render( InputState* input, OffscreenBuffer* back_buffer, SoundBuffer* sound_buffer, Memory* memory ); void update_and_render( InputState* input, OffscreenBuffer* back_buffer, SoundBuffer* sound_buffer, Memory* memory );
NS_ENGINE_END NS_ENGINE_END
// TODO(Ed) : Move this to handmade game layer later.
#define NS_HANDMADE_BEGIN namespace handmade {
#define NS_HANDMADE_END }
NS_HANDMADE_BEGIN
// We want a 'binding' to have multiple binds to active it (most likely)
struct Actionable
{
char const* Name;
engine::InputBindCallback* Binds;
s32 NumBinds;
char _PAD_[4];
};
struct ActionableMode
{
};
/*
Platform Layer:
Controller : Keyboard & Mouse, XPad, DSPad
---VV---
Engine Layer:
InputBinding callbacks (per-game-logic frame basis)
Push/Pop input modes (binding sets)
---VV---
Game Layer:
Actionables : Binding Sets where a raw input, or input interpretation leads to an player action.
ActionSet : Actionables.Push/Pop -> Input.Push/Pop ?
Player : Controller, Actionables, ActionSets
*/
struct Player
{
// So far just has an assigned controller.
engine::ControllerState* Controller;
// Possilby some other stuff in the future.
};
NS_HANDMADE_END

View File

@ -16,3 +16,4 @@ int gen_main()
return 0; return 0;
} }
#endif #endif

View File

@ -29,6 +29,7 @@
#endif #endif
#include <math.h> // TODO : Implement math ourselves #include <math.h> // TODO : Implement math ourselves
#include <stdio.h>
#include "engine.cpp" #include "engine.cpp"
@ -188,6 +189,60 @@ b32 debug_file_write_content( char* file_path, u32 content_size, void* content_m
} }
#endif #endif
internal void
input_process_digital_btn( engine::DigitalBtn* old_state, engine::DigitalBtn* new_state, u32 raw_btns, u32 btn_flag )
{
#define had_transition() ( old_state->EndedDown == new_state->EndedDown )
new_state->EndedDown = (raw_btns & btn_flag) > 0;
new_state->HalfTransitions = had_transition() ? 1 : 0;
#undef had_transition
}
internal f32
xinput_process_axis_value( s16 value, s16 deadzone_threshold )
{
f32 result = 0;
if ( value < -deadzone_threshold )
{
result = scast(f32, value + deadzone_threshold) / (32768.0f - scast(f32, deadzone_threshold));
}
else if ( value > deadzone_threshold )
{
result = scast(f32, value + deadzone_threshold) / (32767.0f - scast(f32, deadzone_threshold));
}
return result;
}
internal f32
input_process_axis_value( f32 value, f32 deadzone_threshold )
{
f32 result = 0;
if ( value < -deadzone_threshold )
{
result = (value + deadzone_threshold ) / (1.0f - deadzone_threshold );
if (result < -1.0f)
result = -1.0f; // Clamp to ensure it doesn't go below -1
}
else if ( value > deadzone_threshold )
{
result = (value - deadzone_threshold ) / (1.0f - deadzone_threshold );
if (result > 1.0f)
result = 1.0f; // Clamp to ensure it doesn't exceed 1
}
return result;
}
internal void
input_process_keyboard_key( engine::DigitalBtn* key, b32 is_down )
{
// This assert fails all the time, have no idea why. I'm just going to use GetAsyncKeyState instead, using the messaging events is horrible.
// assert( key->EndedDown != is_down )
key->EndedDown = is_down;
key->HalfTransitions += is_down;
}
internal void internal void
init_sound(HWND window_handle, s32 samples_per_second, s32 buffer_size ) init_sound(HWND window_handle, s32 samples_per_second, s32 buffer_size )
{ {
@ -487,19 +542,115 @@ main_window_callback(
} }
internal void internal void
input_process_digital_btn( engine::DigitalBtn* old_state, engine::DigitalBtn* new_state, u32 raw_btns, u32 btn_flag ) process_pending_window_messages( engine::KeyboardState* keyboard )
{ {
#define had_transition() ( old_state->State == new_state->State ) MSG window_msg_info;
new_state->State = (raw_btns & btn_flag); while ( PeekMessageA( & window_msg_info, 0, 0, 0, PM_Remove_Messages_From_Queue ) )
new_state->HalfTransitions = had_transition() ? 1 : 0; {
#undef had_transition if ( window_msg_info.message == WM_QUIT )
} {
OutputDebugStringA("WM_QUIT\n");
Running = false;
}
internal void // Keyboard input handling
input_process_keyboard_key( engine::DigitalBtn* key, b32 is_down ) switch (window_msg_info.message)
{ {
key->State = is_down; // I rather do this with GetAsyncKeyState...
key->HalfTransitions += is_down; case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
#if 0
case WM_KEYDOWN:
case WM_KEYUP:
#endif
{
WPARAM vk_code = window_msg_info.wParam;
b32 is_down = scast(b32, (window_msg_info.lParam >> 31) == 0 );
b32 was_down = scast(b32, (window_msg_info.lParam >> 30) );
b32 alt_down = scast(b32, (window_msg_info.lParam & (1 << 29)) );
switch ( vk_code )
{
#if 0
case 'Q':
{
input_process_keyboard_key( & keyboard->Q, is_down );
}
break;
case 'E':
{
input_process_keyboard_key( & keyboard->E, is_down );
}
break;
case 'W':
{
input_process_keyboard_key( & keyboard->W, is_down );
}
break;
case 'A':
{
input_process_keyboard_key( & keyboard->A, is_down );
}
break;
case 'S':
{
input_process_keyboard_key( & keyboard->S, is_down );
}
break;
case 'D':
{
input_process_keyboard_key( & keyboard->D, is_down );
}
break;
case VK_ESCAPE:
{
input_process_keyboard_key( & keyboard->Escape, is_down );
}
break;
case VK_BACK:
input_process_keyboard_key( & keyboard->Backspace, is_down );
break;
case VK_UP:
{
input_process_keyboard_key( & keyboard->Up, is_down );
}
break;
case VK_DOWN:
{
input_process_keyboard_key( & keyboard->Down, is_down );
}
break;
case VK_LEFT:
{
input_process_keyboard_key( & keyboard->Left, is_down );
}
break;
case VK_RIGHT:
{
input_process_keyboard_key( & keyboard->Right, is_down );
}
break;
case VK_SPACE:
{
input_process_keyboard_key( & keyboard->Space, is_down );
}
break;
#endif
case VK_F4:
{
if ( alt_down )
Running = false;
}
break;
}
}
break;
default:
TranslateMessage( & window_msg_info );
DispatchMessageW( & window_msg_info );
}
}
} }
NS_PLATFORM_END NS_PLATFORM_END
@ -561,7 +712,6 @@ WinMain(
WNDCLASSW window_class {}; WNDCLASSW window_class {};
HWND window_handle = nullptr; HWND window_handle = nullptr;
MSG window_msg_info;
{ {
window_class.style = CS_Horizontal_Redraw | CS_Vertical_Redraw; window_class.style = CS_Horizontal_Redraw | CS_Vertical_Redraw;
window_class.lpfnWndProc = main_window_callback; window_class.lpfnWndProc = main_window_callback;
@ -635,17 +785,18 @@ WinMain(
engine::InputState input {}; engine::InputState input {};
engine::KeyboardState keyboard; engine::KeyboardState keyboard_states[2] {};
input.Controllers[0].Keyboard = & keyboard; engine::KeyboardState* old_keyboard = & keyboard_states[0];
engine::KeyboardState* new_keyboard = & keyboard_states[1];
// Important: Assuming keyboard always connected for now, and assigning to first controller. // Important: Assuming keyboard always connected for now, and assigning to first controller.
using EngineXInputPadStates = engine::XInputPadState[ Max_Controllers ]; using EngineXInputPadStates = engine::XInputPadState[ Max_Controllers ];
EngineXInputPadStates xpad_states[2]; EngineXInputPadStates xpad_states[2] {};
EngineXInputPadStates* old_xpads = & xpad_states[0]; EngineXInputPadStates* old_xpads = & xpad_states[0];
EngineXInputPadStates* new_xpads = & xpad_states[1]; EngineXInputPadStates* new_xpads = & xpad_states[1];
using EngineDSPadStates = engine::DualsensePadState[Max_Controllers]; using EngineDSPadStates = engine::DualsensePadState[Max_Controllers];
EngineDSPadStates ds_pad_states[2]; EngineDSPadStates ds_pad_states[2] {};
EngineDSPadStates* old_ds_pads = & ds_pad_states[0]; EngineDSPadStates* old_ds_pads = & ds_pad_states[0];
EngineDSPadStates* new_ds_pads = & ds_pad_states[1]; EngineDSPadStates* new_ds_pads = & ds_pad_states[1];
@ -684,116 +835,50 @@ WinMain(
Running = true; Running = true;
while( Running ) while( Running )
{ {
keyboard = {}; // Handeled properly in the input section.
#if 0
// Window Management swap( old_keyboard, new_keyboard );
*new_keyboard = {};
for ( u32 key_index = 0; key_index < array_count( new_keyboard->Keys ); ++ key_index )
{ {
while ( PeekMessageW( & window_msg_info, 0, 0, 0, PM_Remove_Messages_From_Queue ) ) engine::DigitalBtn* old_key = & old_keyboard->Keys[ key_index ];
{ engine::DigitalBtn* new_key = & new_keyboard->Keys[ key_index ];
if ( window_msg_info.message == WM_QUIT )
{
OutputDebugStringA("WM_QUIT\n");
Running = false;
}
new_key->EndedDown = old_key->EndedDown;
// Keyboard input handling
switch (window_msg_info.message)
{
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_KEYDOWN:
case WM_KEYUP:
{
WPARAM vk_code = window_msg_info.wParam;
b32 is_down = scast(b32, (window_msg_info.lParam >> 31) == 0 );
b32 was_down = scast(b32, (window_msg_info.lParam >> 30) );
b32 alt_down = scast(b32, (window_msg_info.lParam & (1 << 29)) );
switch ( vk_code )
{
case 'Q':
{
input_process_keyboard_key( & keyboard.Q, is_down );
}
break;
case 'E':
{
input_process_keyboard_key( & keyboard.E, is_down );
}
break;
case 'W':
{
input_process_keyboard_key( & keyboard.W, is_down );
}
break;
case 'A':
{
input_process_keyboard_key( & keyboard.A, is_down );
}
break;
case 'S':
{
input_process_keyboard_key( & keyboard.S, is_down );
}
break;
case 'D':
{
input_process_keyboard_key( & keyboard.D, is_down );
}
break;
case VK_ESCAPE:
{
input_process_keyboard_key( & keyboard.Esc, is_down );
}
break;
case VK_UP:
{
input_process_keyboard_key( & keyboard.Up, is_down );
}
break;
case VK_DOWN:
{
input_process_keyboard_key( & keyboard.Down, is_down );
}
break;
case VK_LEFT:
{
input_process_keyboard_key( & keyboard.Left, is_down );
}
break;
case VK_RIGHT:
{
input_process_keyboard_key( & keyboard.Right, is_down );
}
break;
case VK_SPACE:
{
input_process_keyboard_key( & keyboard.Space, is_down );
}
break;
case VK_F4:
{
if ( alt_down )
Running = false;
}
break;
}
}
break;
default:
TranslateMessage( & window_msg_info );
DispatchMessageW( & window_msg_info );
}
}
} }
#endif
process_pending_window_messages( new_keyboard );
input.Controllers[0].Keyboard = new_keyboard;
// printf("Q- Old: %d, New: %d\n", old_keyboard->Q.EndedDown, new_keyboard->Q.EndedDown);
printf("Q- HTOld: %d, HTNew: %d\n", old_keyboard->Q.HalfTransitions, new_keyboard->Q.HalfTransitions);
// Input // Input
// TODO(Ed) : Setup user definable deadzones for triggers and sticks.
{ {
// Swapping at the beginning of the input frame instead of the end. // Swapping at the beginning of the input frame instead of the end.
swap( old_xpads, new_xpads ); swap( old_keyboard, new_keyboard );
swap( old_ds_pads, new_ds_pads ); swap( old_xpads, new_xpads );
swap( old_ds_pads, new_ds_pads );
// Keyboard Polling
{
constexpr u32 is_down = 0x8000;
input_process_digital_btn( & old_keyboard->Q, & new_keyboard->Q, GetAsyncKeyState( 'Q' ), is_down );
input_process_digital_btn( & old_keyboard->E, & new_keyboard->E, GetAsyncKeyState( 'E' ), is_down );
input_process_digital_btn( & old_keyboard->W, & new_keyboard->W, GetAsyncKeyState( 'W' ), is_down );
input_process_digital_btn( & old_keyboard->A, & new_keyboard->A, GetAsyncKeyState( 'A' ), is_down );
input_process_digital_btn( & old_keyboard->S, & new_keyboard->S, GetAsyncKeyState( 'S' ), is_down );
input_process_digital_btn( & old_keyboard->D, & new_keyboard->D, GetAsyncKeyState( 'D' ), is_down );
input_process_digital_btn( & old_keyboard->Escape, & new_keyboard->Escape, GetAsyncKeyState( VK_ESCAPE ), is_down );
input_process_digital_btn( & old_keyboard->Backspace, & new_keyboard->Backspace, GetAsyncKeyState( VK_BACK ), is_down );
input_process_digital_btn( & old_keyboard->Up, & new_keyboard->Up, GetAsyncKeyState( VK_UP ), is_down );
input_process_digital_btn( & old_keyboard->Down, & new_keyboard->Down, GetAsyncKeyState( VK_DOWN ), is_down );
input_process_digital_btn( & old_keyboard->Left, & new_keyboard->Left, GetAsyncKeyState( VK_LEFT ), is_down );
input_process_digital_btn( & old_keyboard->Right, & new_keyboard->Right, GetAsyncKeyState( VK_RIGHT ), is_down );
input_process_digital_btn( & old_keyboard->Space, & new_keyboard->Space, GetAsyncKeyState( VK_SPACE ), is_down );
}
// XInput Polling // XInput Polling
// TODO(Ed) : Should we poll this more frequently? // TODO(Ed) : Should we poll this more frequently?
@ -826,46 +911,16 @@ WinMain(
new_xpad->Stick.Left.X.Start = old_xpad->Stick.Left.X.End; new_xpad->Stick.Left.X.Start = old_xpad->Stick.Left.X.End;
new_xpad->Stick.Left.Y.Start = old_xpad->Stick.Left.Y.End; new_xpad->Stick.Left.Y.Start = old_xpad->Stick.Left.Y.End;
// TODO(Ed) : Compress this into a proc f32 left_x = xinput_process_axis_value( xpad->sThumbLX, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE );
f32 X; f32 left_y = xinput_process_axis_value( xpad->sThumbLY, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE );
if ( xpad->sThumbLX < 0 )
{
X = scast(f32, xpad->sThumbLX) / scast(f32, -S16_MIN);
}
else
{
X = scast(f32, xpad->sThumbLX) / scast(f32, S16_MAX);
}
// TODO(Ed) : Min/Max macros!!! // TODO(Ed) : Min/Max macros!!!
new_xpad->Stick.Left.X.Min = new_xpad->Stick.Left.X.Max = new_xpad->Stick.Left.X.End = X; new_xpad->Stick.Left.X.Min = new_xpad->Stick.Left.X.Max = new_xpad->Stick.Left.X.End = left_x;
new_xpad->Stick.Left.Y.Min = new_xpad->Stick.Left.Y.Max = new_xpad->Stick.Left.Y.End = left_y;
f32 Y; // TODO(Ed): Make this actually an average for later
if ( xpad->sThumbLY < 0 ) new_xpad->Stick.Left.X.Average = left_x;
{ new_xpad->Stick.Left.Y.Average = left_y;
Y = scast(f32, xpad->sThumbLY) / scast(f32, -S16_MIN);
}
else
{
Y = scast(f32, xpad->sThumbLY) / scast(f32, S16_MAX);
}
// TODO(Ed) : Min/Max macros!!!
new_xpad->Stick.Left.Y.Min = new_xpad->Stick.Left.Y.Max = new_xpad->Stick.Left.Y.End = Y;
// epad->Stick.Left.X.End = xpad->sThumbLX;
// epad->Stick.Left.Y.End = xpad->sThumbLY;
// epad->Stick.Right.X.End = xpad->sThumbRX;
// epad->Stick.Right.X.End = xpad->sThumbRY;
// TODO(Ed) : Dead zone processing!!!!!!!!!!!!!!!
// XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE
// XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE
// S16_MAX
// S16_MIN
input.Controllers[ controller_index ].XPad = new_xpad; input.Controllers[ controller_index ].XPad = new_xpad;
} }
@ -888,7 +943,7 @@ WinMain(
if ( jsl_device_index > 4 ) if ( jsl_device_index > 4 )
break; break;
JOY_SHOCK_STATE state = JslGetSimpleState( jsl_device_handles[ jsl_device_index ] ); JOY_SHOCK_STATE state = JslGetSimpleState( jsl_device_handles[ jsl_device_index ] );
engine::DualsensePadState* old_ds_pad = old_ds_pads[ jsl_device_index ]; engine::DualsensePadState* old_ds_pad = old_ds_pads[ jsl_device_index ];
engine::DualsensePadState* new_ds_pad = new_ds_pads[ jsl_device_index ]; engine::DualsensePadState* new_ds_pad = new_ds_pads[ jsl_device_index ];
@ -908,10 +963,20 @@ WinMain(
input_process_digital_btn( & old_ds_pad->L1, & new_ds_pad->L1, state.buttons, JSMASK_L ); input_process_digital_btn( & old_ds_pad->L1, & new_ds_pad->L1, state.buttons, JSMASK_L );
input_process_digital_btn( & old_ds_pad->R1, & new_ds_pad->R1, state.buttons, JSMASK_R ); input_process_digital_btn( & old_ds_pad->R1, & new_ds_pad->R1, state.buttons, JSMASK_R );
// epad->Stick.Left.X.End = state.stickLX; new_ds_pad->Stick.Left.X.Start = old_ds_pad->Stick.Left.X.End;
// epad->Stick.Left.Y.End = state.stickLY; new_ds_pad->Stick.Left.Y.Start = old_ds_pad->Stick.Left.Y.End;
// epad->Stick.Right.X.End = state.stickRX;
// epad->Stick.Right.X.End = state.stickRY; // Joyshock abstracts the sticks to a float value already for us of -1.f to 1.f.
// We'll assume a deadzone of 10% for now.
f32 left_x = input_process_axis_value( state.stickLX, 0.1f );
f32 left_y = input_process_axis_value( state.stickLY, 0.1f );
new_ds_pad->Stick.Left.X.Min = new_ds_pad->Stick.Left.X.Max = new_ds_pad->Stick.Left.X.End = left_x;
new_ds_pad->Stick.Left.Y.Min = new_ds_pad->Stick.Left.Y.Max = new_ds_pad->Stick.Left.Y.End = left_y;
// TODO(Ed): Make this actually an average for later
new_ds_pad->Stick.Left.X.Average = left_x;
new_ds_pad->Stick.Left.Y.Average = left_y;
input.Controllers[ jsl_device_index ].DSPad = new_ds_pad; input.Controllers[ jsl_device_index ].DSPad = new_ds_pad;
} }

View File

@ -52,9 +52,9 @@
#if Build_Development #if Build_Development
# define assert( expression ) \ # define assert( expression ) \
if ( !( expression ) ) \ if ( !( expression ) ) \
{ \ { \
*( int* )0 = 0; \ __debugbreak(); \
} }
// platform::assertion_failure( __FILE__, __LINE__, #expression ); // platform::assertion_failure( __FILE__, __LINE__, #expression );
#else #else
@ -67,3 +67,41 @@
#define ensure( condition, expression ) #define ensure( condition, expression )
#define fatal( message ) #define fatal( message )
#endif #endif
// Just experimenting with a way to check for global variables being accessed from the wrong place.
// (Could also be done with gencpp technically)
#if 0
enum class EGlobalVarsAllowFuncs
{
ProcessPendingWindowMessages,
Num,
Invalid,
};
EGlobalVarsAllowFuncs to_type( char const* proc_name )
{
char const* global_vars_allowed_funcs[] {
"process_pending_window_messages"
};
if ( proc_name )
{
for ( u32 idx = 0; idx < array_count( global_vars_allowed_funcs ); ++idx )
{
if ( strcmp( proc_name, global_vars_allowed_funcs[idx] ) == 0 )
{
return scast( EGlobalVarsAllowFuncs, idx );
}
}
}
return EGlobalVarsAllowFuncs::Invalid;
}
#if Build_Development
# define checked_global_getter( global_var, procedure ) \
( ensure( to_type(procedure) != EGlobalVarsAllowFuncs::Invalid), global_var )
#else
# define checked_global_getter( global_var, procedure ) global_var
#endif
#endif

View File

@ -12,7 +12,7 @@
#pragma warning( disable: 4189 ) // Support for unused variables #pragma warning( disable: 4189 ) // Support for unused variables
#pragma warning( disable: 4514 ) // Support for unused inline functions #pragma warning( disable: 4514 ) // Support for unused inline functions
#pragma warning( disable: 4505 ) // Support for unused static functions #pragma warning( disable: 4505 ) // Support for unused static functions
#pragma warning( disable: 5045 ) // Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified #pragma warning( disable: 5045 ) // Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified
#include "grime.h" #include "grime.h"
#include "macros.h" #include "macros.h"

Binary file not shown.