Added win32 missing files.

This commit is contained in:
Edward R. Gonzalez 2023-10-01 23:40:47 -04:00
parent 42dc75900f
commit 80996709fe
6 changed files with 2134 additions and 4 deletions

4
.gitignore vendored
View File

@ -8,10 +8,6 @@
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/

View File

@ -0,0 +1,187 @@
/*
Windows dependency header
*/
#pragma once
#pragma warning( push )
#pragma warning( disable: 5105 )
#pragma warning( disable: 4820 )
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <xinput.h>
#include <mmeapi.h>
#include <dsound.h>
#include <timeapi.h>
#pragma warning( pop )
// #include "windows/windows_base.h"
// #include "windows/window.h"
// #include "windows/file.h"
// #include "windows/io.h"
// #if Build_Debug
// # include "windows/dbghelp.h"
// #endif
#if Build_DLL
# define WIN_LIB_API extern "C" __declspec(dllexport)
#else
# define WIN_LIB_API extern "C"
#endif
// #ifndef CONST
// # define CONST const
// #endif
// SAL BS
#ifndef _In_
# define _In_
#endif
#define NS_WIN32_BEGIN namespace win32 {
#define NS_WIN32_END }
NS_WIN32_BEGIN
enum LWA : DWORD
{
LWA_Alpha = 0x00000002,
LWA_ColorKey = 0x00000001,
};
enum BI : DWORD
{
BI_RGB_Uncompressed = 0L,
BI_RunLength_Encoded_8bpp = 1L,
BI_RunLength_Encoded_4bpp = 2L,
};
enum CS : UINT
{
CS_Own_Device_Context = CS_OWNDC,
CS_Horizontal_Redraw = CS_HREDRAW,
CS_Vertical_Redraw = CS_VREDRAW,
};
enum CW : s32
{
CW_Use_Default = CW_USEDEFAULT,
};
enum DIB : UINT
{
DIB_ColorTable_RGB = 0,
DIB_ColorTable_Palette = 1
};
enum MB : UINT
{
MB_Ok_Btn = MB_OK,
MB_Icon_Information = MB_ICONINFORMATION,
};
enum Mem : DWORD
{
MEM_Commit_Zeroed = MEM_COMMIT,
MEM_Reserve = MEM_RESERVE,
MEM_Release = MEM_RELEASE,
MEM_Use_Large_pages = MEM_LARGE_PAGES,
};
enum Page : DWORD
{
Page_Read_Write = PAGE_READWRITE,
};
enum PM : UINT
{
PM_Remove_Messages_From_Queue = PM_REMOVE,
};
enum RasterOps : DWORD
{
RO_Source_To_Dest = (DWORD)0x00CC0020,
RO_Blackness = (DWORD)0x00000042,
RO_Whiteness = (DWORD)0x00FF0062,
};
#define WM_ACTIVATEAPP 0x001C
enum WS : UINT
{
WS_Overlapped_Window = WS_OVERLAPPEDWINDOW,
WS_Initially_Visible = WS_VISIBLE,
};
enum XI_State : DWORD
{
XI_PluggedIn = ERROR_SUCCESS,
};
template< typename ProcSignature >
ProcSignature* get_procedure_from_library( HMODULE library_module, char const* symbol )
{
void* address = rcast( void*, GetProcAddress( library_module, symbol ) );
return rcast( ProcSignature*, address );
}
#pragma region XInput
WIN_LIB_API DWORD WINAPI XInputGetState
(
DWORD dwUserIndex, // Index of the gamer associated with the device
XINPUT_STATE* pState // Receives the current state
);
WIN_LIB_API DWORD WINAPI XInputSetState
(
DWORD dwUserIndex, // Index of the gamer associated with the device
XINPUT_VIBRATION* pVibration // The vibration information to send to the controller
);
DWORD WINAPI xinput_get_state_stub( DWORD dwUserIndex, XINPUT_STATE* pVibration ) {
do_once_start
OutputDebugStringA( "xinput_get_state stubbed!\n");
do_once_end
return ERROR_DEVICE_NOT_CONNECTED;
}
DWORD WINAPI xinput_set_state_stub( DWORD dwUserIndex, XINPUT_VIBRATION* pVibration ) {
do_once_start
OutputDebugStringA( "xinput_set_state stubbed!\n");
do_once_end
return ERROR_DEVICE_NOT_CONNECTED;
}
using XInputGetStateFn = DWORD WINAPI( DWORD dwUserIndex, XINPUT_STATE* pVibration );
using XInputSetStateFn = DWORD WINAPI( DWORD dwUserIndex, XINPUT_VIBRATION* pVibration );
global XInputGetStateFn* xinput_get_state = xinput_get_state_stub;
global XInputSetStateFn* xinput_set_state = xinput_set_state_stub;
internal void
xinput_load_library_bindings()
{
HMODULE xinput_lib = LoadLibraryA( XINPUT_DLL_A );
XInputGetStateFn* get_state = get_procedure_from_library< XInputGetStateFn >( xinput_lib, "XInputGetState" );
XInputSetStateFn* set_state = get_procedure_from_library< XInputSetStateFn >( xinput_lib, "XInputSetState" );
if ( get_state )
xinput_get_state = get_state;
if ( set_state )
xinput_set_state = set_state;
}
#pragma endregion XInput
NS_WIN32_END
#undef _SAL_nop_impl_
#undef _SAL2_Source_
#undef _Deref_post2_impl_
#undef _Outptr_result_bytebuffer_
#undef _At_
#undef _When_
#undef GDI_DIBSIZE

