karl2d.odin 23 KB

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