karl2d_raylib.odin 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. package karl2d
  2. import rl "raylib"
  3. import "raylib/rlgl"
  4. import "core:log"
  5. import "core:strings"
  6. import "base:runtime"
  7. _init :: proc(width: int, height: int, title: string,
  8. allocator := context.allocator, loc := #caller_location) -> ^State {
  9. s = new(State, allocator, loc)
  10. s.textures = make([dynamic]rl.Texture, allocator, loc)
  11. s.allocator = allocator
  12. rl.SetConfigFlags({.WINDOW_RESIZABLE, .VSYNC_HINT})
  13. rl.InitWindow(i32(width), i32(height), temp_cstring(title))
  14. return s
  15. }
  16. _shutdown :: proc() {
  17. rl.CloseWindow()
  18. if s != nil {
  19. delete(s.textures)
  20. a := s.allocator
  21. free(s, a)
  22. s = nil
  23. }
  24. }
  25. _set_internal_state :: proc(new_state: ^State) {
  26. s = new_state
  27. }
  28. _clear :: proc(color: Color) {
  29. rl.ClearBackground(rl.Color(color))
  30. }
  31. s: ^State
  32. State :: struct {
  33. textures: [dynamic]rl.Texture,
  34. allocator: runtime.Allocator,
  35. implicitly_created: bool,
  36. }
  37. _load_texture :: proc(filename: string) -> Texture {
  38. tex := rl.LoadTexture(temp_cstring(filename))
  39. if tex.id == 0 {
  40. return {}
  41. }
  42. if len(s.textures) == 0 {
  43. append(&s.textures, rl.Texture{})
  44. }
  45. tex_id := Texture_Handle(len(s.textures))
  46. append(&s.textures, tex)
  47. return {
  48. id = tex_id,
  49. width = int(tex.width),
  50. height = int(tex.height),
  51. }
  52. }
  53. _destroy_texture :: proc(tex: Texture) {
  54. if tex.id < 1 || int(tex.id) >= len(s.textures) {
  55. return
  56. }
  57. rl.UnloadTexture(s.textures[tex.id])
  58. s.textures[tex.id] = {}
  59. }
  60. _draw_texture :: proc(tex: Texture, pos: Vec2, tint := WHITE) {
  61. _draw_texture_ex(
  62. tex,
  63. {0, 0, f32(tex.width), f32(tex.height)},
  64. {pos.x, pos.y, f32(tex.width), f32(tex.height)},
  65. {},
  66. 0,
  67. tint,
  68. )
  69. }
  70. _draw_texture_rect :: proc(tex: Texture, rect: Rect, pos: Vec2, tint := WHITE) {
  71. _draw_texture_ex(
  72. tex,
  73. rect,
  74. {pos.x, pos.y, rect.w, rect.h},
  75. {},
  76. 0,
  77. tint,
  78. )
  79. }
  80. _draw_texture_ex :: proc(tex: Texture, src: Rect, dst: Rect, origin: Vec2, rot: f32, tint := WHITE) {
  81. if tex.id == 0 {
  82. log.error("Invalid texture.")
  83. return
  84. }
  85. rl.DrawTexturePro(
  86. s.textures[tex.id],
  87. transmute(rl.Rectangle)(src),
  88. transmute(rl.Rectangle)(dst),
  89. origin,
  90. rot,
  91. rl.Color(tint),
  92. )
  93. }
  94. _draw_rectangle :: proc(rect: Rect, color: Color) {
  95. rl.DrawRectangleRec(rl_rect(rect), rl_color(color))
  96. }
  97. _draw_rectangle_outline :: proc(rect: Rect, thickness: f32, color: Color) {
  98. rl.DrawRectangleLinesEx(rl_rect(rect), thickness, rl_color(color))
  99. }
  100. _draw_circle :: proc(center: Vec2, radius: f32, color: Color) {
  101. rl.DrawCircleV(center, radius, rl_color(color))
  102. }
  103. _draw_line :: proc(start: Vec2, end: Vec2, thickness: f32, color: Color) {
  104. rl.DrawLineEx(start, end, thickness, rl_color(color))
  105. }
  106. _get_screen_width :: proc() -> int {
  107. return int(rl.GetScreenWidth())
  108. }
  109. _get_screen_height :: proc() -> int {
  110. return int(rl.GetScreenHeight())
  111. }
  112. _key_pressed :: proc(key: Keyboard_Key) -> bool {
  113. return rl.IsKeyPressed(rl.KeyboardKey(key))
  114. }
  115. _key_released :: proc(key: Keyboard_Key) -> bool {
  116. return rl.IsKeyReleased(rl.KeyboardKey(key))
  117. }
  118. _key_held :: proc(key: Keyboard_Key) -> bool {
  119. return rl.IsKeyDown(rl.KeyboardKey(key))
  120. }
  121. _window_should_close :: proc() -> bool {
  122. return rl.WindowShouldClose()
  123. }
  124. rl_texture :: proc(tex: Texture) -> rl.Texture {
  125. if tex.id < 1 || int(tex.id) >= len(s.textures) {
  126. return {}
  127. }
  128. return s.textures[tex.id]
  129. }
  130. rl_rect :: proc(r: Rect) -> rl.Rectangle {
  131. return transmute(rl.Rectangle)(r)
  132. }
  133. rl_color :: proc(c: Color) -> rl.Color {
  134. return (rl.Color)(c)
  135. }
  136. _draw_text :: proc(text: string, pos: Vec2, font_size: f32, color: Color) {
  137. rl.DrawTextEx(rl.GetFontDefault(), temp_cstring(text), pos, font_size, 1, rl_color(color))
  138. }
  139. _mouse_button_pressed :: proc(button: Mouse_Button) -> bool {
  140. return rl.IsMouseButtonPressed(rl.MouseButton(button))
  141. }
  142. _mouse_button_released :: proc(button: Mouse_Button) -> bool {
  143. return rl.IsMouseButtonReleased(rl.MouseButton(button))
  144. }
  145. _mouse_button_held :: proc(button: Mouse_Button) -> bool {
  146. return rl.IsMouseButtonDown(rl.MouseButton(button))
  147. }
  148. _mouse_wheel_delta :: proc() -> f32 {
  149. return rl.GetMouseWheelMove()
  150. }
  151. _mouse_position :: proc() -> Vec2 {
  152. return rl.GetMousePosition()
  153. }
  154. _enable_scissor :: proc(x, y, w, h: int) {
  155. rl.BeginScissorMode(i32(x), i32(y), i32(w), i32(h))
  156. }
  157. _disable_scissor :: proc() {
  158. rl.EndScissorMode()
  159. }
  160. _set_window_size :: proc(width: int, height: int) {
  161. rl.SetWindowSize(i32(width), i32(height))
  162. }
  163. _set_window_position :: proc(x: int, y: int) {
  164. rl.SetWindowPosition(i32(x), i32(y))
  165. }
  166. _screen_to_world :: proc(pos: Vec2, camera: Camera) -> Vec2 {
  167. return rl.GetScreenToWorld2D(pos, rl_camera(camera))
  168. }
  169. rl_camera :: proc(camera: Camera) -> rl.Camera2D {
  170. return {
  171. offset = camera.origin,
  172. target = camera.target,
  173. rotation = camera.rotation,
  174. zoom = camera.zoom,
  175. }
  176. }
  177. _set_camera :: proc(camera: Maybe(Camera)) {
  178. // TODO: Only do something if the camera is actually different.
  179. rlgl.DrawRenderBatchActive()
  180. rlgl.LoadIdentity()
  181. if c, c_ok := camera.?; c_ok {
  182. camera_mat := rl.MatrixToFloatV(rl.GetCameraMatrix2D(rl_camera(c)))
  183. rlgl.MultMatrixf(&camera_mat[0])
  184. }
  185. }
  186. _set_scissor_rect :: proc(scissor_rect: Maybe(Rect)) {
  187. // TODO: Only do something if the scissor rect is actually different
  188. rlgl.DrawRenderBatchActive()
  189. if s, s_ok := scissor_rect.?; s_ok {
  190. rl.BeginScissorMode(i32(s.x), i32(s.y), i32(s.w), i32(s.h))
  191. } else {
  192. rlgl.DisableScissorTest()
  193. }
  194. }
  195. _process_events :: proc() {
  196. rl.PollInputEvents()
  197. }
  198. _flush :: proc() {
  199. rlgl.DrawRenderBatchActive()
  200. }
  201. _present :: proc(do_flush := true) {
  202. if do_flush {
  203. rlgl.DrawRenderBatchActive()
  204. }
  205. rl.SwapScreenBuffer()
  206. }
  207. temp_cstring :: proc(str: string) -> cstring {
  208. return strings.clone_to_cstring(str, context.temp_allocator)
  209. }