View File

@ -0,0 +1,453 @@
#include "platform/platform.hpp"
#include "win32.hpp"
NS_PLATFORM_BEGIN
// TODO : This will def need to be looked over.
struct DirectSoundBuffer
{
LPDIRECTSOUNDBUFFER secondary_buffer;
s16* samples;
u32 secondary_buffer_size;
u32 samples_per_second;
u32 bytes_per_sample;
u32 bytes_per_second;
u32 guard_sample_bytes;
DWORD is_playing;
u32 running_sample_index;
u32 latency_sample_count;
};
struct AudioTimeMarker
{
DWORD output_play_cursor;
DWORD output_write_cursor;
DWORD output_location;
DWORD output_byte_count;
DWORD flip_play_curosr;
DWORD flip_write_cursor;
DWORD expected_flip_cursor;
};
using DirectSoundCreateFn = HRESULT WINAPI (LPGUID lpGuid, LPDIRECTSOUND* ppDS, LPUNKNOWN pUnkOuter );
global DirectSoundCreateFn* direct_sound_create;
#if Build_Development
internal void
debug_draw_vertical_line( s32 x_pos, s32 top, s32 bottom, s32 color )
{
if ( top <= 0 )
{
top = 0;
}
if ( bottom > Surface_Back_Buffer.height )
{
bottom = Surface_Back_Buffer.height;
}
if ( x_pos >= 0 && x_pos < Surface_Back_Buffer.width )
{
u8*
pixel_byte = rcast(u8*, Surface_Back_Buffer.memory );
pixel_byte += x_pos * Surface_Back_Buffer.bytes_per_pixel;
pixel_byte += top * Surface_Back_Buffer.pitch;
for ( s32 y = top; y < bottom; ++ y )
{
s32* pixel = rcast(s32*, pixel_byte);
*pixel = color;
pixel_byte += Surface_Back_Buffer.pitch;
}
}
}
inline void
debug_draw_sound_buffer_marker( DirectSoundBuffer* sound_buffer, f32 ratio
, u32 pad_x, u32 pad_y
, u32 top, u32 bottom
, DWORD value, u32 color )
{
// assert( value < sound_buffer->SecondaryBufferSize );
u32 x = pad_x + scast(u32, ratio * scast(f32, value ));
debug_draw_vertical_line( x, top, bottom, color );
}
internal void
debug_sync_display( DirectSoundBuffer* sound_buffer
, u32 num_markers, AudioTimeMarker* markers
, u32 current_marker
, f32 ms_per_frame )
{
u32 pad_x = 32;
u32 pad_y = 16;
f32 buffers_ratio = scast(f32, Surface_Back_Buffer.width) / (scast(f32, sound_buffer->secondary_buffer_size) * 1);
u32 line_height = 64;
for ( u32 marker_index = 0; marker_index < num_markers; ++ marker_index )
{
AudioTimeMarker* marker = & markers[marker_index];
assert( marker->output_play_cursor < sound_buffer->secondary_buffer_size );
assert( marker->output_write_cursor < sound_buffer->secondary_buffer_size );
assert( marker->output_location < sound_buffer->secondary_buffer_size );
assert( marker->output_byte_count < sound_buffer->secondary_buffer_size );
assert( marker->flip_play_curosr < sound_buffer->secondary_buffer_size );
assert( marker->flip_write_cursor < sound_buffer->secondary_buffer_size );
DWORD play_color = 0x88888888;
DWORD write_color = 0x88800000;
DWORD expected_flip_color = 0xFFFFF000;
DWORD play_window_color = 0xFFFF00FF;
u32 top = pad_y;
u32 bottom = pad_y + line_height;
if ( marker_index == current_marker )
{
play_color = 0xFFFFFFFF;
write_color = 0xFFFF0000;
top += pad_y + line_height;
bottom += pad_y + line_height;
u32 row_2_top = top;
debug_draw_sound_buffer_marker( sound_buffer, buffers_ratio, pad_x, pad_y, top, bottom, marker->output_play_cursor, play_color );
debug_draw_sound_buffer_marker( sound_buffer, buffers_ratio, pad_x, pad_y, top, bottom, marker->output_write_cursor, write_color );
play_color = 0xFFFFFFFF;
write_color = 0xFFFF0000;
top += pad_y + line_height;
bottom += pad_y + line_height;
debug_draw_sound_buffer_marker( sound_buffer, buffers_ratio, pad_x, pad_y, top, bottom, marker->output_location, play_color );
debug_draw_sound_buffer_marker( sound_buffer, buffers_ratio, pad_x, pad_y, top, bottom, marker->output_location + marker->output_byte_count, write_color );
play_color = 0xFFFFFFFF;
write_color = 0xFFFF0000;
top += pad_y + line_height;
bottom += pad_y + line_height;
debug_draw_sound_buffer_marker( sound_buffer, buffers_ratio, pad_x, pad_y, row_2_top, bottom, marker->expected_flip_cursor, expected_flip_color );
}
DWORD play_window = marker->flip_play_curosr + 480 * sound_buffer->bytes_per_sample;
debug_draw_sound_buffer_marker( sound_buffer, buffers_ratio, pad_x, pad_y, top, bottom, marker->flip_play_curosr, play_color );
debug_draw_sound_buffer_marker( sound_buffer, buffers_ratio, pad_x, pad_y, top, bottom, play_window, play_window_color );
debug_draw_sound_buffer_marker( sound_buffer, buffers_ratio, pad_x, pad_y, top, bottom, marker->flip_write_cursor, write_color );
}
}
#endif
internal void
init_sound(HWND window_handle, DirectSoundBuffer* sound_buffer )
{
// Load library
HMODULE sound_library = LoadLibraryA( "dsound.dll" );
if ( ! ensure(sound_library, "Failed to load direct sound library" ) )
{
// TOOD : Diagnostic
return;
}
// Get direct sound object
direct_sound_create = get_procedure_from_library< DirectSoundCreateFn >( sound_library, "DirectSoundCreate" );
if ( ! ensure( direct_sound_create, "Failed to get direct_sound_create_procedure" ) )
{
// TOOD : Diagnostic
return;
}
LPDIRECTSOUND direct_sound;
if ( ! SUCCEEDED(direct_sound_create( 0, & direct_sound, 0 )) )
{
// TODO : Diagnostic
}
if ( ! SUCCEEDED( direct_sound->SetCooperativeLevel(window_handle, DSSCL_PRIORITY) ) )
{
// TODO : Diagnostic
}
WAVEFORMATEX
wave_format {};
wave_format.wFormatTag = WAVE_FORMAT_PCM; /* format type */
wave_format.nChannels = 2; /* number of channels (i.e. mono, stereo...) */
wave_format.nSamplesPerSec = scast(u32, sound_buffer->samples_per_second); /* sample rate */
wave_format.wBitsPerSample = 16; /* number of bits per sample of mono data */
wave_format.nBlockAlign = wave_format.nChannels * wave_format.wBitsPerSample / 8 ; /* block size of data */
wave_format.nAvgBytesPerSec = wave_format.nSamplesPerSec * wave_format.nBlockAlign; /* for buffer estimation */
wave_format.cbSize = 0; /* the count in bytes of the size of */
LPDIRECTSOUNDBUFFER primary_buffer;
{
DSBUFFERDESC
buffer_description { sizeof(buffer_description) };
buffer_description.dwFlags = DSBCAPS_PRIMARYBUFFER;
buffer_description.dwBufferBytes = 0;
if ( ! SUCCEEDED( direct_sound->CreateSoundBuffer( & buffer_description, & primary_buffer, 0 ) ))
{
// TODO : Diagnostic
}
if ( ! SUCCEEDED( primary_buffer->SetFormat( & wave_format ) ) )
{
// TODO : Diagnostic
}
}
DSBUFFERDESC
buffer_description { sizeof(buffer_description) };
buffer_description.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
buffer_description.dwBufferBytes = sound_buffer->secondary_buffer_size;
buffer_description.lpwfxFormat = & wave_format;
if ( ! SUCCEEDED( direct_sound->CreateSoundBuffer( & buffer_description, & sound_buffer->secondary_buffer, 0 ) ))
{
// TODO : Diagnostic
}
if ( ! SUCCEEDED( sound_buffer->secondary_buffer->SetFormat( & wave_format ) ) )
{
// TODO : Diagnostic
}
}
internal void
ds_clear_sound_buffer( DirectSoundBuffer* sound_buffer )
{
LPVOID region_1;
DWORD region_1_size;
LPVOID region_2;
DWORD region_2_size;
HRESULT ds_lock_result = sound_buffer->secondary_buffer->Lock( 0, sound_buffer->secondary_buffer_size
, & region_1, & region_1_size
, & region_2, & region_2_size
, 0 );
if ( ! SUCCEEDED( ds_lock_result ) )
{
return;
}
u8* sample_out = rcast( u8*, region_1 );
for ( DWORD byte_index = 0; byte_index < region_1_size; ++ byte_index )
{
*sample_out = 0;
++ sample_out;
}
sample_out = rcast( u8*, region_2 );
for ( DWORD byte_index = 0; byte_index < region_2_size; ++ byte_index )
{
*sample_out = 0;
++ sample_out;
}
if ( ! SUCCEEDED( sound_buffer->secondary_buffer->Unlock( region_1, region_1_size, region_2, region_2_size ) ))
{
return;
}
}
internal void
ds_fill_sound_buffer( DirectSoundBuffer* sound_buffer, DWORD byte_to_lock, DWORD bytes_to_write )
{
LPVOID region_1;
DWORD region_1_size;
LPVOID region_2;
DWORD region_2_size;
HRESULT ds_lock_result = sound_buffer->secondary_buffer->Lock( byte_to_lock, bytes_to_write
, & region_1, & region_1_size
, & region_2, & region_2_size
, 0 );
if ( ! SUCCEEDED( ds_lock_result ) )
{
return;
}
// TODO : Assert that region sizes are valid
DWORD region_1_sample_count = region_1_size / sound_buffer->bytes_per_sample;
s16* sample_out = rcast( s16*, region_1 );
s16* sample_in = sound_buffer->samples;
for ( DWORD sample_index = 0; sample_index < region_1_sample_count; ++ sample_index )
{
*sample_out = *sample_in;
++ sample_out;
++ sample_in;
*sample_out = *sample_in;
++ sample_out;
++ sample_in;
++ sound_buffer->running_sample_index;
}
DWORD region_2_sample_count = region_2_size / sound_buffer->bytes_per_sample;
sample_out = rcast( s16*, region_2 );
for ( DWORD sample_index = 0; sample_index < region_2_sample_count; ++ sample_index )
{
*sample_out = *sample_in;
++ sample_out;
++ sample_in;
*sample_out = *sample_in;
++ sample_out;
++ sample_in;
++ sound_buffer->running_sample_index;
}
if ( ! SUCCEEDED( sound_buffer->secondary_buffer->Unlock( region_1, region_1_size, region_2, region_2_size ) ))
{
return;
}
}
internal
void process_audio_frame( DirectSoundBuffer& ds_sound_buffer, DWORD& ds_play_cursor, DWORD& ds_write_cursor, f32& ds_latency_ms
, b32& sound_is_valid
, AudioTimeMarker* audio_time_markers, u32 audio_marker_index
, f32 flip_to_audio_ms, u64 last_frame_clock
, engine::ModuleAPI& engine_api, engine::Memory* engine_memory, ModuleAPI* platform_api, engine::ThreadContext* thread_context_placeholder)
{
/*
Audio Processing:
There is a sync boundary value, that is the number of samples that the engine's frame-time may vary by
(ex: approx 2ms of variance between frame-times).
On wakeup : Check play cursor position and forcast ahead where the cursor will be for the next sync boundary.
Based on that, check the write cursor position, if its (at least) before the synch boundary, the target write position is
the frame boundary plus one frame. (Low latency)
If its after (sync boundary), we cannot sync audio.
Write a frame's worth of audio plus some number of "guard" samples. (High Latency)
*/
if ( ! SUCCEEDED( ds_sound_buffer.secondary_buffer->GetCurrentPosition( & ds_play_cursor, & ds_write_cursor ) ))
{
sound_is_valid = false;
return;
}
if ( ! sound_is_valid )
{
ds_sound_buffer.running_sample_index = ds_write_cursor / ds_sound_buffer.bytes_per_sample;
sound_is_valid = true;
}
DWORD byte_to_lock = 0;
DWORD target_cursor = 0;
DWORD bytes_to_write = 0;
byte_to_lock = (ds_sound_buffer.running_sample_index * ds_sound_buffer.bytes_per_sample) % ds_sound_buffer.secondary_buffer_size;
DWORD bytes_per_second = ds_sound_buffer.bytes_per_sample * ds_sound_buffer.samples_per_second;
DWORD expected_samplebytes_per_frame = bytes_per_second / Engine_Refresh_Hz;
f32 left_until_flip_ms = Engine_Frame_Target_MS - flip_to_audio_ms;
DWORD expected_bytes_until_flip = scast(DWORD, (left_until_flip_ms / Engine_Frame_Target_MS) * scast(f32, expected_samplebytes_per_frame));
DWORD expected_sync_boundary_byte = ds_play_cursor + expected_bytes_until_flip;
DWORD sync_write_cursor = ds_write_cursor;
if ( sync_write_cursor < ds_play_cursor )
{
// unwrap the cursor so its ahead of the play curosr linearly.
sync_write_cursor += ds_sound_buffer.secondary_buffer_size;
}
assert( sync_write_cursor >= ds_play_cursor );
sync_write_cursor += ds_sound_buffer.guard_sample_bytes;
b32 audio_interface_is_low_latency = sync_write_cursor < expected_sync_boundary_byte;
if ( audio_interface_is_low_latency )
{
target_cursor = ( expected_sync_boundary_byte + expected_samplebytes_per_frame );
}
else
{
target_cursor = (ds_write_cursor + expected_samplebytes_per_frame + ds_sound_buffer.guard_sample_bytes);
}
target_cursor %= ds_sound_buffer.secondary_buffer_size;
if ( byte_to_lock > target_cursor)
{
// Infront of play cursor |--play--byte_to_write-->--|
bytes_to_write = ds_sound_buffer.secondary_buffer_size - byte_to_lock;
bytes_to_write += target_cursor;
}
else
{
// Behind play cursor |--byte_to_write-->--play--|
bytes_to_write = target_cursor - byte_to_lock;
}
// Engine Sound
// f32 delta_time = timing_get_seconds_elapsed( last_frame_clock, timing_get_wall_clock() );
// s16 samples[ 48000 * 2 ];
engine::AudioBuffer sound_buffer {};
sound_buffer.num_samples = bytes_to_write / ds_sound_buffer.bytes_per_sample;
sound_buffer.running_sample_index = ds_sound_buffer.running_sample_index;
sound_buffer.samples_per_second = ds_sound_buffer.samples_per_second;
sound_buffer.samples = ds_sound_buffer.samples;
engine_api.update_audio( 0.f, & sound_buffer, engine_memory, platform_api, thread_context_placeholder );
AudioTimeMarker* marker = & audio_time_markers[ audio_marker_index ];
marker->output_play_cursor = ds_play_cursor;
marker->output_write_cursor = ds_write_cursor;
marker->output_location = byte_to_lock;
marker->output_byte_count = bytes_to_write;
marker->expected_flip_cursor = expected_sync_boundary_byte;
// Update audio buffer
if ( ! sound_is_valid )
return;
#if Build_Development && 0
#if 0
DWORD play_cursor;
DWORD write_cursor;
ds_sound_buffer.SecondaryBuffer->GetCurrentPosition( & play_cursor, & write_cursor );
#endif
DWORD unwrapped_write_cursor = ds_write_cursor;
if ( unwrapped_write_cursor < ds_play_cursor )
{
unwrapped_write_cursor += ds_sound_buffer.SecondaryBufferSize;
}
ds_cursor_byte_delta = unwrapped_write_cursor - ds_play_cursor;
constexpr f32 to_milliseconds = 1000.f;
f32 sample_delta = scast(f32, ds_cursor_byte_delta) / scast(f32, ds_sound_buffer.BytesPerSample);
f32 ds_latency_s = sample_delta / scast(f32, ds_sound_buffer.SamplesPerSecond);
ds_latency_ms = ds_latency_s * to_milliseconds;
char text_buffer[256];
sprintf_s( text_buffer, sizeof(text_buffer), "BTL:%u TC:%u BTW:%u - PC:%u WC:%u DELTA:%u bytes %f ms\n"
, (u32)byte_to_lock, (u32)target_cursor, (u32)bytes_to_write
, (u32)play_cursor, (u32)write_cursor, (u32)ds_cursor_byte_delta, ds_latency_ms );
OutputDebugStringA( text_buffer );
#endif
ds_fill_sound_buffer( & ds_sound_buffer, byte_to_lock, bytes_to_write );
DWORD ds_status = 0;
if ( SUCCEEDED( ds_sound_buffer.secondary_buffer->GetStatus( & ds_status ) ) )
{
ds_sound_buffer.is_playing = ds_status & DSBSTATUS_PLAYING;
}
if ( ds_sound_buffer.is_playing )
return;
ds_sound_buffer.secondary_buffer->Play( 0, 0, DSBPLAY_LOOPING );
}
NS_PLATFORM_END

