├── LICENSE ├── README.md ├── demo-sdl2 ├── SDL2.dll ├── atlas.odin ├── main.odin ├── renderer.odin └── sdl │ ├── SDL2.lib │ └── sdl.odin └── microui.odin /LICENSE: -------------------------------------------------------------------------------- 1 | Original work: Copyright (c) 2020 rxi 2 | Modified work: Copyright (c) 2020 oskarnp 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 | of the Software, and to permit persons to whom the Software is furnished to do 9 | so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Now part of official Odin vendor collection! https://github.com/odin-lang/Odin/tree/master/vendor/microui 2 | 3 | As a result of being included in the official vendor collection, this repo will no longer be maintained. Any issues or PRs is expected on the official vendor library from now on. 4 | 5 | Old README follows below. 6 | 7 | --- 8 | 9 | # microui-odin 10 | 11 | ## Description 12 | A tiny, portable, immediate-mode UI library written in Odin. (Ported from [rxi/microui](https://github.com/rxi/microui).) 13 | 14 | ![screenshot](https://user-images.githubusercontent.com/3920290/56437823-c3dcdb80-62d8-11e9-978a-a0739f9e16f0.png) 15 | 16 | [**Browser Demo**](https://floooh.github.io/sokol-html5/sgl-microui-sapp.html) (rxi's microui) 17 | 18 | ## Features 19 | * Tiny: around `1200 sloc` of Odin 20 | * Works within a fixed-sized memory region: no additional memory is 21 | allocated 22 | * Built-in controls: window, panel, button, slider, textbox, label, 23 | checkbox, wordwrapped text 24 | * Easy to add custom controls 25 | * Simple layout system 26 | 27 | ## Usage 28 | See the [`demo-sdl2`](demo-sdl2) directory for a usage example (using SDL2). 29 | ``` 30 | cd demo-sdl2 31 | odin run . 32 | ``` 33 | 34 | ## Notes 35 | * This library assumes you are using the latest nightly build or GitHub master of the Odin compiler. Since Odin is still under development this means this library might break in the future. Please create an issue or PR if that happens. Last verified against: odin version dev-2021-07:481fc8a5 36 | * The library expects the user to provide input and handle the resultant 37 | drawing commands, it does not do any drawing itself. 38 | 39 | ## License 40 | This library is free software; you can redistribute it and/or modify it 41 | under the terms of the MIT license. See [LICENSE](LICENSE) for details. 42 | 43 | -------------------------------------------------------------------------------- /demo-sdl2/SDL2.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oskarnp/microui-odin/1180e3c608aeabe217bff0f3fabd600d39be6e18/demo-sdl2/SDL2.dll -------------------------------------------------------------------------------- /demo-sdl2/main.odin: -------------------------------------------------------------------------------- 1 | package microui_demo 2 | 3 | import "sdl" 4 | import mu "../" 5 | 6 | import "core:fmt" 7 | import "core:log" 8 | import "core:time" 9 | import "core:reflect" 10 | import "core:strings" 11 | 12 | bg: [3]u8 = { 90, 95, 100 }; 13 | frame_stats: Frame_Stats; 14 | 15 | logbuf: strings.Builder; 16 | logbuf_updated: bool; 17 | 18 | Frame_Stats :: struct { 19 | samples: [100] time.Duration, 20 | sample_index: int, 21 | sample_sum: time.Duration, 22 | mspf, fps: f64, 23 | last_update: time.Time, 24 | } 25 | 26 | init_frame_stats :: proc(using _: ^Frame_Stats) { 27 | now := time.now(); 28 | last_update = now; 29 | } 30 | 31 | update_frame_stats :: proc(using _: ^Frame_Stats) { 32 | now := time.now(); 33 | dt := time.diff(last_update, now); 34 | last_update = now; 35 | 36 | sample_sum -= samples[sample_index]; 37 | samples[sample_index] = dt; 38 | sample_sum += dt; 39 | sample_index = (sample_index + 1) % len(samples); 40 | 41 | fps = len(samples) / time.duration_seconds(sample_sum); 42 | mspf = 1000.0 * time.duration_seconds(sample_sum) / len(samples); 43 | } 44 | 45 | main :: proc() { 46 | context.logger = log.create_console_logger(ident = "demo"); 47 | 48 | logbuf = strings.make_builder(); 49 | 50 | /* init SDL and renderer */ 51 | if err := sdl.init(.Video); err != 0 { 52 | log.error("init(): ", sdl.get_error()); 53 | return; 54 | } 55 | if ok := r_init(); !ok { 56 | return; 57 | } 58 | 59 | /* init microui */ 60 | ctx := new(mu.Context); 61 | defer free(ctx); 62 | mu.init(ctx); 63 | 64 | text_width :: #force_inline proc(font: mu.Font, text: string) -> i32 do return r_get_text_width(text); 65 | text_height :: #force_inline proc(font: mu.Font) -> i32 do return r_get_text_height(); 66 | ctx.text_width = text_width; 67 | ctx.text_height = text_height; 68 | 69 | init_frame_stats(&frame_stats); 70 | main_loop: for { 71 | /* handle SDL events */ 72 | e: sdl.Event = ---; 73 | for sdl.poll_event(&e) != 0 { 74 | #partial switch e.type { 75 | case .Quit: break main_loop; 76 | case .Mouse_Motion: mu.input_mousemove(ctx, e.motion.x, e.motion.y); 77 | case .Mouse_Wheel: mu.input_scroll(ctx, 0, e.wheel.y * -30); 78 | case .Text_Input: mu.input_text(ctx, string(cstring(&e.text.text[0]))); 79 | 80 | case .Mouse_Button_Down, .Mouse_Button_Up: 81 | button_map :: #force_inline proc(button: u8) -> (res: mu.Mouse, ok: bool) { 82 | ok = true; 83 | switch button { 84 | case 1: res = .LEFT; 85 | case 2: res = .MIDDLE; 86 | case 3: res = .RIGHT; 87 | case: ok = false; 88 | } 89 | return; 90 | } 91 | if btn, ok := button_map(e.button.button); ok { 92 | switch { 93 | case e.type == .Mouse_Button_Down: mu.input_mousedown(ctx, e.button.x, e.button.y, btn); 94 | case e.type == .Mouse_Button_Up: mu.input_mouseup(ctx, e.button.x, e.button.y, btn); 95 | } 96 | } 97 | 98 | case .Key_Down, .Key_Up: 99 | if e.type == .Key_Up && e.key.keysym.sym == sdl.SDLK_ESCAPE { 100 | quit_event: sdl.Event; 101 | quit_event.type = .Quit; 102 | sdl.push_event(&quit_event); 103 | } 104 | 105 | key_map :: #force_inline proc(x: i32) -> (res: mu.Key, ok: bool) { 106 | ok = true; 107 | switch x { 108 | case cast(i32)sdl.SDLK_LSHIFT: res = .SHIFT; 109 | case cast(i32)sdl.SDLK_RSHIFT: res = .SHIFT; 110 | case cast(i32)sdl.SDLK_LCTRL: res = .CTRL; 111 | case cast(i32)sdl.SDLK_RCTRL: res = .CTRL; 112 | case cast(i32)sdl.SDLK_LALT: res = .ALT; 113 | case cast(i32)sdl.SDLK_RALT: res = .ALT; 114 | case cast(i32)sdl.SDLK_RETURN: res = .RETURN; 115 | case cast(i32)sdl.SDLK_BACKSPACE: res = .BACKSPACE; 116 | case: ok = false; 117 | } 118 | return; 119 | } 120 | if key, ok := key_map(e.key.keysym.sym); ok { 121 | switch { 122 | case e.type == .Key_Down: mu.input_keydown(ctx, key); 123 | case e.type == .Key_Up: mu.input_keyup(ctx, key); 124 | } 125 | } 126 | } 127 | } 128 | 129 | /* process frame */ 130 | process_frame(ctx); 131 | 132 | /* render */ 133 | r_clear(mu.Color{bg[0], bg[1], bg[2], 255}); 134 | cmd: ^mu.Command; 135 | for mu.next_command(ctx, &cmd) { 136 | switch cmd.type { 137 | case .TEXT: r_draw_text(cmd.text.str, cmd.text.pos, cmd.text.color); 138 | case .RECT: r_draw_rect(cmd.rect.rect, cmd.rect.color); 139 | case .ICON: r_draw_icon(cmd.icon.id, cmd.icon.rect, cmd.icon.color); 140 | case .CLIP: r_set_clip_rect(cmd.clip.rect); 141 | case .JUMP: unreachable(); /* handled internally by next_command() */ 142 | } 143 | } 144 | 145 | //r_test(); 146 | 147 | r_present(); 148 | 149 | update_frame_stats(&frame_stats); 150 | } // main_loop 151 | 152 | sdl.quit(); 153 | } 154 | 155 | process_frame :: proc(ctx: ^mu.Context) { 156 | mu.begin(ctx); 157 | test_window(ctx); 158 | log_window(ctx); 159 | style_window(ctx); 160 | mu.end(ctx); 161 | } 162 | 163 | test_window :: proc(ctx: ^mu.Context) { 164 | @static opts: mu.Opt_Bits; 165 | 166 | // NOTE(oskar): mu.button() returns Res_Bits and not bool (should fix this) 167 | button :: #force_inline proc(ctx: ^mu.Context, label: string) -> bool do return mu.button(ctx, label) == {.SUBMIT}; 168 | 169 | /* do window */ 170 | if mu.begin_window(ctx, "Demo Window", {40,40,300,450}, opts) { 171 | if mu.header(ctx, "Frame Stats") != {} { 172 | mu.layout_row(ctx, 1, []i32{-1}, 0); 173 | mu.text(ctx, fmt.tprintf("FPS %v MSPF %v", frame_stats.fps, frame_stats.mspf)); 174 | } 175 | 176 | if mu.header(ctx, "Window Options") != {} { 177 | win := mu.get_current_container(ctx); 178 | mu.layout_row(ctx, 3, []i32{120, 120, 120}, 0); 179 | for opt in mu.Opt { 180 | state: bool = opt in opts; 181 | if mu.checkbox(ctx, fmt.tprintf("%v", opt), &state) != {} { 182 | if state { 183 | opts |= {opt}; 184 | } 185 | else { 186 | opts &~= {opt}; 187 | } 188 | } 189 | } 190 | } 191 | 192 | /* window info */ 193 | if mu.header(ctx, "Window Info") != {} { 194 | win := mu.get_current_container(ctx); 195 | mu.layout_row(ctx, 2, []i32{ 54, -1 }, 0); 196 | mu.label(ctx, "Position:"); 197 | mu.label(ctx, fmt.tprintf("%d, %d", win.rect.x, win.rect.y)); 198 | mu.label(ctx, "Size:"); 199 | mu.label(ctx, fmt.tprintf("%d, %d", win.rect.w, win.rect.h)); 200 | } 201 | 202 | /* labels + buttons */ 203 | if mu.header(ctx, "Test Buttons", {.EXPANDED}) != {} { 204 | mu.layout_row(ctx, 3, []i32{ 86, -110, -1 }, 0); 205 | mu.label(ctx, "Test buttons 1:"); 206 | if button(ctx, "Button 1") do write_log("Pressed button 1"); 207 | if button(ctx, "Button 2") do write_log("Pressed button 2"); 208 | mu.label(ctx, "Test buttons 2:"); 209 | if button(ctx, "Button 3") do write_log("Pressed button 3"); 210 | if button(ctx, "Button 4") do write_log("Pressed button 4"); 211 | } 212 | 213 | /* tree */ 214 | if mu.header(ctx, "Tree and Text", {.EXPANDED}) != {} { 215 | mu.layout_row(ctx, 2, []i32{ 140, -1 }, 0); 216 | mu.layout_begin_column(ctx); 217 | if mu.begin_treenode(ctx, "Test 1") != {} { 218 | if mu.begin_treenode(ctx, "Test 1a") != {} { 219 | mu.label(ctx, "Hello"); 220 | mu.label(ctx, "world"); 221 | mu.end_treenode(ctx); 222 | } 223 | if mu.begin_treenode(ctx, "Test 1b") != {} { 224 | if button(ctx, "Button 1") do write_log("Pressed button 1"); 225 | if button(ctx, "Button 2") do write_log("Pressed button 2"); 226 | mu.end_treenode(ctx); 227 | } 228 | mu.end_treenode(ctx); 229 | } 230 | if mu.begin_treenode(ctx, "Test 2") != {} { 231 | mu.layout_row(ctx, 2, []i32{ 54, 54 }, 0); 232 | if button(ctx, "Button 3") do write_log("Pressed button 3"); 233 | if button(ctx, "Button 4") do write_log("Pressed button 4"); 234 | if button(ctx, "Button 5") do write_log("Pressed button 5"); 235 | if button(ctx, "Button 6") do write_log("Pressed button 6"); 236 | mu.end_treenode(ctx); 237 | } 238 | if mu.begin_treenode(ctx, "Test 3") != {} { 239 | @static checks := [3]bool{ true, false, true }; 240 | mu.checkbox(ctx, "Checkbox 1", &checks[0]); 241 | mu.checkbox(ctx, "Checkbox 2", &checks[1]); 242 | mu.checkbox(ctx, "Checkbox 3", &checks[2]); 243 | mu.end_treenode(ctx); 244 | } 245 | mu.layout_end_column(ctx); 246 | 247 | mu.layout_begin_column(ctx); 248 | mu.layout_row(ctx, 1, []i32{ -1 }, 0); 249 | mu.text(ctx, "Lorem ipsum\n dolor sit amet, consectetur adipiscing elit. Maecenas lacinia, sem eu lacinia molestie, mi risus faucibus ipsum, eu varius magna felis a nulla."); 250 | mu.layout_end_column(ctx); 251 | } 252 | 253 | /* background color sliders */ 254 | if mu.header(ctx, "Background Color", {.EXPANDED}) != {} { 255 | mu.layout_row(ctx, 2, []i32{ -78, -1 }, 74); 256 | /* sliders */ 257 | mu.layout_begin_column(ctx); 258 | mu.layout_row(ctx, 2, []i32{ 46, -1 }, 0); 259 | mu.label(ctx, "Red:"); uint8_slider(ctx, &bg[0], 0, 255); 260 | mu.label(ctx, "Green:"); uint8_slider(ctx, &bg[1], 0, 255); 261 | mu.label(ctx, "Blue:"); uint8_slider(ctx, &bg[2], 0, 255); 262 | mu.layout_end_column(ctx); 263 | /* color preview */ 264 | r := mu.layout_next(ctx); 265 | mu.draw_rect(ctx, r, mu.Color{bg[0], bg[1], bg[2], 255}); 266 | mu.draw_control_text(ctx, fmt.tprintf("#%02X%02X%02X", bg[0], bg[1], bg[2]), r, .TEXT, {.ALIGNCENTER}); 267 | } 268 | 269 | mu.end_window(ctx); 270 | } 271 | } 272 | 273 | @private uint8_slider :: proc(ctx: ^mu.Context, value: ^u8, low, high: int) -> (res: mu.Res_Bits) { 274 | using mu; 275 | @static tmp: Real; 276 | push_id(ctx, uintptr(value)); 277 | tmp = Real(value^); 278 | res = slider(ctx, &tmp, Real(low), Real(high), 0, "%.0f", {.ALIGNCENTER}); 279 | value^ = u8(tmp); 280 | pop_id(ctx); 281 | return; 282 | } 283 | 284 | 285 | @private write_log :: proc(text: string) { 286 | strings.write_string(&logbuf, text); 287 | strings.write_string(&logbuf, "\n"); 288 | logbuf_updated = true; 289 | } 290 | 291 | @private log_window :: proc(ctx: ^mu.Context) { 292 | using mu; 293 | 294 | if begin_window(ctx, "Log Window", Rect{350,40,300,200}) { 295 | /* output text panel */ 296 | layout_row(ctx, 1, { -1 }, -28); 297 | begin_panel(ctx, "Log Output"); 298 | panel := get_current_container(ctx); 299 | layout_row(ctx, 1, { -1 }, -1); 300 | text(ctx, strings.to_string(logbuf)); 301 | end_panel(ctx); 302 | if logbuf_updated { 303 | panel.scroll.y = panel.content_size.y; 304 | logbuf_updated = false; 305 | } 306 | 307 | /* input textbox + submit button */ 308 | @static textlen: int; 309 | @static textbuf: [128] byte; 310 | submitted := false; 311 | layout_row(ctx, 2, { -70, -1 }, 0); 312 | if .SUBMIT in textbox(ctx, textbuf[:], &textlen) { 313 | set_focus(ctx, ctx.last_id); 314 | submitted = true; 315 | } 316 | if button(ctx, "Submit") != {} do submitted = true; 317 | if submitted { 318 | textstr := string(textbuf[:textlen]); 319 | write_log(textstr); 320 | textlen = 0; 321 | } 322 | 323 | end_window(ctx); 324 | } 325 | } 326 | 327 | @private style_window :: proc(ctx: ^mu.Context) { 328 | using mu; 329 | 330 | if begin_window(ctx, "Style Editor", Rect{350,250,300,240}) { 331 | sw := i32(Real(get_current_container(ctx).body.w) * 0.14); 332 | layout_row(ctx, 6, { 80, sw, sw, sw, sw, -1 }, 0); 333 | for c in Color_Type { 334 | label(ctx, fmt.tprintf("%s:", reflect.enum_string(c))); 335 | uint8_slider(ctx, &ctx.style.colors[c].r, 0, 255); 336 | uint8_slider(ctx, &ctx.style.colors[c].g, 0, 255); 337 | uint8_slider(ctx, &ctx.style.colors[c].b, 0, 255); 338 | uint8_slider(ctx, &ctx.style.colors[c].a, 0, 255); 339 | draw_rect(ctx, layout_next(ctx), ctx.style.colors[c]); 340 | } 341 | end_window(ctx); 342 | } 343 | } 344 | -------------------------------------------------------------------------------- /demo-sdl2/renderer.odin: -------------------------------------------------------------------------------- 1 | package microui_demo 2 | 3 | import "sdl" 4 | import mu "../" 5 | 6 | import "core:mem" 7 | import "core:log" 8 | 9 | window: ^sdl.Window; 10 | renderer: ^sdl.Renderer; 11 | atlas_texture: ^sdl.Texture; 12 | 13 | width: i32 = 800; 14 | height: i32 = 600; 15 | 16 | @(private="file") 17 | logger: log.Logger = log.create_console_logger(ident = "renderer"); 18 | 19 | r_test :: proc() { 20 | WHITE :: mu.Color{255,255,255,255}; 21 | BLACK :: mu.Color{0,0,0,255}; 22 | MAGENTA :: mu.Color{255,0,255,255}; 23 | 24 | context.logger = logger; 25 | 26 | r_clear(MAGENTA); 27 | r_set_clip_rect({0,0,160,height}); 28 | r_draw_rect({100,100,100,100}, BLACK); 29 | r_draw_rect({100+2,100+2,100-4,100-4}, WHITE); 30 | r_draw_icon(.EXPANDED, {100,100,100,100}, BLACK); 31 | r_draw_text("Hellope", {0,0}, WHITE); 32 | } 33 | 34 | r_init :: proc() -> (ok: bool) { 35 | context.logger = logger; 36 | 37 | window = sdl.create_window(title = "microui-odin", x = cast(i32) sdl.Window_Pos.Undefined, y = cast(i32) sdl.Window_Pos.Undefined, w = width, h = height, flags = .Shown | .Resizable); 38 | if window == nil { 39 | log.error("create_window(): ", sdl.get_error()); 40 | return false; 41 | } 42 | 43 | log.info("================================================================================"); 44 | log.info("Querying available render drivers"); 45 | 46 | if n := sdl.get_num_render_drivers(); n <= 0 { 47 | log.error("No render drivers available"); 48 | return false; 49 | } else do for i in 0.. (res: i32) { 131 | for ch in text { 132 | if ch&0xc0 == 0x80 do continue; 133 | chr := min(int(ch), 127); 134 | res += atlas[ATLAS_FONT + chr].w; 135 | } 136 | return; 137 | } 138 | 139 | r_get_text_height :: proc() -> i32 { 140 | return 18; 141 | } 142 | 143 | r_clear :: proc(using color: mu.Color) { 144 | sdl.set_render_draw_color(renderer, r, g, b, a); 145 | sdl.render_clear(renderer); 146 | } 147 | 148 | r_present :: proc() { 149 | sdl.render_present(renderer); 150 | } 151 | 152 | @(private="file") 153 | atlas_quad :: proc(dst, src: mu.Rect, using color: mu.Color) { 154 | src := transmute(sdl.Rect) src; 155 | dst := transmute(sdl.Rect) dst; 156 | sdl.set_texture_alpha_mod(atlas_texture, a); 157 | sdl.set_texture_color_mod(atlas_texture, r, g, b); 158 | sdl.render_copy(renderer, atlas_texture, &src, &dst); 159 | } 160 | -------------------------------------------------------------------------------- /demo-sdl2/sdl/SDL2.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oskarnp/microui-odin/1180e3c608aeabe217bff0f3fabd600d39be6e18/demo-sdl2/sdl/SDL2.lib -------------------------------------------------------------------------------- /demo-sdl2/sdl/sdl.odin: -------------------------------------------------------------------------------- 1 | package sdl 2 | 3 | import "core:os" 4 | 5 | when os.OS == "windows" do foreign import lib "SDL2.lib"; 6 | when os.OS == "linux" do foreign import lib "system:SDL2"; 7 | when os.OS == "darwin" do foreign import lib "system:SDL2"; 8 | 9 | @(default_calling_convention="c") 10 | foreign lib { 11 | // This one is missing from my source of SDL2 ??? 12 | //@(link_name="SDL_DYNAPI_entry") // dynapi_entry :: proc() -> ---; 13 | 14 | // The source for this one says you should never call it directly, but rather use the macros provided. Need to port those over still 15 | //@(link_name="SDL_ReportAssertion") //report_assertion :: proc() -> ---; 16 | 17 | @(link_name="SDL_AddEventWatch") add_event_watch :: proc(filter: Event_Filter, userdata: rawptr) ---; 18 | @(link_name="SDL_AddHintCallback") add_hint_callback :: proc(name: cstring, callback: Hint_Callback, userdata: rawptr) ---; 19 | @(link_name="SDL_AddTimer") add_timer :: proc(interval: u32, callback: Timer_Callback, param: rawptr) -> Timer_Id ---; 20 | @(link_name="SDL_AllocFormat") alloc_format :: proc(pixel_format: u32) -> ^Pixel_Format ---; 21 | @(link_name="SDL_AllocPalette") alloc_palette :: proc(ncolors: i32) -> ^Palette ---; 22 | @(link_name="SDL_AllocRW") alloc_rw :: proc() -> ^Rw_Ops ---; 23 | @(link_name="SDL_AtomicAdd") atomic_add :: proc(a: ^Atomic, v: i32) -> i32 ---; 24 | @(link_name="SDL_AtomicCAS") atomic_cas :: proc(a: ^Atomic, oldval: i32, newval: i32) -> Bool ---; 25 | @(link_name="SDL_AtomicCASPtr") atomic_cas_ptr :: proc(a: ^rawptr, oldval: rawptr, newval: rawptr) -> Bool ---; 26 | @(link_name="SDL_AtomicGet") atomic_get :: proc(a: ^Atomic) -> i32 ---; 27 | @(link_name="SDL_AtomicGetPtr") atomic_get_ptr :: proc(a: ^rawptr) -> rawptr ---; 28 | @(link_name="SDL_AtomicLock") atomic_lock :: proc(lock: ^Spin_Lock) ---; 29 | @(link_name="SDL_AtomicSet") atomic_set :: proc(a: ^Atomic, v: i32) -> i32 ---; 30 | @(link_name="SDL_AtomicSetPtr") atomic_set_ptr :: proc(a: ^rawptr, v: rawptr) -> rawptr ---; 31 | @(link_name="SDL_AtomicTryLock") atomic_try_lock :: proc(lock: ^Spin_Lock) -> Bool ---; 32 | @(link_name="SDL_AtomicUnlock") atomic_unlock :: proc(lock: ^Spin_Lock) ---; 33 | @(link_name="SDL_AudioInit") audio_init :: proc(driver_name: cstring) -> i32 ---; 34 | @(link_name="SDL_AudioQuit") audio_quit :: proc() ---; 35 | @(link_name="SDL_BuildAudioCVT") build_audio_cvt :: proc(cvt: ^Audio_Cvt, src_format: Audio_Format, src_channels: u8, src_rate: i32, dst_format: Audio_Format, dst_channels: u8, dst_rate: i32) -> i32 ---; 36 | @(link_name="SDL_CalculateGammaRamp") calculate_gamma_ramp :: proc(gamma: f32, ramp: ^u16) ---; 37 | @(link_name="SDL_CaptureMouse") capture_mouse :: proc(enabled: Bool) -> i32 ---; 38 | @(link_name="SDL_ClearError") clear_error :: proc() ---; 39 | @(link_name="SDL_ClearHints") clear_hints :: proc() ---; 40 | @(link_name="SDL_ClearQueuedAudio") clear_queued_audio :: proc(dev: Audio_Device) ---; 41 | @(link_name="SDL_CloseAudio") close_audio :: proc() ---; 42 | @(link_name="SDL_CloseAudioDevice") close_audio_device :: proc(dev: Audio_Device) ---; 43 | @(link_name="SDL_CondBroadcast") cond_broadcast :: proc(cond: ^Cond) -> i32 ---; 44 | @(link_name="SDL_CondSignal") cond_signal :: proc(cond: ^Cond) -> i32 ---; 45 | @(link_name="SDL_CondWait") cond_wait :: proc(cond: ^Cond, mutex: ^Mutex) -> i32 ---; 46 | @(link_name="SDL_CondWaitTimeout") cond_wait_timeout :: proc(cond: ^Cond, mutex: ^Mutex, ms: u32) -> i32 ---; 47 | @(link_name="SDL_ConvertAudio") convert_audio :: proc(cvt: ^Audio_Cvt) -> i32 ---; 48 | @(link_name="SDL_ConvertPixels") convert_pixels :: proc(width: i32, height: i32, src_format: u32, src: rawptr, src_pitch: i32, dst_format: u32, dst: rawptr, dst_pitch: i32) -> i32 ---; 49 | @(link_name="SDL_ConvertSurface") convert_surface :: proc(src: ^Surface, fmt: ^Pixel_Format, flags: u32) -> ^Surface ---; 50 | @(link_name="SDL_ConvertSurfaceFormat") convert_surface_format :: proc(src: ^Surface, pixel_format: u32, flags: u32) -> ^Surface ---; 51 | @(link_name="SDL_CreateColorCursor") create_color_cursor :: proc(surface: ^Surface, hot_x, hot_y: i32) -> ^Cursor ---; 52 | @(link_name="SDL_CreateCond") create_cond :: proc() -> ^Cond ---; 53 | @(link_name="SDL_CreateCursor") create_cursor :: proc(data: ^u8, mask: ^u8, w, h: i32, hot_x, hot_y: i32) -> ^Cursor ---; 54 | @(link_name="SDL_CreateMutex") create_mutex :: proc() -> ^Mutex ---; 55 | @(link_name="SDL_CreateRGBSurface") create_rgb_surface :: proc(flags: u32, width, height, depth: i32, Rmask, Gmask, Bmask, Amask: u32) -> ^Surface ---; 56 | @(link_name="SDL_CreateRGBSurfaceFrom") create_rgb_surface_from :: proc(pixels: rawptr, width, height, depth, pitch: i32, Rmask, Gmask, Bmask, Amask: u32) -> ^Surface ---; 57 | @(link_name="SDL_CreateRGBSurfaceWithFormat") create_rgb_surface_with_format :: proc(flags: u32, width, height, depth: i32, format: u32) -> ^Surface ---; 58 | @(link_name="SDL_CreateRGBSurfaceWithFormatFrom") create_rgb_surface_with_format_from :: proc(pixels: rawptr, width, height, depth, pitch: i32, format: u32) -> ^Surface ---; 59 | @(link_name="SDL_CreateRenderer") create_renderer :: proc(window: ^Window, index: i32, flags: Renderer_Flags) -> ^Renderer ---; 60 | @(link_name="SDL_CreateSemaphore") create_semaphore :: proc(initial_value: u32) -> ^Sem ---; 61 | @(link_name="SDL_CreateShapedWindow") create_shaped_window :: proc(title: cstring, x, y, w, h: u32, flags: Window_Flags) -> ^Window ---; 62 | @(link_name="SDL_CreateSoftwareRenderer") create_software_renderer :: proc(surface: ^Surface) -> ^Renderer ---; 63 | @(link_name="SDL_CreateSystemCursor") create_system_cursor :: proc(id: System_Cursor) -> ^Cursor ---; 64 | @(link_name="SDL_CreateTexture") create_texture :: proc(renderer: ^Renderer, format: u32, access: i32, w, h: i32) -> ^Texture ---; 65 | @(link_name="SDL_CreateTextureFromSurface") create_texture_from_surface :: proc(renderer: ^Renderer, surface: ^Surface) -> ^Texture ---; 66 | @(link_name="SDL_CreateThread") create_thread :: proc(fn: Thread_Function, name: cstring, data: rawptr) -> ^Thread ---; 67 | @(link_name="SDL_CreateWindow") create_window :: proc(title: cstring, x, y, w, h: i32, flags: Window_Flags) -> ^Window ---; 68 | @(link_name="SDL_CreateWindowAndRenderer") create_window_and_renderer :: proc(width, height: i32, window_flags: Window_Flags, window: ^^Window, renderer: ^^Renderer) -> i32 ---; 69 | @(link_name="SDL_CreateWindowFrom") create_window_from :: proc(data: rawptr) -> ^Window ---; 70 | @(link_name="SDL_DXGIGetOutputInfo") dxgi_get_output_info :: proc(display_index: i32, adapter_index: ^i32, output_index: ^i32) -> Bool ---; 71 | @(link_name="SDL_DelEventWatch") del_event_watch :: proc(filter: Event_Filter, userdata: rawptr) ---; 72 | @(link_name="SDL_DelHintCallback") del_hint_callback :: proc(name: cstring, callback: Hint_Callback, userdata: rawptr) ---; 73 | @(link_name="SDL_Delay") delay :: proc(ms: u32) ---; 74 | @(link_name="SDL_DequeueAudio") dequeue_audio :: proc(dev: Audio_Device_Id, data: rawptr, len: u32) -> u32 ---; 75 | @(link_name="SDL_DestroyCond") destroy_cond :: proc(cond: ^Cond) ---; 76 | @(link_name="SDL_DestroyMutex") destroy_mutex :: proc(mutex: ^Mutex) ---; 77 | @(link_name="SDL_DestroyRenderer") destroy_renderer :: proc(renderer: ^Renderer) ---; 78 | @(link_name="SDL_DestroySemaphore") destroy_semaphore :: proc(sem: ^Sem) ---; 79 | @(link_name="SDL_DestroyTexture") destroy_texture :: proc(texture: ^Texture) ---; 80 | @(link_name="SDL_DestroyWindow") destroy_window :: proc(window: ^Window) ---; 81 | @(link_name="SDL_DetachThread") detach_thread :: proc(thread: ^Thread) ---; 82 | @(link_name="SDL_Direct3D9GetAdapterIndex") direct_3d9_get_adapter_index :: proc(display_index: i32) -> i32 ---; 83 | @(link_name="SDL_DisableScreenSaver") disable_screen_saver :: proc() ---; 84 | @(link_name="SDL_EnableScreenSaver") enable_screen_saver :: proc() ---; 85 | @(link_name="SDL_EnclosePoints") enclose_points :: proc(points: ^Point, count: i32, clip: ^Rect, result: ^Rect) -> Bool ---; 86 | @(link_name="SDL_Error") error :: proc(code: Error_Code) -> i32 ---; 87 | @(link_name="SDL_EventState") event_state :: proc(event_type: u32, state: i32) -> u8 ---; 88 | @(link_name="SDL_FillRect") fill_rect :: proc(dst: ^Surface, rect: ^Rect, color: u32) -> i32 ---; 89 | @(link_name="SDL_FillRects") fill_rects :: proc(dst: ^Surface, rect: ^Rect, count: i32, color: u32) -> i32 ---; 90 | @(link_name="SDL_FilterEvents") filter_events :: proc(filter: Event_Filter, userdata: rawptr) ---; 91 | @(link_name="SDL_FlushEvent") flush_event :: proc(event_type: u32) ---; 92 | @(link_name="SDL_FlushEvents") flush_events :: proc(min_type: u32, max_type: u32) ---; 93 | @(link_name="SDL_FreeCursor") free_cursor :: proc(cursor: ^Cursor) ---; 94 | @(link_name="SDL_FreeFormat") free_format :: proc(format: ^Pixel_Format) ---; 95 | @(link_name="SDL_FreePalette") free_palette :: proc(palette: ^Palette) ---; 96 | @(link_name="SDL_FreeRW") free_rw :: proc(area: ^Rw_Ops) ---; 97 | @(link_name="SDL_FreeSurface") free_surface :: proc(surface: ^Surface) ---; 98 | @(link_name="SDL_FreeWAV") free_wav :: proc(audio_buf: ^u8) ---; 99 | @(link_name="SDL_GL_BindTexture") gl_bind_texture :: proc(texture: ^Texture, texw, texh: ^f32) -> i32 ---; 100 | @(link_name="SDL_GL_CreateContext") gl_create_context :: proc(window: ^Window) -> GL_Context ---; 101 | @(link_name="SDL_GL_DeleteContext") gl_delete_context :: proc(gl_context: GL_Context) ---; 102 | @(link_name="SDL_GL_ExtensionSupported") gl_extension_supported :: proc(extension: cstring) -> Bool ---; 103 | @(link_name="SDL_GL_GetAttribute") gl_get_attribute :: proc(attr: GL_Attr, value: ^i32) -> i32 ---; 104 | @(link_name="SDL_GL_GetCurrentContext") gl_get_current_context :: proc() -> GL_Context ---; 105 | @(link_name="SDL_GL_GetCurrentWindow") gl_get_current_window :: proc() -> ^Window ---; 106 | @(link_name="SDL_GL_GetDrawableSize") gl_get_drawable_size :: proc(window: ^Window, w, h: ^i32) ---; 107 | @(link_name="SDL_GL_GetProcAddress") gl_get_proc_address :: proc(name: cstring) -> rawptr ---; 108 | @(link_name="SDL_GL_GetSwapInterval") gl_get_swap_interval :: proc() -> i32 ---; 109 | @(link_name="SDL_GL_LoadLibrary") gl_load_library :: proc(path: cstring) -> i32 ---; 110 | @(link_name="SDL_GL_MakeCurrent") gl_make_current :: proc(window: ^Window, gl_context: GL_Context) -> i32 ---; 111 | @(link_name="SDL_GL_ResetAttributes") gl_reset_attributes :: proc() ---; 112 | @(link_name="SDL_GL_SetAttribute") gl_set_attribute :: proc(attr: GL_Attr, value: i32) -> i32 ---; 113 | @(link_name="SDL_GL_SetSwapInterval") gl_set_swap_interval :: proc(interval: i32) -> i32 ---; 114 | @(link_name="SDL_GL_SwapWindow") gl_swap_window :: proc(window: ^Window) ---; 115 | @(link_name="SDL_GL_UnbindTexture") gl_unbind_texture :: proc(texture: ^Texture) -> i32 ---; 116 | @(link_name="SDL_GL_UnloadLibrary") gl_unload_library :: proc() ---; 117 | @(link_name="SDL_GameControllerAddMapping") game_controller_add_mapping :: proc(mapping_string: cstring) -> i32 ---; 118 | @(link_name="SDL_GameControllerAddMappingsFromRW") game_controller_add_mappings_from_rw :: proc(area: ^Rw_Ops, freerw: i32) -> i32 ---; 119 | @(link_name="SDL_GameControllerClose") game_controller_close :: proc(game_controller: ^Game_Controller) ---; 120 | @(link_name="SDL_GameControllerEventState") game_controller_event_state :: proc(state: i32) -> i32 ---; 121 | @(link_name="SDL_GameControllerFromInstanceID") game_controller_from_instance_id :: proc(joy_id: Joystick_Id) -> ^Game_Controller ---; 122 | @(link_name="SDL_GameControllerGetAttached") game_controller_get_attached :: proc(game_controller: ^Game_Controller) -> Bool ---; 123 | @(link_name="SDL_GameControllerGetAxis") game_controller_get_axis :: proc(game_controller: ^Game_Controller, axis: Game_Controller_Axis) -> i16 ---; 124 | @(link_name="SDL_GameControllerGetAxisFromString") game_controller_get_axis_from_string :: proc(pch_string: cstring) -> cstring ---; 125 | @(link_name="SDL_GameControllerGetBindForAxis") game_controller_get_bind_for_axis :: proc(game_controller: ^Game_Controller, axis: Game_Controller_Axis) -> Game_Controller_Button_Bind ---; 126 | @(link_name="SDL_GameControllerGetBindForButton") game_controller_get_bind_for_button :: proc(game_controller: ^Game_Controller, button: Game_Controller_Button) -> Game_Controller_Button_Bind ---; 127 | @(link_name="SDL_GameControllerGetButton") game_controller_get_button :: proc(game_controller: ^Game_Controller, button: Game_Controller_Button) -> u8 ---; 128 | @(link_name="SDL_GameControllerGetButtonFromString") game_controller_get_button_from_string :: proc(pch_string: cstring) -> Game_Controller_Button ---; 129 | @(link_name="SDL_GameControllerGetJoystick") game_controller_get_joystick :: proc(game_controller: ^Game_Controller) -> ^Joystick ---; 130 | @(link_name="SDL_GameControllerGetStringForAxis") game_controller_get_string_for_axis :: proc(axis: Game_Controller_Axis) -> cstring ---; 131 | @(link_name="SDL_GameControllerGetStringForButton") game_controller_get_string_for_button :: proc(button: Game_Controller_Button) -> cstring ---; 132 | @(link_name="SDL_GameControllerMapping") game_controller_mapping :: proc(game_controller: ^Game_Controller) -> cstring ---; 133 | @(link_name="SDL_GameControllerMappingForGUID") game_controller_mapping_for_guid :: proc(guid: Joystick_Guid) -> cstring ---; 134 | @(link_name="SDL_GameControllerName") game_controller_name :: proc(game_controller: ^Game_Controller) -> cstring ---; 135 | @(link_name="SDL_GameControllerNameForIndex") game_controller_name_for_index :: proc(joystick_index: i32) -> cstring ---; 136 | @(link_name="SDL_GameControllerOpen") game_controller_open :: proc(joystick_index: i32) -> ^Game_Controller ---; 137 | @(link_name="SDL_GameControllerUpdate") game_controller_update :: proc() ---; 138 | @(link_name="SDL_GetAssertionHandler") get_assertion_handler :: proc(userdata: ^rawptr) -> Assertion_Handler ---; 139 | @(link_name="SDL_GetAssertionReport") get_assertion_report :: proc() -> ^Assert_Data ---; 140 | @(link_name="SDL_GetAudioDeviceName") get_audio_device_name :: proc(index: i32, iscapture: i32) -> cstring ---; 141 | @(link_name="SDL_GetAudioDeviceStatus") get_audio_device_status :: proc(dev: Audio_Device_Id) -> Audio_Status ---; 142 | @(link_name="SDL_GetAudioDriver") get_audio_driver :: proc(index: i32) -> cstring ---; 143 | @(link_name="SDL_GetAudioStatus") get_audio_status :: proc() -> Audio_Status ---; 144 | @(link_name="SDL_GetBasePath") get_base_path :: proc() -> cstring ---; 145 | @(link_name="SDL_GetCPUCacheLineSize") get_cpu_cache_line_size :: proc() -> i32 ---; 146 | @(link_name="SDL_GetCPUCount") get_cpu_count :: proc() -> i32 ---; 147 | @(link_name="SDL_GetClipRect") get_clip_rect :: proc(surface: ^Surface, rect: ^Rect) ---; 148 | @(link_name="SDL_GetClipboardText") get_clipboard_text :: proc() -> cstring ---; 149 | @(link_name="SDL_GetClosestDisplayMode") get_closest_display_mode :: proc(display_index: i32, mode: ^Display_Mode, closest: ^Display_Mode) -> ^Display_Mode ---; 150 | @(link_name="SDL_GetColorKey") get_color_key :: proc(surface: ^Surface, key: ^u32) -> i32 ---; 151 | @(link_name="SDL_GetCurrentAudioDriver") get_current_audio_driver :: proc() -> cstring ---; 152 | @(link_name="SDL_GetCurrentDisplayMode") get_current_display_mode :: proc(display_index: i32, mode: ^Display_Mode) -> i32 ---; 153 | @(link_name="SDL_GetCurrentVideoDriver") get_current_video_driver :: proc() -> cstring ---; 154 | @(link_name="SDL_GetCursor") get_cursor :: proc() -> ^Cursor ---; 155 | @(link_name="SDL_GetDefaultAssertionHandler") get_default_assertion_handler :: proc() -> Assertion_Handler ---; 156 | @(link_name="SDL_GetDefaultCursor") get_default_cursor :: proc() -> ^Cursor ---; 157 | @(link_name="SDL_GetDesktopDisplayMode") get_desktop_display_mode :: proc(display_index: i32, mode: ^Display_Mode) -> i32 ---; 158 | @(link_name="SDL_GetDisplayBounds") get_display_bounds :: proc(display_index: i32, rect: ^Rect) -> i32 ---; 159 | @(link_name="SDL_GetDisplayDPI") get_display_dpi :: proc(display_index: i32, ddpi, hdpi, vdpi: ^f32) -> i32 ---; 160 | @(link_name="SDL_GetDisplayMode") get_display_mode :: proc(display_index: i32, mode_index: i32, mode: ^Display_Mode) -> i32 ---; 161 | @(link_name="SDL_GetDisplayName") get_display_name :: proc(display_index: i32) -> cstring ---; 162 | @(link_name="SDL_GetDisplayUsableBounds") get_display_usable_bounds :: proc(display_index: i32, rect: ^Rect) -> i32 ---; 163 | @(link_name="SDL_GetError") get_error :: proc() -> cstring ---; 164 | @(link_name="SDL_GetEventFilter") get_event_filter :: proc(filter: ^Event_Filter, userdata: ^rawptr) -> Bool ---; 165 | @(link_name="SDL_GetGlobalMouseState") get_global_mouse_state :: proc(x, y: ^i32) -> u32 ---; 166 | @(link_name="SDL_GetGrabbedWindow") get_grabbed_window :: proc() -> ^Window ---; 167 | @(link_name="SDL_GetHint") get_hint :: proc(name: cstring) -> cstring ---; 168 | @(link_name="SDL_GetHintBoolean") get_hint_boolean :: proc(name: cstring, default_value: Bool) -> Bool ---; 169 | @(link_name="SDL_GetKeyFromName") get_key_from_name :: proc(name: cstring) -> Keycode ---; 170 | @(link_name="SDL_GetKeyFromScancode") get_key_from_scancode :: proc(scancode: Scancode) -> Keycode ---; 171 | @(link_name="SDL_GetKeyName") get_key_name :: proc(key: Keycode) -> cstring ---; 172 | @(link_name="SDL_GetKeyboardFocus") get_keyboard_focus :: proc() -> ^Window ---; 173 | @(link_name="SDL_GetKeyboardState") get_keyboard_state :: proc(numkeys: ^i32) -> ^u8 ---; 174 | @(link_name="SDL_GetModState") get_mod_state :: proc() -> Keymod ---; 175 | @(link_name="SDL_GetMouseFocus") get_mouse_focus :: proc() -> ^Window ---; 176 | @(link_name="SDL_GetMouseState") get_mouse_state :: proc(x, y: ^i32) -> u32 ---; 177 | @(link_name="SDL_GetNumAudioDevices") get_num_audio_devices :: proc(iscapture: i32) -> i32 ---; 178 | @(link_name="SDL_GetNumAudioDrivers") get_num_audio_drivers :: proc() -> i32 ---; 179 | @(link_name="SDL_GetNumDisplayModes") get_num_display_modes :: proc(display_index: i32) -> i32 ---; 180 | @(link_name="SDL_GetNumRenderDrivers") get_num_render_drivers :: proc() -> i32 ---; 181 | @(link_name="SDL_GetNumTouchDevices") get_num_touch_devices :: proc() -> i32 ---; 182 | @(link_name="SDL_GetNumTouchFingers") get_num_touch_fingers :: proc(touch_id: Touch_Id) -> i32 ---; 183 | @(link_name="SDL_GetNumVideoDisplays") get_num_video_displays :: proc() -> i32 ---; 184 | @(link_name="SDL_GetNumVideoDrivers") get_num_video_drivers :: proc() -> i32 ---; 185 | @(link_name="SDL_GetPerformanceCounter") get_performance_counter :: proc() -> u64 ---; 186 | @(link_name="SDL_GetPerformanceFrequency") get_performance_frequency :: proc() -> u64 ---; 187 | @(link_name="SDL_GetPixelFormatName") get_pixel_format_name :: proc(format: u32) -> cstring ---; 188 | @(link_name="SDL_GetPlatform") get_platform :: proc() -> cstring ---; 189 | @(link_name="SDL_GetPowerInfo") get_power_info :: proc(secs, pct: ^i32) -> Power_State ---; 190 | @(link_name="SDL_GetPrefPath") get_pref_path :: proc(org, app: cstring) -> cstring ---; 191 | @(link_name="SDL_GetQueuedAudioSize") get_queued_audio_size :: proc(dev: Audio_Device_Id) -> u32 ---; 192 | @(link_name="SDL_GetRGB") get_rgb :: proc(pixel: u32, format: ^Pixel_Format, r, g, b: ^u8) ---; 193 | @(link_name="SDL_GetRGBA") get_rgba :: proc(pixel: u32, format: ^Pixel_Format, r, g, b, a: ^u8) ---; 194 | @(link_name="SDL_GetRelativeMouseMode") get_relative_mouse_mode :: proc() -> Bool ---; 195 | @(link_name="SDL_GetRelativeMouseState") get_relative_mouse_state :: proc(x, y: ^i32) -> u32 ---; 196 | @(link_name="SDL_GetRenderDrawBlendMode") get_render_draw_blend_mode :: proc(renderer: ^Renderer, blend_mode: ^Blend_Mode) -> i32 ---; 197 | @(link_name="SDL_GetRenderDrawColor") get_render_draw_color :: proc(renderer: ^Renderer, r, g, b, a: ^u8) -> i32 ---; 198 | @(link_name="SDL_GetRenderDriverInfo") get_render_driver_info :: proc(index: i32, info: ^Renderer_Info) -> i32 ---; 199 | @(link_name="SDL_GetRenderTarget") get_render_target :: proc(renderer: ^Renderer) -> ^Texture ---; 200 | @(link_name="SDL_GetRenderer") get_renderer :: proc(window: ^Window) -> ^Renderer ---; 201 | @(link_name="SDL_GetRendererInfo") get_renderer_info :: proc(renderer: ^Renderer, info: ^Renderer_Info) -> i32 ---; 202 | @(link_name="SDL_GetRendererOutputSize") get_renderer_output_size :: proc(renderer: ^Renderer, w, h: ^i32) -> i32 ---; 203 | @(link_name="SDL_GetRevision") get_revision :: proc() -> cstring ---; 204 | @(link_name="SDL_GetRevisionNumber") get_revision_number :: proc() -> i32 ---; 205 | @(link_name="SDL_GetScancodeFromKey") get_scancode_from_key :: proc(key: Keycode) -> Scancode ---; 206 | @(link_name="SDL_GetScancodeFromName") get_scancode_from_name :: proc(name: cstring) -> Scancode ---; 207 | @(link_name="SDL_GetScancodeName") get_scancode_name :: proc(scancode: Scancode) -> cstring ---; 208 | @(link_name="SDL_GetShapedWindowMode") get_shaped_window_mode :: proc(window: ^Window, shape_mode: ^Window_Shape_Mode) -> i32 ---; 209 | @(link_name="SDL_GetSurfaceAlphaMod") get_surface_alpha_mod :: proc(surface: ^Surface, alpha: ^u8) -> i32 ---; 210 | @(link_name="SDL_GetSurfaceBlendMode") get_surface_blend_mode :: proc(surface: ^Surface, blend_mode: ^Blend_Mode) -> i32 ---; 211 | @(link_name="SDL_GetSurfaceColorMod") get_surface_color_mod :: proc(surface: ^Surface, r, g, b: ^u8) -> i32 ---; 212 | @(link_name="SDL_GetSystemRAM") get_system_ram :: proc() -> i32 ---; 213 | @(link_name="SDL_GetTextureAlphaMod") get_texture_alpha_mod :: proc(texture: ^Texture, alpha: ^u8) -> i32 ---; 214 | @(link_name="SDL_GetTextureBlendMode") get_texture_blend_mode :: proc(texture: ^Texture, blend_mode: ^Blend_Mode) -> i32 ---; 215 | @(link_name="SDL_GetTextureColorMod") get_texture_color_mod :: proc(texture: ^Texture, r, g, b: ^u8) -> i32 ---; 216 | @(link_name="SDL_GetThreadID") get_thread_id :: proc(thread: ^Thread) -> Thread_Id ---; 217 | @(link_name="SDL_GetThreadName") get_thread_name :: proc(thread: ^Thread) -> cstring ---; 218 | @(link_name="SDL_GetTicks") get_ticks :: proc() -> u32 ---; 219 | @(link_name="SDL_GetTouchDevice") get_touch_device :: proc(index: i32) -> Touch_Id ---; 220 | @(link_name="SDL_GetTouchFinger") get_touch_finger :: proc(touch_id: Touch_Id, index: i32) -> ^Finger ---; 221 | @(link_name="SDL_GetVersion") get_version :: proc(ver: ^Version) ---; 222 | @(link_name="SDL_GetVideoDriver") get_video_driver :: proc(index: i32) -> cstring ---; 223 | @(link_name="SDL_GetWindowBordersSize") get_window_borders_size :: proc(window: ^Window, top, left, bottom, right: ^i32) -> i32 ---; 224 | @(link_name="SDL_GetWindowBrightness") get_window_brightness :: proc(window: ^Window) -> f32 ---; 225 | @(link_name="SDL_GetWindowData") get_window_data :: proc(window: ^Window, name: cstring) -> rawptr ---; 226 | @(link_name="SDL_GetWindowDisplayIndex") get_window_display_index :: proc(window: ^Window) -> i32 ---; 227 | @(link_name="SDL_GetWindowDisplayMode") get_window_display_mode :: proc(window: ^Window, mode: ^Display_Mode) -> i32 ---; 228 | @(link_name="SDL_GetWindowFlags") get_window_flags :: proc(window: ^Window) -> u32 ---; 229 | @(link_name="SDL_GetWindowFromID") get_window_fromid :: proc(id: u32) -> ^Window ---; 230 | @(link_name="SDL_GetWindowGammaRamp") get_window_gammaramp :: proc(window: ^Window, r, g, b: u16) -> i32 ---; 231 | @(link_name="SDL_GetWindowGrab") get_window_grab :: proc(window: ^Window) -> Bool ---; 232 | @(link_name="SDL_GetWindowID") get_window_id :: proc(window: ^Window) -> u32 ---; 233 | @(link_name="SDL_GetWindowMaximumSize") get_window_maximum_size :: proc(window: ^Window, w, h: ^i32) ---; 234 | @(link_name="SDL_GetWindowMinimumSize") get_window_minimum_size :: proc(window: ^Window, w, h: ^i32) ---; 235 | @(link_name="SDL_GetWindowOpacity") get_window_opacity :: proc(window: ^Window, opacity: ^f32) -> i32 ---; 236 | @(link_name="SDL_GetWindowPixelFormat") get_window_pixel_format :: proc(window: ^Window) -> u32 ---; 237 | @(link_name="SDL_GetWindowPosition") get_window_position :: proc(window: ^Window, x, y: ^i32) ---; 238 | @(link_name="SDL_GetWindowSize") get_window_size :: proc(window: ^Window, w, h: ^i32) ---; 239 | @(link_name="SDL_GetWindowSurface") get_window_surface :: proc(window: ^Window) -> ^Surface ---; 240 | @(link_name="SDL_GetWindowTitle") get_window_title :: proc(window: ^Window) -> cstring ---; 241 | @(link_name="SDL_GetWindowWMInfo") get_window_wm_info :: proc(window: ^Window, info: ^Sys_Wm_Info) -> Bool ---; 242 | @(link_name="SDL_HapticClose") haptic_close :: proc(haptic: ^Haptic) ---; 243 | @(link_name="SDL_HapticDestroyEffect") haptic_destroy_effect :: proc(haptic: ^Haptic, effect: i32) ---; 244 | @(link_name="SDL_HapticEffectSupported") haptic_effect_supported :: proc(haptic: ^Haptic, effect: ^Haptic_Effect) -> i32 ---; 245 | @(link_name="SDL_HapticGetEffectStatus") haptic_get_effect_status :: proc(haptic: ^Haptic, effect: i32) -> i32 ---; 246 | @(link_name="SDL_HapticIndex") haptic_index :: proc(haptic: ^Haptic) -> i32 ---; 247 | @(link_name="SDL_HapticName") haptic_name :: proc(device_index: i32) -> cstring ---; 248 | @(link_name="SDL_HapticNewEffect") haptic_new_effect :: proc(haptic: ^Haptic, effect: ^Haptic_Effect) -> i32 ---; 249 | @(link_name="SDL_HapticNumAxes") haptic_num_axes :: proc(haptic: ^Haptic) -> i32 ---; 250 | @(link_name="SDL_HapticNumEffects") haptic_num_effects :: proc(haptic: ^Haptic) -> i32 ---; 251 | @(link_name="SDL_HapticNumEffectsPlaying") haptic_num_effects_playing :: proc(haptic: ^Haptic) -> i32 ---; 252 | @(link_name="SDL_HapticOpen") haptic_open :: proc(device_index: i32) -> ^Haptic ---; 253 | @(link_name="SDL_HapticOpenFromJoystick") haptic_open_from_joystick :: proc(joystick: ^Joystick) -> ^Haptic ---; 254 | @(link_name="SDL_HapticOpenFromMouse") haptic_open_from_mouse :: proc() -> ^Haptic ---; 255 | @(link_name="SDL_HapticOpened") haptic_opened :: proc(device_index: i32) -> i32 ---; 256 | @(link_name="SDL_HapticPause") haptic_pause :: proc(haptic: ^Haptic) -> i32 ---; 257 | @(link_name="SDL_HapticQuery") haptic_query :: proc(haptic: ^Haptic) -> u32 ---; 258 | @(link_name="SDL_HapticRumbleInit") haptic_rumble_init :: proc(haptic: ^Haptic) -> i32 ---; 259 | @(link_name="SDL_HapticRumblePlay") haptic_rumble_play :: proc(haptic: ^Haptic, strength: f32, length: u32) -> i32 ---; 260 | @(link_name="SDL_HapticRumbleStop") haptic_rumble_stop :: proc(haptic: ^Haptic) -> i32 ---; 261 | @(link_name="SDL_HapticRumbleSupported") haptic_rumble_supported :: proc(haptic: ^Haptic) -> i32 ---; 262 | @(link_name="SDL_HapticRunEffect") haptic_run_effect :: proc(haptic: ^Haptic, effect: i32, iterations: u32) -> i32 ---; 263 | @(link_name="SDL_HapticSetAutocenter") haptic_set_autocenter :: proc(haptic: ^Haptic, autocenter: i32) -> i32 ---; 264 | @(link_name="SDL_HapticSetGain") haptic_set_gain :: proc(haptic: ^Haptic, gain: i32) -> i32 ---; 265 | @(link_name="SDL_HapticStopAll") haptic_stop_all :: proc(haptic: ^Haptic) -> i32 ---; 266 | @(link_name="SDL_HapticStopEffect") haptic_stop_effect :: proc(haptic: ^Haptic, effect: i32) -> i32 ---; 267 | @(link_name="SDL_HapticUnpause") haptic_unpause :: proc(haptic: ^Haptic) -> i32 ---; 268 | @(link_name="SDL_HapticUpdateEffect") haptic_update_effect :: proc(haptic: ^Haptic, effect: i32, data: ^Haptic_Effect) -> i32 ---; 269 | @(link_name="SDL_Has3DNow") has_3d_now :: proc() -> Bool ---; 270 | @(link_name="SDL_HasAVX") has_avx :: proc() -> Bool ---; 271 | @(link_name="SDL_HasAVX2") has_avx2 :: proc() -> Bool ---; 272 | @(link_name="SDL_HasAltiVec") has_alti_vec :: proc() -> Bool ---; 273 | @(link_name="SDL_HasClipboardText") has_clipboard_text :: proc() -> Bool ---; 274 | @(link_name="SDL_HasEvent") has_event :: proc(event_type: u32) -> Bool ---; 275 | @(link_name="SDL_HasEvents") has_events :: proc(min_type: u32, max_type: u32) -> Bool ---; 276 | @(link_name="SDL_HasIntersection") has_intersection :: proc(a, b: ^Rect) -> Bool ---; 277 | @(link_name="SDL_HasMMX") has_mmx :: proc() -> Bool ---; 278 | @(link_name="SDL_HasRDTSC") has_rdtsc :: proc() -> Bool ---; 279 | @(link_name="SDL_HasSSE") has_sse :: proc() -> Bool ---; 280 | @(link_name="SDL_HasSSE2") has_sse2 :: proc() -> Bool ---; 281 | @(link_name="SDL_HasSSE3") has_sse3 :: proc() -> Bool ---; 282 | @(link_name="SDL_HasSSE41") has_sse41 :: proc() -> Bool ---; 283 | @(link_name="SDL_HasSSE42") has_sse42 :: proc() -> Bool ---; 284 | @(link_name="SDL_HasScreenKeyboardSupport") has_screen_keyboard_support :: proc() -> Bool ---; 285 | @(link_name="SDL_HideWindow") hide_window :: proc(window: ^Window) ---; 286 | @(link_name="SDL_Init") init :: proc(flags: Init_Flags) -> i32 ---; 287 | @(link_name="SDL_InitSubSystem") init_sub_system :: proc(flags: u32) -> i32 ---; 288 | @(link_name="SDL_IntersectRect") intersect_rect :: proc(a, b, result: ^Rect) -> Bool ---; 289 | @(link_name="SDL_IntersectRectAndLine") intersect_rect_and_line :: proc(rect: ^Rect, x1, y1, x2, y2: ^i32) -> Bool ---; 290 | @(link_name="SDL_IsGameController") is_game_controller :: proc(joystick_index: i32) -> Bool ---; 291 | @(link_name="SDL_IsScreenKeyboardShown") is_screen_keyboard_shown :: proc(window: ^Window) -> Bool ---; 292 | @(link_name="SDL_IsScreenSaverEnabled") is_screen_saver_enabled :: proc() -> Bool ---; 293 | @(link_name="SDL_IsShapedWindow") is_shaped_window :: proc(window: Window) -> Bool ---; 294 | @(link_name="SDL_IsTextInputActive") is_text_input_active :: proc() -> Bool ---; 295 | @(link_name="SDL_JoystickClose") joystick_close :: proc(joystick: ^Joystick) ---; 296 | @(link_name="SDL_JoystickCurrentPowerLevel") joystick_current_power_level :: proc(joystick: ^Joystick) -> Joystick_Power_Level ---; 297 | @(link_name="SDL_JoystickEventState") joystick_event_state :: proc(state: i32) -> i32 ---; 298 | @(link_name="SDL_JoystickFromInstanceID") joystick_from_instance_id :: proc(joystick_id: ^Joystick_Id) -> ^Joystick ---; 299 | @(link_name="SDL_JoystickGetAttached") joystick_get_attached :: proc(joystick: ^Joystick) -> Bool ---; 300 | @(link_name="SDL_JoystickGetAxis") joystick_get_axis :: proc(joystick: ^Joystick, axis: i32) -> i16 ---; 301 | @(link_name="SDL_JoystickGetBall") joystick_get_ball :: proc(joystick: ^Joystick, ball: i32, dx, dy: ^i32) -> i32 ---; 302 | @(link_name="SDL_JoystickGetButton") joystick_get_button :: proc(joystick: ^Joystick, button: i32) -> u8 ---; 303 | @(link_name="SDL_JoystickGetDeviceGUID") joystick_get_device_guid :: proc(device_index: i32) -> Joystick_Guid ---; 304 | @(link_name="SDL_JoystickGetGUID") joystick_get_guid :: proc(joystick: ^Joystick) -> Joystick_Guid ---; 305 | @(link_name="SDL_JoystickGetGUIDFromString") joystick_get_guid_from_string :: proc(pch_guid: cstring) -> Joystick_Guid ---; 306 | @(link_name="SDL_JoystickGetGUIDString") joystick_get_guid_string :: proc(guid: Joystick_Guid, psz_guid: ^u8, cb_guid: i32) ---; 307 | @(link_name="SDL_JoystickGetHat") joystick_get_hat :: proc(joystick: ^Joystick, hat: i32) -> u8 ---; 308 | @(link_name="SDL_JoystickInstanceID") joystick_instance_id :: proc(joystick: ^Joystick) -> Joystick_Id ---; 309 | @(link_name="SDL_JoystickIsHaptic") joystick_is_haptic :: proc(joystick: ^Joystick) -> i32 ---; 310 | @(link_name="SDL_JoystickName") joystick_name :: proc(joystick: ^Joystick) -> cstring ---; 311 | @(link_name="SDL_JoystickNameForIndex") joystick_name_for_index :: proc(device_index: i32) -> cstring ---; 312 | @(link_name="SDL_JoystickNumAxes") joystick_num_axes :: proc(joystick: ^Joystick) -> i32 ---; 313 | @(link_name="SDL_JoystickNumBalls") joystick_num_balls :: proc(joystick: ^Joystick) -> i32 ---; 314 | @(link_name="SDL_JoystickNumButtons") joystick_num_buttons :: proc(joystick: ^Joystick) -> i32 ---; 315 | @(link_name="SDL_JoystickNumHats") joystick_num_hats :: proc(joystick: ^Joystick) -> i32 ---; 316 | @(link_name="SDL_JoystickOpen") joystick_open :: proc(device_index: i32) -> ^Joystick ---; 317 | @(link_name="SDL_JoystickUpdate") joystick_update :: proc() ---; 318 | @(link_name="SDL_LoadBMP_RW") load_bmp_rw :: proc(src: ^Rw_Ops, freerw: i32) -> ^Surface ---; 319 | @(link_name="SDL_LoadDollarTemplates") load_dollar_templates :: proc(touch_id: Touch_Id, src: ^Rw_Ops) -> i32 ---; 320 | @(link_name="SDL_LoadFunction") load_function :: proc(handle: rawptr, name: cstring) -> rawptr ---; 321 | @(link_name="SDL_LoadObject") load_object :: proc(sofile: cstring) -> cstring ---; 322 | @(link_name="SDL_LoadWAV_RW") load_wav_rw :: proc(src: ^Rw_Ops, freesrc: i32, spec: ^Audio_Spec, audio_buf: ^^u8, audio_len: ^u32) -> ^Audio_Spec ---; 323 | @(link_name="SDL_LockAudio") lock_audio :: proc() ---; 324 | @(link_name="SDL_LockAudioDevice") lock_audio_device :: proc(dev: Audio_Device_Id) ---; 325 | @(link_name="SDL_LockMutex") lock_mutex :: proc(mutex: ^Mutex) -> i32 ---; 326 | @(link_name="SDL_LockSurface") lock_surface :: proc(surface: ^Surface) -> i32 ---; 327 | @(link_name="SDL_LockTexture") lock_texture :: proc(texture: ^Texture, rect: ^Rect, pixels: ^rawptr, pitch: ^i32) -> i32 ---; 328 | @(link_name="SDL_Log") log :: proc(fmt: ..cstring) ---; 329 | @(link_name="SDL_LogCritical") log_critical :: proc(category: Log_Category, fmt: ..cstring) ---; 330 | @(link_name="SDL_LogDebug") log_debug :: proc(category: Log_Category, fmt: ..cstring) ---; 331 | @(link_name="SDL_LogError") log_error :: proc(category: Log_Category, fmt: ..cstring) ---; 332 | @(link_name="SDL_LogGetOutputFunction") log_get_output_function :: proc(callback: ^Log_Output_Function, userdata: ^rawptr) ---; 333 | @(link_name="SDL_LogGetPriority") log_get_priority :: proc(category: Log_Category) -> Log_Priority ---; 334 | @(link_name="SDL_LogInfo") log_info :: proc(category: Log_Category, fmt: ..cstring) ---; 335 | @(link_name="SDL_LogMessage") log_message :: proc(category: Log_Category, priority: Log_Priority, fmt: ..cstring) ---; 336 | @(link_name="SDL_LogMessageV") log_message_v :: proc(category: Log_Category, priority: Log_Priority, fmt: cstring, va_list: cstring) ---; 337 | @(link_name="SDL_LogResetPriorities") log_reset_priorities :: proc() ---; 338 | @(link_name="SDL_LogSetAllPriority") log_set_all_priority :: proc(priority: Log_Priority) ---; 339 | @(link_name="SDL_LogSetOutputFunction") log_set_output_function :: proc(callback: Log_Output_Function, userdata: rawptr) ---; 340 | @(link_name="SDL_LogSetPriority") log_set_priority :: proc(category: Log_Category, priority: Log_Priority) ---; 341 | @(link_name="SDL_LogVerbose") log_verbose :: proc(category: Log_Category, fmt: ..cstring) ---; 342 | @(link_name="SDL_LogWarn") log_warn :: proc(category: Log_Category, fmt: ..cstring) ---; 343 | @(link_name="SDL_LowerBlit") lower_blit :: proc(src: ^Surface, srcrect: ^Rect, dst: ^Surface, dstrect: ^Rect) -> i32 ---; 344 | @(link_name="SDL_LowerBlitScaled") lower_blit_scaled :: proc(src: ^Surface, srcrect: ^Rect, dst: ^Surface, dstrect: ^Rect) -> i32 ---; 345 | @(link_name="SDL_MapRGB") map_rgb :: proc(format: ^Pixel_Format, r, g, b: u8) -> u32 ---; 346 | @(link_name="SDL_MapRGBA") map_rgba :: proc(format: ^Pixel_Format, r, g, b, a: u8) -> u32 ---; 347 | @(link_name="SDL_MasksToPixelFormatEnum") masks_to_pixel_format_enum :: proc(bpp: i32, r_mask, g_mask, b_mask, a_mask: u32) -> u32 ---; 348 | @(link_name="SDL_MaximizeWindow") maximize_window :: proc(window: ^Window) ---; 349 | @(link_name="SDL_MinimizeWindow") minimize_window :: proc(window: ^Window) ---; 350 | @(link_name="SDL_MixAudio") mix_audio :: proc(dst, src: ^u8, len: u32, volume: i32) ---; 351 | @(link_name="SDL_MixAudioFormat") mix_audio_format :: proc(dst, src: ^u8, format: Audio_Format, len: u32, volume: i32) ---; 352 | @(link_name="SDL_MouseIsHaptic") mouse_is_haptic :: proc() -> i32 ---; 353 | @(link_name="SDL_NumHaptics") num_haptics :: proc() -> i32 ---; 354 | @(link_name="SDL_NumJoysticks") num_joysticks :: proc() -> i32 ---; 355 | @(link_name="SDL_OpenAudio") open_audio :: proc(desired, obtained: ^Audio_Spec) -> i32 ---; 356 | @(link_name="SDL_OpenAudioDevice") open_audio_device :: proc(device: cstring, iscapture: i32, desired, obtained: ^Audio_Spec, allowed_changed: i32) -> Audio_Device_Id ---; 357 | @(link_name="SDL_PauseAudio") pause_audio :: proc(pause_on: i32) ---; 358 | @(link_name="SDL_PauseAudioDevice") pause_audio_device :: proc(dev: Audio_Device_Id, pause_on: i32) ---; 359 | @(link_name="SDL_PeepEvents") peep_events :: proc(events: ^Event, num_events: i32, action: Event_Action, min_type, max_type: u32) -> i32 ---; 360 | @(link_name="SDL_PixelFormatEnumToMasks") pixel_format_enum_to_masks :: proc(format: u32, bpp: ^i32, r_mask, g_mask, b_mask, a_mask: ^u32) -> Bool ---; 361 | @(link_name="SDL_PollEvent") poll_event :: proc(event: ^Event) -> i32 ---; 362 | @(link_name="SDL_PumpEvents") pump_events :: proc() ---; 363 | @(link_name="SDL_PushEvent") push_event :: proc(event: ^Event) -> i32 ---; 364 | @(link_name="SDL_QueryTexture") query_texture :: proc(texture: ^Texture, format: ^u32, access, w, h: ^i32) -> i32 ---; 365 | @(link_name="SDL_QueueAudio") queue_audio :: proc(dev: Audio_Device_Id, data: rawptr, len: u32) -> i32 ---; 366 | @(link_name="SDL_Quit") quit :: proc() ---; 367 | @(link_name="SDL_QuitSubSystem") quit_sub_system :: proc(flags: u32) ---; 368 | @(link_name="SDL_RaiseWindow") raise_window :: proc(window: ^Window) ---; 369 | @(link_name="SDL_ReadBE16") read_be16 :: proc(src: ^Rw_Ops) -> u16 ---; 370 | @(link_name="SDL_ReadBE32") read_be32 :: proc(src: ^Rw_Ops) -> u32 ---; 371 | @(link_name="SDL_ReadBE64") read_be64 :: proc(src: ^Rw_Ops) -> u64 ---; 372 | @(link_name="SDL_ReadLE16") read_le16 :: proc(src: ^Rw_Ops) -> u16 ---; 373 | @(link_name="SDL_ReadLE32") read_le32 :: proc(src: ^Rw_Ops) -> u32 ---; 374 | @(link_name="SDL_ReadLE64") read_le64 :: proc(src: ^Rw_Ops) -> u64 ---; 375 | @(link_name="SDL_ReadU8") read_u8 :: proc(src: ^Rw_Ops) -> u8 ---; 376 | @(link_name="SDL_RecordGesture") record_gesture :: proc(touch_id: Touch_Id) -> i32 ---; 377 | @(link_name="SDL_RegisterApp") register_app :: proc(name: cstring, style: u32, h_inst: rawptr) -> i32 ---; 378 | @(link_name="SDL_RegisterEvents") register_events :: proc(num_events: i32) -> u32 ---; 379 | @(link_name="SDL_RemoveTimer") remove_timer :: proc(id: Timer_Id) -> Bool ---; 380 | @(link_name="SDL_RenderClear") render_clear :: proc(renderer: ^Renderer) -> i32 ---; 381 | @(link_name="SDL_RenderCopy") render_copy :: proc(renderer: ^Renderer, texture: ^Texture, srcrect, dstrect: ^Rect) -> i32 ---; 382 | @(link_name="SDL_RenderCopyEx") render_copy_ex :: proc(renderer: ^Renderer, texture: ^Texture, srcrect, dstrect: ^Rect, angle: f64, center: ^Point, flip: Renderer_Flip) -> i32 ---; 383 | @(link_name="SDL_RenderDrawLine") render_draw_line :: proc(renderer: ^Renderer, x1, y1, x2, y2: i32) -> i32 ---; 384 | @(link_name="SDL_RenderDrawLines") render_draw_lines :: proc(renderer: ^Renderer, points: ^Point, count: i32) -> i32 ---; 385 | @(link_name="SDL_RenderDrawPoint") render_draw_point :: proc(renderer: ^Renderer, x, y: i32) -> i32 ---; 386 | @(link_name="SDL_RenderDrawPoints") render_draw_points :: proc(renderer: ^Renderer, points: ^Point, count: i32) -> i32 ---; 387 | @(link_name="SDL_RenderDrawRect") render_draw_rect :: proc(renderer: ^Renderer, rect: ^Rect) -> i32 ---; 388 | @(link_name="SDL_RenderDrawRects") render_draw_rects :: proc(renderer: ^Renderer, rects: ^Rect, count: i32) -> i32 ---; 389 | @(link_name="SDL_RenderFillRect") render_fill_rect :: proc(dst: ^Renderer, rect: ^Rect) -> i32 ---; 390 | @(link_name="SDL_RenderFillRects") render_fill_rects :: proc(dst: ^Renderer, rect: ^Rect, count: i32) -> i32 ---; 391 | @(link_name="SDL_RenderGetClipRect") render_get_clip_rect :: proc(surface: ^Surface, rect: ^Rect) ---; 392 | @(link_name="SDL_RenderGetD3D9Device") render_get_d3d9_device :: proc(renderer: ^Renderer) -> ^IDirect3D_Device9 ---; 393 | @(link_name="SDL_RenderGetIntegerScale") render_get_integer_scale :: proc(renderer: ^Renderer) -> Bool ---; 394 | @(link_name="SDL_RenderGetLogicalSize") render_get_logical_size :: proc(renderer: ^Renderer, w, h: ^i32) ---; 395 | @(link_name="SDL_RenderGetScale") render_get_scale :: proc(renderer: ^Renderer, scale_x, scale_y: ^f32) ---; 396 | @(link_name="SDL_RenderGetViewport") render_get_viewport :: proc(renderer: ^Renderer, rect: ^Rect) ---; 397 | @(link_name="SDL_RenderIsClipEnabled") render_is_clip_enabled :: proc(renderer: ^Renderer) -> Bool ---; 398 | @(link_name="SDL_RenderPresent") render_present :: proc(renderer: ^Renderer) ---; 399 | @(link_name="SDL_RenderReadPixels") render_read_pixels :: proc(renderer: ^Renderer, rect: ^Rect, format: u32, pixels: rawptr, pitch: i32) -> i32 ---; 400 | @(link_name="SDL_RenderSetClipRect") render_set_clip_rect :: proc(renderer: ^Renderer, rect: ^Rect) -> i32 ---; 401 | @(link_name="SDL_RenderSetIntegerScale") render_set_integer_scale :: proc(renderer: ^Renderer, enable: Bool) -> i32 ---; 402 | @(link_name="SDL_RenderSetLogicalSize") render_set_logical_size :: proc(renderer: ^Renderer, w, h: i32) -> i32 ---; 403 | @(link_name="SDL_RenderSetScale") render_set_scale :: proc(renderer: ^Renderer, scale_x, scale_y: f32) -> i32 ---; 404 | @(link_name="SDL_RenderSetViewport") render_set_viewport :: proc(renderer: ^Renderer, rect: ^Rect) ---; 405 | @(link_name="SDL_RenderTargetSupported") render_target_supported :: proc(renderer: ^Renderer) -> Bool ---; 406 | @(link_name="SDL_ResetAssertionReport") reset_assertion_report :: proc() ---; 407 | @(link_name="SDL_RestoreWindow") restore_window :: proc(window: ^Window) ---; 408 | @(link_name="SDL_RWFromConstMem") rw_from_const_mem :: proc(mem: rawptr, size: i32) -> ^Rw_Ops ---; 409 | @(link_name="SDL_RWFromFP") rw_from_fp :: proc(fp: rawptr, auto_close: Bool) -> ^Rw_Ops ---; 410 | @(link_name="SDL_RWFromFile") rw_from_file :: proc(file: cstring, mode: cstring) -> ^Rw_Ops ---; 411 | @(link_name="SDL_RWFromMem") rw_from_mem :: proc(mem: rawptr, size:i32) -> ^Rw_Ops ---; 412 | @(link_name="SDL_SaveAllDollarTemplates") save_all_dollar_templates :: proc(dst: ^Rw_Ops) -> i32 ---; 413 | @(link_name="SDL_SaveBMP_RW") save_bmp_rw :: proc(surface: ^Surface, dst: ^Rw_Ops, free_dst: i32) -> i32 ---; 414 | @(link_name="SDL_SaveDollarTemplate") save_dollar_template :: proc(gesture_id: Gesture_Id, dst: ^Rw_Ops) -> i32 ---; 415 | @(link_name="SDL_SemPost") sem_post :: proc(sem: Sem) -> i32 ---; 416 | @(link_name="SDL_SemTryWait") sem_try_wait :: proc(sem: Sem) -> i32 ---; 417 | @(link_name="SDL_SemValue") sem_value :: proc(sem: Sem) -> u32 ---; 418 | @(link_name="SDL_SemWait") sem_wait :: proc(sem: Sem) -> i32 ---; 419 | @(link_name="SDL_SemWaitTimeout") sem_wait_timeout :: proc(sem: Sem, ms: u32) -> i32 ---; 420 | @(link_name="SDL_SetAssertionHandler") set_assertion_handler :: proc(handler: Assertion_Handler, userdata: rawptr) ---; 421 | @(link_name="SDL_SetClipRect") set_clip_rect :: proc(surface: ^Surface, rect: ^Rect) -> Bool ---; 422 | @(link_name="SDL_SetClipboardText") set_clipboard_text :: proc(text: cstring) -> i32 ---; 423 | @(link_name="SDL_SetColorKey") set_color_key :: proc(surface: ^Surface, flag: i32, key: u32) -> i32 ---; 424 | @(link_name="SDL_SetCursor") set_cursor :: proc(cursor: ^Cursor) ---; 425 | @(link_name="SDL_SetError") set_error :: proc(fmt: ..cstring) -> i32 ---; 426 | @(link_name="SDL_SetEventFilter") set_event_filter :: proc(filter: Event_Filter, userdata: rawptr) ---; 427 | @(link_name="SDL_SetHint") set_hint :: proc(name, value: cstring) -> Bool ---; 428 | @(link_name="SDL_SetHintWithPriority") set_hint_with_priority :: proc(name, value: cstring, priority: Hint_Priority) -> Bool ---; 429 | @(link_name="SDL_SetMainReady") set_main_ready :: proc() ---; 430 | @(link_name="SDL_SetModState") set_mod_state :: proc(modstate: Keymod) ---; 431 | @(link_name="SDL_SetPaletteColors") set_palette_colors :: proc(palette: ^Palette, colors: ^Color, firstcolor, ncolors: i32) -> i32 ---; 432 | @(link_name="SDL_SetPixelFormatPalette") set_pixel_format_palette :: proc(format: ^Pixel_Format, palette: ^Palette) -> i32 ---; 433 | @(link_name="SDL_SetRelativeMouseMode") set_relative_mouse_mode :: proc(enabled: Bool) -> i32 ---; 434 | @(link_name="SDL_SetRenderDrawBlendMode") set_render_draw_blend_mode :: proc(renderer: ^Renderer, blend_mode: Blend_Mode) -> i32 ---; 435 | @(link_name="SDL_SetRenderDrawColor") set_render_draw_color :: proc(renderer: ^Renderer, r, g, b, a: u8) -> i32 ---; 436 | @(link_name="SDL_SetRenderTarget") set_render_target :: proc(renderer: ^Renderer, texture: ^Texture) -> i32 ---; 437 | @(link_name="SDL_SetSurfaceAlphaMod") set_surface_alpha_mod :: proc(surface: ^Surface, alpha: u8) -> i32 ---; 438 | @(link_name="SDL_SetSurfaceBlendMode") set_surface_blend_mode :: proc(surface: ^Surface, blend_mode: Blend_Mode) -> i32 ---; 439 | @(link_name="SDL_SetSurfaceColorMod") set_surface_color_mod :: proc(surface: ^Surface, r, g, b: u8) -> i32 ---; 440 | @(link_name="SDL_SetSurfacePalette") set_surface_palette :: proc(surface: ^Surface, palette: ^Palette) -> i32 ---; 441 | @(link_name="SDL_SetSurfaceRLE") set_surface_rle :: proc(surface: ^Surface, flag: i32) -> i32 ---; 442 | @(link_name="SDL_SetTextInputRect") set_text_input_rect :: proc(rect: ^Rect) ---; 443 | @(link_name="SDL_SetTextureAlphaMod") set_texture_alpha_mod :: proc(texture: ^Texture, alpha: u8) -> i32 ---; 444 | @(link_name="SDL_SetTextureBlendMode") set_texture_blend_mode :: proc(texture: ^Texture, blend_mode: Blend_Mode) -> i32 ---; 445 | @(link_name="SDL_SetTextureColorMod") set_texture_color_mod :: proc(texture: ^Texture, r, g, b: u8) -> i32 ---; 446 | @(link_name="SDL_SetThreadPriority") set_thread_priority :: proc(priority: Thread_Priority) -> i32 ---; 447 | @(link_name="SDL_SetWindowBordered") set_window_bordered :: proc(window: ^Window, bordered: Bool) ---; 448 | @(link_name="SDL_SetWindowBrightness") set_window_brightness :: proc(window: ^Window, brightness: f32) -> i32 ---; 449 | @(link_name="SDL_SetWindowData") set_window_data :: proc(window: ^Window, name: cstring, userdata: rawptr) -> rawptr ---; 450 | @(link_name="SDL_SetWindowDisplayMode") set_window_display_mode :: proc(window: ^Window, mode: ^Display_Mode) -> i32 ---; 451 | @(link_name="SDL_SetWindowFullscreen") set_window_fullscreen :: proc(window: ^Window, flags: u32) -> i32 ---; 452 | @(link_name="SDL_SetWindowGammaRamp") set_window_gamma_ramp :: proc(window: ^Window, r, g, b: ^u16) -> i32 ---; 453 | @(link_name="SDL_SetWindowGrab") set_window_grab :: proc(window: ^Window, grabbed: Bool) ---; 454 | @(link_name="SDL_SetWindowHitTest") set_window_hit_test :: proc(window: ^Window, callback: Hit_Test, callback_data: rawptr) -> i32 ---; 455 | @(link_name="SDL_SetWindowIcon") set_window_icon :: proc(window: ^Window, icon: ^Surface) ---; 456 | @(link_name="SDL_SetWindowInputFocus") set_window_input_focus :: proc(window: ^Window) -> i32 ---; 457 | @(link_name="SDL_SetWindowMaximumSize") set_window_maximum_size :: proc(window: ^Window, w, h: i32) ---; 458 | @(link_name="SDL_SetWindowMinimumSize") set_window_minimum_size :: proc(window: ^Window, w, h: i32) ---; 459 | @(link_name="SDL_SetWindowModalFor") set_window_modal_for :: proc(window: ^Window, parent_window: ^Window) -> i32 ---; 460 | @(link_name="SDL_SetWindowOpacity") set_window_opacity :: proc(window: ^Window, opacity: f32) -> i32 ---; 461 | @(link_name="SDL_SetWindowPosition") set_window_position :: proc(window: ^Window, x, y: i32) ---; 462 | @(link_name="SDL_SetWindowResizable") set_window_resizable :: proc(window: ^Window, resizable: Bool) ---; 463 | @(link_name="SDL_SetWindowShape") set_window_shape :: proc(window: ^Window, shape: ^Surface, shape_mode: Window_Shape_Mode) -> i32 ---; 464 | @(link_name="SDL_SetWindowSize") set_window_size :: proc(window: ^Window, w, h: i32) ---; 465 | @(link_name="SDL_SetWindowTitle") set_window_title :: proc(window: ^Window, title: cstring) ---; 466 | @(link_name="SDL_SetWindowsMessageHook") set_windows_message_hook :: proc(callback: Windows_Message_Hook, userdata: rawptr) ---; 467 | @(link_name="SDL_ShowCursor") show_cursor :: proc(toggle: i32) -> i32 ---; 468 | @(link_name="SDL_ShowMessageBox") show_message_box :: proc(message_box_data: ^Message_Box_Data, button_id: ^i32) -> i32 ---; 469 | @(link_name="SDL_ShowSimpleMessageBox") show_simple_message_box :: proc(flags: u32, title, message: cstring, window: ^Window) -> i32 ---; 470 | @(link_name="SDL_ShowWindow") show_window :: proc(window: ^Window) ---; 471 | @(link_name="SDL_SoftStretch") soft_stretch :: proc(src: ^Surface, srcrect: ^Rect, dst: ^Surface, dstrect: ^Rect) -> i32 ---; 472 | @(link_name="SDL_StartTextInput") start_text_input :: proc() ---; 473 | @(link_name="SDL_StopTextInput") stop_text_input :: proc() ---; 474 | @(link_name="SDL_TLSCreate") tls_create :: proc() -> Tls_Id ---; 475 | @(link_name="SDL_TLSGet") tls_get :: proc(id: Tls_Id) -> rawptr ---; 476 | @(link_name="SDL_TLSSet") tls_set :: proc(id: Tls_Id, value: rawptr, destructor: proc(data: rawptr)) -> i32 ---; 477 | @(link_name="SDL_ThreadID") thread_id :: proc() -> Thread_Id ---; 478 | @(link_name="SDL_TryLockMutex") try_lock_mutex :: proc(mutex: ^Mutex) -> i32 ---; 479 | @(link_name="SDL_UnionRect") union_rect :: proc(a, b, result: ^Rect) ---; 480 | @(link_name="SDL_UnloadObject") unload_object :: proc(handle: rawptr) ---; 481 | @(link_name="SDL_UnlockAudio") unlock_audio :: proc() ---; 482 | @(link_name="SDL_UnlockAudioDevice") unlock_audio_device :: proc(dev: Audio_Device_Id) ---; 483 | @(link_name="SDL_UnlockMutex") unlock_mutex :: proc(mutex: ^Mutex) -> i32 ---; 484 | @(link_name="SDL_UnlockSurface") unlock_surface :: proc(surface: ^Surface) ---; 485 | @(link_name="SDL_UnlockTexture") unlock_texture :: proc(texture: ^Texture) ---; 486 | @(link_name="SDL_UnregisterApp") unregister_app :: proc() ---; 487 | @(link_name="SDL_UpdateTexture") update_texture :: proc(texture: ^Texture, rect: ^Rect, pixels: rawptr, pitch: i32) -> i32 ---; 488 | @(link_name="SDL_UpdateWindowSurface") update_window_surface :: proc(window: ^Window) -> i32 ---; 489 | @(link_name="SDL_UpdateWindowSurfaceRects") update_window_surface_rects :: proc(window: ^Window, rects: ^Rect, num_rects: i32) -> i32 ---; 490 | @(link_name="SDL_UpdateYUVTexture") update_yuv_texture :: proc(texture: ^Texture, rect: ^Rect, y_plane: ^u8, y_pitch: i32, u_plane: ^u8, u_pitch: i32, v_plane: ^u8, v_pitch: i32) -> i32 ---; 491 | @(link_name="SDL_UpperBlit") upper_blit :: proc(src: ^Surface, srcrect: ^Rect, dst: ^Surface, dstrect: ^Rect) -> i32 ---; 492 | @(link_name="SDL_UpperBlitScaled") upper_blit_scaled :: proc(src: ^Surface, srcrect: ^Rect, dst: ^Surface, dstrect: ^Rect) -> i32 ---; 493 | @(link_name="SDL_VideoInit") video_init :: proc(driver_name: cstring) -> i32 ---; 494 | @(link_name="SDL_VideoQuit") video_quit :: proc() ---; 495 | @(link_name="SDL_WaitEvent") wait_event :: proc(event: ^Event) -> i32 ---; 496 | @(link_name="SDL_WaitEventTimeout") wait_event_timeout :: proc(event: ^Event, timeout: i32) -> i32 ---; 497 | @(link_name="SDL_WaitThread") wait_thread :: proc(thread: ^Thread, status: ^i32) ---; 498 | @(link_name="SDL_WarpMouseGlobal") warp_mouse_global :: proc(x, y: i32) -> i32 ---; 499 | @(link_name="SDL_WarpMouseInWindow") warp_mouse_in_window :: proc(window: ^Window, x, y: i32) ---; 500 | @(link_name="SDL_WasInit") was_init :: proc(flags: u32) -> u32 ---; 501 | @(link_name="SDL_WriteBE16") write_be16 :: proc(dst: ^Rw_Ops, value: u16) -> u64 ---; 502 | @(link_name="SDL_WriteBE32") write_be32 :: proc(dst: ^Rw_Ops, value: u32) -> u64 ---; 503 | @(link_name="SDL_WriteBE64") write_be64 :: proc(dst: ^Rw_Ops, value: u64) -> u64 ---; 504 | @(link_name="SDL_WriteLE16") write_le16 :: proc(dst: ^Rw_Ops, value: u16) -> u64 ---; 505 | @(link_name="SDL_WriteLE32") write_le32 :: proc(dst: ^Rw_Ops, value: u32) -> u64 ---; 506 | @(link_name="SDL_WriteLE64") write_le64 :: proc(dst: ^Rw_Ops, value: u64) -> u64 ---; 507 | @(link_name="SDL_WriteU8") write_u8 :: proc(dst: ^Rw_Ops, value: u8) -> u64 ---; 508 | } 509 | 510 | Init_Flags :: enum u32 { 511 | Timer = 0x00000001, 512 | Audio = 0x00000010, 513 | Video = 0x00000020, 514 | Joystick = 0x00000200, 515 | Haptic = 0x00001000, 516 | GameController = 0x00002000, 517 | Events = 0x00004000, 518 | NoParachute = 0x00100000, 519 | Everything = Timer | Audio | Video | Events | Joystick | Haptic | GameController, 520 | } 521 | 522 | Window_Flags :: enum u32 { 523 | Fullscreen = 0x00000001, 524 | Open_GL = 0x00000002, 525 | Shown = 0x00000004, 526 | Hidden = 0x00000008, 527 | Borderless = 0x00000010, 528 | Resizable = 0x00000020, 529 | Minimized = 0x00000040, 530 | Maximized = 0x00000080, 531 | Input_Grabbed = 0x00000100, 532 | Input_Focus = 0x00000200, 533 | Mouse_Focus = 0x00000400, 534 | Fullscreen_Desktop = Fullscreen | 0x00001000, 535 | Foreign = 0x00000800, 536 | Allow_High_DPI = 0x00002000, 537 | Mouse_Capture = 0x00004000, 538 | Always_On_Top = 0x00008000, 539 | Skip_Taskbar = 0x00010000, 540 | Utility = 0x00020000, 541 | Tooltip = 0x00040000, 542 | Popup_Menu = 0x00080000, 543 | Vulkan = 0x00100000, 544 | } 545 | 546 | Window_Pos :: enum i32 { 547 | Undefined = 0x1FFF0000, 548 | Centered = 0x2FFF0000, 549 | } 550 | 551 | Renderer_Flags :: enum u32 { 552 | Software = 0x00000001, 553 | Accelerated = 0x00000002, 554 | Present_VSync = 0x00000004, 555 | Target_Texture = 0x00000008, 556 | } 557 | 558 | Texture_Access :: enum i32 { 559 | Static = 0, 560 | Streaming, 561 | Target, 562 | } 563 | 564 | Blend_Mode :: enum i32 { 565 | None = 0x00000000, 566 | Blend = 0x00000001, 567 | Add = 0x00000002, 568 | Mod = 0x00000004, 569 | } 570 | 571 | Error_Code :: enum i32 { 572 | No_Mem, 573 | FRead, 574 | FWrite, 575 | FSeek, 576 | Unsupported, 577 | Last_Error, 578 | } 579 | 580 | Joystick_Power_Level :: enum i32 { 581 | Unknown = -1, 582 | Empty, 583 | Low, 584 | Medium, 585 | Full, 586 | Wired, 587 | Max, 588 | } 589 | 590 | Hint_Priority :: enum i32 { 591 | Default, 592 | Normal, 593 | Override, 594 | } 595 | 596 | Thread_Priority :: enum i32 { 597 | Low, 598 | Normal, 599 | High, 600 | } 601 | 602 | Assert_State :: enum i32 { 603 | Retry, 604 | Break, 605 | Abort, 606 | Ignore, 607 | Always_Ignore, 608 | } 609 | 610 | Event_Action :: enum i32 { 611 | Add_Event, 612 | Peek_Event, 613 | Get_Event, 614 | } 615 | 616 | Hit_Test_Result :: enum i32 { 617 | Normal, 618 | Draggable, 619 | Resize_Top_Left, 620 | Resize_Top, 621 | Resize_Top_Right, 622 | Resize_Right, 623 | Resize_Bottom_Right, 624 | Resize_Bottom, 625 | Resize_Bottom_Left, 626 | Resize_Left, 627 | } 628 | 629 | Bool :: enum i32 { 630 | False, 631 | True, 632 | } 633 | 634 | Window_Shape_Modes :: enum i32 { 635 | Default, 636 | Binarize_Alpha, 637 | Reverse_Binarize_Alpha, 638 | Color_Key, 639 | } 640 | 641 | Keymod :: enum i32 { 642 | None = 0x0000, 643 | LShift = 0x0001, 644 | RShift = 0x0002, 645 | LCtrl = 0x0040, 646 | RCtrl = 0x0080, 647 | LAlt = 0x0100, 648 | RAlt = 0x0200, 649 | LGui = 0x0400, 650 | RGui = 0x0800, 651 | Num = 0x1000, 652 | Caps = 0x2000, 653 | Mode = 0x4000, 654 | Reserved = 0x8000, 655 | } 656 | 657 | Renderer_Flip :: enum i32 { 658 | None = 0x00000000, 659 | Horizontal = 0x00000001, 660 | Vertical = 0x00000002, 661 | } 662 | 663 | GL_Attr :: enum i32 { 664 | Red_Size, 665 | Green_Size, 666 | Blue_Size, 667 | Alpha_Size, 668 | Buffer_Size, 669 | Doublebuffer, 670 | Depth_Size, 671 | Stencil_Size, 672 | Accum_Red_Size, 673 | Accum_Green_Size, 674 | Accum_Blue_Size, 675 | Accum_Alpha_Size, 676 | Stereo, 677 | Multisamplebuffers, 678 | Multisample_Samples, 679 | Accelerated_Visual, 680 | Retained_Backing, 681 | Context_Major_Version, 682 | Context_Minor_Version, 683 | Context_EGL, 684 | Context_Flags, 685 | Context_Profile_Mask, 686 | Share_With_Current_Context, 687 | Framebuffer_SRGB_Capable, 688 | Context_Release_Behavior, 689 | } 690 | 691 | GL_Context_Flag :: enum i32 { 692 | Debug = 0x0001, 693 | Forward_Compatible = 0x0002, 694 | Robust_Access = 0x0004, 695 | Reset_Isolation = 0x0008, 696 | } 697 | 698 | GL_Context_Profile :: enum i32 { 699 | Core = 0x0001, 700 | Compatibility = 0x0002, 701 | ES = 0x0004, 702 | } 703 | 704 | Message_Box_Color_Type :: enum i32 { 705 | Background, 706 | Text, 707 | Button_Border, 708 | Button_Background, 709 | Button_Selected, 710 | Max, 711 | } 712 | 713 | Audio_Status :: enum i32 { 714 | Stopped = 0, 715 | Playing, 716 | Paused, 717 | } 718 | 719 | Power_State :: enum i32 { 720 | Unknown, 721 | On_Battery, 722 | No_Battery, 723 | Charging, 724 | Charged, 725 | } 726 | 727 | Log_Category :: enum i32 { 728 | Application, 729 | Error, 730 | Assert, 731 | System, 732 | Audio, 733 | Video, 734 | Render, 735 | Input, 736 | Test, 737 | 738 | Custom = 19, 739 | } 740 | 741 | Log_Priority :: enum i32 { 742 | Verbose = 1, 743 | Debug, 744 | Info, 745 | Warn, 746 | Error, 747 | Critical, 748 | Num_Log_Priorities, 749 | } 750 | 751 | // Input stuff 752 | 753 | 754 | Game_Controller_Button :: enum i32 { 755 | Invalid = -1, 756 | A, 757 | B, 758 | X, 759 | Y, 760 | Back, 761 | Guide, 762 | Start, 763 | Left_Stick, 764 | Right_Stick, 765 | Left_Shoulder, 766 | Right_Shoulder, 767 | DPad_Up, 768 | DPad_Down, 769 | DPad_Left, 770 | DPad_Right, 771 | Max, 772 | } 773 | 774 | Game_Controller_Axis :: enum i32 { 775 | Invalid = -1, 776 | LeftX, 777 | LeftY, 778 | RightX, 779 | RightY, 780 | Trigger_Left, 781 | Trigger_Right, 782 | Max, 783 | } 784 | 785 | Game_Controller_Bind_Type :: enum i32 { 786 | None = 0, 787 | Button, 788 | Axis, 789 | Hat, 790 | } 791 | 792 | System_Cursor :: enum i32 { 793 | Arrow, 794 | IBeam, 795 | Wait, 796 | Crosshair, 797 | Wait_Arrow, 798 | Size_NWSE, 799 | Size_NESW, 800 | Size_WE, 801 | Size_NS, 802 | Size_All, 803 | No, 804 | Hand, 805 | Num_System_Cursors, 806 | } 807 | 808 | 809 | Scancode :: enum i32 { 810 | Unknown = 0, 811 | 812 | A = 4, 813 | B = 5, 814 | C = 6, 815 | D = 7, 816 | E = 8, 817 | F = 9, 818 | G = 10, 819 | H = 11, 820 | I = 12, 821 | J = 13, 822 | K = 14, 823 | L = 15, 824 | M = 16, 825 | N = 17, 826 | O = 18, 827 | P = 19, 828 | Q = 20, 829 | R = 21, 830 | S = 22, 831 | T = 23, 832 | U = 24, 833 | V = 25, 834 | W = 26, 835 | X = 27, 836 | Y = 28, 837 | Z = 29, 838 | 839 | // Number row 840 | Nr1 = 30, 841 | Nr2 = 31, 842 | Nr3 = 32, 843 | Nr4 = 33, 844 | Nr5 = 34, 845 | Nr6 = 35, 846 | Nr7 = 36, 847 | Nr8 = 37, 848 | Nr9 = 38, 849 | Nr0 = 39, 850 | 851 | Return = 40, 852 | Escape = 41, 853 | Backspace = 42, 854 | Tab = 43, 855 | Space = 44, 856 | 857 | Minus = 45, 858 | Equals = 46, 859 | Leftbracket = 47, 860 | Rightbracket = 48, 861 | Backslash = 49, 862 | Nonushash = 50, // ??? 863 | Semicolon = 51, 864 | Apostrophe = 52, 865 | Grave = 53, 866 | Comma = 54, 867 | Period = 55, 868 | Slash = 56, 869 | 870 | Caps_Lock = 57, 871 | 872 | F1 = 58, 873 | F2 = 59, 874 | F3 = 60, 875 | F4 = 61, 876 | F5 = 62, 877 | F6 = 63, 878 | F7 = 64, 879 | F8 = 65, 880 | F9 = 66, 881 | F10 = 67, 882 | F11 = 68, 883 | F12 = 69, 884 | 885 | Print_Screen = 70, 886 | Scroll_Lock = 71, 887 | Pause = 72, 888 | Insert = 73, 889 | Home = 74, 890 | Page_Up = 75, 891 | Delete = 76, 892 | End = 77, 893 | Page_Down = 78, 894 | Right = 79, 895 | Left = 80, 896 | Down = 81, 897 | Up = 82, 898 | 899 | Num_Lock_Clear = 83, 900 | Kp_Divide = 84, 901 | Kp_Multiply = 85, 902 | Kp_Minus = 86, 903 | Kp_Plus = 87, 904 | Kp_Enter = 88, 905 | Kp_1 = 89, 906 | Kp_2 = 90, 907 | Kp_3 = 91, 908 | Kp_4 = 92, 909 | Kp_5 = 93, 910 | Kp_6 = 94, 911 | Kp_7 = 95, 912 | Kp_8 = 96, 913 | Kp_9 = 97, 914 | Kp_0 = 98, 915 | Kp_Period = 99, 916 | 917 | Non_US_Backslash = 100, 918 | Application = 101, 919 | Power = 102, 920 | Kp_Equals = 103, 921 | F13 = 104, 922 | F14 = 105, 923 | F15 = 106, 924 | F16 = 107, 925 | F17 = 108, 926 | F18 = 109, 927 | F19 = 110, 928 | F20 = 111, 929 | F21 = 112, 930 | F22 = 113, 931 | F23 = 114, 932 | F24 = 115, 933 | Execute = 116, 934 | Help = 117, 935 | Menu = 118, 936 | Select = 119, 937 | Stop = 120, 938 | Again = 121, 939 | Undo = 122, 940 | Cut = 123, 941 | Copy = 124, 942 | Paste = 125, 943 | Find = 126, 944 | Mute = 127, 945 | Volume_Up = 128, 946 | Volume_Down = 129, 947 | Kp_Comma = 133, 948 | Kp_Equals_AS400 = 134, 949 | 950 | International1 = 135, 951 | International2 = 136, 952 | International3 = 137, 953 | International4 = 138, 954 | International5 = 139, 955 | International6 = 140, 956 | International7 = 141, 957 | International8 = 142, 958 | International9 = 143, 959 | Lang1 = 144, 960 | Lang2 = 145, 961 | Lang3 = 146, 962 | Lang4 = 147, 963 | Lang5 = 148, 964 | Lang6 = 149, 965 | Lang7 = 150, 966 | Lang8 = 151, 967 | Lang9 = 152, 968 | 969 | Alt_Erase = 153, 970 | Sys_Req = 154, 971 | Cancel = 155, 972 | Clear = 156, 973 | Prior = 157, 974 | Return2 = 158, 975 | Separator = 159, 976 | Out = 160, 977 | Oper = 161, 978 | Clear_Again = 162, 979 | Cr_Sel = 163, 980 | Ex_Sel = 164, 981 | 982 | Kp_00 = 176, 983 | Kp_000 = 177, 984 | Thousands_Separator = 178, 985 | Decimal_Separator = 179, 986 | Currency_Unit = 180, 987 | Currency_Sub_Unit = 181, 988 | Kp_Left_Paren = 182, 989 | Kp_Right_Paren = 183, 990 | Kp_Left_Brace = 184, 991 | Kp_Right_Brace = 185, 992 | Kp_Tab = 186, 993 | Kp_Backspace = 187, 994 | Kp_A = 188, 995 | Kp_B = 189, 996 | Kp_C = 190, 997 | Kp_D = 191, 998 | Kp_E = 192, 999 | Kp_F = 193, 1000 | Kp_Xor = 194, 1001 | Kp_Power = 195, 1002 | Kp_Percent = 196, 1003 | Kp_Less = 197, 1004 | Kp_Greater = 198, 1005 | Kp_Ampersand = 199, 1006 | Kp_Dbl_Ampersand = 200, 1007 | Kp_Vertical_Bar = 201, 1008 | Kp_Dbl_Vertical_Bar = 202, 1009 | Kp_Colon = 203, 1010 | Kp_Hash = 204, 1011 | Kp_Space = 205, 1012 | Kp_At = 206, 1013 | Kp_Exclam = 207, 1014 | Kp_Mem_Store = 208, 1015 | Kp_Mem_Recall = 209, 1016 | Kp_Mem_Clear = 210, 1017 | Kp_Mem_Add = 211, 1018 | Kp_Mem_Subtract = 212, 1019 | Kp_Mem_Multiply = 213, 1020 | Kp_Mem_Divide = 214, 1021 | Kp_Plus_Minus = 215, 1022 | Kp_Clear = 216, 1023 | Kp_Clear_Entry = 217, 1024 | Kp_Binary = 218, 1025 | Kp_Octal = 219, 1026 | Kp_Decimal = 220, 1027 | Kp_Hexadecimal = 221, 1028 | 1029 | LCtrl = 224, 1030 | LShift = 225, 1031 | LAlt = 226, 1032 | LGui = 227, 1033 | RCtrl = 228, 1034 | RShift = 229, 1035 | RAlt = 230, 1036 | RGui = 231, 1037 | 1038 | Mode = 257, 1039 | 1040 | Audio_Next = 258, 1041 | Audio_Prev = 259, 1042 | Audio_Stop = 260, 1043 | Audio_Play = 261, 1044 | Audio_Mute = 262, 1045 | Media_Select = 263, 1046 | WWW = 264, 1047 | Mail = 265, 1048 | Calculator = 266, 1049 | Computer = 267, 1050 | Ac_Search = 268, 1051 | Ac_Home = 269, 1052 | Ac_Back = 270, 1053 | Ac_Forward = 271, 1054 | Ac_Stop = 272, 1055 | Ac_Refresh = 273, 1056 | Ac_Bookmarks = 274, 1057 | 1058 | Brightness_Down = 275, 1059 | Brightness_Up = 276, 1060 | Display_Switch = 277, 1061 | Kb_Dillum_Toggle = 278, 1062 | Kb_Dillum_Down = 279, 1063 | Kb_Dillum_Up = 280, 1064 | Eject = 281, 1065 | Sleep = 282, 1066 | 1067 | App1 = 283, 1068 | App2 = 284, 1069 | 1070 | Num_Scancodes = 512, 1071 | } 1072 | 1073 | SDLK_UNKNOWN :: 0; 1074 | 1075 | SDLK_RETURN :: '\r'; 1076 | SDLK_ESCAPE :: '\033'; 1077 | SDLK_BACKSPACE :: '\b'; 1078 | SDLK_TAB :: '\t'; 1079 | SDLK_SPACE :: ' '; 1080 | SDLK_EXCLAIM :: '!'; 1081 | SDLK_QUOTEDBL :: '"'; 1082 | SDLK_HASH :: '#'; 1083 | SDLK_PERCENT :: '%'; 1084 | SDLK_DOLLAR :: '$'; 1085 | SDLK_AMPERSAND :: '&'; 1086 | SDLK_QUOTE :: '\''; 1087 | SDLK_LEFTPAREN :: '('; 1088 | SDLK_RIGHTPAREN :: ')'; 1089 | SDLK_ASTERISK :: '*'; 1090 | SDLK_PLUS :: '+'; 1091 | SDLK_COMMA :: ','; 1092 | SDLK_MINUS :: '-'; 1093 | SDLK_PERIOD :: '.'; 1094 | SDLK_SLASH :: '/'; 1095 | SDLK_0 :: '0'; 1096 | SDLK_1 :: '1'; 1097 | SDLK_2 :: '2'; 1098 | SDLK_3 :: '3'; 1099 | SDLK_4 :: '4'; 1100 | SDLK_5 :: '5'; 1101 | SDLK_6 :: '6'; 1102 | SDLK_7 :: '7'; 1103 | SDLK_8 :: '8'; 1104 | SDLK_9 :: '9'; 1105 | SDLK_COLON :: ':'; 1106 | SDLK_SEMICOLON :: ';'; 1107 | SDLK_LESS :: '<'; 1108 | SDLK_EQUALS :: '='; 1109 | SDLK_GREATER :: '>'; 1110 | SDLK_QUESTION :: '?'; 1111 | SDLK_AT :: '@'; 1112 | 1113 | SDLK_LEFTBRACKET :: '['; 1114 | SDLK_BACKSLASH :: '\\'; 1115 | SDLK_RIGHTBRACKET :: ']'; 1116 | SDLK_CARET :: '^'; 1117 | SDLK_UNDERSCORE :: '_'; 1118 | SDLK_BACKQUOTE :: '`'; 1119 | SDLK_a :: 'a'; 1120 | SDLK_b :: 'b'; 1121 | SDLK_c :: 'c'; 1122 | SDLK_d :: 'd'; 1123 | SDLK_e :: 'e'; 1124 | SDLK_f :: 'f'; 1125 | SDLK_g :: 'g'; 1126 | SDLK_h :: 'h'; 1127 | SDLK_i :: 'i'; 1128 | SDLK_j :: 'j'; 1129 | SDLK_k :: 'k'; 1130 | SDLK_l :: 'l'; 1131 | SDLK_m :: 'm'; 1132 | SDLK_n :: 'n'; 1133 | SDLK_o :: 'o'; 1134 | SDLK_p :: 'p'; 1135 | SDLK_q :: 'q'; 1136 | SDLK_r :: 'r'; 1137 | SDLK_s :: 's'; 1138 | SDLK_t :: 't'; 1139 | SDLK_u :: 'u'; 1140 | SDLK_v :: 'v'; 1141 | SDLK_w :: 'w'; 1142 | SDLK_x :: 'x'; 1143 | SDLK_y :: 'y'; 1144 | SDLK_z :: 'z'; 1145 | 1146 | SDLK_CAPSLOCK :: Scancode.Caps_Lock | SDLK_SCANCODE_MASK; 1147 | 1148 | SDLK_F1 :: Scancode.F1 | SDLK_SCANCODE_MASK; 1149 | SDLK_F2 :: Scancode.F2 | SDLK_SCANCODE_MASK; 1150 | SDLK_F3 :: Scancode.F3 | SDLK_SCANCODE_MASK; 1151 | SDLK_F4 :: Scancode.F4 | SDLK_SCANCODE_MASK; 1152 | SDLK_F5 :: Scancode.F5 | SDLK_SCANCODE_MASK; 1153 | SDLK_F6 :: Scancode.F6 | SDLK_SCANCODE_MASK; 1154 | SDLK_F7 :: Scancode.F7 | SDLK_SCANCODE_MASK; 1155 | SDLK_F8 :: Scancode.F8 | SDLK_SCANCODE_MASK; 1156 | SDLK_F9 :: Scancode.F9 | SDLK_SCANCODE_MASK; 1157 | SDLK_F10 :: Scancode.F10 | SDLK_SCANCODE_MASK; 1158 | SDLK_F11 :: Scancode.F11 | SDLK_SCANCODE_MASK; 1159 | SDLK_F12 :: Scancode.F12 | SDLK_SCANCODE_MASK; 1160 | 1161 | SDLK_PRINTSCREEN :: Scancode.Print_Screen | SDLK_SCANCODE_MASK; 1162 | SDLK_SCROLLLOCK :: Scancode.Scroll_Lock | SDLK_SCANCODE_MASK; 1163 | SDLK_PAUSE :: Scancode.Pause | SDLK_SCANCODE_MASK; 1164 | SDLK_INSERT :: Scancode.Insert | SDLK_SCANCODE_MASK; 1165 | SDLK_HOME :: Scancode.Home | SDLK_SCANCODE_MASK; 1166 | SDLK_PAGEUP :: Scancode.Page_Up | SDLK_SCANCODE_MASK; 1167 | SDLK_DELETE :: '\177'; 1168 | SDLK_END :: Scancode.End | SDLK_SCANCODE_MASK; 1169 | SDLK_PAGEDOWN :: Scancode.Page_Down | SDLK_SCANCODE_MASK; 1170 | SDLK_RIGHT :: Scancode.Right | SDLK_SCANCODE_MASK; 1171 | SDLK_LEFT :: Scancode.Left | SDLK_SCANCODE_MASK; 1172 | SDLK_DOWN :: Scancode.Down | SDLK_SCANCODE_MASK; 1173 | SDLK_UP :: Scancode.Up | SDLK_SCANCODE_MASK; 1174 | 1175 | SDLK_NUMLOCKCLEAR :: Scancode.Num_Lock_Clear | SDLK_SCANCODE_MASK; 1176 | SDLK_KP_DIVIDE :: Scancode.Kp_Divide | SDLK_SCANCODE_MASK; 1177 | SDLK_KP_MULTIPLY :: Scancode.Kp_Multiply | SDLK_SCANCODE_MASK; 1178 | SDLK_KP_MINUS :: Scancode.Kp_Minus | SDLK_SCANCODE_MASK; 1179 | SDLK_KP_PLUS :: Scancode.Kp_Plus | SDLK_SCANCODE_MASK; 1180 | SDLK_KP_ENTER :: Scancode.Kp_Enter | SDLK_SCANCODE_MASK; 1181 | SDLK_KP_1 :: Scancode.Kp_1 | SDLK_SCANCODE_MASK; 1182 | SDLK_KP_2 :: Scancode.Kp_2 | SDLK_SCANCODE_MASK; 1183 | SDLK_KP_3 :: Scancode.Kp_3 | SDLK_SCANCODE_MASK; 1184 | SDLK_KP_4 :: Scancode.Kp_4 | SDLK_SCANCODE_MASK; 1185 | SDLK_KP_5 :: Scancode.Kp_5 | SDLK_SCANCODE_MASK; 1186 | SDLK_KP_6 :: Scancode.Kp_6 | SDLK_SCANCODE_MASK; 1187 | SDLK_KP_7 :: Scancode.Kp_7 | SDLK_SCANCODE_MASK; 1188 | SDLK_KP_8 :: Scancode.Kp_8 | SDLK_SCANCODE_MASK; 1189 | SDLK_KP_9 :: Scancode.Kp_9 | SDLK_SCANCODE_MASK; 1190 | SDLK_KP_0 :: Scancode.Kp_0 | SDLK_SCANCODE_MASK; 1191 | SDLK_KP_PERIOD :: Scancode.Kp_Period | SDLK_SCANCODE_MASK; 1192 | 1193 | SDLK_APPLICATION :: Scancode.Application | SDLK_SCANCODE_MASK; 1194 | SDLK_POWER :: Scancode.Power | SDLK_SCANCODE_MASK; 1195 | SDLK_KP_EQUALS :: Scancode.Kp_Equals | SDLK_SCANCODE_MASK; 1196 | SDLK_F13 :: Scancode.F13 | SDLK_SCANCODE_MASK; 1197 | SDLK_F14 :: Scancode.F14 | SDLK_SCANCODE_MASK; 1198 | SDLK_F15 :: Scancode.F15 | SDLK_SCANCODE_MASK; 1199 | SDLK_F16 :: Scancode.F16 | SDLK_SCANCODE_MASK; 1200 | SDLK_F17 :: Scancode.F17 | SDLK_SCANCODE_MASK; 1201 | SDLK_F18 :: Scancode.F18 | SDLK_SCANCODE_MASK; 1202 | SDLK_F19 :: Scancode.F19 | SDLK_SCANCODE_MASK; 1203 | SDLK_F20 :: Scancode.F20 | SDLK_SCANCODE_MASK; 1204 | SDLK_F21 :: Scancode.F21 | SDLK_SCANCODE_MASK; 1205 | SDLK_F22 :: Scancode.F22 | SDLK_SCANCODE_MASK; 1206 | SDLK_F23 :: Scancode.F23 | SDLK_SCANCODE_MASK; 1207 | SDLK_F24 :: Scancode.F24 | SDLK_SCANCODE_MASK; 1208 | SDLK_EXECUTE :: Scancode.Execute | SDLK_SCANCODE_MASK; 1209 | SDLK_HELP :: Scancode.Help | SDLK_SCANCODE_MASK; 1210 | SDLK_MENU :: Scancode.Menu | SDLK_SCANCODE_MASK; 1211 | SDLK_SELECT :: Scancode.Select | SDLK_SCANCODE_MASK; 1212 | SDLK_STOP :: Scancode.Stop | SDLK_SCANCODE_MASK; 1213 | SDLK_AGAIN :: Scancode.Again | SDLK_SCANCODE_MASK; 1214 | SDLK_UNDO :: Scancode.Undo | SDLK_SCANCODE_MASK; 1215 | SDLK_CUT :: Scancode.Cut | SDLK_SCANCODE_MASK; 1216 | SDLK_COPY :: Scancode.Copy | SDLK_SCANCODE_MASK; 1217 | SDLK_PASTE :: Scancode.Paste | SDLK_SCANCODE_MASK; 1218 | SDLK_FIND :: Scancode.Find | SDLK_SCANCODE_MASK; 1219 | SDLK_MUTE :: Scancode.Mute | SDLK_SCANCODE_MASK; 1220 | SDLK_VOLUMEUP :: Scancode.Volume_Up | SDLK_SCANCODE_MASK; 1221 | SDLK_VOLUMEDOWN :: Scancode.Volume_Down | SDLK_SCANCODE_MASK; 1222 | SDLK_KP_COMMA :: Scancode.Kp_Comma | SDLK_SCANCODE_MASK; 1223 | SDLK_KP_EQUALSAS400 :: Scancode.Kp_Equals_AS400 | SDLK_SCANCODE_MASK; 1224 | 1225 | SDLK_ALTERASE :: Scancode.Alt_Erase | SDLK_SCANCODE_MASK; 1226 | SDLK_SYSREQ :: Scancode.Sys_Req | SDLK_SCANCODE_MASK; 1227 | SDLK_CANCEL :: Scancode.Cancel | SDLK_SCANCODE_MASK; 1228 | SDLK_CLEAR :: Scancode.Clear | SDLK_SCANCODE_MASK; 1229 | SDLK_PRIOR :: Scancode.Prior | SDLK_SCANCODE_MASK; 1230 | SDLK_RETURN2 :: Scancode.Return2 | SDLK_SCANCODE_MASK; 1231 | SDLK_SEPARATOR :: Scancode.Separator | SDLK_SCANCODE_MASK; 1232 | SDLK_OUT :: Scancode.Out | SDLK_SCANCODE_MASK; 1233 | SDLK_OPER :: Scancode.Oper | SDLK_SCANCODE_MASK; 1234 | SDLK_CLEARAGAIN :: Scancode.Clear_Again | SDLK_SCANCODE_MASK; 1235 | SDLK_CRSEL :: Scancode.Cr_Sel | SDLK_SCANCODE_MASK; 1236 | SDLK_EXSEL :: Scancode.Ex_Sel | SDLK_SCANCODE_MASK; 1237 | 1238 | SDLK_KP_00 :: Scancode.Kp_00 | SDLK_SCANCODE_MASK; 1239 | SDLK_KP_000 :: Scancode.Kp_000 | SDLK_SCANCODE_MASK; 1240 | SDLK_THOUSANDSSEPARATOR :: Scancode.Thousands_Separator | SDLK_SCANCODE_MASK; 1241 | SDLK_DECIMALSEPARATOR :: Scancode.Decimal_Separator | SDLK_SCANCODE_MASK; 1242 | SDLK_CURRENCYUNIT :: Scancode.Currency_Unit | SDLK_SCANCODE_MASK; 1243 | SDLK_CURRENCYSUBUNIT :: Scancode.Currency_Sub_Unit | SDLK_SCANCODE_MASK; 1244 | SDLK_KP_LEFTPAREN :: Scancode.Kp_Left_Paren | SDLK_SCANCODE_MASK; 1245 | SDLK_KP_RIGHTPAREN :: Scancode.Kp_Right_Paren | SDLK_SCANCODE_MASK; 1246 | SDLK_KP_LEFTBRACE :: Scancode.Kp_Left_Brace | SDLK_SCANCODE_MASK; 1247 | SDLK_KP_RIGHTBRACE :: Scancode.Kp_Right_Brace | SDLK_SCANCODE_MASK; 1248 | SDLK_KP_TAB :: Scancode.Kp_Tab | SDLK_SCANCODE_MASK; 1249 | SDLK_KP_BACKSPACE :: Scancode.Kp_Backspace | SDLK_SCANCODE_MASK; 1250 | SDLK_KP_A :: Scancode.Kp_A | SDLK_SCANCODE_MASK; 1251 | SDLK_KP_B :: Scancode.Kp_B | SDLK_SCANCODE_MASK; 1252 | SDLK_KP_C :: Scancode.Kp_C | SDLK_SCANCODE_MASK; 1253 | SDLK_KP_D :: Scancode.Kp_D | SDLK_SCANCODE_MASK; 1254 | SDLK_KP_E :: Scancode.Kp_E | SDLK_SCANCODE_MASK; 1255 | SDLK_KP_F :: Scancode.Kp_F | SDLK_SCANCODE_MASK; 1256 | SDLK_KP_XOR :: Scancode.Kp_Xor | SDLK_SCANCODE_MASK; 1257 | SDLK_KP_POWER :: Scancode.Kp_Power | SDLK_SCANCODE_MASK; 1258 | SDLK_KP_PERCENT :: Scancode.Kp_Percent | SDLK_SCANCODE_MASK; 1259 | SDLK_KP_LESS :: Scancode.Kp_Less | SDLK_SCANCODE_MASK; 1260 | SDLK_KP_GREATER :: Scancode.Kp_Greater | SDLK_SCANCODE_MASK; 1261 | SDLK_KP_AMPERSAND :: Scancode.Kp_Ampersand | SDLK_SCANCODE_MASK; 1262 | SDLK_KP_DBLAMPERSAND :: Scancode.Kp_Dbl_Ampersand | SDLK_SCANCODE_MASK; 1263 | SDLK_KP_VERTICALBAR :: Scancode.Kp_Vertical_Bar | SDLK_SCANCODE_MASK; 1264 | SDLK_KP_DBLVERTICALBAR :: Scancode.Kp_Dbl_Vertical_Bar | SDLK_SCANCODE_MASK; 1265 | SDLK_KP_COLON :: Scancode.Kp_Colon | SDLK_SCANCODE_MASK; 1266 | SDLK_KP_HASH :: Scancode.Kp_Hash | SDLK_SCANCODE_MASK; 1267 | SDLK_KP_SPACE :: Scancode.Kp_Space | SDLK_SCANCODE_MASK; 1268 | SDLK_KP_AT :: Scancode.Kp_At | SDLK_SCANCODE_MASK; 1269 | SDLK_KP_EXCLAM :: Scancode.Kp_Exclam | SDLK_SCANCODE_MASK; 1270 | SDLK_KP_MEMSTORE :: Scancode.Kp_Mem_Store | SDLK_SCANCODE_MASK; 1271 | SDLK_KP_MEMRECALL :: Scancode.Kp_Mem_Recall | SDLK_SCANCODE_MASK; 1272 | SDLK_KP_MEMCLEAR :: Scancode.Kp_Mem_Clear | SDLK_SCANCODE_MASK; 1273 | SDLK_KP_MEMADD :: Scancode.Kp_Mem_Add | SDLK_SCANCODE_MASK; 1274 | SDLK_KP_MEMSUBTRACT :: Scancode.Kp_Mem_Subtract | SDLK_SCANCODE_MASK; 1275 | SDLK_KP_MEMMULTIPLY :: Scancode.Kp_Mem_Multiply | SDLK_SCANCODE_MASK; 1276 | SDLK_KP_MEMDIVIDE :: Scancode.Kp_Mem_Divide | SDLK_SCANCODE_MASK; 1277 | SDLK_KP_PLUSMINUS :: Scancode.Kp_Plus_Minus | SDLK_SCANCODE_MASK; 1278 | SDLK_KP_CLEAR :: Scancode.Kp_Clear | SDLK_SCANCODE_MASK; 1279 | SDLK_KP_CLEARENTRY :: Scancode.Kp_Clear_Entry | SDLK_SCANCODE_MASK; 1280 | SDLK_KP_BINARY :: Scancode.Kp_Binary | SDLK_SCANCODE_MASK; 1281 | SDLK_KP_OCTAL :: Scancode.Kp_Octal | SDLK_SCANCODE_MASK; 1282 | SDLK_KP_DECIMAL :: Scancode.Kp_Decimal | SDLK_SCANCODE_MASK; 1283 | SDLK_KP_HEXADECIMAL :: Scancode.Kp_Hexadecimal | SDLK_SCANCODE_MASK; 1284 | 1285 | SDLK_LCTRL :: Scancode.LCtrl | SDLK_SCANCODE_MASK; 1286 | SDLK_LSHIFT :: Scancode.LShift | SDLK_SCANCODE_MASK; 1287 | SDLK_LALT :: Scancode.LAlt | SDLK_SCANCODE_MASK; 1288 | SDLK_LGUI :: Scancode.LGui | SDLK_SCANCODE_MASK; 1289 | SDLK_RCTRL :: Scancode.RCtrl | SDLK_SCANCODE_MASK; 1290 | SDLK_RSHIFT :: Scancode.RShift | SDLK_SCANCODE_MASK; 1291 | SDLK_RALT :: Scancode.RAlt | SDLK_SCANCODE_MASK; 1292 | SDLK_RGUI :: Scancode.RGui | SDLK_SCANCODE_MASK; 1293 | 1294 | SDLK_MODE :: Scancode.Mode | SDLK_SCANCODE_MASK; 1295 | 1296 | SDLK_AUDIONEXT :: Scancode.Audio_Next | SDLK_SCANCODE_MASK; 1297 | SDLK_AUDIOPREV :: Scancode.Audio_Prev | SDLK_SCANCODE_MASK; 1298 | SDLK_AUDIOSTOP :: Scancode.Audio_Stop | SDLK_SCANCODE_MASK; 1299 | SDLK_AUDIOPLAY :: Scancode.Audio_Play | SDLK_SCANCODE_MASK; 1300 | SDLK_AUDIOMUTE :: Scancode.Audio_Mute | SDLK_SCANCODE_MASK; 1301 | SDLK_MEDIASELECT :: Scancode.Media_Select | SDLK_SCANCODE_MASK; 1302 | SDLK_WWW :: Scancode.WWW | SDLK_SCANCODE_MASK; 1303 | SDLK_MAIL :: Scancode.Mail | SDLK_SCANCODE_MASK; 1304 | SDLK_CALCULATOR :: Scancode.Calculator | SDLK_SCANCODE_MASK; 1305 | SDLK_COMPUTER :: Scancode.Computer | SDLK_SCANCODE_MASK; 1306 | SDLK_AC_SEARCH :: Scancode.Ac_Search | SDLK_SCANCODE_MASK; 1307 | SDLK_AC_HOME :: Scancode.Ac_Home | SDLK_SCANCODE_MASK; 1308 | SDLK_AC_BACK :: Scancode.Ac_Back | SDLK_SCANCODE_MASK; 1309 | SDLK_AC_FORWARD :: Scancode.Ac_Forward | SDLK_SCANCODE_MASK; 1310 | SDLK_AC_STOP :: Scancode.Ac_Stop | SDLK_SCANCODE_MASK; 1311 | SDLK_AC_REFRESH :: Scancode.Ac_Refresh | SDLK_SCANCODE_MASK; 1312 | SDLK_AC_BOOKMARKS :: Scancode.Ac_Bookmarks | SDLK_SCANCODE_MASK; 1313 | 1314 | SDLK_BRIGHTNESSDOWN :: Scancode.Brightness_Down | SDLK_SCANCODE_MASK; 1315 | SDLK_BRIGHTNESSUP :: Scancode.Brightness_Up | SDLK_SCANCODE_MASK; 1316 | SDLK_DISPLAYSWITCH :: Scancode.Display_Switch | SDLK_SCANCODE_MASK; 1317 | SDLK_KBDILLUMTOGGLE :: Scancode.Kb_Dillum_Toggle | SDLK_SCANCODE_MASK; 1318 | SDLK_KBDILLUMDOWN :: Scancode.Kb_Dillum_Down | SDLK_SCANCODE_MASK; 1319 | SDLK_KBDILLUMUP :: Scancode.Kb_Dillum_Up | SDLK_SCANCODE_MASK; 1320 | SDLK_EJECT :: Scancode.Eject | SDLK_SCANCODE_MASK; 1321 | SDLK_SLEEP :: Scancode.Sleep | SDLK_SCANCODE_MASK; 1322 | 1323 | SDLK_SCANCODE_MASK :: Scancode(1<<30); 1324 | 1325 | Mousecode :: enum i32 { 1326 | Left = 1 << 0, 1327 | Middle = 1 << 1, 1328 | Right = 1 << 2, 1329 | X1 = 1 << 3, 1330 | X2 = 1 << 4, 1331 | } 1332 | 1333 | 1334 | Hat :: enum i32 { 1335 | Centered = 0x00, 1336 | Up = 0x01, 1337 | Right = 0x02, 1338 | Down = 0x04, 1339 | Left = 0x08, 1340 | Right_Up = Right | Up, 1341 | Right_Down = Right | Down, 1342 | Left_Up = Left | Up, 1343 | Left_Down = Left | Down, 1344 | } 1345 | 1346 | Event_Type :: enum u32 { 1347 | First_Event = 0, 1348 | 1349 | Quit = 0x100, 1350 | 1351 | App_Terminating = 257, 1352 | App_Low_Memory = 258, 1353 | App_Will_Enter_Background = 259, 1354 | App_Did_Enter_Background = 260, 1355 | App_Will_Enter_Foreground = 261, 1356 | App_Did_Enter_Foreground = 262, 1357 | 1358 | Window_Event = 0x200, 1359 | Sys_Wm_Event = 513, 1360 | 1361 | Key_Down = 0x300, 1362 | Key_Up = 769, 1363 | Text_Editing = 770, 1364 | Text_Input = 771, 1365 | Key_Map_Changed = 772, 1366 | 1367 | Mouse_Motion = 0x400, 1368 | Mouse_Button_Down = 1025, 1369 | Mouse_Button_Up = 1026, 1370 | Mouse_Wheel = 1027, 1371 | 1372 | Joy_Axis_Motion = 0x600, 1373 | Joy_Ball_Motion = 1537, 1374 | Joy_Hat_Motion = 1538, 1375 | Joy_Button_Down = 1539, 1376 | Joy_Button_Up = 1540, 1377 | Joy_Device_Added = 1541, 1378 | Joy_Device_Removed = 1542, 1379 | 1380 | Controller_Axis_Motion = 0x650, 1381 | Controller_Button_Down = 1617, 1382 | Controller_Button_Up = 1618, 1383 | Controller_Device_Added = 1619, 1384 | Controller_Device_Removed = 1620, 1385 | Controller_Device_Remapped = 1621, 1386 | 1387 | Finger_Down = 0x700, 1388 | Finger_Up = 1793, 1389 | Finger_Motion = 1794, 1390 | 1391 | Dollar_Gesture = 0x800, 1392 | Dollar_Record = 2049, 1393 | Multigesture = 2050, 1394 | 1395 | Clipboard_Update = 0x900, 1396 | 1397 | Drop_File = 0x1000, 1398 | Drop_Text = 4097, 1399 | Drop_Begin = 4098, 1400 | Drop_Complete = 4099, 1401 | 1402 | Audio_Device_Added = 0x1100, 1403 | Audio_Device_Removed = 4353, 1404 | 1405 | Render_Targets_Reset = 0x2000, 1406 | Render_Device_Reset = 8193, 1407 | 1408 | User_Event = 0x8000, 1409 | 1410 | Last_Event = 0xFFFF, 1411 | } 1412 | 1413 | Window_Event_ID :: enum u8 { 1414 | None = 0, 1415 | Shown, 1416 | Hidden, 1417 | Exposed, 1418 | Moved, 1419 | Resized, 1420 | Size_Changed, 1421 | Minimized, 1422 | Maximized, 1423 | Restored, 1424 | Enter, 1425 | Leave, 1426 | Focus_Gained, 1427 | Focus_Lost, 1428 | Close, 1429 | Take_Focus, 1430 | Hit_Test, 1431 | } 1432 | 1433 | GL_Context :: rawptr; 1434 | 1435 | Blit_Map :: struct {}; 1436 | Window :: struct {}; 1437 | Renderer :: struct {}; 1438 | Texture :: struct {}; 1439 | Cond :: struct {}; 1440 | Mutex :: struct {}; 1441 | Sem :: struct {}; 1442 | Thread :: struct {}; 1443 | Haptic :: struct {}; 1444 | Joystick :: struct {}; 1445 | Game_Controller :: struct {}; 1446 | Cursor :: struct {}; 1447 | IDirect3D_Device9 :: struct {}; 1448 | Rw_Ops :: struct {}; 1449 | 1450 | // Unsure of these 1451 | Sys_Wm_Info :: struct {}; 1452 | Sys_Wm_Msg :: struct {}; 1453 | 1454 | Joystick_Id :: i32; 1455 | Timer_Id :: i32; 1456 | Spin_Lock :: i32; 1457 | Tls_Id :: u32; 1458 | Audio_Device_Id :: u32; 1459 | Audio_Device :: u32; 1460 | Audio_Format :: u16; 1461 | Keycode :: i32; 1462 | Thread_Id :: u64; 1463 | Touch_Id :: i64; 1464 | Gesture_Id :: i64; 1465 | Finger_Id :: i64; 1466 | 1467 | Hint_Callback :: proc "c" (interval: u32, param: rawptr) -> u32; 1468 | Event_Filter :: proc "c" (userdata: rawptr, param: ^Event) -> i32; 1469 | Timer_Callback :: proc "c" (interval: u32, param: rawptr) -> u32; 1470 | Audio_Callback :: proc "c" (userdata: rawptr, stream: ^u8, len: i32); 1471 | Assertion_Handler :: proc "c" (data: ^Assert_Data, userdata: rawptr) -> Assert_State; 1472 | Audio_Filter :: proc "c" (cvt: ^Audio_Cvt, format: Audio_Format); 1473 | Thread_Function :: proc "c" (data: rawptr) -> i32; 1474 | Hit_Test :: proc "c" (window: ^Window, area: ^Point, data: rawptr) -> Hit_Test_Result; 1475 | Windows_Message_Hook :: proc "c" (userdata: rawptr, hwnd: rawptr, message: u32, wparam: u64, lparam: i64); 1476 | Log_Output_Function :: proc "c" (userdata: rawptr, category: Log_Category, priority: Log_Priority, message: cstring); 1477 | 1478 | // Thanks gingerBill for this one! 1479 | Game_Controller_Button_Bind :: struct { 1480 | bind_type: Game_Controller_Bind_Type, 1481 | value: struct #raw_union { 1482 | button: i32, 1483 | axis: i32, 1484 | using hat_mask: struct { 1485 | hat, mask: i32, 1486 | }, 1487 | }, 1488 | } 1489 | 1490 | Message_Box_Data :: struct { 1491 | flags: u32, 1492 | window: ^Window, 1493 | title: cstring, 1494 | message: cstring, 1495 | 1496 | num_buttons: i32, 1497 | buttons: ^Message_Box_Button_Data, 1498 | 1499 | color_scheme: ^Message_Box_Color_Scheme, 1500 | } 1501 | 1502 | Message_Box_Button_Data :: struct { 1503 | flags: u32, 1504 | button_id: i32, 1505 | text: cstring, 1506 | } 1507 | 1508 | Message_Box_Color_Scheme :: struct { 1509 | colors: [Message_Box_Color_Type.Max]Message_Box_Color, 1510 | } 1511 | 1512 | Message_Box_Color :: struct { 1513 | r, g, b: u8, 1514 | } 1515 | 1516 | Assert_Data :: struct { 1517 | always_ignore: i32, 1518 | trigger_count: u32, 1519 | condition: cstring, 1520 | filename: cstring, 1521 | linenum: i32, 1522 | function: cstring, 1523 | next: ^Assert_Data, 1524 | } 1525 | 1526 | Window_Shape_Params :: struct #raw_union { 1527 | binarization_cutoff: u8, 1528 | color_key: Color, 1529 | } 1530 | 1531 | Window_Shape_Mode :: struct { 1532 | mode: Window_Shape_Modes, 1533 | parameters: Window_Shape_Params, 1534 | } 1535 | 1536 | Point :: struct { 1537 | x: i32, 1538 | y: i32, 1539 | } 1540 | 1541 | Renderer_Info :: struct { 1542 | name: cstring, 1543 | flags: u32, 1544 | num_texture_formats: u32, 1545 | texture_formats: [16]u32, 1546 | max_texture_width: i32, 1547 | max_texture_height: i32, 1548 | } 1549 | 1550 | Version :: struct { 1551 | major: u8, 1552 | minor: u8, 1553 | patch: u8, 1554 | } 1555 | 1556 | Display_Mode :: struct { 1557 | format: u32, 1558 | w: i32, 1559 | h: i32, 1560 | refresh_rate: i32, 1561 | driver_data: rawptr, 1562 | } 1563 | 1564 | Finger :: struct { 1565 | id: Finger_Id, 1566 | x: f32, 1567 | y: f32, 1568 | pressure: f32, 1569 | } 1570 | 1571 | Audio_Spec :: struct { 1572 | freq: i32, 1573 | format: Audio_Format, 1574 | channels: u8, 1575 | silence: u8, 1576 | samples: u16, 1577 | padding: u16, 1578 | size: u32, 1579 | callback: Audio_Callback, 1580 | userdata: rawptr, 1581 | } 1582 | 1583 | Joystick_Guid :: struct { 1584 | data: [16]u8, 1585 | } 1586 | 1587 | Audio_Cvt :: struct { 1588 | needed: i32, 1589 | src_format: Audio_Format, 1590 | dst_format: Audio_Format, 1591 | rate_incr: i64, 1592 | buf: ^u8, 1593 | len: i32, 1594 | len_cvt: i32, 1595 | len_mult: i32, 1596 | len_ratio: i64, 1597 | filters: [10]Audio_Filter, 1598 | filter_index: i32, 1599 | } 1600 | 1601 | Surface :: struct { 1602 | flags: u32, 1603 | format: ^Pixel_Format, 1604 | w, h: i32, 1605 | pitch: i32, 1606 | pixels: rawptr, 1607 | 1608 | userdata: rawptr, 1609 | 1610 | locked: i32, 1611 | lock_data: rawptr, 1612 | 1613 | clip_rect: Rect, 1614 | blip_map: ^Blit_Map, 1615 | 1616 | refcount: i32, 1617 | } 1618 | 1619 | Color :: struct { 1620 | r: u8, 1621 | g: u8, 1622 | b: u8, 1623 | a: u8, 1624 | } 1625 | 1626 | Palette :: struct { 1627 | num_colors: i32, 1628 | colors: ^Color, 1629 | version: u32, 1630 | ref_count: i32, 1631 | } 1632 | 1633 | Pixel_Type :: enum u32 { 1634 | UNKNOWN, 1635 | INDEX1, 1636 | INDEX4, 1637 | INDEX8, 1638 | PACKED8, 1639 | PACKED16, 1640 | PACKED32, 1641 | ARRAYU8, 1642 | ARRAYU16, 1643 | ARRAYU32, 1644 | ARRAYF16, 1645 | ARRAYF32, 1646 | } 1647 | 1648 | Bitmap_Order :: enum u32 { 1649 | NONE, 1650 | _4321, 1651 | _1234, 1652 | } 1653 | 1654 | Packed_Order :: enum u32 { 1655 | NONE, 1656 | XRGB, 1657 | RGBX, 1658 | ARGB, 1659 | RGBA, 1660 | XBGR, 1661 | BGRX, 1662 | ABGR, 1663 | BGRA, 1664 | } 1665 | 1666 | Array_Order :: enum { 1667 | NONE, 1668 | RGB, 1669 | RGBA, 1670 | ARGB, 1671 | BGR, 1672 | BGRA, 1673 | ABGR, 1674 | } 1675 | 1676 | Packed_Layout :: enum u32 { 1677 | NONE, 1678 | _332, 1679 | _4444, 1680 | _1555, 1681 | _5551, 1682 | _565, 1683 | _8888, 1684 | _2101010, 1685 | _1010102, 1686 | } 1687 | 1688 | pixel_format_enum_to_u32 :: proc(e: Pixel_Format_Enum) -> u32 { 1689 | _pack_fourcc :: #force_inline proc (a, b, c, d: u8) -> u32 { 1690 | return (u32(a) << 0) | (u32(b) << 8) | (u32(c) << 16) | (u32(d) << 24); 1691 | } 1692 | _pack_pixelformat :: #force_inline proc(auto_cast type, order, layout, bits, bytes: u32) -> u32 { 1693 | return ((1 << 28) | (u32(type) << 24) | (order << 20) | (layout << 16) | (bits << 8) | (bytes << 0)); 1694 | } 1695 | switch e { 1696 | case .INDEX1LSB: return _pack_pixelformat(Pixel_Type.INDEX1, Bitmap_Order._4321, Packed_Layout.NONE, 1, 0); 1697 | case .INDEX1MSB: return _pack_pixelformat(Pixel_Type.INDEX1, Bitmap_Order._1234, Packed_Layout.NONE, 1, 0); 1698 | case .INDEX4LSB: return _pack_pixelformat(Pixel_Type.INDEX4, Bitmap_Order._4321, Packed_Layout.NONE, 4, 0); 1699 | case .INDEX4MSB: return _pack_pixelformat(Pixel_Type.INDEX4, Bitmap_Order._1234, Packed_Layout.NONE, 4, 0); 1700 | case .INDEX8: return _pack_pixelformat(Pixel_Type.INDEX8, Packed_Order.NONE, Packed_Layout.NONE, 8, 1); 1701 | case .RGB332: return _pack_pixelformat(Pixel_Type.PACKED8, Packed_Order.XRGB, Packed_Layout._332, 8, 1); 1702 | case .RGB444: return _pack_pixelformat(Pixel_Type.PACKED16, Packed_Order.XRGB, Packed_Layout._4444, 12, 2); 1703 | case .BGR444: return _pack_pixelformat(Pixel_Type.PACKED16, Packed_Order.XBGR, Packed_Layout._4444, 12, 2); 1704 | case .RGB555: return _pack_pixelformat(Pixel_Type.PACKED16, Packed_Order.XRGB, Packed_Layout._1555, 15, 2); 1705 | case .BGR555: return _pack_pixelformat(Pixel_Type.PACKED16, Packed_Order.XBGR, Packed_Layout._1555, 15, 2); 1706 | case .ARGB4444: return _pack_pixelformat(Pixel_Type.PACKED16, Packed_Order.ARGB, Packed_Layout._4444, 16, 2); 1707 | case .RGBA4444: return _pack_pixelformat(Pixel_Type.PACKED16, Packed_Order.RGBA, Packed_Layout._4444, 16, 2); 1708 | case .ABGR4444: return _pack_pixelformat(Pixel_Type.PACKED16, Packed_Order.ABGR, Packed_Layout._4444, 16, 2); 1709 | case .BGRA4444: return _pack_pixelformat(Pixel_Type.PACKED16, Packed_Order.BGRA, Packed_Layout._4444, 16, 2); 1710 | case .ARGB1555: return _pack_pixelformat(Pixel_Type.PACKED16, Packed_Order.ARGB, Packed_Layout._1555, 16, 2); 1711 | case .RGBA5551: return _pack_pixelformat(Pixel_Type.PACKED16, Packed_Order.RGBA, Packed_Layout._5551, 16, 2); 1712 | case .ABGR1555: return _pack_pixelformat(Pixel_Type.PACKED16, Packed_Order.ABGR, Packed_Layout._1555, 16, 2); 1713 | case .BGRA5551: return _pack_pixelformat(Pixel_Type.PACKED16, Packed_Order.BGRA, Packed_Layout._5551, 16, 2); 1714 | case .RGB565: return _pack_pixelformat(Pixel_Type.PACKED16, Packed_Order.XRGB, Packed_Layout._565, 16, 2); 1715 | case .BGR565: return _pack_pixelformat(Pixel_Type.PACKED16, Packed_Order.XBGR, Packed_Layout._565, 16, 2); 1716 | case .RGB24: return _pack_pixelformat(Pixel_Type.ARRAYU8, Array_Order.RGB, Packed_Layout.NONE, 24, 3); 1717 | case .BGR24: return _pack_pixelformat(Pixel_Type.ARRAYU8, Array_Order.BGR, Packed_Layout.NONE, 24, 3); 1718 | case .RGB888: return _pack_pixelformat(Pixel_Type.PACKED32, Packed_Order.XRGB, Packed_Layout._8888, 24, 4); 1719 | case .RGBX8888: return _pack_pixelformat(Pixel_Type.PACKED32, Packed_Order.RGBX, Packed_Layout._8888, 24, 4); 1720 | case .BGR888: return _pack_pixelformat(Pixel_Type.PACKED32, Packed_Order.XBGR, Packed_Layout._8888, 24, 4); 1721 | case .BGRX8888: return _pack_pixelformat(Pixel_Type.PACKED32, Packed_Order.BGRX, Packed_Layout._8888, 24, 4); 1722 | case .ARGB8888: return _pack_pixelformat(Pixel_Type.PACKED32, Packed_Order.ARGB, Packed_Layout._8888, 32, 4); 1723 | case .RGBA8888: return _pack_pixelformat(Pixel_Type.PACKED32, Packed_Order.RGBA, Packed_Layout._8888, 32, 4); 1724 | case .ABGR8888: return _pack_pixelformat(Pixel_Type.PACKED32, Packed_Order.ABGR, Packed_Layout._8888, 32, 4); 1725 | case .BGRA8888: return _pack_pixelformat(Pixel_Type.PACKED32, Packed_Order.BGRA, Packed_Layout._8888, 32, 4); 1726 | case .ARGB2101010: return _pack_pixelformat(Pixel_Type.PACKED32, Packed_Order.ARGB, Packed_Layout._2101010, 32, 4); 1727 | // NOTE(oskar): these duplicates cases above. 1728 | // case .YV12: return _pack_fourcc('Y', 'V', '1', '2'); 1729 | // case .IYUV: return _pack_fourcc('I', 'Y', 'U', 'V'); 1730 | // case .YUY2: return _pack_fourcc('Y', 'U', 'Y', '2'); 1731 | case .UYVY: return _pack_fourcc('U', 'Y', 'V', 'Y'); 1732 | case .YVYU: return _pack_fourcc('Y', 'V', 'Y', 'U'); 1733 | case .NV12: return _pack_fourcc('N', 'V', '1', '2'); 1734 | case .NV21: return _pack_fourcc('N', 'V', '2', '1'); 1735 | case .EXTERNAL_OES: return _pack_fourcc('O', 'E', 'S', ' '); 1736 | case .UNKNOWN: 1737 | } 1738 | return 0; 1739 | } 1740 | 1741 | Pixel_Format_Enum :: enum { 1742 | UNKNOWN, 1743 | INDEX1LSB, 1744 | INDEX1MSB, 1745 | INDEX4LSB, 1746 | INDEX4MSB, 1747 | INDEX8, 1748 | RGB332, 1749 | RGB444, 1750 | BGR444, 1751 | RGB555, 1752 | BGR555, 1753 | ARGB4444, 1754 | RGBA4444, 1755 | ABGR4444, 1756 | BGRA4444, 1757 | ARGB1555, 1758 | RGBA5551, 1759 | ABGR1555, 1760 | BGRA5551, 1761 | RGB565, 1762 | BGR565, 1763 | RGB24, 1764 | BGR24, 1765 | RGB888, 1766 | RGBX8888, 1767 | BGR888, 1768 | BGRX8888, 1769 | ARGB8888, 1770 | RGBA8888, 1771 | ABGR8888, 1772 | BGRA8888, 1773 | ARGB2101010, 1774 | RGBA32 = ABGR8888, 1775 | ARGB32 = BGRA8888, 1776 | BGRA32 = ARGB8888, 1777 | ABGR32 = RGBA8888, 1778 | YV12, 1779 | IYUV, 1780 | YUY2, 1781 | UYVY, 1782 | YVYU, 1783 | NV12, 1784 | NV21, 1785 | EXTERNAL_OES, 1786 | } 1787 | 1788 | Pixel_Format :: struct { 1789 | format: u32, 1790 | palette: ^Palette, 1791 | bits_per_pixel: u8, 1792 | bytes_per_pixel: u8, 1793 | padding: [2]u8, 1794 | r_mask: u32, 1795 | g_mask: u32, 1796 | b_mask: u32, 1797 | a_mask: u32, 1798 | r_loss: u8, 1799 | g_loss: u8, 1800 | b_loss: u8, 1801 | a_loss: u8, 1802 | r_shift: u8, 1803 | g_shift: u8, 1804 | b_shift: u8, 1805 | a_shift: u8, 1806 | ref_count: i32, 1807 | next: ^Pixel_Format, 1808 | } 1809 | 1810 | Rect :: struct { 1811 | x, y: i32, 1812 | w, h: i32, 1813 | } 1814 | 1815 | Atomic :: struct { 1816 | value: i32, 1817 | } 1818 | 1819 | Keysym :: struct { 1820 | scancode: Scancode, 1821 | sym: i32, 1822 | mod: u16, 1823 | unused: u32, 1824 | } 1825 | 1826 | Haptic_Effect :: struct #raw_union { 1827 | haptic_type: u16, 1828 | constant: Haptic_Constant, 1829 | periodic: Haptic_Periodic, 1830 | condition: Haptic_Condition, 1831 | ramp: Haptic_Ramp, 1832 | left_right: Haptic_Left_Right, 1833 | custom: Haptic_Custom, 1834 | } 1835 | 1836 | Haptic_Constant :: struct { 1837 | haptic_type: u16, 1838 | direction: Haptic_Direction, 1839 | 1840 | length: u32, 1841 | delay: u16, 1842 | 1843 | button: u16, 1844 | interval: u16, 1845 | 1846 | level: i16, 1847 | 1848 | attack_length: u16, 1849 | attack_level: u16, 1850 | fade_length: u16, 1851 | fade_level: u16, 1852 | } 1853 | 1854 | Haptic_Periodic :: struct { 1855 | haptic_type: u16, 1856 | direction: Haptic_Direction, 1857 | 1858 | length: u32, 1859 | delay: u16, 1860 | 1861 | button: u16, 1862 | interval: u16, 1863 | 1864 | period: u16, 1865 | magnitude: i16, 1866 | offset: i16, 1867 | phase: u16, 1868 | 1869 | attack_length: u16, 1870 | attack_level: u16, 1871 | fade_length: u16, 1872 | fade_level: u16, 1873 | } 1874 | 1875 | Haptic_Direction :: struct { 1876 | haptic_type: u8, 1877 | dir: [3]i32, 1878 | } 1879 | 1880 | Haptic_Condition :: struct { 1881 | haptic_type: u16, 1882 | direction: Haptic_Direction, 1883 | 1884 | length: u32, 1885 | delay: u16, 1886 | 1887 | button: u16, 1888 | interval: u16, 1889 | 1890 | right_sat: [3]u16, 1891 | left_sat: [3]u16, 1892 | right_coeff: [3]i16, 1893 | left_coeff: [3]i16, 1894 | dead_band: [3]u16, 1895 | center: [3]i16, 1896 | } 1897 | 1898 | Haptic_Ramp :: struct { 1899 | haptic_type: u16, 1900 | direction: Haptic_Direction, 1901 | 1902 | length: u32, 1903 | delay: u16, 1904 | 1905 | button: u16, 1906 | interval: u16, 1907 | 1908 | start: i16, 1909 | end: i16, 1910 | 1911 | attack_length: u16, 1912 | attack_level: u16, 1913 | fade_length: u16, 1914 | fade_level: u16, 1915 | } 1916 | 1917 | Haptic_Left_Right :: struct { 1918 | haptic_type: u16, 1919 | 1920 | length: u32, 1921 | 1922 | large_magnitude: u16, 1923 | small_magnitude: u16, 1924 | } 1925 | 1926 | Haptic_Custom :: struct { 1927 | haptic_type: u16, 1928 | direction: Haptic_Direction, 1929 | 1930 | length: u32, 1931 | delay: u16, 1932 | 1933 | button: u16, 1934 | interval: u16, 1935 | 1936 | channels: u8, 1937 | period: u16, 1938 | samples: u16, 1939 | data: ^u16, 1940 | 1941 | attack_length: u16, 1942 | attack_level: u16, 1943 | fade_length: u16, 1944 | fade_level: u16, 1945 | } 1946 | 1947 | Event :: struct #raw_union { 1948 | type: Event_Type, 1949 | common: Common_Event, 1950 | window: Window_Event, 1951 | key: Keyboard_Event, 1952 | edit: Text_Editing_Event, 1953 | text: Text_Input_Event, 1954 | motion: Mouse_Motion_Event, 1955 | button: Mouse_Button_Event, 1956 | wheel: Mouse_Wheel_Event, 1957 | jaxis: Joy_Axis_Event, 1958 | jball: Joy_Ball_Event, 1959 | jhat: Joy_Hat_Event, 1960 | jbutton: Joy_Button_Event, 1961 | jdevice: Joy_Device_Event, 1962 | caxis: Controller_Axis_Event, 1963 | cbutton: Controller_Button_Event, 1964 | cdevice: Controller_Device_Event, 1965 | adevice: Audio_Device_Event, 1966 | quit: Quit_Event, 1967 | user: User_Event, 1968 | syswm: Sys_Wm_Event, 1969 | tfinger: Touch_Finger_Event, 1970 | mgesture: Multi_Gesture_Event, 1971 | dgesture: Dollar_Gesture_Event, 1972 | drop: Drop_Event, 1973 | 1974 | padding: [56]u8, 1975 | } 1976 | 1977 | Common_Event :: struct { 1978 | type: Event_Type, 1979 | timestamp: u32, 1980 | } 1981 | 1982 | Window_Event :: struct { 1983 | type: Event_Type, 1984 | timestamp: u32, 1985 | window_id: u32, 1986 | event: Window_Event_ID, 1987 | padding1: u8, 1988 | padding2: u8, 1989 | padding3: u8, 1990 | data1: i32, 1991 | data2: i32, 1992 | } 1993 | 1994 | Keyboard_Event :: struct { 1995 | type: Event_Type, 1996 | timestamp: u32, 1997 | window_id: u32, 1998 | state: u8, 1999 | repeat: u8, 2000 | padding2: u8, 2001 | padding3: u8, 2002 | keysym: Keysym, 2003 | } 2004 | 2005 | TEXT_EDITING_EVENT_TEXT_SIZE :: 32; 2006 | Text_Editing_Event :: struct { 2007 | type: Event_Type, 2008 | timestamp: u32, 2009 | window_id: u32, 2010 | text: [TEXT_EDITING_EVENT_TEXT_SIZE]u8, 2011 | start: i32, 2012 | length: i32, 2013 | } 2014 | 2015 | 2016 | TEXT_INPUT_EVENT_TEXT_SIZE :: 32; 2017 | Text_Input_Event :: struct { 2018 | type: Event_Type, 2019 | timestamp: u32, 2020 | window_id: u32, 2021 | text: [TEXT_INPUT_EVENT_TEXT_SIZE]u8, 2022 | } 2023 | 2024 | Mouse_Motion_Event :: struct { 2025 | type: Event_Type, 2026 | timestamp: u32, 2027 | window_id: u32, 2028 | which: u32, 2029 | state: u32, 2030 | x: i32, 2031 | y: i32, 2032 | xrel: i32, 2033 | yrel: i32, 2034 | } 2035 | 2036 | Mouse_Button_Event :: struct { 2037 | type: Event_Type, 2038 | timestamp: u32, 2039 | window_id: u32, 2040 | which: u32, 2041 | button: u8, 2042 | state: u8, 2043 | clicks: u8, 2044 | padding1: u8, 2045 | x: i32, 2046 | y: i32, 2047 | } 2048 | 2049 | Mouse_Wheel_Event :: struct { 2050 | type: Event_Type, 2051 | timestamp: u32, 2052 | window_id: u32, 2053 | which: u32, 2054 | x: i32, 2055 | y: i32, 2056 | direction: u32, 2057 | } 2058 | 2059 | Joy_Axis_Event :: struct { 2060 | type: Event_Type, 2061 | timestamp: u32, 2062 | which: i32, 2063 | axis: u8, 2064 | padding1: u8, 2065 | padding2: u8, 2066 | padding3: u8, 2067 | value: i16, 2068 | padding4: u16, 2069 | } 2070 | 2071 | Joy_Ball_Event :: struct { 2072 | type: Event_Type, 2073 | timestamp: u32, 2074 | which: i32, 2075 | ball: u8, 2076 | padding1: u8, 2077 | padding2: u8, 2078 | padding3: u8, 2079 | xrel: i16, 2080 | yrel: i16, 2081 | } 2082 | 2083 | Joy_Hat_Event :: struct { 2084 | type: Event_Type, 2085 | timestamp: u32, 2086 | which: i32, 2087 | hat: u8, 2088 | value: u8, 2089 | padding1: u8, 2090 | padding2: u8, 2091 | } 2092 | 2093 | Joy_Button_Event :: struct { 2094 | type: Event_Type, 2095 | timestamp: u32, 2096 | which: i32, 2097 | button: u8, 2098 | state: u8, 2099 | padding1: u8, 2100 | padding2: u8, 2101 | } 2102 | 2103 | Joy_Device_Event :: struct { 2104 | type: Event_Type, 2105 | timestamp: u32, 2106 | which: i32, 2107 | } 2108 | 2109 | Controller_Axis_Event :: struct { 2110 | type: Event_Type, 2111 | timestamp: u32, 2112 | which: i32, 2113 | axis: u8, 2114 | padding1: u8, 2115 | padding2: u8, 2116 | padding3: u8, 2117 | value: i16, 2118 | padding4: u16, 2119 | } 2120 | 2121 | Controller_Button_Event :: struct { 2122 | type: Event_Type, 2123 | timestamp: u32, 2124 | which: i32, 2125 | button: u8, 2126 | state: u8, 2127 | padding1: u8, 2128 | padding2: u8, 2129 | } 2130 | 2131 | Controller_Device_Event :: struct { 2132 | type: Event_Type, 2133 | timestamp: u32, 2134 | which: i32, 2135 | } 2136 | 2137 | Audio_Device_Event :: struct { 2138 | type: Event_Type, 2139 | timestamp: u32, 2140 | which: u32, 2141 | iscapture: u8, 2142 | padding1: u8, 2143 | padding2: u8, 2144 | padding3: u8, 2145 | } 2146 | 2147 | Touch_Finger_Event :: struct { 2148 | type: Event_Type, 2149 | timestamp: u32, 2150 | touch_id: i64, 2151 | finger_id: i64, 2152 | x: f32, 2153 | y: f32, 2154 | dx: f32, 2155 | dy: f32, 2156 | pressure: f32, 2157 | } 2158 | 2159 | Multi_Gesture_Event :: struct { 2160 | type: Event_Type, 2161 | timestamp: u32, 2162 | touch_id: i64, 2163 | d_theta: f32, 2164 | d_dist: f32, 2165 | x: f32, 2166 | y: f32, 2167 | num_fingers: u16, 2168 | padding: u16, 2169 | } 2170 | 2171 | Dollar_Gesture_Event :: struct { 2172 | type: Event_Type, 2173 | timestamp: u32, 2174 | touch_id: i64, 2175 | gesture_id: i64, 2176 | num_fingers: u32, 2177 | error: f32, 2178 | x: f32, 2179 | y: f32, 2180 | } 2181 | 2182 | Drop_Event :: struct { 2183 | type: Event_Type, 2184 | timestamp: u32, 2185 | file: cstring, 2186 | window_id: u32, 2187 | } 2188 | 2189 | Quit_Event :: struct { 2190 | type: Event_Type, 2191 | timestamp: u32, 2192 | } 2193 | 2194 | OS_Event :: struct { 2195 | type: Event_Type, 2196 | timestamp: u32, 2197 | } 2198 | 2199 | User_Event :: struct { 2200 | type: Event_Type, 2201 | timestamp: u32, 2202 | window_id: u32, 2203 | code: i32, 2204 | data1: ^rawptr, 2205 | data2: ^rawptr, 2206 | } 2207 | 2208 | Sys_Wm_Event :: struct { 2209 | type: Event_Type, 2210 | timestamp: u32, 2211 | msg: ^Sys_Wm_Msg, 2212 | } 2213 | -------------------------------------------------------------------------------- /microui.odin: -------------------------------------------------------------------------------- 1 | /* 2 | ** Original work: Copyright (c) 2020 rxi 3 | ** Modified work: Copyright (c) 2020 oskarnp 4 | ** 5 | ** Permission is hereby granted, free of charge, to any person obtaining a copy 6 | ** of this software and associated documentation files (the "Software"), to 7 | ** deal in the Software without restriction, including without limitation the 8 | ** rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9 | ** sell copies of the Software, and to permit persons to whom the Software is 10 | ** furnished to do so, subject to the following conditions: 11 | ** 12 | ** The above copyright notice and this permission notice shall be included in 13 | ** all copies or substantial portions of the Software. 14 | ** 15 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | ** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 | ** IN THE SOFTWARE. 22 | */ 23 | 24 | package microui 25 | 26 | import "core:fmt" 27 | import "core:runtime" 28 | import "core:mem" 29 | import "core:sort" 30 | import "core:builtin" 31 | import "core:strings" 32 | import "core:reflect" 33 | import "core:strconv" 34 | 35 | COMMANDLIST_SIZE :: 256 * 1024; 36 | ROOTLIST_SIZE :: 32; 37 | CONTAINERSTACK_SIZE :: 32; 38 | CLIPSTACK_SIZE :: 32; 39 | IDSTACK_SIZE :: 32; 40 | LAYOUTSTACK_SIZE :: 16; 41 | CONTAINERPOOL_SIZE :: 48; 42 | TREENODEPOOL_SIZE :: 48; 43 | MAX_WIDTHS :: 16; 44 | SLIDER_FMT :: "%.2f"; 45 | MAX_FMT :: 127; 46 | 47 | Clip :: enum { 48 | NONE, 49 | PART, 50 | ALL, 51 | } 52 | 53 | Command_Type :: enum i32 { 54 | JUMP = 1, 55 | CLIP, 56 | RECT, 57 | TEXT, 58 | ICON, 59 | } 60 | 61 | Color_Type :: enum { 62 | TEXT, 63 | BORDER, 64 | WINDOWBG, 65 | TITLEBG, 66 | TITLETEXT, 67 | PANELBG, 68 | BUTTON, 69 | BUTTONHOVER = BUTTON+1, 70 | BUTTONFOCUS = BUTTON+2, 71 | BASE, 72 | BASEHOVER = BASE+1, 73 | BASEFOCUS = BASE+2, 74 | SCROLLBASE, 75 | SCROLLTHUMB, 76 | } 77 | 78 | Icon :: enum i32 { 79 | NONE, 80 | CLOSE, 81 | CHECK, 82 | COLLAPSED, 83 | EXPANDED, 84 | RESIZE, 85 | } 86 | 87 | Res :: enum { 88 | ACTIVE, 89 | SUBMIT, 90 | CHANGE, 91 | } 92 | Res_Bits :: bit_set[Res]; 93 | 94 | Opt :: enum { 95 | ALIGNCENTER, 96 | ALIGNRIGHT, 97 | NOINTERACT, 98 | NOFRAME, 99 | NORESIZE, 100 | NOSCROLL, 101 | NOCLOSE, 102 | NOTITLE, 103 | HOLDFOCUS, 104 | AUTOSIZE, 105 | POPUP, 106 | CLOSED, 107 | EXPANDED, 108 | } 109 | Opt_Bits :: bit_set[Opt]; 110 | 111 | Mouse :: enum { 112 | LEFT, 113 | RIGHT, 114 | MIDDLE, 115 | } 116 | Mouse_Bits :: bit_set[Mouse]; 117 | 118 | Key :: enum { 119 | SHIFT, 120 | CTRL, 121 | ALT, 122 | BACKSPACE, 123 | RETURN, 124 | } 125 | Key_Bits :: bit_set[Key]; 126 | 127 | Id :: distinct u32; 128 | Real :: f32; 129 | Font :: distinct rawptr; 130 | Vec2 :: distinct [2] i32; 131 | Rect :: struct { x, y, w, h: i32 } 132 | Color :: struct { r, g, b, a: u8 } 133 | Frame_Index :: distinct i32; 134 | Pool_Item :: struct { id: Id, last_update: Frame_Index } 135 | 136 | Base_Command :: struct { type: Command_Type, size: i32 } 137 | Jump_Command :: struct { using base: Base_Command, dst: rawptr } 138 | Clip_Command :: struct { using base: Base_Command, rect: Rect } 139 | Rect_Command :: struct { using base: Base_Command, rect: Rect, color: Color } 140 | Text_Command :: struct { using base: Base_Command, font: Font, pos: Vec2, color: Color, str: string /* + string data (VLA) */ } 141 | Icon_Command :: struct { using base: Base_Command, rect: Rect, id: Icon, color: Color } 142 | 143 | Command :: struct #raw_union { // TODO: use discriminated union? 144 | type: Command_Type, 145 | base: Base_Command, 146 | jump: Jump_Command, 147 | clip: Clip_Command, 148 | rect: Rect_Command, 149 | text: Text_Command, 150 | icon: Icon_Command, 151 | } 152 | 153 | Layout :: struct { 154 | body, next: Rect, 155 | position, size, max: Vec2, 156 | widths: [MAX_WIDTHS] i32, 157 | items, item_index, next_row: i32, 158 | next_type: Layout_Type, 159 | indent: i32, 160 | } 161 | 162 | Container :: struct { 163 | head, tail: ^Command, 164 | rect, body: Rect, 165 | content_size: Vec2, 166 | scroll: Vec2, 167 | zindex: i32, 168 | open: b32, 169 | } 170 | 171 | Style :: struct { 172 | font: Font, 173 | size: Vec2, 174 | padding: i32, 175 | spacing: i32, 176 | indent: i32, 177 | title_height: i32, 178 | footer_height: i32, 179 | scrollbar_size: i32, 180 | thumb_size: i32, 181 | colors: [Color_Type] Color, 182 | } 183 | 184 | Context :: struct { 185 | /* callbacks */ 186 | text_width: proc(font: Font, str: string) -> i32, 187 | text_height: proc(font: Font) -> i32, 188 | draw_frame: proc(ctx: ^Context, rect: Rect, colorid: Color_Type), 189 | /* core state */ 190 | _style: Style, 191 | style: ^Style, 192 | hover_id, focus_id, last_id: Id, 193 | last_rect: Rect, 194 | last_zindex: i32, 195 | updated_focus: b32, 196 | frame: Frame_Index, 197 | hover_root, next_hover_root: ^Container, 198 | scroll_target: ^Container, 199 | number_edit_buf: [MAX_FMT] u8, 200 | number_edit_len: int, 201 | number_edit_id: Id, 202 | /* stacks */ 203 | command_list: Stack(u8, COMMANDLIST_SIZE), 204 | root_list: Stack(^Container, ROOTLIST_SIZE), 205 | container_stack: Stack(^Container, CONTAINERSTACK_SIZE), 206 | clip_stack: Stack(Rect, CLIPSTACK_SIZE), 207 | id_stack: Stack(Id, IDSTACK_SIZE), 208 | layout_stack: Stack(Layout, LAYOUTSTACK_SIZE), 209 | /* retained state pools */ 210 | container_pool: [CONTAINERPOOL_SIZE] Pool_Item, 211 | containers: [CONTAINERPOOL_SIZE] Container, 212 | treenode_pool: [TREENODEPOOL_SIZE] Pool_Item, 213 | /* input state */ 214 | mouse_pos, last_mouse_pos: Vec2, 215 | mouse_delta, scroll_delta: Vec2, 216 | mouse_down_bits: Mouse_Bits, 217 | mouse_pressed_bits: Mouse_Bits, 218 | mouse_released_bits: Mouse_Bits, 219 | key_down_bits, key_pressed_bits: Key_Bits, 220 | _text_store: [32] u8, 221 | text_input: strings.Builder, // uses `_text_store` as backing store with nil_allocator. 222 | } 223 | 224 | expect :: builtin.assert; 225 | 226 | Stack :: struct(T: typeid, N: int) { 227 | idx: i32, 228 | items: [N]T, 229 | } 230 | push :: #force_inline proc(stk: ^$T/Stack($V,$N), val: V) { expect(stk.idx < len(stk.items)); stk.items[stk.idx] = val; stk.idx += 1; } 231 | pop :: #force_inline proc(stk: ^$T/Stack($V,$N)) { expect(stk.idx > 0); stk.idx -= 1; } 232 | 233 | unclipped_rect := Rect{0, 0, 0x1000000, 0x1000000}; 234 | 235 | default_style := Style{ 236 | font = nil, size = { 68, 10 }, 237 | padding = 5, spacing = 4, indent = 24, 238 | title_height = 24, footer_height = 20, 239 | scrollbar_size = 12, thumb_size = 8, 240 | colors = { 241 | .TEXT = {230, 230, 230, 255}, 242 | .BORDER = {25, 25, 25, 255}, 243 | .WINDOWBG = {50, 50, 50, 255}, 244 | .TITLEBG = {25, 25, 25, 255}, 245 | .TITLETEXT = {240, 240, 240, 255}, 246 | .PANELBG = {0, 0, 0, 0 }, 247 | .BUTTON = {75, 75, 75, 255}, 248 | .BUTTONHOVER = {95, 95, 95, 255}, 249 | .BUTTONFOCUS = {115, 115, 115, 255}, 250 | .BASE = {30, 30, 30, 255}, 251 | .BASEHOVER = {35, 35, 35, 255}, 252 | .BASEFOCUS = {40, 40, 40, 255}, 253 | .SCROLLBASE = {43, 43, 43, 255}, 254 | .SCROLLTHUMB = {30, 30, 30, 255}, 255 | }, 256 | }; 257 | 258 | @private expand_rect :: proc(rect: Rect, n: i32) -> Rect { 259 | return Rect{rect.x - n, rect.y - n, rect.w + n * 2, rect.h + n * 2}; 260 | } 261 | 262 | @private intersect_rects :: proc(r1, r2: Rect) -> Rect { 263 | x1 := max(r1.x, r2.x); 264 | y1 := max(r1.y, r2.y); 265 | x2 := min(r1.x + r1.w, r2.x + r2.w); 266 | y2 := min(r1.y + r1.h, r2.y + r2.h); 267 | if x2 < x1 do x2 = x1; 268 | if y2 < y1 do y2 = y1; 269 | return Rect{x1, y1, x2 - x1, y2 - y1}; 270 | } 271 | 272 | @private rect_overlaps_vec2 :: proc(r: Rect, p: Vec2) -> bool { 273 | return p.x >= r.x && p.x < r.x + r.w && p.y >= r.y && p.y < r.y + r.h; 274 | } 275 | 276 | @private draw_frame :: proc(ctx: ^Context, rect: Rect, colorid: Color_Type) { 277 | draw_rect(ctx, rect, ctx.style.colors[colorid]); 278 | if colorid == .SCROLLBASE || colorid == .SCROLLTHUMB || colorid == .TITLEBG do return; 279 | if ctx.style.colors[.BORDER].a != 0 { /* draw border */ 280 | draw_box(ctx, expand_rect(rect, 1), ctx.style.colors[.BORDER]); 281 | } 282 | } 283 | 284 | init :: proc(ctx: ^Context) { 285 | ctx^ = {}; // zero memory 286 | ctx.draw_frame = draw_frame; 287 | ctx._style = default_style; 288 | ctx.style = &ctx._style; 289 | ctx.text_input = strings.builder_from_slice(ctx._text_store[:]); 290 | } 291 | 292 | begin :: proc(ctx: ^Context) { 293 | expect(ctx.text_width != nil && ctx.text_height != nil); 294 | ctx.command_list.idx = 0; 295 | ctx.root_list.idx = 0; 296 | ctx.scroll_target = nil; 297 | ctx.hover_root = ctx.next_hover_root; 298 | ctx.next_hover_root = nil; 299 | ctx.mouse_delta.x = ctx.mouse_pos.x - ctx.last_mouse_pos.x; 300 | ctx.mouse_delta.y = ctx.mouse_pos.y - ctx.last_mouse_pos.y; 301 | ctx.frame += 1; 302 | } 303 | 304 | end :: proc(ctx: ^Context) { 305 | /* check stacks */ 306 | expect(ctx.container_stack.idx == 0); 307 | expect(ctx.clip_stack.idx == 0); 308 | expect(ctx.id_stack.idx == 0); 309 | expect(ctx.layout_stack.idx == 0); 310 | 311 | /* handle scroll input */ 312 | if ctx.scroll_target != nil { 313 | ctx.scroll_target.scroll.x += ctx.scroll_delta.x; 314 | ctx.scroll_target.scroll.y += ctx.scroll_delta.y; 315 | } 316 | 317 | /* unset focus if focus id was not touched this frame */ 318 | if !ctx.updated_focus do ctx.focus_id = 0; 319 | ctx.updated_focus = false; 320 | 321 | /* bring hover root to front if mouse was pressed */ 322 | if mouse_pressed(ctx) && ctx.next_hover_root != nil && 323 | ctx.next_hover_root.zindex < ctx.last_zindex && 324 | ctx.next_hover_root.zindex >= 0 { 325 | bring_to_front(ctx, ctx.next_hover_root); 326 | } 327 | 328 | /* reset input state */ 329 | ctx.key_pressed_bits = {}; // clear 330 | strings.reset_builder(&ctx.text_input); 331 | ctx.mouse_pressed_bits = {}; // clear 332 | ctx.mouse_released_bits = {}; // clear 333 | ctx.scroll_delta = Vec2{0, 0}; 334 | ctx.last_mouse_pos = ctx.mouse_pos; 335 | 336 | /* sort root containers by zindex */ 337 | n := ctx.root_list.idx; 338 | sort.quick_sort_proc(ctx.root_list.items[:n], proc(a, b: ^Container) -> int { 339 | return int(a.zindex) - int(b.zindex); 340 | }); 341 | 342 | /* set root container jump commands */ 343 | for i: i32 = 0; i < n; i += 1 { 344 | cnt := ctx.root_list.items[i]; 345 | /* if this is the first container then make the first command jump to it. 346 | ** otherwise set the previous container's tail to jump to this one */ 347 | if i == 0 { 348 | cmd := cast(^Command) &ctx.command_list.items[0]; 349 | cmd.jump.dst = rawptr(uintptr(cnt.head) + size_of(Jump_Command)); 350 | } else { 351 | prev := ctx.root_list.items[i - 1]; 352 | prev.tail.jump.dst = rawptr(uintptr(cnt.head) + size_of(Jump_Command)); 353 | } 354 | /* make the last container's tail jump to the end of command list */ 355 | if i == n - 1 { 356 | cnt.tail.jump.dst = rawptr(&ctx.command_list.items[ctx.command_list.idx]); 357 | } 358 | } 359 | } 360 | 361 | set_focus :: proc(ctx: ^Context, id: Id) { 362 | ctx.focus_id = id; 363 | ctx.updated_focus = true; 364 | } 365 | 366 | /* 32bit fnv-1a hash */ 367 | HASH_INITIAL :: 2166136261; 368 | 369 | @private hash :: proc(hash: ^Id, data: rawptr, size: int) { 370 | size := size; 371 | cptr := cast(^u8) data; 372 | for ; size > 0; size -= 1 { 373 | hash^ = cast(Id) (u32(hash^) ~ u32(cptr^)) * 16777619; 374 | cptr = mem.ptr_offset(cptr, 1); 375 | } 376 | } 377 | 378 | get_id :: proc{get_id_string, get_id_any, get_id_bytes, get_id_rawptr}; 379 | get_id_any :: #force_inline proc(ctx: ^Context, val: any) -> Id do return get_id_bytes(ctx, reflect.as_bytes(val)); 380 | get_id_string :: #force_inline proc(ctx: ^Context, str: string) -> Id do return get_id_bytes(ctx, transmute([]byte) str); 381 | get_id_rawptr :: #force_inline proc(ctx: ^Context, data: rawptr, size: int) -> Id do return get_id_bytes(ctx, mem.slice_ptr(cast(^u8)data, size)); 382 | get_id_bytes :: proc(ctx: ^Context, bytes: []byte) -> Id { 383 | idx := ctx.id_stack.idx; 384 | res := ctx.id_stack.items[idx - 1] if idx > 0 else HASH_INITIAL; 385 | hash(&res, &bytes[0], len(bytes)); 386 | ctx.last_id = res; 387 | return res; 388 | } 389 | 390 | push_id :: proc{push_id_any, push_id_rawptr, push_id_bytes, push_id_string}; 391 | push_id_any :: #force_inline proc(ctx: ^Context, val: any) do push(&ctx.id_stack, get_id(ctx, reflect.as_bytes(val))); 392 | push_id_string :: #force_inline proc(ctx: ^Context, str: string) do push(&ctx.id_stack, get_id(ctx, str)); 393 | push_id_rawptr :: #force_inline proc(ctx: ^Context, data: rawptr, size: int) do push(&ctx.id_stack, get_id(ctx, data, size)); 394 | push_id_bytes :: #force_inline proc(ctx: ^Context, bytes: []byte) do push(&ctx.id_stack, get_id(ctx, bytes)); 395 | 396 | pop_id :: proc(ctx: ^Context) do pop(&ctx.id_stack); 397 | 398 | push_clip_rect :: proc(ctx: ^Context, rect: Rect) { 399 | last := get_clip_rect(ctx); 400 | push(&ctx.clip_stack, intersect_rects(rect, last)); 401 | } 402 | 403 | pop_clip_rect :: proc(ctx: ^Context) { 404 | pop(&ctx.clip_stack); 405 | } 406 | 407 | get_clip_rect :: proc(ctx: ^Context) -> Rect { 408 | expect(ctx.clip_stack.idx > 0); 409 | return ctx.clip_stack.items[ctx.clip_stack.idx - 1]; 410 | } 411 | 412 | check_clip :: proc(ctx: ^Context, r: Rect) -> Clip { 413 | cr := get_clip_rect(ctx); 414 | if r.x > cr.x + cr.w || r.x + r.w < cr.x || 415 | r.y > cr.y + cr.h || r.y + r.h < cr.y { return .ALL; } 416 | if r.x >= cr.x && r.x + r.w <= cr.x + cr.w && 417 | r.y >= cr.y && r.y + r.h <= cr.y + cr.h { return .NONE; } 418 | return .PART; 419 | } 420 | 421 | @private push_layout :: proc(ctx: ^Context, body: Rect, scroll: Vec2) { 422 | layout: Layout; 423 | layout.body = Rect{body.x - scroll.x, body.y - scroll.y, body.w, body.h}; 424 | layout.max = Vec2{-0x1000000, -0x1000000}; 425 | push(&ctx.layout_stack, layout); 426 | layout_row(ctx, 1, []i32{0}, 0); 427 | } 428 | 429 | @private get_layout :: proc(ctx: ^Context) -> ^Layout { 430 | return &ctx.layout_stack.items[ctx.layout_stack.idx - 1]; 431 | } 432 | 433 | @private pop_container :: proc(ctx: ^Context) { 434 | cnt := get_current_container(ctx); 435 | layout := get_layout(ctx); 436 | cnt.content_size.x = layout.max.x - layout.body.x; 437 | cnt.content_size.y = layout.max.y - layout.body.y; 438 | /* pop container, layout and id */ 439 | pop(&ctx.container_stack); 440 | pop(&ctx.layout_stack); 441 | pop_id(ctx); 442 | } 443 | 444 | get_current_container :: proc(ctx: ^Context) -> ^Container { 445 | expect(ctx.container_stack.idx > 0); 446 | return ctx.container_stack.items[ctx.container_stack.idx - 1]; 447 | } 448 | 449 | @private _get_container :: proc(ctx: ^Context, id: Id, opt: Opt_Bits) -> ^Container { 450 | /* try to get existing container from pool */ 451 | idx, ok := pool_get(ctx, ctx.container_pool[:], id); 452 | if ok { 453 | if ctx.containers[idx].open || .CLOSED not_in opt { 454 | pool_update(ctx, &ctx.container_pool[idx]); 455 | } 456 | return &ctx.containers[idx]; 457 | } 458 | if .CLOSED in opt do return nil; 459 | /* container not found in pool: init new container */ 460 | idx = pool_init(ctx, ctx.container_pool[:], id); 461 | cnt := &ctx.containers[idx]; 462 | cnt^ = {}; // clear memory 463 | cnt.open = true; 464 | bring_to_front(ctx, cnt); 465 | return cnt; 466 | } 467 | 468 | get_container :: proc(ctx: ^Context, name: string) -> ^Container { 469 | id := get_id(ctx, name); 470 | return _get_container(ctx, id, {}); 471 | } 472 | 473 | bring_to_front :: proc(ctx: ^Context, cnt: ^Container) { 474 | ctx.last_zindex += 1; 475 | cnt.zindex = ctx.last_zindex; 476 | } 477 | 478 | /*============================================================================ 479 | ** pool 480 | **============================================================================*/ 481 | 482 | pool_init :: proc(ctx: ^Context, items: []Pool_Item, id: Id) -> int { 483 | f := ctx.frame; 484 | n := -1; 485 | for _, i in items { 486 | if items[i].last_update < f { 487 | f = items[i].last_update; 488 | n = i; 489 | } 490 | } 491 | expect(n > -1); 492 | items[n].id = id; 493 | pool_update(ctx, &items[n]); 494 | return n; 495 | } 496 | 497 | pool_get :: proc(ctx: ^Context, items: []Pool_Item, id: Id) -> (int, bool) { 498 | for _, i in items { 499 | if items[i].id == id do return i, true; 500 | } 501 | return -1, false; 502 | } 503 | 504 | pool_update :: proc(ctx: ^Context, item: ^Pool_Item) { 505 | item.last_update = ctx.frame; 506 | } 507 | 508 | /*============================================================================ 509 | ** input handlers 510 | **============================================================================*/ 511 | 512 | input_mousemove :: proc(ctx: ^Context, x, y: i32) { 513 | ctx.mouse_pos = Vec2{x, y}; 514 | } 515 | 516 | input_mousedown :: proc(ctx: ^Context, x, y: i32, btn: Mouse) { 517 | input_mousemove(ctx, x, y); 518 | incl(&ctx.mouse_down_bits, btn); 519 | incl(&ctx.mouse_pressed_bits, btn); 520 | } 521 | 522 | input_mouseup :: proc(ctx: ^Context, x, y: i32, btn: Mouse) { 523 | input_mousemove(ctx, x, y); 524 | excl(&ctx.mouse_down_bits, btn); 525 | incl(&ctx.mouse_released_bits, btn); 526 | } 527 | 528 | input_scroll :: proc(ctx: ^Context, x, y: i32) { 529 | ctx.scroll_delta.x += x; 530 | ctx.scroll_delta.y += y; 531 | } 532 | 533 | input_keydown :: proc(ctx: ^Context, key: Key) { 534 | incl(&ctx.key_pressed_bits, key); 535 | incl(&ctx.key_down_bits, key); 536 | } 537 | 538 | input_keyup :: proc(ctx: ^Context, key: Key) { 539 | excl(&ctx.key_down_bits, key); 540 | } 541 | 542 | input_text :: proc(ctx: ^Context, text: string) { 543 | strings.write_string(&ctx.text_input, text); 544 | } 545 | 546 | /*============================================================================ 547 | ** commandlist 548 | **============================================================================*/ 549 | 550 | push_command :: proc(ctx: ^Context, type: Command_Type, size: int) -> ^Command { 551 | cmd := transmute(^Command) &ctx.command_list.items[ctx.command_list.idx]; 552 | expect(int(ctx.command_list.idx) + size < COMMANDLIST_SIZE); 553 | cmd.base.type = type; 554 | cmd.base.size = i32(size); 555 | ctx.command_list.idx += i32(size); 556 | return cmd; 557 | } 558 | 559 | next_command :: proc(ctx: ^Context, pcmd: ^^Command) -> bool { 560 | cmd := pcmd^; 561 | defer pcmd^ = cmd; 562 | if cmd != nil do cmd = cast(^Command) (uintptr(cmd) + uintptr(cmd.base.size)); 563 | else do cmd = cast(^Command) &ctx.command_list.items[0]; 564 | invalid_command :: #force_inline proc(ctx: ^Context) -> ^Command do return cast(^Command) &ctx.command_list.items[ctx.command_list.idx]; 565 | for cmd != invalid_command(ctx) { 566 | if cmd.type != .JUMP do return true; 567 | cmd = cast(^Command) cmd.jump.dst; 568 | } 569 | return false; 570 | } 571 | 572 | @private push_jump :: proc(ctx: ^Context, dst: ^Command) -> ^Command { 573 | cmd := push_command(ctx, .JUMP, size_of(Jump_Command)); 574 | cmd.jump.dst = dst; 575 | return cmd; 576 | } 577 | 578 | set_clip :: proc(ctx: ^Context, rect: Rect) { 579 | cmd := push_command(ctx, .CLIP, size_of(Clip_Command)); 580 | cmd.clip.rect = rect; 581 | } 582 | 583 | draw_rect :: proc(ctx: ^Context, rect: Rect, color: Color) { 584 | rect := intersect_rects(rect, get_clip_rect(ctx)); 585 | if rect.w > 0 && rect.h > 0 { 586 | cmd := push_command(ctx, .RECT, size_of(Rect_Command)); 587 | cmd.rect.rect = rect; 588 | cmd.rect.color = color; 589 | } 590 | } 591 | 592 | draw_box :: proc(ctx: ^Context, rect: Rect, color: Color) { 593 | draw_rect(ctx, Rect{rect.x+1, rect.y, rect.w-2, 1 }, color); 594 | draw_rect(ctx, Rect{rect.x+1, rect.y+rect.h-1, rect.w-2, 1 }, color); 595 | draw_rect(ctx, Rect{rect.x, rect.y, 1, rect.h}, color); 596 | draw_rect(ctx, Rect{rect.x+rect.w-1, rect.y, 1, rect.h}, color); 597 | } 598 | 599 | draw_text :: proc(ctx: ^Context, font: Font, str: string, pos: Vec2, color: Color) { 600 | rect := Rect{pos.x, pos.y, ctx.text_width(font, str), ctx.text_height(font)}; 601 | clipped := check_clip(ctx, rect); 602 | if clipped == .ALL do return; 603 | if clipped == .PART do set_clip(ctx, get_clip_rect(ctx)); 604 | /* add command */ 605 | text_cmd := cast(^Text_Command) push_command(ctx, .TEXT, size_of(Text_Command) + len(str)); 606 | text_cmd.pos = pos; 607 | text_cmd.color = color; 608 | text_cmd.font = font; 609 | /* copy string */ 610 | dst_raw_str := transmute(^mem.Raw_String) &text_cmd.str; 611 | dst_raw_str.data = cast(^byte) mem.ptr_offset(text_cmd, 1); 612 | dst_raw_str.len = len(str); 613 | runtime.mem_copy(dst_raw_str.data, (transmute(mem.Raw_String)str).data, len(str)); 614 | /* reset clipping if it was set */ 615 | if clipped != .NONE do set_clip(ctx, unclipped_rect); 616 | } 617 | 618 | draw_icon :: proc(ctx: ^Context, id: Icon, rect: Rect, color: Color) { 619 | /* do clip command if the rect isn't fully contained within the cliprect */ 620 | clipped := check_clip(ctx, rect); 621 | if clipped == .ALL do return; 622 | if clipped == .PART do set_clip(ctx, get_clip_rect(ctx)); 623 | /* do icon command */ 624 | cmd := push_command(ctx, .ICON, size_of(Icon_Command)); 625 | cmd.icon.id = id; 626 | cmd.icon.rect = rect; 627 | cmd.icon.color = color; 628 | /* reset clipping if it was set */ 629 | if clipped != .NONE do set_clip(ctx, unclipped_rect); 630 | } 631 | 632 | /*============================================================================ 633 | ** layout 634 | **============================================================================*/ 635 | 636 | Layout_Type :: enum { NONE = 0, RELATIVE = 1, ABSOLUTE = 2 } 637 | 638 | layout_begin_column :: proc(ctx: ^Context) { 639 | push_layout(ctx, layout_next(ctx), Vec2{0, 0}); 640 | } 641 | 642 | layout_end_column :: proc(ctx: ^Context) { 643 | b := get_layout(ctx); 644 | pop(&ctx.layout_stack); 645 | /* inherit position/next_row/max from child layout if they are greater */ 646 | a := get_layout(ctx); 647 | a.position.x = max(a.position.x, b.position.x + b.body.x - a.body.x); 648 | a.next_row = max(a.next_row, b.next_row + b.body.y - a.body.y); 649 | a.max.x = max(a.max.x, b.max.x); 650 | a.max.y = max(a.max.y, b.max.y); 651 | } 652 | 653 | layout_row :: proc(ctx: ^Context, items: i32, widths: []i32, height: i32) { 654 | layout := get_layout(ctx); 655 | if len(widths) > 0 { 656 | expect(items <= MAX_WIDTHS); 657 | runtime.mem_copy(&layout.widths, &widths[0], int(items) * size_of(widths[0])); 658 | } 659 | layout.items = items; 660 | layout.position = Vec2{layout.indent, layout.next_row}; 661 | layout.size.y = height; 662 | layout.item_index = 0; 663 | } 664 | 665 | layout_width :: proc(ctx: ^Context, width: i32) { 666 | get_layout(ctx).size.x = width; 667 | } 668 | 669 | layout_height :: proc(ctx: ^Context, height: i32) { 670 | get_layout(ctx).size.y = height; 671 | } 672 | 673 | layout_set_next :: proc(ctx: ^Context, r: Rect, relative: bool) { 674 | layout := get_layout(ctx); 675 | layout.next = r; 676 | layout.next_type = .RELATIVE if relative else .ABSOLUTE; 677 | } 678 | 679 | layout_next :: proc(ctx: ^Context) -> (res: Rect) { 680 | layout := get_layout(ctx); 681 | style := ctx.style; 682 | defer ctx.last_rect = res; 683 | 684 | if layout.next_type != .NONE { 685 | /* handle rect set by `layout_set_next` */ 686 | type := layout.next_type; 687 | layout.next_type = .NONE; 688 | res = layout.next; 689 | if type == .ABSOLUTE do return; 690 | } else { 691 | /* handle next row */ 692 | if layout.item_index == layout.items { 693 | layout_row(ctx, layout.items, []i32{}, layout.size.y); 694 | } 695 | 696 | /* position */ 697 | res.x = layout.position.x; 698 | res.y = layout.position.y; 699 | 700 | /* size */ 701 | res.w = layout.items > 0 ? layout.widths[layout.item_index] : layout.size.x; 702 | res.h = layout.size.y; 703 | if res.w == 0 do res.w = style.size.x + style.padding * 2; 704 | if res.h == 0 do res.h = style.size.y + style.padding * 2; 705 | if res.w < 0 do res.w += layout.body.w - res.x + 1; 706 | if res.h < 0 do res.h += layout.body.h - res.y + 1; 707 | 708 | layout.item_index += 1; 709 | } 710 | 711 | /* update position */ 712 | layout.position.x += res.w + style.spacing; 713 | layout.next_row = max(layout.next_row, res.y + res.h + style.spacing); 714 | 715 | /* apply body offset */ 716 | res.x += layout.body.x; 717 | res.y += layout.body.y; 718 | 719 | /* update max position */ 720 | layout.max.x = max(layout.max.x, res.x + res.w); 721 | layout.max.y = max(layout.max.y, res.y + res.h); 722 | return; 723 | } 724 | 725 | /*============================================================================ 726 | ** controls 727 | **============================================================================*/ 728 | 729 | @private in_hover_root :: proc(ctx: ^Context) -> bool { 730 | for i := ctx.container_stack.idx - 1; i >= 0; i -= 1 { 731 | if ctx.container_stack.items[i] == ctx.hover_root do return true; 732 | /* only root containers have their `head` field set; stop searching if we've 733 | ** reached the current root container */ 734 | if ctx.container_stack.items[i].head != nil do break; 735 | } 736 | return false; 737 | } 738 | 739 | draw_control_frame :: proc(ctx: ^Context, id: Id, rect: Rect, colorid: Color_Type, opt: Opt_Bits = {}) { 740 | if .NOFRAME in opt do return; 741 | expect(colorid == .BUTTON || colorid == .BASE); 742 | colorid := Color_Type(int(colorid) + int((ctx.focus_id == id) ? 2 : (ctx.hover_id == id) ? 1 : 0)); 743 | ctx.draw_frame(ctx, rect, colorid); 744 | } 745 | 746 | draw_control_text :: proc(ctx: ^Context, str: string, rect: Rect, colorid: Color_Type, opt: Opt_Bits = {}) { 747 | pos: Vec2; 748 | font := ctx.style.font; 749 | tw := ctx.text_width(font, str); 750 | push_clip_rect(ctx, rect); 751 | pos.y = rect.y + (rect.h - ctx.text_height(font)) / 2; 752 | if .ALIGNCENTER in opt { 753 | pos.x = rect.x + (rect.w - tw) / 2; 754 | } else if .ALIGNRIGHT in opt { 755 | pos.x = rect.x + rect.w - tw - ctx.style.padding; 756 | } else { 757 | pos.x = rect.x + ctx.style.padding; 758 | } 759 | draw_text(ctx, font, str, pos, ctx.style.colors[colorid]); 760 | pop_clip_rect(ctx); 761 | } 762 | 763 | mouse_over :: proc(ctx: ^Context, rect: Rect) -> bool { 764 | return rect_overlaps_vec2(rect, ctx.mouse_pos) && 765 | rect_overlaps_vec2(get_clip_rect(ctx), ctx.mouse_pos) && 766 | in_hover_root(ctx); 767 | } 768 | 769 | update_control :: proc(ctx: ^Context, id: Id, rect: Rect, opt: Opt_Bits = {}) { 770 | mouseover := mouse_over(ctx, rect); 771 | 772 | if ctx.focus_id == id do ctx.updated_focus = true; 773 | if .NOINTERACT in opt do return; 774 | if mouseover && !mouse_down(ctx) do ctx.hover_id = id; 775 | 776 | if ctx.focus_id == id { 777 | if mouse_pressed(ctx) && !mouseover do set_focus(ctx, 0); 778 | if !mouse_down(ctx) && .HOLDFOCUS not_in opt do set_focus(ctx, 0); 779 | } 780 | 781 | if ctx.hover_id == id { 782 | if mouse_pressed(ctx) { 783 | set_focus(ctx, id); 784 | } else if !mouseover { 785 | ctx.hover_id = 0; 786 | } 787 | } 788 | } 789 | 790 | text :: proc(ctx: ^Context, text: string) { 791 | text := text; 792 | font := ctx.style.font; 793 | color := ctx.style.colors[.TEXT]; 794 | layout_begin_column(ctx); 795 | layout_row(ctx, 1, {-1}, ctx.text_height(font)); 796 | for len(text) > 0 { 797 | w: i32; 798 | start: int; 799 | end: int = len(text); 800 | r := layout_next(ctx); 801 | for ch, i in text { 802 | if ch == ' ' || ch == '\n' { 803 | word := text[start:i]; 804 | w += ctx.text_width(font, word); 805 | if w > r.w && start != 0 { 806 | end = start; 807 | break; 808 | } 809 | w += ctx.text_width(font, text[i:i+1]); 810 | if ch == '\n' { 811 | end = i+1; 812 | break; 813 | } 814 | start = i+1; 815 | } 816 | } 817 | draw_text(ctx, font, text[:end], Vec2{r.x, r.y}, color); 818 | text = text[end:]; 819 | } 820 | layout_end_column(ctx); 821 | } 822 | 823 | label :: proc(ctx: ^Context, text: string) { 824 | draw_control_text(ctx, text, layout_next(ctx), .TEXT); 825 | } 826 | 827 | button :: proc(ctx: ^Context, label: string, icon: Icon = .NONE, opt: Opt_Bits = {.ALIGNCENTER}) -> (res: Res_Bits) { 828 | id := len(label) > 0 ? get_id(ctx, label) : get_id(ctx, icon); 829 | r := layout_next(ctx); 830 | update_control(ctx, id, r, opt); 831 | /* handle click */ 832 | if ctx.mouse_pressed_bits == {.LEFT} && ctx.focus_id == id { 833 | res |= {.SUBMIT}; 834 | } 835 | /* draw */ 836 | draw_control_frame(ctx, id, r, .BUTTON, opt); 837 | if len(label) > 0 do draw_control_text(ctx, label, r, .TEXT, opt); 838 | if icon != .NONE do draw_icon(ctx, icon, r, ctx.style.colors[.TEXT]); 839 | return; 840 | } 841 | 842 | checkbox :: proc(ctx: ^Context, label: string, state: ^bool) -> (res: Res_Bits) { 843 | id := get_id(ctx, uintptr(state)); 844 | r := layout_next(ctx); 845 | box := Rect{r.x, r.y, r.h, r.h}; 846 | update_control(ctx, id, r, {}); 847 | /* handle click */ 848 | if .LEFT in ctx.mouse_released_bits && ctx.hover_id == id { 849 | res |= {.CHANGE}; 850 | state^ = !state^; 851 | } 852 | /* draw */ 853 | draw_control_frame(ctx, id, box, .BASE, {}); 854 | if state^ { 855 | draw_icon(ctx, .CHECK, box, ctx.style.colors[.TEXT]); 856 | } 857 | r = Rect{r.x + box.w, r.y, r.w - box.w, r.h}; 858 | draw_control_text(ctx, label, r, .TEXT); 859 | return; 860 | } 861 | 862 | textbox_raw :: proc(ctx: ^Context, textbuf: []u8, textlen: ^int, id: Id, r: Rect, opt: Opt_Bits = {}) -> (res: Res_Bits) { 863 | update_control(ctx, id, r, opt | {.HOLDFOCUS}); 864 | 865 | if ctx.focus_id == id { 866 | /* handle text input */ 867 | n := min(len(textbuf) - textlen^, strings.builder_len(ctx.text_input)); 868 | if n > 0 { 869 | copy(textbuf[textlen^:], strings.to_string(ctx.text_input)[:n]); 870 | textlen^ += n; 871 | res |= {.CHANGE}; 872 | } 873 | /* handle backspace */ 874 | if .BACKSPACE in ctx.key_pressed_bits && textlen^ > 0 { 875 | /* skip utf-8 continuation bytes */ 876 | for textlen^ > 0 { 877 | textlen^ -= 1; 878 | if textbuf[textlen^] & 0xc0 == 0x80 do continue; 879 | else do break; 880 | } 881 | res |= {.CHANGE}; 882 | } 883 | /* handle return */ 884 | if .RETURN in ctx.key_pressed_bits { 885 | set_focus(ctx, 0); 886 | res |= {.SUBMIT}; 887 | } 888 | } 889 | 890 | textstr := string(textbuf[:textlen^]); 891 | 892 | /* draw */ 893 | draw_control_frame(ctx, id, r, .BASE, opt); 894 | if ctx.focus_id == id { 895 | color := ctx.style.colors[.TEXT]; 896 | font := ctx.style.font; 897 | textw := ctx.text_width(font, textstr); 898 | texth := ctx.text_height(font); 899 | ofx := r.w - ctx.style.padding - textw - 1; 900 | textx := r.x + min(ofx, ctx.style.padding); 901 | texty := r.y + (r.h - texth) / 2; 902 | push_clip_rect(ctx, r); 903 | draw_text(ctx, font, textstr, Vec2{textx, texty}, color); 904 | draw_rect(ctx, Rect{textx + textw, texty, 1, texth}, color); 905 | pop_clip_rect(ctx); 906 | } else { 907 | draw_control_text(ctx, textstr, r, .TEXT, opt); 908 | } 909 | 910 | return; 911 | } 912 | 913 | @private parse_real :: #force_inline proc(s: string) -> (Real, bool) { 914 | when Real == f32 do return strconv.parse_f32(s); 915 | else when Real == f64 do return strconv.parse_f64(s); 916 | //unreachable(); 917 | return 0, false; 918 | } 919 | 920 | @private number_textbox :: proc(ctx: ^Context, value: ^Real, r: Rect, id: Id, fmt_string: string) -> bool { 921 | if ctx.mouse_pressed_bits == {.LEFT} && .SHIFT in ctx.key_down_bits && ctx.hover_id == id { 922 | ctx.number_edit_id = id; 923 | nstr := fmt.bprintf(ctx.number_edit_buf[:], fmt_string, value^); 924 | ctx.number_edit_len = len(nstr); 925 | } 926 | if ctx.number_edit_id == id { 927 | res := textbox_raw(ctx, ctx.number_edit_buf[:], &ctx.number_edit_len, id, r, {}); 928 | if .SUBMIT in res || ctx.focus_id != id { 929 | ok: bool; 930 | value^, ok = parse_real(string(ctx.number_edit_buf[:ctx.number_edit_len])); 931 | expect(ok == true); 932 | ctx.number_edit_id = 0; 933 | } else { 934 | return true; 935 | } 936 | } 937 | return false; 938 | } 939 | 940 | textbox :: proc(ctx: ^Context, buf: []u8, textlen: ^int, opt: Opt_Bits = {}) -> Res_Bits { 941 | id := get_id(ctx, uintptr(&buf[0])); 942 | r := layout_next(ctx); 943 | return textbox_raw(ctx, buf, textlen, id, r, opt); 944 | } 945 | 946 | slider :: proc(ctx: ^Context, value: ^Real, low, high: Real, step: Real = 0.0, fmt_string: string = SLIDER_FMT, opt: Opt_Bits = {.ALIGNCENTER}) -> (res: Res_Bits) { 947 | last := value^; 948 | v := last; 949 | id := get_id(ctx, uintptr(value)); 950 | base := layout_next(ctx); 951 | 952 | /* handle text input mode */ 953 | if number_textbox(ctx, &v, base, id, fmt_string) do return; 954 | 955 | /* handle normal mode */ 956 | update_control(ctx, id, base, opt); 957 | 958 | /* handle input */ 959 | if ctx.focus_id == id && ctx.mouse_down_bits == {.LEFT} { 960 | v = low + Real(ctx.mouse_pos.x - base.x) * (high - low) / Real(base.w); 961 | if step != 0.0 do v = ((v + step/2) / step) * step; 962 | } 963 | /* clamp and store value, update res */ 964 | v = clamp(v, low, high); value^ = v; 965 | if last != v do res |= {.CHANGE}; 966 | 967 | /* draw base */ 968 | draw_control_frame(ctx, id, base, .BASE, opt); 969 | /* draw thumb */ 970 | w := ctx.style.thumb_size; 971 | x := i32((v - low) * Real(base.w - w) / (high - low)); 972 | thumb := Rect{base.x + x, base.y, w, base.h}; 973 | draw_control_frame(ctx, id, thumb, .BUTTON, opt); 974 | /* draw text */ 975 | draw_control_text(ctx, fmt.tprintf(fmt_string, v), base, .TEXT, opt); 976 | 977 | return; 978 | } 979 | 980 | number :: proc(ctx: ^Context, value: ^Real, step: Real, fmt_string: string = SLIDER_FMT, opt: Opt_Bits = {.ALIGNCENTER}) -> (res: Res_Bits) { 981 | id := get_id(ctx, uintptr(value)); 982 | base := layout_next(ctx); 983 | last := value^; 984 | 985 | /* handle text input mode */ 986 | if number_textbox(ctx, value, base, id, fmt_string) do return; 987 | 988 | /* handle normal mode */ 989 | update_control(ctx, id, base, opt); 990 | 991 | /* handle input */ 992 | if ctx.focus_id == id && ctx.mouse_down_bits == {.LEFT} { 993 | value^ += Real(ctx.mouse_delta.x) * step; 994 | } 995 | /* set flag if value changed */ 996 | if value^ != last do res |= {.CHANGE}; 997 | 998 | /* draw base */ 999 | draw_control_frame(ctx, id, base, .BASE, opt); 1000 | /* draw text */ 1001 | draw_control_text(ctx, fmt.tprintf(fmt_string, value^), base, .TEXT, opt); 1002 | 1003 | return; 1004 | } 1005 | 1006 | @private _header :: proc(ctx: ^Context, label: string, istreenode: bool, opt: Opt_Bits = {}) -> Res_Bits { 1007 | id := get_id(ctx, label); 1008 | idx, active := pool_get(ctx, ctx.treenode_pool[:], id); 1009 | expanded := .EXPANDED in opt ? !active : active; 1010 | layout_row(ctx, 1, {-1}, 0); 1011 | r := layout_next(ctx); 1012 | update_control(ctx, id, r, {}); 1013 | /* handle click */ 1014 | if ctx.mouse_pressed_bits == {.LEFT} && ctx.focus_id == id { 1015 | active = !active; 1016 | } 1017 | /* update pool ref */ 1018 | if idx >= 0 { 1019 | if active do pool_update(ctx, &ctx.treenode_pool[idx]); 1020 | else do mem.zero_item(&ctx.treenode_pool[idx]); 1021 | } else if active { 1022 | pool_init(ctx, ctx.treenode_pool[:], id); 1023 | } 1024 | /* draw */ 1025 | if istreenode { 1026 | if ctx.hover_id == id do ctx.draw_frame(ctx, r, .BUTTONHOVER); 1027 | } else { 1028 | draw_control_frame(ctx, id, r, .BUTTON); 1029 | } 1030 | draw_icon(ctx, expanded ? .EXPANDED : .COLLAPSED, Rect{r.x, r.y, r.h, r.h}, ctx.style.colors[.TEXT]); 1031 | r.x += r.h - ctx.style.padding; 1032 | r.w -= r.h - ctx.style.padding; 1033 | draw_control_text(ctx, label, r, .TEXT); 1034 | return expanded ? {.ACTIVE} : {}; 1035 | } 1036 | 1037 | header :: proc(ctx: ^Context, label: string, opt: Opt_Bits = {}) -> Res_Bits { 1038 | return _header(ctx, label, false, opt); 1039 | } 1040 | 1041 | begin_treenode :: proc(ctx: ^Context, label: string, opt: Opt_Bits = {}) -> Res_Bits { 1042 | res := _header(ctx, label, true, opt); 1043 | if .ACTIVE in res { 1044 | get_layout(ctx).indent += ctx.style.indent; 1045 | push(&ctx.id_stack, ctx.last_id); 1046 | } 1047 | return res; 1048 | } 1049 | 1050 | end_treenode :: proc(ctx: ^Context) { 1051 | get_layout(ctx).indent -= ctx.style.indent; 1052 | pop_id(ctx); 1053 | } 1054 | 1055 | @private scrollbar :: proc(ctx: ^Context, cnt: ^Container, _b: ^Rect, cs: Vec2, id_string: string, i: int) { 1056 | b := cast(^struct{ pos, size: [2]i32 }) _b; 1057 | #assert(size_of(b^) == size_of(_b^)); 1058 | 1059 | /* only add scrollbar if content size is larger than body */ 1060 | maxscroll := cs[i] - b.size[i]; 1061 | contentsize := b.size[i]; 1062 | if maxscroll > 0 && contentsize > 0 { 1063 | id := get_id(ctx, id_string); 1064 | 1065 | /* get sizing / positioning */ 1066 | base := b^; 1067 | base.pos[1-i] = b.pos[1-i] + b.size[1-i]; 1068 | base.size[1-i] = ctx.style.scrollbar_size; 1069 | 1070 | /* handle input */ 1071 | update_control(ctx, id, transmute(Rect) base); 1072 | if ctx.focus_id == id && .LEFT in ctx.mouse_down_bits { 1073 | cnt.scroll[i] += ctx.mouse_delta[i] * cs[i] / base.size[i]; 1074 | } 1075 | /* clamp scroll to limits */ 1076 | cnt.scroll[i] = clamp(cnt.scroll[i], 0, maxscroll); 1077 | 1078 | /* draw base and thumb */ 1079 | ctx.draw_frame(ctx, transmute(Rect) base, .SCROLLBASE); 1080 | thumb := base; 1081 | thumb.size[i] = max(ctx.style.thumb_size, base.size[i] * b.size[i] / cs[i]); 1082 | thumb.pos[i] += cnt.scroll[i] * (base.size[i] - thumb.size[i]) / maxscroll; 1083 | ctx.draw_frame(ctx, transmute(Rect) thumb, .SCROLLTHUMB); 1084 | 1085 | /* set this as the scroll_target (will get scrolled on mousewheel) */ 1086 | /* if the mouse is over it */ 1087 | if mouse_over(ctx, transmute(Rect) b^) do ctx.scroll_target = cnt; 1088 | } else { 1089 | cnt.scroll[i] = 0; 1090 | } 1091 | } 1092 | 1093 | @private scrollbars :: proc(ctx: ^Context, cnt: ^Container, body: ^Rect) { 1094 | sz := ctx.style.scrollbar_size; 1095 | cs := cnt.content_size; 1096 | cs.x += ctx.style.padding * 2; 1097 | cs.y += ctx.style.padding * 2; 1098 | push_clip_rect(ctx, body^); 1099 | /* resize body to make room for scrollbars */ 1100 | if cs.y > cnt.body.h do body.w -= sz; 1101 | if cs.x > cnt.body.w do body.h -= sz; 1102 | /* to create a horizontal or vertical scrollbar almost-identical code is 1103 | ** used; only the references to `x|y` `w|h` need to be switched */ 1104 | scrollbar(ctx, cnt, body, cs, "!scrollbarv", 1); // 1 = y,h 1105 | scrollbar(ctx, cnt, body, cs, "!scrollbarh", 0); // 0 = x,w 1106 | pop_clip_rect(ctx); 1107 | } 1108 | 1109 | @private push_container_body :: proc(ctx: ^Context, cnt: ^Container, body: Rect, opt: Opt_Bits = {}) { 1110 | body := body; 1111 | if .NOSCROLL not_in opt do scrollbars(ctx, cnt, &body); 1112 | push_layout(ctx, expand_rect(body, -ctx.style.padding), cnt.scroll); 1113 | cnt.body = body; 1114 | } 1115 | 1116 | @private begin_root_container :: proc(ctx: ^Context, cnt: ^Container) { 1117 | push(&ctx.container_stack, cnt); 1118 | /* push container to roots list and push head command */ 1119 | push(&ctx.root_list, cnt); 1120 | cnt.head = push_jump(ctx, nil); 1121 | /* set as hover root if the mouse is overlapping this container and it has a 1122 | ** higher zindex than the current hover root */ 1123 | if rect_overlaps_vec2(cnt.rect, ctx.mouse_pos) && 1124 | (ctx.next_hover_root == nil || cnt.zindex > ctx.next_hover_root.zindex) { 1125 | ctx.next_hover_root = cnt; 1126 | } 1127 | /* clipping is reset here in case a root-container is made within 1128 | ** another root-containers's begin/end block; this prevents the inner 1129 | ** root-container being clipped to the outer */ 1130 | push(&ctx.clip_stack, unclipped_rect); 1131 | } 1132 | 1133 | @private end_root_container :: proc(ctx: ^Context) { 1134 | /* push tail 'goto' jump command and set head 'skip' command. the final steps 1135 | ** on initing these are done in end() */ 1136 | cnt := get_current_container(ctx); 1137 | cnt.tail = push_jump(ctx, nil); 1138 | cnt.head.jump.dst = &ctx.command_list.items[ctx.command_list.idx]; 1139 | /* pop base clip rect and container */ 1140 | pop_clip_rect(ctx); 1141 | pop_container(ctx); 1142 | } 1143 | 1144 | begin_window :: proc(ctx: ^Context, title: string, rect: Rect, opt: Opt_Bits = {}) -> bool { 1145 | id := get_id(ctx, title); 1146 | cnt := _get_container(ctx, id, opt); 1147 | if cnt == nil || !cnt.open do return false; 1148 | push(&ctx.id_stack, id); 1149 | 1150 | if cnt.rect.w == 0 do cnt.rect = rect; 1151 | begin_root_container(ctx, cnt); 1152 | rect := cnt.rect; 1153 | body := cnt.rect; 1154 | 1155 | /* draw frame */ 1156 | if .NOFRAME not_in opt { 1157 | ctx.draw_frame(ctx, rect, .WINDOWBG); 1158 | } 1159 | 1160 | /* do title bar */ 1161 | if .NOTITLE not_in opt { 1162 | tr := rect; 1163 | tr.h = ctx.style.title_height; 1164 | ctx.draw_frame(ctx, tr, .TITLEBG); 1165 | 1166 | /* do title text */ 1167 | if .NOTITLE not_in opt { 1168 | id := get_id(ctx, "!title"); 1169 | update_control(ctx, id, tr, opt); 1170 | draw_control_text(ctx, title, tr, .TITLETEXT, opt); 1171 | if id == ctx.focus_id && ctx.mouse_down_bits == {.LEFT} { 1172 | cnt.rect.x += ctx.mouse_delta.x; 1173 | cnt.rect.y += ctx.mouse_delta.y; 1174 | } 1175 | body.y += tr.h; 1176 | body.h -= tr.h; 1177 | } 1178 | 1179 | /* do `close` button */ 1180 | if .NOCLOSE not_in opt { 1181 | id := get_id(ctx, "!close"); 1182 | r := Rect{tr.x + tr.w - tr.h, tr.y, tr.h, tr.h}; 1183 | tr.w -= r.w; 1184 | draw_icon(ctx, .CLOSE, r, ctx.style.colors[.TITLETEXT]); 1185 | update_control(ctx, id, r, opt); 1186 | if .LEFT in ctx.mouse_released_bits && id == ctx.hover_id { 1187 | cnt.open = false; 1188 | } 1189 | } 1190 | } 1191 | 1192 | /* do `resize` handle */ 1193 | if .NORESIZE not_in opt { 1194 | sz := ctx.style.footer_height; 1195 | id := get_id(ctx, "!resize"); 1196 | r := Rect{rect.x + rect.w - sz, rect.y + rect.h - sz, sz, sz}; 1197 | draw_icon(ctx, .RESIZE, r, ctx.style.colors[.TEXT]); 1198 | update_control(ctx, id, r, opt); 1199 | if id == ctx.focus_id && .LEFT in ctx.mouse_down_bits { 1200 | cnt.rect.w = max(96, cnt.rect.w + ctx.mouse_delta.x); 1201 | cnt.rect.h = max(64, cnt.rect.h + ctx.mouse_delta.y); 1202 | } 1203 | body.h -= sz; 1204 | } 1205 | 1206 | push_container_body(ctx, cnt, body, opt); 1207 | 1208 | /* resize to content size */ 1209 | if .AUTOSIZE in opt { 1210 | r := get_layout(ctx).body; 1211 | cnt.rect.w = cnt.content_size.x + (cnt.rect.w - r.w); 1212 | cnt.rect.h = cnt.content_size.y + (cnt.rect.h - r.h); 1213 | } 1214 | 1215 | /* close if this is a popup window and elsewhere was clicked */ 1216 | if .POPUP in opt && mouse_pressed(ctx) && ctx.hover_root != cnt { 1217 | cnt.open = false; 1218 | } 1219 | 1220 | push_clip_rect(ctx, cnt.body); 1221 | return true; 1222 | } 1223 | 1224 | end_window :: proc(ctx: ^Context) { 1225 | pop_clip_rect(ctx); 1226 | end_root_container(ctx); 1227 | } 1228 | 1229 | open_popup :: proc(ctx: ^Context, name: string) { 1230 | cnt := get_container(ctx, name); 1231 | /* set as hover root so popup isn't closed in begin_window() */ 1232 | ctx.hover_root = cnt; 1233 | ctx.next_hover_root = cnt; 1234 | /* position at mouse cursor, open and bring-to-front */ 1235 | cnt.rect = Rect{ctx.mouse_pos.x, ctx.mouse_pos.y, 1, 1}; 1236 | cnt.open = true; 1237 | bring_to_front(ctx, cnt); 1238 | } 1239 | 1240 | begin_popup :: proc(ctx: ^Context, name: string) -> bool { 1241 | opt := Opt_Bits{.POPUP, .AUTOSIZE, .NORESIZE, .NOSCROLL, .NOTITLE, .CLOSED}; 1242 | return begin_window(ctx, name, Rect{}, opt); 1243 | } 1244 | 1245 | end_popup :: proc(ctx: ^Context) { 1246 | end_window(ctx); 1247 | } 1248 | 1249 | begin_panel :: proc(ctx: ^Context, name: string, opt: Opt_Bits = {}) { 1250 | push_id(ctx, name); 1251 | cnt := _get_container(ctx, ctx.last_id, opt); 1252 | cnt.rect = layout_next(ctx); 1253 | if .NOFRAME not_in opt do ctx.draw_frame(ctx, cnt.rect, .PANELBG); 1254 | push(&ctx.container_stack, cnt); 1255 | push_container_body(ctx, cnt, cnt.rect, opt); 1256 | push_clip_rect(ctx, cnt.body); 1257 | } 1258 | 1259 | end_panel :: proc(ctx: ^Context) { 1260 | pop_clip_rect(ctx); 1261 | pop_container(ctx); 1262 | } 1263 | 1264 | @private mouse_released :: #force_inline proc(ctx: ^Context) -> bool do return card(ctx.mouse_released_bits) != 0; 1265 | @private mouse_pressed :: #force_inline proc(ctx: ^Context) -> bool do return card(ctx.mouse_pressed_bits) != 0; 1266 | @private mouse_down :: #force_inline proc(ctx: ^Context) -> bool do return card(ctx.mouse_down_bits) != 0; 1267 | --------------------------------------------------------------------------------