karl2d_raylib.odin 6.5 KB

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