aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Ginger Bill 2016-06-07 15:51:37 +0100
committerGravatar Ginger Bill 2016-06-07 15:51:37 +0100
commitb7fcb11ed888df96012bd0ae58eaf4cf8db18829 (patch)
treef9cd3831363bec8cde4c0b8e4f3eb4e0508e8e96
parentCompile on OSX (excluding platform part) (diff)
OS X gbPlatform Support (missing some things)
Diffstat (limited to '')
-rw-r--r--README.md4
-rw-r--r--gb.h771
-rw-r--r--gb_math.h22
3 files changed, 767 insertions, 30 deletions
diff --git a/README.md b/README.md
index 5375cce..473afc9 100644
--- a/README.md
+++ b/README.md
@@ -4,8 +4,8 @@ gb single-file public domain libraries for C & C++
library | latest version | category | description
----------------|----------------|----------|-------------
-**gb.h** | 0.24b | misc | Helper library (Standard library _improvement_)
-**gb_math.h** | 0.06g | math | Vector math library geared towards game development
+**gb.h** | 0.25 | misc | Helper library (Standard library _improvement_)
+**gb_math.h** | 0.06h | math | Vector math library geared towards game development
**gb_gl.h** | 0.05 | graphics | OpenGL Helper Library
**gb_string.h** | 0.95a | strings | A better string library (this is built into gb.h too with custom allocator support!)
**gb_ini.h** | 0.93 | misc | Simple ini file loader library
diff --git a/gb.h b/gb.h
index ac112e2..dfaf1d4 100644
--- a/gb.h
+++ b/gb.h
@@ -1,4 +1,4 @@
-/* gb.h - v0.24b - Ginger Bill's C Helper Library - public domain
+/* gb.h - v0.25 - Ginger Bill's C Helper Library - public domain
- no warranty implied; use at your own risk
This is a single header file with a bunch of useful stuff
@@ -58,6 +58,7 @@ TODOS
- More date & time functions
VERSION HISTORY
+ 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
@@ -126,15 +127,14 @@ extern "C" {
#define GB_EXTERN extern
#endif
-#ifndef GB_DLL_EXPORT
-#define GB_DLL_EXPORT GB_EXTERN __declspec(dllexport)
-#endif
-
-#ifndef GB_DLL_IMPORT
-#define GB_DLL_IMPORT GB_EXTERN __declspec(dllimport)
+#if defined(_WIN32)
+ #define GB_DLL_EXPORT GB_EXTERN __declspec(dllexport)
+ #define GB_DLL_IMPORT GB_EXTERN __declspec(dllimport)
+#else
+ #define GB_DLL_EXPORT GB_EXTERN __attribute__((visibility("default")))
+ #define GB_DLL_IMPORT GB_EXTERN
#endif
-
// NOTE(bill): Redefine for DLL, etc.
#ifndef GB_DEF
#ifdef GB_STATIC
@@ -2284,6 +2284,18 @@ GB_DEF isize gb_count_set_bits(u64 mask);
// 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
@@ -2349,11 +2361,11 @@ typedef enum gbKeyType {
gbKey_Lcontrol, // Left Control
gbKey_Lshift, // Left Shift
gbKey_Lalt, // Left Alt
- gbKey_Lsystem, // Left OS specific: window (Windows and Linux), apple (MacOS X), ...
+ 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 (MacOS X), ...
+ gbKey_Rsystem, // Right OS specific: window (Windows and Linux), apple/cmd (MacOS X), ...
gbKey_Menu, // Menu
gbKey_Return, // Return
gbKey_Backspace, // Backspace
@@ -2382,8 +2394,8 @@ typedef enum gbKeyType {
gbKey_Numpad7, // Numpad 7
gbKey_Numpad8, // Numpad 8
gbKey_Numpad9, // Numpad 9
- gbKey_NumpadDot, // Numpad .
- gbKey_NumpadEnter, // Numpad Enter
+ gbKey_NumpadDot, // Numpad .
+ gbKey_NumpadEnter, // Numpad Enter
gbKey_F1, // F1
gbKey_F2, // F2
gbKey_F3, // F3
@@ -2492,12 +2504,8 @@ typedef enum gbRendererType {
} gbRendererType;
-#if defined(_MSC_VER)
-#pragma warning(push)
-#pragma warning(disable:4201)
-#endif
-#if !defined(_WINDOWS_)
+#if defined(GB_SYSTEM_WINDOWS) && !defined(_WINDOWS_)
typedef struct tagBITMAPINFOHEADER {
unsigned long biSize;
long biWidth;
@@ -2534,6 +2542,8 @@ typedef struct gbPlatform {
#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;
@@ -2572,7 +2582,7 @@ typedef struct gbPlatform {
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
- i32 mouse_wheel_delta;
+ f32 mouse_wheel_delta;
gbKeyState mouse_buttons[gbMouseButton_Count];
gbGameController game_controllers[GB_MAX_GAME_CONTROLLER_COUNT];
@@ -2589,9 +2599,6 @@ typedef struct gbPlatform {
#endif
} gbPlatform;
-#if defined(_MSC_VER)
-#pragma warning(pop)
-#endif
typedef struct gbVideoMode {
i32 width, height;
@@ -2613,7 +2620,7 @@ GB_DEF b32 gb_platform_init_with_opengl (gbPlatform *p, char const *
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, i32 show);
+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);
@@ -2696,7 +2703,7 @@ extern "C" {
#endif
-#if defined(_MSC_VER) && !defined(_WINDOWS_)
+#if defined(GB_COMPILER_MSVC) && !defined(_WINDOWS_)
////////////////////////////////////////////////////////////////
//
// Bill's Mini Windows.h
@@ -3717,9 +3724,9 @@ extern "C" {
#pragma GCC diagnostic ignored "-Wmissing-braces"
#endif
-
#if defined(_MSC_VER)
#pragma warning(push)
+#pragma warning(disable:4201)
#pragma warning(disable:4127) // Conditional expression is constant
#endif
@@ -8280,7 +8287,8 @@ gb_inline gbDllProc gb_dll_proc_address(gbDllHandle dll, char const *proc_name)
gb__timestart = mach_absolute_time();
}
- result = (mach_absolute_time() - gb__timestart) *gb__timebase;
+ // NOTE(bill): mach_absolute_time() returns things in nanoseconds
+ result = 1.0e-9 * (mach_absolute_time() - gb__timestart) * gb__timebase;
return result;
#else
struct timespec t;
@@ -9317,7 +9325,7 @@ void gb_platform_destroy(gbPlatform *p) {
DestroyWindow(cast(HWND)p->window_handle);
}
-void gb_platform_show_cursor(gbPlatform *p, i32 show) {
+void gb_platform_show_cursor(gbPlatform *p, b32 show) {
gb_unused(p);
ShowCursor(show);
}
@@ -9533,6 +9541,717 @@ char *gb_platform_get_clipboard_text(gbPlatform *p, gbAllocator a) {
return text;
}
+#elif defined(GB_SYSTEM_OSX)
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreGraphics/CoreGraphics.h>
+#include <objc/objc.h>
+#include <objc/runtime.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
+ #include <CoreGraphics/CGBase.h>
+ #include <CoreGraphics/CGGeometry.h>
+ 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
+ #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);
+
+ Class appDelegateClass = objc_allocateClassPair((Class)objc_getClass("NSObject"), "AppDelegate", 0);
+ b32 resultAddProtoc = class_addProtocol(appDelegateClass, objc_getProtocol("NSApplicationDelegate"));
+ assert(resultAddProtoc);
+ b32 resultAddMethod = class_addMethod(appDelegateClass, sel_registerName("applicationShouldTerminate:"), cast(IMP)gb__osx_application_should_terminate, NSUIntegerEncoding "@:@");
+ assert(resultAddMethod);
+ id dgAlloc = objc_msgSend_id(cast(id)appDelegateClass, sel_registerName("alloc"));
+ id 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"));
+
+ id menubarAlloc = objc_msgSend_id(cast(id)objc_getClass("NSMenu"), sel_registerName("alloc"));
+ id menubar = objc_msgSend_id(menubarAlloc, sel_registerName("init"));
+ #ifndef ARC_AVAILABLE
+ objc_msgSend_void(menubar, sel_registerName("autorelease"));
+ #endif
+
+ id appMenuItemAlloc = objc_msgSend_id(cast(id)objc_getClass("NSMenuItem"), sel_registerName("alloc"));
+ id 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);
+
+ id appMenuAlloc = objc_msgSend_id(cast(id)objc_getClass("NSMenu"), sel_registerName("alloc"));
+ id 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;
+
+ 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);
+
+ Class WindowDelegateClass = objc_allocateClassPair((Class)objc_getClass("NSObject"), "WindowDelegate", 0);
+ b32 resultAddProtoc = class_addProtocol(WindowDelegateClass, objc_getProtocol("NSWindowDelegate"));
+ assert(resultAddProtoc);
+ b32 resultAddIvar = class_addIvar(WindowDelegateClass, "closed", sizeof(NSUInteger), rint(log2(sizeof(NSUInteger))), NSUIntegerEncoding);
+ assert(resultAddIvar);
+ resultAddIvar = class_addIvar(WindowDelegateClass, "tigrHandle", sizeof(void*), rint(log2(sizeof(void*))), "ˆv");
+ assert(resultAddIvar);
+ b32 resultAddMethod = class_addMethod(WindowDelegateClass, sel_registerName("windowWillClose:"), cast(IMP)gb__osx_window_will_close, "v@:@");
+ assert(resultAddMethod);
+ resultAddMethod = class_addMethod(WindowDelegateClass, sel_registerName("windowDidBecomeKey:"), cast(IMP)gb__osx_window_did_become_key, "v@:@");
+ 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_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_version, // NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
+ 0
+ };
+
+ id pixel_format_alloc = objc_msgSend_id(cast(id)objc_getClass("NSOpenGLPixelFormat"), sel_registerName("alloc"));
+ id 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
+
+ id opengl_context_alloc = objc_msgSend_id(cast(id)objc_getClass("NSOpenGLContext"), sel_registerName("alloc"));
+ id 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;
+
+ id wdg = objc_msgSend_id(window, sel_registerName("delegate"));
+ if (!wdg) return;
+
+
+ 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
+ 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);
+
+ 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)], 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);
+ if (cg_modes == NULL) {
+ return 0;
+ }
+ CFIndex i, count = CFArrayGetCount(cg_modes);
+ count = gb_min(count, 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 count;
+}
+
#endif
diff --git a/gb_math.h b/gb_math.h
index 48a26f8..075dd28 100644
--- a/gb_math.h
+++ b/gb_math.h
@@ -1,8 +1,9 @@
-/* gb_math.h - v0.06g - public domain C math library - no warranty implied; use at your own risk
+/* gb_math.h - v0.06h - public domain C math library - no warranty implied; use at your own risk
A C math library geared towards game development
use '#define GB_MATH_IMPLEMENTATION' before including to create the implementation in _ONE_ file
Version History:
+ 0.06h - Ignore silly warnings
0.06g - Remove memzero
0.06f - Remove warning on MSVC
0.06e - Change brace style and fix some warnings
@@ -748,11 +749,21 @@ inline gbVec3 operator*(gbQuat q, gbVec3 v) { gbVec3 r; gb_quat_rotate_vec3(&r,
*
*
*
-/****************************************************************/
+ ****************************************************************/
#if defined(GB_MATH_IMPLEMENTATION) && !defined(GB_MATH_IMPLEMENTATION_DONE)
#define GB_MATH_IMPLEMENTATION_DONE
+ #if (defined(__GCC__) || defined(__GNUC__)) && !defined(__clang__)
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wattributes"
+ #pragma GCC diagnostic ignored "-Wmissing-braces"
+ #elif __clang__
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wattributes"
+ #pragma clang diagnostic ignored "-Wmissing-braces"
+ #endif
+
/* NOTE(bill): To remove the need for memcpy */
static void gb__memcpy_4byte(void *dest, void const *src, size_t size) {
@@ -2057,5 +2068,12 @@ int gb_random_range_int(int min_inc, int max_inc) {
return result;
}
+#if defined(__GCC__) || defined(__GNUC__)
+#pragma GCC diagnostic pop
+#elif defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
+
#endif /* GB_MATH_IMPLEMENTATION */