karl2d.odin 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809
  1. package karl2d
  2. import win32 "core:sys/windows"
  3. import "base:runtime"
  4. import "core:mem"
  5. import "core:log"
  6. import "core:math"
  7. import "core:math/linalg"
  8. import "core:slice"
  9. import "core:image"
  10. import "core:image/bmp"
  11. import "core:image/png"
  12. import "core:image/tga"
  13. import hm "handle_map"
  14. _ :: bmp
  15. _ :: png
  16. _ :: tga
  17. Handle :: hm.Handle
  18. Texture_Handle :: distinct Handle
  19. // Opens a window and initializes some internal state. The internal state will use `allocator` for
  20. // all dynamically allocated memory. The return value can be ignored unless you need to later call
  21. // `set_state`.
  22. init :: proc(window_width: int, window_height: int, window_title: string,
  23. allocator := context.allocator, loc := #caller_location) -> ^State {
  24. win32.SetProcessDPIAware()
  25. s = new(State, allocator, loc)
  26. s.allocator = allocator
  27. s.custom_context = context
  28. CLASS_NAME :: "karl2d"
  29. instance := win32.HINSTANCE(win32.GetModuleHandleW(nil))
  30. s.run = true
  31. s.width = window_width
  32. s.height = window_height
  33. cls := win32.WNDCLASSW {
  34. lpfnWndProc = window_proc,
  35. lpszClassName = CLASS_NAME,
  36. hInstance = instance,
  37. hCursor = win32.LoadCursorA(nil, win32.IDC_ARROW),
  38. }
  39. window_proc :: proc "stdcall" (hwnd: win32.HWND, msg: win32.UINT, wparam: win32.WPARAM, lparam: win32.LPARAM) -> win32.LRESULT {
  40. context = s.custom_context
  41. switch msg {
  42. case win32.WM_DESTROY:
  43. win32.PostQuitMessage(0)
  44. s.run = false
  45. case win32.WM_CLOSE:
  46. s.run = false
  47. case win32.WM_KEYDOWN:
  48. key := VK_MAP[wparam]
  49. s.keys_went_down[key] = true
  50. s.keys_is_held[key] = true
  51. case win32.WM_KEYUP:
  52. key := VK_MAP[wparam]
  53. s.keys_is_held[key] = false
  54. s.keys_went_up[key] = true
  55. }
  56. return win32.DefWindowProcW(hwnd, msg, wparam, lparam)
  57. }
  58. win32.RegisterClassW(&cls)
  59. r: win32.RECT
  60. r.right = i32(window_width)
  61. r.bottom = i32(window_height)
  62. style := win32.WS_OVERLAPPEDWINDOW | win32.WS_VISIBLE
  63. win32.AdjustWindowRect(&r, style, false)
  64. hwnd := win32.CreateWindowW(CLASS_NAME,
  65. win32.utf8_to_wstring(window_title),
  66. style,
  67. 100, 10, r.right - r.left, r.bottom - r.top,
  68. nil, nil, instance, nil)
  69. s.window = hwnd
  70. assert(hwnd != nil, "Failed creating window")
  71. s.rb = BACKEND_D3D11
  72. rb_alloc_error: runtime.Allocator_Error
  73. s.rb_state, rb_alloc_error = mem.alloc(s.rb.state_size())
  74. log.assertf(rb_alloc_error == nil, "Failed allocating memory for rendering backend: %v", rb_alloc_error)
  75. s.proj_matrix = make_default_projection(window_width, window_height)
  76. s.view_matrix = 1
  77. s.rb.init(s.rb_state, uintptr(hwnd), window_width, window_height, allocator, loc)
  78. s.vertex_buffer_cpu = make([]u8, VERTEX_BUFFER_MAX, allocator, loc)
  79. white_rect: [16*16*4]u8
  80. slice.fill(white_rect[:], 255)
  81. s.shape_drawing_texture = s.rb.load_texture(white_rect[:], 16, 16)
  82. s.default_shader = s.rb.load_shader(string(DEFAULT_SHADER_SOURCE), {
  83. .RG32_Float,
  84. .RG32_Float,
  85. .RGBA8_Norm,
  86. })
  87. return s
  88. }
  89. DEFAULT_SHADER_SOURCE :: #load("shader.hlsl")
  90. // Closes the window and cleans up the internal state.
  91. shutdown :: proc() {
  92. s.rb.destroy_texture(s.shape_drawing_texture)
  93. destroy_shader(s.default_shader)
  94. s.rb.shutdown()
  95. delete(s.vertex_buffer_cpu, s.allocator)
  96. win32.DestroyWindow(s.window)
  97. a := s.allocator
  98. free(s.rb_state, a)
  99. free(s, a)
  100. s = nil
  101. }
  102. // Clear the backbuffer with supplied color.
  103. clear :: proc(color: Color) {
  104. s.rb.clear(color)
  105. }
  106. // Present the backbuffer. Call at end of frame to make everything you've drawn appear on the screen.
  107. present :: proc() {
  108. draw_current_batch()
  109. s.rb.present()
  110. }
  111. // Call at start or end of frame to process all events that have arrived to the window.
  112. //
  113. // WARNING: Not calling this will make your program impossible to interact with.
  114. process_events :: proc() {
  115. s.keys_went_up = {}
  116. s.keys_went_down = {}
  117. msg: win32.MSG
  118. for win32.PeekMessageW(&msg, nil, 0, 0, win32.PM_REMOVE) {
  119. win32.TranslateMessage(&msg)
  120. win32.DispatchMessageW(&msg)
  121. }
  122. }
  123. /* Flushes the current batch. This sends off everything to the GPU that has been queued in the
  124. current batch. Normally, you do not need to do this manually. It is done automatically when these
  125. procedures run:
  126. present
  127. set_camera
  128. set_shader
  129. TODO: complete this list and motivate why it needs to happen on those procs (or do that in the
  130. docs for those procs).
  131. */
  132. draw_current_batch :: proc() {
  133. shader := s.batch_shader.? or_else s.default_shader
  134. s.rb.draw(shader, s.batch_texture, s.vertex_buffer_cpu[:s.vertex_buffer_cpu_used])
  135. s.vertex_buffer_cpu_used = 0
  136. }
  137. // Can be used to restore the internal state using the pointer returned by `init`. Useful after
  138. // reloading the library (for example, when doing code hot reload).
  139. set_internal_state :: proc(state: ^State) {
  140. s = state
  141. s.rb.set_internal_state(s.rb_state)
  142. }
  143. get_screen_width :: proc() -> int {
  144. return s.rb.get_swapchain_width()
  145. }
  146. get_screen_height :: proc() -> int {
  147. return s.rb.get_swapchain_height()
  148. }
  149. key_went_down :: proc(key: Keyboard_Key) -> bool {
  150. return s.keys_went_down[key]
  151. }
  152. key_went_up :: proc(key: Keyboard_Key) -> bool {
  153. return s.keys_went_up[key]
  154. }
  155. key_is_held :: proc(key: Keyboard_Key) -> bool {
  156. return s.keys_is_held[key]
  157. }
  158. // Returns true if the user has tried to close the window.
  159. window_should_close :: proc() -> bool {
  160. return !s.run
  161. }
  162. set_window_position :: proc(x: int, y: int) {
  163. // TODO: Does x, y respect monitor DPI?
  164. win32.SetWindowPos(
  165. s.window,
  166. {},
  167. i32(x),
  168. i32(y),
  169. 0,
  170. 0,
  171. win32.SWP_NOACTIVATE | win32.SWP_NOZORDER | win32.SWP_NOSIZE,
  172. )
  173. }
  174. set_window_size :: proc(width: int, height: int) {
  175. panic("Not implemented")
  176. }
  177. set_camera :: proc(camera: Maybe(Camera)) {
  178. if camera == s.batch_camera {
  179. return
  180. }
  181. draw_current_batch()
  182. s.batch_camera = camera
  183. s.proj_matrix = make_default_projection(s.width, s.height)
  184. if c, c_ok := camera.?; c_ok {
  185. origin_trans := linalg.matrix4_translate(vec3_from_vec2(-c.origin))
  186. translate := linalg.matrix4_translate(vec3_from_vec2(c.target))
  187. rot := linalg.matrix4_rotate_f32(c.rotation * math.RAD_PER_DEG, {0, 0, 1})
  188. camera_matrix := translate * rot * origin_trans
  189. s.view_matrix = linalg.inverse(camera_matrix)
  190. s.proj_matrix[0, 0] *= c.zoom
  191. s.proj_matrix[1, 1] *= c.zoom
  192. } else {
  193. s.view_matrix = 1
  194. }
  195. s.rb.set_view_projection_matrix(s.proj_matrix * s.view_matrix)
  196. }
  197. load_texture_from_file :: proc(filename: string) -> Texture {
  198. img, img_err := image.load_from_file(filename, options = {.alpha_add_if_missing}, allocator = context.temp_allocator)
  199. if img_err != nil {
  200. log.errorf("Error loading texture %v: %v", filename, img_err)
  201. return {}
  202. }
  203. backend_tex := s.rb.load_texture(img.pixels.buf[:], img.width, img.height)
  204. return {
  205. handle = backend_tex,
  206. width = img.width,
  207. height = img.height,
  208. }
  209. }
  210. destroy_texture :: proc(tex: Texture) {
  211. s.rb.destroy_texture(tex.handle)
  212. }
  213. draw_rect :: proc(r: Rect, c: Color) {
  214. if s.batch_texture != TEXTURE_NONE && s.batch_texture != s.shape_drawing_texture {
  215. draw_current_batch()
  216. }
  217. s.batch_texture = s.shape_drawing_texture
  218. _batch_vertex({r.x, r.y}, {0, 0}, c)
  219. _batch_vertex({r.x + r.w, r.y}, {1, 0}, c)
  220. _batch_vertex({r.x + r.w, r.y + r.h}, {1, 1}, c)
  221. _batch_vertex({r.x, r.y}, {0, 0}, c)
  222. _batch_vertex({r.x + r.w, r.y + r.h}, {1, 1}, c)
  223. _batch_vertex({r.x, r.y + r.h}, {0, 1}, c)
  224. }
  225. draw_rect_outline :: proc(r: Rect, thickness: f32, color: Color) {
  226. t := thickness
  227. // Based on DrawRectangleLinesEx from Raylib
  228. top := Rect {
  229. r.x,
  230. r.y,
  231. r.w,
  232. t,
  233. }
  234. bottom := Rect {
  235. r.x,
  236. r.y + r.h - t,
  237. r.w,
  238. t,
  239. }
  240. left := Rect {
  241. r.x,
  242. r.y + t,
  243. t,
  244. r.h - t * 2,
  245. }
  246. right := Rect {
  247. r.x + r.w - t,
  248. r.y + t,
  249. t,
  250. r.h - t * 2,
  251. }
  252. draw_rect(top, color)
  253. draw_rect(bottom, color)
  254. draw_rect(left, color)
  255. draw_rect(right, color)
  256. }
  257. draw_circle :: proc(center: Vec2, radius: f32, color: Color) {
  258. panic("not implemented")
  259. }
  260. draw_line :: proc(start: Vec2, end: Vec2, thickness: f32, color: Color) {
  261. panic("not implemented")
  262. }
  263. draw_texture :: proc(tex: Texture, pos: Vec2, tint := WHITE) {
  264. draw_texture_ex(
  265. tex,
  266. {0, 0, f32(tex.width), f32(tex.height)},
  267. {pos.x, pos.y, f32(tex.width), f32(tex.height)},
  268. {},
  269. 0,
  270. tint,
  271. )
  272. }
  273. draw_texture_rect :: proc(tex: Texture, rect: Rect, pos: Vec2, tint := WHITE) {
  274. draw_texture_ex(
  275. tex,
  276. rect,
  277. {pos.x, pos.y, rect.w, rect.h},
  278. {},
  279. 0,
  280. tint,
  281. )
  282. }
  283. draw_texture_ex :: proc(tex: Texture, src: Rect, dst: Rect, origin: Vec2, rotation: f32, tint := WHITE) {
  284. if tex.width == 0 || tex.height == 0 {
  285. return
  286. }
  287. if s.batch_texture != TEXTURE_NONE && s.batch_texture != tex.handle {
  288. draw_current_batch()
  289. }
  290. r := dst
  291. r.x -= origin.x
  292. r.y -= origin.y
  293. s.batch_texture = tex.handle
  294. tl, tr, bl, br: Vec2
  295. // Rotation adapted from Raylib's "DrawTexturePro"
  296. if rotation == 0 {
  297. x := dst.x - origin.x
  298. y := dst.y - origin.y
  299. tl = { x, y }
  300. tr = { x + dst.w, y }
  301. bl = { x, y + dst.h }
  302. br = { x + dst.w, y + dst.h }
  303. } else {
  304. sin_rot := math.sin(rotation * math.RAD_PER_DEG)
  305. cos_rot := math.cos(rotation * math.RAD_PER_DEG)
  306. x := dst.x
  307. y := dst.y
  308. dx := -origin.x
  309. dy := -origin.y
  310. tl = {
  311. x + dx * cos_rot - dy * sin_rot,
  312. y + dx * sin_rot + dy * cos_rot,
  313. }
  314. tr = {
  315. x + (dx + dst.w) * cos_rot - dy * sin_rot,
  316. y + (dx + dst.w) * sin_rot + dy * cos_rot,
  317. }
  318. bl = {
  319. x + dx * cos_rot - (dy + dst.h) * sin_rot,
  320. y + dx * sin_rot + (dy + dst.h) * cos_rot,
  321. }
  322. br = {
  323. x + (dx + dst.w) * cos_rot - (dy + dst.h) * sin_rot,
  324. y + (dx + dst.w) * sin_rot + (dy + dst.h) * cos_rot,
  325. }
  326. }
  327. ts := Vec2{f32(tex.width), f32(tex.height)}
  328. up := Vec2{src.x, src.y} / ts
  329. us := Vec2{src.w, src.h} / ts
  330. c := tint
  331. _batch_vertex(tl, up, c)
  332. _batch_vertex(tr, up + {us.x, 0}, c)
  333. _batch_vertex(br, up + us, c)
  334. _batch_vertex(tl, up, c)
  335. _batch_vertex(br, up + us, c)
  336. _batch_vertex(bl, up + {0, us.y}, c)
  337. }
  338. load_shader :: proc(shader_source: string, layout_formats: []Shader_Input_Format = {}) -> Shader {
  339. return s.rb.load_shader(shader_source, layout_formats)
  340. }
  341. destroy_shader :: proc(shader: Shader) {
  342. s.rb.destroy_shader(shader)
  343. }
  344. set_shader :: proc(shader: Maybe(Shader)) {
  345. if maybe_handle_equal(shader, s.batch_shader) {
  346. return
  347. }
  348. draw_current_batch()
  349. s.batch_shader = shader
  350. }
  351. maybe_handle_equal :: proc(m1: Maybe($T), m2: Maybe(T)) -> bool {
  352. if m1 == nil && m2 == nil {
  353. return true
  354. }
  355. m1v, m1v_ok := m1.?
  356. m2v, m2v_ok := m2.?
  357. if !m1v_ok || !m2v_ok {
  358. return false
  359. }
  360. return m1v.handle == m2v.handle
  361. }
  362. set_shader_constant :: proc(shd: Shader, loc: Shader_Constant_Location, val: $T) {
  363. draw_current_batch()
  364. if int(loc.buffer_idx) >= len(shd.constant_buffers) {
  365. log.warnf("Constant buffer idx %v is out of bounds", loc.buffer_idx)
  366. return
  367. }
  368. b := &shd.constant_buffers[loc.buffer_idx]
  369. if int(loc.offset) + size_of(val) > len(b.cpu_data) {
  370. log.warnf("Constant buffer idx %v is trying to be written out of bounds by at offset %v with %v bytes", loc.buffer_idx, loc.offset, size_of(val))
  371. return
  372. }
  373. dst := (^T)(&b.cpu_data[loc.offset])
  374. dst^ = val
  375. }
  376. set_shader_constant_mat4 :: proc(shader: Shader, loc: Shader_Constant_Location, val: matrix[4,4]f32) {
  377. set_shader_constant(shader, loc, val)
  378. }
  379. set_shader_constant_f32 :: proc(shader: Shader, loc: Shader_Constant_Location, val: f32) {
  380. set_shader_constant(shader, loc, val)
  381. }
  382. set_shader_constant_vec2 :: proc(shader: Shader, loc: Shader_Constant_Location, val: Vec2) {
  383. set_shader_constant(shader, loc, val)
  384. }
  385. get_default_shader :: proc() -> Shader {
  386. return s.default_shader
  387. }
  388. set_scissor_rect :: proc(scissor_rect: Maybe(Rect)) {
  389. panic("not implemented")
  390. }
  391. screen_to_world :: proc(pos: Vec2, camera: Camera) -> Vec2 {
  392. panic("not implemented")
  393. }
  394. draw_text :: proc(text: string, pos: Vec2, font_size: f32, color: Color) {
  395. }
  396. mouse_button_went_down :: proc(button: Mouse_Button) -> bool {
  397. panic("not implemented")
  398. }
  399. mouse_button_went_up :: proc(button: Mouse_Button) -> bool {
  400. panic("not implemented")
  401. }
  402. mouse_button_is_held :: proc(button: Mouse_Button) -> bool {
  403. panic("not implemented")
  404. }
  405. get_mouse_wheel_delta :: proc() -> f32 {
  406. panic("not implemented")
  407. }
  408. get_mouse_position :: proc() -> Vec2 {
  409. panic("not implemented")
  410. }
  411. _batch_vertex :: proc(v: Vec2, uv: Vec2, color: Color) {
  412. v := v
  413. if s.vertex_buffer_cpu_used == len(s.vertex_buffer_cpu) {
  414. panic("Must dispatch here")
  415. }
  416. shd := s.batch_shader.? or_else s.default_shader
  417. base_offset := s.vertex_buffer_cpu_used
  418. pos_offset := shd.default_input_offsets[.Position]
  419. uv_offset := shd.default_input_offsets[.UV]
  420. color_offset := shd.default_input_offsets[.Color]
  421. if pos_offset != -1 {
  422. (^Vec2)(&s.vertex_buffer_cpu[base_offset + pos_offset])^ = v
  423. }
  424. if uv_offset != -1 {
  425. (^Vec2)(&s.vertex_buffer_cpu[base_offset + uv_offset])^ = uv
  426. }
  427. if color_offset != -1 {
  428. (^Color)(&s.vertex_buffer_cpu[base_offset + color_offset])^ = color
  429. }
  430. override_offset: int
  431. for &o, idx in shd.input_overrides {
  432. input := &shd.inputs[idx]
  433. sz := shader_input_format_size(input.format)
  434. if o.used != 0 {
  435. mem.copy(&s.vertex_buffer_cpu[base_offset + override_offset], raw_data(&o.val), o.used)
  436. }
  437. override_offset += sz
  438. }
  439. s.vertex_buffer_cpu_used += shd.vertex_size
  440. }
  441. State :: struct {
  442. allocator: runtime.Allocator,
  443. custom_context: runtime.Context,
  444. rb: Rendering_Backend,
  445. rb_state: rawptr,
  446. keys_went_down: #sparse [Keyboard_Key]bool,
  447. keys_went_up: #sparse [Keyboard_Key]bool,
  448. keys_is_held: #sparse [Keyboard_Key]bool,
  449. window: win32.HWND,
  450. width: int,
  451. height: int,
  452. run: bool,
  453. shape_drawing_texture: Texture_Handle,
  454. batch_camera: Maybe(Camera),
  455. batch_shader: Maybe(Shader),
  456. batch_texture: Texture_Handle,
  457. view_matrix: Mat4,
  458. proj_matrix: Mat4,
  459. vertex_buffer_cpu: []u8,
  460. vertex_buffer_cpu_used: int,
  461. default_shader: Shader,
  462. }
  463. VK_MAP := [255]Keyboard_Key {
  464. win32.VK_A = .A,
  465. win32.VK_B = .B,
  466. win32.VK_C = .C,
  467. win32.VK_D = .D,
  468. win32.VK_E = .E,
  469. win32.VK_F = .F,
  470. win32.VK_G = .G,
  471. win32.VK_H = .H,
  472. win32.VK_I = .I,
  473. win32.VK_J = .J,
  474. win32.VK_K = .K,
  475. win32.VK_L = .L,
  476. win32.VK_M = .M,
  477. win32.VK_N = .N,
  478. win32.VK_O = .O,
  479. win32.VK_P = .P,
  480. win32.VK_Q = .Q,
  481. win32.VK_R = .R,
  482. win32.VK_S = .S,
  483. win32.VK_T = .T,
  484. win32.VK_U = .U,
  485. win32.VK_V = .V,
  486. win32.VK_W = .W,
  487. win32.VK_X = .X,
  488. win32.VK_Y = .Y,
  489. win32.VK_Z = .Z,
  490. win32.VK_LEFT = .Left,
  491. win32.VK_RIGHT = .Right,
  492. win32.VK_UP = .Up,
  493. win32.VK_DOWN = .Down,
  494. }
  495. @(private="file")
  496. s: ^State
  497. Shader_Input_Format :: enum {
  498. Unknown,
  499. RGBA32_Float,
  500. RGBA8_Norm,
  501. RGBA8_Norm_SRGB,
  502. RG32_Float,
  503. R32_Float,
  504. }
  505. Color :: [4]u8
  506. Vec2 :: [2]f32
  507. Vec3 :: [3]f32
  508. Mat4 :: matrix[4,4]f32
  509. Vec2i :: [2]int
  510. Rect :: struct {
  511. x, y: f32,
  512. w, h: f32,
  513. }
  514. Texture :: struct {
  515. handle: Texture_Handle,
  516. width: int,
  517. height: int,
  518. }
  519. Shader :: struct {
  520. handle: Shader_Handle,
  521. constant_buffers: []Shader_Constant_Buffer,
  522. constant_lookup: map[string]Shader_Constant_Location,
  523. constant_builtin_locations: [Shader_Builtin_Constant]Maybe(Shader_Constant_Location),
  524. inputs: []Shader_Input,
  525. input_overrides: []Shader_Input_Value_Override,
  526. default_input_offsets: [Shader_Default_Inputs]int,
  527. vertex_size: int,
  528. }
  529. Camera :: struct {
  530. target: Vec2,
  531. origin: Vec2,
  532. rotation: f32,
  533. zoom: f32,
  534. }
  535. // Support for up to 255 mouse buttons. Cast an int to type `Mouse_Button` to use things outside the
  536. // options presented here.
  537. Mouse_Button :: enum {
  538. Left,
  539. Right,
  540. Middle,
  541. Max = 255,
  542. }
  543. // TODO: These are just copied from raylib, we probably want a list of our own "default colors"
  544. WHITE :: Color { 255, 255, 255, 255 }
  545. BLACK :: Color { 0, 0, 0, 255 }
  546. GRAY :: Color{ 130, 130, 130, 255 }
  547. RED :: Color { 230, 41, 55, 255 }
  548. YELLOW :: Color { 253, 249, 0, 255 }
  549. BLUE :: Color { 0, 121, 241, 255 }
  550. MAGENTA :: Color { 255, 0, 255, 255 }
  551. DARKGRAY :: Color{ 80, 80, 80, 255 }
  552. GREEN :: Color{ 0, 228, 48, 255 }
  553. Shader_Handle :: distinct Handle
  554. SHADER_NONE :: Shader_Handle {}
  555. // Based on Raylib / GLFW
  556. Keyboard_Key :: enum {
  557. None = 0,
  558. // Alphanumeric keys
  559. Apostrophe = 39,
  560. Comma = 44,
  561. Minus = 45,
  562. Period = 46,
  563. Slash = 47,
  564. Zero = 48,
  565. One = 49,
  566. Two = 50,
  567. Three = 51,
  568. Four = 52,
  569. Five = 53,
  570. Six = 54,
  571. Seven = 55,
  572. Eight = 56,
  573. Nine = 57,
  574. Semicolon = 59,
  575. Equal = 61,
  576. A = 65,
  577. B = 66,
  578. C = 67,
  579. D = 68,
  580. E = 69,
  581. F = 70,
  582. G = 71,
  583. H = 72,
  584. I = 73,
  585. J = 74,
  586. K = 75,
  587. L = 76,
  588. M = 77,
  589. N = 78,
  590. O = 79,
  591. P = 80,
  592. Q = 81,
  593. R = 82,
  594. S = 83,
  595. T = 84,
  596. U = 85,
  597. V = 86,
  598. W = 87,
  599. X = 88,
  600. Y = 89,
  601. Z = 90,
  602. Left_Bracket = 91,
  603. Backslash = 92,
  604. Right_Bracket = 93,
  605. Grave = 96,
  606. // Function keys
  607. Space = 32,
  608. Escape = 256,
  609. Enter = 257,
  610. Tab = 258,
  611. Backspace = 259,
  612. Insert = 260,
  613. Delete = 261,
  614. Right = 262,
  615. Left = 263,
  616. Down = 264,
  617. Up = 265,
  618. Page_Up = 266,
  619. Page_Down = 267,
  620. Home = 268,
  621. End = 269,
  622. Caps_Lock = 280,
  623. Scroll_Lock = 281,
  624. Num_Lock = 282,
  625. Print_Screen = 283,
  626. Pause = 284,
  627. F1 = 290,
  628. F2 = 291,
  629. F3 = 292,
  630. F4 = 293,
  631. F5 = 294,
  632. F6 = 295,
  633. F7 = 296,
  634. F8 = 297,
  635. F9 = 298,
  636. F10 = 299,
  637. F11 = 300,
  638. F12 = 301,
  639. Left_Shift = 340,
  640. Left_Control = 341,
  641. Left_Alt = 342,
  642. Left_Super = 343,
  643. Right_Shift = 344,
  644. Right_Control = 345,
  645. Right_Alt = 346,
  646. Right_Super = 347,
  647. Menu = 348,
  648. // Keypad keys
  649. KP_0 = 320,
  650. KP_1 = 321,
  651. KP_2 = 322,
  652. KP_3 = 323,
  653. KP_4 = 324,
  654. KP_5 = 325,
  655. KP_6 = 326,
  656. KP_7 = 327,
  657. KP_8 = 328,
  658. KP_9 = 329,
  659. KP_Decimal = 330,
  660. KP_Divide = 331,
  661. KP_Multiply = 332,
  662. KP_Subtract = 333,
  663. KP_Add = 334,
  664. KP_Enter = 335,
  665. KP_Equal = 336,
  666. }