670 lines
21 KiB
C
670 lines
21 KiB
C
|
// TODO(allen): Changed durring this jam
|
||
|
// WM_SYSKEYDOWN bell sounds removed
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include <windowsx.h>
|
||
|
#include <xinput.h>
|
||
|
#include <objbase.h>
|
||
|
#include <mmdeviceapi.h>
|
||
|
#include <audioclient.h>
|
||
|
#include <audiopolicy.h>
|
||
|
#undef DeleteFile
|
||
|
|
||
|
// NOTE(rjf): OpenGL
|
||
|
#include <gl/gl.h>
|
||
|
#include "ext/wglext.h"
|
||
|
#include "ext/glext.h"
|
||
|
|
||
|
// NOTE(rjf): CRT
|
||
|
#include <stdio.h>
|
||
|
|
||
|
// NOTE(rjf): Headers
|
||
|
#include "program_options.h"
|
||
|
#include "language_layer.h"
|
||
|
#include "app_memory.h"
|
||
|
#include "os.h"
|
||
|
#include "win32_timer.h"
|
||
|
|
||
|
#include "language_layer.c"
|
||
|
#include "app_memory.c"
|
||
|
#include "os.c"
|
||
|
|
||
|
// NOTE(rjf): Globals
|
||
|
global char global_executable_path[256];
|
||
|
global char global_executable_directory[256];
|
||
|
global char global_working_directory[256];
|
||
|
global char global_app_dll_path[256];
|
||
|
global char global_temp_app_dll_path[256];
|
||
|
global OS_State global_os;
|
||
|
global HDC global_device_context;
|
||
|
global HINSTANCE global_instance_handle;
|
||
|
global W32_Timer global_win32_timer = {0};
|
||
|
#define W32_MAX_GAMEPADS 16
|
||
|
typedef struct W32_GamepadInput W32_GamepadInput;
|
||
|
struct W32_GamepadInput
|
||
|
{
|
||
|
b32 connected;
|
||
|
v2 joystick_1;
|
||
|
v2 joystick_2;
|
||
|
f32 trigger_left;
|
||
|
f32 trigger_right;
|
||
|
i32 button_states[GamepadButton_Max];
|
||
|
};
|
||
|
W32_GamepadInput global_gamepads[W32_MAX_GAMEPADS];
|
||
|
|
||
|
|
||
|
// NOTE(rjf): Implementations
|
||
|
#include "win32_utilities.c"
|
||
|
#include "win32_timer.c"
|
||
|
#include "win32_file_io.c"
|
||
|
#include "win32_app_code.c"
|
||
|
#include "win32_xinput.c"
|
||
|
#include "win32_wasapi.c"
|
||
|
#include "win32_opengl.c"
|
||
|
#include "win32_thread.c"
|
||
|
|
||
|
//~
|
||
|
|
||
|
typedef enum W32_CursorStyle
|
||
|
{
|
||
|
W32_CursorStyle_Normal,
|
||
|
W32_CursorStyle_HorizontalResize,
|
||
|
W32_CursorStyle_VerticalResize,
|
||
|
W32_CursorStyle_IBar,
|
||
|
}
|
||
|
W32_CursorStyle;
|
||
|
|
||
|
global W32_CursorStyle global_cursor_style = 0;
|
||
|
|
||
|
internal v2
|
||
|
W32_GetMousePosition(HWND window)
|
||
|
{
|
||
|
v2 result = {0};
|
||
|
POINT mouse;
|
||
|
GetCursorPos(&mouse);
|
||
|
ScreenToClient(window, &mouse);
|
||
|
result.x = (f32)(mouse.x);
|
||
|
result.y = (f32)(mouse.y);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
internal LRESULT
|
||
|
W32_WindowProc(HWND window_handle, UINT message, WPARAM w_param, LPARAM l_param)
|
||
|
{
|
||
|
LRESULT result = 0;
|
||
|
|
||
|
local_persist b32 mouse_hover_active_because_windows_makes_me_cry = 0;
|
||
|
|
||
|
KeyModifiers modifiers = 0;
|
||
|
if(GetKeyState(VK_CONTROL) & 0x8000)
|
||
|
{
|
||
|
modifiers |= KeyModifier_Ctrl;
|
||
|
}
|
||
|
if(GetKeyState(VK_SHIFT) & 0x8000)
|
||
|
{
|
||
|
modifiers |= KeyModifier_Shift;
|
||
|
}
|
||
|
if(GetKeyState(VK_MENU) & 0x8000)
|
||
|
{
|
||
|
modifiers |= KeyModifier_Alt;
|
||
|
}
|
||
|
|
||
|
if(message == WM_CLOSE || message == WM_DESTROY || message == WM_QUIT)
|
||
|
{
|
||
|
global_os.quit = 1;
|
||
|
result = 0;
|
||
|
}
|
||
|
else if(message == WM_LBUTTONDOWN)
|
||
|
{
|
||
|
OS_PushEvent(OS_MousePressEvent(MouseButton_Left, global_os.mouse_position));
|
||
|
}
|
||
|
else if(message == WM_LBUTTONUP)
|
||
|
{
|
||
|
OS_PushEvent(OS_MouseReleaseEvent(MouseButton_Left, global_os.mouse_position));
|
||
|
}
|
||
|
else if(message == WM_RBUTTONDOWN)
|
||
|
{
|
||
|
OS_PushEvent(OS_MousePressEvent(MouseButton_Right, global_os.mouse_position));
|
||
|
}
|
||
|
else if(message == WM_RBUTTONUP)
|
||
|
{
|
||
|
OS_PushEvent(OS_MouseReleaseEvent(MouseButton_Right, global_os.mouse_position));
|
||
|
}
|
||
|
else if(message == WM_MOUSEMOVE)
|
||
|
{
|
||
|
i16 x_position = LOWORD(l_param);
|
||
|
i16 y_position = HIWORD(l_param);
|
||
|
v2 last_mouse = global_os.mouse_position;
|
||
|
global_os.mouse_position = W32_GetMousePosition(window_handle);
|
||
|
OS_PushEvent(OS_MouseMoveEvent(global_os.mouse_position,
|
||
|
v2(global_os.mouse_position.x - last_mouse.x,
|
||
|
global_os.mouse_position.y - last_mouse.y)));
|
||
|
|
||
|
if(mouse_hover_active_because_windows_makes_me_cry == 0)
|
||
|
{
|
||
|
mouse_hover_active_because_windows_makes_me_cry = 1;
|
||
|
TRACKMOUSEEVENT track_mouse_event = {0};
|
||
|
{
|
||
|
track_mouse_event.cbSize = sizeof(track_mouse_event);
|
||
|
track_mouse_event.dwFlags = TME_LEAVE;
|
||
|
track_mouse_event.hwndTrack = window_handle;
|
||
|
track_mouse_event.dwHoverTime = HOVER_DEFAULT;
|
||
|
}
|
||
|
TrackMouseEvent(&track_mouse_event);
|
||
|
}
|
||
|
}
|
||
|
else if(message == WM_MOUSELEAVE)
|
||
|
{
|
||
|
mouse_hover_active_because_windows_makes_me_cry = 0;
|
||
|
}
|
||
|
else if(message == WM_MOUSEWHEEL)
|
||
|
{
|
||
|
i16 wheel_delta = HIWORD(w_param);
|
||
|
OS_PushEvent(OS_MouseScrollEvent(v2(0, (f32)wheel_delta), modifiers));
|
||
|
}
|
||
|
else if(message == WM_MOUSEHWHEEL)
|
||
|
{
|
||
|
i16 wheel_delta = HIWORD(w_param);
|
||
|
OS_PushEvent(OS_MouseScrollEvent(v2((f32)wheel_delta, 0), modifiers));
|
||
|
}
|
||
|
else if(message == WM_SETCURSOR)
|
||
|
{
|
||
|
|
||
|
if(global_os.mouse_position.x >= 1 && global_os.mouse_position.x <= global_os.window_size.x-1 &&
|
||
|
global_os.mouse_position.y >= 1 && global_os.mouse_position.y <= global_os.window_size.y-1 && mouse_hover_active_because_windows_makes_me_cry)
|
||
|
{
|
||
|
switch(global_cursor_style)
|
||
|
{
|
||
|
case W32_CursorStyle_HorizontalResize:
|
||
|
{
|
||
|
SetCursor(LoadCursorA(0, IDC_SIZEWE));
|
||
|
break;
|
||
|
}
|
||
|
case W32_CursorStyle_VerticalResize:
|
||
|
{
|
||
|
SetCursor(LoadCursorA(0, IDC_SIZENS));
|
||
|
break;
|
||
|
}
|
||
|
case W32_CursorStyle_IBar:
|
||
|
{
|
||
|
SetCursor(LoadCursorA(0, IDC_IBEAM));
|
||
|
break;
|
||
|
}
|
||
|
case W32_CursorStyle_Normal:
|
||
|
{
|
||
|
SetCursor(LoadCursorA(0, IDC_ARROW));
|
||
|
break;
|
||
|
}
|
||
|
default: break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
result = DefWindowProc(window_handle, message, w_param, l_param);
|
||
|
}
|
||
|
}
|
||
|
else if(message == WM_SYSKEYDOWN || message == WM_SYSKEYUP ||
|
||
|
message == WM_KEYDOWN || message == WM_KEYUP)
|
||
|
{
|
||
|
u64 vkey_code = w_param;
|
||
|
i8 was_down = !!(l_param & (1 << 30));
|
||
|
i8 is_down = !(l_param & (1 << 31));
|
||
|
|
||
|
u64 key_input = 0;
|
||
|
|
||
|
if((vkey_code >= 'A' && vkey_code <= 'Z') ||
|
||
|
(vkey_code >= '0' && vkey_code <= '9'))
|
||
|
{
|
||
|
// NOTE(rjf): Letter/number buttons
|
||
|
key_input = (vkey_code >= 'A' && vkey_code <= 'Z') ? Key_A + (vkey_code-'A') : Key_0 + (vkey_code-'0');
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(vkey_code == VK_ESCAPE)
|
||
|
{
|
||
|
key_input = Key_Esc;
|
||
|
}
|
||
|
else if(vkey_code >= VK_F1 && vkey_code <= VK_F12)
|
||
|
{
|
||
|
key_input = Key_F1 + vkey_code - VK_F1;
|
||
|
}
|
||
|
else if(vkey_code == VK_OEM_3)
|
||
|
{
|
||
|
key_input = Key_GraveAccent;
|
||
|
}
|
||
|
else if(vkey_code == VK_OEM_MINUS)
|
||
|
{
|
||
|
key_input = Key_Minus;
|
||
|
}
|
||
|
else if(vkey_code == VK_OEM_PLUS)
|
||
|
{
|
||
|
key_input = Key_Equal;
|
||
|
}
|
||
|
else if(vkey_code == VK_BACK)
|
||
|
{
|
||
|
key_input = Key_Backspace;
|
||
|
}
|
||
|
else if(vkey_code == VK_TAB)
|
||
|
{
|
||
|
key_input = Key_Tab;
|
||
|
}
|
||
|
else if(vkey_code == VK_SPACE)
|
||
|
{
|
||
|
key_input = Key_Space;
|
||
|
}
|
||
|
else if(vkey_code == VK_RETURN)
|
||
|
{
|
||
|
key_input = Key_Enter;
|
||
|
}
|
||
|
else if(vkey_code == VK_CONTROL)
|
||
|
{
|
||
|
key_input = Key_Ctrl;
|
||
|
modifiers &= ~KeyModifier_Ctrl;
|
||
|
}
|
||
|
else if(vkey_code == VK_SHIFT)
|
||
|
{
|
||
|
key_input = Key_Shift;
|
||
|
modifiers &= ~KeyModifier_Shift;
|
||
|
}
|
||
|
else if(vkey_code == VK_MENU)
|
||
|
{
|
||
|
key_input = Key_Alt;
|
||
|
modifiers &= ~KeyModifier_Alt;
|
||
|
}
|
||
|
else if(vkey_code == VK_UP)
|
||
|
{
|
||
|
key_input = Key_Up;
|
||
|
}
|
||
|
else if(vkey_code == VK_LEFT)
|
||
|
{
|
||
|
key_input = Key_Left;
|
||
|
}
|
||
|
else if(vkey_code == VK_DOWN)
|
||
|
{
|
||
|
key_input = Key_Down;
|
||
|
}
|
||
|
else if(vkey_code == VK_RIGHT)
|
||
|
{
|
||
|
key_input = Key_Right;
|
||
|
}
|
||
|
else if(vkey_code == VK_DELETE)
|
||
|
{
|
||
|
key_input = Key_Delete;
|
||
|
}
|
||
|
else if(vkey_code == VK_PRIOR)
|
||
|
{
|
||
|
key_input = Key_PageUp;
|
||
|
}
|
||
|
else if(vkey_code == VK_NEXT)
|
||
|
{
|
||
|
key_input = Key_PageDown;
|
||
|
}
|
||
|
else if(vkey_code == VK_HOME)
|
||
|
{
|
||
|
key_input = Key_Home;
|
||
|
}
|
||
|
else if(vkey_code == VK_END)
|
||
|
{
|
||
|
key_input = Key_End;
|
||
|
}
|
||
|
else if(vkey_code == VK_OEM_2)
|
||
|
{
|
||
|
key_input = Key_ForwardSlash;
|
||
|
}
|
||
|
else if(vkey_code == VK_OEM_PERIOD)
|
||
|
{
|
||
|
key_input = Key_Period;
|
||
|
}
|
||
|
else if(vkey_code == VK_OEM_COMMA)
|
||
|
{
|
||
|
key_input = Key_Comma;
|
||
|
}
|
||
|
else if(vkey_code == VK_OEM_7)
|
||
|
{
|
||
|
key_input = Key_Quote;
|
||
|
}
|
||
|
else if(vkey_code == VK_OEM_4)
|
||
|
{
|
||
|
key_input = Key_LeftBracket;
|
||
|
}
|
||
|
else if(vkey_code == VK_OEM_6)
|
||
|
{
|
||
|
key_input = Key_RightBracket;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(is_down)
|
||
|
{
|
||
|
OS_PushEvent(OS_KeyPressEvent(key_input, modifiers));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
OS_PushEvent(OS_KeyReleaseEvent(key_input, modifiers));
|
||
|
}
|
||
|
|
||
|
DefWindowProc(window_handle, message, w_param, l_param);
|
||
|
}
|
||
|
else if (message == WM_SYSCHAR){
|
||
|
// NOTE(allen): Do nothing - just don't fall through to DefWindowProc which will
|
||
|
// cause bell sounds for alt modified combos.
|
||
|
}
|
||
|
else if(message == WM_CHAR)
|
||
|
{
|
||
|
u64 char_input = w_param;
|
||
|
if(char_input >= 32 && char_input != VK_RETURN && char_input != VK_ESCAPE &&
|
||
|
char_input != 127)
|
||
|
{
|
||
|
OS_PushEvent(OS_CharacterInputEvent(char_input));
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
result = DefWindowProc(window_handle, message, w_param, l_param);
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
internal f32
|
||
|
W32_GetTime(void)
|
||
|
{
|
||
|
W32_Timer *timer = &global_win32_timer;
|
||
|
LARGE_INTEGER current_time;
|
||
|
QueryPerformanceCounter(¤t_time);
|
||
|
return global_os.current_time + (f32)(current_time.QuadPart - timer->begin_frame.QuadPart) / (f32)timer->counts_per_second.QuadPart;
|
||
|
}
|
||
|
|
||
|
internal u64
|
||
|
W32_GetCycles(void)
|
||
|
{
|
||
|
u64 result = __rdtsc();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
internal void
|
||
|
W32_ResetCursor(void)
|
||
|
{
|
||
|
global_cursor_style = W32_CursorStyle_Normal;
|
||
|
}
|
||
|
|
||
|
internal void
|
||
|
W32_SetCursorToHorizontalResize(void)
|
||
|
{
|
||
|
global_cursor_style = W32_CursorStyle_HorizontalResize;
|
||
|
}
|
||
|
|
||
|
internal void
|
||
|
W32_SetCursorToVerticalResize(void)
|
||
|
{
|
||
|
global_cursor_style = W32_CursorStyle_VerticalResize;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
WinMain(HINSTANCE instance, HINSTANCE prev_instance, LPSTR lp_cmd_line, int n_show_cmd)
|
||
|
{
|
||
|
global_instance_handle = instance;
|
||
|
|
||
|
W32_TimerInit(&global_win32_timer);
|
||
|
W32_AppCode win32_game_code = {0};
|
||
|
W32_SoundOutput win32_sound_output = {0};
|
||
|
|
||
|
// NOTE(rjf): Calculate executable name and path to DLL
|
||
|
{
|
||
|
DWORD size_of_executable_path =
|
||
|
GetModuleFileNameA(0, global_executable_path, sizeof(global_executable_path));
|
||
|
|
||
|
// NOTE(rjf): Calculate executable directory
|
||
|
{
|
||
|
MemoryCopy(global_executable_directory, global_executable_path, size_of_executable_path);
|
||
|
char *one_past_last_slash = global_executable_directory;
|
||
|
for(i32 i = 0; global_executable_directory[i]; ++i)
|
||
|
{
|
||
|
if(global_executable_directory[i] == '\\')
|
||
|
{
|
||
|
one_past_last_slash = global_executable_directory + i + 1;
|
||
|
}
|
||
|
}
|
||
|
*one_past_last_slash = 0;
|
||
|
}
|
||
|
|
||
|
// NOTE(rjf): Create DLL filenames
|
||
|
{
|
||
|
wsprintf(global_app_dll_path, "%s%s.dll", global_executable_directory, PROGRAM_FILENAME);
|
||
|
wsprintf(global_temp_app_dll_path, "%stemp_%s.dll", global_executable_directory, PROGRAM_FILENAME);
|
||
|
}
|
||
|
|
||
|
GetCurrentDirectory(sizeof(global_working_directory), global_working_directory);
|
||
|
}
|
||
|
|
||
|
WNDCLASS window_class = {0};
|
||
|
{
|
||
|
window_class.style = CS_HREDRAW | CS_VREDRAW;
|
||
|
window_class.lpfnWndProc = W32_WindowProc;
|
||
|
window_class.hInstance = instance;
|
||
|
window_class.lpszClassName = "ApplicationWindowClass";
|
||
|
window_class.hCursor = LoadCursor(0, IDC_ARROW);
|
||
|
}
|
||
|
|
||
|
if(!RegisterClass(&window_class))
|
||
|
{
|
||
|
// NOTE(rjf): ERROR: Window class registration failure
|
||
|
W32_OutputError("Fatal Error", "Window class registration failure.");
|
||
|
goto quit;
|
||
|
}
|
||
|
|
||
|
HWND window_handle = CreateWindow("ApplicationWindowClass", WINDOW_TITLE,
|
||
|
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
|
||
|
DEFAULT_WINDOW_WIDTH,
|
||
|
DEFAULT_WINDOW_HEIGHT,
|
||
|
0, 0, instance, 0);
|
||
|
|
||
|
if(!window_handle)
|
||
|
{
|
||
|
// NOTE(rjf): ERROR: Window creation failure
|
||
|
W32_OutputError("Fatal Error", "Window creation failure.");
|
||
|
goto quit;
|
||
|
}
|
||
|
|
||
|
// NOTE(rjf): Load application code
|
||
|
W32_AppCode win32_app_code = {0};
|
||
|
{
|
||
|
if(!W32_AppCodeLoad(&win32_app_code))
|
||
|
{
|
||
|
// NOTE(rjf): ERROR: Application code load failure
|
||
|
W32_OutputError("Fatal Error", "Application code load failure.");
|
||
|
goto quit;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// NOTE(rjf): Sound initialization
|
||
|
{
|
||
|
win32_sound_output.channels = 2;
|
||
|
win32_sound_output.samples_per_second = 48000;
|
||
|
win32_sound_output.latency_frame_count = 48000;
|
||
|
W32_LoadWASAPI();
|
||
|
W32_InitWASAPI(&win32_sound_output);
|
||
|
}
|
||
|
|
||
|
// NOTE(rjf): Find refresh rate
|
||
|
f32 refresh_rate = 60.f;
|
||
|
{
|
||
|
DEVMODEA device_mode = {0};
|
||
|
if(EnumDisplaySettingsA(0, ENUM_CURRENT_SETTINGS, &device_mode))
|
||
|
{
|
||
|
refresh_rate = (float)device_mode.dmDisplayFrequency;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// NOTE(rjf): Initialize platform
|
||
|
{
|
||
|
os = &global_os;
|
||
|
|
||
|
global_os.executable_folder_absolute_path = String8FromCString(global_executable_directory);
|
||
|
global_os.executable_absolute_path = String8FromCString(global_executable_path);
|
||
|
global_os.working_directory_path = String8FromCString(global_working_directory);
|
||
|
|
||
|
global_os.quit = 0;
|
||
|
global_os.vsync = 1;
|
||
|
global_os.fullscreen = 0;
|
||
|
global_os.window_size.x = DEFAULT_WINDOW_WIDTH;
|
||
|
global_os.window_size.y = DEFAULT_WINDOW_HEIGHT;
|
||
|
global_os.current_time = 0.f;
|
||
|
global_os.target_frames_per_second = refresh_rate;
|
||
|
|
||
|
global_os.sample_out = W32_HeapAlloc(win32_sound_output.samples_per_second * sizeof(f32) * 2);
|
||
|
global_os.samples_per_second = win32_sound_output.samples_per_second;
|
||
|
|
||
|
global_os.Reserve = W32_Reserve;
|
||
|
global_os.Release = W32_Release;
|
||
|
global_os.Commit = W32_Commit;
|
||
|
global_os.Decommit = W32_Decommit;
|
||
|
global_os.OutputError = W32_OutputError;
|
||
|
global_os.SaveToFile = W32_SaveToFile;
|
||
|
global_os.AppendToFile = W32_AppendToFile;
|
||
|
global_os.LoadEntireFile = W32_LoadEntireFile;
|
||
|
global_os.LoadEntireFileAndNullTerminate = W32_LoadEntireFileAndNullTerminate;
|
||
|
global_os.DeleteFile = W32_DeleteFile;
|
||
|
global_os.MakeDirectory = W32_MakeDirectory;
|
||
|
global_os.DoesFileExist = W32_DoesFileExist;
|
||
|
global_os.DoesDirectoryExist = W32_DoesDirectoryExist;
|
||
|
global_os.CopyFile = W32_CopyFile;
|
||
|
global_os.ListDirectory = W32_DirectoryListLoad;
|
||
|
global_os.GetTime = W32_GetTime;
|
||
|
global_os.GetCycles = W32_GetCycles;
|
||
|
global_os.ResetCursor = W32_ResetCursor;
|
||
|
global_os.SetCursorToHorizontalResize = W32_SetCursorToHorizontalResize;
|
||
|
global_os.SetCursorToVerticalResize = W32_SetCursorToVerticalResize;
|
||
|
global_os.LoadOpenGLProcedure = W32_LoadOpenGLProcedure;
|
||
|
global_os.RefreshScreen = W32_OpenGLRefreshScreen;
|
||
|
global_os.GetThreadContext = W32_GetThreadContext;
|
||
|
|
||
|
global_os.DialogueSavePath = W32_DialogueSavePath;
|
||
|
global_os.DialogueLoadPath = W32_DialogueLoadPath;
|
||
|
|
||
|
global_os.permanent_arena = M_ArenaInitialize();
|
||
|
global_os.frame_arena = M_ArenaInitialize();
|
||
|
}
|
||
|
|
||
|
// NOTE(allen): Thread Context
|
||
|
OS_ThreadContext tctx_;
|
||
|
OS_ArenaNode tctx_scratch_nodes[3];
|
||
|
W32_ThreadInit(&tctx_, tctx_scratch_nodes, 3);
|
||
|
|
||
|
// NOTE(rjf): OpenGL initialization
|
||
|
{
|
||
|
global_device_context = GetDC(window_handle);
|
||
|
if(!W32_InitOpenGL(&global_device_context, global_instance_handle))
|
||
|
{
|
||
|
W32_OutputError("Fatal Error", "OpenGL initialization failure.");
|
||
|
goto quit;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
W32_LoadXInput();
|
||
|
|
||
|
win32_app_code.PermanentLoad(&global_os);
|
||
|
win32_app_code.HotLoad(&global_os);
|
||
|
|
||
|
ShowWindow(window_handle, n_show_cmd);
|
||
|
UpdateWindow(window_handle);
|
||
|
|
||
|
while(!global_os.quit)
|
||
|
{
|
||
|
W32_TimerBeginFrame(&global_win32_timer);
|
||
|
M_ArenaClear(&os->frame_arena);
|
||
|
|
||
|
// NOTE(rjf): Update Windows events
|
||
|
{
|
||
|
os->event_count = 0;
|
||
|
|
||
|
MSG message;
|
||
|
if(global_os.wait_for_events_to_update && !global_os.pump_events)
|
||
|
{
|
||
|
WaitMessage();
|
||
|
}
|
||
|
|
||
|
while(PeekMessage(&message, 0, 0, 0, PM_REMOVE))
|
||
|
{
|
||
|
TranslateMessage(&message);
|
||
|
DispatchMessage(&message);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// NOTE(rjf): Update window size
|
||
|
{
|
||
|
RECT client_rect;
|
||
|
GetClientRect(window_handle, &client_rect);
|
||
|
global_os.window_size.x = client_rect.right - client_rect.left;
|
||
|
global_os.window_size.y = client_rect.bottom - client_rect.top;
|
||
|
}
|
||
|
|
||
|
// NOTE(rjf): Update input data (post-event)
|
||
|
OS_BeginFrame();
|
||
|
{
|
||
|
POINT mouse;
|
||
|
GetCursorPos(&mouse);
|
||
|
ScreenToClient(window_handle, &mouse);
|
||
|
W32_UpdateXInput();
|
||
|
global_os.pump_events = 0;
|
||
|
}
|
||
|
|
||
|
// NOTE(rjf): Find how much sound to write and where
|
||
|
if(win32_sound_output.initialized)
|
||
|
{
|
||
|
global_os.sample_count_to_output = 0;
|
||
|
UINT32 sound_padding_size;
|
||
|
if(SUCCEEDED(win32_sound_output.audio_client->lpVtbl->GetCurrentPadding(win32_sound_output.audio_client, &sound_padding_size)))
|
||
|
{
|
||
|
global_os.samples_per_second = win32_sound_output.samples_per_second;
|
||
|
global_os.sample_count_to_output = (u32)(win32_sound_output.latency_frame_count - sound_padding_size);
|
||
|
if(global_os.sample_count_to_output > win32_sound_output.latency_frame_count)
|
||
|
{
|
||
|
global_os.sample_count_to_output = win32_sound_output.latency_frame_count;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for(u32 i = 0; i < win32_sound_output.buffer_frame_count; ++i)
|
||
|
{
|
||
|
global_os.sample_out[i] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// NOTE(rjf): Call into the app layer to update
|
||
|
{
|
||
|
b32 last_fullscreen = global_os.fullscreen;
|
||
|
|
||
|
win32_app_code.Update();
|
||
|
|
||
|
// NOTE(rjf): Update fullscreen if necessary
|
||
|
if(last_fullscreen != global_os.fullscreen)
|
||
|
{
|
||
|
W32_ToggleFullscreen(window_handle);
|
||
|
}
|
||
|
|
||
|
// NOTE(rjf): Fill sound buffer with game sound
|
||
|
if(win32_sound_output.initialized)
|
||
|
{
|
||
|
W32_FillSoundBuffer(global_os.sample_count_to_output, global_os.sample_out, &win32_sound_output);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// NOTE(rjf): Post-update platform data update
|
||
|
{
|
||
|
OS_EndFrame();
|
||
|
}
|
||
|
|
||
|
W32_AppCodeUpdate(&win32_app_code);
|
||
|
|
||
|
W32_TimerEndFrame(&global_win32_timer, 1000.0 * (1.0 / (f64)global_os.target_frames_per_second));
|
||
|
}
|
||
|
|
||
|
ShowWindow(window_handle, SW_HIDE);
|
||
|
|
||
|
W32_AppCodeUnload(&win32_app_code);
|
||
|
W32_CleanUpOpenGL(&global_device_context);
|
||
|
|
||
|
quit:;
|
||
|
|
||
|
return 0;
|
||
|
}
|