karl2d.odin 20 KB

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