karl2d.odin 21 KB

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