karl2d.odin 24 KB

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