View File

@ -0,0 +1,227 @@
#include "platform/platform.hpp"
#include "platform/jsl.hpp"
#include "win32.hpp"
NS_PLATFORM_BEGIN
// Max controllers for the platform layer and thus for all other layers is 4. (Sanity and xinput limit)
constexpr u32 Max_Controllers = 4;
using JSL_DeviceHandle = int;
using EngineXInputPadStates = engine::XInputPadState[ Max_Controllers ];
using EngineDSPadStates = engine::DualsensePadState[Max_Controllers];
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->ended_down != new_state->ended_down )
new_state->ended_down = (raw_btns & btn_flag) > 0;
if ( had_transition() )
new_state->half_transitions += 1;
else
new_state->half_transitions = 0;
#undef had_transition
}
internal f32
jsl_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 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 void
poll_input( HWND window_handle, engine::InputState* input, u32 jsl_num_devices, JSL_DeviceHandle* jsl_device_handles
, engine::KeyboardState* old_keyboard, engine::KeyboardState* new_keyboard
, engine::MousesState* old_mouse, engine::MousesState* new_mouse
, EngineXInputPadStates* old_xpads, EngineXInputPadStates* new_xpads
, EngineDSPadStates* old_ds_pads, EngineDSPadStates* new_ds_pads )
{
// Keyboard Polling
// Keyboards are unified for now.
{
constexpr u32 is_down = 0x80000000;
input_process_digital_btn( & old_keyboard->_1, & new_keyboard->_1, GetAsyncKeyState( '1' ), is_down );
input_process_digital_btn( & old_keyboard->_2, & new_keyboard->_2, GetAsyncKeyState( '2' ), is_down );
input_process_digital_btn( & old_keyboard->_3, & new_keyboard->_3, GetAsyncKeyState( '3' ), is_down );
input_process_digital_btn( & old_keyboard->_4, & new_keyboard->_4, GetAsyncKeyState( '4' ), is_down );
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->K, & new_keyboard->K, GetAsyncKeyState( 'K' ), is_down );
input_process_digital_btn( & old_keyboard->L, & new_keyboard->L, GetAsyncKeyState( 'L' ), 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 );
input_process_digital_btn( & old_keyboard->pause, & new_keyboard->pause, GetAsyncKeyState( VK_PAUSE ), is_down );
input_process_digital_btn( & old_keyboard->left_alt, & new_keyboard->left_alt, GetAsyncKeyState( VK_LMENU ), is_down );
input_process_digital_btn( & old_keyboard->right_alt, & new_keyboard->right_alt, GetAsyncKeyState( VK_RMENU ), is_down );
input_process_digital_btn( & old_keyboard->left_shift, & new_keyboard->left_shift, GetAsyncKeyState( VK_LSHIFT ), is_down );
input_process_digital_btn( & old_keyboard->right_shift, & new_keyboard->right_shift, GetAsyncKeyState( VK_RSHIFT ), is_down );
input->controllers[0].keyboard = new_keyboard;
}
// Mouse polling
{
// input->Controllers[0].Mouse = {};
constexpr u32 is_down = 0x80000000;
input_process_digital_btn( & old_mouse->left, & new_mouse->left, GetAsyncKeyState( VK_LBUTTON ), is_down );
input_process_digital_btn( & old_mouse->middle, & new_mouse->middle, GetAsyncKeyState( VK_MBUTTON ), is_down );
input_process_digital_btn( & old_mouse->right, & new_mouse->right, GetAsyncKeyState( VK_RBUTTON ), is_down );
POINT mouse_pos;
GetCursorPos( & mouse_pos );
ScreenToClient( window_handle, & mouse_pos );
new_mouse->vertical_wheel = {};
new_mouse->horizontal_wheel = {};
new_mouse->X.end = (f32)mouse_pos.x;
new_mouse->Y.end = (f32)mouse_pos.y;
input->controllers[0].mouse = new_mouse;
}
// XInput Polling
// TODO(Ed) : Should we poll this more frequently?
for ( DWORD controller_index = 0; controller_index < Max_Controllers; ++ controller_index )
{
XINPUT_STATE controller_state;
b32 xinput_detected = xinput_get_state( controller_index, & controller_state ) == XI_PluggedIn;
if ( xinput_detected )
{
XINPUT_GAMEPAD* xpad = & controller_state.Gamepad;
engine::XInputPadState* old_xpad = old_xpads[ controller_index ];
engine::XInputPadState* new_xpad = new_xpads[ controller_index ];
input_process_digital_btn( & old_xpad->dpad.up, & new_xpad->dpad.up, xpad->wButtons, XINPUT_GAMEPAD_DPAD_UP );
input_process_digital_btn( & old_xpad->dpad.down, & new_xpad->dpad.down, xpad->wButtons, XINPUT_GAMEPAD_DPAD_DOWN );
input_process_digital_btn( & old_xpad->dpad.left, & new_xpad->dpad.left, xpad->wButtons, XINPUT_GAMEPAD_DPAD_LEFT );
input_process_digital_btn( & old_xpad->dpad.right, & new_xpad->dpad.right, xpad->wButtons, XINPUT_GAMEPAD_DPAD_RIGHT );
input_process_digital_btn( & old_xpad->Y, & new_xpad->Y, xpad->wButtons, XINPUT_GAMEPAD_Y );
input_process_digital_btn( & old_xpad->A, & new_xpad->A, xpad->wButtons, XINPUT_GAMEPAD_A );
input_process_digital_btn( & old_xpad->B, & new_xpad->B, xpad->wButtons, XINPUT_GAMEPAD_B );
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->left_shoulder, & new_xpad->left_shoulder, xpad->wButtons, XINPUT_GAMEPAD_LEFT_SHOULDER );
input_process_digital_btn( & old_xpad->right_shoulder, & new_xpad->right_shoulder, 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;
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 = left_x;
new_xpad->stick.left.Y.min = new_xpad->stick.left.Y.max = new_xpad->stick.left.Y.end = left_y;
// 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;
}
else
{
input->controllers[ controller_index ].xpad = nullptr;
}
}
// JSL Input Polling
for ( u32 jsl_device_index = 0; jsl_device_index < jsl_num_devices; ++ jsl_device_index )
{
if ( ! JslStillConnected( jsl_device_handles[ jsl_device_index ] ) )
{
OutputDebugStringA( "Error: JSLStillConnected returned false\n" );
continue;
}
// TODO : Won't support more than 4 for now... (or prob ever)
if ( jsl_device_index > 4 )
break;
JOY_SHOCK_STATE state = JslGetSimpleState( jsl_device_handles[ jsl_device_index ] );
// For now we're assuming anything that is detected via JSL is a dualsense pad.
// We'll eventually add support possibly for the nintendo pro controller.
engine::DualsensePadState* old_ds_pad = old_ds_pads[ jsl_device_index ];
engine::DualsensePadState* new_ds_pad = new_ds_pads[ jsl_device_index ];
input_process_digital_btn( & old_ds_pad->dpad.up, & new_ds_pad->dpad.up, state.buttons, JSMASK_UP );
input_process_digital_btn( & old_ds_pad->dpad.down, & new_ds_pad->dpad.down, state.buttons, JSMASK_DOWN );
input_process_digital_btn( & old_ds_pad->dpad.left, & new_ds_pad->dpad.left, state.buttons, JSMASK_LEFT );
input_process_digital_btn( & old_ds_pad->dpad.right, & new_ds_pad->dpad.right, state.buttons, JSMASK_RIGHT );
input_process_digital_btn( & old_ds_pad->triangle, & new_ds_pad->triangle, state.buttons, JSMASK_N );
input_process_digital_btn( & old_ds_pad->cross, & new_ds_pad->cross, state.buttons, JSMASK_S );
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 );
input_process_digital_btn( & old_ds_pad->share, & new_ds_pad->share, state.buttons, JSMASK_SHARE );
input_process_digital_btn( & old_ds_pad->options, & new_ds_pad->options, state.buttons, JSMASK_OPTIONS );
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 );
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 = jsl_input_process_axis_value( state.stickLX, 0.1f );
f32 left_y = jsl_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 ].ds_pad = new_ds_pad;
}
}
NS_PLATFORM_END

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,261 @@
#include "platform/platform.hpp"
#include "platform/jsl.hpp"
#include "win32.hpp"
NS_PLATFORM_BEGIN
global b32 Pause_Rendering = false;
#pragma region Platfom API
#if Build_Development
void congrats_impl( char const* message )
{
JslSetLightColour( 0, (255 << 16) | (215 << 8) );
MessageBoxA( 0, message, "Congratulations!", MB_OK | MB_ICONEXCLAMATION );
JslSetLightColour( 0, (255 << 8 ) );
}
bool impl_ensure( bool condition, char const* message )
{
if ( ! condition ) {
JslSetLightColour( 0, (255 << 16) );
MessageBoxA( 0, message, "Ensure Failure", MB_OK | MB_ICONASTERISK );
JslSetLightColour( 0, ( 255 << 8 ) );
}
return condition;
}
void impl_fatal( char const* message )
{
JslSetLightColour( 0, (255 << 16) );
MessageBoxA( 0, message, "Fatal Error", MB_OK | MB_ICONERROR );
JslSetLightColour( 0, (255 << 8 ) );
}
#endif
#if Build_Development
void debug_set_pause_rendering( b32 value )
{
Pause_Rendering = value;
}
#endif
b32 file_check_exists( Str path )
{
HANDLE file_handle = CreateFileA( path
, GENERIC_READ, FILE_SHARE_READ, 0
, OPEN_EXISTING, 0, 0
);
if ( file_handle != INVALID_HANDLE_VALUE )
{
CloseHandle( file_handle );
return true;
}
return false;
}
void file_close( File* file )
{
HANDLE handle = pcast(HANDLE, file->opaque_handle);
if ( handle == INVALID_HANDLE_VALUE )
return;
CloseHandle( handle );
if ( file->data )
{
// TODO(Ed): This should use our persistent memory block.
VirtualFree( file->data, 0, MEM_Release);
}
*file = {};
}
b32 file_delete( Str path )
{
return DeleteFileA( path );
}
b32 file_read_stream( File* file, u32 content_size, void* content_memory )
{
HANDLE file_handle;
if ( file->opaque_handle == nullptr )
{
file_handle = CreateFileA( file->path
, GENERIC_READ, FILE_SHARE_READ, 0
, OPEN_EXISTING, 0, 0
);
if ( file_handle == INVALID_HANDLE_VALUE )
{
// TODO : Logging
return {};
}
file->opaque_handle = file_handle;
}
else
{
file_handle = pcast(HANDLE, file->opaque_handle );
}
u32 bytes_read;
if ( ReadFile( file_handle, content_memory, content_size, rcast(LPDWORD, &bytes_read), 0 ) == false )
{
// TODO : Logging
return {};
}
if ( bytes_read != content_size )
{
// TODO : Logging
return {};
}
return bytes_read;
}
b32 file_read_content( File* file )
{
HANDLE file_handle = CreateFileA( file->path
, GENERIC_READ, FILE_SHARE_READ, 0
, OPEN_EXISTING, 0, 0
);
if ( file_handle == INVALID_HANDLE_VALUE )
{
// TODO(Ed) : Logging
return {};
}
u32 size;
GetFileSizeEx( file_handle, rcast(LARGE_INTEGER*, &size) );
if ( size == 0 )
{
// TODO(Ed) : Logging
CloseHandle( file_handle );
return {};
}
// TODO(Ed) : This should use our memory block.
file->data = rcast(HANDLE*, VirtualAlloc( 0, sizeof(HANDLE) + size, MEM_Commit_Zeroed | MEM_Reserve, Page_Read_Write ));
file->size = size;
file->opaque_handle = file_handle;
u32 bytes_read;
if ( ReadFile( file_handle, file->data, file->size, rcast(LPDWORD, &bytes_read), 0 ) == false )
{
// TODO(Ed) : Logging
CloseHandle( file_handle );
return {};
}
if ( bytes_read != file->size )
{
// TODO : Logging
CloseHandle( file_handle );
return {};
}
return bytes_read;
}
void file_rewind( File* file )
{
HANDLE file_handle = pcast(HANDLE, file->opaque_handle );
if ( file_handle == INVALID_HANDLE_VALUE )
return;
SetFilePointer(file_handle, 0, NULL, FILE_BEGIN);
}
u32 file_write_stream( File* file, u32 content_size, void* content_memory )
{
HANDLE file_handle;
if ( file->opaque_handle == nullptr )
{
file_handle = CreateFileA( file->path
,GENERIC_WRITE, 0, 0
, OPEN_ALWAYS, 0, 0
);
if ( file_handle == INVALID_HANDLE_VALUE )
{
// TODO(Ed) : Logging
return {};
}
file->opaque_handle = file_handle;
}
else
{
file_handle = pcast(HANDLE, file->opaque_handle );
}
DWORD bytes_written;
if ( WriteFile( file_handle, content_memory, content_size, & bytes_written, 0 ) == false )
{
// TODO : Logging
return false;
}
return bytes_written;
}
u32 file_write_content( File* file, u32 content_size, void* content_memory )
{
HANDLE file_handle = CreateFileA( file->path
, GENERIC_WRITE, 0, 0
, CREATE_ALWAYS, 0, 0
);
if ( file_handle == INVALID_HANDLE_VALUE )
{
// TODO : Logging
return false;
}
file->opaque_handle = file_handle;
DWORD bytes_written;
if ( WriteFile( file_handle, content_memory, content_size, & bytes_written, 0 ) == false )
{
// TODO : Logging
return false;
}
return bytes_written;
}
u32 get_monitor_refresh_rate()
{
return 0;
}
void set_monitor_refresh_rate( u32 refresh_rate )
{
}
u32 get_engine_refresh_rate()
{
return 0;
}
void set_engine_refresh_rate( u32 refresh_rate )
{
}
BinaryModule load_binary_module( char const* module_path )
{
HMODULE lib = LoadLibraryA( module_path );
return BinaryModule { scast(void*, lib) };
}
void unload_binary_module( BinaryModule* module )
{
FreeLibrary( scast(HMODULE, module->opaque_handle) );
*module = {};
}
void* get_binary_module_symbol( BinaryModule module, char const* symbol_name )
{
return rcast(void*, GetProcAddress( scast(HMODULE, module.opaque_handle), symbol_name ));
}
void memory_copy( void* dest, u64 src_size, void* src )
{
CopyMemory( dest, src, src_size );
}
#pragma endregion Platform API
NS_PLATFORM_END