punity.odin 11 KB

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