mirror of
https://github.com/Ed94/HandmadeHero.git
synced 2024-12-22 14:24:43 -08:00
Day 13 complete
This commit is contained in:
parent
ad5288f9e8
commit
abe3066071
96
docs/Day 013.md
Normal file
96
docs/Day 013.md
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
# Day 13
|
||||||
|
|
||||||
|
Started to lifting input, not happy about my abstraction to gamepad state in hindsight. Which is kinda lead by how Casey is doing it.
|
||||||
|
|
||||||
|
The reality of how input is actually done in the games; that I've worked on; is we don't abstract the gamepad.
|
||||||
|
We just make a layout per device we decide to support (Dualsense/shock, xinput, nintendo, etc) and then just see what device is mapped to what player. This allows us to have a tailored layout to the device. Doing otherwise usually leads to some discrepancy in the UX for that layout for the user.
|
||||||
|
|
||||||
|
Casey has no concept of a player nor a device beyond xinput for this engine (at least up to this point), which is most likely fine for the scope of this project.
|
||||||
|
|
||||||
|
For the purposes of my version of Handmade I will make 3 devices that could be mapped to a `Controller` struct: `Keyboard & Mouse`, `Dualsense`, and `XInput`.
|
||||||
|
This is to retain implementation Casey is already making while also natively supporting the Dualsense controller from sony which I personally perfer to use.
|
||||||
|
|
||||||
|
From the 3 layer abstraction (platform/engine/game):
|
||||||
|
Platform will deal with the raw polling (and most likely down the line have a thread dedicated to running it as fast as possible).
|
||||||
|
It will provide the engine layer the pad states in the following struct:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct InputState
|
||||||
|
{
|
||||||
|
ControllerState Controllers[4];
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
There can only be four controllers available at a time and are equivalnet to the input aspect of a local player in Unreal.
|
||||||
|
(Sort of)
|
||||||
|
Each controller can be assigned the following:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct ControllerState
|
||||||
|
{
|
||||||
|
KeyboardState* Keyboard;
|
||||||
|
MousesState* Mouse;
|
||||||
|
XInputPadState* XPad;
|
||||||
|
DualsensePadState* DSPad;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
If any are null that means the controller has no assignment.
|
||||||
|
Each pad state is the latest state but the platform keeps a record of the previous frame's state to compare against.
|
||||||
|
|
||||||
|
Exmaple for Dualsense:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct DualsensePadState
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
AnalogStick Left;
|
||||||
|
AnalogStick Right;
|
||||||
|
} Stick;
|
||||||
|
|
||||||
|
AnalogAxis L2;
|
||||||
|
AnalogAxis R2;
|
||||||
|
|
||||||
|
union {
|
||||||
|
DigitalBtn Btns[14];
|
||||||
|
struct {
|
||||||
|
struct {
|
||||||
|
DigitalBtn Up;
|
||||||
|
DigitalBtn Down;
|
||||||
|
DigitalBtn Left;
|
||||||
|
DigitalBtn Right;
|
||||||
|
} DPad;
|
||||||
|
DigitalBtn X;
|
||||||
|
DigitalBtn Circle;
|
||||||
|
DigitalBtn Square;
|
||||||
|
DigitalBtn Triangle;
|
||||||
|
DigitalBtn Share;
|
||||||
|
DigitalBtn Options;
|
||||||
|
DigitalBtn L1;
|
||||||
|
DigitalBtn R1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
b32 using_analog()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
The game layer handles mapping an input state of a controller to an action binding.
|
||||||
|
Possible action binding when we get to that point:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct ActionBinding
|
||||||
|
{
|
||||||
|
String InternalName;
|
||||||
|
StringCached LocalizedName;
|
||||||
|
|
||||||
|
DigitalBtnBinding* BtnBinds;
|
||||||
|
AxisBinding* AxisBinds;
|
||||||
|
StickBinding* StickBinds;
|
||||||
|
MouseBinding* MouseBinds;
|
||||||
|
};
|
||||||
|
```
|
@ -1,17 +1,21 @@
|
|||||||
#include "engine.h"
|
#include "engine.h"
|
||||||
|
#include "win32.h"
|
||||||
|
|
||||||
NS_ENGINE_BEGIN
|
NS_ENGINE_BEGIN
|
||||||
|
|
||||||
|
|
||||||
using GetSoundSampleValueFn = s16( SoundBuffer* sound_buffer );
|
using GetSoundSampleValueFn = s16( SoundBuffer* sound_buffer );
|
||||||
|
|
||||||
global s32 SoundWavePeriod = 250;
|
global s32 SoundTest_ToneVolume = 3000;
|
||||||
|
global s32 SoundTest_WavePeriod = 0;
|
||||||
|
global s32 SoundTest_WaveToneHz = 262;
|
||||||
|
|
||||||
|
|
||||||
internal s16
|
internal s16
|
||||||
square_wave_sample_value( SoundBuffer* sound_buffer )
|
square_wave_sample_value( SoundBuffer* sound_buffer )
|
||||||
{
|
{
|
||||||
s16 sample_value = (sound_buffer->RunningSampleIndex / (sound_buffer->WavePeriod /2)) % 2 ?
|
s16 sample_value = (sound_buffer->RunningSampleIndex / (SoundTest_WavePeriod /2)) % 2 ?
|
||||||
sound_buffer->ToneVolume : - sound_buffer->ToneVolume;
|
SoundTest_ToneVolume : - SoundTest_ToneVolume;
|
||||||
|
|
||||||
return sample_value;
|
return sample_value;
|
||||||
}
|
}
|
||||||
@ -21,10 +25,11 @@ sine_wave_sample_value( SoundBuffer* sound_buffer )
|
|||||||
{
|
{
|
||||||
local_persist f32 time = 0.f;
|
local_persist f32 time = 0.f;
|
||||||
|
|
||||||
|
// time = TAU * (f32)sound_buffer->RunningSampleIndex / (f32)SoundTest_WavePeriod;
|
||||||
f32 sine_value = sinf( time );
|
f32 sine_value = sinf( time );
|
||||||
s16 sample_value = scast(u16, sine_value * sound_buffer->ToneVolume);
|
s16 sample_value = scast(u16, sine_value * SoundTest_ToneVolume);
|
||||||
|
|
||||||
time += TAU * 1.0f / scast(f32, sound_buffer->WavePeriod );
|
time += TAU * 1.0f / scast(f32, SoundTest_WavePeriod );
|
||||||
return sample_value;
|
return sample_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,7 +40,11 @@ output_sound( SoundBuffer* sound_buffer, GetSoundSampleValueFn* get_sample_value
|
|||||||
for ( u32 sample_index = 0; sample_index < sound_buffer->NumSamples; ++ sample_index )
|
for ( u32 sample_index = 0; sample_index < sound_buffer->NumSamples; ++ sample_index )
|
||||||
{
|
{
|
||||||
s16 sample_value = get_sample_value( sound_buffer );
|
s16 sample_value = get_sample_value( sound_buffer );
|
||||||
++ sound_buffer->RunningSampleIndex;
|
sound_buffer->RunningSampleIndex++;
|
||||||
|
|
||||||
|
// char ms_timing_debug[256] {};
|
||||||
|
// wsprintfA( ms_timing_debug, "sample_value: %d\n", sample_value );
|
||||||
|
// OutputDebugStringA( ms_timing_debug );
|
||||||
|
|
||||||
*sample_out = sample_value;
|
*sample_out = sample_value;
|
||||||
++ sample_out;
|
++ sample_out;
|
||||||
@ -92,14 +101,133 @@ render_weird_graident(OffscreenBuffer* buffer, u32 x_offset, u32 y_offset )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal
|
b32 input_using_analog()
|
||||||
void update_and_render( OffscreenBuffer* back_buffer, SoundBuffer* sound_buffer
|
|
||||||
// Temp (for feature parity)
|
|
||||||
, u32 x_offset, u32 y_offset
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO : I rather expose the back_buffer and sound_buffer using getters for access in any function.
|
||||||
|
internal void
|
||||||
|
update_and_render( InputState* input, OffscreenBuffer* back_buffer, SoundBuffer* sound_buffer )
|
||||||
|
{
|
||||||
|
// Graphics & Input Test
|
||||||
|
local_persist u32 x_offset = 0;
|
||||||
|
local_persist u32 y_offset = 0;
|
||||||
|
|
||||||
|
// Wave Sound Test
|
||||||
|
local_persist bool wave_switch = false;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if ( input_using_analog() )
|
||||||
|
{
|
||||||
|
// TODO(Ed) : Use analog movement tuning
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO(Ed) : Use digital movement tuning
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
do_once_start
|
||||||
|
{
|
||||||
|
SoundTest_WavePeriod = sound_buffer->SamplesPerSecond / SoundTest_WaveToneHz;
|
||||||
|
}
|
||||||
|
do_once_end
|
||||||
|
|
||||||
|
ControllerState* controller = & input->Controllers[0];
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
x_offset += pad->Stick.Left.X.End;
|
||||||
|
y_offset += pad->Stick.Left.Y.End;
|
||||||
|
|
||||||
|
if ( pad->Triangle.State )
|
||||||
|
{
|
||||||
|
SoundTest_ToneVolume += 10;
|
||||||
|
}
|
||||||
|
if ( pad->Circle.State )
|
||||||
|
{
|
||||||
|
SoundTest_ToneVolume -= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( pad->Square.State )
|
||||||
|
{
|
||||||
|
SoundTest_WaveToneHz += 1;
|
||||||
|
SoundTest_WavePeriod = sound_buffer->SamplesPerSecond / SoundTest_WaveToneHz;
|
||||||
|
}
|
||||||
|
if ( pad->X.State )
|
||||||
|
{
|
||||||
|
SoundTest_WaveToneHz -= 1;
|
||||||
|
SoundTest_WavePeriod = sound_buffer->SamplesPerSecond / SoundTest_WaveToneHz;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( pad->Options.State )
|
||||||
|
{
|
||||||
|
wave_switch ^= true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( pad->Share.State )
|
||||||
|
{
|
||||||
|
// TODO(Ed) : Add rumble test
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else 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;
|
||||||
|
|
||||||
|
x_offset += pad->Stick.Left.X.End;
|
||||||
|
y_offset += pad->Stick.Left.Y.End;
|
||||||
|
|
||||||
|
if ( pad->Y.State )
|
||||||
|
{
|
||||||
|
SoundTest_ToneVolume += 10;
|
||||||
|
}
|
||||||
|
if ( pad->B.State )
|
||||||
|
{
|
||||||
|
SoundTest_ToneVolume -= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( pad->X.State )
|
||||||
|
{
|
||||||
|
SoundTest_WaveToneHz += 1;
|
||||||
|
SoundTest_WavePeriod = sound_buffer->SamplesPerSecond / SoundTest_WaveToneHz;
|
||||||
|
}
|
||||||
|
if ( pad->A.State )
|
||||||
|
{
|
||||||
|
SoundTest_WaveToneHz -= 1;
|
||||||
|
SoundTest_WavePeriod = sound_buffer->SamplesPerSecond / SoundTest_WaveToneHz;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( pad->Start.State )
|
||||||
|
{
|
||||||
|
wave_switch ^= true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( pad->Back.State )
|
||||||
|
{
|
||||||
|
// TODO(Ed) : Add rumble test
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// TODO(Ed) : Allow sample offsets here for more robust platform options
|
// TODO(Ed) : Allow sample offsets here for more robust platform options
|
||||||
output_sound( sound_buffer, square_wave_sample_value );
|
if ( ! wave_switch )
|
||||||
|
output_sound( sound_buffer, sine_wave_sample_value );
|
||||||
|
else
|
||||||
|
output_sound( sound_buffer, square_wave_sample_value );
|
||||||
|
|
||||||
render_weird_graident( back_buffer, x_offset, y_offset );
|
render_weird_graident( back_buffer, x_offset, y_offset );
|
||||||
}
|
}
|
||||||
|
135
project/engine.h
135
project/engine.h
@ -20,22 +20,143 @@ struct OffscreenBuffer
|
|||||||
u32 BytesPerPixel;
|
u32 BytesPerPixel;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO : Will be gutting this once we have other stuff lifted.
|
||||||
struct SoundBuffer
|
struct SoundBuffer
|
||||||
{
|
{
|
||||||
s16* Samples;
|
s16* Samples;
|
||||||
u32 RunningSampleIndex;
|
u32 RunningSampleIndex;
|
||||||
s32 SamplesPerSecond;
|
s32 SamplesPerSecond;
|
||||||
s32 NumSamples;
|
s32 NumSamples;
|
||||||
s32 ToneVolume;
|
|
||||||
s32 WaveToneHz;
|
|
||||||
s32 WavePeriod;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct DigitalBtn
|
||||||
|
{
|
||||||
|
s32 HalfTransitions;
|
||||||
|
b32 State;
|
||||||
|
};
|
||||||
|
#define DigitalBtn_Up 0
|
||||||
|
#define DigitalBtn_Down 1
|
||||||
|
|
||||||
|
struct AnalogAxis
|
||||||
|
{
|
||||||
|
f32 Start;
|
||||||
|
f32 End;
|
||||||
|
f32 Min;
|
||||||
|
f32 Max;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AnalogStick
|
||||||
|
{
|
||||||
|
AnalogAxis X;
|
||||||
|
AnalogAxis Y;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct KeyboardState
|
||||||
|
{
|
||||||
|
DigitalBtn W;
|
||||||
|
DigitalBtn A;
|
||||||
|
DigitalBtn S;
|
||||||
|
DigitalBtn D;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MousesState
|
||||||
|
{
|
||||||
|
DigitalBtn Left;
|
||||||
|
DigitalBtn Middle;
|
||||||
|
DigitalBtn Right;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct XInputPadState
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
AnalogStick Left;
|
||||||
|
AnalogStick Right;
|
||||||
|
} Stick;
|
||||||
|
|
||||||
|
AnalogAxis LeftTrigger;
|
||||||
|
AnalogAxis RightTrigger;
|
||||||
|
|
||||||
|
union {
|
||||||
|
DigitalBtn Btns[14];
|
||||||
|
struct {
|
||||||
|
struct {
|
||||||
|
DigitalBtn Up;
|
||||||
|
DigitalBtn Down;
|
||||||
|
DigitalBtn Left;
|
||||||
|
DigitalBtn Right;
|
||||||
|
} DPad;
|
||||||
|
DigitalBtn A;
|
||||||
|
DigitalBtn B;
|
||||||
|
DigitalBtn X;
|
||||||
|
DigitalBtn Y;
|
||||||
|
DigitalBtn Back;
|
||||||
|
DigitalBtn Start;
|
||||||
|
DigitalBtn LeftShoulder;
|
||||||
|
DigitalBtn RightShoulder;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
b32 using_analog()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DualsensePadState
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
AnalogStick Left;
|
||||||
|
AnalogStick Right;
|
||||||
|
} Stick;
|
||||||
|
|
||||||
|
AnalogAxis L2;
|
||||||
|
AnalogAxis R2;
|
||||||
|
|
||||||
|
union {
|
||||||
|
DigitalBtn Btns[14];
|
||||||
|
struct {
|
||||||
|
struct {
|
||||||
|
DigitalBtn Up;
|
||||||
|
DigitalBtn Down;
|
||||||
|
DigitalBtn Left;
|
||||||
|
DigitalBtn Right;
|
||||||
|
} DPad;
|
||||||
|
DigitalBtn X;
|
||||||
|
DigitalBtn Circle;
|
||||||
|
DigitalBtn Square;
|
||||||
|
DigitalBtn Triangle;
|
||||||
|
DigitalBtn Share;
|
||||||
|
DigitalBtn Options;
|
||||||
|
DigitalBtn L1;
|
||||||
|
DigitalBtn R1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
b32 using_analog()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ControllerState
|
||||||
|
{
|
||||||
|
KeyboardState* Keyboard;
|
||||||
|
MousesState* Mouse;
|
||||||
|
XInputPadState* XPad;
|
||||||
|
DualsensePadState* DSPad;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct InputState
|
||||||
|
{
|
||||||
|
ControllerState Controllers[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
b32 input_using_analog();
|
||||||
|
|
||||||
// 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( OffscreenBuffer* back_buffer, SoundBuffer* sound_buffer
|
void update_and_render( InputState* input, OffscreenBuffer* back_buffer, SoundBuffer* sound_buffer );
|
||||||
// Temp (for feature parity)
|
|
||||||
, u32 x_offset, u32 y_offset
|
|
||||||
);
|
|
||||||
|
|
||||||
NS_ENGINE_END
|
NS_ENGINE_END
|
||||||
|
10
project/platform/generics.h
Normal file
10
project/platform/generics.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
template< class Type >
|
||||||
|
void swap( Type& a, Type& b )
|
||||||
|
{
|
||||||
|
Type
|
||||||
|
temp = a;
|
||||||
|
a = b;
|
||||||
|
b = temp;
|
||||||
|
}
|
@ -89,8 +89,16 @@ struct WinDimensions
|
|||||||
u32 Height;
|
u32 Height;
|
||||||
};
|
};
|
||||||
|
|
||||||
HRESULT WINAPI
|
// TODO : This will def need to be looked over.
|
||||||
DirectSoundCreate(LPGUID lpGuid, LPDIRECTSOUND* ppDS, LPUNKNOWN pUnkOuter );
|
struct SoundOutput
|
||||||
|
{
|
||||||
|
DWORD IsPlaying;
|
||||||
|
u32 RunningSampleIndex;
|
||||||
|
s32 LatencySampleCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT WINAPI DirectSoundCreate(LPGUID lpGuid, LPDIRECTSOUND* ppDS, LPUNKNOWN pUnkOuter );
|
||||||
|
|
||||||
using DirectSoundCreateFn = HRESULT WINAPI (LPGUID lpGuid, LPDIRECTSOUND* ppDS, LPUNKNOWN pUnkOuter );
|
using DirectSoundCreateFn = HRESULT WINAPI (LPGUID lpGuid, LPDIRECTSOUND* ppDS, LPUNKNOWN pUnkOuter );
|
||||||
global DirectSoundCreateFn* direct_sound_create;
|
global DirectSoundCreateFn* direct_sound_create;
|
||||||
@ -177,16 +185,6 @@ init_sound(HWND window_handle, s32 samples_per_second, s32 buffer_size )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SoundOutput
|
|
||||||
{
|
|
||||||
DWORD IsPlaying;
|
|
||||||
u32 RunningSampleIndex;
|
|
||||||
s32 WaveToneHz;
|
|
||||||
s32 WavePeriod;
|
|
||||||
s32 ToneVolume;
|
|
||||||
s32 LatencySampleCount;
|
|
||||||
};
|
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
ds_clear_sound_buffer( SoundOutput* sound_output )
|
ds_clear_sound_buffer( SoundOutput* sound_output )
|
||||||
{
|
{
|
||||||
@ -494,6 +492,15 @@ main_window_callback(
|
|||||||
|
|
||||||
NS_WIN32_END
|
NS_WIN32_END
|
||||||
|
|
||||||
|
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->State == new_state->State )
|
||||||
|
new_state->State = (raw_btns & btn_flag);
|
||||||
|
new_state->HalfTransitions = had_transition() ? 1 : 0;
|
||||||
|
#undef had_transition
|
||||||
|
}
|
||||||
|
|
||||||
int CALLBACK
|
int CALLBACK
|
||||||
WinMain(
|
WinMain(
|
||||||
HINSTANCE instance,
|
HINSTANCE instance,
|
||||||
@ -503,130 +510,126 @@ WinMain(
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
using namespace win32;
|
using namespace win32;
|
||||||
// xinput_load_library_bindings();
|
|
||||||
|
|
||||||
using JSL_DeviceHandle = int;
|
|
||||||
u32 jsl_num_devices = JslConnectDevices();
|
|
||||||
|
|
||||||
JSL_DeviceHandle device_handles[4] {};
|
|
||||||
u32 jsl_getconnected_found = JslGetConnectedDeviceHandles( device_handles, jsl_num_devices );
|
|
||||||
{
|
|
||||||
if ( jsl_getconnected_found != jsl_num_devices )
|
|
||||||
{
|
|
||||||
OutputDebugStringA( "Error: JSLGetConnectedDeviceHandles didn't find as many as were stated with JslConnectDevices\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( jsl_num_devices > 0 )
|
|
||||||
{
|
|
||||||
OutputDebugStringA( "JSL Connected Devices:\n" );
|
|
||||||
for ( u32 jsl_device_index = 0; jsl_device_index < jsl_num_devices; ++ jsl_device_index )
|
|
||||||
{
|
|
||||||
JslSetLightColour( device_handles[ jsl_device_index ], (255 << 8) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MessageBox( 0, L"First message!", L"Handmade Hero", MB_Ok_Btn | MB_Icon_Information );
|
// MessageBox( 0, L"First message!", L"Handmade Hero", MB_Ok_Btn | MB_Icon_Information );
|
||||||
|
|
||||||
WNDCLASSW
|
WNDCLASSW window_class {};
|
||||||
window_class {};
|
HWND window_handle = nullptr;
|
||||||
window_class.style = CS_Horizontal_Redraw | CS_Vertical_Redraw;
|
MSG window_msg_info;
|
||||||
window_class.lpfnWndProc = main_window_callback;
|
|
||||||
// window_class.cbClsExtra = ;
|
|
||||||
// window_class.cbWndExtra = ;
|
|
||||||
window_class.hInstance = instance;
|
|
||||||
// window_class.hIcon = ;
|
|
||||||
// window_class.hCursor = ;
|
|
||||||
// window_class.hbrBackground = ;
|
|
||||||
window_class.lpszMenuName = L"Handmade Hero!";
|
|
||||||
window_class.lpszClassName = L"HandmadeHeroWindowClass";
|
|
||||||
|
|
||||||
if ( ! RegisterClassW( & window_class ) )
|
|
||||||
{
|
{
|
||||||
// TODO : Diagnostic Logging
|
window_class.style = CS_Horizontal_Redraw | CS_Vertical_Redraw;
|
||||||
return 0;
|
window_class.lpfnWndProc = main_window_callback;
|
||||||
|
// window_class.cbClsExtra = ;
|
||||||
|
// window_class.cbWndExtra = ;
|
||||||
|
window_class.hInstance = instance;
|
||||||
|
// window_class.hIcon = ;
|
||||||
|
// window_class.hCursor = ;
|
||||||
|
// window_class.hbrBackground = ;
|
||||||
|
window_class.lpszMenuName = L"Handmade Hero!";
|
||||||
|
window_class.lpszClassName = L"HandmadeHeroWindowClass";
|
||||||
|
|
||||||
|
if ( ! RegisterClassW( & window_class ) )
|
||||||
|
{
|
||||||
|
// TODO : Diagnostic Logging
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
window_handle = CreateWindowExW(
|
||||||
|
0,
|
||||||
|
window_class.lpszClassName,
|
||||||
|
L"Handmade Hero",
|
||||||
|
WS_Overlapped_Window | WS_Initially_Visible,
|
||||||
|
CW_Use_Default, CW_Use_Default, // x, y
|
||||||
|
CW_Use_Default, CW_Use_Default, // width, height
|
||||||
|
0, 0, // parent, menu
|
||||||
|
instance, 0 // instance, param
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( ! window_handle )
|
||||||
|
{
|
||||||
|
// TODO : Diagnostic Logging
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HWND window_handle = CreateWindowExW(
|
|
||||||
0,
|
|
||||||
window_class.lpszClassName,
|
|
||||||
L"Handmade Hero",
|
|
||||||
WS_Overlapped_Window | WS_Initially_Visible,
|
|
||||||
CW_Use_Default, CW_Use_Default, // x, y
|
|
||||||
CW_Use_Default, CW_Use_Default, // width, height
|
|
||||||
0, 0, // parent, menu
|
|
||||||
instance, 0 // instance, param
|
|
||||||
);
|
|
||||||
|
|
||||||
if ( ! window_handle )
|
|
||||||
{
|
|
||||||
// TODO : Diagnostic Logging
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Running = true;
|
|
||||||
|
|
||||||
WinDimensions dimensions = get_window_dimensions( window_handle );
|
WinDimensions dimensions = get_window_dimensions( window_handle );
|
||||||
resize_dib_section( &BackBuffer, 1280, 720 );
|
resize_dib_section( &BackBuffer, 1280, 720 );
|
||||||
|
|
||||||
SoundOutput sound_output;
|
SoundOutput sound_output;
|
||||||
sound_output.IsPlaying = 0;
|
{
|
||||||
DS_SecondaryBuffer_SamplesPerSecond = 48000;
|
sound_output.IsPlaying = 0;
|
||||||
DS_SecondaryBuffer_BytesPerSample = sizeof(s16) * 2;
|
DS_SecondaryBuffer_SamplesPerSecond = 48000;
|
||||||
|
DS_SecondaryBuffer_BytesPerSample = sizeof(s16) * 2;
|
||||||
|
|
||||||
DS_SecondaryBuffer_Size = DS_SecondaryBuffer_SamplesPerSecond * DS_SecondaryBuffer_BytesPerSample;
|
DS_SecondaryBuffer_Size = DS_SecondaryBuffer_SamplesPerSecond * DS_SecondaryBuffer_BytesPerSample;
|
||||||
init_sound( window_handle, DS_SecondaryBuffer_SamplesPerSecond, DS_SecondaryBuffer_Size );
|
init_sound( window_handle, DS_SecondaryBuffer_SamplesPerSecond, DS_SecondaryBuffer_Size );
|
||||||
|
|
||||||
SoundBufferSamples = rcast( s16*, VirtualAlloc( 0, 48000 * 2 * sizeof(s16)
|
SoundBufferSamples = rcast( s16*, VirtualAlloc( 0, 48000 * 2 * sizeof(s16)
|
||||||
, MEM_Commit_Zeroed | MEM_Reserve, Page_Read_Write ));
|
, MEM_Commit_Zeroed | MEM_Reserve, Page_Read_Write ));
|
||||||
|
|
||||||
// Wave Sound Test
|
sound_output.RunningSampleIndex = 0;
|
||||||
bool wave_switch = false;
|
sound_output.LatencySampleCount = DS_SecondaryBuffer_SamplesPerSecond / 15;
|
||||||
sound_output.RunningSampleIndex = 0;
|
// ds_clear_sound_buffer( & sound_output );
|
||||||
sound_output.WaveToneHz = 262;
|
DS_SecondaryBuffer->Play( 0, 0, DSBPLAY_LOOPING );
|
||||||
sound_output.WavePeriod = DS_SecondaryBuffer_SamplesPerSecond / sound_output.WaveToneHz;
|
}
|
||||||
sound_output.ToneVolume = 3000;
|
|
||||||
sound_output.LatencySampleCount = DS_SecondaryBuffer_SamplesPerSecond / 15;
|
|
||||||
ds_clear_sound_buffer( & sound_output );
|
|
||||||
DS_SecondaryBuffer->Play( 0, 0, DSBPLAY_LOOPING );
|
|
||||||
|
|
||||||
// Graphics & Input Test
|
|
||||||
u32 x_offset = 0;
|
|
||||||
u32 y_offset = 0;
|
|
||||||
|
|
||||||
// Controller State
|
|
||||||
bool xinput_detected = false;
|
|
||||||
|
|
||||||
b32 dpad_up = false;
|
|
||||||
b32 dpad_down = false;
|
|
||||||
b32 dpad_left = false;
|
|
||||||
b32 dpad_right = false;
|
|
||||||
b32 start = false;
|
|
||||||
b32 back = false;
|
|
||||||
b32 left_shoulder = false;
|
|
||||||
b32 right_shoulder = false;
|
|
||||||
b32 btn_a = false;
|
|
||||||
b32 btn_b = false;
|
|
||||||
b32 btn_x = false;
|
|
||||||
b32 btn_y = false;
|
|
||||||
u16 stick_left_x = 0;
|
|
||||||
u16 stick_left_y = 0;
|
|
||||||
u16 stick_right_x = 0;
|
|
||||||
u16 stick_right_y = 0;
|
|
||||||
|
|
||||||
// TODO : Add sine wave test
|
|
||||||
|
|
||||||
// Windows
|
|
||||||
MSG window_msg_info;
|
|
||||||
|
|
||||||
|
// Timing
|
||||||
u64 perf_counter_frequency;
|
u64 perf_counter_frequency;
|
||||||
QueryPerformanceFrequency( rcast(LARGE_INTEGER*, & perf_counter_frequency) );
|
|
||||||
|
|
||||||
u64 last_frame_time;
|
u64 last_frame_time;
|
||||||
|
QueryPerformanceFrequency( rcast(LARGE_INTEGER*, & perf_counter_frequency) );
|
||||||
QueryPerformanceCounter( rcast(LARGE_INTEGER*, & last_frame_time) );
|
QueryPerformanceCounter( rcast(LARGE_INTEGER*, & last_frame_time) );
|
||||||
|
|
||||||
u64 last_cycle_time = __rdtsc();
|
u64 last_cycle_time = __rdtsc();
|
||||||
|
|
||||||
|
// Input shitshow
|
||||||
|
constexpr u32 Max_Controllers = 4;
|
||||||
|
// Max controllers for the platform layer and thus for all other layers is 4. (Sanity and xinput limit)
|
||||||
|
|
||||||
|
engine::InputState input {};
|
||||||
|
|
||||||
|
using EngineXInputPadStates = engine::XInputPadState[ Max_Controllers ];
|
||||||
|
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* old_ds_pads = & ds_pad_states[0];
|
||||||
|
EngineDSPadStates* new_ds_pads = & ds_pad_states[1];
|
||||||
|
|
||||||
|
using JSL_DeviceHandle = int;
|
||||||
|
u32 jsl_num_devices
|
||||||
|
// = JslConnectDevices();
|
||||||
|
= 0;
|
||||||
|
JSL_DeviceHandle jsl_device_handles[4] {};
|
||||||
|
{
|
||||||
|
xinput_load_library_bindings();
|
||||||
|
|
||||||
|
u32 jsl_getconnected_found = JslGetConnectedDeviceHandles( jsl_device_handles, jsl_num_devices );
|
||||||
|
{
|
||||||
|
if ( jsl_getconnected_found != jsl_num_devices )
|
||||||
|
{
|
||||||
|
OutputDebugStringA( "Error: JSLGetConnectedDeviceHandles didn't find as many as were stated with JslConnectDevices\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( jsl_num_devices > 0 )
|
||||||
|
{
|
||||||
|
OutputDebugStringA( "JSL Connected Devices:\n" );
|
||||||
|
for ( u32 jsl_device_index = 0; jsl_device_index < jsl_num_devices; ++ jsl_device_index )
|
||||||
|
{
|
||||||
|
JslSetLightColour( jsl_device_handles[ jsl_device_index ], (255 << 8) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( jsl_num_devices > 4 )
|
||||||
|
{
|
||||||
|
jsl_num_devices = 4;
|
||||||
|
MessageBoxA( window_handle, "More than 4 JSL devices found, this engine will only support the first four found.", "Warning", MB_ICONEXCLAMATION );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Running = true;
|
||||||
while( Running )
|
while( Running )
|
||||||
{
|
{
|
||||||
// Window Management
|
// Window Management
|
||||||
@ -646,103 +649,132 @@ WinMain(
|
|||||||
|
|
||||||
// Input
|
// Input
|
||||||
{
|
{
|
||||||
|
// Swapping at the beginning of the input frame instead of the end.
|
||||||
|
swap( old_xpads, new_xpads );
|
||||||
|
swap( old_ds_pads, new_ds_pads );
|
||||||
|
|
||||||
// XInput Polling
|
// XInput Polling
|
||||||
// TODO(Ed) : Should we poll this more frequently?
|
// TODO(Ed) : Should we poll this more frequently?
|
||||||
for ( DWORD controller_index = 0; controller_index < XUSER_MAX_COUNT; ++ controller_index )
|
for ( DWORD controller_index = 0; controller_index < Max_Controllers; ++ controller_index )
|
||||||
{
|
{
|
||||||
XINPUT_STATE controller_state;
|
XINPUT_STATE controller_state;
|
||||||
xinput_detected = xinput_get_state( controller_index, & controller_state ) == XI_PluggedIn;
|
b32 xinput_detected = xinput_get_state( controller_index, & controller_state ) == XI_PluggedIn;
|
||||||
if ( xinput_detected )
|
if ( xinput_detected )
|
||||||
{
|
{
|
||||||
XINPUT_GAMEPAD* pad = & controller_state.Gamepad;
|
XINPUT_GAMEPAD* xpad = & controller_state.Gamepad;
|
||||||
|
engine::XInputPadState* old_xpad = old_xpads[ controller_index ];
|
||||||
|
engine::XInputPadState* new_xpad = new_xpads[ controller_index ];
|
||||||
|
|
||||||
dpad_up = pad->wButtons & XINPUT_GAMEPAD_DPAD_UP;
|
input_process_digital_btn( & old_xpad->DPad.Up, & new_xpad->DPad.Up, xpad->wButtons, XINPUT_GAMEPAD_DPAD_UP );
|
||||||
dpad_down = pad->wButtons & XINPUT_GAMEPAD_DPAD_DOWN;
|
input_process_digital_btn( & old_xpad->DPad.Down, & new_xpad->DPad.Down, xpad->wButtons, XINPUT_GAMEPAD_DPAD_DOWN );
|
||||||
dpad_left = pad->wButtons & XINPUT_GAMEPAD_DPAD_LEFT;
|
input_process_digital_btn( & old_xpad->DPad.Left, & new_xpad->DPad.Left, xpad->wButtons, XINPUT_GAMEPAD_DPAD_LEFT );
|
||||||
dpad_right = pad->wButtons & XINPUT_GAMEPAD_DPAD_RIGHT;
|
input_process_digital_btn( & old_xpad->DPad.Right, & new_xpad->DPad.Right, xpad->wButtons, XINPUT_GAMEPAD_DPAD_RIGHT );
|
||||||
start = pad->wButtons & XINPUT_GAMEPAD_START;
|
|
||||||
back = pad->wButtons & XINPUT_GAMEPAD_BACK;
|
|
||||||
left_shoulder = pad->wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER;
|
|
||||||
right_shoulder = pad->wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER;
|
|
||||||
btn_a = pad->wButtons & XINPUT_GAMEPAD_A;
|
|
||||||
btn_b = pad->wButtons & XINPUT_GAMEPAD_B;
|
|
||||||
btn_x = pad->wButtons & XINPUT_GAMEPAD_X;
|
|
||||||
btn_y = pad->wButtons & XINPUT_GAMEPAD_Y;
|
|
||||||
|
|
||||||
stick_left_x = pad->sThumbLX;
|
input_process_digital_btn( & old_xpad->Y, & new_xpad->Y, xpad->wButtons, XINPUT_GAMEPAD_Y );
|
||||||
stick_left_y = pad->sThumbLY;
|
input_process_digital_btn( & old_xpad->A, & new_xpad->A, xpad->wButtons, XINPUT_GAMEPAD_A );
|
||||||
stick_right_x = pad->sThumbRX;
|
input_process_digital_btn( & old_xpad->B, & new_xpad->B, xpad->wButtons, XINPUT_GAMEPAD_B );
|
||||||
stick_right_y = pad->sThumbRY;
|
input_process_digital_btn( & old_xpad->X, & new_xpad->X, xpad->wButtons, XINPUT_GAMEPAD_X );
|
||||||
|
|
||||||
|
input_process_digital_btn( & old_xpad->Back, & new_xpad->Back, xpad->wButtons, XINPUT_GAMEPAD_BACK );
|
||||||
|
input_process_digital_btn( & old_xpad->Start, & new_xpad->Start, xpad->wButtons, XINPUT_GAMEPAD_START );
|
||||||
|
|
||||||
|
input_process_digital_btn( & old_xpad->LeftShoulder, & new_xpad->LeftShoulder, xpad->wButtons, XINPUT_GAMEPAD_LEFT_SHOULDER );
|
||||||
|
input_process_digital_btn( & old_xpad->RightShoulder, & new_xpad->RightShoulder, xpad->wButtons, XINPUT_GAMEPAD_RIGHT_SHOULDER );
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(Ed) : Min/Max macros!!!
|
||||||
|
new_xpad->Stick.Left.X.Min = new_xpad->Stick.Left.X.Max = new_xpad->Stick.Left.X.End = X;
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
input.Controllers[ controller_index ].XPad = new_xpad;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// NOTE: Controller is not available
|
input.Controllers[ controller_index ].XPad = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSL Input Polling
|
// JSL Input Polling
|
||||||
for ( u32 jsl_device_index = 0; jsl_device_index < jsl_num_devices; ++ jsl_device_index )
|
for ( u32 jsl_device_index = 0; jsl_device_index < jsl_num_devices; ++ jsl_device_index )
|
||||||
{
|
{
|
||||||
if ( ! JslStillConnected( device_handles[ jsl_device_index ] ) )
|
if ( ! JslStillConnected( jsl_device_handles[ jsl_device_index ] ) )
|
||||||
{
|
{
|
||||||
OutputDebugStringA( "Error: JSLStillConnected returned false\n" );
|
OutputDebugStringA( "Error: JSLStillConnected returned false\n" );
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
JOY_SHOCK_STATE state = JslGetSimpleState( device_handles[ jsl_device_index ] );
|
// TODO : Won't support more than 4 for now... (or prob ever)
|
||||||
dpad_up = state.buttons & JSMASK_UP;
|
if ( jsl_device_index > 4 )
|
||||||
dpad_down = state.buttons & JSMASK_DOWN;
|
break;
|
||||||
dpad_left = state.buttons & JSMASK_LEFT;
|
|
||||||
dpad_right = state.buttons & JSMASK_RIGHT;
|
|
||||||
start = state.buttons & JSMASK_PLUS;
|
|
||||||
back = state.buttons & JSMASK_MINUS;
|
|
||||||
left_shoulder = state.buttons & JSMASK_L;
|
|
||||||
right_shoulder = state.buttons & JSMASK_R;
|
|
||||||
btn_a = state.buttons & JSMASK_S;
|
|
||||||
btn_b = state.buttons & JSMASK_E;
|
|
||||||
btn_x = state.buttons & JSMASK_W;
|
|
||||||
btn_y = state.buttons & JSMASK_N;
|
|
||||||
|
|
||||||
stick_left_x = state.stickLX;
|
JOY_SHOCK_STATE state = JslGetSimpleState( jsl_device_handles[ jsl_device_index ] );
|
||||||
stick_left_y = state.stickLY;
|
engine::DualsensePadState* old_ds_pad = old_ds_pads[ jsl_device_index ];
|
||||||
stick_right_x = state.stickRX;
|
engine::DualsensePadState* new_ds_pad = new_ds_pads[ jsl_device_index ];
|
||||||
stick_right_y = state.stickRY;
|
|
||||||
}
|
|
||||||
|
|
||||||
x_offset += dpad_right;
|
input_process_digital_btn( & old_ds_pad->DPad.Up, & new_ds_pad->DPad.Up, state.buttons, JSMASK_UP );
|
||||||
x_offset -= dpad_left;
|
input_process_digital_btn( & old_ds_pad->DPad.Down, & new_ds_pad->DPad.Down, state.buttons, JSMASK_DOWN );
|
||||||
y_offset += dpad_up;
|
input_process_digital_btn( & old_ds_pad->DPad.Left, & new_ds_pad->DPad.Left, state.buttons, JSMASK_LEFT );
|
||||||
y_offset -= dpad_down;
|
input_process_digital_btn( & old_ds_pad->DPad.Right, & new_ds_pad->DPad.Right, state.buttons, JSMASK_RIGHT );
|
||||||
|
|
||||||
if ( start )
|
input_process_digital_btn( & old_ds_pad->Triangle, & new_ds_pad->Triangle, state.buttons, JSMASK_N );
|
||||||
{
|
input_process_digital_btn( & old_ds_pad->X, & new_ds_pad->X, state.buttons, JSMASK_S );
|
||||||
if ( xinput_detected )
|
input_process_digital_btn( & old_ds_pad->Square, & new_ds_pad->Square, state.buttons, JSMASK_W );
|
||||||
{
|
input_process_digital_btn( & old_ds_pad->Circle, & new_ds_pad->Circle, state.buttons, JSMASK_E );
|
||||||
XINPUT_VIBRATION vibration;
|
|
||||||
vibration.wLeftMotorSpeed = 30000;
|
input_process_digital_btn( & old_ds_pad->Share, & new_ds_pad->Share, state.buttons, JSMASK_SHARE );
|
||||||
xinput_set_state( 0, & vibration );
|
input_process_digital_btn( & old_ds_pad->Options, & new_ds_pad->Options, state.buttons, JSMASK_OPTIONS );
|
||||||
}
|
|
||||||
else
|
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 );
|
||||||
JslSetRumble( 0, 1, 0 );
|
|
||||||
}
|
// epad->Stick.Left.X.End = state.stickLX;
|
||||||
}
|
// epad->Stick.Left.Y.End = state.stickLY;
|
||||||
else
|
// epad->Stick.Right.X.End = state.stickRX;
|
||||||
{
|
// epad->Stick.Right.X.End = state.stickRY;
|
||||||
if ( xinput_detected )
|
|
||||||
{
|
input.Controllers[ jsl_device_index ].DSPad = new_ds_pad;
|
||||||
XINPUT_VIBRATION vibration;
|
|
||||||
vibration.wLeftMotorSpeed = 0;
|
|
||||||
xinput_set_state( 0, & vibration );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
JslSetRumble( 0, 0, 0 );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Pain...
|
// Pain...
|
||||||
b32 sound_is_valid = false;
|
b32 sound_is_valid = false;
|
||||||
DWORD ds_play_cursor;
|
DWORD ds_play_cursor;
|
||||||
@ -751,17 +783,11 @@ WinMain(
|
|||||||
DWORD bytes_to_write;
|
DWORD bytes_to_write;
|
||||||
if ( SUCCEEDED( DS_SecondaryBuffer->GetCurrentPosition( & ds_play_cursor, & ds_write_cursor ) ))
|
if ( SUCCEEDED( DS_SecondaryBuffer->GetCurrentPosition( & ds_play_cursor, & ds_write_cursor ) ))
|
||||||
{
|
{
|
||||||
DWORD target_cursor = (ds_play_cursor + sound_output.LatencySampleCount * DS_SecondaryBuffer_BytesPerSample) % DS_SecondaryBuffer_Size;
|
|
||||||
|
|
||||||
byte_to_lock = (sound_output.RunningSampleIndex * DS_SecondaryBuffer_BytesPerSample) % DS_SecondaryBuffer_Size;
|
byte_to_lock = (sound_output.RunningSampleIndex * DS_SecondaryBuffer_BytesPerSample) % DS_SecondaryBuffer_Size;
|
||||||
bytes_to_write;
|
DWORD target_cursor = (ds_play_cursor + (sound_output.LatencySampleCount * DS_SecondaryBuffer_BytesPerSample)) % DS_SecondaryBuffer_Size;
|
||||||
|
|
||||||
if ( byte_to_lock == target_cursor )
|
if ( byte_to_lock > target_cursor)
|
||||||
{
|
|
||||||
// We are in the middle of playing. Wait for the write cursor to catch up.
|
|
||||||
bytes_to_write = 0;
|
|
||||||
}
|
|
||||||
else if ( byte_to_lock > target_cursor)
|
|
||||||
{
|
{
|
||||||
// Infront of play cursor |--play--byte_to_write-->--|
|
// Infront of play cursor |--play--byte_to_write-->--|
|
||||||
bytes_to_write = DS_SecondaryBuffer_Size - byte_to_lock;
|
bytes_to_write = DS_SecondaryBuffer_Size - byte_to_lock;
|
||||||
@ -778,15 +804,12 @@ WinMain(
|
|||||||
|
|
||||||
// s16 samples[ 48000 * 2 ];
|
// s16 samples[ 48000 * 2 ];
|
||||||
engine::SoundBuffer sound_buffer {};
|
engine::SoundBuffer sound_buffer {};
|
||||||
sound_buffer.NumSamples = DS_SecondaryBuffer_SamplesPerSecond / 30;
|
sound_buffer.NumSamples = bytes_to_write / DS_SecondaryBuffer_BytesPerSample;
|
||||||
sound_buffer.RunningSampleIndex = sound_output.RunningSampleIndex;
|
sound_buffer.RunningSampleIndex = sound_output.RunningSampleIndex;
|
||||||
sound_buffer.SamplesPerSecond = DS_SecondaryBuffer_SamplesPerSecond;
|
sound_buffer.SamplesPerSecond = DS_SecondaryBuffer_SamplesPerSecond;
|
||||||
sound_buffer.ToneVolume = sound_output.ToneVolume;
|
|
||||||
sound_buffer.Samples = SoundBufferSamples;
|
sound_buffer.Samples = SoundBufferSamples;
|
||||||
sound_buffer.WavePeriod = sound_output.WavePeriod;
|
|
||||||
sound_buffer.WaveToneHz = sound_output.WaveToneHz;
|
|
||||||
|
|
||||||
engine::update_and_render( rcast(engine::OffscreenBuffer*, & BackBuffer.Memory), & sound_buffer, x_offset, y_offset );
|
engine::update_and_render( & input, rcast(engine::OffscreenBuffer*, & BackBuffer.Memory), & sound_buffer );
|
||||||
|
|
||||||
// Rendering
|
// Rendering
|
||||||
{
|
{
|
||||||
@ -799,29 +822,6 @@ WinMain(
|
|||||||
|
|
||||||
// Audio
|
// Audio
|
||||||
do {
|
do {
|
||||||
if ( btn_y )
|
|
||||||
{
|
|
||||||
sound_output.ToneVolume += 10;
|
|
||||||
}
|
|
||||||
if ( btn_b )
|
|
||||||
{
|
|
||||||
sound_output.ToneVolume -= 10;
|
|
||||||
}
|
|
||||||
if ( btn_x )
|
|
||||||
{
|
|
||||||
sound_output.WaveToneHz += 1;
|
|
||||||
sound_output.WavePeriod = DS_SecondaryBuffer_SamplesPerSecond / sound_output.WaveToneHz;
|
|
||||||
}
|
|
||||||
if ( btn_a )
|
|
||||||
{
|
|
||||||
sound_output.WaveToneHz -= 1;
|
|
||||||
sound_output.WavePeriod = DS_SecondaryBuffer_SamplesPerSecond / sound_output.WaveToneHz;
|
|
||||||
}
|
|
||||||
if ( back )
|
|
||||||
{
|
|
||||||
wave_switch ^= true;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD ds_status = 0;
|
DWORD ds_status = 0;
|
||||||
if ( SUCCEEDED( DS_SecondaryBuffer->GetStatus( & ds_status ) ) )
|
if ( SUCCEEDED( DS_SecondaryBuffer->GetStatus( & ds_status ) ) )
|
||||||
{
|
{
|
||||||
@ -854,9 +854,9 @@ WinMain(
|
|||||||
u32 ms_per_frame = MS_PER_SECOND * frame_time_elapsed / perf_counter_frequency;
|
u32 ms_per_frame = MS_PER_SECOND * frame_time_elapsed / perf_counter_frequency;
|
||||||
u32 fps = perf_counter_frequency / frame_time_elapsed;
|
u32 fps = perf_counter_frequency / frame_time_elapsed;
|
||||||
|
|
||||||
char ms_timing_debug[256] {};
|
// char ms_timing_debug[256] {};
|
||||||
wsprintfA( ms_timing_debug, "%d ms\n" "FPS: %d\n" "mega cycles: %d\n", ms_per_frame, fps, mega_cycles_elapsed );
|
// wsprintfA( ms_timing_debug, "%d ms\n" "FPS: %d\n" "mega cycles: %d\n", ms_per_frame, fps, mega_cycles_elapsed );
|
||||||
OutputDebugStringA( ms_timing_debug );
|
// OutputDebugStringA( ms_timing_debug );
|
||||||
|
|
||||||
last_cycle_time = end_cycle_count;
|
last_cycle_time = end_cycle_count;
|
||||||
last_frame_time = frame_cycle_time_end;
|
last_frame_time = frame_cycle_time_end;
|
||||||
@ -864,15 +864,11 @@ WinMain(
|
|||||||
|
|
||||||
if ( jsl_num_devices > 0 )
|
if ( jsl_num_devices > 0 )
|
||||||
{
|
{
|
||||||
OutputDebugStringA( "JSL Connected Devices:\n" );
|
|
||||||
for ( u32 jsl_device_index = 0; jsl_device_index < jsl_num_devices; ++ jsl_device_index )
|
for ( u32 jsl_device_index = 0; jsl_device_index < jsl_num_devices; ++ jsl_device_index )
|
||||||
{
|
{
|
||||||
JslSetLightColour( device_handles[ jsl_device_index ], 0 );
|
JslSetLightColour( jsl_device_handles[ jsl_device_index ], 0 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Engine layer translation unit.
|
|
||||||
// #include "engine.cpp"
|
|
||||||
|
@ -38,3 +38,6 @@
|
|||||||
#define do_once_end \
|
#define do_once_end \
|
||||||
} \
|
} \
|
||||||
while(0);
|
while(0);
|
||||||
|
|
||||||
|
|
||||||
|
#define array_count( array ) ( sizeof( array ) / sizeof( ( array )[0] ) )
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "grime.h"
|
#include "grime.h"
|
||||||
#include "macros.h"
|
#include "macros.h"
|
||||||
|
#include "generics.h"
|
||||||
#include "math_constants.h"
|
#include "math_constants.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
@ -4,29 +4,31 @@
|
|||||||
|
|
||||||
#define U8_MIN 0u
|
#define U8_MIN 0u
|
||||||
#define U8_MAX 0xffu
|
#define U8_MAX 0xffu
|
||||||
#define I8_MIN ( -0x7f - 1 )
|
#define S8_MIN ( -0x7f - 1 )
|
||||||
#define I8_MAX 0x7f
|
#define S8_MAX 0x7f
|
||||||
|
|
||||||
#define U16_MIN 0u
|
#define U16_MIN 0u
|
||||||
#define U16_MAX 0xffffu
|
#define U16_MAX 0xffffu
|
||||||
#define I16_MIN ( -0x7fff - 1 )
|
#define S16_MIN ( -0x7fff - 1 )
|
||||||
#define I16_MAX 0x7fff
|
#define S16_MAX 0x7fff
|
||||||
|
|
||||||
#define U32_MIN 0u
|
#define U32_MIN 0u
|
||||||
#define U32_MAX 0xffffffffu
|
#define U32_MAX 0xffffffffu
|
||||||
#define I32_MIN ( -0x7fffffff - 1 )
|
#define S32_MIN ( -0x7fffffff - 1 )
|
||||||
#define I32_MAX 0x7fffffff
|
#define S32_MAX 0x7fffffff
|
||||||
|
|
||||||
#define U64_MIN 0ull
|
#define U64_MIN 0ull
|
||||||
#define U64_MAX 0xffffffffffffffffull
|
#define U64_MAX 0xffffffffffffffffull
|
||||||
#define I64_MIN ( -0x7fffffffffffffffll - 1 )
|
#define S64_MIN ( -0x7fffffffffffffffll - 1 )
|
||||||
#define I64_MAX 0x7fffffffffffffffll
|
#define S64_MAX 0x7fffffffffffffffll
|
||||||
|
|
||||||
|
// Word size is the same as uw or size_t. This engine will not run on some weird compiler that doesn't
|
||||||
|
// Match the largest object to the word size of the architecture.
|
||||||
#if defined( ARCH_64_BIT )
|
#if defined( ARCH_64_BIT )
|
||||||
# define USIZE_MIN GEN_U64_MIN
|
# define UWORD_MIN U64_MIN
|
||||||
# define USIZE_MAX GEN_U64_MAX
|
# define UWORD_MAX U64_MAX
|
||||||
# define ISIZE_MIN GEN_I64_MIN
|
# define SWORD_MIN S64_MIN
|
||||||
# define ISIZE_MAX GEN_I64_MAX
|
# define SWORD_MAX S64_MAX
|
||||||
#else
|
#else
|
||||||
# error Unknown architecture size. This library only supports 64 bit architectures.
|
# error Unknown architecture size. This library only supports 64 bit architectures.
|
||||||
#endif
|
#endif
|
||||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user