mirror of
				https://github.com/Ed94/HandmadeHero.git
				synced 2025-11-03 15:26:12 -08:00 
			
		
		
		
	Added win32 missing files.
This commit is contained in:
		
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -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/
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										187
									
								
								project/platform/win32/win32.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								project/platform/win32/win32.hpp
									
									
									
									
									
										Normal 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
 | 
			
		||||
							
								
								
									
										453
									
								
								project/platform/win32/win32_audio.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										453
									
								
								project/platform/win32/win32_audio.cpp
									
									
									
									
									
										Normal 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
 | 
			
		||||
							
								
								
									
										227
									
								
								project/platform/win32/win32_input.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								project/platform/win32/win32_input.cpp
									
									
									
									
									
										Normal 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
 | 
			
		||||
							
								
								
									
										1006
									
								
								project/platform/win32/win32_platform.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1006
									
								
								project/platform/win32/win32_platform.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										261
									
								
								project/platform/win32/win32_platform_api.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										261
									
								
								project/platform/win32/win32_platform_api.cpp
									
									
									
									
									
										Normal 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
 | 
			
		||||
		Reference in New Issue
	
	Block a user