diff options
| author | gingerBill <bill@gingerbill.org> | 2021-08-19 15:09:39 +0100 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2021-08-19 15:09:39 +0100 |
| commit | 9ae4de2ab8de61d130924b6ecf6c079f65f45720 (patch) | |
| tree | 07b49f22b01dcc91e164132a32a1559410519222 /src | |
| parent | 7845769d4b417fdd321740c5404016dbc3119d43 (diff) | |
Remove unused code from gb.h (which means it is heavily modified now)
Diffstat (limited to 'src')
| -rw-r--r-- | src/gb/gb.h | 2271 |
1 files changed, 2 insertions, 2269 deletions
diff --git a/src/gb/gb.h b/src/gb/gb.h index c374da066..a67e0a076 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -4,126 +4,8 @@ This is a single header file with a bunch of useful stuff to replace the C/C++ standard library -=========================================================================== - YOU MUST - - #define GB_IMPLEMENTATION - - in EXACTLY _one_ C or C++ file that includes this header, BEFORE the - include like this: - - #define GB_IMPLEMENTATION - #include "gb.h" - - All other files should just #include "gb.h" without #define - - - If you want the platform layer, YOU MUST - - #define GB_PLATFORM - - BEFORE the include like this: - - #define GB_PLATFORM - #include "gb.h" - -=========================================================================== - -LICENSE - This software is dual-licensed to the public domain and under the following - license: you are granted a perpetual, irrevocable license to copy, modify, - publish, and distribute this file as you see fit. - -WARNING - - This library is _slightly_ experimental and features may not work as expected. - - This also means that many functions are not documented. - -CREDITS - Written by Ginger Bill - -TODOS - - Remove CRT dependency for people who want that - - But do I really? - - Or make it only depend on the really needed stuff? - - Older compiler support? - - How old do you wanna go? - - Only support C90+extension and C99 not pure C89. - - File handling - - All files to be UTF-8 (even on windows) - - Better Virtual Memory handling - - Generic Heap Allocator (tcmalloc/dlmalloc/?) - - Fixed Heap Allocator - - Better UTF support and conversion - - Free List, best fit rather than first fit - - More date & time functions - -VERSION HISTORY - 0.33 - Minor fixes - 0.32 - Minor fixes - 0.31 - Add gb_file_remove - 0.30 - Changes to gbThread (and gbMutex on Windows) - 0.29 - Add extras for gbString - 0.28 - Handle UCS2 correctly in Win32 part - 0.27 - OSX fixes and Linux gbAffinity - 0.26d - Minor changes to how gbFile works - 0.26c - gb_str_to_f* fix - 0.26b - Minor fixes - 0.26a - gbString Fix - 0.26 - Default allocator flags and generic hash table - 0.25a - Fix UTF-8 stuff - 0.25 - OS X gbPlatform Support (missing some things) - 0.24b - Compile on OSX (excluding platform part) - 0.24a - Minor additions - 0.24 - Enum convention change - 0.23 - Optional Windows.h removal (because I'm crazy) - 0.22a - Remove gbVideoMode from gb_platform_init_* - 0.22 - gbAffinity - (Missing Linux version) - 0.21 - Platform Layer Restructuring - 0.20 - Improve file io - 0.19 - Clipboard Text - 0.18a - Controller vibration - 0.18 - Raw keyboard and mouse input for WIN32 - 0.17d - Fixed printf bug for strings - 0.17c - Compile as 32 bit - 0.17b - Change formating style because why not? - 0.17a - Dropped C90 Support (For numerous reasons) - 0.17 - Instantiated Hash Table - 0.16a - Minor code layout changes - 0.16 - New file API and improved platform layer - 0.15d - Linux Experimental Support (DON'T USE IT PLEASE) - 0.15c - Linux Experimental Support (DON'T USE IT) - 0.15b - C90 Support - 0.15a - gb_atomic(32|64)_spin_(lock|unlock) - 0.15 - Recursive "Mutex"; Key States; gbRandom - 0.14 - Better File Handling and better printf (WIN32 Only) - 0.13 - Highly experimental platform layer (WIN32 Only) - 0.12b - Fix minor file bugs - 0.12a - Compile as C++ - 0.12 - New File Handing System! No stdio or stdlib! (WIN32 Only) - 0.11a - Add string precision and width (experimental) - 0.11 - Started making stdio & stdlib optional (Not tested much) - 0.10c - Fix gb_endian_swap32() - 0.10b - Probable timing bug for gb_time_now() - 0.10a - Work on multiple compilers - 0.10 - Scratch Memory Allocator - 0.09a - Faster Mutex and the Free List is slightly improved - 0.09 - Basic Virtual Memory System and Dreadful Free List allocator - 0.08a - Fix *_appendv bug - 0.08 - Huge Overhaul! - 0.07a - Fix alignment in gb_heap_allocator_proc - 0.07 - Hash Table and Hashing Functions - 0.06c - Better Documentation - 0.06b - OS X Support - 0.06a - Linux Support - 0.06 - Windows GCC Support and MSVC x86 Support - 0.05b - Formatting - 0.05a - Minor function name changes - 0.05 - Radix Sort for unsigned integers (TODO: Other primitives) - 0.04 - Better UTF support and search/sort procs - 0.03 - Completely change procedure naming convention - 0.02a - Bug fixes - 0.02 - Change naming convention and gbArray(Type) - 0.01 - Initial Version + IMPORTANT NOTE: THIS IS A HEAVILY MODIFIED VERSION OF THE ORIGINAL + DO NO REPLACE IT WITH THE ORIGINAL */ @@ -2179,374 +2061,6 @@ GB_DEF u64 gb_endian_swap64(u64 i); GB_DEF isize gb_count_set_bits(u64 mask); -//////////////////////////////////////////////////////////////// -// -// Platform Stuff -// -// - -#if defined(GB_PLATFORM) - -// NOTE(bill): -// Coordiate system - +ve x - left to right -// - +ve y - bottom to top -// - Relative to window - -// TODO(bill): Proper documentation for this with code examples - -// Window Support - Complete -// OS X Support - Missing: -// * Sofware framebuffer -// * (show|hide) window -// * show_cursor -// * toggle (fullscreen|borderless) -// * set window position -// * Clipboard -// * GameControllers -// Linux Support - None -// Other OS Support - None - -#ifndef GB_MAX_GAME_CONTROLLER_COUNT -#define GB_MAX_GAME_CONTROLLER_COUNT 4 -#endif - -typedef enum gbKeyType { - gbKey_Unknown = 0, // Unhandled key - - // NOTE(bill): Allow the basic printable keys to be aliased with their chars - gbKey_0 = '0', - gbKey_1, - gbKey_2, - gbKey_3, - gbKey_4, - gbKey_5, - gbKey_6, - gbKey_7, - gbKey_8, - gbKey_9, - - gbKey_A = 'A', - gbKey_B, - gbKey_C, - gbKey_D, - gbKey_E, - gbKey_F, - gbKey_G, - gbKey_H, - gbKey_I, - gbKey_J, - gbKey_K, - gbKey_L, - gbKey_M, - gbKey_N, - gbKey_O, - gbKey_P, - gbKey_Q, - gbKey_R, - gbKey_S, - gbKey_T, - gbKey_U, - gbKey_V, - gbKey_W, - gbKey_X, - gbKey_Y, - gbKey_Z, - - gbKey_Lbracket = '[', - gbKey_Rbracket = ']', - gbKey_Semicolon = ';', - gbKey_Comma = ',', - gbKey_Period = '.', - gbKey_Quote = '\'', - gbKey_Slash = '/', - gbKey_Backslash = '\\', - gbKey_Grave = '`', - gbKey_Equals = '=', - gbKey_Minus = '-', - gbKey_Space = ' ', - - gbKey__Pad = 128, // NOTE(bill): make sure ASCII is reserved - - gbKey_Escape, // Escape - gbKey_Lcontrol, // Left Control - gbKey_Lshift, // Left Shift - gbKey_Lalt, // Left Alt - gbKey_Lsystem, // Left OS specific: window (Windows and Linux), apple/cmd (MacOS X), ... - gbKey_Rcontrol, // Right Control - gbKey_Rshift, // Right Shift - gbKey_Ralt, // Right Alt - gbKey_Rsystem, // Right OS specific: window (Windows and Linux), apple/cmd (MacOS X), ... - gbKey_Menu, // Menu - gbKey_Return, // Return - gbKey_Backspace, // Backspace - gbKey_Tab, // Tabulation - gbKey_Pageup, // Page up - gbKey_Pagedown, // Page down - gbKey_End, // End - gbKey_Home, // Home - gbKey_Insert, // Insert - gbKey_Delete, // Delete - gbKey_Plus, // + - gbKey_Subtract, // - - gbKey_Multiply, // * - gbKey_Divide, // / - gbKey_Left, // Left arrow - gbKey_Right, // Right arrow - gbKey_Up, // Up arrow - gbKey_Down, // Down arrow - gbKey_Numpad0, // Numpad 0 - gbKey_Numpad1, // Numpad 1 - gbKey_Numpad2, // Numpad 2 - gbKey_Numpad3, // Numpad 3 - gbKey_Numpad4, // Numpad 4 - gbKey_Numpad5, // Numpad 5 - gbKey_Numpad6, // Numpad 6 - gbKey_Numpad7, // Numpad 7 - gbKey_Numpad8, // Numpad 8 - gbKey_Numpad9, // Numpad 9 - gbKey_NumpadDot, // Numpad . - gbKey_NumpadEnter, // Numpad Enter - gbKey_F1, // F1 - gbKey_F2, // F2 - gbKey_F3, // F3 - gbKey_F4, // F4 - gbKey_F5, // F5 - gbKey_F6, // F6 - gbKey_F7, // F7 - gbKey_F8, // F8 - gbKey_F9, // F8 - gbKey_F10, // F10 - gbKey_F11, // F11 - gbKey_F12, // F12 - gbKey_F13, // F13 - gbKey_F14, // F14 - gbKey_F15, // F15 - gbKey_Pause, // Pause - - gbKey_Count, -} gbKeyType; - -/* TODO(bill): Change name? */ -typedef u8 gbKeyState; -typedef enum gbKeyStateFlag { - gbKeyState_Down = GB_BIT(0), - gbKeyState_Pressed = GB_BIT(1), - gbKeyState_Released = GB_BIT(2) -} gbKeyStateFlag; - -GB_DEF void gb_key_state_update(gbKeyState *s, b32 is_down); - -typedef enum gbMouseButtonType { - gbMouseButton_Left, - gbMouseButton_Middle, - gbMouseButton_Right, - gbMouseButton_X1, - gbMouseButton_X2, - - gbMouseButton_Count -} gbMouseButtonType; - -typedef enum gbControllerAxisType { - gbControllerAxis_LeftX, - gbControllerAxis_LeftY, - gbControllerAxis_RightX, - gbControllerAxis_RightY, - gbControllerAxis_LeftTrigger, - gbControllerAxis_RightTrigger, - - gbControllerAxis_Count -} gbControllerAxisType; - -typedef enum gbControllerButtonType { - gbControllerButton_Up, - gbControllerButton_Down, - gbControllerButton_Left, - gbControllerButton_Right, - gbControllerButton_A, - gbControllerButton_B, - gbControllerButton_X, - gbControllerButton_Y, - gbControllerButton_LeftShoulder, - gbControllerButton_RightShoulder, - gbControllerButton_Back, - gbControllerButton_Start, - gbControllerButton_LeftThumb, - gbControllerButton_RightThumb, - - gbControllerButton_Count -} gbControllerButtonType; - -typedef struct gbGameController { - b16 is_connected, is_analog; - - f32 axes[gbControllerAxis_Count]; - gbKeyState buttons[gbControllerButton_Count]; -} gbGameController; - -#if defined(GB_SYSTEM_WINDOWS) - typedef struct _XINPUT_GAMEPAD XINPUT_GAMEPAD; - typedef struct _XINPUT_STATE XINPUT_STATE; - typedef struct _XINPUT_VIBRATION XINPUT_VIBRATION; - - #define GB_XINPUT_GET_STATE(name) unsigned long __stdcall name(unsigned long dwUserIndex, XINPUT_STATE *pState) - typedef GB_XINPUT_GET_STATE(gbXInputGetStateProc); - - #define GB_XINPUT_SET_STATE(name) unsigned long __stdcall name(unsigned long dwUserIndex, XINPUT_VIBRATION *pVibration) - typedef GB_XINPUT_SET_STATE(gbXInputSetStateProc); -#endif - - -typedef enum gbWindowFlag { - gbWindow_Fullscreen = GB_BIT(0), - gbWindow_Hidden = GB_BIT(1), - gbWindow_Borderless = GB_BIT(2), - gbWindow_Resizable = GB_BIT(3), - gbWindow_Minimized = GB_BIT(4), - gbWindow_Maximized = GB_BIT(5), - gbWindow_FullscreenDesktop = gbWindow_Fullscreen | gbWindow_Borderless, -} gbWindowFlag; - -typedef enum gbRendererType { - gbRenderer_Opengl, - gbRenderer_Software, - - gbRenderer_Count, -} gbRendererType; - - - -#if defined(GB_SYSTEM_WINDOWS) && !defined(_WINDOWS_) -typedef struct tagBITMAPINFOHEADER { - unsigned long biSize; - long biWidth; - long biHeight; - u16 biPlanes; - u16 biBitCount; - unsigned long biCompression; - unsigned long biSizeImage; - long biXPelsPerMeter; - long biYPelsPerMeter; - unsigned long biClrUsed; - unsigned long biClrImportant; -} BITMAPINFOHEADER, *PBITMAPINFOHEADER; -typedef struct tagRGBQUAD { - u8 rgbBlue; - u8 rgbGreen; - u8 rgbRed; - u8 rgbReserved; -} RGBQUAD; -typedef struct tagBITMAPINFO { - BITMAPINFOHEADER bmiHeader; - RGBQUAD bmiColors[1]; -} BITMAPINFO, *PBITMAPINFO; -#endif - -typedef struct gbPlatform { - b32 is_initialized; - - void *window_handle; - i32 window_x, window_y; - i32 window_width, window_height; - u32 window_flags; - b16 window_is_closed, window_has_focus; - -#if defined(GB_SYSTEM_WINDOWS) - void *win32_dc; -#elif defined(GB_SYSTEM_OSX) - void *osx_autorelease_pool; // TODO(bill): Is this really needed? -#endif - - gbRendererType renderer_type; - union { - struct { - void * context; - i32 major; - i32 minor; - b16 core, compatible; - gbDllHandle dll_handle; - } opengl; - - // NOTE(bill): Software rendering - struct { -#if defined(GB_SYSTEM_WINDOWS) - BITMAPINFO win32_bmi; -#endif - void * memory; - isize memory_size; - i32 pitch; - i32 bits_per_pixel; - } sw_framebuffer; - }; - - gbKeyState keys[gbKey_Count]; - struct { - gbKeyState control; - gbKeyState alt; - gbKeyState shift; - } key_modifiers; - - Rune char_buffer[256]; - isize char_buffer_count; - - b32 mouse_clip; - i32 mouse_x, mouse_y; - i32 mouse_dx, mouse_dy; // NOTE(bill): Not raw mouse movement - i32 mouse_raw_dx, mouse_raw_dy; // NOTE(bill): Raw mouse movement - f32 mouse_wheel_delta; - gbKeyState mouse_buttons[gbMouseButton_Count]; - - gbGameController game_controllers[GB_MAX_GAME_CONTROLLER_COUNT]; - - f64 curr_time; - f64 dt_for_frame; - b32 quit_requested; - -#if defined(GB_SYSTEM_WINDOWS) - struct { - gbXInputGetStateProc *get_state; - gbXInputSetStateProc *set_state; - } xinput; -#endif -} gbPlatform; - - -typedef struct gbVideoMode { - i32 width, height; - i32 bits_per_pixel; -} gbVideoMode; - -GB_DEF gbVideoMode gb_video_mode (i32 width, i32 height, i32 bits_per_pixel); -GB_DEF b32 gb_video_mode_is_valid (gbVideoMode mode); -GB_DEF gbVideoMode gb_video_mode_get_desktop (void); -GB_DEF isize gb_video_mode_get_fullscreen_modes(gbVideoMode *modes, isize max_mode_count); // NOTE(bill): returns mode count -GB_DEF GB_COMPARE_PROC(gb_video_mode_cmp); // NOTE(bill): Sort smallest to largest (Ascending) -GB_DEF GB_COMPARE_PROC(gb_video_mode_dsc_cmp); // NOTE(bill): Sort largest to smallest (Descending) - - -// NOTE(bill): Software rendering -GB_DEF b32 gb_platform_init_with_software (gbPlatform *p, char const *window_title, i32 width, i32 height, u32 window_flags); -// NOTE(bill): OpenGL Rendering -GB_DEF b32 gb_platform_init_with_opengl (gbPlatform *p, char const *window_title, i32 width, i32 height, u32 window_flags, i32 major, i32 minor, b32 core, b32 compatible); -GB_DEF void gb_platform_update (gbPlatform *p); -GB_DEF void gb_platform_display (gbPlatform *p); -GB_DEF void gb_platform_destroy (gbPlatform *p); -GB_DEF void gb_platform_show_cursor (gbPlatform *p, b32 show); -GB_DEF void gb_platform_set_mouse_position (gbPlatform *p, i32 x, i32 y); -GB_DEF void gb_platform_set_controller_vibration (gbPlatform *p, isize index, f32 left_motor, f32 right_motor); -GB_DEF b32 gb_platform_has_clipboard_text (gbPlatform *p); -GB_DEF void gb_platform_set_clipboard_text (gbPlatform *p, char const *str); -GB_DEF char *gb_platform_get_clipboard_text (gbPlatform *p, gbAllocator a); -GB_DEF void gb_platform_set_window_position (gbPlatform *p, i32 x, i32 y); -GB_DEF void gb_platform_set_window_title (gbPlatform *p, char const *title, ...) GB_PRINTF_ARGS(2); -GB_DEF void gb_platform_toggle_fullscreen (gbPlatform *p, b32 fullscreen_desktop); -GB_DEF void gb_platform_toggle_borderless (gbPlatform *p); -GB_DEF void gb_platform_make_opengl_context_current(gbPlatform *p); -GB_DEF void gb_platform_show_window (gbPlatform *p); -GB_DEF void gb_platform_hide_window (gbPlatform *p); - - -#endif // GB_PLATFORM - #if defined(__cplusplus) } #endif @@ -9311,1787 +8825,6 @@ gb_inline isize gb_count_set_bits(u64 mask) { } - - - - -//////////////////////////////////////////////////////////////// -// -// Platform -// -// - -#if defined(GB_PLATFORM) - -gb_inline void gb_key_state_update(gbKeyState *s, b32 is_down) { - b32 was_down = (*s & gbKeyState_Down) != 0; - is_down = is_down != 0; // NOTE(bill): Make sure it's a boolean - GB_MASK_SET(*s, is_down, gbKeyState_Down); - GB_MASK_SET(*s, !was_down && is_down, gbKeyState_Pressed); - GB_MASK_SET(*s, was_down && !is_down, gbKeyState_Released); -} - -#if defined(GB_SYSTEM_WINDOWS) - -#ifndef ERROR_DEVICE_NOT_CONNECTED -#define ERROR_DEVICE_NOT_CONNECTED 1167 -#endif - -GB_XINPUT_GET_STATE(gbXInputGetState_Stub) { - gb_unused(dwUserIndex); gb_unused(pState); - return ERROR_DEVICE_NOT_CONNECTED; -} -GB_XINPUT_SET_STATE(gbXInputSetState_Stub) { - gb_unused(dwUserIndex); gb_unused(pVibration); - return ERROR_DEVICE_NOT_CONNECTED; -} - - -gb_internal gb_inline f32 gb__process_xinput_stick_value(i16 value, i16 dead_zone_threshold) { - f32 result = 0; - - if (value < -dead_zone_threshold) { - result = cast(f32) (value + dead_zone_threshold) / (32768.0f - dead_zone_threshold); - } else if (value > dead_zone_threshold) { - result = cast(f32) (value - dead_zone_threshold) / (32767.0f - dead_zone_threshold); - } - - return result; -} - -gb_internal void gb__platform_resize_dib_section(gbPlatform *p, i32 width, i32 height) { - if ((p->renderer_type == gbRenderer_Software) && - !(p->window_width == width && p->window_height == height)) { - BITMAPINFO bmi = {0}; - - if (width == 0 || height == 0) { - return; - } - - p->window_width = width; - p->window_height = height; - - // TODO(bill): Is this slow to get the desktop mode everytime? - p->sw_framebuffer.bits_per_pixel = gb_video_mode_get_desktop().bits_per_pixel; - p->sw_framebuffer.pitch = (p->sw_framebuffer.bits_per_pixel * width / 8); - - bmi.bmiHeader.biSize = gb_size_of(bmi.bmiHeader); - bmi.bmiHeader.biWidth = width; - bmi.bmiHeader.biHeight = height; // NOTE(bill): -ve is top-down, +ve is bottom-up - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = cast(u16)p->sw_framebuffer.bits_per_pixel; - bmi.bmiHeader.biCompression = 0 /*BI_RGB*/; - - p->sw_framebuffer.win32_bmi = bmi; - - - if (p->sw_framebuffer.memory) { - gb_vm_free(gb_virtual_memory(p->sw_framebuffer.memory, p->sw_framebuffer.memory_size)); - } - - { - isize memory_size = p->sw_framebuffer.pitch * height; - gbVirtualMemory vm = gb_vm_alloc(0, memory_size); - p->sw_framebuffer.memory = vm.data; - p->sw_framebuffer.memory_size = vm.size; - } - } -} - - -gb_internal gbKeyType gb__win32_from_vk(unsigned int key) { - // NOTE(bill): Letters and numbers are defined the same for VK_* and GB_* - if (key >= 'A' && key < 'Z') return cast(gbKeyType)key; - if (key >= '0' && key < '9') return cast(gbKeyType)key; - switch (key) { - case VK_ESCAPE: return gbKey_Escape; - - case VK_LCONTROL: return gbKey_Lcontrol; - case VK_LSHIFT: return gbKey_Lshift; - case VK_LMENU: return gbKey_Lalt; - case VK_LWIN: return gbKey_Lsystem; - case VK_RCONTROL: return gbKey_Rcontrol; - case VK_RSHIFT: return gbKey_Rshift; - case VK_RMENU: return gbKey_Ralt; - case VK_RWIN: return gbKey_Rsystem; - case VK_MENU: return gbKey_Menu; - - case VK_OEM_4: return gbKey_Lbracket; - case VK_OEM_6: return gbKey_Rbracket; - case VK_OEM_1: return gbKey_Semicolon; - case VK_OEM_COMMA: return gbKey_Comma; - case VK_OEM_PERIOD: return gbKey_Period; - case VK_OEM_7: return gbKey_Quote; - case VK_OEM_2: return gbKey_Slash; - case VK_OEM_5: return gbKey_Backslash; - case VK_OEM_3: return gbKey_Grave; - case VK_OEM_PLUS: return gbKey_Equals; - case VK_OEM_MINUS: return gbKey_Minus; - - case VK_SPACE: return gbKey_Space; - case VK_RETURN: return gbKey_Return; - case VK_BACK: return gbKey_Backspace; - case VK_TAB: return gbKey_Tab; - - case VK_PRIOR: return gbKey_Pageup; - case VK_NEXT: return gbKey_Pagedown; - case VK_END: return gbKey_End; - case VK_HOME: return gbKey_Home; - case VK_INSERT: return gbKey_Insert; - case VK_DELETE: return gbKey_Delete; - - case VK_ADD: return gbKey_Plus; - case VK_SUBTRACT: return gbKey_Subtract; - case VK_MULTIPLY: return gbKey_Multiply; - case VK_DIVIDE: return gbKey_Divide; - - case VK_LEFT: return gbKey_Left; - case VK_RIGHT: return gbKey_Right; - case VK_UP: return gbKey_Up; - case VK_DOWN: return gbKey_Down; - - case VK_NUMPAD0: return gbKey_Numpad0; - case VK_NUMPAD1: return gbKey_Numpad1; - case VK_NUMPAD2: return gbKey_Numpad2; - case VK_NUMPAD3: return gbKey_Numpad3; - case VK_NUMPAD4: return gbKey_Numpad4; - case VK_NUMPAD5: return gbKey_Numpad5; - case VK_NUMPAD6: return gbKey_Numpad6; - case VK_NUMPAD7: return gbKey_Numpad7; - case VK_NUMPAD8: return gbKey_Numpad8; - case VK_NUMPAD9: return gbKey_Numpad9; - case VK_SEPARATOR: return gbKey_NumpadEnter; - case VK_DECIMAL: return gbKey_NumpadDot; - - case VK_F1: return gbKey_F1; - case VK_F2: return gbKey_F2; - case VK_F3: return gbKey_F3; - case VK_F4: return gbKey_F4; - case VK_F5: return gbKey_F5; - case VK_F6: return gbKey_F6; - case VK_F7: return gbKey_F7; - case VK_F8: return gbKey_F8; - case VK_F9: return gbKey_F9; - case VK_F10: return gbKey_F10; - case VK_F11: return gbKey_F11; - case VK_F12: return gbKey_F12; - case VK_F13: return gbKey_F13; - case VK_F14: return gbKey_F14; - case VK_F15: return gbKey_F15; - - case VK_PAUSE: return gbKey_Pause; - } - return gbKey_Unknown; -} -LRESULT CALLBACK gb__win32_window_callback(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { - // NOTE(bill): Silly callbacks - gbPlatform *platform = cast(gbPlatform *)GetWindowLongPtrW(hWnd, GWLP_USERDATA); - b32 window_has_focus = (platform != NULL) && platform->window_has_focus; - - if (msg == WM_CREATE) { // NOTE(bill): Doesn't need the platform - // NOTE(bill): https://msdn.microsoft.com/en-us/library/windows/desktop/ms645536(v=vs.85).aspx - RAWINPUTDEVICE rid[2] = {0}; - - // NOTE(bill): Keyboard - rid[0].usUsagePage = 0x01; - rid[0].usUsage = 0x06; - rid[0].dwFlags = 0x00000030/*RIDEV_NOLEGACY*/; // NOTE(bill): Do not generate legacy messages such as WM_KEYDOWN - rid[0].hwndTarget = hWnd; - - // NOTE(bill): Mouse - rid[1].usUsagePage = 0x01; - rid[1].usUsage = 0x02; - rid[1].dwFlags = 0; // NOTE(bill): adds HID mouse and also allows legacy mouse messages to allow for window movement etc. - rid[1].hwndTarget = hWnd; - - if (RegisterRawInputDevices(rid, gb_count_of(rid), gb_size_of(rid[0])) == false) { - DWORD err = GetLastError(); - GB_PANIC("Failed to initialize raw input device for win32." - "Err: %u", err); - } - } - - if (!platform) { - return DefWindowProcW(hWnd, msg, wParam, lParam); - } - - switch (msg) { - case WM_CLOSE: - case WM_DESTROY: - platform->window_is_closed = true; - return 0; - - case WM_QUIT: { - platform->quit_requested = true; - } break; - - case WM_UNICHAR: { - if (window_has_focus) { - if (wParam == '\r') { - wParam = '\n'; - } - // TODO(bill): Does this need to be thread-safe? - platform->char_buffer[platform->char_buffer_count++] = cast(Rune)wParam; - } - } break; - - - case WM_INPUT: { - RAWINPUT raw = {0}; - unsigned int size = gb_size_of(RAWINPUT); - - if (!GetRawInputData(cast(HRAWINPUT)lParam, RID_INPUT, &raw, &size, gb_size_of(RAWINPUTHEADER))) { - return 0; - } - switch (raw.header.dwType) { - case RIM_TYPEKEYBOARD: { - // NOTE(bill): Many thanks to https://blog.molecular-matters.com/2011/09/05/properly-handling-keyboard-input/ - // for the - RAWKEYBOARD *raw_kb = &raw.data.keyboard; - unsigned int vk = raw_kb->VKey; - unsigned int scan_code = raw_kb->MakeCode; - unsigned int flags = raw_kb->Flags; - // NOTE(bill): e0 and e1 are escape sequences used for certain special keys, such as PRINT and PAUSE/BREAK. - // NOTE(bill): http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html - b32 is_e0 = (flags & RI_KEY_E0) != 0; - b32 is_e1 = (flags & RI_KEY_E1) != 0; - b32 is_up = (flags & RI_KEY_BREAK) != 0; - b32 is_down = !is_up; - - // TODO(bill): Should I handle scan codes? - - if (vk == 255) { - // NOTE(bill): Discard "fake keys" - return 0; - } else if (vk == VK_SHIFT) { - // NOTE(bill): Correct left/right shift - vk = MapVirtualKeyW(scan_code, MAPVK_VSC_TO_VK_EX); - } else if (vk == VK_NUMLOCK) { - // NOTE(bill): Correct PAUSE/BREAK and NUM LOCK and set the extended bit - scan_code = MapVirtualKeyW(vk, MAPVK_VK_TO_VSC) | 0x100; - } - - if (is_e1) { - // NOTE(bill): Escaped sequences, turn vk into the correct scan code - // except for VK_PAUSE (it's a bug) - if (vk == VK_PAUSE) { - scan_code = 0x45; - } else { - scan_code = MapVirtualKeyW(vk, MAPVK_VK_TO_VSC); - } - } - - switch (vk) { - case VK_CONTROL: vk = (is_e0) ? VK_RCONTROL : VK_LCONTROL; break; - case VK_MENU: vk = (is_e0) ? VK_RMENU : VK_LMENU; break; - - case VK_RETURN: if (is_e0) vk = VK_SEPARATOR; break; // NOTE(bill): Numpad return - case VK_DELETE: if (!is_e0) vk = VK_DECIMAL; break; // NOTE(bill): Numpad dot - case VK_INSERT: if (!is_e0) vk = VK_NUMPAD0; break; - case VK_HOME: if (!is_e0) vk = VK_NUMPAD7; break; - case VK_END: if (!is_e0) vk = VK_NUMPAD1; break; - case VK_PRIOR: if (!is_e0) vk = VK_NUMPAD9; break; - case VK_NEXT: if (!is_e0) vk = VK_NUMPAD3; break; - - // NOTE(bill): The standard arrow keys will always have their e0 bit set, but the - // corresponding keys on the NUMPAD will not. - case VK_LEFT: if (!is_e0) vk = VK_NUMPAD4; break; - case VK_RIGHT: if (!is_e0) vk = VK_NUMPAD6; break; - case VK_UP: if (!is_e0) vk = VK_NUMPAD8; break; - case VK_DOWN: if (!is_e0) vk = VK_NUMPAD2; break; - - // NUMPAD 5 doesn't have its e0 bit set - case VK_CLEAR: if (!is_e0) vk = VK_NUMPAD5; break; - } - - // NOTE(bill): Set appropriate key state flags - gb_key_state_update(&platform->keys[gb__win32_from_vk(vk)], is_down); - - } break; - case RIM_TYPEMOUSE: { - RAWMOUSE *raw_mouse = &raw.data.mouse; - u16 flags = raw_mouse->usButtonFlags; - long dx = +raw_mouse->lLastX; - long dy = -raw_mouse->lLastY; - - if (flags & RI_MOUSE_WHEEL) { - platform->mouse_wheel_delta = cast(i16)raw_mouse->usButtonData; - } - - platform->mouse_raw_dx = dx; - platform->mouse_raw_dy = dy; - } break; - } - } break; - - default: break; - } - - return DefWindowProcW(hWnd, msg, wParam, lParam); -} - - -typedef void *wglCreateContextAttribsARB_Proc(void *hDC, void *hshareContext, int const *attribList); - - -b32 gb__platform_init(gbPlatform *p, char const *window_title, gbVideoMode mode, gbRendererType type, u32 window_flags) { - WNDCLASSEXW wc = {gb_size_of(WNDCLASSEXW)}; - DWORD ex_style = 0, style = 0; - RECT wr; - u16 title_buffer[256] = {0}; // TODO(bill): gb_local_persist this? - - wc.style = CS_HREDRAW | CS_VREDRAW; // | CS_OWNDC - wc.lpfnWndProc = gb__win32_window_callback; - wc.hbrBackground = cast(HBRUSH)GetStockObject(0/*WHITE_BRUSH*/); - wc.lpszMenuName = NULL; - wc.lpszClassName = L"gb-win32-wndclass"; // TODO(bill): Is this enough? - wc.hInstance = GetModuleHandleW(NULL); - - if (RegisterClassExW(&wc) == 0) { - MessageBoxW(NULL, L"Failed to register the window class", L"ERROR", MB_OK | MB_ICONEXCLAMATION); - return false; - } - - if ((window_flags & gbWindow_Fullscreen) && !(window_flags & gbWindow_Borderless)) { - DEVMODEW screen_settings = {gb_size_of(DEVMODEW)}; - screen_settings.dmPelsWidth = mode.width; - screen_settings.dmPelsHeight = mode.height; - screen_settings.dmBitsPerPel = mode.bits_per_pixel; - screen_settings.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT; - - if (ChangeDisplaySettingsW(&screen_settings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) { - if (MessageBoxW(NULL, L"The requested fullscreen mode is not supported by\n" - L"your video card. Use windowed mode instead?", - L"", - MB_YESNO|MB_ICONEXCLAMATION) == IDYES) { - window_flags &= ~gbWindow_Fullscreen; - } else { - mode = gb_video_mode_get_desktop(); - screen_settings.dmPelsWidth = mode.width; - screen_settings.dmPelsHeight = mode.height; - screen_settings.dmBitsPerPel = mode.bits_per_pixel; - ChangeDisplaySettingsW(&screen_settings, CDS_FULLSCREEN); - } - } - } - - - // ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; - // style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE | WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX; - - style |= WS_VISIBLE; - - if (window_flags & gbWindow_Hidden) style &= ~WS_VISIBLE; - if (window_flags & gbWindow_Resizable) style |= WS_THICKFRAME | WS_MAXIMIZEBOX; - if (window_flags & gbWindow_Maximized) style |= WS_MAXIMIZE; - if (window_flags & gbWindow_Minimized) style |= WS_MINIMIZE; - - // NOTE(bill): Completely ignore the given mode and just change it - if (window_flags & gbWindow_FullscreenDesktop) { - mode = gb_video_mode_get_desktop(); - } - - if ((window_flags & gbWindow_Fullscreen) || (window_flags & gbWindow_Borderless)) { - style |= WS_POPUP; - } else { - style |= WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; - } - - - wr.left = 0; - wr.top = 0; - wr.right = mode.width; - wr.bottom = mode.height; - AdjustWindowRect(&wr, style, false); - - p->window_flags = window_flags; - p->window_handle = CreateWindowExW(ex_style, - wc.lpszClassName, - cast(wchar_t const *)gb_utf8_to_ucs2(title_buffer, gb_size_of(title_buffer), window_title), - style, - CW_USEDEFAULT, CW_USEDEFAULT, - wr.right - wr.left, wr.bottom - wr.top, - 0, 0, - GetModuleHandleW(NULL), - NULL); - - if (!p->window_handle) { - MessageBoxW(NULL, L"Window creation failed", L"Error", MB_OK|MB_ICONEXCLAMATION); - return false; - } - - p->win32_dc = GetDC(cast(HWND)p->window_handle); - - p->renderer_type = type; - switch (p->renderer_type) { - case gbRenderer_Opengl: { - wglCreateContextAttribsARB_Proc *wglCreateContextAttribsARB; - i32 attribs[8] = {0}; - isize c = 0; - - PIXELFORMATDESCRIPTOR pfd = {gb_size_of(PIXELFORMATDESCRIPTOR)}; - pfd.nVersion = 1; - pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; - pfd.iPixelType = PFD_TYPE_RGBA; - pfd.cColorBits = 32; - pfd.cAlphaBits = 8; - pfd.cDepthBits = 24; - pfd.cStencilBits = 8; - pfd.iLayerType = PFD_MAIN_PLANE; - - SetPixelFormat(cast(HDC)p->win32_dc, ChoosePixelFormat(cast(HDC)p->win32_dc, &pfd), NULL); - p->opengl.context = cast(void *)wglCreateContext(cast(HDC)p->win32_dc); - wglMakeCurrent(cast(HDC)p->win32_dc, cast(HGLRC)p->opengl.context); - - if (p->opengl.major > 0) { - attribs[c++] = 0x2091; // WGL_CONTEXT_MAJOR_VERSION_ARB - attribs[c++] = gb_max(p->opengl.major, 1); - } - if (p->opengl.major > 0 && p->opengl.minor >= 0) { - attribs[c++] = 0x2092; // WGL_CONTEXT_MINOR_VERSION_ARB - attribs[c++] = gb_max(p->opengl.minor, 0); - } - - if (p->opengl.core) { - attribs[c++] = 0x9126; // WGL_CONTEXT_PROFILE_MASK_ARB - attribs[c++] = 0x0001; // WGL_CONTEXT_CORE_PROFILE_BIT_ARB - } else if (p->opengl.compatible) { - attribs[c++] = 0x9126; // WGL_CONTEXT_PROFILE_MASK_ARB - attribs[c++] = 0x0002; // WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB - } - attribs[c++] = 0; // NOTE(bill): tells the proc that this is the end of attribs - - wglCreateContextAttribsARB = cast(wglCreateContextAttribsARB_Proc *)wglGetProcAddress("wglCreateContextAttribsARB"); - if (wglCreateContextAttribsARB) { - HGLRC rc = cast(HGLRC)wglCreateContextAttribsARB(p->win32_dc, 0, attribs); - if (rc && wglMakeCurrent(cast(HDC)p->win32_dc, rc)) { - p->opengl.context = rc; - } else { - // TODO(bill): Handle errors from GetLastError - // ERROR_INVALID_VERSION_ARB 0x2095 - // ERROR_INVALID_PROFILE_ARB 0x2096 - } - } - - } break; - - case gbRenderer_Software: - gb__platform_resize_dib_section(p, mode.width, mode.height); - break; - - default: - GB_PANIC("Unknown window type"); - break; - } - - SetForegroundWindow(cast(HWND)p->window_handle); - SetFocus(cast(HWND)p->window_handle); - SetWindowLongPtrW(cast(HWND)p->window_handle, GWLP_USERDATA, cast(LONG_PTR)p); - - p->window_width = mode.width; - p->window_height = mode.height; - - if (p->renderer_type == gbRenderer_Opengl) { - p->opengl.dll_handle = gb_dll_load("opengl32.dll"); - } - - { // Load XInput - // TODO(bill): What other dlls should I look for? - gbDllHandle xinput_library = gb_dll_load("xinput1_4.dll"); - p->xinput.get_state = gbXInputGetState_Stub; - p->xinput.set_state = gbXInputSetState_Stub; - - if (!xinput_library) xinput_library = gb_dll_load("xinput9_1_0.dll"); - if (!xinput_library) xinput_library = gb_dll_load("xinput1_3.dll"); - if (!xinput_library) { - // TODO(bill): Proper Diagnostic - gb_printf_err("XInput could not be loaded. Controllers will not work!\n"); - } else { - p->xinput.get_state = cast(gbXInputGetStateProc *)gb_dll_proc_address(xinput_library, "XInputGetState"); - p->xinput.set_state = cast(gbXInputSetStateProc *)gb_dll_proc_address(xinput_library, "XInputSetState"); - } - } - - // Init keys - gb_zero_array(p->keys, gb_count_of(p->keys)); - - p->is_initialized = true; - return true; -} - -gb_inline b32 gb_platform_init_with_software(gbPlatform *p, char const *window_title, - i32 width, i32 height, u32 window_flags) { - gbVideoMode mode; - mode.width = width; - mode.height = height; - mode.bits_per_pixel = 32; - return gb__platform_init(p, window_title, mode, gbRenderer_Software, window_flags); -} - -gb_inline b32 gb_platform_init_with_opengl(gbPlatform *p, char const *window_title, - i32 width, i32 height, u32 window_flags, i32 major, i32 minor, b32 core, b32 compatible) { - gbVideoMode mode; - mode.width = width; - mode.height = height; - mode.bits_per_pixel = 32; - p->opengl.major = major; - p->opengl.minor = minor; - p->opengl.core = cast(b16)core; - p->opengl.compatible = cast(b16)compatible; - return gb__platform_init(p, window_title, mode, gbRenderer_Opengl, window_flags); -} - -#ifndef _XINPUT_H_ -typedef struct _XINPUT_GAMEPAD { - u16 wButtons; - u8 bLeftTrigger; - u8 bRightTrigger; - u16 sThumbLX; - u16 sThumbLY; - u16 sThumbRX; - u16 sThumbRY; -} XINPUT_GAMEPAD; - -typedef struct _XINPUT_STATE { - DWORD dwPacketNumber; - XINPUT_GAMEPAD Gamepad; -} XINPUT_STATE; - -typedef struct _XINPUT_VIBRATION { - u16 wLeftMotorSpeed; - u16 wRightMotorSpeed; -} XINPUT_VIBRATION; - -#define XINPUT_GAMEPAD_DPAD_UP 0x00000001 -#define XINPUT_GAMEPAD_DPAD_DOWN 0x00000002 -#define XINPUT_GAMEPAD_DPAD_LEFT 0x00000004 -#define XINPUT_GAMEPAD_DPAD_RIGHT 0x00000008 -#define XINPUT_GAMEPAD_START 0x00000010 -#define XINPUT_GAMEPAD_BACK 0x00000020 -#define XINPUT_GAMEPAD_LEFT_THUMB 0x00000040 -#define XINPUT_GAMEPAD_RIGHT_THUMB 0x00000080 -#define XINPUT_GAMEPAD_LEFT_SHOULDER 0x0100 -#define XINPUT_GAMEPAD_RIGHT_SHOULDER 0x0200 -#define XINPUT_GAMEPAD_A 0x1000 -#define XINPUT_GAMEPAD_B 0x2000 -#define XINPUT_GAMEPAD_X 0x4000 -#define XINPUT_GAMEPAD_Y 0x8000 -#define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE 7849 -#define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689 -#define XINPUT_GAMEPAD_TRIGGER_THRESHOLD 30 -#endif - -#ifndef XUSER_MAX_COUNT -#define XUSER_MAX_COUNT 4 -#endif - -void gb_platform_update(gbPlatform *p) { - isize i; - - { // NOTE(bill): Set window state - // TODO(bill): Should this be moved to gb__win32_window_callback ? - RECT window_rect; - i32 x, y, w, h; - - GetClientRect(cast(HWND)p->window_handle, &window_rect); - x = window_rect.left; - y = window_rect.top; - w = window_rect.right - window_rect.left; - h = window_rect.bottom - window_rect.top; - - if ((p->window_width != w) || (p->window_height != h)) { - if (p->renderer_type == gbRenderer_Software) { - gb__platform_resize_dib_section(p, w, h); - } - } - - - p->window_x = x; - p->window_y = y; - p->window_width = w; - p->window_height = h; - GB_MASK_SET(p->window_flags, IsIconic(cast(HWND)p->window_handle) != 0, gbWindow_Minimized); - - p->window_has_focus = GetFocus() == cast(HWND)p->window_handle; - } - - { // NOTE(bill): Set mouse position - POINT mouse_pos; - DWORD win_button_id[gbMouseButton_Count] = { - VK_LBUTTON, - VK_MBUTTON, - VK_RBUTTON, - VK_XBUTTON1, - VK_XBUTTON2, - }; - - // NOTE(bill): This needs to be GetAsyncKeyState as RAWMOUSE doesn't aways work for some odd reason - // TODO(bill): Try and get RAWMOUSE to work for key presses - for (i = 0; i < gbMouseButton_Count; i++) { - gb_key_state_update(p->mouse_buttons+i, GetAsyncKeyState(win_button_id[i]) < 0); - } - - GetCursorPos(&mouse_pos); - ScreenToClient(cast(HWND)p->window_handle, &mouse_pos); - { - i32 x = mouse_pos.x; - i32 y = p->window_height-1 - mouse_pos.y; - p->mouse_dx = x - p->mouse_x; - p->mouse_dy = y - p->mouse_y; - p->mouse_x = x; - p->mouse_y = y; - } - - if (p->mouse_clip) { - b32 update = false; - i32 x = p->mouse_x; - i32 y = p->mouse_y; - if (p->mouse_x < 0) { - x = 0; - update = true; - } else if (p->mouse_y > p->window_height-1) { - y = p->window_height-1; - update = true; - } - - if (p->mouse_y < 0) { - y = 0; - update = true; - } else if (p->mouse_x > p->window_width-1) { - x = p->window_width-1; - update = true; - } - - if (update) { - gb_platform_set_mouse_position(p, x, y); - } - } - - - } - - - // NOTE(bill): Set Key/Button states - if (p->window_has_focus) { - p->char_buffer_count = 0; // TODO(bill): Reset buffer count here or else where? - - // NOTE(bill): Need to update as the keys only get updates on events - for (i = 0; i < gbKey_Count; i++) { - b32 is_down = (p->keys[i] & gbKeyState_Down) != 0; - gb_key_state_update(&p->keys[i], is_down); - } - - p->key_modifiers.control = p->keys[gbKey_Lcontrol] | p->keys[gbKey_Rcontrol]; - p->key_modifiers.alt = p->keys[gbKey_Lalt] | p->keys[gbKey_Ralt]; - p->key_modifiers.shift = p->keys[gbKey_Lshift] | p->keys[gbKey_Rshift]; - - } - - { // NOTE(bill): Set Controller states - isize max_controller_count = XUSER_MAX_COUNT; - if (max_controller_count > gb_count_of(p->game_controllers)) { - max_controller_count = gb_count_of(p->game_controllers); - } - - for (i = 0; i < max_controller_count; i++) { - gbGameController *controller = &p->game_controllers[i]; - XINPUT_STATE controller_state = {0}; - if (p->xinput.get_state(cast(DWORD)i, &controller_state) != 0) { - // NOTE(bill): The controller is not available - controller->is_connected = false; - } else { - // NOTE(bill): This controller is plugged in - // TODO(bill): See if ControllerState.dwPacketNumber increments too rapidly - XINPUT_GAMEPAD *pad = &controller_state.Gamepad; - - controller->is_connected = true; - - // TODO(bill): This is a square deadzone, check XInput to verify that the deadzone is "round" and do round deadzone processing. - controller->axes[gbControllerAxis_LeftX] = gb__process_xinput_stick_value(pad->sThumbLX, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); - controller->axes[gbControllerAxis_LeftY] = gb__process_xinput_stick_value(pad->sThumbLY, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); - controller->axes[gbControllerAxis_RightX] = gb__process_xinput_stick_value(pad->sThumbRX, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE); - controller->axes[gbControllerAxis_RightY] = gb__process_xinput_stick_value(pad->sThumbRY, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE); - - controller->axes[gbControllerAxis_LeftTrigger] = cast(f32)pad->bLeftTrigger / 255.0f; - controller->axes[gbControllerAxis_RightTrigger] = cast(f32)pad->bRightTrigger / 255.0f; - - - if ((controller->axes[gbControllerAxis_LeftX] != 0.0f) || - (controller->axes[gbControllerAxis_LeftY] != 0.0f)) { - controller->is_analog = true; - } - - #define GB__PROCESS_DIGITAL_BUTTON(button_type, xinput_button) \ - gb_key_state_update(&controller->buttons[button_type], (pad->wButtons & xinput_button) == xinput_button) - - GB__PROCESS_DIGITAL_BUTTON(gbControllerButton_A, XINPUT_GAMEPAD_A); - GB__PROCESS_DIGITAL_BUTTON(gbControllerButton_B, XINPUT_GAMEPAD_B); - GB__PROCESS_DIGITAL_BUTTON(gbControllerButton_X, XINPUT_GAMEPAD_X); - GB__PROCESS_DIGITAL_BUTTON(gbControllerButton_Y, XINPUT_GAMEPAD_Y); - GB__PROCESS_DIGITAL_BUTTON(gbControllerButton_LeftShoulder, XINPUT_GAMEPAD_LEFT_SHOULDER); - GB__PROCESS_DIGITAL_BUTTON(gbControllerButton_RightShoulder, XINPUT_GAMEPAD_RIGHT_SHOULDER); - GB__PROCESS_DIGITAL_BUTTON(gbControllerButton_Start, XINPUT_GAMEPAD_START); - GB__PROCESS_DIGITAL_BUTTON(gbControllerButton_Back, XINPUT_GAMEPAD_BACK); - GB__PROCESS_DIGITAL_BUTTON(gbControllerButton_Left, XINPUT_GAMEPAD_DPAD_LEFT); - GB__PROCESS_DIGITAL_BUTTON(gbControllerButton_Right, XINPUT_GAMEPAD_DPAD_RIGHT); - GB__PROCESS_DIGITAL_BUTTON(gbControllerButton_Down, XINPUT_GAMEPAD_DPAD_DOWN); - GB__PROCESS_DIGITAL_BUTTON(gbControllerButton_Up, XINPUT_GAMEPAD_DPAD_UP); - GB__PROCESS_DIGITAL_BUTTON(gbControllerButton_LeftThumb, XINPUT_GAMEPAD_LEFT_THUMB); - GB__PROCESS_DIGITAL_BUTTON(gbControllerButton_RightThumb, XINPUT_GAMEPAD_RIGHT_THUMB); - #undef GB__PROCESS_DIGITAL_BUTTON - } - } - } - - { // NOTE(bill): Process pending messages - MSG message; - for (;;) { - BOOL is_okay = PeekMessageW(&message, 0, 0, 0, PM_REMOVE); - if (!is_okay) break; - - switch (message.message) { - case WM_QUIT: - p->quit_requested = true; - break; - - default: - TranslateMessage(&message); - DispatchMessageW(&message); - break; - } - } - } -} - -void gb_platform_display(gbPlatform *p) { - if (p->renderer_type == gbRenderer_Opengl) { - SwapBuffers(cast(HDC)p->win32_dc); - } else if (p->renderer_type == gbRenderer_Software) { - StretchDIBits(cast(HDC)p->win32_dc, - 0, 0, p->window_width, p->window_height, - 0, 0, p->window_width, p->window_height, - p->sw_framebuffer.memory, - &p->sw_framebuffer.win32_bmi, - DIB_RGB_COLORS, SRCCOPY); - } else { - GB_PANIC("Invalid window rendering type"); - } - - { - f64 prev_time = p->curr_time; - f64 curr_time = gb_time_now(); - p->dt_for_frame = curr_time - prev_time; - p->curr_time = curr_time; - } -} - - -void gb_platform_destroy(gbPlatform *p) { - if (p->renderer_type == gbRenderer_Opengl) { - wglDeleteContext(cast(HGLRC)p->opengl.context); - } else if (p->renderer_type == gbRenderer_Software) { - gb_vm_free(gb_virtual_memory(p->sw_framebuffer.memory, p->sw_framebuffer.memory_size)); - } - - DestroyWindow(cast(HWND)p->window_handle); -} - -void gb_platform_show_cursor(gbPlatform *p, b32 show) { - gb_unused(p); - ShowCursor(show); -} - -void gb_platform_set_mouse_position(gbPlatform *p, i32 x, i32 y) { - POINT point; - point.x = cast(LONG)x; - point.y = cast(LONG)(p->window_height-1 - y); - ClientToScreen(cast(HWND)p->window_handle, &point); - SetCursorPos(point.x, point.y); - - p->mouse_x = point.x; - p->mouse_y = p->window_height-1 - point.y; -} - - - -void gb_platform_set_controller_vibration(gbPlatform *p, isize index, f32 left_motor, f32 right_motor) { - if (gb_is_between(index, 0, GB_MAX_GAME_CONTROLLER_COUNT-1)) { - XINPUT_VIBRATION vibration = {0}; - left_motor = gb_clamp01(left_motor); - right_motor = gb_clamp01(right_motor); - vibration.wLeftMotorSpeed = cast(WORD)(65535 * left_motor); - vibration.wRightMotorSpeed = cast(WORD)(65535 * right_motor); - - p->xinput.set_state(cast(DWORD)index, &vibration); - } -} - - -void gb_platform_set_window_position(gbPlatform *p, i32 x, i32 y) { - RECT rect; - i32 width, height; - - GetClientRect(cast(HWND)p->window_handle, &rect); - width = rect.right - rect.left; - height = rect.bottom - rect.top; - MoveWindow(cast(HWND)p->window_handle, x, y, width, height, false); -} - -void gb_platform_set_window_title(gbPlatform *p, char const *title, ...) { - u16 buffer[256] = {0}; - char str[512] = {0}; - va_list va; - va_start(va, title); - gb_snprintf_va(str, gb_size_of(str), title, va); - va_end(va); - - if (str[0] != '\0') { - SetWindowTextW(cast(HWND)p->window_handle, cast(wchar_t const *)gb_utf8_to_ucs2(buffer, gb_size_of(buffer), str)); - } -} - -void gb_platform_toggle_fullscreen(gbPlatform *p, b32 fullscreen_desktop) { - // NOTE(bill): From the man himself, Raymond Chen! (Modified for my need.) - HWND handle = cast(HWND)p->window_handle; - DWORD style = cast(DWORD)GetWindowLongW(handle, GWL_STYLE); - WINDOWPLACEMENT placement; - - if (style & WS_OVERLAPPEDWINDOW) { - MONITORINFO monitor_info = {gb_size_of(monitor_info)}; - if (GetWindowPlacement(handle, &placement) && - GetMonitorInfoW(MonitorFromWindow(handle, 1), &monitor_info)) { - style &= ~WS_OVERLAPPEDWINDOW; - if (fullscreen_desktop) { - style &= ~WS_CAPTION; - style |= WS_POPUP; - } - SetWindowLongW(handle, GWL_STYLE, style); - SetWindowPos(handle, HWND_TOP, - monitor_info.rcMonitor.left, monitor_info.rcMonitor.top, - monitor_info.rcMonitor.right - monitor_info.rcMonitor.left, - monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top, - SWP_NOOWNERZORDER | SWP_FRAMECHANGED); - - if (fullscreen_desktop) { - p->window_flags |= gbWindow_FullscreenDesktop; - } else { - p->window_flags |= gbWindow_Fullscreen; - } - } - } else { - style &= ~WS_POPUP; - style |= WS_OVERLAPPEDWINDOW | WS_CAPTION; - SetWindowLongW(handle, GWL_STYLE, style); - SetWindowPlacement(handle, &placement); - SetWindowPos(handle, 0, 0, 0, 0, 0, - SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | - SWP_NOOWNERZORDER | SWP_FRAMECHANGED); - - p->window_flags &= ~gbWindow_Fullscreen; - } -} - -void gb_platform_toggle_borderless(gbPlatform *p) { - HWND handle = cast(HWND)p->window_handle; - DWORD style = GetWindowLongW(handle, GWL_STYLE); - b32 is_borderless = (style & WS_POPUP) != 0; - - GB_MASK_SET(style, is_borderless, WS_OVERLAPPEDWINDOW | WS_CAPTION); - GB_MASK_SET(style, !is_borderless, WS_POPUP); - - SetWindowLongW(handle, GWL_STYLE, style); - - GB_MASK_SET(p->window_flags, !is_borderless, gbWindow_Borderless); -} - - - -gb_inline void gb_platform_make_opengl_context_current(gbPlatform *p) { - if (p->renderer_type == gbRenderer_Opengl) { - wglMakeCurrent(cast(HDC)p->win32_dc, cast(HGLRC)p->opengl.context); - } -} - -gb_inline void gb_platform_show_window(gbPlatform *p) { - ShowWindow(cast(HWND)p->window_handle, SW_SHOW); - p->window_flags &= ~gbWindow_Hidden; -} - -gb_inline void gb_platform_hide_window(gbPlatform *p) { - ShowWindow(cast(HWND)p->window_handle, SW_HIDE); - p->window_flags |= gbWindow_Hidden; -} - -gb_inline gbVideoMode gb_video_mode_get_desktop(void) { - DEVMODEW win32_mode = {gb_size_of(win32_mode)}; - EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &win32_mode); - return gb_video_mode(win32_mode.dmPelsWidth, win32_mode.dmPelsHeight, win32_mode.dmBitsPerPel); -} - -isize gb_video_mode_get_fullscreen_modes(gbVideoMode *modes, isize max_mode_count) { - DEVMODEW win32_mode = {gb_size_of(win32_mode)}; - i32 count; - for (count = 0; - count < max_mode_count && EnumDisplaySettingsW(NULL, count, &win32_mode); - count++) { - modes[count] = gb_video_mode(win32_mode.dmPelsWidth, win32_mode.dmPelsHeight, win32_mode.dmBitsPerPel); - } - - gb_sort_array(modes, count, gb_video_mode_dsc_cmp); - return count; -} - - - -b32 gb_platform_has_clipboard_text(gbPlatform *p) { - b32 result = false; - - if (IsClipboardFormatAvailable(1/*CF_TEXT*/) && - OpenClipboard(cast(HWND)p->window_handle)) { - HANDLE mem = GetClipboardData(1/*CF_TEXT*/); - if (mem) { - char *str = cast(char *)GlobalLock(mem); - if (str && str[0] != '\0') { - result = true; - } - GlobalUnlock(mem); - } else { - return false; - } - - CloseClipboard(); - } - - return result; -} - -// TODO(bill): Handle UTF-8 -void gb_platform_set_clipboard_text(gbPlatform *p, char const *str) { - if (OpenClipboard(cast(HWND)p->window_handle)) { - isize i, len = gb_strlen(str)+1; - - HANDLE mem = cast(HANDLE)GlobalAlloc(0x0002/*GMEM_MOVEABLE*/, len); - if (mem) { - char *dst = cast(char *)GlobalLock(mem); - if (dst) { - for (i = 0; str[i]; i++) { - // TODO(bill): Does this cause a buffer overflow? - // NOTE(bill): Change \n to \r\n 'cause windows - if (str[i] == '\n' && (i == 0 || str[i-1] != '\r')) { - *dst++ = '\r'; - } - *dst++ = str[i]; - } - *dst = 0; - } - GlobalUnlock(mem); - } - - EmptyClipboard(); - if (!SetClipboardData(1/*CF_TEXT*/, mem)) { - return; - } - CloseClipboard(); - } -} - -// TODO(bill): Handle UTF-8 -char *gb_platform_get_clipboard_text(gbPlatform *p, gbAllocator a) { - char *text = NULL; - - if (IsClipboardFormatAvailable(1/*CF_TEXT*/) && - OpenClipboard(cast(HWND)p->window_handle)) { - HANDLE mem = GetClipboardData(1/*CF_TEXT*/); - if (mem) { - char *str = cast(char *)GlobalLock(mem); - text = gb_alloc_str(a, str); - GlobalUnlock(mem); - } else { - return NULL; - } - - CloseClipboard(); - } - - return text; -} - -#elif defined(GB_SYSTEM_OSX) - -#include <CoreGraphics/CoreGraphics.h> -#include <objc/objc.h> -#include <objc/message.h> -#include <objc/NSObjCRuntime.h> - -#if __LP64__ || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64 - #define NSIntegerEncoding "q" - #define NSUIntegerEncoding "L" -#else - #define NSIntegerEncoding "i" - #define NSUIntegerEncoding "I" -#endif - -#ifdef __OBJC__ - #import <Cocoa/Cocoa.h> -#else - typedef CGPoint NSPoint; - typedef CGSize NSSize; - typedef CGRect NSRect; - - extern id NSApp; - extern id const NSDefaultRunLoopMode; -#endif - -#if defined(__OBJC__) && __has_feature(objc_arc) -#error TODO(bill): Cannot compile as objective-c code just yet! -#endif - -// ABI is a bit different between platforms -#ifdef __arm64__ -#define abi_objc_msgSend_stret objc_msgSend -#else -#define abi_objc_msgSend_stret objc_msgSend_stret -#endif -#ifdef __i386__ -#define abi_objc_msgSend_fpret objc_msgSend_fpret -#else -#define abi_objc_msgSend_fpret objc_msgSend -#endif - -#define objc_msgSend_id ((id (*)(id, SEL))objc_msgSend) -#define objc_msgSend_void ((void (*)(id, SEL))objc_msgSend) -#define objc_msgSend_void_id ((void (*)(id, SEL, id))objc_msgSend) -#define objc_msgSend_void_bool ((void (*)(id, SEL, BOOL))objc_msgSend) -#define objc_msgSend_id_char_const ((id (*)(id, SEL, char const *))objc_msgSend) - -gb_internal NSUInteger gb__osx_application_should_terminate(id self, SEL _sel, id sender) { - // NOTE(bill): Do nothing - return 0; -} - -gb_internal void gb__osx_window_will_close(id self, SEL _sel, id notification) { - NSUInteger value = true; - object_setInstanceVariable(self, "closed", cast(void *)value); -} - -gb_internal void gb__osx_window_did_become_key(id self, SEL _sel, id notification) { - gbPlatform *p = NULL; - object_getInstanceVariable(self, "gbPlatform", cast(void **)&p); - if (p) { - // TODO(bill): - } -} - -b32 gb__platform_init(gbPlatform *p, char const *window_title, gbVideoMode mode, gbRendererType type, u32 window_flags) { - if (p->is_initialized) { - return true; - } - // Init Platform - { // Initial OSX State - Class appDelegateClass; - b32 resultAddProtoc, resultAddMethod; - id dgAlloc, dg, menubarAlloc, menubar; - id appMenuItemAlloc, appMenuItem; - id appMenuAlloc, appMenu; - - #if defined(ARC_AVAILABLE) - #error TODO(bill): This code should be compiled as C for now - #else - id poolAlloc = objc_msgSend_id(cast(id)objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); - p->osx_autorelease_pool = objc_msgSend_id(poolAlloc, sel_registerName("init")); - #endif - - objc_msgSend_id(cast(id)objc_getClass("NSApplication"), sel_registerName("sharedApplication")); - ((void (*)(id, SEL, NSInteger))objc_msgSend)(NSApp, sel_registerName("setActivationPolicy:"), 0); - - appDelegateClass = objc_allocateClassPair((Class)objc_getClass("NSObject"), "AppDelegate", 0); - resultAddProtoc = class_addProtocol(appDelegateClass, objc_getProtocol("NSApplicationDelegate")); - assert(resultAddProtoc); - resultAddMethod = class_addMethod(appDelegateClass, sel_registerName("applicationShouldTerminate:"), cast(IMP)gb__osx_application_should_terminate, NSUIntegerEncoding "@:@"); - assert(resultAddMethod); - dgAlloc = objc_msgSend_id(cast(id)appDelegateClass, sel_registerName("alloc")); - dg = objc_msgSend_id(dgAlloc, sel_registerName("init")); - #ifndef ARC_AVAILABLE - objc_msgSend_void(dg, sel_registerName("autorelease")); - #endif - - objc_msgSend_void_id(NSApp, sel_registerName("setDelegate:"), dg); - objc_msgSend_void(NSApp, sel_registerName("finishLaunching")); - - menubarAlloc = objc_msgSend_id(cast(id)objc_getClass("NSMenu"), sel_registerName("alloc")); - menubar = objc_msgSend_id(menubarAlloc, sel_registerName("init")); - #ifndef ARC_AVAILABLE - objc_msgSend_void(menubar, sel_registerName("autorelease")); - #endif - - appMenuItemAlloc = objc_msgSend_id(cast(id)objc_getClass("NSMenuItem"), sel_registerName("alloc")); - appMenuItem = objc_msgSend_id(appMenuItemAlloc, sel_registerName("init")); - #ifndef ARC_AVAILABLE - objc_msgSend_void(appMenuItem, sel_registerName("autorelease")); - #endif - - objc_msgSend_void_id(menubar, sel_registerName("addItem:"), appMenuItem); - ((id (*)(id, SEL, id))objc_msgSend)(NSApp, sel_registerName("setMainMenu:"), menubar); - - appMenuAlloc = objc_msgSend_id(cast(id)objc_getClass("NSMenu"), sel_registerName("alloc")); - appMenu = objc_msgSend_id(appMenuAlloc, sel_registerName("init")); - #ifndef ARC_AVAILABLE - objc_msgSend_void(appMenu, sel_registerName("autorelease")); - #endif - - { - id processInfo = objc_msgSend_id(cast(id)objc_getClass("NSProcessInfo"), sel_registerName("processInfo")); - id appName = objc_msgSend_id(processInfo, sel_registerName("processName")); - - id quitTitlePrefixString = objc_msgSend_id_char_const(cast(id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "Quit "); - id quitTitle = ((id (*)(id, SEL, id))objc_msgSend)(quitTitlePrefixString, sel_registerName("stringByAppendingString:"), appName); - - id quitMenuItemKey = objc_msgSend_id_char_const(cast(id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "q"); - id quitMenuItemAlloc = objc_msgSend_id(cast(id)objc_getClass("NSMenuItem"), sel_registerName("alloc")); - id quitMenuItem = ((id (*)(id, SEL, id, SEL, id))objc_msgSend)(quitMenuItemAlloc, sel_registerName("initWithTitle:action:keyEquivalent:"), quitTitle, sel_registerName("terminate:"), quitMenuItemKey); - #ifndef ARC_AVAILABLE - objc_msgSend_void(quitMenuItem, sel_registerName("autorelease")); - #endif - - objc_msgSend_void_id(appMenu, sel_registerName("addItem:"), quitMenuItem); - objc_msgSend_void_id(appMenuItem, sel_registerName("setSubmenu:"), appMenu); - } - } - - { // Init Window - NSRect rect = {{0, 0}, {cast(CGFloat)mode.width, cast(CGFloat)mode.height}}; - id windowAlloc, window, wdgAlloc, wdg, contentView, titleString; - Class WindowDelegateClass; - b32 resultAddProtoc, resultAddIvar, resultAddMethod; - - windowAlloc = objc_msgSend_id(cast(id)objc_getClass("NSWindow"), sel_registerName("alloc")); - window = ((id (*)(id, SEL, NSRect, NSUInteger, NSUInteger, BOOL))objc_msgSend)(windowAlloc, sel_registerName("initWithContentRect:styleMask:backing:defer:"), rect, 15, 2, NO); - #ifndef ARC_AVAILABLE - objc_msgSend_void(window, sel_registerName("autorelease")); - #endif - - // when we are not using ARC, than window will be added to autorelease pool - // so if we close it by hand (pressing red button), we don't want it to be released for us - // so it will be released by autorelease pool later - objc_msgSend_void_bool(window, sel_registerName("setReleasedWhenClosed:"), NO); - - WindowDelegateClass = objc_allocateClassPair((Class)objc_getClass("NSObject"), "WindowDelegate", 0); - resultAddProtoc = class_addProtocol(WindowDelegateClass, objc_getProtocol("NSWindowDelegate")); - GB_ASSERT(resultAddProtoc); - resultAddIvar = class_addIvar(WindowDelegateClass, "closed", gb_size_of(NSUInteger), rint(log2(gb_size_of(NSUInteger))), NSUIntegerEncoding); - GB_ASSERT(resultAddIvar); - resultAddIvar = class_addIvar(WindowDelegateClass, "gbPlatform", gb_size_of(void *), rint(log2(gb_size_of(void *))), "ˆv"); - GB_ASSERT(resultAddIvar); - resultAddMethod = class_addMethod(WindowDelegateClass, sel_registerName("windowWillClose:"), cast(IMP)gb__osx_window_will_close, "v@:@"); - GB_ASSERT(resultAddMethod); - resultAddMethod = class_addMethod(WindowDelegateClass, sel_registerName("windowDidBecomeKey:"), cast(IMP)gb__osx_window_did_become_key, "v@:@"); - GB_ASSERT(resultAddMethod); - wdgAlloc = objc_msgSend_id(cast(id)WindowDelegateClass, sel_registerName("alloc")); - wdg = objc_msgSend_id(wdgAlloc, sel_registerName("init")); - #ifndef ARC_AVAILABLE - objc_msgSend_void(wdg, sel_registerName("autorelease")); - #endif - - objc_msgSend_void_id(window, sel_registerName("setDelegate:"), wdg); - - contentView = objc_msgSend_id(window, sel_registerName("contentView")); - - { - NSPoint point = {20, 20}; - ((void (*)(id, SEL, NSPoint))objc_msgSend)(window, sel_registerName("cascadeTopLeftFromPoint:"), point); - } - - titleString = objc_msgSend_id_char_const(cast(id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), window_title); - objc_msgSend_void_id(window, sel_registerName("setTitle:"), titleString); - - if (type == gbRenderer_Opengl) { - // TODO(bill): Make sure this works correctly - u32 opengl_hex_version = (p->opengl.major << 12) | (p->opengl.minor << 8); - u32 gl_attribs[] = { - 8, 24, // NSOpenGLPFAColorSize, 24, - 11, 8, // NSOpenGLPFAAlphaSize, 8, - 5, // NSOpenGLPFADoubleBuffer, - 73, // NSOpenGLPFAAccelerated, - //72, // NSOpenGLPFANoRecovery, - //55, 1, // NSOpenGLPFASampleBuffers, 1, - //56, 4, // NSOpenGLPFASamples, 4, - 99, opengl_hex_version, // NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, - 0 - }; - - id pixel_format_alloc, pixel_format; - id opengl_context_alloc, opengl_context; - - pixel_format_alloc = objc_msgSend_id(cast(id)objc_getClass("NSOpenGLPixelFormat"), sel_registerName("alloc")); - pixel_format = ((id (*)(id, SEL, const uint32_t*))objc_msgSend)(pixel_format_alloc, sel_registerName("initWithAttributes:"), gl_attribs); - #ifndef ARC_AVAILABLE - objc_msgSend_void(pixel_format, sel_registerName("autorelease")); - #endif - - opengl_context_alloc = objc_msgSend_id(cast(id)objc_getClass("NSOpenGLContext"), sel_registerName("alloc")); - opengl_context = ((id (*)(id, SEL, id, id))objc_msgSend)(opengl_context_alloc, sel_registerName("initWithFormat:shareContext:"), pixel_format, nil); - #ifndef ARC_AVAILABLE - objc_msgSend_void(opengl_context, sel_registerName("autorelease")); - #endif - - objc_msgSend_void_id(opengl_context, sel_registerName("setView:"), contentView); - objc_msgSend_void_id(window, sel_registerName("makeKeyAndOrderFront:"), window); - objc_msgSend_void_bool(window, sel_registerName("setAcceptsMouseMovedEvents:"), YES); - - - p->window_handle = cast(void *)window; - p->opengl.context = cast(void *)opengl_context; - } else { - GB_PANIC("TODO(bill): Software rendering"); - } - - { - id blackColor = objc_msgSend_id(cast(id)objc_getClass("NSColor"), sel_registerName("blackColor")); - objc_msgSend_void_id(window, sel_registerName("setBackgroundColor:"), blackColor); - objc_msgSend_void_bool(NSApp, sel_registerName("activateIgnoringOtherApps:"), YES); - } - object_setInstanceVariable(wdg, "gbPlatform", cast(void *)p); - - p->is_initialized = true; - } - - return true; -} - -// NOTE(bill): Software rendering -b32 gb_platform_init_with_software(gbPlatform *p, char const *window_title, i32 width, i32 height, u32 window_flags) { - GB_PANIC("TODO(bill): Software rendering in not yet implemented on OS X\n"); - return gb__platform_init(p, window_title, gb_video_mode(width, height, 32), gbRenderer_Software, window_flags); -} -// NOTE(bill): OpenGL Rendering -b32 gb_platform_init_with_opengl(gbPlatform *p, char const *window_title, i32 width, i32 height, u32 window_flags, - i32 major, i32 minor, b32 core, b32 compatible) { - - p->opengl.major = major; - p->opengl.minor = minor; - p->opengl.core = core; - p->opengl.compatible = compatible; - return gb__platform_init(p, window_title, gb_video_mode(width, height, 32), gbRenderer_Opengl, window_flags); -} - -// NOTE(bill): Reverse engineering can be fun!!! -gb_internal gbKeyType gb__osx_from_key_code(u16 key_code) { - switch (key_code) { - default: return gbKey_Unknown; - // NOTE(bill): WHO THE FUCK DESIGNED THIS VIRTUAL KEY CODE SYSTEM?! - // THEY ARE FUCKING IDIOTS! - case 0x1d: return gbKey_0; - case 0x12: return gbKey_1; - case 0x13: return gbKey_2; - case 0x14: return gbKey_3; - case 0x15: return gbKey_4; - case 0x17: return gbKey_5; - case 0x16: return gbKey_6; - case 0x1a: return gbKey_7; - case 0x1c: return gbKey_8; - case 0x19: return gbKey_9; - - case 0x00: return gbKey_A; - case 0x0b: return gbKey_B; - case 0x08: return gbKey_C; - case 0x02: return gbKey_D; - case 0x0e: return gbKey_E; - case 0x03: return gbKey_F; - case 0x05: return gbKey_G; - case 0x04: return gbKey_H; - case 0x22: return gbKey_I; - case 0x26: return gbKey_J; - case 0x28: return gbKey_K; - case 0x25: return gbKey_L; - case 0x2e: return gbKey_M; - case 0x2d: return gbKey_N; - case 0x1f: return gbKey_O; - case 0x23: return gbKey_P; - case 0x0c: return gbKey_Q; - case 0x0f: return gbKey_R; - case 0x01: return gbKey_S; - case 0x11: return gbKey_T; - case 0x20: return gbKey_U; - case 0x09: return gbKey_V; - case 0x0d: return gbKey_W; - case 0x07: return gbKey_X; - case 0x10: return gbKey_Y; - case 0x06: return gbKey_Z; - - case 0x21: return gbKey_Lbracket; - case 0x1e: return gbKey_Rbracket; - case 0x29: return gbKey_Semicolon; - case 0x2b: return gbKey_Comma; - case 0x2f: return gbKey_Period; - case 0x27: return gbKey_Quote; - case 0x2c: return gbKey_Slash; - case 0x2a: return gbKey_Backslash; - case 0x32: return gbKey_Grave; - case 0x18: return gbKey_Equals; - case 0x1b: return gbKey_Minus; - case 0x31: return gbKey_Space; - - case 0x35: return gbKey_Escape; // Escape - case 0x3b: return gbKey_Lcontrol; // Left Control - case 0x38: return gbKey_Lshift; // Left Shift - case 0x3a: return gbKey_Lalt; // Left Alt - case 0x37: return gbKey_Lsystem; // Left OS specific: window (Windows and Linux), apple/cmd (MacOS X), ... - case 0x3e: return gbKey_Rcontrol; // Right Control - case 0x3c: return gbKey_Rshift; // Right Shift - case 0x3d: return gbKey_Ralt; // Right Alt - // case 0x37: return gbKey_Rsystem; // Right OS specific: window (Windows and Linux), apple/cmd (MacOS X), ... - case 0x6e: return gbKey_Menu; // Menu - case 0x24: return gbKey_Return; // Return - case 0x33: return gbKey_Backspace; // Backspace - case 0x30: return gbKey_Tab; // Tabulation - case 0x74: return gbKey_Pageup; // Page up - case 0x79: return gbKey_Pagedown; // Page down - case 0x77: return gbKey_End; // End - case 0x73: return gbKey_Home; // Home - case 0x72: return gbKey_Insert; // Insert - case 0x75: return gbKey_Delete; // Delete - case 0x45: return gbKey_Plus; // + - case 0x4e: return gbKey_Subtract; // - - case 0x43: return gbKey_Multiply; // * - case 0x4b: return gbKey_Divide; // / - case 0x7b: return gbKey_Left; // Left arrow - case 0x7c: return gbKey_Right; // Right arrow - case 0x7e: return gbKey_Up; // Up arrow - case 0x7d: return gbKey_Down; // Down arrow - case 0x52: return gbKey_Numpad0; // Numpad 0 - case 0x53: return gbKey_Numpad1; // Numpad 1 - case 0x54: return gbKey_Numpad2; // Numpad 2 - case 0x55: return gbKey_Numpad3; // Numpad 3 - case 0x56: return gbKey_Numpad4; // Numpad 4 - case 0x57: return gbKey_Numpad5; // Numpad 5 - case 0x58: return gbKey_Numpad6; // Numpad 6 - case 0x59: return gbKey_Numpad7; // Numpad 7 - case 0x5b: return gbKey_Numpad8; // Numpad 8 - case 0x5c: return gbKey_Numpad9; // Numpad 9 - case 0x41: return gbKey_NumpadDot; // Numpad . - case 0x4c: return gbKey_NumpadEnter; // Numpad Enter - case 0x7a: return gbKey_F1; // F1 - case 0x78: return gbKey_F2; // F2 - case 0x63: return gbKey_F3; // F3 - case 0x76: return gbKey_F4; // F4 - case 0x60: return gbKey_F5; // F5 - case 0x61: return gbKey_F6; // F6 - case 0x62: return gbKey_F7; // F7 - case 0x64: return gbKey_F8; // F8 - case 0x65: return gbKey_F9; // F8 - case 0x6d: return gbKey_F10; // F10 - case 0x67: return gbKey_F11; // F11 - case 0x6f: return gbKey_F12; // F12 - case 0x69: return gbKey_F13; // F13 - case 0x6b: return gbKey_F14; // F14 - case 0x71: return gbKey_F15; // F15 - // case : return gbKey_Pause; // Pause // NOTE(bill): Not possible on OS X - } -} - -gb_internal void gb__osx_on_cocoa_event(gbPlatform *p, id event, id window) { - if (!event) { - return; - } else if (objc_msgSend_id(window, sel_registerName("delegate"))) { - NSUInteger event_type = ((NSUInteger (*)(id, SEL))objc_msgSend)(event, sel_registerName("type")); - switch (event_type) { - case 1: gb_key_state_update(&p->mouse_buttons[gbMouseButton_Left], true); break; // NSLeftMouseDown - case 2: gb_key_state_update(&p->mouse_buttons[gbMouseButton_Left], false); break; // NSLeftMouseUp - case 3: gb_key_state_update(&p->mouse_buttons[gbMouseButton_Right], true); break; // NSRightMouseDown - case 4: gb_key_state_update(&p->mouse_buttons[gbMouseButton_Right], false); break; // NSRightMouseUp - case 25: { // NSOtherMouseDown - // TODO(bill): Test thoroughly - NSInteger number = ((NSInteger (*)(id, SEL))objc_msgSend)(event, sel_registerName("buttonNumber")); - if (number == 2) gb_key_state_update(&p->mouse_buttons[gbMouseButton_Middle], true); - if (number == 3) gb_key_state_update(&p->mouse_buttons[gbMouseButton_X1], true); - if (number == 4) gb_key_state_update(&p->mouse_buttons[gbMouseButton_X2], true); - } break; - case 26: { // NSOtherMouseUp - NSInteger number = ((NSInteger (*)(id, SEL))objc_msgSend)(event, sel_registerName("buttonNumber")); - if (number == 2) gb_key_state_update(&p->mouse_buttons[gbMouseButton_Middle], false); - if (number == 3) gb_key_state_update(&p->mouse_buttons[gbMouseButton_X1], false); - if (number == 4) gb_key_state_update(&p->mouse_buttons[gbMouseButton_X2], false); - - } break; - - // TODO(bill): Scroll wheel - case 22: { // NSScrollWheel - CGFloat dx = ((CGFloat (*)(id, SEL))abi_objc_msgSend_fpret)(event, sel_registerName("scrollingDeltaX")); - CGFloat dy = ((CGFloat (*)(id, SEL))abi_objc_msgSend_fpret)(event, sel_registerName("scrollingDeltaY")); - BOOL precision_scrolling = ((BOOL (*)(id, SEL))objc_msgSend)(event, sel_registerName("hasPreciseScrollingDeltas")); - if (precision_scrolling) { - dx *= 0.1f; - dy *= 0.1f; - } - // TODO(bill): Handle sideways - p->mouse_wheel_delta = dy; - // p->mouse_wheel_dy = dy; - // gb_printf("%f %f\n", dx, dy); - } break; - - case 12: { // NSFlagsChanged - #if 0 - // TODO(bill): Reverse engineer this properly - NSUInteger modifiers = ((NSUInteger (*)(id, SEL))objc_msgSend)(event, sel_registerName("modifierFlags")); - u32 upper_mask = (modifiers & 0xffff0000ul) >> 16; - b32 shift = (upper_mask & 0x02) != 0; - b32 control = (upper_mask & 0x04) != 0; - b32 alt = (upper_mask & 0x08) != 0; - b32 command = (upper_mask & 0x10) != 0; - #endif - - // gb_printf("%u\n", keys.mask); - // gb_printf("%x\n", cast(u32)modifiers); - } break; - - case 10: { // NSKeyDown - u16 key_code; - - id input_text = objc_msgSend_id(event, sel_registerName("characters")); - char const *input_text_utf8 = ((char const *(*)(id, SEL))objc_msgSend)(input_text, sel_registerName("UTF8String")); - p->char_buffer_count = gb_strnlen(input_text_utf8, gb_size_of(p->char_buffer)); - gb_memcopy(p->char_buffer, input_text_utf8, p->char_buffer_count); - - key_code = ((unsigned short (*)(id, SEL))objc_msgSend)(event, sel_registerName("keyCode")); - gb_key_state_update(&p->keys[gb__osx_from_key_code(key_code)], true); - } break; - - case 11: { // NSKeyUp - u16 key_code = ((unsigned short (*)(id, SEL))objc_msgSend)(event, sel_registerName("keyCode")); - gb_key_state_update(&p->keys[gb__osx_from_key_code(key_code)], false); - } break; - - default: break; - } - - objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), event); - } -} - - -void gb_platform_update(gbPlatform *p) { - id window, key_window, content_view; - NSRect original_frame; - - window = cast(id)p->window_handle; - key_window = objc_msgSend_id(NSApp, sel_registerName("keyWindow")); - p->window_has_focus = key_window == window; // TODO(bill): Is this right - - - if (p->window_has_focus) { - isize i; - p->char_buffer_count = 0; // TODO(bill): Reset buffer count here or else where? - - // NOTE(bill): Need to update as the keys only get updates on events - for (i = 0; i < gbKey_Count; i++) { - b32 is_down = (p->keys[i] & gbKeyState_Down) != 0; - gb_key_state_update(&p->keys[i], is_down); - } - - for (i = 0; i < gbMouseButton_Count; i++) { - b32 is_down = (p->mouse_buttons[i] & gbKeyState_Down) != 0; - gb_key_state_update(&p->mouse_buttons[i], is_down); - } - - } - - { // Handle Events - id distant_past = objc_msgSend_id(cast(id)objc_getClass("NSDate"), sel_registerName("distantPast")); - id event = ((id (*)(id, SEL, NSUInteger, id, id, BOOL))objc_msgSend)(NSApp, sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"), NSUIntegerMax, distant_past, NSDefaultRunLoopMode, YES); - gb__osx_on_cocoa_event(p, event, window); - } - - if (p->window_has_focus) { - p->key_modifiers.control = p->keys[gbKey_Lcontrol] | p->keys[gbKey_Rcontrol]; - p->key_modifiers.alt = p->keys[gbKey_Lalt] | p->keys[gbKey_Ralt]; - p->key_modifiers.shift = p->keys[gbKey_Lshift] | p->keys[gbKey_Rshift]; - } - - { // Check if window is closed - id wdg = objc_msgSend_id(window, sel_registerName("delegate")); - if (!wdg) { - p->window_is_closed = false; - } else { - NSUInteger value = 0; - object_getInstanceVariable(wdg, "closed", cast(void **)&value); - p->window_is_closed = (value != 0); - } - } - - - - content_view = objc_msgSend_id(window, sel_registerName("contentView")); - original_frame = ((NSRect (*)(id, SEL))abi_objc_msgSend_stret)(content_view, sel_registerName("frame")); - - { // Window - NSRect frame = original_frame; - frame = ((NSRect (*)(id, SEL, NSRect))abi_objc_msgSend_stret)(content_view, sel_registerName("convertRectToBacking:"), frame); - p->window_width = frame.size.width; - p->window_height = frame.size.height; - frame = ((NSRect (*)(id, SEL, NSRect))abi_objc_msgSend_stret)(window, sel_registerName("convertRectToScreen:"), frame); - p->window_x = frame.origin.x; - p->window_y = frame.origin.y; - } - - { // Mouse - NSRect frame = original_frame; - NSPoint mouse_pos = ((NSPoint (*)(id, SEL))objc_msgSend)(window, sel_registerName("mouseLocationOutsideOfEventStream")); - mouse_pos.x = gb_clamp(mouse_pos.x, 0, frame.size.width-1); - mouse_pos.y = gb_clamp(mouse_pos.y, 0, frame.size.height-1); - - { - i32 x = mouse_pos.x; - i32 y = mouse_pos.y; - p->mouse_dx = x - p->mouse_x; - p->mouse_dy = y - p->mouse_y; - p->mouse_x = x; - p->mouse_y = y; - } - - if (p->mouse_clip) { - b32 update = false; - i32 x = p->mouse_x; - i32 y = p->mouse_y; - if (p->mouse_x < 0) { - x = 0; - update = true; - } else if (p->mouse_y > p->window_height-1) { - y = p->window_height-1; - update = true; - } - - if (p->mouse_y < 0) { - y = 0; - update = true; - } else if (p->mouse_x > p->window_width-1) { - x = p->window_width-1; - update = true; - } - - if (update) { - gb_platform_set_mouse_position(p, x, y); - } - } - } - - { // TODO(bill): Controllers - - } - - // TODO(bill): Is this in the correct place? - objc_msgSend_void(NSApp, sel_registerName("updateWindows")); - if (p->renderer_type == gbRenderer_Opengl) { - objc_msgSend_void(cast(id)p->opengl.context, sel_registerName("update")); - gb_platform_make_opengl_context_current(p); - } -} - -void gb_platform_display(gbPlatform *p) { - // TODO(bill): Do more - if (p->renderer_type == gbRenderer_Opengl) { - gb_platform_make_opengl_context_current(p); - objc_msgSend_void(cast(id)p->opengl.context, sel_registerName("flushBuffer")); - } else if (p->renderer_type == gbRenderer_Software) { - // TODO(bill): - } else { - GB_PANIC("Invalid window rendering type"); - } - - { - f64 prev_time = p->curr_time; - f64 curr_time = gb_time_now(); - p->dt_for_frame = curr_time - prev_time; - p->curr_time = curr_time; - } -} - -void gb_platform_destroy(gbPlatform *p) { - gb_platform_make_opengl_context_current(p); - - objc_msgSend_void(cast(id)p->window_handle, sel_registerName("close")); - - #if defined(ARC_AVAILABLE) - // TODO(bill): autorelease pool - #else - objc_msgSend_void(cast(id)p->osx_autorelease_pool, sel_registerName("drain")); - #endif -} - -void gb_platform_show_cursor(gbPlatform *p, b32 show) { - if (show ) { - // objc_msgSend_void(class_registerName("NSCursor"), sel_registerName("unhide")); - } else { - // objc_msgSend_void(class_registerName("NSCursor"), sel_registerName("hide")); - } -} - -void gb_platform_set_mouse_position(gbPlatform *p, i32 x, i32 y) { - // TODO(bill): - CGPoint pos = {cast(CGFloat)x, cast(CGFloat)y}; - pos.x += p->window_x; - pos.y += p->window_y; - CGWarpMouseCursorPosition(pos); -} - -void gb_platform_set_controller_vibration(gbPlatform *p, isize index, f32 left_motor, f32 right_motor) { - // TODO(bill): -} - -b32 gb_platform_has_clipboard_text(gbPlatform *p) { - // TODO(bill): - return false; -} - -void gb_platform_set_clipboard_text(gbPlatform *p, char const *str) { - // TODO(bill): -} - -char *gb_platform_get_clipboard_text(gbPlatform *p, gbAllocator a) { - // TODO(bill): - return NULL; -} - -void gb_platform_set_window_position(gbPlatform *p, i32 x, i32 y) { - // TODO(bill): -} - -void gb_platform_set_window_title(gbPlatform *p, char const *title, ...) { - id title_string; - char buf[256] = {0}; - va_list va; - va_start(va, title); - gb_snprintf_va(buf, gb_count_of(buf), title, va); - va_end(va); - - title_string = objc_msgSend_id_char_const(cast(id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), buf); - objc_msgSend_void_id(cast(id)p->window_handle, sel_registerName("setTitle:"), title_string); -} - -void gb_platform_toggle_fullscreen(gbPlatform *p, b32 fullscreen_desktop) { - // TODO(bill): -} - -void gb_platform_toggle_borderless(gbPlatform *p) { - // TODO(bill): -} - -void gb_platform_make_opengl_context_current(gbPlatform *p) { - objc_msgSend_void(cast(id)p->opengl.context, sel_registerName("makeCurrentContext")); -} - -void gb_platform_show_window(gbPlatform *p) { - // TODO(bill): -} - -void gb_platform_hide_window(gbPlatform *p) { - // TODO(bill): -} - -i32 gb__osx_mode_bits_per_pixel(CGDisplayModeRef mode) { - i32 bits_per_pixel = 0; - CFStringRef pixel_encoding = CGDisplayModeCopyPixelEncoding(mode); - if(CFStringCompare(pixel_encoding, CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) { - bits_per_pixel = 32; - } else if(CFStringCompare(pixel_encoding, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) { - bits_per_pixel = 16; - } else if(CFStringCompare(pixel_encoding, CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) { - bits_per_pixel = 8; - } - CFRelease(pixel_encoding); - - return bits_per_pixel; -} - -i32 gb__osx_display_bits_per_pixel(CGDirectDisplayID display) { - CGDisplayModeRef mode = CGDisplayCopyDisplayMode(display); - i32 bits_per_pixel = gb__osx_mode_bits_per_pixel(mode); - CGDisplayModeRelease(mode); - return bits_per_pixel; -} - -gbVideoMode gb_video_mode_get_desktop(void) { - CGDirectDisplayID display = CGMainDisplayID(); - return gb_video_mode(CGDisplayPixelsWide(display), - CGDisplayPixelsHigh(display), - gb__osx_display_bits_per_pixel(display)); -} - - -isize gb_video_mode_get_fullscreen_modes(gbVideoMode *modes, isize max_mode_count) { - CFArrayRef cg_modes = CGDisplayCopyAllDisplayModes(CGMainDisplayID(), NULL); - CFIndex i, count; - if (cg_modes == NULL) { - return 0; - } - - count = gb_min(CFArrayGetCount(cg_modes), max_mode_count); - for (i = 0; i < count; i++) { - CGDisplayModeRef cg_mode = cast(CGDisplayModeRef)CFArrayGetValueAtIndex(cg_modes, i); - modes[i] = gb_video_mode(CGDisplayModeGetWidth(cg_mode), - CGDisplayModeGetHeight(cg_mode), - gb__osx_mode_bits_per_pixel(cg_mode)); - } - - CFRelease(cg_modes); - - gb_sort_array(modes, count, gb_video_mode_dsc_cmp); - return cast(isize)count; -} - -#endif - - -// TODO(bill): OSX Platform Layer -// NOTE(bill): Use this as a guide so there is no need for Obj-C https://github.com/jimon/osx_app_in_plain_c - -gb_inline gbVideoMode gb_video_mode(i32 width, i32 height, i32 bits_per_pixel) { - gbVideoMode m; - m.width = width; - m.height = height; - m.bits_per_pixel = bits_per_pixel; - return m; -} - -gb_inline b32 gb_video_mode_is_valid(gbVideoMode mode) { - gb_local_persist gbVideoMode modes[256] = {0}; - gb_local_persist isize mode_count = 0; - gb_local_persist b32 is_set = false; - isize i; - - if (!is_set) { - mode_count = gb_video_mode_get_fullscreen_modes(modes, gb_count_of(modes)); - is_set = true; - } - - for (i = 0; i < mode_count; i++) { - gb_printf("%d %d\n", modes[i].width, modes[i].height); - } - - return gb_binary_search_array(modes, mode_count, &mode, gb_video_mode_cmp) >= 0; -} - -GB_COMPARE_PROC(gb_video_mode_cmp) { - gbVideoMode const *x = cast(gbVideoMode const *)a; - gbVideoMode const *y = cast(gbVideoMode const *)b; - - if (x->bits_per_pixel == y->bits_per_pixel) { - if (x->width == y->width) { - return x->height < y->height ? -1 : x->height > y->height; - } - return x->width < y->width ? -1 : x->width > y->width; - } - return x->bits_per_pixel < y->bits_per_pixel ? -1 : +1; -} - -GB_COMPARE_PROC(gb_video_mode_dsc_cmp) { - return gb_video_mode_cmp(b, a); -} - -#endif // defined(GB_PLATFORM) - - - - #if defined(GB_COMPILER_MSVC) #pragma warning(pop) #endif |