mirror of
https://github.com/odin-lang/Odin.git
synced 2025-12-29 17:34:34 +00:00
499 lines
10 KiB
Odin
499 lines
10 KiB
Odin
import (
|
|
win32 "sys/windows.odin";
|
|
"fmt.odin";
|
|
"os.odin";
|
|
"mem.odin";
|
|
)
|
|
|
|
const (
|
|
CANVAS_WIDTH = 128;
|
|
CANVAS_HEIGHT = 128;
|
|
CANVAS_SCALE = 3;
|
|
FRAME_TIME = 1.0/30.0;
|
|
WINDOW_TITLE = "Punity\x00";
|
|
)
|
|
|
|
const _ = compile_assert(CANVAS_WIDTH % 16 == 0);
|
|
|
|
const (
|
|
WINDOW_WIDTH = CANVAS_WIDTH * CANVAS_SCALE;
|
|
WINDOW_HEIGHT = CANVAS_HEIGHT * CANVAS_SCALE;
|
|
)
|
|
|
|
const (
|
|
STACK_CAPACITY = 1<<20;
|
|
STORAGE_CAPACITY = 1<<20;
|
|
|
|
DRAW_LIST_RESERVE = 128;
|
|
|
|
MAX_KEYS = 256;
|
|
)
|
|
|
|
type Core struct {
|
|
stack: ^Bank,
|
|
storage: ^Bank,
|
|
|
|
running: bool,
|
|
key_modifiers: u32,
|
|
key_states: [MAX_KEYS]u8,
|
|
key_deltas: [MAX_KEYS]u8,
|
|
|
|
perf_frame,
|
|
perf_frame_inner,
|
|
perf_step,
|
|
perf_audio,
|
|
perf_blit,
|
|
perf_blit_cvt,
|
|
perf_blit_gdi: Perf_Span,
|
|
|
|
frame: i64,
|
|
|
|
canvas: Canvas,
|
|
draw_list: ^Draw_List,
|
|
}
|
|
|
|
type Perf_Span struct {
|
|
stamp: f64,
|
|
delta: f32,
|
|
}
|
|
|
|
type Bank struct {
|
|
memory: []u8,
|
|
cursor: int,
|
|
}
|
|
|
|
type Bank_State struct {
|
|
state: Bank,
|
|
bank: ^Bank,
|
|
}
|
|
|
|
|
|
type Color raw_union {
|
|
using channels: struct{a, b, g, r: u8},
|
|
rgba: u32,
|
|
}
|
|
|
|
type Palette struct {
|
|
colors: [256]Color,
|
|
colors_count: u8,
|
|
}
|
|
|
|
|
|
type Rect raw_union {
|
|
using minmax: struct {min_x, min_y, max_x, max_y: int},
|
|
using pos: struct {left, top, right, bottom: int},
|
|
e: [4]int,
|
|
}
|
|
|
|
type Bitmap struct {
|
|
pixels: []u8,
|
|
width: int,
|
|
height: int,
|
|
}
|
|
|
|
type Font struct {
|
|
using bitmap: Bitmap,
|
|
char_width: int,
|
|
char_height: int,
|
|
}
|
|
|
|
type Canvas struct {
|
|
using bitmap: ^Bitmap,
|
|
palette: Palette,
|
|
translate_x: int,
|
|
translate_y: int,
|
|
clip: Rect,
|
|
font: ^Font,
|
|
}
|
|
|
|
type DrawFlag enum {
|
|
NONE = 0,
|
|
FLIP_H = 1<<0,
|
|
FLIP_V = 1<<1,
|
|
MASK = 1<<2,
|
|
}
|
|
|
|
type Draw_Item struct {}
|
|
type Draw_List struct {
|
|
items: []Draw_Item,
|
|
}
|
|
|
|
type Key enum {
|
|
ModShift = 0x0001,
|
|
ModControl = 0x0002,
|
|
ModAlt = 0x0004,
|
|
ModSuper = 0x0008,
|
|
|
|
|
|
Unknown =-1,
|
|
Invalid =-2,
|
|
|
|
|
|
Lbutton = 1,
|
|
Rbutton = 2,
|
|
Cancel = 3,
|
|
Mbutton = 4,
|
|
|
|
|
|
Back = 8,
|
|
Tab = 9,
|
|
Clear = 12,
|
|
Return = 13,
|
|
Shift = 16,
|
|
Control = 17,
|
|
Menu = 18,
|
|
Pause = 19,
|
|
Capital = 20,
|
|
Kana = 0x15,
|
|
Hangeul = 0x15,
|
|
Hangul = 0x15,
|
|
Junja = 0x17,
|
|
Final = 0x18,
|
|
Hanja = 0x19,
|
|
Kanji = 0x19,
|
|
Escape = 0x1B,
|
|
Convert = 0x1C,
|
|
NonConvert = 0x1D,
|
|
Accept = 0x1E,
|
|
ModeChange = 0x1F,
|
|
Space = 32,
|
|
Prior = 33,
|
|
Next = 34,
|
|
End = 35,
|
|
Home = 36,
|
|
Left = 37,
|
|
Up = 38,
|
|
Right = 39,
|
|
Down = 40,
|
|
Select = 41,
|
|
Print = 42,
|
|
Exec = 43,
|
|
Snapshot = 44,
|
|
Insert = 45,
|
|
Delete = 46,
|
|
Help = 47,
|
|
Lwin = 0x5B,
|
|
Rwin = 0x5C,
|
|
Apps = 0x5D,
|
|
Sleep = 0x5F,
|
|
Numpad0 = 0x60,
|
|
Numpad1 = 0x61,
|
|
Numpad2 = 0x62,
|
|
Numpad3 = 0x63,
|
|
Numpad4 = 0x64,
|
|
Numpad5 = 0x65,
|
|
Numpad6 = 0x66,
|
|
Numpad7 = 0x67,
|
|
Numpad8 = 0x68,
|
|
Numpad9 = 0x69,
|
|
Multiply = 0x6A,
|
|
Add = 0x6B,
|
|
Separator = 0x6C,
|
|
Subtract = 0x6D,
|
|
Decimal = 0x6E,
|
|
Divide = 0x6F,
|
|
F1 = 0x70,
|
|
F2 = 0x71,
|
|
F3 = 0x72,
|
|
F4 = 0x73,
|
|
F5 = 0x74,
|
|
F6 = 0x75,
|
|
F7 = 0x76,
|
|
F8 = 0x77,
|
|
F9 = 0x78,
|
|
F10 = 0x79,
|
|
F11 = 0x7A,
|
|
F12 = 0x7B,
|
|
F13 = 0x7C,
|
|
F14 = 0x7D,
|
|
F15 = 0x7E,
|
|
F16 = 0x7F,
|
|
F17 = 0x80,
|
|
F18 = 0x81,
|
|
F19 = 0x82,
|
|
F20 = 0x83,
|
|
F21 = 0x84,
|
|
F22 = 0x85,
|
|
F23 = 0x86,
|
|
F24 = 0x87,
|
|
Numlock = 0x90,
|
|
Scroll = 0x91,
|
|
Lshift = 0xA0,
|
|
Rshift = 0xA1,
|
|
Lcontrol = 0xA2,
|
|
Rcontrol = 0xA3,
|
|
Lmenu = 0xA4,
|
|
Rmenu = 0xA5,
|
|
|
|
|
|
Apostrophe = 39, /* ' */
|
|
Comma = 44, /* , */
|
|
Minus = 45, /* - */
|
|
Period = 46, /* . */
|
|
Slash = 47, /* / */
|
|
Num0 = 48,
|
|
Num1 = 49,
|
|
Num2 = 50,
|
|
Num3 = 51,
|
|
Num4 = 52,
|
|
Num5 = 53,
|
|
Num6 = 54,
|
|
Num7 = 55,
|
|
Num8 = 56,
|
|
Num9 = 57,
|
|
Semicolon = 59, /* ; */
|
|
Equal = 61, /* = */
|
|
A = 65,
|
|
B = 66,
|
|
C = 67,
|
|
D = 68,
|
|
E = 69,
|
|
F = 70,
|
|
G = 71,
|
|
H = 72,
|
|
I = 73,
|
|
J = 74,
|
|
K = 75,
|
|
L = 76,
|
|
M = 77,
|
|
N = 78,
|
|
O = 79,
|
|
P = 80,
|
|
Q = 81,
|
|
R = 82,
|
|
S = 83,
|
|
T = 84,
|
|
U = 85,
|
|
V = 86,
|
|
W = 87,
|
|
X = 88,
|
|
Y = 89,
|
|
Z = 90,
|
|
LeftBracket = 91, /* [ */
|
|
Backslash = 92, /* \ */
|
|
RightBracket = 93, /* ] */
|
|
GraveAccent = 96, /* ` */
|
|
};
|
|
|
|
|
|
proc key_down(k: Key) -> bool {
|
|
return _core.key_states[k] != 0;
|
|
}
|
|
|
|
proc key_pressed(k: Key) -> bool {
|
|
return (_core.key_deltas[k] != 0) && key_down(k);
|
|
}
|
|
|
|
|
|
|
|
|
|
let win32_perf_count_freq = win32.get_query_performance_frequency();
|
|
proc time_now() -> f64 {
|
|
assert(win32_perf_count_freq != 0);
|
|
|
|
var counter: i64;
|
|
win32.query_performance_counter(&counter);
|
|
return f64(counter) / f64(win32_perf_count_freq);
|
|
}
|
|
|
|
var _core: Core;
|
|
|
|
proc run(user_init, user_step: proc(c: ^Core)) {
|
|
using win32;
|
|
|
|
_core.running = true;
|
|
|
|
proc win32_proc(hwnd: win32.Hwnd, msg: u32, wparam: win32.Wparam, lparam: win32.Lparam) -> win32.Lresult #no_inline #cc_c {
|
|
proc win32_app_key_mods() -> u32 {
|
|
var mods: u32 = 0;
|
|
|
|
if is_key_down(KeyCode.Shift) {
|
|
mods |= u32(Key.ModShift);
|
|
}
|
|
if is_key_down(KeyCode.Control) {
|
|
mods |= u32(Key.ModControl);
|
|
}
|
|
if is_key_down(KeyCode.Menu) {
|
|
mods |= u32(Key.ModAlt);
|
|
}
|
|
if is_key_down(KeyCode.Lwin) || is_key_down(KeyCode.Rwin) {
|
|
mods |= u32(Key.ModSuper);
|
|
}
|
|
|
|
return mods;
|
|
}
|
|
|
|
match msg {
|
|
case WM_KEYDOWN:
|
|
_core.key_modifiers = win32_app_key_mods();
|
|
if wparam < MAX_KEYS {
|
|
_core.key_states[wparam] = 1;
|
|
_core.key_deltas[wparam] = 1;
|
|
}
|
|
return 0;
|
|
|
|
case WM_KEYUP:
|
|
_core.key_modifiers = win32_app_key_mods();
|
|
if wparam < MAX_KEYS {
|
|
_core.key_states[wparam] = 0;
|
|
_core.key_deltas[wparam] = 1;
|
|
}
|
|
return 0;
|
|
|
|
case WM_CLOSE:
|
|
post_quit_message(0);
|
|
_core.running = false;
|
|
return 0;
|
|
}
|
|
|
|
return def_window_proc_a(hwnd, msg, wparam, lparam);
|
|
}
|
|
|
|
|
|
var class_name = "Punity\x00";
|
|
var window_class = WndClassExA{
|
|
class_name = &class_name[0],
|
|
size = size_of(WndClassExA),
|
|
style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
|
|
instance = Hinstance(get_module_handle_a(nil)),
|
|
wnd_proc = win32_proc,
|
|
// wnd_proc = DefWindowProcA,
|
|
background = Hbrush(get_stock_object(BLACK_BRUSH)),
|
|
};
|
|
|
|
if register_class_ex_a(&window_class) == 0 {
|
|
fmt.fprintln(os.stderr, "register_class_ex_a failed");
|
|
return;
|
|
}
|
|
|
|
var screen_width = get_system_metrics(SM_CXSCREEN);
|
|
var screen_height = get_system_metrics(SM_CYSCREEN);
|
|
|
|
var rc: Rect;
|
|
rc.left = (screen_width - WINDOW_WIDTH) / 2;
|
|
rc.top = (screen_height - WINDOW_HEIGHT) / 2;
|
|
rc.right = rc.left + WINDOW_WIDTH;
|
|
rc.bottom = rc.top + WINDOW_HEIGHT;
|
|
|
|
var style: u32 = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
|
|
assert(adjust_window_rect(&rc, style, 0) != 0);
|
|
|
|
var wt = WINDOW_TITLE;
|
|
|
|
var win32_window = create_window_ex_a(0,
|
|
window_class.class_name,
|
|
&wt[0],
|
|
style,
|
|
rc.left, rc.top,
|
|
rc.right-rc.left, rc.bottom-rc.top,
|
|
nil, nil, window_class.instance,
|
|
nil);
|
|
|
|
if win32_window == nil {
|
|
fmt.fprintln(os.stderr, "create_window_ex_a failed");
|
|
return;
|
|
}
|
|
|
|
|
|
var window_bmi: BitmapInfo;
|
|
window_bmi.size = size_of(BitmapInfoHeader);
|
|
window_bmi.width = CANVAS_WIDTH;
|
|
window_bmi.height = CANVAS_HEIGHT;
|
|
window_bmi.planes = 1;
|
|
window_bmi.bit_count = 32;
|
|
window_bmi.compression = BI_RGB;
|
|
|
|
|
|
user_init(&_core);
|
|
|
|
show_window(win32_window, SW_SHOW);
|
|
|
|
var window_buffer = make([]u32, CANVAS_WIDTH * CANVAS_HEIGHT);
|
|
defer free(window_buffer);
|
|
|
|
for _, i in window_buffer {
|
|
window_buffer[i] = 0xff00ff;
|
|
}
|
|
|
|
var (
|
|
dt: f64;
|
|
prev_time = time_now();
|
|
curr_time = time_now();
|
|
total_time : f64 = 0;
|
|
offset_x = 0;
|
|
offset_y = 0;
|
|
)
|
|
|
|
var message: Msg;
|
|
for _core.running {
|
|
curr_time = time_now();
|
|
dt = curr_time - prev_time;
|
|
prev_time = curr_time;
|
|
total_time += dt;
|
|
|
|
offset_x += 1;
|
|
offset_y += 2;
|
|
|
|
{
|
|
var buf: [128]u8;
|
|
var s = fmt.bprintf(buf[..], "Punity: %.4f ms\x00", dt*1000);
|
|
win32.set_window_text_a(win32_window, &s[0]);
|
|
}
|
|
|
|
|
|
for var y = 0; y < CANVAS_HEIGHT; y++ {
|
|
for var x = 0; x < CANVAS_WIDTH; x++ {
|
|
var g = (x % 32) * 8;
|
|
var b = (y % 32) * 8;
|
|
window_buffer[x + y*CANVAS_WIDTH] = u32(g << 8 | b);
|
|
}
|
|
}
|
|
|
|
mem.zero(&_core.key_deltas[0], size_of(_core.key_deltas));
|
|
|
|
for peek_message_a(&message, nil, 0, 0, PM_REMOVE) != 0 {
|
|
if message.message == WM_QUIT {
|
|
_core.running = false;
|
|
}
|
|
translate_message(&message);
|
|
dispatch_message_a(&message);
|
|
}
|
|
|
|
user_step(&_core);
|
|
|
|
var dc = get_dc(win32_window);
|
|
stretch_dibits(dc,
|
|
0, 0, CANVAS_WIDTH * CANVAS_SCALE, CANVAS_HEIGHT * CANVAS_SCALE,
|
|
0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
|
|
&window_buffer[0],
|
|
&window_bmi,
|
|
DIB_RGB_COLORS,
|
|
SRCCOPY);
|
|
release_dc(win32_window, dc);
|
|
|
|
|
|
{
|
|
var delta = time_now() - prev_time;
|
|
var ms = i32((FRAME_TIME - delta) * 1000);
|
|
if ms > 0 {
|
|
win32.sleep(ms);
|
|
}
|
|
}
|
|
|
|
_core.frame++;
|
|
}
|
|
}
|
|
|
|
|
|
proc main() {
|
|
proc user_init(c: ^Core) {
|
|
|
|
}
|
|
|
|
proc user_step(c: ^Core) {
|
|
|
|
}
|
|
|
|
run(user_init, user_step);
|
|
}
|