mirror of
https://github.com/Ed94/HandmadeHero.git
synced 2024-12-22 06:14:45 -08:00
Day 17 complete
This commit is contained in:
parent
100cf96d4f
commit
5902aec2bf
43
.vscode/settings.json
vendored
43
.vscode/settings.json
vendored
@ -33,7 +33,48 @@
|
||||
"mutex": "cpp",
|
||||
"system_error": "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.errorSquiggles": "enabled",
|
||||
|
13
docs/Day 017.md
Normal file
13
docs/Day 017.md
Normal 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".
|
@ -141,10 +141,11 @@ void update_and_render( InputState* input, OffscreenBuffer* back_buffer, SoundBu
|
||||
#endif
|
||||
|
||||
EngineState* state = rcast( EngineState*, memory->Persistent );
|
||||
|
||||
do_once_start
|
||||
assert( sizeof(EngineState) <= memory->PersistentSize );
|
||||
|
||||
state->ToneVolume = 3000;
|
||||
state->ToneVolume = 1000;
|
||||
state->WaveToneHz = 262;
|
||||
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];
|
||||
|
||||
// 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 )
|
||||
{
|
||||
DualsensePadState* pad = controller->DSPad;
|
||||
|
||||
x_offset += pad->DPad.Right.State;
|
||||
x_offset -= pad->DPad.Left.State;
|
||||
y_offset += pad->DPad.Down.State;
|
||||
y_offset -= pad->DPad.Up.State;
|
||||
move_right |= pad->DPad.Right.EndedDown || pad->Stick.Left.X.End > analog_threshold;
|
||||
move_left |= pad->DPad.Left.EndedDown || pad->Stick.Left.X.End < -analog_threshold;
|
||||
move_up |= pad->DPad.Up.EndedDown || pad->Stick.Left.Y.End > analog_threshold;
|
||||
move_down |= pad->DPad.Down.EndedDown || pad->Stick.Left.Y.End < -analog_threshold;
|
||||
|
||||
x_offset += scast(u32, pad->Stick.Left.X.End);
|
||||
y_offset += scast(u32, pad->Stick.Left.Y.End);
|
||||
raise_volume |= pad->Triangle.EndedDown;
|
||||
lower_volume |= pad->Circle.EndedDown;
|
||||
|
||||
if ( pad->Triangle.State )
|
||||
{
|
||||
state->ToneVolume += 10;
|
||||
}
|
||||
if ( pad->Circle.State )
|
||||
{
|
||||
state->ToneVolume -= 10;
|
||||
}
|
||||
raise_tone_hz |= pad->Square.EndedDown;
|
||||
lower_tone_hz |= pad->X.EndedDown;
|
||||
|
||||
if ( pad->Square.State )
|
||||
{
|
||||
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
|
||||
}
|
||||
toggle_wave_tone |= pad->Options.EndedDown;
|
||||
}
|
||||
if ( controller->XPad )
|
||||
{
|
||||
XInputPadState* pad = controller->XPad;
|
||||
|
||||
x_offset += pad->DPad.Right.State;
|
||||
x_offset -= pad->DPad.Left.State;
|
||||
y_offset -= pad->DPad.Down.State;
|
||||
y_offset += pad->DPad.Up.State;
|
||||
move_right |= pad->DPad.Right.EndedDown || pad->Stick.Left.X.End > analog_threshold;
|
||||
move_left |= pad->DPad.Left.EndedDown || pad->Stick.Left.X.End < -analog_threshold;
|
||||
move_up |= pad->DPad.Up.EndedDown || pad->Stick.Left.Y.End > analog_threshold;
|
||||
move_down |= pad->DPad.Down.EndedDown || pad->Stick.Left.Y.End < -analog_threshold;
|
||||
|
||||
x_offset += scast(u32, pad->Stick.Left.X.End);
|
||||
y_offset += scast(u32, pad->Stick.Left.Y.End);
|
||||
raise_volume |= pad->Y.EndedDown;
|
||||
lower_volume |= pad->B.EndedDown;
|
||||
|
||||
if ( pad->Y.State )
|
||||
{
|
||||
state->ToneVolume += 10;
|
||||
}
|
||||
if ( pad->B.State )
|
||||
{
|
||||
state->ToneVolume -= 10;
|
||||
}
|
||||
raise_tone_hz |= pad->X.EndedDown;
|
||||
lower_tone_hz |= pad->A.EndedDown;
|
||||
|
||||
if ( pad->X.State )
|
||||
{
|
||||
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
|
||||
}
|
||||
toggle_wave_tone |= pad->Start.EndedDown;
|
||||
}
|
||||
if ( controller->Keyboard )
|
||||
{
|
||||
KeyboardState* keyboard = controller->Keyboard;
|
||||
|
||||
x_offset += keyboard->D.State;
|
||||
x_offset -= keyboard->A.State;
|
||||
y_offset += keyboard->W.State;
|
||||
y_offset -= keyboard->S.State;
|
||||
move_right |= keyboard->D.EndedDown;
|
||||
move_left |= keyboard->A.EndedDown;
|
||||
move_up |= keyboard->W.EndedDown;
|
||||
move_down |= keyboard->S.EndedDown;
|
||||
|
||||
if ( keyboard->Esc.State )
|
||||
{
|
||||
// TODO : Add exit game
|
||||
raise_volume |= keyboard->Up.EndedDown;
|
||||
lower_volume |= keyboard->Down.EndedDown;
|
||||
|
||||
raise_tone_hz |= keyboard->Right.EndedDown;
|
||||
lower_tone_hz |= keyboard->Left.EndedDown;
|
||||
|
||||
toggle_wave_tone |= keyboard->Space.EndedDown;
|
||||
}
|
||||
|
||||
if ( keyboard->Space.State )
|
||||
{
|
||||
wave_switch ^= true;
|
||||
}
|
||||
x_offset += move_right;
|
||||
x_offset -= move_left;
|
||||
y_offset += move_down;
|
||||
y_offset -= move_up;
|
||||
|
||||
if ( keyboard->Up.State )
|
||||
if ( raise_volume )
|
||||
{
|
||||
state->ToneVolume += 10;
|
||||
}
|
||||
if ( keyboard->Down.State )
|
||||
if ( lower_volume )
|
||||
{
|
||||
state->ToneVolume -= 10;
|
||||
}
|
||||
if ( keyboard->Left.State )
|
||||
{
|
||||
state->WaveToneHz -= 1;
|
||||
state->WavePeriod = sound_buffer->SamplesPerSecond / state->WaveToneHz;
|
||||
}
|
||||
if ( keyboard->Right.State )
|
||||
|
||||
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
|
||||
|
@ -56,7 +56,7 @@ struct SoundBuffer
|
||||
struct DigitalBtn
|
||||
{
|
||||
s32 HalfTransitions;
|
||||
b32 State;
|
||||
b32 EndedDown;
|
||||
};
|
||||
#define DigitalBtn_Up 0
|
||||
#define DigitalBtn_Down 1
|
||||
@ -67,6 +67,9 @@ struct AnalogAxis
|
||||
f32 End;
|
||||
f32 Min;
|
||||
f32 Max;
|
||||
|
||||
// Platform doesn't provide this, we process in the engine layer.
|
||||
f32 Average;
|
||||
};
|
||||
|
||||
struct AnalogStick
|
||||
@ -75,20 +78,24 @@ struct AnalogStick
|
||||
AnalogAxis Y;
|
||||
};
|
||||
|
||||
struct KeyboardState
|
||||
union KeyboardState
|
||||
{
|
||||
DigitalBtn Keys[12];
|
||||
struct {
|
||||
DigitalBtn Q;
|
||||
DigitalBtn E;
|
||||
DigitalBtn W;
|
||||
DigitalBtn A;
|
||||
DigitalBtn S;
|
||||
DigitalBtn D;
|
||||
DigitalBtn Esc;
|
||||
DigitalBtn Escape;
|
||||
DigitalBtn Backspace;
|
||||
DigitalBtn Up;
|
||||
DigitalBtn Down;
|
||||
DigitalBtn Left;
|
||||
DigitalBtn Right;
|
||||
DigitalBtn Space;
|
||||
};
|
||||
};
|
||||
|
||||
struct MousesState
|
||||
@ -128,11 +135,6 @@ struct XInputPadState
|
||||
DigitalBtn RightShoulder;
|
||||
};
|
||||
};
|
||||
|
||||
b32 using_analog()
|
||||
{
|
||||
return true;
|
||||
};
|
||||
};
|
||||
|
||||
struct DualsensePadState
|
||||
@ -165,11 +167,6 @@ struct DualsensePadState
|
||||
DigitalBtn R1;
|
||||
};
|
||||
};
|
||||
|
||||
b32 using_analog()
|
||||
{
|
||||
return true;
|
||||
};
|
||||
};
|
||||
|
||||
struct ControllerState
|
||||
@ -185,10 +182,76 @@ struct InputState
|
||||
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:
|
||||
// Timing, Input, Bitmap Buffer, Sound Buffer
|
||||
void update_and_render( InputState* input, OffscreenBuffer* back_buffer, SoundBuffer* sound_buffer, Memory* memory );
|
||||
|
||||
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
|
||||
|
||||
|
@ -16,3 +16,4 @@ int gen_main()
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
#endif
|
||||
|
||||
#include <math.h> // TODO : Implement math ourselves
|
||||
#include <stdio.h>
|
||||
#include "engine.cpp"
|
||||
|
||||
|
||||
@ -188,6 +189,60 @@ b32 debug_file_write_content( char* file_path, u32 content_size, void* content_m
|
||||
}
|
||||
#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
|
||||
init_sound(HWND window_handle, s32 samples_per_second, s32 buffer_size )
|
||||
{
|
||||
@ -487,19 +542,115 @@ main_window_callback(
|
||||
}
|
||||
|
||||
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 )
|
||||
new_state->State = (raw_btns & btn_flag);
|
||||
new_state->HalfTransitions = had_transition() ? 1 : 0;
|
||||
#undef had_transition
|
||||
}
|
||||
MSG window_msg_info;
|
||||
while ( PeekMessageA( & window_msg_info, 0, 0, 0, PM_Remove_Messages_From_Queue ) )
|
||||
{
|
||||
if ( window_msg_info.message == WM_QUIT )
|
||||
{
|
||||
OutputDebugStringA("WM_QUIT\n");
|
||||
Running = false;
|
||||
}
|
||||
|
||||
internal void
|
||||
input_process_keyboard_key( engine::DigitalBtn* key, b32 is_down )
|
||||
{
|
||||
key->State = is_down;
|
||||
key->HalfTransitions += is_down;
|
||||
// Keyboard input handling
|
||||
switch (window_msg_info.message)
|
||||
{
|
||||
// I rather do this with GetAsyncKeyState...
|
||||
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
|
||||
@ -561,7 +712,6 @@ WinMain(
|
||||
|
||||
WNDCLASSW window_class {};
|
||||
HWND window_handle = nullptr;
|
||||
MSG window_msg_info;
|
||||
{
|
||||
window_class.style = CS_Horizontal_Redraw | CS_Vertical_Redraw;
|
||||
window_class.lpfnWndProc = main_window_callback;
|
||||
@ -635,17 +785,18 @@ WinMain(
|
||||
|
||||
engine::InputState input {};
|
||||
|
||||
engine::KeyboardState keyboard;
|
||||
input.Controllers[0].Keyboard = & keyboard;
|
||||
engine::KeyboardState keyboard_states[2] {};
|
||||
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.
|
||||
|
||||
using EngineXInputPadStates = engine::XInputPadState[ Max_Controllers ];
|
||||
EngineXInputPadStates xpad_states[2];
|
||||
EngineXInputPadStates xpad_states[2] {};
|
||||
EngineXInputPadStates* old_xpads = & xpad_states[0];
|
||||
EngineXInputPadStates* new_xpads = & xpad_states[1];
|
||||
|
||||
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* new_ds_pads = & ds_pad_states[1];
|
||||
|
||||
@ -684,117 +835,51 @@ WinMain(
|
||||
Running = true;
|
||||
while( Running )
|
||||
{
|
||||
keyboard = {};
|
||||
// Handeled properly in the input section.
|
||||
#if 0
|
||||
swap( old_keyboard, new_keyboard );
|
||||
*new_keyboard = {};
|
||||
for ( u32 key_index = 0; key_index < array_count( new_keyboard->Keys ); ++ key_index )
|
||||
{
|
||||
engine::DigitalBtn* old_key = & old_keyboard->Keys[ key_index ];
|
||||
engine::DigitalBtn* new_key = & new_keyboard->Keys[ key_index ];
|
||||
|
||||
// Window Management
|
||||
{
|
||||
while ( PeekMessageW( & window_msg_info, 0, 0, 0, PM_Remove_Messages_From_Queue ) )
|
||||
{
|
||||
if ( window_msg_info.message == WM_QUIT )
|
||||
{
|
||||
OutputDebugStringA("WM_QUIT\n");
|
||||
Running = false;
|
||||
new_key->EndedDown = old_key->EndedDown;
|
||||
}
|
||||
#endif
|
||||
process_pending_window_messages( new_keyboard );
|
||||
|
||||
|
||||
// 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
// TODO(Ed) : Setup user definable deadzones for triggers and sticks.
|
||||
{
|
||||
// Swapping at the beginning of the input frame instead of the end.
|
||||
swap( old_keyboard, new_keyboard );
|
||||
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
|
||||
// TODO(Ed) : Should we poll this more frequently?
|
||||
for ( DWORD controller_index = 0; controller_index < Max_Controllers; ++ controller_index )
|
||||
@ -826,46 +911,16 @@ WinMain(
|
||||
new_xpad->Stick.Left.X.Start = old_xpad->Stick.Left.X.End;
|
||||
new_xpad->Stick.Left.Y.Start = old_xpad->Stick.Left.Y.End;
|
||||
|
||||
// TODO(Ed) : Compress this into a proc
|
||||
f32 X;
|
||||
if ( xpad->sThumbLX < 0 )
|
||||
{
|
||||
X = scast(f32, xpad->sThumbLX) / scast(f32, -S16_MIN);
|
||||
}
|
||||
else
|
||||
{
|
||||
X = scast(f32, xpad->sThumbLX) / scast(f32, S16_MAX);
|
||||
}
|
||||
f32 left_x = xinput_process_axis_value( xpad->sThumbLX, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE );
|
||||
f32 left_y = xinput_process_axis_value( xpad->sThumbLY, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE );
|
||||
|
||||
// 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;
|
||||
if ( xpad->sThumbLY < 0 )
|
||||
{
|
||||
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
|
||||
// TODO(Ed): Make this actually an average for later
|
||||
new_xpad->Stick.Left.X.Average = left_x;
|
||||
new_xpad->Stick.Left.Y.Average = left_y;
|
||||
|
||||
input.Controllers[ controller_index ].XPad = new_xpad;
|
||||
}
|
||||
@ -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->R1, & new_ds_pad->R1, state.buttons, JSMASK_R );
|
||||
|
||||
// epad->Stick.Left.X.End = state.stickLX;
|
||||
// epad->Stick.Left.Y.End = state.stickLY;
|
||||
// epad->Stick.Right.X.End = state.stickRX;
|
||||
// epad->Stick.Right.X.End = state.stickRY;
|
||||
new_ds_pad->Stick.Left.X.Start = old_ds_pad->Stick.Left.X.End;
|
||||
new_ds_pad->Stick.Left.Y.Start = old_ds_pad->Stick.Left.Y.End;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
@ -54,7 +54,7 @@
|
||||
# define assert( expression ) \
|
||||
if ( !( expression ) ) \
|
||||
{ \
|
||||
*( int* )0 = 0; \
|
||||
__debugbreak(); \
|
||||
}
|
||||
// platform::assertion_failure( __FILE__, __LINE__, #expression );
|
||||
#else
|
||||
@ -67,3 +67,41 @@
|
||||
#define ensure( condition, expression )
|
||||
#define fatal( message )
|
||||
#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
|
||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user