VarDecl and ConstDecl split; error, warning, et al. now global

This commit is contained in:
Ginger Bill
2016-09-17 11:39:08 +01:00
parent eb424bb315
commit 67694c0df0
13 changed files with 1840 additions and 670 deletions

View File

@@ -2,7 +2,6 @@
main :: proc() {
init :: proc(c: ^pn.Core) {
}
step :: proc(c: ^pn.Core) {
@@ -11,5 +10,5 @@ main :: proc() {
}
}
// pn.run(init, step)
pn.run(init, step)
}

583
code/fmt.odin Normal file
View File

@@ -0,0 +1,583 @@
#import "os.odin" as os
print_byte_buffer :: proc(buf: ^[]byte, b: []byte) {
if buf.count < buf.capacity {
n := min(buf.capacity-buf.count, b.count)
if n > 0 {
offset := ptr_offset(buf.data, buf.count)
memory_copy(offset, ^b[0], n)
buf.count += n
}
}
}
print_string_to_buffer :: proc(buf: ^[]byte, s: string) {
print_byte_buffer(buf, s as []byte)
}
byte_reverse :: proc(b: []byte) {
n := b.count
for i := 0; i < n/2; i++ {
b[i], b[n-1-i] = b[n-1-i], b[i]
}
}
encode_rune :: proc(r: rune) -> ([4]byte, int) {
buf: [4]byte
i := r as u32
mask: byte : 0x3f
if i <= 1<<7-1 {
buf[0] = r as byte
return buf, 1
}
if i <= 1<<11-1 {
buf[0] = 0xc0 | (r>>6) as byte
buf[1] = 0x80 | (r) as byte & mask
return buf, 2
}
// Invalid or Surrogate range
if i > 0x0010ffff ||
(i >= 0xd800 && i <= 0xdfff) {
r = 0xfffd
}
if i <= 1<<16-1 {
buf[0] = 0xe0 | (r>>12) as byte
buf[1] = 0x80 | (r>>6) as byte & mask
buf[2] = 0x80 | (r) as byte & mask
return buf, 3
}
buf[0] = 0xf0 | (r>>18) as byte
buf[1] = 0x80 | (r>>12) as byte & mask
buf[2] = 0x80 | (r>>6) as byte & mask
buf[3] = 0x80 | (r) as byte & mask
return buf, 4
}
print_rune_to_buffer :: proc(buf: ^[]byte, r: rune) {
b, n := encode_rune(r)
print_string_to_buffer(buf, b[:n] as string)
}
print_space_to_buffer :: proc(buf: ^[]byte) { print_rune_to_buffer(buf, #rune " ") }
print_nl_to_buffer :: proc(buf: ^[]byte) { print_rune_to_buffer(buf, #rune "\n") }
print_int_to_buffer :: proc(buf: ^[]byte, i: int) {
print_int_base_to_buffer(buf, i, 10);
}
PRINT__NUM_TO_CHAR_TABLE :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$"
print_int_base_to_buffer :: proc(buffer: ^[]byte, i, base: int) {
buf: [65]byte
len := 0
negative := false
if i < 0 {
negative = true
i = -i
}
if i == 0 {
buf[len] = #rune "0"
len++
}
for i > 0 {
buf[len] = PRINT__NUM_TO_CHAR_TABLE[i % base]
len++
i /= base
}
if negative {
buf[len] = #rune "-"
len++
}
byte_reverse(buf[:len])
print_string_to_buffer(buffer, buf[:len] as string)
}
print_uint_to_buffer :: proc(buffer: ^[]byte, i: uint) {
print_uint_base_to_buffer(buffer, i, 10, 0, #rune " ")
}
print_uint_base_to_buffer :: proc(buffer: ^[]byte, i, base: uint, min_width: int, pad_char: byte) {
buf: [65]byte
len := 0
if i == 0 {
buf[len] = #rune "0"
len++
}
for i > 0 {
buf[len] = PRINT__NUM_TO_CHAR_TABLE[i % base]
len++
i /= base
}
for len < min_width {
buf[len] = pad_char
len++
}
byte_reverse(buf[:len])
print_string_to_buffer(buffer, buf[:len] as string)
}
print_bool_to_buffer :: proc(buffer: ^[]byte, b : bool) {
if b { print_string_to_buffer(buffer, "true") }
else { print_string_to_buffer(buffer, "false") }
}
print_pointer_to_buffer :: proc(buffer: ^[]byte, p: rawptr) #inline { print_uint_base_to_buffer(buffer, p as uint, 16, 0, #rune " ") }
print_f32_to_buffer :: proc(buffer: ^[]byte, f: f32) #inline { print__f64(buffer, f as f64, 7) }
print_f64_to_buffer :: proc(buffer: ^[]byte, f: f64) #inline { print__f64(buffer, f, 10) }
print__f64 :: proc(buffer: ^[]byte, f: f64, decimal_places: int) {
if f == 0 {
print_rune_to_buffer(buffer, #rune "0")
return
}
if f < 0 {
print_rune_to_buffer(buffer, #rune "-")
f = -f
}
print_u64_to_buffer :: proc(buffer: ^[]byte, i: u64) {
buf: [22]byte
len := 0
if i == 0 {
buf[len] = #rune "0"
len++
}
for i > 0 {
buf[len] = PRINT__NUM_TO_CHAR_TABLE[i % 10]
len++
i /= 10
}
byte_reverse(buf[:len])
print_string_to_buffer(buffer, buf[:len] as string)
}
i := f as u64
print_u64_to_buffer(buffer, i)
f -= i as f64
print_rune_to_buffer(buffer, #rune ".")
mult := 10.0
for decimal_places := 6; decimal_places >= 0; decimal_places-- {
i = (f * mult) as u64
print_u64_to_buffer(buffer, i as u64)
f -= i as f64 / mult
mult *= 10
}
}
print_type_to_buffer :: proc(buf: ^[]byte, ti: ^Type_Info) {
if ti == null { return }
using Type_Info
match type info : ti {
case Named:
print_string_to_buffer(buf, info.name)
case Integer:
match {
case ti == type_info(int):
print_string_to_buffer(buf, "int")
case ti == type_info(uint):
print_string_to_buffer(buf, "uint")
default:
if info.signed {
print_string_to_buffer(buf, "i")
} else {
print_string_to_buffer(buf, "u")
}
print_int_to_buffer(buf, 8*info.size)
}
case Float:
match info.size {
case 4: print_string_to_buffer(buf, "f32")
case 8: print_string_to_buffer(buf, "f64")
}
case String: print_string_to_buffer(buf, "string")
case Boolean: print_string_to_buffer(buf, "bool")
case Pointer:
print_string_to_buffer(buf, "^")
print_type_to_buffer(buf, info.elem)
case Procedure:
print_string_to_buffer(buf, "proc")
if info.params == null {
print_string_to_buffer(buf, "()")
} else {
count := (info.params as ^Tuple).fields.count
if count == 1 { print_string_to_buffer(buf, "(") }
print_type_to_buffer(buf, info.params)
if count == 1 { print_string_to_buffer(buf, ")") }
}
if info.results != null {
print_string_to_buffer(buf, " -> ")
print_type_to_buffer(buf, info.results)
}
case Tuple:
count := info.fields.count
if count != 1 { print_string_to_buffer(buf, "(") }
for i := 0; i < count; i++ {
if i > 0 { print_string_to_buffer(buf, ", ") }
f := info.fields[i]
if f.name.count > 0 {
print_string_to_buffer(buf, f.name)
print_string_to_buffer(buf, ": ")
}
print_type_to_buffer(buf, f.type_info)
}
if count != 1 { print_string_to_buffer(buf, ")") }
case Array:
print_string_to_buffer(buf, "[")
print_int_to_buffer(buf, info.count)
print_string_to_buffer(buf, "]")
print_type_to_buffer(buf, info.elem)
case Slice:
print_string_to_buffer(buf, "[")
print_string_to_buffer(buf, "]")
print_type_to_buffer(buf, info.elem)
case Vector:
print_string_to_buffer(buf, "{")
print_int_to_buffer(buf, info.count)
print_string_to_buffer(buf, "}")
print_type_to_buffer(buf, info.elem)
case Struct:
print_string_to_buffer(buf, "struct ")
if info.packed { print_string_to_buffer(buf, "#packed ") }
if info.ordered { print_string_to_buffer(buf, "#ordered ") }
print_string_to_buffer(buf, "{")
for i := 0; i < info.fields.count; i++ {
if i > 0 {
print_string_to_buffer(buf, ", ")
}
print_any_to_buffer(buf, info.fields[i].name)
print_string_to_buffer(buf, ": ")
print_type_to_buffer(buf, info.fields[i].type_info)
}
print_string_to_buffer(buf, "}")
case Union:
print_string_to_buffer(buf, "union {")
for i := 0; i < info.fields.count; i++ {
if i > 0 {
print_string_to_buffer(buf, ", ")
}
print_any_to_buffer(buf, info.fields[i].name)
print_string_to_buffer(buf, ": ")
print_type_to_buffer(buf, info.fields[i].type_info)
}
print_string_to_buffer(buf, "}")
case Raw_Union:
print_string_to_buffer(buf, "raw_union {")
for i := 0; i < info.fields.count; i++ {
if i > 0 {
print_string_to_buffer(buf, ", ")
}
print_any_to_buffer(buf, info.fields[i].name)
print_string_to_buffer(buf, ": ")
print_type_to_buffer(buf, info.fields[i].type_info)
}
print_string_to_buffer(buf, "}")
case Enum:
print_string_to_buffer(buf, "enum ")
print_type_to_buffer(buf, info.base)
print_string_to_buffer(buf, "{}")
}
}
print_any_to_buffer :: proc(buf: ^[]byte, arg: any) {
using Type_Info
match type info : arg.type_info {
case Named:
a: any
a.type_info = info.base
a.data = arg.data
match type b : info.base {
case Struct:
print_string_to_buffer(buf, info.name)
print_string_to_buffer(buf, "{")
for i := 0; i < b.fields.count; i++ {
f := b.fields[i];
if i > 0 {
print_string_to_buffer(buf, ", ")
}
print_any_to_buffer(buf, f.name)
print_string_to_buffer(buf, " = ")
v: any
v.type_info = f.type_info
v.data = ptr_offset(arg.data as ^byte, f.offset)
print_any_to_buffer(buf, v)
}
print_string_to_buffer(buf, "}")
default:
print_any_to_buffer(buf, a)
}
case Integer:
if info.signed {
i: int = 0;
if arg.data != null {
match info.size {
case 1: i = (arg.data as ^i8)^ as int
case 2: i = (arg.data as ^i16)^ as int
case 4: i = (arg.data as ^i32)^ as int
case 8: i = (arg.data as ^i64)^ as int
case 16: i = (arg.data as ^i128)^ as int
}
}
print_int_to_buffer(buf, i)
} else {
i: uint = 0;
if arg.data != null {
match info.size {
case 1: i = (arg.data as ^u8)^ as uint
case 2: i = (arg.data as ^u16)^ as uint
case 4: i = (arg.data as ^u32)^ as uint
case 8: i = (arg.data as ^u64)^ as uint
case 16: i = (arg.data as ^u128)^ as uint
}
}
print_uint_to_buffer(buf, i)
}
case Float:
f: f64 = 0
if arg.data != null {
match info.size {
case 4: f = (arg.data as ^f32)^ as f64
case 8: f = (arg.data as ^f64)^ as f64
}
}
print_f64_to_buffer(buf, f)
case String:
s := ""
if arg.data != null {
s = (arg.data as ^string)^
}
print_string_to_buffer(buf, s)
case Boolean:
v := false;
if arg.data != null {
v = (arg.data as ^bool)^
}
print_bool_to_buffer(buf, v)
case Pointer:
v := null;
if arg.data != null {
v = (arg.data as ^rawptr)^
}
print_pointer_to_buffer(buf, v)
case Enum:
v: any
v.data = arg.data
v.type_info = info.base
print_any_to_buffer(buf, v)
case Array:
print_string_to_buffer(buf, "[")
defer print_string_to_buffer(buf, "]")
for i := 0; i < info.count; i++ {
if i > 0 {
print_string_to_buffer(buf, ", ")
}
elem: any
elem.data = (arg.data as int + i*info.elem_size) as rawptr
elem.type_info = info.elem
print_any_to_buffer(buf, elem)
}
case Slice:
slice := arg.data as ^[]byte
print_string_to_buffer(buf, "[")
defer print_string_to_buffer(buf, "]")
for i := 0; i < slice.count; i++ {
if i > 0 {
print_string_to_buffer(buf, ", ")
}
elem: any
elem.data = ptr_offset(slice.data, i*info.elem_size)
elem.type_info = info.elem
print_any_to_buffer(buf, elem)
}
case Vector:
print_string_to_buffer(buf, "<")
defer print_string_to_buffer(buf, ">")
for i := 0; i < info.count; i++ {
if i > 0 {
print_string_to_buffer(buf, ", ")
}
elem: any
elem.data = ptr_offset(arg.data as ^byte, i*info.elem_size)
elem.type_info = info.elem
print_any_to_buffer(buf, elem)
}
case Struct:
print_string_to_buffer(buf, "struct")
print_string_to_buffer(buf, "{")
defer print_string_to_buffer(buf, "}")
for i := 0; i < info.fields.count; i++ {
if i > 0 {
print_string_to_buffer(buf, ", ")
}
print_any_to_buffer(buf, info.fields[i].name)
print_string_to_buffer(buf, " = ")
a: any
a.data = ptr_offset(arg.data as ^byte, info.fields[i].offset)
a.type_info = info.fields[i].type_info
print_any_to_buffer(buf, a)
}
case Union:
print_string_to_buffer(buf, "(union)")
case Raw_Union:
print_string_to_buffer(buf, "(raw_union)")
case Procedure:
print_type_to_buffer(buf, arg.type_info)
print_string_to_buffer(buf, " @ 0x")
print_pointer_to_buffer(buf, (arg.data as ^rawptr)^)
default:
}
}
type_info_is_string :: proc(info: ^Type_Info) -> bool {
using Type_Info
if info == null {
return false
}
for {
match type i : info {
case Named:
info = i.base
continue
case String:
return true
default:
return false
}
}
return false
}
print_to_buffer :: proc(buf: ^[]byte, fmt: string, args: ..any) {
is_digit :: proc(r: rune) -> bool #inline {
return r >= #rune "0" && r <= #rune "9"
}
parse_int :: proc(s: string, offset: int) -> (int, int) {
result := 0
for ; offset < s.count; offset++ {
c := s[offset] as rune
if !is_digit(c) {
break
}
result *= 10
result += (c - #rune "0") as int
}
return result, offset
}
prev := 0
implicit_index := 0
for i := 0; i < fmt.count; i++ {
r := fmt[i] as rune
index := implicit_index
if r != #rune "%" {
continue
}
print_string_to_buffer(buf, fmt[prev:i])
i++ // Skip %
if i < fmt.count {
next := fmt[i] as rune
if next == #rune "%" {
print_string_to_buffer(buf, "%")
i++
prev = i
continue
}
if is_digit(next) {
index, i = parse_int(fmt, i)
}
}
if 0 <= index && index < args.count {
print_any_to_buffer(buf, args[index])
implicit_index = index+1
} else {
// TODO(bill): Error check index out bounds
print_string_to_buffer(buf, "<invalid>")
}
prev = i
}
print_string_to_buffer(buf, fmt[prev:])
}
PRINT_BUF_SIZE :: 1<<12
print_to_file :: proc(f: ^os.File, fmt: string, args: ..any) {
data: [PRINT_BUF_SIZE]byte
buf := data[:0]
print_to_buffer(^buf, fmt, ..args)
os.write(f, buf)
}
println_to_file :: proc(f: ^os.File, fmt: string, args: ..any) {
data: [PRINT_BUF_SIZE]byte
buf := data[:0]
print_to_buffer(^buf, fmt, ..args)
print_nl_to_buffer(^buf)
os.write(f, buf)
}
print :: proc(fmt: string, args: ..any) {
print_to_file(os.get_standard_file(os.File_Standard.OUTPUT), fmt, ..args)
}
print_err :: proc(fmt: string, args: ..any) {
print_to_file(os.get_standard_file(os.File_Standard.ERROR), fmt, ..args)
}
println :: proc(fmt: string, args: ..any) {
println_to_file(os.get_standard_file(os.File_Standard.OUTPUT), fmt, ..args)
}
println_err :: proc(fmt: string, args: ..any) {
println_to_file(os.get_standard_file(os.File_Standard.ERROR), fmt, ..args)
}

107
code/os.odin Normal file
View File

@@ -0,0 +1,107 @@
#import "runtime.odin" as _ // TODO(bill): make the compile import this automatically
#import "win32.odin" as win32
File :: type struct {
Handle :: type win32.HANDLE
handle: Handle
}
open :: proc(name: string) -> (File, bool) {
using win32
buf: [300]byte
copy(buf[:], name as []byte)
f := File{CreateFileA(^buf[0], FILE_GENERIC_READ, FILE_SHARE_READ, null, OPEN_EXISTING, 0, null)}
success := f.handle != INVALID_HANDLE_VALUE as File.Handle
return f, success
}
create :: proc(name: string) -> (File, bool) {
using win32
buf: [300]byte
copy(buf[:], name as []byte)
f := File{
handle = CreateFileA(^buf[0], FILE_GENERIC_WRITE, FILE_SHARE_READ, null, CREATE_ALWAYS, 0, null),
}
success := f.handle != INVALID_HANDLE_VALUE as File.Handle
return f, success
}
close :: proc(using f: ^File) {
win32.CloseHandle(handle)
}
write :: proc(using f: ^File, buf: []byte) -> bool {
bytes_written: i32
return win32.WriteFile(handle, buf.data, buf.count as i32, ^bytes_written, null) != 0
}
File_Standard :: type enum {
INPUT,
OUTPUT,
ERROR,
COUNT,
}
__std_files := __set_file_standards();
__set_file_standards :: proc() -> [File_Standard.COUNT as int]File {
return [File_Standard.COUNT as int]File{
File{handle = win32.GetStdHandle(win32.STD_INPUT_HANDLE)},
File{handle = win32.GetStdHandle(win32.STD_OUTPUT_HANDLE)},
File{handle = win32.GetStdHandle(win32.STD_ERROR_HANDLE)},
}
}
get_standard_file :: proc(std: File_Standard) -> ^File {
return ^__std_files[std]
}
read_entire_file :: proc(name: string) -> (string, bool) {
buf: [300]byte
copy(buf[:], name as []byte)
f, file_ok := open(name)
if !file_ok {
return "", false
}
defer close(^f)
length: i64
file_size_ok := win32.GetFileSizeEx(f.handle as win32.HANDLE, ^length) != 0
if !file_size_ok {
return "", false
}
data := new_slice(u8, length)
if data.data == null {
return "", false
}
single_read_length: i32
total_read: i64
for total_read < length {
remaining := length - total_read
to_read: u32
MAX :: 1<<32-1
if remaining <= MAX {
to_read = remaining as u32
} else {
to_read = MAX
}
win32.ReadFile(f.handle as win32.HANDLE, ^data[total_read], to_read, ^single_read_length, null)
if single_read_length <= 0 {
free(data.data)
return "", false
}
total_read += single_read_length as i64
}
return data as string, true
}

484
code/punity.odin Normal file
View File

@@ -0,0 +1,484 @@
#import "win32.odin" as win32
#import "fmt.odin" as _
CANVAS_WIDTH :: 128
CANVAS_HEIGHT :: 128
CANVAS_SCALE :: 3
FRAME_TIME :: 1.0/30.0
WINDOW_TITLE : string : "Punity\x00"
_ := compile_assert(CANVAS_WIDTH % 16 == 0)
WINDOW_WIDTH :: CANVAS_WIDTH * CANVAS_SCALE
WINDOW_HEIGHT :: CANVAS_HEIGHT * CANVAS_SCALE
STACK_CAPACITY :: 1<<20
STORAGE_CAPACITY :: 1<<20
DRAW_LIST_RESERVE :: 128
MAX_KEYS :: 256
Core :: struct {
stack: ^Bank
storage: ^Bank
running: bool
key_modifiers: u32
key_states: [MAX_KEYS]byte
key_deltas: [MAX_KEYS]byte
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
}
Perf_Span :: struct {
stamp: f64
delta: f32
}
Bank :: struct {
memory: []byte
cursor: int
}
Bank_State :: struct {
state: Bank
bank: ^Bank
}
Color :: raw_union {
using channels: struct{ a, b, g, r: byte }
rgba: u32
}
Palette :: struct {
colors: [256]Color
colors_count: byte
}
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
}
Bitmap :: struct {
pixels: []byte
width: int
height: int
}
Font :: struct {
using bitmap: Bitmap
char_width: int
char_height: int
}
Canvas :: struct {
using bitmap: ^Bitmap
palette: Palette
translate_x: int
translate_y: int
clip: Rect
font: ^Font
}
DrawFlag :: enum {
NONE = 0,
FLIP_H = 1<<0,
FLIP_V = 1<<1,
MASK = 1<<2,
}
Draw_List :: struct {
Item :: struct {
}
items: []Item
}
Key :: enum {
MOD_SHIFT = 0x0001,
MOD_CONTROL = 0x0002,
MOD_ALT = 0x0004,
MOD_SUPER = 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,
LEFT_BRACKET = 91, /* [ */
BACKSLASH = 92, /* \ */
RIGHT_BRACKET = 93, /* ] */
GRAVE_ACCENT = 96, /* ` */
}
key_down :: proc(k: Key) -> bool {
return _core.key_states[k] != 0
}
key_pressed :: proc(k: Key) -> bool {
return (_core.key_deltas[k] != 0) && key_down(k)
}
win32_perf_count_freq := win32.GetQueryPerformanceFrequency()
time_now :: proc() -> f64 {
assert(win32_perf_count_freq != 0)
counter: i64
win32.QueryPerformanceCounter(^counter)
result := counter as f64 / win32_perf_count_freq as f64
return result
}
_core: Core
run :: proc(user_init, user_step: proc(c: ^Core)) {
using win32
_core.running = true
win32_proc :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #no_inline #stdcall {
win32_app_key_mods :: proc() -> u32 {
mods: u32 = 0
if is_key_down(Key_Code.SHIFT) {
mods |= Key.MOD_SHIFT as u32;
}
if is_key_down(Key_Code.CONTROL) {
mods |= Key.MOD_CONTROL as u32;
}
if is_key_down(Key_Code.MENU) {
mods |= Key.MOD_ALT as u32;
}
if is_key_down(Key_Code.LWIN) || is_key_down(Key_Code.RWIN) {
mods |= Key.MOD_SUPER as u32;
}
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:
PostQuitMessage(0)
_core.running = false
return 0
}
return DefWindowProcA(hwnd, msg, wparam, lparam)
}
window_class := WNDCLASSEXA{
class_name = ("Punity\x00" as string).data, // C-style string
size = size_of(WNDCLASSEXA) as u32,
style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
instance = GetModuleHandleA(null) as HINSTANCE,
wnd_proc = win32_proc,
// wnd_proc = DefWindowProcA,
background = GetStockObject(BLACK_BRUSH) as HBRUSH,
}
if RegisterClassExA(^window_class) == 0 {
/*fmt.*/println_err("RegisterClassExA failed")
return
}
screen_width := GetSystemMetrics(SM_CXSCREEN)
screen_height := GetSystemMetrics(SM_CYSCREEN)
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
style: u32 = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX
assert(AdjustWindowRect(^rc, style, 0) != 0)
wt := WINDOW_TITLE
win32_window := CreateWindowExA(0,
window_class.class_name,
WINDOW_TITLE.data,
// wt.data,
style,
rc.left, rc.top,
rc.right-rc.left, rc.bottom-rc.top,
null, null, window_class.instance,
null);
if win32_window == null {
/*fmt.*/println_err("CreateWindowExA failed")
return
}
window_bmi: BITMAPINFO;
window_bmi.size = size_of(BITMAPINFO.HEADER) as u32
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)
ShowWindow(win32_window, SW_SHOW)
window_buffer := new_slice(u32, CANVAS_WIDTH * CANVAS_HEIGHT);
assert(window_buffer.data != null)
defer free(window_buffer.data)
for i := 0; i < window_buffer.count; i++ {
window_buffer[i] = 0xff00ff
}
prev_time, curr_time,dt: f64
prev_time = time_now()
curr_time = time_now()
total_time : f64 = 0
offset_x := 0;
offset_y := 0;
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
{
data: [128]byte
buf := data[:0]
/*fmt.*/print_to_buffer(^buf, "Punity: % ms\x00", dt*1000)
win32.SetWindowTextA(win32_window, buf.data)
}
for y := 0; y < CANVAS_HEIGHT; y++ {
for x := 0; x < CANVAS_WIDTH; x++ {
g := (x % 32) * 8
b := (y % 32) * 8
window_buffer[x + y*CANVAS_WIDTH] = (g << 8 | b) as u32
}
}
memory_zero(^_core.key_deltas[0], size_of(_core.key_deltas[0]))
for PeekMessageA(^message, null, 0, 0, PM_REMOVE) != 0 {
if message.message == WM_QUIT {
_core.running = false
}
TranslateMessage(^message)
DispatchMessageA(^message)
}
user_step(^_core)
dc := GetDC(win32_window);
StretchDIBits(dc,
0, 0, CANVAS_WIDTH * CANVAS_SCALE, CANVAS_HEIGHT * CANVAS_SCALE,
0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
window_buffer.data,
^window_bmi,
DIB_RGB_COLORS,
SRCCOPY)
ReleaseDC(win32_window, dc)
{
delta := time_now() - prev_time
ms := ((FRAME_TIME - delta) * 1000) as i32
if ms > 0 {
win32.Sleep(ms)
}
}
_core.frame++
}
}