karl2d.odin 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. package karl2d
  2. import win32 "core:sys/windows"
  3. import "base:runtime"
  4. import "core:mem"
  5. import "core:log"
  6. // Opens a window and initializes some internal state. The internal state will use `allocator` for
  7. // all dynamically allocated memory. The return value can be ignored unless you need to later call
  8. // `set_state`.
  9. init :: proc(window_width: int, window_height: int, window_title: string,
  10. allocator := context.allocator, loc := #caller_location) -> ^State {
  11. win32.SetProcessDPIAware()
  12. s = new(State, allocator, loc)
  13. s.allocator = allocator
  14. s.custom_context = context
  15. CLASS_NAME :: "karl2d"
  16. instance := win32.HINSTANCE(win32.GetModuleHandleW(nil))
  17. s.run = true
  18. s.width = window_width
  19. s.height = window_height
  20. cls := win32.WNDCLASSW {
  21. lpfnWndProc = window_proc,
  22. lpszClassName = CLASS_NAME,
  23. hInstance = instance,
  24. hCursor = win32.LoadCursorA(nil, win32.IDC_ARROW),
  25. }
  26. window_proc :: proc "stdcall" (hwnd: win32.HWND, msg: win32.UINT, wparam: win32.WPARAM, lparam: win32.LPARAM) -> win32.LRESULT {
  27. context = s.custom_context
  28. switch msg {
  29. case win32.WM_DESTROY:
  30. win32.PostQuitMessage(0)
  31. s.run = false
  32. case win32.WM_CLOSE:
  33. s.run = false
  34. case win32.WM_KEYDOWN:
  35. key := VK_MAP[wparam]
  36. s.keys_went_down[key] = true
  37. s.keys_is_held[key] = true
  38. case win32.WM_KEYUP:
  39. key := VK_MAP[wparam]
  40. s.keys_is_held[key] = false
  41. s.keys_went_up[key] = true
  42. }
  43. return win32.DefWindowProcW(hwnd, msg, wparam, lparam)
  44. }
  45. win32.RegisterClassW(&cls)
  46. r: win32.RECT
  47. r.right = i32(window_width)
  48. r.bottom = i32(window_height)
  49. style := win32.WS_OVERLAPPEDWINDOW | win32.WS_VISIBLE
  50. win32.AdjustWindowRect(&r, style, false)
  51. hwnd := win32.CreateWindowW(CLASS_NAME,
  52. win32.utf8_to_wstring(window_title),
  53. style,
  54. 100, 10, r.right - r.left, r.bottom - r.top,
  55. nil, nil, instance, nil)
  56. s.window = hwnd
  57. assert(hwnd != nil, "Failed creating window")
  58. s.rb = BACKEND_D3D11
  59. rb_alloc_error: runtime.Allocator_Error
  60. s.rb_state, rb_alloc_error = mem.alloc(s.rb.state_size())
  61. log.assertf(rb_alloc_error == nil, "Failed allocating memory for rendering backend: %v", rb_alloc_error)
  62. s.rb.init(s.rb_state, uintptr(hwnd), window_width, window_height, allocator, loc)
  63. return s
  64. }
  65. // Closes the window and cleans up the internal state.
  66. shutdown :: proc() {
  67. s.rb.shutdown()
  68. win32.DestroyWindow(s.window)
  69. a := s.allocator
  70. free(s.rb_state, a)
  71. free(s, a)
  72. s = nil
  73. }
  74. // Clear the backbuffer with supplied color.
  75. clear :: proc(color: Color) {
  76. s.rb.clear(color)
  77. }
  78. // Present the backbuffer. Call at end of frame to make everything you've drawn appear on the screen.
  79. present :: proc() {
  80. s.rb.present()
  81. }
  82. // Call at start or end of frame to process all events that have arrived to the window.
  83. //
  84. // WARNING: Not calling this will make your program impossible to interact with.
  85. process_events :: proc() {
  86. s.keys_went_up = {}
  87. s.keys_went_down = {}
  88. msg: win32.MSG
  89. for win32.PeekMessageW(&msg, nil, 0, 0, win32.PM_REMOVE) {
  90. win32.TranslateMessage(&msg)
  91. win32.DispatchMessageW(&msg)
  92. }
  93. }
  94. /* Flushes the current batch. This sends off everything to the GPU that has been queued in the
  95. current batch. Normally, you do not need to do this manually. It is done automatically when these
  96. procedures run:
  97. present
  98. set_camera
  99. set_shader
  100. TODO: complete this list and motivate why it needs to happen on those procs (or do that in the
  101. docs for those procs).
  102. */
  103. draw_current_batch :: proc() {
  104. s.rb.draw_current_batch()
  105. }
  106. // Can be used to restore the internal state using the pointer returned by `init`. Useful after
  107. // reloading the library (for example, when doing code hot reload).
  108. set_internal_state :: proc(state: ^State) {
  109. s = state
  110. s.rb.set_internal_state(s.rb_state)
  111. }
  112. get_screen_width :: proc() -> int {
  113. return s.rb.get_swapchain_width()
  114. }
  115. get_screen_height :: proc() -> int {
  116. return s.rb.get_swapchain_height()
  117. }
  118. key_went_down :: proc(key: Keyboard_Key) -> bool {
  119. return s.keys_went_down[key]
  120. }
  121. key_went_up :: proc(key: Keyboard_Key) -> bool {
  122. return s.keys_went_up[key]
  123. }
  124. key_is_held :: proc(key: Keyboard_Key) -> bool {
  125. return s.keys_is_held[key]
  126. }
  127. // Returns true if the user has tried to close the window.
  128. window_should_close :: proc() -> bool {
  129. return !s.run
  130. }
  131. set_window_position :: proc(x: int, y: int) {
  132. // TODO: Does x, y respect monitor DPI?
  133. win32.SetWindowPos(
  134. s.window,
  135. {},
  136. i32(x),
  137. i32(y),
  138. 0,
  139. 0,
  140. win32.SWP_NOACTIVATE | win32.SWP_NOZORDER | win32.SWP_NOSIZE,
  141. )
  142. }
  143. Rendering_Backend :: struct {
  144. state_size: proc() -> int,
  145. init: proc(state: rawptr, window_handle: uintptr, swapchain_width, swapchain_height: int,
  146. allocator := context.allocator, loc := #caller_location),
  147. shutdown: proc(),
  148. clear: proc(color: Color),
  149. present: proc(),
  150. draw_current_batch: proc(),
  151. set_internal_state: proc(state: rawptr),
  152. get_swapchain_width: proc() -> int,
  153. get_swapchain_height: proc() -> int,
  154. }
  155. State :: struct {
  156. allocator: runtime.Allocator,
  157. custom_context: runtime.Context,
  158. rb: Rendering_Backend,
  159. rb_state: rawptr,
  160. keys_went_down: #sparse [Keyboard_Key]bool,
  161. keys_went_up: #sparse [Keyboard_Key]bool,
  162. keys_is_held: #sparse [Keyboard_Key]bool,
  163. window: win32.HWND,
  164. width: int,
  165. height: int,
  166. run: bool,
  167. }
  168. VK_MAP := [255]Keyboard_Key {
  169. win32.VK_A = .A,
  170. win32.VK_B = .B,
  171. win32.VK_C = .C,
  172. win32.VK_D = .D,
  173. win32.VK_E = .E,
  174. win32.VK_F = .F,
  175. win32.VK_G = .G,
  176. win32.VK_H = .H,
  177. win32.VK_I = .I,
  178. win32.VK_J = .J,
  179. win32.VK_K = .K,
  180. win32.VK_L = .L,
  181. win32.VK_M = .M,
  182. win32.VK_N = .N,
  183. win32.VK_O = .O,
  184. win32.VK_P = .P,
  185. win32.VK_Q = .Q,
  186. win32.VK_R = .R,
  187. win32.VK_S = .S,
  188. win32.VK_T = .T,
  189. win32.VK_U = .U,
  190. win32.VK_V = .V,
  191. win32.VK_W = .W,
  192. win32.VK_X = .X,
  193. win32.VK_Y = .Y,
  194. win32.VK_Z = .Z,
  195. win32.VK_LEFT = .Left,
  196. win32.VK_RIGHT = .Right,
  197. win32.VK_UP = .Up,
  198. win32.VK_DOWN = .Down,
  199. }
  200. @(private="file")
  201. s: ^State
  202. // --------------------------------
  203. // old, non migrated API below
  204. set_window_size: proc(width: int, height: int) : _set_window_size
  205. get_default_shader: proc() -> Shader_Handle : _get_default_shader
  206. load_texture_from_file: proc(filename: string) -> Texture : _load_texture_from_file
  207. load_texture_from_memory: proc(data: []u8, width: int, height: int) -> Texture : _load_texture_from_memory
  208. // load_texture_from_bytes or buffer or something ()
  209. destroy_texture: proc(tex: Texture) : _destroy_texture
  210. set_camera: proc(camera: Maybe(Camera)) : _set_camera
  211. set_scissor_rect: proc(scissor_rect: Maybe(Rect)) : _set_scissor_rect
  212. set_shader: proc(shader: Shader_Handle) : _set_shader
  213. //set_vertex_value :: _set_vertex_value
  214. draw_texture: proc(tex: Texture, pos: Vec2, tint := WHITE) : _draw_texture
  215. draw_texture_rect: proc(tex: Texture, rect: Rect, pos: Vec2, tint := WHITE) : _draw_texture_rect
  216. draw_texture_ex: proc(tex: Texture, src: Rect, dest: Rect, origin: Vec2, rotation: f32, tint := WHITE) : _draw_texture_ex
  217. draw_rect: proc(rect: Rect, color: Color) : _draw_rectangle
  218. draw_rect_outline: proc(rect: Rect, thickness: f32, color: Color) : _draw_rectangle_outline
  219. draw_circle: proc(center: Vec2, radius: f32, color: Color) : _draw_circle
  220. draw_line: proc(start: Vec2, end: Vec2, thickness: f32, color: Color) : _draw_line
  221. load_shader: proc(shader_source: string, layout_formats: []Shader_Input_Format = {}) -> Shader_Handle : _load_shader
  222. destroy_shader: proc(shader: Shader_Handle) : _destroy_shader
  223. get_shader_constant_location: proc(shader: Shader_Handle, name: string) -> Shader_Constant_Location : _get_shader_constant_location
  224. set_shader_constant :: _set_shader_constant
  225. set_shader_constant_mat4: proc(shader: Shader_Handle, loc: Shader_Constant_Location, val: matrix[4,4]f32) : _set_shader_constant_mat4
  226. set_shader_constant_f32: proc(shader: Shader_Handle, loc: Shader_Constant_Location, val: f32) : _set_shader_constant_f32
  227. set_shader_constant_vec2: proc(shader: Shader_Handle, loc: Shader_Constant_Location, val: Vec2) : _set_shader_constant_vec2
  228. Shader_Input_Format :: enum {
  229. Unknown,
  230. RGBA32_Float,
  231. RGBA8_Norm,
  232. RGBA8_Norm_SRGB,
  233. RG32_Float,
  234. R32_Float,
  235. }
  236. // WARNING: Not proper text rendering yet... No font support etc
  237. draw_text: proc(text: string, pos: Vec2, font_size: f32, color: Color) : _draw_text
  238. screen_to_world: proc(pos: Vec2, camera: Camera) -> Vec2 : _screen_to_world
  239. mouse_button_went_down: proc(button: Mouse_Button) -> bool : _mouse_button_pressed
  240. mouse_button_went_up: proc(button: Mouse_Button) -> bool : _mouse_button_released
  241. mouse_button_is_held: proc(button: Mouse_Button) -> bool : _mouse_button_held
  242. get_mouse_wheel_delta: proc() -> f32 : _mouse_wheel_delta
  243. get_mouse_position: proc() -> Vec2 : _mouse_position
  244. Color :: [4]u8
  245. Vec2 :: [2]f32
  246. Vec2i :: [2]int
  247. Rect :: struct {
  248. x, y: f32,
  249. w, h: f32,
  250. }
  251. Texture :: struct {
  252. id: Texture_Handle,
  253. width: int,
  254. height: int,
  255. }
  256. Camera :: struct {
  257. target: Vec2,
  258. origin: Vec2,
  259. rotation: f32,
  260. zoom: f32,
  261. }
  262. // Support for up to 255 mouse buttons. Cast an int to type `Mouse_Button` to use things outside the
  263. // options presented here.
  264. Mouse_Button :: enum {
  265. Left,
  266. Right,
  267. Middle,
  268. Max = 255,
  269. }
  270. // TODO: These are just copied from raylib, we probably want a list of our own "default colors"
  271. WHITE :: Color { 255, 255, 255, 255 }
  272. BLACK :: Color { 0, 0, 0, 255 }
  273. GRAY :: Color{ 130, 130, 130, 255 }
  274. RED :: Color { 230, 41, 55, 255 }
  275. YELLOW :: Color { 253, 249, 0, 255 }
  276. BLUE :: Color { 0, 121, 241, 255 }
  277. MAGENTA :: Color { 255, 0, 255, 255 }
  278. DARKGRAY :: Color{ 80, 80, 80, 255 }
  279. GREEN :: Color{ 0, 228, 48, 255 }
  280. Shader_Handle :: distinct Handle
  281. SHADER_NONE :: Shader_Handle {}
  282. // Based on Raylib / GLFW
  283. Keyboard_Key :: enum {
  284. None = 0,
  285. // Alphanumeric keys
  286. Apostrophe = 39,
  287. Comma = 44,
  288. Minus = 45,
  289. Period = 46,
  290. Slash = 47,
  291. Zero = 48,
  292. One = 49,
  293. Two = 50,
  294. Three = 51,
  295. Four = 52,
  296. Five = 53,
  297. Six = 54,
  298. Seven = 55,
  299. Eight = 56,
  300. Nine = 57,
  301. Semicolon = 59,
  302. Equal = 61,
  303. A = 65,
  304. B = 66,
  305. C = 67,
  306. D = 68,
  307. E = 69,
  308. F = 70,
  309. G = 71,
  310. H = 72,
  311. I = 73,
  312. J = 74,
  313. K = 75,
  314. L = 76,
  315. M = 77,
  316. N = 78,
  317. O = 79,
  318. P = 80,
  319. Q = 81,
  320. R = 82,
  321. S = 83,
  322. T = 84,
  323. U = 85,
  324. V = 86,
  325. W = 87,
  326. X = 88,
  327. Y = 89,
  328. Z = 90,
  329. Left_Bracket = 91,
  330. Backslash = 92,
  331. Right_Bracket = 93,
  332. Grave = 96,
  333. // Function keys
  334. Space = 32,
  335. Escape = 256,
  336. Enter = 257,
  337. Tab = 258,
  338. Backspace = 259,
  339. Insert = 260,
  340. Delete = 261,
  341. Right = 262,
  342. Left = 263,
  343. Down = 264,
  344. Up = 265,
  345. Page_Up = 266,
  346. Page_Down = 267,
  347. Home = 268,
  348. End = 269,
  349. Caps_Lock = 280,
  350. Scroll_Lock = 281,
  351. Num_Lock = 282,
  352. Print_Screen = 283,
  353. Pause = 284,
  354. F1 = 290,
  355. F2 = 291,
  356. F3 = 292,
  357. F4 = 293,
  358. F5 = 294,
  359. F6 = 295,
  360. F7 = 296,
  361. F8 = 297,
  362. F9 = 298,
  363. F10 = 299,
  364. F11 = 300,
  365. F12 = 301,
  366. Left_Shift = 340,
  367. Left_Control = 341,
  368. Left_Alt = 342,
  369. Left_Super = 343,
  370. Right_Shift = 344,
  371. Right_Control = 345,
  372. Right_Alt = 346,
  373. Right_Super = 347,
  374. Menu = 348,
  375. // Keypad keys
  376. KP_0 = 320,
  377. KP_1 = 321,
  378. KP_2 = 322,
  379. KP_3 = 323,
  380. KP_4 = 324,
  381. KP_5 = 325,
  382. KP_6 = 326,
  383. KP_7 = 327,
  384. KP_8 = 328,
  385. KP_9 = 329,
  386. KP_Decimal = 330,
  387. KP_Divide = 331,
  388. KP_Multiply = 332,
  389. KP_Subtract = 333,
  390. KP_Add = 334,
  391. KP_Enter = 335,
  392. KP_Equal = 336,
  393. }