punity.odin 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. #import "win32.odin"
  2. #import "fmt.odin"
  3. #import "os.odin"
  4. CANVAS_WIDTH :: 128
  5. CANVAS_HEIGHT :: 128
  6. CANVAS_SCALE :: 3
  7. FRAME_TIME :: 1.0/30.0
  8. WINDOW_TITLE : string : "Punity\x00"
  9. _ := compile_assert(CANVAS_WIDTH % 16 == 0)
  10. WINDOW_WIDTH :: CANVAS_WIDTH * CANVAS_SCALE
  11. WINDOW_HEIGHT :: CANVAS_HEIGHT * CANVAS_SCALE
  12. STACK_CAPACITY :: 1<<20
  13. STORAGE_CAPACITY :: 1<<20
  14. DRAW_LIST_RESERVE :: 128
  15. MAX_KEYS :: 256
  16. Core :: struct {
  17. stack: ^Bank
  18. storage: ^Bank
  19. running: bool
  20. key_modifiers: u32
  21. key_states: [MAX_KEYS]byte
  22. key_deltas: [MAX_KEYS]byte
  23. perf_frame,
  24. perf_frame_inner,
  25. perf_step,
  26. perf_audio,
  27. perf_blit,
  28. perf_blit_cvt,
  29. perf_blit_gdi: Perf_Span
  30. frame: i64
  31. canvas: Canvas
  32. draw_list: ^Draw_List
  33. }
  34. Perf_Span :: struct {
  35. stamp: f64
  36. delta: f32
  37. }
  38. Bank :: struct {
  39. memory: []byte
  40. cursor: int
  41. }
  42. Bank_State :: struct {
  43. state: Bank
  44. bank: ^Bank
  45. }
  46. Color :: raw_union {
  47. using channels: struct{ a, b, g, r: byte }
  48. rgba: u32
  49. }
  50. Palette :: struct {
  51. colors: [256]Color
  52. colors_count: byte
  53. }
  54. Rect :: raw_union {
  55. using minmax: struct {
  56. min_x, min_y, max_x, max_y: int
  57. }
  58. using pos: struct {
  59. left, top, right, bottom: int
  60. }
  61. e: [4]int
  62. }
  63. Bitmap :: struct {
  64. pixels: []byte
  65. width: int
  66. height: int
  67. }
  68. Font :: struct {
  69. using bitmap: Bitmap
  70. char_width: int
  71. char_height: int
  72. }
  73. Canvas :: struct {
  74. using bitmap: ^Bitmap
  75. palette: Palette
  76. translate_x: int
  77. translate_y: int
  78. clip: Rect
  79. font: ^Font
  80. }
  81. DrawFlag :: enum {
  82. NONE = 0,
  83. FLIP_H = 1<<0,
  84. FLIP_V = 1<<1,
  85. MASK = 1<<2,
  86. }
  87. Draw_List :: struct {
  88. Item :: struct {
  89. }
  90. items: []Item
  91. }
  92. Key :: enum {
  93. MOD_SHIFT = 0x0001,
  94. MOD_CONTROL = 0x0002,
  95. MOD_ALT = 0x0004,
  96. MOD_SUPER = 0x0008,
  97. UNKNOWN =-1,
  98. INVALID =-2,
  99. LBUTTON = 1,
  100. RBUTTON = 2,
  101. CANCEL = 3,
  102. MBUTTON = 4,
  103. BACK = 8,
  104. TAB = 9,
  105. CLEAR = 12,
  106. RETURN = 13,
  107. SHIFT = 16,
  108. CONTROL = 17,
  109. MENU = 18,
  110. PAUSE = 19,
  111. CAPITAL = 20,
  112. KANA = 0x15,
  113. HANGEUL = 0x15,
  114. HANGUL = 0x15,
  115. JUNJA = 0x17,
  116. FINAL = 0x18,
  117. HANJA = 0x19,
  118. KANJI = 0x19,
  119. ESCAPE = 0x1B,
  120. CONVERT = 0x1C,
  121. NONCONVERT = 0x1D,
  122. ACCEPT = 0x1E,
  123. MODECHANGE = 0x1F,
  124. SPACE = 32,
  125. PRIOR = 33,
  126. NEXT = 34,
  127. END = 35,
  128. HOME = 36,
  129. LEFT = 37,
  130. UP = 38,
  131. RIGHT = 39,
  132. DOWN = 40,
  133. SELECT = 41,
  134. PRINT = 42,
  135. EXEC = 43,
  136. SNAPSHOT = 44,
  137. INSERT = 45,
  138. DELETE = 46,
  139. HELP = 47,
  140. LWIN = 0x5B,
  141. RWIN = 0x5C,
  142. APPS = 0x5D,
  143. SLEEP = 0x5F,
  144. NUMPAD0 = 0x60,
  145. NUMPAD1 = 0x61,
  146. NUMPAD2 = 0x62,
  147. NUMPAD3 = 0x63,
  148. NUMPAD4 = 0x64,
  149. NUMPAD5 = 0x65,
  150. NUMPAD6 = 0x66,
  151. NUMPAD7 = 0x67,
  152. NUMPAD8 = 0x68,
  153. NUMPAD9 = 0x69,
  154. MULTIPLY = 0x6A,
  155. ADD = 0x6B,
  156. SEPARATOR = 0x6C,
  157. SUBTRACT = 0x6D,
  158. DECIMAL = 0x6E,
  159. DIVIDE = 0x6F,
  160. F1 = 0x70,
  161. F2 = 0x71,
  162. F3 = 0x72,
  163. F4 = 0x73,
  164. F5 = 0x74,
  165. F6 = 0x75,
  166. F7 = 0x76,
  167. F8 = 0x77,
  168. F9 = 0x78,
  169. F10 = 0x79,
  170. F11 = 0x7A,
  171. F12 = 0x7B,
  172. F13 = 0x7C,
  173. F14 = 0x7D,
  174. F15 = 0x7E,
  175. F16 = 0x7F,
  176. F17 = 0x80,
  177. F18 = 0x81,
  178. F19 = 0x82,
  179. F20 = 0x83,
  180. F21 = 0x84,
  181. F22 = 0x85,
  182. F23 = 0x86,
  183. F24 = 0x87,
  184. NUMLOCK = 0x90,
  185. SCROLL = 0x91,
  186. LSHIFT = 0xA0,
  187. RSHIFT = 0xA1,
  188. LCONTROL = 0xA2,
  189. RCONTROL = 0xA3,
  190. LMENU = 0xA4,
  191. RMENU = 0xA5,
  192. APOSTROPHE = 39, /* ' */
  193. COMMA = 44, /* , */
  194. MINUS = 45, /* - */
  195. PERIOD = 46, /* . */
  196. SLASH = 47, /* / */
  197. NUM0 = 48,
  198. NUM1 = 49,
  199. NUM2 = 50,
  200. NUM3 = 51,
  201. NUM4 = 52,
  202. NUM5 = 53,
  203. NUM6 = 54,
  204. NUM7 = 55,
  205. NUM8 = 56,
  206. NUM9 = 57,
  207. SEMICOLON = 59, /* ; */
  208. EQUAL = 61, /* = */
  209. A = 65,
  210. B = 66,
  211. C = 67,
  212. D = 68,
  213. E = 69,
  214. F = 70,
  215. G = 71,
  216. H = 72,
  217. I = 73,
  218. J = 74,
  219. K = 75,
  220. L = 76,
  221. M = 77,
  222. N = 78,
  223. O = 79,
  224. P = 80,
  225. Q = 81,
  226. R = 82,
  227. S = 83,
  228. T = 84,
  229. U = 85,
  230. V = 86,
  231. W = 87,
  232. X = 88,
  233. Y = 89,
  234. Z = 90,
  235. LEFT_BRACKET = 91, /* [ */
  236. BACKSLASH = 92, /* \ */
  237. RIGHT_BRACKET = 93, /* ] */
  238. GRAVE_ACCENT = 96, /* ` */
  239. }
  240. key_down :: proc(k: Key) -> bool {
  241. return _core.key_states[k] != 0
  242. }
  243. key_pressed :: proc(k: Key) -> bool {
  244. return (_core.key_deltas[k] != 0) && key_down(k)
  245. }
  246. win32_perf_count_freq := win32.GetQueryPerformanceFrequency()
  247. time_now :: proc() -> f64 {
  248. assert(win32_perf_count_freq != 0)
  249. counter: i64
  250. win32.QueryPerformanceCounter(^counter)
  251. result := counter as f64 / win32_perf_count_freq as f64
  252. return result
  253. }
  254. _core: Core
  255. run :: proc(user_init, user_step: proc(c: ^Core)) {
  256. using win32
  257. _core.running = true
  258. win32_proc :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #no_inline #stdcall {
  259. win32_app_key_mods :: proc() -> u32 {
  260. mods: u32 = 0
  261. if is_key_down(Key_Code.SHIFT) {
  262. mods |= Key.MOD_SHIFT as u32;
  263. }
  264. if is_key_down(Key_Code.CONTROL) {
  265. mods |= Key.MOD_CONTROL as u32;
  266. }
  267. if is_key_down(Key_Code.MENU) {
  268. mods |= Key.MOD_ALT as u32;
  269. }
  270. if is_key_down(Key_Code.LWIN) || is_key_down(Key_Code.RWIN) {
  271. mods |= Key.MOD_SUPER as u32;
  272. }
  273. return mods
  274. }
  275. match msg {
  276. case WM_KEYDOWN:
  277. _core.key_modifiers = win32_app_key_mods()
  278. if wparam < MAX_KEYS {
  279. _core.key_states[wparam] = 1
  280. _core.key_deltas[wparam] = 1
  281. }
  282. return 0
  283. case WM_KEYUP:
  284. _core.key_modifiers = win32_app_key_mods()
  285. if wparam < MAX_KEYS {
  286. _core.key_states[wparam] = 0
  287. _core.key_deltas[wparam] = 1
  288. }
  289. return 0
  290. case WM_CLOSE:
  291. PostQuitMessage(0)
  292. _core.running = false
  293. return 0
  294. }
  295. return DefWindowProcA(hwnd, msg, wparam, lparam)
  296. }
  297. window_class := WNDCLASSEXA{
  298. class_name = ("Punity\x00" as string).data, // C-style string
  299. size = size_of(WNDCLASSEXA) as u32,
  300. style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
  301. instance = GetModuleHandleA(null) as HINSTANCE,
  302. wnd_proc = win32_proc,
  303. // wnd_proc = DefWindowProcA,
  304. background = GetStockObject(BLACK_BRUSH) as HBRUSH,
  305. }
  306. if RegisterClassExA(^window_class) == 0 {
  307. fmt.fprintln(os.stderr, "RegisterClassExA failed")
  308. return
  309. }
  310. screen_width := GetSystemMetrics(SM_CXSCREEN)
  311. screen_height := GetSystemMetrics(SM_CYSCREEN)
  312. rc: RECT
  313. rc.left = (screen_width - WINDOW_WIDTH) / 2
  314. rc.top = (screen_height - WINDOW_HEIGHT) / 2
  315. rc.right = rc.left + WINDOW_WIDTH
  316. rc.bottom = rc.top + WINDOW_HEIGHT
  317. style: u32 = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX
  318. assert(AdjustWindowRect(^rc, style, 0) != 0)
  319. wt := WINDOW_TITLE
  320. win32_window := CreateWindowExA(0,
  321. window_class.class_name,
  322. wt.data,
  323. style,
  324. rc.left, rc.top,
  325. rc.right-rc.left, rc.bottom-rc.top,
  326. null, null, window_class.instance,
  327. null);
  328. if win32_window == null {
  329. fmt.fprintln(os.stderr, "CreateWindowExA failed")
  330. return
  331. }
  332. window_bmi: BITMAPINFO;
  333. window_bmi.size = size_of(BITMAPINFO.HEADER) as u32
  334. window_bmi.width = CANVAS_WIDTH
  335. window_bmi.height = CANVAS_HEIGHT
  336. window_bmi.planes = 1
  337. window_bmi.bit_count = 32
  338. window_bmi.compression = BI_RGB
  339. user_init(^_core)
  340. ShowWindow(win32_window, SW_SHOW)
  341. window_buffer := new_slice(u32, CANVAS_WIDTH * CANVAS_HEIGHT);
  342. assert(window_buffer.data != null)
  343. defer free(window_buffer.data)
  344. for i := 0; i < window_buffer.count; i++ {
  345. window_buffer[i] = 0xff00ff
  346. }
  347. prev_time, curr_time,dt: f64
  348. prev_time = time_now()
  349. curr_time = time_now()
  350. total_time : f64 = 0
  351. offset_x := 0;
  352. offset_y := 0;
  353. message: MSG
  354. for _core.running {
  355. curr_time = time_now()
  356. dt = curr_time - prev_time
  357. prev_time = curr_time
  358. total_time += dt
  359. offset_x += 1
  360. offset_y += 2
  361. {
  362. data: [128]byte
  363. buf := data[:0]
  364. fmt.bprintf(^buf, "Punity: % ms\x00", dt*1000)
  365. win32.SetWindowTextA(win32_window, buf.data)
  366. }
  367. for y := 0; y < CANVAS_HEIGHT; y++ {
  368. for x := 0; x < CANVAS_WIDTH; x++ {
  369. g := (x % 32) * 8
  370. b := (y % 32) * 8
  371. window_buffer[x + y*CANVAS_WIDTH] = (g << 8 | b) as u32
  372. }
  373. }
  374. memory_zero(^_core.key_deltas[0], size_of_val(_core.key_deltas[0]))
  375. for PeekMessageA(^message, null, 0, 0, PM_REMOVE) != 0 {
  376. if message.message == WM_QUIT {
  377. _core.running = false
  378. }
  379. TranslateMessage(^message)
  380. DispatchMessageA(^message)
  381. }
  382. user_step(^_core)
  383. dc := GetDC(win32_window);
  384. StretchDIBits(dc,
  385. 0, 0, CANVAS_WIDTH * CANVAS_SCALE, CANVAS_HEIGHT * CANVAS_SCALE,
  386. 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
  387. window_buffer.data,
  388. ^window_bmi,
  389. DIB_RGB_COLORS,
  390. SRCCOPY)
  391. ReleaseDC(win32_window, dc)
  392. {
  393. delta := time_now() - prev_time
  394. ms := ((FRAME_TIME - delta) * 1000) as i32
  395. if ms > 0 {
  396. win32.Sleep(ms)
  397. }
  398. }
  399. _core.frame++
  400. }
  401. }