punity.odin 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. import win32 "core:sys/windows.odin";
  2. import "core:fmt.odin";
  3. import "core:os.odin";
  4. import "core:mem.odin";
  5. CANVAS_WIDTH :: 128;
  6. CANVAS_HEIGHT :: 128;
  7. CANVAS_SCALE :: 3;
  8. FRAME_TIME :: 1.0/30.0;
  9. WINDOW_TITLE :: "Punity\x00";
  10. _ :: compile_assert(CANVAS_WIDTH % 16 == 0);
  11. WINDOW_WIDTH :: CANVAS_WIDTH * CANVAS_SCALE;
  12. WINDOW_HEIGHT :: CANVAS_HEIGHT * CANVAS_SCALE;
  13. STACK_CAPACITY :: 1<<20;
  14. STORAGE_CAPACITY :: 1<<20;
  15. DRAW_LIST_RESERVE :: 128;
  16. MAX_KEYS :: 256;
  17. Core :: struct {
  18. stack: ^Bank,
  19. storage: ^Bank,
  20. running: bool,
  21. key_modifiers: u32,
  22. key_states: [MAX_KEYS]u8,
  23. key_deltas: [MAX_KEYS]u8,
  24. perf_frame,
  25. perf_frame_inner,
  26. perf_step,
  27. perf_audio,
  28. perf_blit,
  29. perf_blit_cvt,
  30. perf_blit_gdi: Perf_Span,
  31. frame: i64,
  32. canvas: Canvas,
  33. draw_list: ^Draw_List,
  34. }
  35. Perf_Span :: struct {
  36. stamp: f64,
  37. delta: f32,
  38. }
  39. Bank :: struct {
  40. memory: []u8,
  41. cursor: int,
  42. }
  43. Bank_State :: struct {
  44. state: Bank,
  45. bank: ^Bank,
  46. }
  47. Color :: struct #raw_union {
  48. using channels: struct{a, b, g, r: u8},
  49. rgba: u32,
  50. }
  51. Palette :: struct {
  52. colors: [256]Color,
  53. colors_count: u8,
  54. }
  55. Rect :: struct #raw_union {
  56. using minmax: struct {min_x, min_y, max_x, max_y: int},
  57. using pos: struct {left, top, right, bottom: int},
  58. e: [4]int,
  59. }
  60. Bitmap :: struct {
  61. pixels: []u8,
  62. width: int,
  63. height: int,
  64. }
  65. Font :: struct {
  66. using bitmap: Bitmap,
  67. char_width: int,
  68. char_height: int,
  69. }
  70. Canvas :: struct {
  71. using bitmap: ^Bitmap,
  72. palette: Palette,
  73. translate_x: int,
  74. translate_y: int,
  75. clip: Rect,
  76. font: ^Font,
  77. }
  78. DrawFlag :: enum {
  79. NONE = 0,
  80. FLIP_H = 1<<0,
  81. FLIP_V = 1<<1,
  82. MASK = 1<<2,
  83. }
  84. Draw_Item :: struct {}
  85. Draw_List :: struct {
  86. items: []Draw_Item,
  87. }
  88. Key :: enum {
  89. Mod_Shift = 0x0001,
  90. Mod_Control = 0x0002,
  91. Mod_Alt = 0x0004,
  92. Mod_Super = 0x0008,
  93. Unknown =-1,
  94. Invalid =-2,
  95. Lbutton = 1,
  96. Rbutton = 2,
  97. Cancel = 3,
  98. Mbutton = 4,
  99. Back = 8,
  100. Tab = 9,
  101. Clear = 12,
  102. Return = 13,
  103. Shift = 16,
  104. Control = 17,
  105. Menu = 18,
  106. Pause = 19,
  107. Capital = 20,
  108. Kana = 0x15,
  109. Hangeul = 0x15,
  110. Hangul = 0x15,
  111. Junja = 0x17,
  112. Final = 0x18,
  113. Hanja = 0x19,
  114. Kanji = 0x19,
  115. Escape = 0x1B,
  116. Convert = 0x1C,
  117. Non_Convert = 0x1D,
  118. Accept = 0x1E,
  119. Mode_Change = 0x1F,
  120. Space = 32,
  121. Prior = 33,
  122. Next = 34,
  123. End = 35,
  124. Home = 36,
  125. Left = 37,
  126. Up = 38,
  127. Right = 39,
  128. Down = 40,
  129. Select = 41,
  130. Print = 42,
  131. Exec = 43,
  132. Snapshot = 44,
  133. Insert = 45,
  134. Delete = 46,
  135. Help = 47,
  136. Lwin = 0x5B,
  137. Rwin = 0x5C,
  138. Apps = 0x5D,
  139. Sleep = 0x5F,
  140. Numpad0 = 0x60,
  141. Numpad1 = 0x61,
  142. Numpad2 = 0x62,
  143. Numpad3 = 0x63,
  144. Numpad4 = 0x64,
  145. Numpad5 = 0x65,
  146. Numpad6 = 0x66,
  147. Numpad7 = 0x67,
  148. Numpad8 = 0x68,
  149. Numpad9 = 0x69,
  150. Multiply = 0x6A,
  151. Add = 0x6B,
  152. Separator = 0x6C,
  153. Subtract = 0x6D,
  154. Decimal = 0x6E,
  155. Divide = 0x6F,
  156. F1 = 0x70,
  157. F2 = 0x71,
  158. F3 = 0x72,
  159. F4 = 0x73,
  160. F5 = 0x74,
  161. F6 = 0x75,
  162. F7 = 0x76,
  163. F8 = 0x77,
  164. F9 = 0x78,
  165. F10 = 0x79,
  166. F11 = 0x7A,
  167. F12 = 0x7B,
  168. F13 = 0x7C,
  169. F14 = 0x7D,
  170. F15 = 0x7E,
  171. F16 = 0x7F,
  172. F17 = 0x80,
  173. F18 = 0x81,
  174. F19 = 0x82,
  175. F20 = 0x83,
  176. F21 = 0x84,
  177. F22 = 0x85,
  178. F23 = 0x86,
  179. F24 = 0x87,
  180. Numlock = 0x90,
  181. Scroll = 0x91,
  182. Lshift = 0xA0,
  183. Rshift = 0xA1,
  184. Lcontrol = 0xA2,
  185. Rcontrol = 0xA3,
  186. Lmenu = 0xA4,
  187. Rmenu = 0xA5,
  188. Apostrophe = 39, /* ' */
  189. Comma = 44, /* , */
  190. Minus = 45, /* - */
  191. Period = 46, /* . */
  192. Slash = 47, /* / */
  193. Num0 = 48,
  194. Num1 = 49,
  195. Num2 = 50,
  196. Num3 = 51,
  197. Num4 = 52,
  198. Num5 = 53,
  199. Num6 = 54,
  200. Num7 = 55,
  201. Num8 = 56,
  202. Num9 = 57,
  203. Semicolon = 59, /* ; */
  204. Equal = 61, /* = */
  205. A = 65,
  206. B = 66,
  207. C = 67,
  208. D = 68,
  209. E = 69,
  210. F = 70,
  211. G = 71,
  212. H = 72,
  213. I = 73,
  214. J = 74,
  215. K = 75,
  216. L = 76,
  217. M = 77,
  218. N = 78,
  219. O = 79,
  220. P = 80,
  221. Q = 81,
  222. R = 82,
  223. S = 83,
  224. T = 84,
  225. U = 85,
  226. V = 86,
  227. W = 87,
  228. X = 88,
  229. Y = 89,
  230. Z = 90,
  231. Left_Bracket = 91, /* [ */
  232. Backslash = 92, /* \ */
  233. Right_Bracket = 93, /* ] */
  234. Grave_Accent = 96, /* ` */
  235. };
  236. key_down :: proc(k: Key) -> bool {
  237. return _core.key_states[k] != 0;
  238. }
  239. key_pressed :: proc(k: Key) -> bool {
  240. return (_core.key_deltas[k] != 0) && key_down(k);
  241. }
  242. win32_perf_count_freq := win32.get_query_performance_frequency();
  243. time_now :: proc() -> f64 {
  244. assert(win32_perf_count_freq != 0);
  245. counter: i64;
  246. win32.query_performance_counter(&counter);
  247. return f64(counter) / f64(win32_perf_count_freq);
  248. }
  249. _core: Core;
  250. run :: proc(user_init, user_step: proc(c: ^Core)) {
  251. using win32;
  252. _core.running = true;
  253. win32_proc :: proc(hwnd: win32.Hwnd, msg: u32, wparam: win32.Wparam, lparam: win32.Lparam) -> win32.Lresult #no_inline #cc_c {
  254. win32_app_key_mods :: proc() -> u32 {
  255. mods: u32 = 0;
  256. if is_key_down(Key_Code.Shift) do mods |= u32(Key.Mod_Shift);
  257. if is_key_down(Key_Code.Control) do mods |= u32(Key.Mod_Control);
  258. if is_key_down(Key_Code.Menu) do mods |= u32(Key.Mod_Alt);
  259. if is_key_down(Key_Code.Lwin) do mods |= u32(Key.Mod_Super);
  260. if is_key_down(Key_Code.Rwin) do mods |= u32(Key.Mod_Super);
  261. return mods;
  262. }
  263. match msg {
  264. case WM_KEYDOWN:
  265. _core.key_modifiers = win32_app_key_mods();
  266. if wparam < MAX_KEYS {
  267. _core.key_states[wparam] = 1;
  268. _core.key_deltas[wparam] = 1;
  269. }
  270. return 0;
  271. case WM_KEYUP:
  272. _core.key_modifiers = win32_app_key_mods();
  273. if wparam < MAX_KEYS {
  274. _core.key_states[wparam] = 0;
  275. _core.key_deltas[wparam] = 1;
  276. }
  277. return 0;
  278. case WM_CLOSE:
  279. post_quit_message(0);
  280. _core.running = false;
  281. return 0;
  282. }
  283. return def_window_proc_a(hwnd, msg, wparam, lparam);
  284. }
  285. class_name := "Punity\x00";
  286. window_class := Wnd_Class_Ex_A{
  287. class_name = &class_name[0],
  288. size = size_of(Wnd_Class_Ex_A),
  289. style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
  290. instance = Hinstance(get_module_handle_a(nil)),
  291. wnd_proc = win32_proc,
  292. background = Hbrush(get_stock_object(BLACK_BRUSH)),
  293. };
  294. if register_class_ex_a(&window_class) == 0 {
  295. fmt.fprintln(os.stderr, "register_class_ex_a failed");
  296. return;
  297. }
  298. screen_width := get_system_metrics(SM_CXSCREEN);
  299. screen_height := get_system_metrics(SM_CYSCREEN);
  300. rc: Rect;
  301. rc.left = (screen_width - WINDOW_WIDTH) / 2;
  302. rc.top = (screen_height - WINDOW_HEIGHT) / 2;
  303. rc.right = rc.left + WINDOW_WIDTH;
  304. rc.bottom = rc.top + WINDOW_HEIGHT;
  305. style: u32 = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
  306. assert(adjust_window_rect(&rc, style, 0) != 0);
  307. wt := WINDOW_TITLE;
  308. win32_window := create_window_ex_a(0,
  309. window_class.class_name,
  310. &wt[0],
  311. style,
  312. rc.left, rc.top,
  313. rc.right-rc.left, rc.bottom-rc.top,
  314. nil, nil, window_class.instance,
  315. nil);
  316. if win32_window == nil {
  317. fmt.fprintln(os.stderr, "create_window_ex_a failed");
  318. return;
  319. }
  320. window_bmi: Bitmap_Info;
  321. window_bmi.size = size_of(Bitmap_Info_Header);
  322. window_bmi.width = CANVAS_WIDTH;
  323. window_bmi.height = CANVAS_HEIGHT;
  324. window_bmi.planes = 1;
  325. window_bmi.bit_count = 32;
  326. window_bmi.compression = BI_RGB;
  327. user_init(&_core);
  328. show_window(win32_window, SW_SHOW);
  329. window_buffer := make([]u32, CANVAS_WIDTH * CANVAS_HEIGHT);
  330. defer free(window_buffer);
  331. for _, i in window_buffer do window_buffer[i] = 0xff00ff;
  332. dt: f64;
  333. prev_time := time_now();
  334. curr_time := time_now();
  335. total_time: f64 = 0;
  336. offset_x := 0;
  337. offset_y := 0;
  338. message: Msg;
  339. for _core.running {
  340. curr_time = time_now();
  341. dt = curr_time - prev_time;
  342. prev_time = curr_time;
  343. total_time += dt;
  344. offset_x += 1;
  345. offset_y += 2;
  346. {
  347. buf: [128]u8;
  348. s := fmt.bprintf(buf[..], "Punity: %.4f ms\x00", dt*1000);
  349. win32.set_window_text_a(win32_window, &s[0]);
  350. }
  351. for y in 0..CANVAS_HEIGHT {
  352. for x in 0..CANVAS_WIDTH {
  353. g := (x % 32) * 8;
  354. b := (y % 32) * 8;
  355. window_buffer[x + y*CANVAS_WIDTH] = u32(g << 8 | b);
  356. }
  357. }
  358. mem.zero(&_core.key_deltas[0], size_of(_core.key_deltas));
  359. for peek_message_a(&message, nil, 0, 0, PM_REMOVE) != 0 {
  360. if message.message == WM_QUIT {
  361. _core.running = false;
  362. }
  363. translate_message(&message);
  364. dispatch_message_a(&message);
  365. }
  366. user_step(&_core);
  367. dc := get_dc(win32_window);
  368. stretch_dibits(dc,
  369. 0, 0, CANVAS_WIDTH * CANVAS_SCALE, CANVAS_HEIGHT * CANVAS_SCALE,
  370. 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
  371. &window_buffer[0],
  372. &window_bmi,
  373. DIB_RGB_COLORS,
  374. SRCCOPY);
  375. release_dc(win32_window, dc);
  376. delta := time_now() - prev_time;
  377. if ms := i32((FRAME_TIME - delta) * 1000); ms > 0 {
  378. win32.sleep(ms);
  379. }
  380. _core.frame += 1;
  381. }
  382. }
  383. main :: proc() {
  384. user_init :: proc(c: ^Core) {
  385. }
  386. user_step :: proc(c: ^Core) {
  387. }
  388. run(user_init, user_step);
  389. }