karl2d.odin 26 KB

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