You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
724 lines
32 KiB
724 lines
32 KiB
(set-cakelisp-option cakelisp-src-dir "Dependencies/cakelisp/src")
|
|
|
|
(add-cakelisp-search-directory "Dependencies/cakelisp/runtime")
|
|
(import "CHelpers.cake" "BuildTools.cake" "Dependencies.cake")
|
|
|
|
(export-and-evaluate
|
|
(c-import "SDL.h" "SDL_syswm.h"))
|
|
|
|
(c-import "<stdio.h>" &with-decls "<stddef.h>")
|
|
|
|
;;
|
|
;; Core/windowing
|
|
;;
|
|
|
|
(forward-declare (struct SDL_Window)
|
|
(struct SDL_AudioSpec))
|
|
|
|
(defun sdl-print-error ()
|
|
(fprintf stderr "SDL_Error: %s\n" (SDL_GetError)))
|
|
|
|
;; This supports drawing using SDL functions
|
|
(defun sdl-initialize-for-2d (window-out (* (* SDL_Window))
|
|
title (* (const char))
|
|
width int height int
|
|
&return bool)
|
|
(when (< (SDL_Init (bit-or SDL_INIT_VIDEO SDL_INIT_AUDIO SDL_INIT_TIMER)) 0)
|
|
(sdl-print-error)
|
|
(return false))
|
|
|
|
(set (deref window-out)
|
|
(SDL_CreateWindow title
|
|
SDL_WINDOWPOS_UNDEFINED SDL_WINDOWPOS_UNDEFINED
|
|
width height
|
|
(bit-or SDL_WINDOW_RESIZABLE)))
|
|
(unless (deref window-out)
|
|
(sdl-print-error)
|
|
(return false))
|
|
|
|
(return true))
|
|
|
|
;; This is the OpenGL version, which may not support SDL drawing functions, only OpenGL
|
|
(defun sdl-initialize-for-3d (window-out (* (* SDL_Window))
|
|
title (* (const char))
|
|
width int height int
|
|
&return bool)
|
|
(when (< (SDL_Init (bit-or SDL_INIT_VIDEO SDL_INIT_AUDIO SDL_INIT_TIMER)) 0)
|
|
(sdl-print-error)
|
|
(return false))
|
|
|
|
;; This is necessary to make sure the context is created using a newer version. I mainly did this
|
|
;; because RenderDoc said it needed it. This version comes from my current machine's version, and
|
|
;; isn't a requirement to be this high
|
|
(SDL_GL_SetAttribute SDL_GL_CONTEXT_MAJOR_VERSION 4)
|
|
(SDL_GL_SetAttribute SDL_GL_CONTEXT_MINOR_VERSION 6)
|
|
|
|
(set (deref window-out)
|
|
(SDL_CreateWindow title
|
|
SDL_WINDOWPOS_UNDEFINED SDL_WINDOWPOS_UNDEFINED width height
|
|
(bit-or SDL_WINDOW_RESIZABLE SDL_WINDOW_OPENGL)))
|
|
(unless (deref window-out)
|
|
(sdl-print-error)
|
|
(return false))
|
|
|
|
;; Must explicitly create the GL context for Ogre
|
|
(unless (SDL_GL_CreateContext (deref window-out))
|
|
(sdl-print-error)
|
|
(return false))
|
|
(return true))
|
|
|
|
(defun sdl-shutdown (window (* SDL_Window))
|
|
(SDL_DestroyWindow window)
|
|
(SDL_Quit))
|
|
|
|
;;
|
|
;; Graphics
|
|
;;
|
|
|
|
(defun sdl-list-2d-render-drivers (&return bool)
|
|
(var num-render-drivers int (SDL_GetNumRenderDrivers))
|
|
(unless num-render-drivers
|
|
(return false))
|
|
(var i int 0)
|
|
(each-in-range
|
|
num-render-drivers i
|
|
(var driver-info SDL_RendererInfo (array 0))
|
|
(unless (= 0 (SDL_GetRenderDriverInfo i (addr driver-info)))
|
|
(return false))
|
|
(SDL_Log "Renderer [%d]: %s\n
|
|
\tHardware accelerated: %s\n
|
|
\tRender to texture: %s\n
|
|
\tMax texture width: %d\n
|
|
\tMax texture height: %d\n
|
|
\n"
|
|
i (field driver-info name)
|
|
(? (bit-and (field driver-info flags) SDL_RENDERER_ACCELERATED) "yes" "no")
|
|
(? (bit-and (field driver-info flags) SDL_RENDERER_TARGETTEXTURE) "yes" "no")
|
|
(field driver-info max_texture_width)
|
|
(field driver-info max_texture_height)))
|
|
(return true))
|
|
|
|
(defun-local sdl-texture-from-bmp (filename (* (const char)) renderer (* SDL_Renderer)
|
|
&return (* SDL_Texture))
|
|
(var surface (* SDL_Surface) (SDL_LoadBMP filename))
|
|
(unless surface
|
|
(SDL_Log "Failed to load surface from BMP %s\n" filename)
|
|
(sdl-print-error)
|
|
(return null))
|
|
|
|
(var texture (* SDL_Texture)
|
|
(SDL_CreateTextureFromSurface renderer surface))
|
|
;; No need to hold on to surface after texture has been created
|
|
(SDL_FreeSurface surface)
|
|
(unless texture (sdl-print-error))
|
|
(return texture))
|
|
|
|
(defun-local sdl-texture-from-bmp-color-to-transparent
|
|
(filename (* (const char)) renderer (* SDL_Renderer) r char g char b char
|
|
&return (* SDL_Texture))
|
|
(var surface (* SDL_Surface) (SDL_LoadBMP filename))
|
|
(unless surface
|
|
(SDL_Log "Failed to load surface from BMP %s\n" filename)
|
|
(sdl-print-error)
|
|
(return null))
|
|
|
|
(SDL_SetColorKey surface SDL_TRUE (SDL_MapRGB (path surface > format) r g b))
|
|
|
|
(var texture (* SDL_Texture)
|
|
(SDL_CreateTextureFromSurface renderer surface))
|
|
;; No need to hold on to surface after texture has been created
|
|
(SDL_FreeSurface surface)
|
|
(unless texture (sdl-print-error))
|
|
(return texture))
|
|
|
|
;;
|
|
;; Audio
|
|
;;
|
|
|
|
;; Allocates both names and array
|
|
;; Returns number of devices in device-names-out
|
|
(defun sdl-audio-get-devices (device-names-out (* (* (* (const char))))
|
|
is-capture bool &return int)
|
|
(var num-devices int (SDL_GetNumAudioDevices is-capture))
|
|
(set (deref device-names-out) (type-cast
|
|
(calloc (sizeof (type (* (const char)))) num-devices)
|
|
(* (* (const char)))))
|
|
(fprintf stderr "Available %s devices:\n" (? is-capture "recording" "playback"))
|
|
(var i int 0)
|
|
(while (< i num-devices)
|
|
(var device-name (* (const char)) (SDL_GetAudioDeviceName i is-capture))
|
|
(when device-name
|
|
(fprintf stderr "\t[%d] %s\n" i device-name)
|
|
(set (at i (deref device-names-out)) (strdup device-name)))
|
|
(incr i))
|
|
(return num-devices))
|
|
|
|
(defun sdl-audio-list-specification (spec (* SDL_AudioSpec))
|
|
(fprintf stderr "freq: %d\n" (path spec > freq))
|
|
(fprintf stderr "format: %d\n" (path spec > format))
|
|
(fprintf stderr "channels: %d\n" (path spec > channels))
|
|
(fprintf stderr "samples: %d\n" (path spec > samples)))
|
|
|
|
(defun sdl-audio-free-device-list (device-names (* (* (const char))) num-devices int)
|
|
(var i int 0)
|
|
(while (< i num-devices)
|
|
(free (type-cast (at i device-names) (* void)))
|
|
(incr i))
|
|
(free device-names))
|
|
|
|
;;
|
|
;; Time
|
|
;;
|
|
|
|
;; Useful for getting a quick idea how long something takes, e.g.:
|
|
;; (var start-load-ticks (const Uint64) (SDL_GetPerformanceFrequency))
|
|
;; (do-load)
|
|
;; (sdl-print-time-delta start-load-ticks "Loading done")
|
|
;; ...Will print e.g. "--- Loading done at 0.94 seconds"
|
|
(defun-local sdl-print-time-delta (start-num-perf-ticks Uint64 label (* (const char)))
|
|
(var performance-num-ticks-per-second (const Uint64) (SDL_GetPerformanceFrequency))
|
|
|
|
(var current-counter-ticks Uint64 (SDL_GetPerformanceCounter))
|
|
(var frame-diff-ticks Uint64 (- current-counter-ticks start-num-perf-ticks))
|
|
(var delta-time float (/ frame-diff-ticks
|
|
(type-cast performance-num-ticks-per-second float)))
|
|
|
|
(SDL_Log "--- %s at %f seconds\n" label delta-time))
|
|
|
|
;; This should be thread-safe assuming set-startup-time-now is only called once
|
|
(var s-startup-num-perf-ticks Uint64 0)
|
|
|
|
(defun set-startup-time-now ()
|
|
(set s-startup-num-perf-ticks (SDL_GetPerformanceCounter)))
|
|
|
|
(defun get-time-since-startup (&return float)
|
|
(var performance-num-ticks-per-second (const Uint64) (SDL_GetPerformanceFrequency))
|
|
|
|
(var current-counter-ticks Uint64 (SDL_GetPerformanceCounter))
|
|
(var frame-diff-ticks Uint64 (- current-counter-ticks s-startup-num-perf-ticks))
|
|
(var delta-time float (/ frame-diff-ticks
|
|
(type-cast performance-num-ticks-per-second float)))
|
|
(return delta-time))
|
|
|
|
;;
|
|
;; Input
|
|
;;
|
|
|
|
(defun sdl-is-key-tapped-this-frame (key (unsigned int)
|
|
current-key-states (* (const (unsigned char)))
|
|
last-frame-key-states (* (const (unsigned char)))
|
|
&return bool)
|
|
(return (and key
|
|
(at key current-key-states)
|
|
(not (at key last-frame-key-states)))))
|
|
|
|
(defun sdl-scancode-to-user-string (code (unsigned int) &return (* (const char)))
|
|
;; TODO: Would be faster in switch, possibly
|
|
(cond
|
|
((= code SDL_SCANCODE_UNKNOWN) (return "Unknown"))
|
|
((= code SDL_SCANCODE_A) (return "A"))
|
|
((= code SDL_SCANCODE_B) (return "B"))
|
|
((= code SDL_SCANCODE_C) (return "C"))
|
|
((= code SDL_SCANCODE_D) (return "D"))
|
|
((= code SDL_SCANCODE_E) (return "E"))
|
|
((= code SDL_SCANCODE_F) (return "F"))
|
|
((= code SDL_SCANCODE_G) (return "G"))
|
|
((= code SDL_SCANCODE_H) (return "H"))
|
|
((= code SDL_SCANCODE_I) (return "I"))
|
|
((= code SDL_SCANCODE_J) (return "J"))
|
|
((= code SDL_SCANCODE_K) (return "K"))
|
|
((= code SDL_SCANCODE_L) (return "L"))
|
|
((= code SDL_SCANCODE_M) (return "M"))
|
|
((= code SDL_SCANCODE_N) (return "N"))
|
|
((= code SDL_SCANCODE_O) (return "O"))
|
|
((= code SDL_SCANCODE_P) (return "P"))
|
|
((= code SDL_SCANCODE_Q) (return "Q"))
|
|
((= code SDL_SCANCODE_R) (return "R"))
|
|
((= code SDL_SCANCODE_S) (return "S"))
|
|
((= code SDL_SCANCODE_T) (return "T"))
|
|
((= code SDL_SCANCODE_U) (return "U"))
|
|
((= code SDL_SCANCODE_V) (return "V"))
|
|
((= code SDL_SCANCODE_W) (return "W"))
|
|
((= code SDL_SCANCODE_X) (return "X"))
|
|
((= code SDL_SCANCODE_Y) (return "Y"))
|
|
((= code SDL_SCANCODE_Z) (return "Z"))
|
|
((= code SDL_SCANCODE_1) (return "1"))
|
|
((= code SDL_SCANCODE_2) (return "2"))
|
|
((= code SDL_SCANCODE_3) (return "3"))
|
|
((= code SDL_SCANCODE_4) (return "4"))
|
|
((= code SDL_SCANCODE_5) (return "5"))
|
|
((= code SDL_SCANCODE_6) (return "6"))
|
|
((= code SDL_SCANCODE_7) (return "7"))
|
|
((= code SDL_SCANCODE_8) (return "8"))
|
|
((= code SDL_SCANCODE_9) (return "9"))
|
|
((= code SDL_SCANCODE_0) (return "0"))
|
|
((= code SDL_SCANCODE_RETURN) (return "Return"))
|
|
((= code SDL_SCANCODE_ESCAPE) (return "Escape"))
|
|
((= code SDL_SCANCODE_BACKSPACE) (return "Backspace"))
|
|
((= code SDL_SCANCODE_TAB) (return "Tab"))
|
|
((= code SDL_SCANCODE_SPACE) (return "Space"))
|
|
((= code SDL_SCANCODE_MINUS) (return "Minus"))
|
|
((= code SDL_SCANCODE_EQUALS) (return "Equals"))
|
|
((= code SDL_SCANCODE_LEFTBRACKET) (return "["))
|
|
((= code SDL_SCANCODE_RIGHTBRACKET) (return "]"))
|
|
((= code SDL_SCANCODE_BACKSLASH) (return "Backslash"))
|
|
((= code SDL_SCANCODE_NONUSHASH) (return "NONUSHASH"))
|
|
((= code SDL_SCANCODE_SEMICOLON) (return ";"))
|
|
((= code SDL_SCANCODE_APOSTROPHE) (return "'"))
|
|
((= code SDL_SCANCODE_GRAVE) (return "`"))
|
|
((= code SDL_SCANCODE_COMMA) (return ","))
|
|
((= code SDL_SCANCODE_PERIOD) (return "."))
|
|
((= code SDL_SCANCODE_SLASH) (return "/"))
|
|
((= code SDL_SCANCODE_CAPSLOCK) (return "Capslock"))
|
|
((= code SDL_SCANCODE_F1) (return "F1"))
|
|
((= code SDL_SCANCODE_F2) (return "F2"))
|
|
((= code SDL_SCANCODE_F3) (return "F3"))
|
|
((= code SDL_SCANCODE_F4) (return "F4"))
|
|
((= code SDL_SCANCODE_F5) (return "F5"))
|
|
((= code SDL_SCANCODE_F6) (return "F6"))
|
|
((= code SDL_SCANCODE_F7) (return "F7"))
|
|
((= code SDL_SCANCODE_F8) (return "F8"))
|
|
((= code SDL_SCANCODE_F9) (return "F9"))
|
|
((= code SDL_SCANCODE_F10) (return "F10"))
|
|
((= code SDL_SCANCODE_F11) (return "F11"))
|
|
((= code SDL_SCANCODE_F12) (return "F12"))
|
|
((= code SDL_SCANCODE_PRINTSCREEN) (return "Print screen"))
|
|
((= code SDL_SCANCODE_SCROLLLOCK) (return "Scroll lock"))
|
|
((= code SDL_SCANCODE_PAUSE) (return "Pause"))
|
|
((= code SDL_SCANCODE_INSERT) (return "Insert"))
|
|
((= code SDL_SCANCODE_HOME) (return "Home"))
|
|
((= code SDL_SCANCODE_PAGEUP) (return "Page Up"))
|
|
((= code SDL_SCANCODE_DELETE) (return "Delete"))
|
|
((= code SDL_SCANCODE_END) (return "End"))
|
|
((= code SDL_SCANCODE_PAGEDOWN) (return "Page Down"))
|
|
((= code SDL_SCANCODE_RIGHT) (return "Right"))
|
|
((= code SDL_SCANCODE_LEFT) (return "Left"))
|
|
((= code SDL_SCANCODE_DOWN) (return "Down"))
|
|
((= code SDL_SCANCODE_UP) (return "Up"))
|
|
((= code SDL_SCANCODE_NUMLOCKCLEAR) (return "Num lock clear"))
|
|
((= code SDL_SCANCODE_KP_DIVIDE) (return "Keypad /"))
|
|
((= code SDL_SCANCODE_KP_MULTIPLY) (return "Keypad *"))
|
|
((= code SDL_SCANCODE_KP_MINUS) (return "Keypad -"))
|
|
((= code SDL_SCANCODE_KP_PLUS) (return "Keypad +"))
|
|
((= code SDL_SCANCODE_KP_ENTER) (return "Keypad Enter"))
|
|
((= code SDL_SCANCODE_KP_1) (return "Keypad 1"))
|
|
((= code SDL_SCANCODE_KP_2) (return "Keypad 2"))
|
|
((= code SDL_SCANCODE_KP_3) (return "Keypad 3"))
|
|
((= code SDL_SCANCODE_KP_4) (return "Keypad 4"))
|
|
((= code SDL_SCANCODE_KP_5) (return "Keypad 5"))
|
|
((= code SDL_SCANCODE_KP_6) (return "Keypad 6"))
|
|
((= code SDL_SCANCODE_KP_7) (return "Keypad 7"))
|
|
((= code SDL_SCANCODE_KP_8) (return "Keypad 8"))
|
|
((= code SDL_SCANCODE_KP_9) (return "Keypad 9"))
|
|
((= code SDL_SCANCODE_KP_0) (return "Keypad 0"))
|
|
((= code SDL_SCANCODE_KP_PERIOD) (return "Keypad ."))
|
|
((= code SDL_SCANCODE_NONUSBACKSLASH) (return "NONUSBACKSLASH"))
|
|
((= code SDL_SCANCODE_APPLICATION) (return "Application"))
|
|
((= code SDL_SCANCODE_POWER) (return "Power"))
|
|
((= code SDL_SCANCODE_KP_EQUALS) (return "Keypad ="))
|
|
((= code SDL_SCANCODE_F13) (return "F13"))
|
|
((= code SDL_SCANCODE_F14) (return "F14"))
|
|
((= code SDL_SCANCODE_F15) (return "F15"))
|
|
((= code SDL_SCANCODE_F16) (return "F16"))
|
|
((= code SDL_SCANCODE_F17) (return "F17"))
|
|
((= code SDL_SCANCODE_F18) (return "F18"))
|
|
((= code SDL_SCANCODE_F19) (return "F19"))
|
|
((= code SDL_SCANCODE_F20) (return "F20"))
|
|
((= code SDL_SCANCODE_F21) (return "F21"))
|
|
((= code SDL_SCANCODE_F22) (return "F22"))
|
|
((= code SDL_SCANCODE_F23) (return "F23"))
|
|
((= code SDL_SCANCODE_F24) (return "F24"))
|
|
((= code SDL_SCANCODE_EXECUTE) (return "Execute"))
|
|
((= code SDL_SCANCODE_HELP) (return "Help"))
|
|
((= code SDL_SCANCODE_MENU) (return "Menu"))
|
|
((= code SDL_SCANCODE_SELECT) (return "Select"))
|
|
((= code SDL_SCANCODE_STOP) (return "Stop"))
|
|
((= code SDL_SCANCODE_AGAIN) (return "Again"))
|
|
((= code SDL_SCANCODE_UNDO) (return "Undo"))
|
|
((= code SDL_SCANCODE_CUT) (return "Cut"))
|
|
((= code SDL_SCANCODE_COPY) (return "Copy"))
|
|
((= code SDL_SCANCODE_PASTE) (return "Paste"))
|
|
((= code SDL_SCANCODE_FIND) (return "Find"))
|
|
((= code SDL_SCANCODE_MUTE) (return "Mute"))
|
|
((= code SDL_SCANCODE_VOLUMEUP) (return "Volume Up"))
|
|
((= code SDL_SCANCODE_VOLUMEDOWN) (return "Volume Down"))
|
|
((= code SDL_SCANCODE_KP_COMMA) (return "Keypad ,"))
|
|
((= code SDL_SCANCODE_KP_EQUALSAS400) (return "Keypad EQUALSAS400"))
|
|
((= code SDL_SCANCODE_INTERNATIONAL1) (return "International1"))
|
|
((= code SDL_SCANCODE_INTERNATIONAL2) (return "International2"))
|
|
((= code SDL_SCANCODE_INTERNATIONAL3) (return "International3"))
|
|
((= code SDL_SCANCODE_INTERNATIONAL4) (return "International4"))
|
|
((= code SDL_SCANCODE_INTERNATIONAL5) (return "International5"))
|
|
((= code SDL_SCANCODE_INTERNATIONAL6) (return "International6"))
|
|
((= code SDL_SCANCODE_INTERNATIONAL7) (return "International7"))
|
|
((= code SDL_SCANCODE_INTERNATIONAL8) (return "International8"))
|
|
((= code SDL_SCANCODE_INTERNATIONAL9) (return "International9"))
|
|
((= code SDL_SCANCODE_LANG1) (return "Lang1"))
|
|
((= code SDL_SCANCODE_LANG2) (return "Lang2"))
|
|
((= code SDL_SCANCODE_LANG3) (return "Lang3"))
|
|
((= code SDL_SCANCODE_LANG4) (return "Lang4"))
|
|
((= code SDL_SCANCODE_LANG5) (return "Lang5"))
|
|
((= code SDL_SCANCODE_LANG6) (return "Lang6"))
|
|
((= code SDL_SCANCODE_LANG7) (return "Lang7"))
|
|
((= code SDL_SCANCODE_LANG8) (return "Lang8"))
|
|
((= code SDL_SCANCODE_LANG9) (return "Lang9"))
|
|
((= code SDL_SCANCODE_ALTERASE) (return "Alt erase"))
|
|
((= code SDL_SCANCODE_SYSREQ) (return "Sysreq"))
|
|
((= code SDL_SCANCODE_CANCEL) (return "Cancel"))
|
|
((= code SDL_SCANCODE_CLEAR) (return "Clear"))
|
|
((= code SDL_SCANCODE_PRIOR) (return "Prior"))
|
|
((= code SDL_SCANCODE_RETURN2) (return "Return2"))
|
|
((= code SDL_SCANCODE_SEPARATOR) (return "Separator"))
|
|
((= code SDL_SCANCODE_OUT) (return "Out"))
|
|
((= code SDL_SCANCODE_OPER) (return "Oper"))
|
|
((= code SDL_SCANCODE_CLEARAGAIN) (return "Clearagain"))
|
|
((= code SDL_SCANCODE_CRSEL) (return "Crsel"))
|
|
((= code SDL_SCANCODE_EXSEL) (return "Exsel"))
|
|
((= code SDL_SCANCODE_KP_00) (return "Keypad 00"))
|
|
((= code SDL_SCANCODE_KP_000) (return "Keypad 000"))
|
|
((= code SDL_SCANCODE_THOUSANDSSEPARATOR) (return "Thousands separator"))
|
|
((= code SDL_SCANCODE_DECIMALSEPARATOR) (return "Decimal separator"))
|
|
((= code SDL_SCANCODE_CURRENCYUNIT) (return "Currency unit"))
|
|
((= code SDL_SCANCODE_CURRENCYSUBUNIT) (return "Currency sub-unit"))
|
|
((= code SDL_SCANCODE_KP_LEFTPAREN) (return "Keypad ("))
|
|
((= code SDL_SCANCODE_KP_RIGHTPAREN) (return "Keypad )"))
|
|
((= code SDL_SCANCODE_KP_LEFTBRACE) (return "Keypad ["))
|
|
((= code SDL_SCANCODE_KP_RIGHTBRACE) (return "Keypad ]"))
|
|
((= code SDL_SCANCODE_KP_TAB) (return "Keypad Tab"))
|
|
((= code SDL_SCANCODE_KP_BACKSPACE) (return "Keypad Backspace"))
|
|
((= code SDL_SCANCODE_KP_A) (return "Keypad A"))
|
|
((= code SDL_SCANCODE_KP_B) (return "Keypad B"))
|
|
((= code SDL_SCANCODE_KP_C) (return "Keypad C"))
|
|
((= code SDL_SCANCODE_KP_D) (return "Keypad D"))
|
|
((= code SDL_SCANCODE_KP_E) (return "Keypad E"))
|
|
((= code SDL_SCANCODE_KP_F) (return "Keypad F"))
|
|
((= code SDL_SCANCODE_KP_XOR) (return "Keypad XOR"))
|
|
((= code SDL_SCANCODE_KP_POWER) (return "Keypad Power"))
|
|
((= code SDL_SCANCODE_KP_PERCENT) (return "Keypad %"))
|
|
((= code SDL_SCANCODE_KP_LESS) (return "Keypad <"))
|
|
((= code SDL_SCANCODE_KP_GREATER) (return "Keypad >"))
|
|
((= code SDL_SCANCODE_KP_AMPERSAND) (return "Keypad &"))
|
|
((= code SDL_SCANCODE_KP_DBLAMPERSAND) (return "Keypad &&"))
|
|
((= code SDL_SCANCODE_KP_VERTICALBAR) (return "Keypad |"))
|
|
((= code SDL_SCANCODE_KP_DBLVERTICALBAR) (return "Keypad ||"))
|
|
((= code SDL_SCANCODE_KP_COLON) (return "Keypad :"))
|
|
((= code SDL_SCANCODE_KP_HASH) (return "Keypad #"))
|
|
((= code SDL_SCANCODE_KP_SPACE) (return "Keypad Space"))
|
|
((= code SDL_SCANCODE_KP_AT) (return "Keypad At"))
|
|
((= code SDL_SCANCODE_KP_EXCLAM) (return "Keypad !"))
|
|
((= code SDL_SCANCODE_KP_MEMSTORE) (return "Keypad Mem store"))
|
|
((= code SDL_SCANCODE_KP_MEMRECALL) (return "Keypad Mem recall"))
|
|
((= code SDL_SCANCODE_KP_MEMCLEAR) (return "Keypad Mem clear"))
|
|
((= code SDL_SCANCODE_KP_MEMADD) (return "Keypad Mem add"))
|
|
((= code SDL_SCANCODE_KP_MEMSUBTRACT) (return "Keypad Mem subtract"))
|
|
((= code SDL_SCANCODE_KP_MEMMULTIPLY) (return "Keypad Mem multiply"))
|
|
((= code SDL_SCANCODE_KP_MEMDIVIDE) (return "Keypad Mem divide"))
|
|
((= code SDL_SCANCODE_KP_PLUSMINUS) (return "Keypad Plus/minus"))
|
|
((= code SDL_SCANCODE_KP_CLEAR) (return "Keypad Clear"))
|
|
((= code SDL_SCANCODE_KP_CLEARENTRY) (return "Keypad Clearentry"))
|
|
((= code SDL_SCANCODE_KP_BINARY) (return "Keypad Binary"))
|
|
((= code SDL_SCANCODE_KP_OCTAL) (return "Keypad Octal"))
|
|
((= code SDL_SCANCODE_KP_DECIMAL) (return "Keypad Decimal"))
|
|
((= code SDL_SCANCODE_KP_HEXADECIMAL) (return "Keypad Hexadecimal"))
|
|
((= code SDL_SCANCODE_LCTRL) (return "Left Ctrl"))
|
|
((= code SDL_SCANCODE_LSHIFT) (return "Left Shift"))
|
|
((= code SDL_SCANCODE_LALT) (return "Left Alt"))
|
|
((= code SDL_SCANCODE_LGUI) (return "Left GUI"))
|
|
((= code SDL_SCANCODE_RCTRL) (return "Right Ctrl"))
|
|
((= code SDL_SCANCODE_RSHIFT) (return "Right Shift"))
|
|
((= code SDL_SCANCODE_RALT) (return "Right Alt"))
|
|
((= code SDL_SCANCODE_RGUI) (return "Right GUI"))
|
|
((= code SDL_SCANCODE_MODE) (return "Mode"))
|
|
((= code SDL_SCANCODE_AUDIONEXT) (return "Audio next"))
|
|
((= code SDL_SCANCODE_AUDIOPREV) (return "Audio prev"))
|
|
((= code SDL_SCANCODE_AUDIOSTOP) (return "Audio stop"))
|
|
((= code SDL_SCANCODE_AUDIOPLAY) (return "Audio play"))
|
|
((= code SDL_SCANCODE_AUDIOMUTE) (return "Audio mute"))
|
|
((= code SDL_SCANCODE_MEDIASELECT) (return "Media select"))
|
|
((= code SDL_SCANCODE_WWW) (return "www"))
|
|
((= code SDL_SCANCODE_MAIL) (return "Mail"))
|
|
((= code SDL_SCANCODE_CALCULATOR) (return "Calculator"))
|
|
((= code SDL_SCANCODE_COMPUTER) (return "Computer"))
|
|
((= code SDL_SCANCODE_AC_SEARCH) (return "AC Search"))
|
|
((= code SDL_SCANCODE_AC_HOME) (return "AC Home"))
|
|
((= code SDL_SCANCODE_AC_BACK) (return "AC Back"))
|
|
((= code SDL_SCANCODE_AC_FORWARD) (return "AC Forward"))
|
|
((= code SDL_SCANCODE_AC_STOP) (return "AC Stop"))
|
|
((= code SDL_SCANCODE_AC_REFRESH) (return "AC Refresh"))
|
|
((= code SDL_SCANCODE_AC_BOOKMARKS) (return "AC Bookmarks"))
|
|
((= code SDL_SCANCODE_BRIGHTNESSDOWN) (return "Brightness down"))
|
|
((= code SDL_SCANCODE_BRIGHTNESSUP) (return "Brightness up"))
|
|
((= code SDL_SCANCODE_DISPLAYSWITCH) (return "Display switch"))
|
|
((= code SDL_SCANCODE_KBDILLUMTOGGLE) (return "Kbd illum toggle"))
|
|
((= code SDL_SCANCODE_KBDILLUMDOWN) (return "Kbd illum down"))
|
|
((= code SDL_SCANCODE_KBDILLUMUP) (return "Kbd illum up"))
|
|
((= code SDL_SCANCODE_EJECT) (return "Eject"))
|
|
((= code SDL_SCANCODE_SLEEP) (return "Sleep"))
|
|
((= code SDL_SCANCODE_APP1) (return "App1"))
|
|
((= code SDL_SCANCODE_APP2) (return "App2"))
|
|
((= code SDL_SCANCODE_AUDIOREWIND) (return "Audio rewind"))
|
|
((= code SDL_SCANCODE_AUDIOFASTFORWARD) (return "Audio fast-forward"))
|
|
(true
|
|
(return "Unknown"))))
|
|
|
|
;; TODO Cakelisp CHelpers support flags
|
|
(var-global keybind-modifier-flags-none (unsigned char) 0)
|
|
(var-global keybind-modifier-flags-ctrl (unsigned char) (bit-<< 1 0))
|
|
(var-global keybind-modifier-flags-shift (unsigned char) (bit-<< 1 1))
|
|
(var-global keybind-modifier-flags-alt (unsigned char) (bit-<< 1 2))
|
|
|
|
(defstruct keybind-key
|
|
key (unsigned int)
|
|
modifier-flags (unsigned char))
|
|
(defstruct keybind
|
|
bound-keys (* keybind-key)
|
|
num-binds (unsigned char))
|
|
|
|
(defstruct sdl-key-states
|
|
last-frame-states (* (const (unsigned char)))
|
|
this-frame-states (* (const (unsigned char))))
|
|
|
|
(defun keybind-tapped (keybinds (* keybind) key-states (* sdl-key-states) &return bool)
|
|
(each-in-range (path keybinds > num-binds) i
|
|
(var bind (* keybind-key) (addr (at i (path keybinds > bound-keys))))
|
|
(when (sdl-is-key-tapped-this-frame
|
|
(path bind > key)
|
|
(path key-states > this-frame-states)
|
|
(path key-states > last-frame-states))
|
|
(cond
|
|
((bit-and (path bind > modifier-flags) keybind-modifier-flags-ctrl)
|
|
(return (or (at SDL_SCANCODE_LCTRL (path key-states > this-frame-states))
|
|
(at SDL_SCANCODE_RCTRL (path key-states > this-frame-states)))))
|
|
((bit-and (path bind > modifier-flags) keybind-modifier-flags-shift)
|
|
(return (or (at SDL_SCANCODE_LSHIFT (path key-states > this-frame-states))
|
|
(at SDL_SCANCODE_RSHIFT (path key-states > this-frame-states)))))
|
|
((bit-and (path bind > modifier-flags) keybind-modifier-flags-alt)
|
|
(return (or (at SDL_SCANCODE_LALT (path key-states > this-frame-states))
|
|
(at SDL_SCANCODE_RALT (path key-states > this-frame-states)))))
|
|
(true
|
|
(return true)))))
|
|
(return false))
|
|
|
|
(defun-local append-to-string-buffer (buffer-out (* char) buffer-size size_t write-head (* (* char))
|
|
append-str (* (const char)))
|
|
(var str-length size_t (strlen append-str))
|
|
(when (> str-length (- buffer-size (- (deref write-head) buffer-out)))
|
|
(fprintf stderr "error: Buffer was not large enough to fit string! Buffer size: %d\n"
|
|
(type-cast buffer-size int))
|
|
(return))
|
|
(strcpy (deref write-head) append-str)
|
|
(set (deref write-head) (+ (deref write-head) str-length)))
|
|
|
|
(defun keybind-get-description (buffer-out (* char) buffer-size size_t keybinds (* keybind))
|
|
(set (at 0 buffer-out) 0)
|
|
(unless (path keybinds > num-binds)
|
|
(return))
|
|
(var write-head (* char) buffer-out)
|
|
(each-in-range (path keybinds > num-binds) i
|
|
(var bind (* keybind-key) (addr (at i (path keybinds > bound-keys))))
|
|
(defstruct flag-to-modifier flag (unsigned char) text (* (const char)))
|
|
(var flag-to-modifiers ([] (const flag-to-modifier))
|
|
(array (array keybind-modifier-flags-ctrl "Ctrl+")
|
|
(array keybind-modifier-flags-shift "Shift+")
|
|
(array keybind-modifier-flags-alt "Alt+")))
|
|
(each-in-array flag-to-modifiers modifier-index
|
|
(when (bit-and (path bind > modifier-flags)
|
|
(field (at modifier-index flag-to-modifiers) flag))
|
|
(append-to-string-buffer buffer-out buffer-size (addr write-head)
|
|
(field (at modifier-index flag-to-modifiers) text))))
|
|
(append-to-string-buffer buffer-out buffer-size (addr write-head)
|
|
(sdl-scancode-to-user-string (path bind > key)))
|
|
(when (< i (- (path keybinds > num-binds) 1))
|
|
(append-to-string-buffer buffer-out buffer-size (addr write-head)
|
|
", "))))
|
|
|
|
(defmacro define-keybind (name symbol &rest binds array)
|
|
(var buttons-name Token (deref name))
|
|
(call-on append (field buttons-name contents) "-buttons")
|
|
(tokenize-push output
|
|
(var (token-splice-addr buttons-name) ([] keybind-key)
|
|
(array (token-splice-rest binds tokens)))
|
|
(var (token-splice name) keybind (array (token-splice-addr buttons-name)
|
|
(array-size (token-splice-addr buttons-name)))))
|
|
(return true))
|
|
|
|
;;
|
|
;; Files
|
|
;;
|
|
|
|
(defun sdl-make-app-data-path (buffer (* char) buffer-size int
|
|
company (* (const char)) application (* (const char))
|
|
path (* (const char)))
|
|
(var pref-path (* char) (SDL_GetPrefPath company application))
|
|
(snprintf buffer buffer-size "%s%s" pref-path path)
|
|
(SDL_free pref-path))
|
|
|
|
;;
|
|
;; Test
|
|
;;
|
|
|
|
(defun test--sdl-main (&return int)
|
|
(fprintf stderr "Hello, SDL!\n")
|
|
(var window (* SDL_Window) null)
|
|
(unless (sdl-initialize-for-2d (addr window) "GameLib" 640 480) (return 1))
|
|
|
|
;; (var window-surface (* SDL_Surface) (SDL_GetWindowSurface window))
|
|
|
|
(var exit-reason (* (const char)) null)
|
|
(while (not exit-reason)
|
|
(var event SDL_Event)
|
|
(while (SDL_PollEvent (addr event))
|
|
(when (= (field event type) SDL_QUIT)
|
|
(set exit-reason "Window event")))
|
|
(var currentKeyStates (* (const Uint8)) (SDL_GetKeyboardState null))
|
|
(when (at SDL_SCANCODE_ESCAPE currentKeyStates)
|
|
(set exit-reason "Escape pressed"))
|
|
(SDL_UpdateWindowSurface window))
|
|
|
|
(when exit-reason
|
|
(fprintf stderr "Exiting. Reason: %s\n" exit-reason))
|
|
|
|
(sdl-shutdown window)
|
|
(return 0))
|
|
|
|
;;
|
|
;; Building
|
|
;;
|
|
|
|
(defun-comptime build-sdl-on-failure (failure-message (* (const char)))
|
|
(Logf "error: SDL build: %s\n
|
|
Note that you can also build SDL manually. This can be useful if you are porting to a new platform
|
|
and do not want to try to automate it yet.\n
|
|
The build step will automatically detect your build, as long as it is installed to
|
|
cakelisp_cache/SDLInstallDir/[include | lib].\n
|
|
See http://wiki.libsdl.org/Installation for how to build manually.\n"
|
|
failure-message))
|
|
|
|
;; TODO: Build into cakelisp_cache instead of dirtying Git repo
|
|
(defun-comptime build-sdl (manager (& ModuleManager) module (* Module) &return bool)
|
|
(comptime-cond
|
|
('Windows
|
|
(when (and (fileExists "Dependencies/SDL/include/SDL.h")
|
|
(fileExists "Dependencies/SDL/VisualC/x64/Debug/SDL2.dll"))
|
|
(return true))
|
|
|
|
;; Cakelisp's resolveExecutablePath() will find MSBuild for us
|
|
(var msbuild-path (* (const char)) "MSBuild.exe")
|
|
(var target-platform-version ([] 256 char) (array 0))
|
|
(makeTargetPlatformVersionArgument target-platform-version (sizeof target-platform-version))
|
|
(run-process-sequential-or
|
|
(msbuild-path
|
|
"Dependencies/SDL/VisualC/SDL.sln"
|
|
;; TODO: Debug vs release
|
|
;; TODO: Auto detect? Environment variables: WindowsSDKVersion
|
|
;;"/p:PlatformToolset=v142"
|
|
target-platform-version)
|
|
(build-sdl-on-failure
|
|
"failed at SDL build step. This requires Microsoft Visual Studio to execute.\nYou may also
|
|
need to edit SDL.cake and update the PlatformToolset and SDK versions for your environment.")
|
|
(return false))
|
|
|
|
(unless (and (fileExists "Dependencies/SDL/include/SDL.h")
|
|
(fileExists "Dependencies/SDL/VisualC/x64/Debug/SDL2.dll"))
|
|
(build-sdl-on-failure
|
|
"error: SDL build sequence completed, but files are not where expected. Is there an issue
|
|
with the configuration?")
|
|
(return false)))
|
|
|
|
('Unix
|
|
;; Already built?
|
|
;; We could enhance this by checking for modifications, but that's pretty rare
|
|
(when (and (fileExists "cakelisp_cache/SDLInstallDir/include/SDL2/SDL.h")
|
|
(fileExists "cakelisp_cache/SDLInstallDir/lib/libSDL2.a"))
|
|
(return true))
|
|
|
|
(Log "SDL: Building via Configure and Make\n")
|
|
|
|
(var sdl-working-dir (* (const char)) "cakelisp_cache/SDLBuildDir")
|
|
(makeDirectory sdl-working-dir)
|
|
|
|
(var sdl-output-dir (* (const char)) "cakelisp_cache/SDLInstallDir")
|
|
(makeDirectory sdl-output-dir)
|
|
|
|
(var configure-output-prefix ([] MAX_PATH_LENGTH char) (array 0))
|
|
(scope ;; Output must be absolute directory
|
|
(var absolute-output-path (* (const char))
|
|
(makeAbsolutePath_Allocated null sdl-output-dir))
|
|
|
|
(unless absolute-output-path
|
|
(Logf "error: failed to make SDL output directory '%s'\n" sdl-output-dir)
|
|
(return false))
|
|
|
|
(PrintfBuffer configure-output-prefix "--prefix=%s" absolute-output-path)
|
|
(free (type-cast absolute-output-path (* void))))
|
|
|
|
(run-process-sequential-or
|
|
("sh" "../../Dependencies/SDL/configure" configure-output-prefix :in-directory sdl-working-dir)
|
|
(build-sdl-on-failure
|
|
"failed at SDL configure step. This requires a sh/bash-style shell to execute.")
|
|
(return false))
|
|
|
|
(run-process-sequential-or
|
|
("make" "--jobs=8" :in-directory sdl-working-dir)
|
|
(build-sdl-on-failure "failed at SDL make. This tool requires Makefile support.")
|
|
(return false))
|
|
|
|
(run-process-sequential-or
|
|
("make" "install" :in-directory sdl-working-dir)
|
|
(build-sdl-on-failure
|
|
"failed at SDL make install. Was there a configuration issue with --prefix?")
|
|
(return false))
|
|
|
|
;; One final to check to ensure everything's good to go
|
|
(unless (and (fileExists "cakelisp_cache/SDLInstallDir/include/SDL2/SDL.h")
|
|
(fileExists "cakelisp_cache/SDLInstallDir/lib/libSDL2.a"))
|
|
(build-sdl-on-failure
|
|
"error: SDL build sequence completed, but files are not where expected. Is there an issue
|
|
with the configuration?\nFiles are expected in:\n\tcakelisp_cache/SDLInstallDir/include
|
|
\n\tcakelisp_cache/SDLInstallDir/lib")
|
|
(return false)))
|
|
(true
|
|
(comptime-error "need to define platform, e.g. (comptime-define-symbol 'Unix), or your platform
|
|
has not been implemented yet. See http://wiki.libsdl.org/Installation to add your platform.")))
|
|
|
|
(Log "SDL: Successfully built\n")
|
|
(return true))
|
|
|
|
(add-dependency-git-submodule clone-sdl2 "https://github.com/libsdl-org/SDL" "Dependencies/SDL")
|
|
(add-compile-time-hook-module pre-build build-sdl)
|
|
|
|
(export-and-evaluate
|
|
(comptime-cond
|
|
('Windows
|
|
(add-c-search-directory-module "Dependencies/SDL/include"))
|
|
('Unix
|
|
(add-c-search-directory-module "cakelisp_cache/SDLInstallDir/include/SDL2"))))
|
|
|
|
;; TODO: Add debug version
|
|
(comptime-cond
|
|
('Windows
|
|
(add-library-search-directory "Dependencies/SDL/VisualC/x64/Debug")
|
|
(add-static-link-objects "SDL2main.lib" "SDL2.lib"))
|
|
;; (add-library-runtime-search-directory "Dependencies/SDL/VisualC/x64/Debug" "."))
|
|
('Unix ;; Static link
|
|
(add-compiler-link-options "-pthread")
|
|
(comptime-cond
|
|
('SDL-Dynamic
|
|
(add-library-search-directory "cakelisp_cache/SDLInstallDir/lib")
|
|
(add-library-dependency "SDL2")
|
|
;; TODO: Relative path is going to break for sure
|
|
(add-library-runtime-search-directory "cakelisp_cache/SDLInstallDir/lib" "."))
|
|
(true
|
|
(add-static-link-objects "cakelisp_cache/SDLInstallDir/lib/libSDL2.a")))))
|
|
|
|
(comptime-cond
|
|
('Windows ;; DLLs need to be in the same directory as the executable
|
|
(defun-comptime copy-sdl2-dlls (manager (& ModuleManager) module (* Module) &return bool)
|
|
(unless (fileIsMoreRecentlyModified "Dependencies/SDL/VisualC/x64/Debug/SDL2.dll" "SDL2.dll")
|
|
(return true))
|
|
(Log "SDL: Copying DLLs to working directory\n")
|
|
(unless (copyBinaryFileTo "Dependencies/SDL/VisualC/x64/Debug/SDL2.dll" "SDL2.dll")
|
|
(Log "SDL: Failed to copy SDL2 dlls to working directory\n")
|
|
(return false))
|
|
(return true))
|
|
(add-compile-time-hook-module pre-build copy-sdl2-dlls)))
|
|
|