Skip to content

Instantly share code, notes, and snippets.

@colrdavidson
Created August 28, 2024 04:04
Show Gist options
  • Select an option

  • Save colrdavidson/aecf689196fcae49122749f866780854 to your computer and use it in GitHub Desktop.

Select an option

Save colrdavidson/aecf689196fcae49122749f866780854 to your computer and use it in GitHub Desktop.
OSX Platform Layer
//+build darwin
package main
import "core:fmt"
import "core:strings"
import "core:os"
import "core:time"
import gl "vendor:OpenGL"
import NS "vendor:darwin/Foundation"
import CA "vendor:darwin/QuartzCore"
normalize_key :: proc(v: NS.kVK) -> KeyType {
switch v {
case .ANSI_A: return .A
case .ANSI_S: return .S
case .ANSI_D: return .D
case .ANSI_F: return .F
case .ANSI_H: return .H
case .ANSI_G: return .G
case .ANSI_Z: return .Z
case .ANSI_X: return .X
case .ANSI_C: return .C
case .ANSI_V: return .V
case .ANSI_B: return .B
case .ANSI_Q: return .Q
case .ANSI_W: return .W
case .ANSI_E: return .E
case .ANSI_R: return .R
case .ANSI_Y: return .Y
case .ANSI_T: return .T
case .ANSI_1: return ._1
case .ANSI_2: return ._2
case .ANSI_3: return ._3
case .ANSI_4: return ._4
case .ANSI_6: return ._6
case .ANSI_5: return ._5
case .ANSI_Equal: return .Equal
case .ANSI_9: return ._9
case .ANSI_7: return ._7
case .ANSI_Minus: return .Minus
case .ANSI_8: return ._8
case .ANSI_0: return ._0
case .ANSI_RightBracket: return .RightBracket
case .ANSI_O: return .O
case .ANSI_U: return .U
case .ANSI_LeftBracket: return .LeftBracket
case .ANSI_I: return .I
case .ANSI_P: return .P
case .ANSI_L: return .L
case .ANSI_J: return .J
case .ANSI_Quote: return .Quote
case .ANSI_K: return .K
case .ANSI_Semicolon: return .Semicolon
case .ANSI_Backslash: return .Backslash
case .ANSI_Comma: return .Comma
case .ANSI_Slash: return .Slash
case .ANSI_N: return .N
case .ANSI_M: return .M
case .ANSI_Period: return .Period
case .ANSI_Grave: return .Grave
case .ANSI_KeypadDecimal: return .Keypad_Period
case .ANSI_KeypadMultiply: return .Keypad_Multiply
case .ANSI_KeypadPlus: return .Keypad_Plus
case .ANSI_KeypadClear: return .Keypad_Clear
case .ANSI_KeypadDivide: return .Keypad_Divide
case .ANSI_KeypadEnter: return .Keypad_Enter
case .ANSI_KeypadMinus: return .Keypad_Minus
case .ANSI_KeypadEquals: return .Keypad_Equal
case .ANSI_Keypad0: return ._0
case .ANSI_Keypad1: return ._1
case .ANSI_Keypad2: return ._2
case .ANSI_Keypad3: return ._3
case .ANSI_Keypad4: return ._4
case .ANSI_Keypad5: return ._5
case .ANSI_Keypad6: return ._6
case .ANSI_Keypad7: return ._7
case .ANSI_Keypad8: return ._8
case .ANSI_Keypad9: return ._9
case .Return: return .Return
case .Tab: return .Tab
case .Space: return .Space
case .Delete: return .Delete
case .Escape: return .Escape
case .Command: return .LeftSuper
case .Shift: return .LeftShift
case .CapsLock: return .CapsLock
case .Option: return .LeftAlt
case .Control: return .LeftControl
case .RightCommand: return .RightSuper
case .RightShift: return .RightShift
case .RightOption: return .RightAlt
case .RightControl: return .RightControl
case .Function: return .Function
case .F17: return .F17
case .VolumeUp: return .VolumeUp
case .VolumeDown: return .VolumeDown
case .Mute: return .Mute
case .F18: return .F18
case .F19: return .F19
case .F20: return .F20
case .F5: return .F5
case .F6: return .F6
case .F7: return .F7
case .F3: return .F3
case .F8: return .F8
case .F9: return .F9
case .F11: return .F11
case .F13: return .F13
case .F16: return .F16
case .F14: return .F14
case .F10: return .F10
case .F12: return .F12
case .F15: return .F16
case .Help: return .Help
case .Home: return .Home
case .PageUp: return .PageUp
case .ForwardDelete: return .FwdDelete
case .F4: return .F4
case .End: return .End
case .F2: return .F2
case .PageDown: return .PageDown
case .F1: return .F1
case .LeftArrow: return .ArrowLeft
case .RightArrow: return .ArrowRight
case .DownArrow: return .ArrowDown
case .UpArrow: return .ArrowUp
case .JIS_Yen: return .None
case .JIS_Underscore: return .None
case .JIS_KeypadComma: return .None
case .JIS_Eisu: return .None
case .JIS_Kana: return .None
case .ISO_Section: return .None
}
return .None
}
open_file_dialog :: proc() -> (string, bool) {
panel := NS.OpenPanel.openPanel()
panel->setCanChooseFiles(true)
panel->setResolvesAliases(true)
panel->setCanChooseDirectories(false)
panel->setAllowsMultipleSelection(false)
if panel->runModal() == .OK {
urls := panel->URLs()
ret_count := urls->count()
if ret_count != 1 {
return "", false
}
url := urls->objectAs(0, ^NS.URL)
return strings.clone_from_cstring(url->fileSystemRepresentation()), true
}
return "", false
}
GFX_Context :: struct {
app: ^NS.Application,
window: ^NS.Window,
ctx: ^NS.OpenGLContext,
}
create_context :: proc(title: cstring, width, height: int) -> GFX_Context {
gfx := GFX_Context{}
frame_rect := NS.Rect{{0, 0}, {NS.Float(width), NS.Float(height)}}
app: ^NS.Application
window: ^NS.Window
{
app = NS.Application.sharedApplication()
app->setActivationPolicy(.Regular)
// auto-center window on main-screen
screen := NS.Screen_mainScreen()
screen_rect := screen->frame()
screen_width := screen_rect.size.width
screen_height := screen_rect.size.height
frame_rect.origin.x = NS.Float((f32(screen_rect.size.width) / 2) - (f32(width) / 2))
frame_rect.origin.y = NS.Float((f32(screen_rect.size.height) / 2) - (f32(height) / 2))
window = NS.Window_alloc()
window->initWithContentRect(frame_rect, {.Resizable, .Miniaturizable, .Closable, .Titled}, .Buffered, false, screen)
window->setTitle(NS.AT("Zxx"))
{
delegate := NS.window_delegate_register_and_alloc({
windowShouldClose = proc(^NS.Window) -> NS.BOOL {
running = false
return true
},
windowDidResize = proc(^NS.Notification) {
fmt.printf("resized!\n")
},
windowDidBecomeKey = proc(^NS.Notification) {
fmt.printf("Got focus\n")
},
windowDidResignKey = proc(^NS.Notification) {
fmt.printf("Lost focus\n")
},
}, "window_delegate", context)
window->setDelegate(delegate)
}
}
attrs := [?]NS.OpenGLPixelFormatAttribute{
NS.OpenGLPFAAccelerated, NS.OpenGLPFADoubleBuffer,
NS.OpenGLPFAOpenGLProfile, NS.OpenGLProfileVersion3_2Core,
NS.OpenGLPFAColorSize, 24,
NS.OpenGLPFAAlphaSize, 8,
NS.OpenGLPFADepthSize, 24,
NS.OpenGLPFAStencilSize, 8,
NS.OpenGLPFASampleBuffers, 0,
0,
}
gl_pixelfmt := NS.OpenGLPixelFormat_alloc()
gl_pixelfmt->initWithAttributes(raw_data(attrs[:]))
gl_view := NS.OpenGLView_alloc()
gl_view->initWithFrame(frame_rect, gl_pixelfmt)
gl_view->updateTrackingAreas()
gl_view->setWantsBestResolutionOpenGLSurface(true)
gl_ctx := gl_view->getOpenGLContext()
gl_ctx->makeCurrentContext()
swap_int : i32 = 1
gl_ctx->setValues(&swap_int, NS.OpenGLContextParameterSwapInterval)
window->setContentView(gl_view)
window->makeFirstResponder(gl_view)
window->makeKeyAndOrderFront(nil)
app->activateIgnoringOtherApps(true)
major_version := 3
minor_version := 3
gl.load_up_to(major_version, minor_version, NS.gl_set_proc_address)
gfx.app = app
gfx.window = window
gfx.ctx = gl_ctx
return gfx
}
get_next_event :: proc(gfx: ^GFX_Context, wait: bool) -> Event {
if !running {
return Event{type = .Exit}
}
timeout : ^NS.Date
if wait {
timeout = NS.Date_distantFuture()
}
event := gfx.app->nextEventMatchingMask(NS.EventMaskAny, timeout, NS.DefaultRunLoopMode, true)
if event == nil {
return Event{type = .None}
}
ev_type := event->type()
handled := false
defer { if !handled { gfx.app->sendEvent(event) } }
#partial switch ev_type {
case .LeftMouseDown: {
pos := event->locationInWindow()
return Event{type = .LeftMouseDown, x = f32(pos.x), y = f32(pos.y)}
}
case .LeftMouseUp: {
pos := event->locationInWindow()
return Event{type = .LeftMouseUp, x = f32(pos.x), y = f32(pos.y)}
}
case .MouseMoved: {
pos := event->locationInWindow()
return Event{type = .MouseMoved, x = f32(pos.x), y = f32(pos.y)}
}
case .ScrollWheel: {
dx, dy := event->scrollingDelta()
return Event{type = .Scroll, x = f32(dx), y = f32(dy)}
}
case .Magnify: {
pos := event->locationInWindow()
scale := event->deltaZ()
return Event{type = .Zoom, x = f32(pos.x), y = f32(pos.x), z = f32(scale)}
}
case .Rotate: {
pos := event->locationInWindow()
rot := event->deltaZ()
return Event{type = .Rotate, x = f32(pos.x), y = f32(pos.x), z = f32(rot)}
}
case .KeyDown: {
key_code := event->keyCode()
key := normalize_key(NS.kVK(key_code))
handled = true
return Event{type = .KeyDown, key = key}
}
case .KeyUp: {
key_code := event->keyCode()
key := normalize_key(NS.kVK(key_code))
return Event{type = .KeyUp, key = key}
}
case .FlagsChanged: {
key_code := event->keyCode()
key := normalize_key(NS.kVK(key_code))
flags := event->modifierFlags()
return Event{type = .KeyDown, key = key}
}
case .AppleEvent: {
ev_subtype := event->subtype()
if ev_subtype == -32768 {
return Event{type = .Exit}
}
return Event{type = .None}
}
case: {
return Event{type = .None}
}
}
}
swap_buffers :: proc(gfx: ^GFX_Context) {
gfx.ctx->flushBuffer()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment