Previously it wasnt working but now its working, TRUST ME

This commit is contained in:
Krzosa Karol
2023-04-02 11:23:36 +02:00
parent 9bb355ed93
commit ad5c692506
32 changed files with 4 additions and 3 deletions

293
build/examples/_demo1.core Normal file
View File

@@ -0,0 +1,293 @@
/* EXTRA CREDITS (bottom of README.md on github)
* https://bitwise.handmade.network/ - series by Per Vognsen where he actually creates a C like language, very helpful, very hands on!
* https://hero.handmade.network/episode/code/day206/ - this episode of handmade hero started me on the entire compiler journey a long, long time ago.
* https://www.youtube.com/watch?v=TH9VCN6UkyQ&list=PLmV5I2fxaiCKfxMBrNsU1kgKJXD3PkyxO - I have rewatched this playlist many this, searching for keywords and ideas. Jonathan Blow's compiler was a big inspiration of mine when learning programming languages.
* A Retargetable C Compiler: Design and Implementation by Christopher W. Fraser and David R. Hanson - sometimes looked at this as a reference to figure stuff out. Very helpful resource on compiler construction, the way it's written reads more like documentation but you use what you have.
* https://github.com/JoshuaManton/sif - looked at this as a reference from time to time, author seems like a Jonathan Blow fan so it was a good resource informed by similar resources as I used.
* https://github.com/c3lang/c3c - I sometimes looked at C3 compiler as a reference, the author also let me use his big int library he wrote sometime in the past! Thanks a lot!
* https://go.dev/blog/constants - article on golang type system, untyped types, constants that kind of stuff.
* https://github.com/gingerbill/odin - I sometimes peeked at the compiler to figure stuff out when I was confused about stuff. Also we get a free code indexing and syntax highlighting using odin sublime text plugin ! :D
*/
//
// #1
//
// * Inspired by: Per Vognsen(Ion), Jonathan Blow(Jai)
// * Standard programming constructs
// * No forward declarations needed
// * Named function arguments
// * Enum values are nicely namespaced
#import "Multimedia.core"
main :: (): int
StartMultimedia(title = "Hello people!")
DrawYellowFill()
DrawCoolGradient()
DrawCircleWithGradient()
AnimateTransmorphingCircle()
RaymarchSphere()
DrawYellowFill :: ()
for y := 0, y < Mu.window.y, y+=1
for x := 0, x < Mu.window.x, x+=1
Mu.screen[x + y*Mu.window.x] = 0xFFFFFF00
for UpdateMultimedia()
if Mu.key[Key.Escape].down
Mu.key[Key.Escape].down = false
break
//
// #2
//
// * Modules
// * User names the imports
// * Aliasing
// * Operator overloads
F :: #import "MathF32.core"
V3 :: #import "MathVec3.core"
V2 :: #import "MathVec2.core"
Vec3 :: V3.Vec3
DrawCoolGradient :: ()
for y := 0, y < Mu.window.y, y+=1
for x := 0, x < Mu.window.x, x+=1
// Normalize to range {0, 1}
uv := V2.Vec2{x->F32, y->F32} / Mu.window.sizef
// Move to range {-1, 1}
uv = uv*2->F32 - 1->F32
Assert(uv.x >= -1 && uv.x <= 1)
Assert(uv.y >= -1 && uv.y <= 1)
color := Vec3{uv.x, uv.y, 1}
Mu.screen[x + y*Mu.window.x] = V3.ConvertToARGB(color)
for UpdateMultimedia()
if Mu.key[Key.Escape].down
Mu.key[Key.Escape].down = false
break
//
// #3
//
// * The ';;' operator
// * The ';' operator
// * Compound expressions, named parameters!
DrawCircleWithGradient :: ()
default_color := V3.ConvertToARGB({x = 1, y = 1, z = 1})
ratio := Mu.window.sizef.x / Mu.window.sizef.y
for y := 0, y < Mu.window.y, y+=1
for x := 0, x < Mu.window.x, x+=1
// Normalize to range {0, 1}
uv := V2.Vec2{x->F32, y->F32} / Mu.window.sizef
// Move to range {-1, 1}
uv = uv*2->F32 - 1->F32
uv.x *= ratio
if uv.x*uv.x + uv.y*uv.y < 0.5
color := Vec3{uv.x, uv.y, 1}
Mu.screen[x + y*Mu.window.x] = V3.ConvertToARGB(color)
else;; Mu.screen[x + y*Mu.window.x] = default_color
for UpdateMultimedia()
if Mu.key[Key.Escape].down
Mu.key[Key.Escape].down = false
break
//
// #4
//
AnimateTransmorphingCircle :: ()
for UpdateMultimedia()
if Mu.key[Key.Escape].down
Mu.key[Key.Escape].down = false
break
default_color := V3.ConvertToARGB({x = 1, y = 1, z = 1})
ratio := Mu.window.sizef.x / Mu.window.sizef.y
for y := 0, y < Mu.window.y, y+=1
for x := 0, x < Mu.window.x, x+=1
// Normalize to range {0, 1}
uv := V2.Vec2{x->F32, y->F32} / Mu.window.sizef
// Move to range {-1, 1}
uv = uv*2->F32 - 1->F32
uv.x *= ratio
if F.Cos(Mu.time.total->F32)*uv.x*uv.x + F.Sin(Mu.time.total->F32)*uv.y*uv.y < 0.5
color := Vec3{uv.x, uv.y, 1}
Mu.screen[x + y*Mu.window.x] = V3.ConvertToARGB(color)
else ;; Mu.screen[x + y*Mu.window.x] = default_color
//
// #5
//
Epsilon :: 0.00001
SphereSDF :: (pos: Vec3): F32
result := V3.Length(pos) - 1.0
return result
RaymarchSphere :: ()
for UpdateMultimedia()
if Mu.key[Key.Escape].down
Mu.key[Key.Escape].down = false
break
up := Vec3{0, 1, 0}
forward := Vec3{0, 0, -1}
side := V3.Normalize(V3.Cross(forward, up))
LightPos := Vec3{2,4,2}
LightPos.x = F.Cos(Mu.time.total->F32)*4
LightPos.y = F.Sin(Mu.time.total->F32)*4
ambient_color := Vec3{0.2,0.2,0.2}
diffuse_color := Vec3{0.7,0.2,0.2}
eye := Vec3{0, 0, 2}
light_intensity :: 1.2->F32
Xf := 1 / Mu.window.sizef.x
Yf := 1 / Mu.window.sizef.y
ratio := Mu.window.sizef.x / Mu.window.sizef.y
for y := 0, y < Mu.window.y, y+=1
for x := 0, x < Mu.window.x, x+=1
uv := Vec3{x->F32 * Xf * 2 - 1, y->F32 * Yf * 2 - 1, 1.0}
uv.x *= ratio
dir := V3.Normalize(Vec3{V3.Dot(side, uv), V3.Dot(up, uv), V3.Dot(forward, uv)})
t: F32
end: F32 = 100.0
hit := true
p: Vec3
for i := 0, i < 255, i+=1
p = eye + dir*t
distance := SphereSDF(p)
if distance < Epsilon
break
t += distance
if distance >= end
hit = false
break
if hit
normal := V3.Normalize(Vec3{
SphereSDF({p.x + Epsilon, p.y, p.z}) - SphereSDF({p.x - Epsilon, p.y, p.z}),
SphereSDF({p.x, p.y + Epsilon, p.z}) - SphereSDF({p.x, p.y - Epsilon, p.z}),
SphereSDF({p.x, p.y, p.z + Epsilon}) - SphereSDF({p.x, p.y, p.z - Epsilon}),
})
light_to_point := V3.Normalize(LightPos - p)
ambient :: 0.2->F32
diffuse := V3.Dot(normal, light_to_point)
color := ambient_color*ambient->F32
if diffuse > Epsilon
color = color + diffuse_color*diffuse
color = color * light_intensity
// Gamma correction
color.x = F.SquareRoot(color.x)
color.y = F.SquareRoot(color.y)
color.z = F.SquareRoot(color.z)
Mu.screen[x + y*Mu.window.x] = V3.ConvertToARGB(color)
else;; Mu.screen[x + y*Mu.window.x] = 0

View File

@@ -0,0 +1,90 @@
/*
PushStruct :: (a: *MA.Arena, $T: Type): *$T
size := size_of(Type)
result := PushSize(a, size)
return result
Array(int)
QueueAddSLL(list: $List, node: $Node, first: #Identifier = first, last: #Identifier = last, next: #Identifier = next)
ArrayAdd(array: $Array, item: $Item, data: #Identifier = data, len: #Identifier = len, len: #Identifier = cap)
QueueAddSLL(list: $List, node: $Node, $first = first, $last = last, $next = next)
if list.first == 0
list.first = list.last = node
else
list.last = list.last.next = node
*/
Array :: struct($T: Type)
data: *T
len: int
cap: int
Tuple :: struct($A: Type, $B: Type)
a: A
b: B
Triple :: struct($A: Type, $B: Type, $C: Type)
a: A
b: B
c: C
Variant :: union($A: Type, $B: Type, $C: Type)
a: A
b: B
c: C
MakeArray :: (a: *int, count: int): Array(int)
result := Array(int) {
data = a,
len = count,
cap = count
}
return result
// :Multiple arguments
// @todo: maybe disallow multiple arguments in current form
// and use polimorphism. Then we could make var unpacking,
// unpack structs making it more powerful
MultipleArgs :: (): Tuple(int, F32)
return {32, 32}
PolyLambda :: ($T: Type): T
return 32
GetCount :: (a: int): int
return a
// @todo: this is allowed, shouldn't be
// Test :: (a: int, b: int = 10, c: int???)
Test :: (a: int, b: int = 10, c: int = 20)
pass
main :: (argc: int, argv: **char): int
buff: *int
array: Array(int) = {len = 10, cap = 10, data = buff}
second_array: Array(int)
third_array: Array(int)
fourth: Array(F32)
fifth: Array(F32)
sixth: Array(Array(F32))
seventh: Variant(int, F32, S64)
// d: int(32)
// c := MakeArray(buff, GetCount(GetCount(32)))
// a,b := MultipleArgs()
a := MultipleArgs()
Test(10)
Test(10, 20)
Test(10, 20, 30)
Test(10, b = 10)
Test(10, b = 10, c = 20)
Test(a = 10, b = 10, c = 20)
value := PolyLambda(int)
return 0

View File

@@ -0,0 +1,97 @@
VariadicArguments :: (string: *char, args: []Any): Any
return args[0]
AnyArguments :: (values: []Any)
for values
Assert(it.type == S64)
Assert(*(values[0].data->*S64) == 10)
Assert(*(values[1].data->*S64) == 20)
/**
* C++ version 0.4 char* style "itoa":
* Written by Lukás Chmela
* Released under GPLv3.
*/
IntegerToString :: (value: S64, result: *U8, base: S64): *U8
// check that the base if valid
if (base < 2) || (base > 36)
*result = 0 // '
return result
ptr := result
ptr1 := result
tmp_char: U8
tmp_value: S64
for value != 0
tmp_value = value
value /= base
*ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35 + (tmp_value - value * base)]
// Apply negative sign
if tmp_value < 0
*ptr++ = '-'
*ptr-- = 0
for ptr1 < ptr
tmp_char = *ptr
*ptr-- = *ptr1
*ptr1++ = tmp_char
return result
StringToDouble :: (s: String): F64
sign: F64 = 1.0
i := 0
if s[i] == '-'
sign = -1
i += 1
elif s[i] == '+'
i += 1
for , i < Len(s), i+= 1
pass // BACKUP
return 0
FormatString :: (buffer: *U8, buffer_len: U64, string: String, args: []Any)
// @todo(krzosa): Add consideration of buffer SIZE! Add some function to handle this OutStr or something
arg_counter := 0
out_buffer_len := 0
for i := 0, i < Len(string), i+=1
if string[i] == '%'
Assert(arg_counter < Len(args), "Passed too many [%] to the string formating function")
arg := args[arg_counter++]
if arg.type == S64
value := *(arg.data->*S64)
itoa_buff: [64]U8
p := IntegerToString(value, &itoa_buff[0], 10)
for *p != 0
buffer[out_buffer_len++] = *p++
else;; Assert(false)
else
buffer[out_buffer_len++] = string[i]
main :: (): int
a := 10
b := 20
values := []Any{a, b}
for values
Assert(it.type == S64)
AnyArguments({a,b})
c := VariadicArguments("Test", args = {a+b,b})
Assert(*(c.data->*S64) == 30)
d := VariadicArguments("Test", {b,a})
Assert(*(d.data->*S64) == b)
Assert(*(values[0].data->*S64) == 10)
Assert(*(values[1].data->*S64) == 20)
buf: [128]U8
FormatString(&buf[0], Len(buf), "Test % %", {32, 156})
return 0

View File

@@ -0,0 +1,55 @@
/*
Static arrays are exactly like c arrays, difference is
we can easily then get a slice of that array.
Slices are static arrays + length, they simplify array handling.
This allows us to pass an array into a function easily, then that function
can still access that length information easily.
Passing a pointer to array + length is a common pattern in C. So it would
be nice if handling of that was simplified.
*/
main :: (): int
static_array: [8]int
// We can get size of array using Length builtin
#Assert(Len(static_array) == 8)
// Accessing values is like in C
// Variables are zeroed by default
Assert(static_array[1] == 0)
element2 := static_array[2]
element0: int = static_array[0]
Assert(element0 == 0 && element2 == 0)
// We can loop through arrays
// this implicitly defines 'it' variable
for static_array
*it = 1
// We set all variables to 1 so
Assert(static_array[6] == 1)
// This is how slice is defined, no [] index in between brackets
// slice is array pointer + length
// Other then that it works exactly like regular array
slice: []int = static_array
// We can't do a compile time Assert anymore
Assert(Len(slice) == 8)
Assert(slice[4] == 1)
// After we loop and reassign slice values
// old static_array gets changed
//
// In this example, operator ';;' is used
// it inserts a new line, allows to write this
// example in a single line
for slice;; *it = 2
Assert(static_array[2] == 2)
return 0

View File

@@ -0,0 +1,40 @@
// We can bind module to a name
M :: #import "Multimedia.core"
// You can bind struct to a name
MU :: M.MU
// We can bind a lambda to a name
Start :: M.StartMultimedia
Update :: M.UpdateMultimedia
// Other example of binding a lambda to a name
SomeOtherLambda :: () ;; pass
AliasOf :: SomeOtherLambda
// We can bind a simple type to name, this type is
// exactly the same as int, typechecker doesn't complain
NewInt :: int
// We can force it to complain using a '#strict' directive
// this makes a new type that requires casting, good for ids
// and stuff like that, normal int operations still work!
StrictInt :: #strict int
SomeStruct :: struct ;; a: int
StructAlias :: SomeStruct
main :: (): int
some_struct: SomeStruct = {a = 10}
struct_alias: StructAlias = some_struct
Assert(struct_alias.a == 10)
#Assert(SomeStruct == StructAlias)
#Assert(NewInt == int)
#Assert(StrictInt != int)
Start(x = 1280, y = 720)
Update()
return 0

View File

@@ -0,0 +1,76 @@
#import "Base.core"
#import "Arena.core"
#import "KERNEL32.core"
#import "GDI32.core"
#import "USER32.core"
WinMain :: (hInstance: HINSTANCE, hPrevInstance: HINSTANCE, lpCmdLine: LPSTR, nShowCmd: int): int
screen_size_x: int = 1280
screen_size_y: int = 720
arena: Arena
window_name := StringToString16(&arena, "Have a wonderful day!")
w := WNDCLASSW{
lpfnWndProc = WindowProc,
hInstance = hInstance,
lpszClassName = window_name.str,
}
Assert(RegisterClassW(&w) != 0)
window := CreateWindowExW(
dwExStyle = 0, hWndParent = 0, hMenu = 0, lpParam = 0,
X = CW_USEDEFAULT, Y = CW_USEDEFAULT, nWidth = screen_size_x, nHeight = screen_size_y,
lpClassName = window_name.str,
lpWindowName = window_name.str,
dwStyle = WS_OVERLAPPEDWINDOW,
hInstance = hInstance
)
Assert(window != 0)
ShowWindow(window, nShowCmd)
window_dc := GetDC(window)
header_size: U32 = SizeOf(BITMAPINFOHEADER)
Assert(header_size == 40)
bminfo := BITMAPINFO{
BITMAPINFOHEADER{
biSize = header_size,
biWidth = screen_size_x->LONG,
biHeight = screen_size_y->LONG,
biPlanes = 1,
biBitCount = 32,
biCompression = BI_RGB,
biXPelsPerMeter = 1,
biYPelsPerMeter = 1,
}
}
pixels: *U32
bitmap_dib := CreateDIBSection(window_dc, &bminfo, DIB_RGB_COLORS, (&pixels)->**void, 0, 0)
bitmap_hdc := CreateCompatibleDC(window_dc)
for AppIsRunning
msg: MSG
for PeekMessageW(&msg, window, 0, 0, PM_REMOVE) > 0
TranslateMessage(&msg)
DispatchMessageW(&msg)
for y := 0->int, y < screen_size_y, y+=1
for x := 0->int, x < screen_size_x, x+=1
pixels[x + y*screen_size_x] = 0xFFFF0000
SelectObject(bitmap_hdc, bitmap_dib)
BitBlt(window_dc, 0, 0, screen_size_x, screen_size_y, bitmap_hdc, 0, 0, SRCCOPY)
Sleep(100)
if CStringCompare(lpCmdLine, "testing")
return 0
return 0
AppIsRunning := true
WindowProc :: (hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM): LRESULT
if msg == WM_DESTROY
PostQuitMessage(0)
AppIsRunning = false
return 0
else;; return DefWindowProcW(hwnd, msg, wparam, lparam)

View File

@@ -0,0 +1,55 @@
/*
Language enables implementing dynamic typing using operator overloads and
the Any type. Any type is a bundle of typeid and a pointer to value.
Current semantics of the Any dictate that values that get assigned to
Any values, they get implicitly converted to a pointer and a type.
a: Any = 10 // This sentence allocates 10 on the stack
a: Any = a + 10 // This also allocates on stack
a: Any = a // Does not allocate, takes pointer to a
a: Any = array[1] // Does not allocate, takes pointer to value in array
The general picture you can take from this is that if we are referencing
something it will take a pointer to it.
If the operation results in a new value it will allocate the result on stack
and make a pointer out of it. Have to be mindful of the lifetime.
*/
storage: [32]S64
len : S64
"+" :: (a: Any, b: Any): Any
result: Any = storage[len++]
if a.type == S64 && b.type == S64
*(result.data->*S64) = *(a.data->*S64) + *(b.data->*S64)
return result
"+" :: (a: Any, b: S64): Any
result: Any = storage[len++]
if a.type == S64
*(result.data->*S64) = *(a.data->*S64) + b
return result
"==" :: (a: Any, b: S64): Bool
result := false
if a.type == S64
result = *(a.data->*S64) == b
return result
"==" :: (a: Any, b: Any): Bool
result := false
if a.type == S64 && b.type == S64
result = *(a.data->*S64) == *(b.data->*S64)
return result
main :: (): int
a: Any = 10
b: Any = 20
c := a + b
Assert(c.type == S64 && c == 30)
Assert(a+b+a==c+(5+5))
return 0

View File

@@ -0,0 +1,103 @@
main :: (): int
// Language has a bunch of standard builtin types:
// Signed integer types
s64val: S64 = 0
s32val: S32 = 0
s16val: S16 = 0
s8val : S8 = 0
intval: int = 0
// Unsigned integer types = U64, U32, U16, U8,
u64val: U64 = 0
u32val: U32 = 0
u16val: U16 = 0
u8val : U8 = 0
// Floating point types = F64, F32
f64val: F64 = 0
f32val: F32 = 0
// String type = String
string_val: String = "String type"
cstring_val: *char = "CString type"
// This is how we can assign variables
// There is no need for prefixes, compiler figures
// out the format by itself
signed_variable: S32 = 10
unsigned_variable: U32 = 10
// We can also tell the compiler to infer the type
this_is_s64_by_default := 10
this_is_f32_by_default := 10.1251
this_is_string_by_default := "Thing"
// Reassigning values is exactly like in other languages
this_is_s64_by_default = 20
this_is_string_by_default = "Other_Thing"
this_is_f32_by_default = 15.1255
// @todo: Add type_of operator!!!
// Assert(type_of(this_is_string_by_default) == String)
// Assert(type_of(this_is_s64_by_default) == S64)
// There are also constant bindings in the language.
// You can bind all sorts of constants to names this way.
INT_VALUE :: 10
FLOAT_VALUE :: 124.125
// For constants we can mix and match different types
COMBINE_VALUE :: INT_VALUE + FLOAT_VALUE
// When it comes to runtime variables it's a bit different
// To do this we need a cast
combining_types := this_is_s64_by_default->F32 + this_is_f32_by_default
// Compound statements
// Struct is at the bottom of the file!
data1 := Data{
a = 1,
d = 2
}
data2: Data = {
a = 4,
b = 2,
}
size0 := SizeOf(Data)
size1 := SizeOf(data1)
align0 := AlignOf(Data)
align1 := AlignOf(data1)
type0 := TypeOf(Data)
type1 := TypeOf(data1)
Assert(s64val == 0 && s32val == 0 && s16val == 0 && s8val == 0 && intval == 0 && u64val == 0 && u32val == 0 && u16val == 0 && u8val == 0 && f64val == 0 && f32val == 0)
Assert(string_val[0] == 'S')
Assert(cstring_val[0] == 'C')
Assert(signed_variable == 10 && unsigned_variable == 10)
Assert(INT_VALUE == 10)
Assert(FLOAT_VALUE == 124.125)
Assert(this_is_f32_by_default == 15.1255)
Assert(combining_types == 15.1255 + 20)
Assert(data1.a == 1)
Assert(data1.b == 0)
Assert(data1.c == 0)
Assert(data1.d == 2)
Assert(data2.a == 4)
Assert(data2.b == 2)
Assert(data2.c == 0)
Assert(data2.d == 0)
Assert(size0 == size1)
Assert(align0 == align1)
Assert(type0 == type1)
Assert(TypeOf(data2) == Data)
return 0
Data :: struct
a: S64
b: S32
c: S32
d: S32

View File

@@ -0,0 +1,26 @@
Vec3 :: struct;; x: F32; y: F32; z: F32
// We can define operator overloads for arbitrary types
// these are just regular lambdas/functions
"+" :: (a: Vec3, b: Vec3): Vec3
return {a.x+b.x, a.y+b.y, a.z+b.z}
// We can make a one liner out of these using ';;' operator
// which functions as a new line with indent
"-" :: (a: Vec3, b: Vec3): Vec3 ;; return {a.x-b.x, a.y-b.y, a.z-b.z}
"-" :: (a: Vec3): Vec3 ;; return {-a.x, -a.y, -a.z}
main :: (): int
a := Vec3{1,1,1}
b := Vec3{2,3,4}
// The expressions are replaced with the defined lambdas
c := a + b
Assert(c.x == 3 && c.y == 4 && c.z == 5)
d := -c
Assert(d.x == -3 && d.y == -4 && d.z == -5)
e := c - d
Assert(e.x == 6 && e.y == 8 && e.z == 10)
return 0

View File

@@ -0,0 +1,74 @@
/*
Biggest problems with C/C++ are the header files and the fact that
top level declarations are required to be ordered.
In C++ you simply cannot write code like this:
struct Asset{
Asset_Tag asset_tag;
};
enum Asset_Tag{
ASSET_SOUND,
ASSET_IMAGE,
};
Even though it makes more sense to do that, I would rather first learn
about what Asset is rather then what tags it can have. C/C++ force on you
an order of declarations that doesn't match what you have in your head.
The next problem are the header files. Frequently on top of writing code,
in C/C++ there is a need to maintain a header file. Header files contain
all the forward declarations of the functions that you are implementing.
Problem with this is that if you are changing something, potentially
you now need to change that in multiple places. It would be nice if I could
write a module that doesn't yet have any concrete spec but the functions
are available everywhere, immediately. On top of that those functions would
be nicely localized in a single file without thinking about what depends
on what, how to fit it in the stack of includes etc. It would be just nice
to tell the compiler to solve all those issues for us.
*/
// We can have main at the top level, this is something
// that is sometimes pretty tricky in C++
main :: (): int
// Even though Asset is beneath main, this still works
// this feature is even nicer when we think about modules etc.
asset1 := make_sound()
asset2 := make_sound()
asset1.next_asset = &asset2
return 0
// @todo: This does not work
// asset := []Asset{make_sound(), make_sound()}
// asset[0].next_sound = &asset[1]
// Recursion is a pain point for this kinds of algorithms
// As can be seen here it works very nicely
make_sound :: (should_exit_recursion: Bool = false): Asset
if should_exit_recursion == true
asset: Asset
asset.tag = Asset_Tag.Sound
return asset
return make_sound(true)
Asset :: struct
tag: Asset_Tag
// Pointers to self work as expected
// this is always a pain point for these kinds of
// algorithms
next_asset: *Asset
// enum #flag assigns default values differently from normal enums.
// It assigns a unique bit of a value to each enumeration.
// Default values go: 1, 2, 4, 8, 16, 32, 64
Asset_Tag :: enum #flag
Sound
Image
Text

View File

@@ -0,0 +1,15 @@
MA :: #import "Arena.core"
PushStruct :: (a: *MA.Arena, $K: Type, $T: Type): *T
size := SizeOf(T)
result := MA.PushSize(a, size->U64)
return result->*T
main :: (argc: int, argv: **char): int
arena: MA.Arena
a: *int = PushStruct(&arena, int, int)
b: *F32 = PushStruct(&arena, int, F32)
padding := SizeOf(int)
Assert(arena.len->S64 == (SizeOf(int) + SizeOf(F32) + padding))
return 0

View File

@@ -0,0 +1,210 @@
F :: #import "MathF32.core"
V3 :: #import "MathVec3.core"; Vec3 :: V3.Vec3
V2 :: #import "MathVec2.core"; Vec2 :: V2.Vec2
Epsilon :: 0.00001
Screen : *U32
X : S64
Y : S64
TotalTime: F64
LightPos := Vec3{2,4,2}
SphereSDF :: (pos: Vec3): F32
result := V3.Length(pos) - 1.0
return result
Raymarcher_Update :: ()
up := Vec3{0, 1, 0}
forward := Vec3{0, 0, -1}
side := V3.Normalize(V3.Cross(forward, up))
LightPos.x = F.Cos(TotalTime->F32)*4
LightPos.y = F.Sin(TotalTime->F32)*4
ambient_color := Vec3{0.2,0.2,0.2}
diffuse_color := Vec3{0.7,0.2,0.2}
specular_color := Vec3{1,1,1}
eye := Vec3{0, 0, 2}
light_intensity :: 1.2->F32
Xf := 1 / X->F32
Yf := 1 / Y->F32
ratio := X->F32 / Y->F32
for y := 0, y < Y, y+=1
for x := 0, x < X, x+=1
uv := Vec3{x->F32 * Xf * 2 - 1, y->F32 * Yf * 2 - 1, 1.0}
uv.x *= ratio
dir := V3.Normalize(Vec3{V3.Dot(side, uv), V3.Dot(up, uv), V3.Dot(forward, uv)})
t: F32
end: F32 = 100.0
hit := true
p: Vec3
for i := 0, i < 255, i+=1
p = eye + dir*t
distance := SphereSDF(p)
if distance < Epsilon
break
t += distance
if distance >= end
hit = false
break
if hit
normal := V3.Normalize(Vec3{
SphereSDF({p.x + Epsilon, p.y, p.z}) - SphereSDF({p.x - Epsilon, p.y, p.z}),
SphereSDF({p.x, p.y + Epsilon, p.z}) - SphereSDF({p.x, p.y - Epsilon, p.z}),
SphereSDF({p.x, p.y, p.z + Epsilon}) - SphereSDF({p.x, p.y, p.z - Epsilon}),
})
light_to_point := V3.Normalize(LightPos - p)
eye_to_point := V3.Normalize(eye - p)
reflected_light := V3.Normalize(V3.Reflect(V3.Negate(light_to_point), normal))
ambient :: 0.2->F32
diffuse := V3.Dot(normal, light_to_point)
color := ambient_color*ambient->F32
if diffuse > Epsilon
color = color + diffuse_color*diffuse
specular := V3.Dot(reflected_light, eye_to_point)
if specular > Epsilon
specular = specular*specular*specular*specular
color = color + specular_color*specular*0.2->F32
color = color * light_intensity
// Gamma correction
color.x = F.SquareRoot(color.x)
color.y = F.SquareRoot(color.y)
color.z = F.SquareRoot(color.z)
Screen[x + y*X] = V3.ConvertToARGB(color)
else;; Screen[x + y*X] = 0
/////////////////////////////////////
//
// Windows specific code
//
#import "Base.core"
#import "Arena.core"
#import "OS$OS.core"
#import "KERNEL32.core"
#import "GDI32.core"
#import "USER32.core"
#import "WINMM.core"
AppIsRunning := true
WindowProc :: (hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM): LRESULT
if msg == WM_DESTROY
PostQuitMessage(0)
AppIsRunning = false
return 0
else;; return DefWindowProcW(hwnd, msg, wparam, lparam)
WinMain :: (hInstance: HINSTANCE, hPrevInstance: HINSTANCE, lpCmdLine: LPSTR, nShowCmd: int): int
if good_scheduling := false, timeBeginPeriod(1) == TIMERR_NOERROR
good_scheduling = true
dpi_aware_set := SetProcessDPIAware()
Assert(dpi_aware_set != 0)
arena: Arena
window_name := StringToString16(&arena, "Have a wonderful day! 你好世界 ")
w := WNDCLASSW{
lpfnWndProc = WindowProc,
hInstance = hInstance,
lpszClassName = window_name.str,
}
Assert(RegisterClassW(&w) != 0)
screen_size: V2.Vec2I = {1280, 720}
window := CreateWindowExW(
dwExStyle = 0, hWndParent = 0, hMenu = 0, lpParam = 0,
X = CW_USEDEFAULT, Y = CW_USEDEFAULT, nWidth = screen_size.x->int, nHeight = screen_size.y->int,
lpClassName = window_name.str,
lpWindowName = window_name.str,
dwStyle = WS_OVERLAPPEDWINDOW,
hInstance = hInstance
)
Assert(window != 0)
ShowWindow(window, nShowCmd)
window_dc := GetDC(window)
bitmap := CreateBitmap(screen_size)
requested_time_per_frame: F64 = 1.0 / 60.0
frame_start_time := Time()
frame_number: S64
for AppIsRunning
msg: MSG
for PeekMessageW(&msg, window, 0, 0, PM_REMOVE) > 0
TranslateMessage(&msg)
DispatchMessageW(&msg)
Screen = bitmap.data; X = bitmap.size.x; Y = bitmap.size.y
Raymarcher_Update()
SelectObject(bitmap.hdc, bitmap.dib)
BitBlt(window_dc, 0, 0, (bitmap.size.x)->int, (bitmap.size.y)->int, bitmap.hdc, 0, 0, SRCCOPY)
frame_time := Time() - frame_start_time
frame_number += 1
TotalTime += frame_time
if frame_time < requested_time_per_frame
if good_scheduling
time_to_sleep := (requested_time_per_frame - frame_time) * 1000
if time_to_sleep > 0
time_to_sleep_dword := time_to_sleep->DWORD
// @check if time_to_sleep_dword truncates down
Sleep(time_to_sleep_dword)
new_frame_time := Time()
for new_frame_time < requested_time_per_frame
new_frame_time = Time() - frame_start_time
frame_time = new_frame_time
if CStringCompare(lpCmdLine, "testing")
return 0
return 0
Windows_Bitmap :: struct
size: V2.Vec2I
data: *U32
hdc: HDC
dib: HBITMAP
CreateBitmap :: (size: V2.Vec2I, bottom_up: Bool = true): Windows_Bitmap
result: Windows_Bitmap = {size = size}
if bottom_up == false
result.size.y = -result.size.y
header_size: U32 = SizeOf(BITMAPINFOHEADER)
Assert(header_size == 40)
bminfo := BITMAPINFO{
BITMAPINFOHEADER{
biSize = header_size,
biWidth = size.x->LONG,
biHeight = size.y->LONG,
biPlanes = 1,
biBitCount = 32,
biCompression = BI_RGB,
biXPelsPerMeter = 1,
biYPelsPerMeter = 1,
}
}
hdc := GetDC(0)
result.dib = CreateDIBSection(hdc, &bminfo, DIB_RGB_COLORS, (&result.data)->**void, 0, 0)
result.hdc = CreateCompatibleDC(hdc)
return result

View File

@@ -0,0 +1,69 @@
main :: (): int
// Let's say we have a type
some_type := S64
// this function call allows us to get extensive type information
// about this type. For example this information allows us to walk
// the type tree, pretty print all values in that type, along with their sizes.
// Other use cases allow us to do a type safe printf
type_info: *Type_Info = GetTypeInfo(some_type)
// It can be null, requiring the type information would be a bit unwise
// this is a lot of data
if !type_info
return 1
if type_info.type == S64
// We can use SizeOf and AlignOf operators
// to figure out the type alignment and it's size
Assert(type_info.size == SizeOf(S64))
Assert(type_info.align == AlignOf(S64))
else;; Assert(false, "We expected S64 here! What a boomer!")
//
// @todo: This should work
//
// any_thing: Any = 10
//
// Any type allows us to combine a value pointer and
// it's corresponding type_id
//
value_to_be_wrapped := 10
any_value: Any = value_to_be_wrapped
if any_value.type == S64
*(any_value.data->*S64) = 20
elif any_value.type == int
// Void pointers get implicitly cast
value: *int = any_value.data
*value = 30
elif any_value.type == char;; Assert(false, "No bueno")
Assert(*(any_value.data->*S64) == 20)
letter := GetFirstLetterOfType(value_to_be_wrapped)
Assert(letter == 'I')
return 0
GetFirstLetterOfType :: (a: Any): U8
type_info := GetTypeInfo(a.type)
if !type_info
return '-'
result: U8
switch type_info.kind
Type_Info_Kind.S64, Type_Info_Kind.S32, Type_Info_Kind.S16, Type_Info_Kind.S8, Type_Info_Kind.INT
result = 'I'
Type_Info_Kind.U64, Type_Info_Kind.U32, Type_Info_Kind.U16, Type_Info_Kind.U8
result = 'U'
Type_Info_Kind.F64
result = 'F'
Type_Info_Kind.POINTER
result = '*'
default;; result = '-'
return result

View File

@@ -0,0 +1,48 @@
main :: (): int
// Types can be evaluated at compile time for equality
#Assert(int == int)
#Assert(int != char)
#Assert(*char == *char)
// They can also be evaluated at runtime, they basically get
// replaced with type ids, which are just unique integers assigned
// to each type
Assert(int == int)
Assert(int != char)
Assert(*char == *char)
// We can assign types to compile time variable constants
New_Type :: int
// This is a loose association
thing: int = 10
new_type_thing: New_Type = thing
#Assert(New_Type == int)
// to force typechecker to treat$
// both of these types as different we need to add a #strict directive
Strict_Type :: #strict int
// new_strict_type_thing: Strict_Type = thing // This produces a compile time type error
// But this works
strict_thing: Strict_Type = 10
#Assert(Strict_Type != int)
// If we want to use those types together we need to cast
Assert(new_type_thing + strict_thing->int != 0)
// We can also assign types to runtime variables, there is a special type for that
some_type: Type = int
some_type_implicit := char
// These can be checked for equality using ifs and switches
if some_type == char
pass
elif some_type_implicit == char
pass
return 0

View File

@@ -0,0 +1,40 @@
U :: union
a: F64
b: F32
C :: struct
a: int
b: int
main :: (argc: int, argv: **char): int
memes: U
memes.b = 10
Assert(memes.b == 10)
Assert(memes.a != 0)
compound: U = {b = 10.0}
Assert(compound.b == 10)
t := U
ti := GetTypeInfo(t)
Assert(ti.size == SizeOf(U))
for ti.struct_members
Assert(it.offset == 0)
ti_it := GetTypeInfo(it.type)
Assert(ti_it.size != 0)
/* @reproduction @todo
```
examples/unions.core - Error! Couldn't infer type of compound expression
c = {10}
```
c: C
c = {10}
*/
return 0

View File

@@ -0,0 +1,12 @@
#import "Multimedia.core"
main :: (): int
StartMultimedia(title = "Hello people!")
for UpdateMultimedia()
if Mu.key[Key.Escape].down ;; Mu.quit = true
for y := 0, y < Mu.window.y, y+=1
for x := 0, x < Mu.window.x, x+=1
Mu.screen[x + y*Mu.window.x] = 0xFFFFFF00
return 0

42
build/modules/Arena.core Normal file
View File

@@ -0,0 +1,42 @@
OS :: #import "OS$OS.core"
Base :: #import "Base.core"
ArenaDI: U64
ADDITIONAL_COMMIT_SIZE :: 1024*1024
DEFAULT_RESERVE_SIZE :: 1024*1024*1024
DEFAULT_ALIGNMENT :: 8
Arena :: struct
di: U64 // @debug_id
memory: OS.Memory
alignment: U64
len: U64
Init :: (a: *Arena)
a.memory = OS.Reserve(DEFAULT_RESERVE_SIZE)
a.alignment = DEFAULT_ALIGNMENT
a.di = ArenaDI++
FromBuffer :: (buffer: []U8): Arena
a: Arena
a.memory.reserve = Len(buffer)->U64
a.memory.commit = Len(buffer)->U64
a.alignment = DEFAULT_ALIGNMENT
a.di = ArenaDI++
return a
PushSize :: (a: *Arena, size: Base.SizeU): *void
generous_size := size + a.alignment
if a.len + generous_size > a.memory.commit
if a.memory.reserve == 0
Init(a)
result := OS.Commit(&a.memory, generous_size + ADDITIONAL_COMMIT_SIZE)
Assert(result == true)
a.len = Base.AlignUp(a.len, a.alignment)
Assert(a.memory.reserve > a.len + a.memory.commit)
result: *void = a.memory.data + a.len
a.len += size
return result
Release :: (a: *Arena)
OS.Release(&a.memory)

124
build/modules/Base.core Normal file
View File

@@ -0,0 +1,124 @@
#import "Arena.core"
OS :: #import "OS$OS.core"
SizeU :: U64
ClampTopSizeU :: (val: SizeU, max: SizeU): SizeU
if val > max
return max
return val
GetAlignOffset :: (size: SizeU, align: SizeU): SizeU
mask := align - 1
val := size & mask
if val != 0
val = align - val
return val
AlignUp :: (size: SizeU, align: SizeU): SizeU
result := size + GetAlignOffset(size, align)
return result
ZeroMemory :: (p: *void, size: SizeU)
pcast := p->*U8
for i := 0->SizeU, i < size, i++
pcast[i] = 0
//
// Unicode
//
QuestionMark16 :: 0x003f
String32 :: struct;; str: *U32; len: S64
String16 :: struct;; str: *U16; len: S64
Utf8ToUtf32 :: (c: *U8, max_advance: S64): U32, S64
out_str: U32
advance: S64
if (c[0] & 0b10000000) == 0
if max_advance >= 1
c0 := c[0]->U32
out_str = c0
advance = 1
elif (c[0] & 0b11100000) == 0b11000000
if (c[1] & 0b11000000) == 0b10000000 // Continuation byte required
if max_advance >= 2
c0 := c[0]->U32; c1 := c[1]->U32
out_str = (c0 & 0b00011111) << 6 | (c1 & 0b00111111)
advance = 2
elif (c[0] & 0b11110000) == 0b11100000
if (c[1] & 0b11000000) == 0b10000000 && (c[2] & 0b11000000) == 0b10000000 // Two continuation bytes required
if max_advance >= 3
c0 := c[0]->U32; c1 := c[1]->U32; c2 := c[2]->U32
out_str = (c0 & 0b00001111) << 12 | (c1 & 0b00111111) << 6 | (c2 & 0b00111111)
advance = 3
elif (c[0] & 0b11111000) == 0b11110000
if (c[1] & 0b11000000) == 0b10000000 && (c[2] & 0b11000000) == 0b10000000 && (c[3] & 0b11000000) == 0b10000000 // Three continuation bytes required
if max_advance >= 4
c0 := c[0]->U32; c1 := c[1]->U32; c2 := c[2]->U32; c3 := c[3]->U32
out_str = (c0 & 0b00001111) << 18 | (c1 & 0b00111111) << 12 | (c2 & 0b00111111) << 6 | (c3 & 0b00111111)
advance = 4
return out_str, advance
Utf32ToUtf16 :: (codepoint: U32): [2]U16, S64
str: [2]U16
len := 0
if codepoint < 0x10000
str[0] = codepoint->U16
len = 1
elif codepoint <= 0x10FFFF
code: U32 = (codepoint - 0x10000)
str[0] = (0xD800 | (code >> 10))->U16
str[1] = (0xDC00 | (code & 0x3FF))->U16
len = 2
return str, len
StringToString16 :: (arena: *Arena, in: String): String16
in_str := &in[0]
// @Note(Krzosa): Should be more then enough space
alloc_size := (Len(in)*2)+1
result := String16{str = PushSize(arena, alloc_size->U64)}
for i := 0, i < Len(in)
s32, s32_len := Utf8ToUtf32(in_str + i, Len(in) - i)
if s32_len != 0
i += s32_len
s16, s16_len := Utf32ToUtf16(s32)
if s16_len != 0
for j := 0, j < s16_len, j++
result.str[result.len++] = s16[j]
else
result.str[result.len++] = QuestionMark16
break
else
result.str[result.len++] = QuestionMark16
break
result.str[result.len] = 0
return result
CStringCompare :: (a: *char, b: *char): Bool
i := 0
for , a[i] != 0, i+=1
if a[i] != b[i]
return false
if a[i] != b[i]
return false
return true
TestUnicode :: (arena: *Arena)
string := " 豈 更 車 賈 滑 串 句 龜 龜 契 金 喇 奈 懶 癩 羅 蘿 螺 裸 邏 樂 洛 烙 珞 落 酪 駱 亂 卵 欄 爛 蘭 鸞 嵐 濫 藍 襤 拉 臘 蠟 廊 朗 浪 狼 郎 來 冷 勞 擄 櫓 爐 盧 老 蘆 虜 路 露 魯 鷺 碌 祿 綠 菉 錄 鹿 論 壟 弄 籠 聾 牢 磊 賂 雷 壘 屢 樓 淚 漏 累 縷 陋 勒 肋 凜 凌 稜 綾 菱 陵 讀 拏 樂 諾 丹 寧 怒 率 異 北 磻 便 復 不 泌 數 索 參 塞 省 葉 說 殺 辰 沈 拾 若 掠 略 亮 兩 凉 梁 糧 良 諒 量 勵 ..."
string_result := StringToString16(arena, string)
print(string_result)
s32, s32_len := Utf8ToUtf32('A', 1)
assert(s32 == 'A', "Invalid decode")
s32_2, s32_len_2 := Utf8ToUtf32('ć', 2)
assert(s32_2 == 0x107, "Invalid decode")
s32_3, s32_len_3 := Utf8ToUtf32('ó', 2)
assert(s32_3 == 0xF3, "Invalid decode")

41
build/modules/GDI32.core Normal file
View File

@@ -0,0 +1,41 @@
#import "KERNEL32.core"
#link "gdi32"
RBGQUAD :: struct;; rgbBlue: BYTE; rgbGreen: BYTE; rgbRed: BYTE; rgbReserved: BYTE
BITMAPINFOHEADER :: struct;; biSize: DWORD; biWidth: LONG; biHeight: LONG; biPlanes: WORD; biBitCount: WORD; biCompression: DWORD; biSizeImage: DWORD; biXPelsPerMeter: LONG; biYPelsPerMeter: LONG; biClrUsed: DWORD; biClrImportant: DWORD
BITMAPINFO :: struct;; bmiHeader: BITMAPINFOHEADER; bmiColors: [1]RBGQUAD
HGDIOBJ :: HANDLE
BI_RGB :: 0x0000
BI_RLE8 :: 0x0001
BI_RLE4 :: 0x0002
BI_BITFIELDS :: 0x0003
BI_JPEG :: 0x0004
BI_PNG :: 0x0005
BI_CMYK :: 0x000B
BI_CMYKRLE8 :: 0x000C
BI_CMYKRLE4 :: 0x000
DIB_RGB_COLORS :: 0x00
SRCCOPY :: 0x00CC0020 /* dest = source */
SRCPAINT :: 0x00EE0086 /* dest = source OR dest */
SRCAND :: 0x008800C6 /* dest = source AND dest */
SRCINVERT :: 0x00660046 /* dest = source XOR dest */
SRCERASE :: 0x00440328 /* dest = source AND (NOT dest ) */
NOTSRCCOPY :: 0x00330008 /* dest = (NOT source) */
NOTSRCERASE :: 0x001100A6 /* dest = (NOT src) AND (NOT dest) */
MERGECOPY :: 0x00C000CA /* dest = (source AND pattern) */
MERGEPAINT :: 0x00BB0226 /* dest = (NOT source) OR dest */
PATCOPY :: 0x00F00021 /* dest = pattern */
PATPAINT :: 0x00FB0A09 /* dest = DPSnoo */
PATINVERT :: 0x005A0049 /* dest = pattern XOR dest */
DSTINVERT :: 0x00550009 /* dest = (NOT dest) */
BLACKNESS :: 0x00000042 /* dest = BLACK */
WHITENESS :: 0x00FF0062 /* dest = WHITE */
CreateDIBSection :: #foreign (hdc: HDC, pbmi: *BITMAPINFO, usage: UINT, ppvBits: **VOID, hSection: HANDLE, offset: DWORD): HBITMAP
CreateCompatibleDC :: #foreign (hdc: HDC): HDC
SelectObject :: #foreign (hdc: HDC, h: HGDIOBJ): HGDIOBJ
BitBlt :: #foreign (hdc: HDC, x: int, y: int, cx: int, cy: int, hdcSrc: HDC, x1: int, y1: int, ro: DWORD): BOOL
DeleteDC :: #foreign (hdc: HDC): BOOL
DeleteObject :: #foreign (ho : HGDIOBJ): BOOL

130
build/modules/KERNEL32.core Normal file
View File

@@ -0,0 +1,130 @@
#link "kernel32"
DWORD :: U32
LPCSTR :: *char
LPSTR :: *char
LPCWSTR :: *U16
HWND :: *void
HMENU :: *void
HINSTANCE :: *void
HBITMAP :: *void
HDC :: *void
LPVOID :: *void
SIZE_T :: U64
BOOL :: int
HMODULE :: HANDLE
HANDLE :: *void
VOID :: void
HICON :: HANDLE
HCURSOR :: HANDLE
HBRUSH :: HANDLE
LPDWORD :: *DWORD
LRESULT :: S64
WPARAM :: U64
LPARAM :: S64
BYTE :: U8 // @todo? unsigned char
WORD :: S16 // short
LONG :: S32 // @todo long
UINT :: U32 // @todo uint
ATOM :: WORD
LARGE_INTEGER :: S64
PLARGE_INTEGER :: *LARGE_INTEGER
LPOVERLAPPED :: *OVERLAPPED
LONG_PTR :: *S64
ULONG_PTR :: *U64
MEM_COMMIT :: 0x00001000
MEM_RESERVE :: 0x00002000
MEM_RESET :: 0x00080000
MEM_RESET_UNDO :: 0x1000000
MEM_DECOMMIT :: 0x00004000
MEM_RELEASE :: 0x00008000
PAGE_NOACCESS :: 1
PAGE_READONLY :: 2
PAGE_READWRITE :: 4
PAGE_WRITECOPY :: 8
PAGE_EXECUTE :: 0x10; PAGE_EXECUTE_READ :: 0x20; PAGE_EXECUTE_READWRITE :: 0x40; PAGE_EXECUTE_WRITECOPY :: 0x80
VirtualAlloc :: #foreign (lpAddress: LPVOID, dwSize: SIZE_T, flAllocationType: DWORD, flProtect: DWORD): LPVOID
VirtualFree :: #foreign (lpAddress: LPVOID, dwSize: SIZE_T, dwFreeType: DWORD): BOOL
HEAP_ZERO_MEMORY :: 0x8; HEAP_NO_SERIALIZE :: 0x1; HEAP_GENERATE_EXCEPTIONS :: 0x4
GetProcessHeap :: #foreign (): HANDLE
HeapAlloc :: #foreign (hHeap: HANDLE, dwFlags: DWORD, dwByte: SIZE_T): LPVOID
HeapFree :: #foreign (hHeap: HANDLE, dwFlags: DWORD, lpMe: LPVOID): BOOL
STD_INPUT_HANDLE :: 4294967286//(-10)->DWORD
STD_OUTPUT_HANDLE :: 4294967285//(-11)->DWORD
//STD_ERROR_HANDLE :: (-12)->DWORD
GetStdHandle :: #foreign (nStdHandle: DWORD): HANDLE
WriteConsoleA :: #foreign (hConsoleOutput: HANDLE,lpBuffer: *VOID,nNumberOfCharsToWrite: DWORD,lpNumberOfCharsWritten: LPDWORD,lpReserve: LPVOID): BOOL
WriteConsoleW :: #foreign (hConsoleOutput: HANDLE,lpBuffer: *VOID,nNumberOfCharsToWrite: DWORD,lpNumberOfCharsWritten: LPDWORD,lpReserve: LPVOID): BOOL
__debugbreak :: #foreign ()
GetModuleHandleA :: #foreign (lpModuleName: LPCSTR): HMODULE
ExitProcess :: #foreign (uExitCode: UINT)
GetLastError :: #foreign (): DWORD
QueryPerformanceFrequency :: #foreign (lpFrequency: *LARGE_INTEGER): BOOL
QueryPerformanceCounter :: #foreign (lpFrequency: *LARGE_INTEGER): BOOL
Sleep :: #foreign (dwMilliseconds: DWORD)
OutputDebugStringA :: #foreign (lpOutputString: LPCSTR)
CreateFileW :: #foreign (lpFileName: LPCWSTR, dwDesiredAccess: DWORD, dwShareMode: DWORD, lpSecurityAttributes: LPSECURITY_ATTRIBUTES, dwCreationDisposition: DWORD, dwFlagsAndAttributes: DWORD, hTemplateFile: HANDLE): HANDLE
ReadFile :: #foreign (hFile: HANDLE, lpBuffer: LPVOID, nNumberOfBytesToRead: DWORD, lpNumberOfBytesRead: LPDWORD, lpOverlapped: LPOVERLAPPED): BOOL
CloseHandle :: #foreign (hObject: HANDLE): BOOL
GetFileSizeEx :: #foreign (hFile: HANDLE, lpFileSize: PLARGE_INTEGER)
OVERLAPPED :: struct
Internal: ULONG_PTR
InternalHigh: ULONG_PTR
Pointer: PVOID
hEvent: HANDLE
LPSECURITY_ATTRIBUTES :: *SECURITY_ATTRIBUTES
SECURITY_ATTRIBUTES :: struct
nLength: DWORD
lpSecurityDescriptor: LPVOID
bInheritHandle: BOOL
GENERIC_READ :: 0x80000000
GENERIC_WRITE :: 0x40000000
GENERIC_EXECUTE :: 0x20000000
GENERIC_ALL :: 0x10000000
CREATE_NEW :: 1
CREATE_ALWAYS :: 2
OPEN_EXISTING :: 3
OPEN_ALWAYS :: 4
TRUNCATE_EXISTING :: 5
FILE_SHARE_READ :: 0x00000001
FILE_SHARE_WRITE :: 0x00000002
FILE_SHARE_DELETE :: 0x00000004
// INVALID_HANDLE_VALUE :: ((-1)->LONG_PTR)->HANDLE
INVALID_HANDLE_VALUE :: (~(0->U64))
FILE_ATTRIBUTE_READONLY :: 0x00000001
FILE_ATTRIBUTE_HIDDEN :: 0x00000002
FILE_ATTRIBUTE_SYSTEM :: 0x00000004
FILE_ATTRIBUTE_DIRECTORY :: 0x00000010
FILE_ATTRIBUTE_ARCHIVE :: 0x00000020
FILE_ATTRIBUTE_DEVICE :: 0x00000040
FILE_ATTRIBUTE_NORMAL :: 0x00000080
FILE_ATTRIBUTE_TEMPORARY :: 0x00000100
FILE_ATTRIBUTE_SPARSE_FILE :: 0x00000200
FILE_ATTRIBUTE_REPARSE_POINT :: 0x00000400
FILE_ATTRIBUTE_COMPRESSED :: 0x00000800
FILE_ATTRIBUTE_OFFLINE :: 0x00001000
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED :: 0x00002000
FILE_ATTRIBUTE_ENCRYPTED :: 0x00004000
FILE_ATTRIBUTE_INTEGRITY_STREAM :: 0x00008000
FILE_ATTRIBUTE_VIRTUAL :: 0x00010000
FILE_ATTRIBUTE_NO_SCRUB_DATA :: 0x00020000
FILE_ATTRIBUTE_EA :: 0x00040000
FILE_ATTRIBUTE_PINNED :: 0x00080000
FILE_ATTRIBUTE_UNPINNED :: 0x00100000
FILE_ATTRIBUTE_RECALL_ON_OPEN :: 0x00040000
FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS :: 0x00400000

View File

@@ -0,0 +1,60 @@
/*
Any :: struct
data: *void
type: Type
Type_Info_Kind :: enum
S64 // FIRST_NUMERIC
S32
S16
S8
INT
CHAR
U64
U32
U16
U8
F32
F64
POINTER
BOOL // LAST_NUMERIC
STRING
VOID
ARRAY
LAMBDA
STRUCT
UNION
ENUM
TYPE
SLICE
TUPLE
Type_Info_Struct_Member :: struct
name: String
type: Type
offset: S64
Type_Info :: struct
kind: Type_Info_Kind
size: S64
align: S64
is_unsigned: Bool
type: Type
base_type: Type
array_size: S64
struct_members: *Type_Info_Struct_Member
struct_member_count: S64
lambda_arguments: *Type_Info
lambda_argument_count: S64
lambda_return: Type
type_infos_len: S64 #foreign
type_infos : *Type_Info #foreign
GetTypeInfo :: (type: Type): *Type_Info
id := type->S64
if id >= type_infos_len
return 0
return type_infos + id
*/

17
build/modules/LibC.core Normal file
View File

@@ -0,0 +1,17 @@
size_t :: U64 // @todo(Krzosa): Need this type
long :: #strict int // @todo(Krzosa): Need this type
malloc :: #foreign (size: size_t): *void
realloc :: #foreign (ptr: *void, size: size_t): *void
free :: #foreign (ptr: *void)
FILE :: #strict U64 // Doesnt matter the type just handle
fopen :: #foreign (file: *char, mode: *char): *FILE
fclose :: #foreign (file: *FILE): int
fseek :: #foreign (public_stream: *FILE, offset: long, whence: int): int
ftell :: #foreign (public_stream: *FILE): long
fread :: #foreign (buffer: *void, element_size: size_t, element_count: size_t, stream: *FILE): size_t
SEEK_CUR :: 1
SEEK_END :: 2
SEEK_SET :: 0

View File

@@ -0,0 +1,34 @@
sqrtf :: #foreign (value: F32): F32
cosf :: #foreign (value: F32): F32
sinf :: #foreign (value: F32): F32
floorf :: #foreign (value: F32): F32
roundf :: #foreign (value: F32): F32
ceilf :: #foreign (value: F32): F32
Floor :: floorf
Round :: roundf
Ceil :: ceilf
SquareRoot :: sqrtf
Cos :: cosf
Sin :: sinf
Clamp :: (min: F32, value: F32, max: F32): F32
if value > max;; return max
if value < min;; return min
return value
ClampBottom :: (min: F32, value: F32): F32
if value < min;; return min
return value
Absolute :: (val: F32): F32
if val < 0;; return -val
return val
Min :: (a: F32, b: F32): F32
if a > b ;; return b
return a
Max :: (a: F32, b: F32): F32
if a > b ;; return a
return b

View File

@@ -0,0 +1,32 @@
Vec2I :: struct;; x: S64; y: S64
Vec2 :: struct;; x: F32; y: F32
"*" :: (a: Vec2, b: Vec2): Vec2 ;; return {a.x*b.x, a.y*b.y}
"*" :: (a: Vec2, b: F32) : Vec2 ;; return {a.x*b, a.y*b}
"*" :: (a: F32, b: Vec2) : Vec2 ;; return {a*b.x, a*b.y}
"-" :: (a: Vec2, b: Vec2): Vec2 ;; return {a.x-b.x, a.y-b.y}
"-" :: (a: Vec2, b: F32) : Vec2 ;; return {a.x-b, a.y-b}
"-" :: (a: F32, b: Vec2) : Vec2 ;; return {a-b.x, a-b.y}
"+" :: (a: Vec2, b: Vec2): Vec2 ;; return {a.x+b.x, a.y+b.y}
"+" :: (a: Vec2, b: F32) : Vec2 ;; return {a.x+b, a.y+b}
"+" :: (a: F32, b: Vec2) : Vec2 ;; return {a+b.x, a+b.y}
"/" :: (a: Vec2, b: Vec2): Vec2 ;; return {a.x/b.x, a.y/b.y}
"/" :: (a: Vec2, b: F32) : Vec2 ;; return {a.x/b, a.y/b}
"/" :: (a: F32, b: Vec2) : Vec2 ;; return {a/b.x, a/b.y}
"*" :: (a: Vec2I, b: Vec2I): Vec2I ;; return {a.x*b.x, a.y*b.y}
"*" :: (a: Vec2I, b: S64) : Vec2I ;; return {a.x*b, a.y*b}
"*" :: (a: S64, b: Vec2I) : Vec2I ;; return {a*b.x, a*b.y}
"-" :: (a: Vec2I, b: Vec2I): Vec2I ;; return {a.x-b.x, a.y-b.y}
"-" :: (a: Vec2I, b: S64) : Vec2I ;; return {a.x-b, a.y-b}
"-" :: (a: S64, b: Vec2I) : Vec2I ;; return {a-b.x, a-b.y}
"+" :: (a: Vec2I, b: Vec2I): Vec2I ;; return {a.x+b.x, a.y+b.y}
"+" :: (a: Vec2I, b: S64) : Vec2I ;; return {a.x+b, a.y+b}
"+" :: (a: S64, b: Vec2I) : Vec2I ;; return {a+b.x, a+b.y}
"/" :: (a: Vec2I, b: Vec2I): Vec2I ;; return {a.x/b.x, a.y/b.y}
"/" :: (a: Vec2I, b: S64) : Vec2I ;; return {a.x/b, a.y/b}
"/" :: (a: S64, b: Vec2I) : Vec2I ;; return {a/b.x, a/b.y}
FloorVec2ToVec2I :: (a: Vec2): Vec2I ;; return {floorf(a.x)->S64, floorf(a.y)->S64}
CastVec2ToVec2I :: (a: Vec2): Vec2I ;; return {a.x->S64, a.y->S64}

View File

@@ -0,0 +1,46 @@
#import "MathF32.core"
Vec3 :: struct ;; x: F32; y: F32; z: F32
Length :: (a: Vec3): F32 ;; return sqrtf(a.x*a.x + a.y*a.y + a.z*a.z)
Negate :: (a: Vec3): Vec3 ;; return {-a.x, -a.y, -a.z}
Dot :: (a: Vec3, b: Vec3): F32 ;; return a.x*b.x + a.y*b.y + a.z*b.z
"*" :: (a: Vec3, b: Vec3): Vec3 ;; return {a.x*b.x, a.y*b.y, a.z*b.z}
"*" :: (a: Vec3, b: F32) : Vec3 ;; return {a.x*b, a.y*b, a.z*b}
"*" :: (a: F32, b: Vec3) : Vec3 ;; return {a*b.x, a*b.y, a*b.z}
"-" :: (a: Vec3, b: Vec3): Vec3 ;; return {a.x-b.x, a.y-b.y, a.z-b.z}
"-" :: (a: Vec3, b: F32) : Vec3 ;; return {a.x-b, a.y-b, a.z-b}
"-" :: (a: F32, b: Vec3) : Vec3 ;; return {a-b.x, a-b.y, a-b.z}
"+" :: (a: Vec3, b: Vec3): Vec3 ;; return {a.x+b.x, a.y+b.y, a.z+b.z}
"+" :: (a: Vec3, b: F32) : Vec3 ;; return {a.x+b, a.y+b, a.z+b}
"+" :: (a: F32, b: Vec3) : Vec3 ;; return {a+b.x, a+b.y, a+b.z}
"/" :: (a: Vec3, b: Vec3): Vec3 ;; return {a.x/b.x, a.y/b.y, a.z/b.z}
"/" :: (a: Vec3, b: F32) : Vec3 ;; return {a.x/b, a.y/b, a.z/b}
"/" :: (a: F32, b: Vec3) : Vec3 ;; return {a/b.x, a/b.y, a/b.z}
Cross :: (a: Vec3, b: Vec3): Vec3
result := Vec3{
a.y * b.z - a.z * b.y,
a.z * b.x - a.x * b.z,
a.x * b.y - a.y * b.x,
}
return result
Normalize :: (a: Vec3): Vec3
length := Length(a)
result := a / length
return result
Reflect :: (a: Vec3, normal: Vec3): Vec3
an := Dot(a, normal)*2
result := a - a * an
return result
ConvertToARGB :: (a: Vec3): U32
a.x = Clamp(0, a.x, 1)
a.y = Clamp(0, a.y, 1)
a.z = Clamp(0, a.z, 1)
r := (a.x * 255)->U32 << 16
g := (a.y * 255)->U32 << 8
b := (a.z * 255)->U32 << 0
result := r | g | b
return result

View File

@@ -0,0 +1,64 @@
/*
Library for making games/graphical applications
* The api is very simple, very few function calls
* You retrieve information about the state of application from "Mu" struct
* Data is available in many different formats to avoid format conversions in user code
API and name inspired by one of Per Vognsen streams
https://www.youtube.com/watch?v=NG_mUhc8LRw&list=PLU94OURih-CjrtFuazwZ5GYzTrupOMDL7&index=19
All of his channel is recommended watch for programmers.
*/
Mu: MU
MU :: struct
screen: *U32
window: MUWindow
key: [Key.Count]KeyState
mouse: Mouse
frame_count: U64
time: MUTime
quit: Bool
frame_arena: Arena
os: Platform
MUWindow :: struct
x: S64
y: S64
sizef: Vec2
size: Vec2I
resizable: Bool
MUTime :: struct
total : F64
delta : F64 // @modifiable
start : F64
frame_start: F64
KeyState :: struct
down: Bool
Key :: enum
None
Up;Down;Left;Right;Escape;Control;Backspace;Alt;Shift;Tab
F1;F2;F3;F4;F5;F6;F7;F8;F9;F10
F11;F12;A;B;C;D;E;F;G;H
I;J;K;L;M;N;O;P;Q;R
S;T;U;V;W;X;Y;Z;K0;K1
K2;K3;K4;K5;K6;K7;K8;K9
Count
Mouse :: struct
left: KeyState
right: KeyState
middle: KeyState
wheel: S64
#import "Base.core"
#import "MathF32.core"
#import "MathVec2.core"
#import "Arena.core"
#load "$os_multimedia.core"

View File

@@ -0,0 +1,65 @@
#import "KERNEL32.core"
#import "Base.core"
PAGE_SIZE :: 4096
Memory :: struct
commit : SizeU
reserve: SizeU
data : *U8
ProcessHeap: HANDLE
Allocate :: (size: U64): *void
if ProcessHeap == 0
ProcessHeap = GetProcessHeap()
return HeapAlloc(ProcessHeap, 0, size)
Reserve :: (size: SizeU): Memory
result := Memory{reserve=AlignUp(size, PAGE_SIZE)}
result.data = VirtualAlloc(
flProtect = PAGE_READWRITE,
dwSize = result.reserve,
flAllocationType = MEM_RESERVE,
lpAddress = 0)->*U8
return result
Commit :: (m: *Memory, size: SizeU): Bool
commit_size := AlignUp(size, PAGE_SIZE)
total_commit := m.commit + commit_size
clamped_commit := ClampTopSizeU(total_commit, m.reserve)
adjusted_commit := clamped_commit - m.commit
if adjusted_commit != 0
result := VirtualAlloc(
lpAddress = (m.data + m.commit)->*void,
dwSize = adjusted_commit,
flAllocationType = MEM_COMMIT,
flProtect = PAGE_READWRITE,
)
Assert(result != 0)
m.commit += adjusted_commit
return true
return false
Release :: (m: *Memory)
result := VirtualFree(m.data->*void, 0, MEM_RELEASE)
if result != 0
m.data = 0
m.commit = 0
m.reserve = 0
WriteConsole :: (string: String16)
handle := GetStdHandle(STD_OUTPUT_HANDLE)
WriteConsoleW(handle, string.str->*void, string.len->DWORD, 0, 0)
PerformanceFrequency: F64
PerformanceFrequency_S64: S64
Time :: (): F64
query: LARGE_INTEGER
if PerformanceFrequency_S64 == 0
err := QueryPerformanceFrequency(&PerformanceFrequency_S64)
Assert(err != 0)
PerformanceFrequency = PerformanceFrequency_S64->F64
err := QueryPerformanceCounter(&query)
Assert(err != 0)
result := query->F64 / PerformanceFrequency
return result

200
build/modules/USER32.core Normal file
View File

@@ -0,0 +1,200 @@
#import "KERNEL32.core"
#link "user32"
WNDPROC :: (hwnd: HWND, uMsg: UINT, wParam: WPARAM, lParam: LPARAM): LRESULT
WNDCLASSW :: struct;; style: UINT; lpfnWndProc: WNDPROC; cbClsExtra: int; cbWndExtra: int; hInstance: HINSTANCE; hIcon: HICON; hCursor: HCURSOR; hbrBackground: HBRUSH; lpszMenuName: LPCWSTR; lpszClassName: LPCWSTR
MSG :: struct;; hwnd: HWND; message: UINT; wParam: WPARAM; lParam: LPARAM; time: DWORD; pt: POINT; lPrivate: DWORD
POINT :: struct;; x: LONG; y: LONG
LPMSG :: *MSG
RECT :: struct;; left: LONG; top: LONG; right: LONG; bottom: LONG
LPRECT :: *RECT
PostQuitMessage :: #foreign (nExitCode: int)
DefWindowProcW :: #foreign (hwnd: HWND, uMsg: UINT, wParam: WPARAM, lParam: LPARAM): LRESULT
GetDC :: #foreign (hWnd: HWND): HDC
CreateWindowA :: #foreign (dwExStyle: DWORD, lpClassName: *char, lpWindowName: *char, dwStyle: DWORD, X: int, Y: int, nWidth: int, nHeight: int, hWndParent: HWND, hMenu: HMENU, hInstance: HINSTANCE, lpParam: *void): HWND
CreateWindowExW :: #foreign (dwExStyle: DWORD, lpClassName: LPCWSTR, lpWindowName: LPCWSTR, dwStyle: DWORD, X: int, Y: int, nWidth: int, nHeight: int, hWndParent: HWND, hMenu: HMENU, hInstance: HINSTANCE, lpParam: LPVOID): HWND
RegisterClassW :: #foreign (lpWndClass: *WNDCLASSW): ATOM
ShowWindow :: #foreign (hWnd: HWND, nCmdShow: int): BOOL
PeekMessageW :: #foreign (lpMsg: LPMSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT, wRemoveMs: UINT):BOOL
TranslateMessage :: #foreign (lpMsg: *MSG): BOOL
DispatchMessageW :: #foreign (lpMsg: *MSG): LRESULT
SetProcessDPIAware:: #foreign (): BOOL
GetDpiForWindow :: #foreign (hwnd: HWND): UINT
AdjustWindowRectExForDpi :: #foreign (lpRect: *RECT, dwStyle: DWORD, bMenu: BOOL, dwExStyle: DWORD, dpi: UINT): BOOL
AdjustWindowRectEx :: #foreign (lpRect: *RECT, dwStyle: DWORD, bMenu: BOOL, dwExStyle: DWORD): BOOL
SetWindowPos :: #foreign (hWnd: HWND, hWndInsertAfter: HWND, X: int, Y: int, cx: int, cy: int, uFlags: UINT): BOOL
GetClientRect :: #foreign (hWnd: HWND, lpRect: LPRECT): BOOL
CW_USEDEFAULT :: -2147483648//0x80000000
WS_CAPTION :: 0x00C00000
WS_CHILD :: 0x40000000
WS_CHILDWINDOW :: 0x40000000
WS_CLIPCHILDREN :: 0x02000000
WS_CLIPSIBLINGS :: 0x04000000
WS_DISABLED :: 0x08000000
WS_DLGFRAME :: 0x00400000
WS_GROUP :: 0x00020000
WS_HSCROLL :: 0x00100000
WS_ICONIC :: 0x20000000
WS_MAXIMIZE :: 0x01000000
WS_MAXIMIZEBOX :: 0x00010000
WS_MINIMIZE :: 0x20000000
WS_MINIMIZEBOX :: 0x00020000
WS_OVERLAPPED :: 0x00000000
WS_POPUP :: 0x80000000
WS_SIZEBOX :: 0x00040000
WS_SYSMENU :: 0x00080000
WS_TABSTOP :: 0x00010000
WS_THICKFRAME :: 0x00040000
WS_TILED :: 0x00000000
WS_VISIBLE :: 0x10000000
WS_VSCROLL :: 0x00200000
WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX
PM_NOREMOVE :: 0
PM_REMOVE :: 0x0001
PM_NOYIELD :: 0x0002
SW_HIDE :: 0
SW_NORMAL :: 1
SW_SHOWMINIMIZED :: 2
SW_SHOWMAXIMIZED :: 3
SW_SHOWNOACTIVATE :: 4
SW_SHOW :: 5
SW_MINIMIZE :: 6
SW_SHOWMINNOACTIVE :: 7
SW_SHOWNA :: 8
SW_RESTORE :: 9
SW_SHOWDEFAULT :: 10
SW_FORCEMINIMIZE :: 11
HWND_TOP :: 0
HWND_BOTTOM :: 1
// HWND_NOTOPMOST :: -2 // Probably relies on overflow ?
// HWND_TOPMOST :: -1 // Probably relies on overflow ?
SWP_ASYNCWINDOWPOS :: 0x4000
SWP_DEFERERASE :: 0x2000
SWP_DRAWFRAME :: 0x0020
SWP_FRAMECHANGED :: 0x0020
SWP_HIDEWINDOW :: 0x0080
SWP_NOACTIVATE :: 0x0010
SWP_NOCOPYBITS :: 0x0100
SWP_NOMOVE :: 0x0002
SWP_NOOWNERZORDER :: 0x0200
SWP_NOREDRAW :: 0x0008
SWP_NOREPOSITION :: 0x0200
SWP_NOSENDCHANGING :: 0x0400
SWP_NOSIZE :: 0x0001
SWP_NOZORDER :: 0x0004
SWP_SHOWWINDOW :: 0x0040
WM_NULL :: 0x0000; WM_CREATE :: 0x0001; WM_DESTROY :: 0x0002; WM_MOVE :: 0x0003; WM_SIZE :: 0x0005
WM_ACTIVATE :: 0x0006; WA_INACTIVE :: 0; WA_ACTIVE :: 1; WA_CLICKACTIVE :: 2
WM_SETFOCUS :: 0x0007; WM_KILLFOCUS :: 0x0008; WM_ENABLE :: 0x000A; WM_SETREDRAW :: 0x000B; WM_SETTEXT :: 0x000C; WM_GETTEXT :: 0x000D; WM_GETTEXTLENGTH :: 0x000E; WM_PAINT :: 0x000F; WM_CLOSE :: 0x0010
WM_KEYFIRST :: 0x0100
WM_KEYDOWN :: 0x0100
WM_KEYUP :: 0x0101
WM_CHAR :: 0x0102
WM_DEADCHAR :: 0x0103
WM_SYSKEYDOWN :: 0x0104
WM_SYSKEYUP :: 0x0105
WM_SYSCHAR :: 0x0106
WM_SYSDEADCHAR :: 0x0107
WM_MOUSEFIRST :: 0x0200
WM_MOUSEMOVE :: 0x0200
WM_LBUTTONDOWN :: 0x0201
WM_LBUTTONUP :: 0x0202
WM_LBUTTONDBLCLK :: 0x0203
WM_RBUTTONDOWN :: 0x0204
WM_RBUTTONUP :: 0x0205
WM_RBUTTONDBLCLK :: 0x0206
WM_MBUTTONDOWN :: 0x0207
WM_MBUTTONUP :: 0x0208
WM_MBUTTONDBLCLK :: 0x0209
WM_MOUSEWHEEL :: 0x020A
VK_BACK :: 0x08
VK_TAB :: 0x09
VK_CLEAR :: 0x0C
VK_RETURN :: 0x0D
VK_SHIFT :: 0x10
VK_CONTROL :: 0x11
VK_MENU :: 0x12
VK_PAUSE :: 0x13
VK_CAPITAL :: 0x14
VK_KANA :: 0x15
VK_HANGEUL :: 0x15 /* old name - should be here for compatibility */
VK_HANGUL :: 0x15
VK_IME_ON :: 0x16
VK_JUNJA :: 0x17
VK_FINAL :: 0x18
VK_HANJA :: 0x19
VK_KANJI :: 0x19
VK_IME_OFF :: 0x1A
VK_ESCAPE :: 0x1B
VK_CONVERT :: 0x1C
VK_NONCONVERT :: 0x1D
VK_ACCEPT :: 0x1E
VK_MODECHANGE :: 0x1F
VK_SPACE :: 0x20
VK_PRIOR :: 0x21
VK_NEXT :: 0x22
VK_END :: 0x23
VK_HOME :: 0x24
VK_LEFT :: 0x25
VK_UP :: 0x26
VK_RIGHT :: 0x27
VK_DOWN :: 0x28
VK_SELECT :: 0x29
VK_PRINT :: 0x2A
VK_EXECUTE :: 0x2B
VK_SNAPSHOT :: 0x2C
VK_INSERT :: 0x2D
VK_DELETE :: 0x2E
VK_HELP :: 0x2F
/*
* VK_0 - VK_9 are the same as ASCII '0' - '9' (0x30 - 0x39)
* 0x3A - 0x40 : unassigned
* VK_A - VK_Z are the same as ASCII 'A' - 'Z' (0x41 - 0x5A)
*/
VK_LWIN :: 0x5B
VK_RWIN :: 0x5C
VK_APPS :: 0x5D
VK_SLEEP :: 0x5F
VK_NUMPAD0 :: 0x60
VK_NUMPAD1 :: 0x61
VK_NUMPAD2 :: 0x62
VK_NUMPAD3 :: 0x63
VK_NUMPAD4 :: 0x64
VK_NUMPAD5 :: 0x65
VK_NUMPAD6 :: 0x66
VK_NUMPAD7 :: 0x67
VK_NUMPAD8 :: 0x68
VK_NUMPAD9 :: 0x69
VK_MULTIPLY :: 0x6A
VK_ADD :: 0x6B
VK_SEPARATOR :: 0x6C
VK_SUBTRACT :: 0x6D
VK_DECIMAL :: 0x6E
VK_DIVIDE :: 0x6F
VK_F1 :: 0x70
VK_F2 :: 0x71
VK_F3 :: 0x72
VK_F4 :: 0x73
VK_F5 :: 0x74
VK_F6 :: 0x75
VK_F7 :: 0x76
VK_F8 :: 0x77
VK_F9 :: 0x78
VK_F10 :: 0x79
VK_F11 :: 0x7A
VK_F12 :: 0x7B

6
build/modules/WINMM.core Normal file
View File

@@ -0,0 +1,6 @@
#import "KERNEL32.core"
#link "winmm"
MMRESULT :: UINT
TIMERR_NOERROR :: 0
timeBeginPeriod :: #foreign (uPeriod: UINT): MMRESULT

View File

@@ -0,0 +1,355 @@
#import "KERNEL32.core"
#import "GDI32.core"
#import "USER32.core"
#import "WINMM.core"
#import "OS$OS.core"
Platform :: struct
bitmap: WIN32_Bitmap
window_dc: HDC
window: HWND
good_scheduling: Bool
WIN32_Bitmap :: struct
size: Vec2I
data: *U32
hdc: HDC
dib: HBITMAP
compatible_dc: HDC
IsValidBitmap :: (b: *WIN32_Bitmap): Bool
result := b.data != 0
return result
CreateBitmap :: (for_dc: HDC, size: Vec2I, bottom_up: Bool = true): WIN32_Bitmap
result: WIN32_Bitmap = {size = size}
if bottom_up == false
result.size.y = -result.size.y
header_size: U32 = SizeOf(BITMAPINFOHEADER)
Assert(header_size == 40)
bminfo := BITMAPINFO{
BITMAPINFOHEADER{
biSize = header_size,
biWidth = size.x->LONG,
biHeight = size.y->LONG,
biPlanes = 1,
biBitCount = 32,
biCompression = BI_RGB,
biXPelsPerMeter = 1,
biYPelsPerMeter = 1,
}
}
result.dib = CreateDIBSection(for_dc, &bminfo, DIB_RGB_COLORS, (&result.data)->**void, 0, 0)
result.hdc = CreateCompatibleDC(for_dc)
result.compatible_dc = for_dc
return result
DestroyBitmap :: (b: *WIN32_Bitmap)
if IsValidBitmap(b)
DeleteDC(b.hdc)
DeleteObject(b.dib)
ZeroMemory(b, SizeOf(WIN32_Bitmap))
DrawBitmapInCompatibleDC :: (b: *WIN32_Bitmap)
if IsValidBitmap(b)
SelectObject(b.hdc, b.dib)
BitBlt(b.compatible_dc, 0, 0, b.size.x->int, b.size.y->int, b.hdc, 0, 0, SRCCOPY)
GetWindowStyle :: (resizable: Bool): DWORD
style: DWORD = WS_SYSMENU | WS_OVERLAPPED | WS_CAPTION
if resizable ;; style |= WS_MAXIMIZEBOX | WS_THICKFRAME | WS_MINIMIZEBOX
return style
GetWindowSize :: (window: HWND): Vec2I
result: Vec2I
window_rect: RECT
GetClientRect(window, &window_rect)
result.x = (window_rect.right - window_rect.left)->S64
result.y = (window_rect.bottom - window_rect.top)->S64
return result
GetWindowPos :: (window: HWND): Vec2I
pos: Point
ClientToScreen(window, &pos)
return {pos.x, pos.y}
AdjustWindowRect :: (window: HWND, style: DWORD, rect: *RECT): void
FALSE :: 0
// if window == 0
// dpi := GetDpiForWindow(window)
// AdjustWindowRectExForDpi(rect, style, FALSE, 0, dpi)
// else
AdjustWindowRectEx(rect, style, FALSE, 0)
SetWindowSize :: (window: HWND, style: DWORD, size: Vec2I): void
rect := RECT{ 0, 0, size.x->LONG, size.y->LONG }
AdjustWindowRect(window, style, &rect)
SetWindowPos(window, HWND_TOP, 0, 0, (rect.right - rect.left)->int, (rect.bottom - rect.top)->int, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER)
SetWindowPosition :: (window: HWND, style: DWORD, pos: Vec2I): void
rect := RECT{ pos.x->LONG, pos.y->LONG, pos.x->LONG, pos.y->LONG }
AdjustWindowRect(window, style, &rect)
SetWindowPos(window, 0, rect.left, rect.top, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE)
StartMultimedia :: (
x: S64 = 1280, y: S64 = 720,
title: String = "Hello people!",
window_resizable: Bool = false,
target_ms: F64 = 0.0166666
)
Mu.time.delta = target_ms
if timeBeginPeriod(1) == TIMERR_NOERROR
Mu.os.good_scheduling = true
dpi_aware := SetProcessDPIAware()
Assert(dpi_aware != 0)
Mu.time.start = Time()
hInstance := GetModuleHandleA(0)
window_name := StringToString16(&Mu.frame_arena, title)
w := WNDCLASSW{
lpfnWndProc = WindowProc,
hInstance = hInstance,
lpszClassName = window_name.str,
// style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW,
}
Assert(RegisterClassW(&w) != 0)
style: DWORD = GetWindowStyle(window_resizable)
Mu.os.window = CreateWindowExW(
dwExStyle = 0, hWndParent = 0, hMenu = 0, lpParam = 0,
X = CW_USEDEFAULT, Y = CW_USEDEFAULT, nWidth = x->int, nHeight = y->int,
lpClassName = window_name.str,
lpWindowName = window_name.str,
dwStyle = style,
hInstance = hInstance
)
Assert(Mu.os.window != 0)
SetWindowSize(Mu.os.window, style, {x,y})
ShowWindow(Mu.os.window, SW_SHOW)
size := GetWindowSize(Mu.os.window)
Assert(size.x == x && size.y == y)
Mu.os.window_dc = GetDC(Mu.os.window)
Mu.os.bitmap = CreateBitmap(Mu.os.window_dc, size)
Mu.window.resizable = window_resizable
Mu.screen = Mu.os.bitmap.data
Mu.window.x = size.x
Mu.window.y = size.y
Mu.window.size = size
Mu.window.sizef.x = Mu.window.x->F32
Mu.window.sizef.y = Mu.window.y->F32
UpdateMultimedia :: (): Bool
DrawBitmapInCompatibleDC(&Mu.os.bitmap)
msg: MSG
for PeekMessageW(&msg, Mu.os.window, 0, 0, PM_REMOVE) == 1
TranslateMessage(&msg)
DispatchMessageW(&msg)
size := GetWindowSize(Mu.os.window)
if size.x != Mu.window.x || size.y != Mu.window.y
DestroyBitmap(&Mu.os.bitmap)
Mu.os.bitmap = CreateBitmap(Mu.os.window_dc, size)
Mu.screen = Mu.os.bitmap.data
Mu.window.x = size.x
Mu.window.y = size.y
Mu.window.sizef.x = Mu.window.x->F32
Mu.window.sizef.y = Mu.window.y->F32
Mu.window.size = size
Mu.frame_count += 1
frame_time := Time() - Mu.time.frame_start
Mu.time.total += frame_time
if frame_time < Mu.time.delta
if Mu.os.good_scheduling
time_to_sleep := (Mu.time.delta - frame_time) * 1000
if time_to_sleep > 0
time_to_sleep_dword := time_to_sleep->DWORD
// @check if time_to_sleep_dword truncates down
Sleep(time_to_sleep_dword)
new_frame_time := Time()
for new_frame_time < Mu.time.delta
new_frame_time = Time() - Mu.time.frame_start
Mu.time.frame_start = Time()
return !Mu.quit
WindowProc :: (hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM): LRESULT
result: LRESULT
if msg == WM_DESTROY
// @todo: Add destroy window
PostQuitMessage(0)
return 0
elif msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN
key := MapVKToKey(wparam)
Mu.key[key].down = true
elif msg == WM_KEYUP || msg == WM_SYSKEYUP
key := MapVKToKey(wparam)
Mu.key[key].down = false
elif msg == WM_LBUTTONDOWN ;; Mu.mouse.left.down = true
elif msg == WM_LBUTTONUP ;; Mu.mouse.left.down = false
elif msg == WM_RBUTTONDOWN ;; Mu.mouse.right.down = true
elif msg == WM_RBUTTONUP ;; Mu.mouse.right.down = false
elif msg == WM_MBUTTONDOWN ;; Mu.mouse.middle.down = true
elif msg == WM_MBUTTONUP ;; Mu.mouse.middle.down = false
elif msg == WM_MOUSEWHEEL
if wparam->int > 0
Mu.mouse.wheel = 1
else
Mu.mouse.wheel = -1
// Case(WM_CHAR){
// Utf32Result utf32 = Utf16ToUtf32((u16 *)&wparam, 1);
// if(!utf32.error){
// int index = OS->input_count;
// OS->input_count = ClampTop(OS->input_count + 1, (int)(ArrayCount(OS->input) - 1));
// OS->input[index] = utf32.out_str;
// }
// }Break;
else;; result = DefWindowProcW(hwnd, msg, wparam, lparam)
return result
/*#
mapping = [
["Up", "VK_UP"],
["Down", "VK_DOWN"],
["Left", "VK_LEFT"],
["Right", "VK_RIGHT"],
["Escape", "VK_ESCAPE"],
["Control", "VK_CONTROL"],
["Backspace", "VK_BACK"],
["Alt", "VK_MENU"],
["Shift", "VK_SHIFT"],
["Tab", "VK_TAB"],
["F1", "VK_F1"],
["F2", "VK_F2"],
["F3", "VK_F3"],
["F4", "VK_F4"],
["F5", "VK_F5"],
["F6", "VK_F6"],
["F7", "VK_F7"],
["F8", "VK_F8"],
["F9", "VK_F9"],
["F10", "VK_F10"],
["F11", "VK_F11"],
["F12", "VK_F12"],
["A", "'A'"],
["B", "'B'"],
["C", "'C'"],
["D", "'D'"],
["E", "'E'"],
["F", "'F'"],
["G", "'G'"],
["H", "'H'"],
["I", "'I'"],
["J", "'J'"],
["K", "'K'"],
["L", "'L'"],
["M", "'M'"],
["N", "'N'"],
["O", "'O'"],
["P", "'P'"],
["Q", "'Q'"],
["R", "'R'"],
["S", "'S'"],
["T", "'T'"],
["U", "'U'"],
["V", "'V'"],
["W", "'W'"],
["X", "'X'"],
["Y", "'Y'"],
["Z", "'Z'"],
["K0", "'0'"],
["K1", "'1'"],
["K2", "'2'"],
["K3", "'3'"],
["K4", "'4'"],
["K5", "'5'"],
["K6", "'6'"],
["K7", "'7'"],
["K8", "'8'"],
["K9", "'9'"],
]
print("MapVKToKey :: (vk: WPARAM): Key")
el = ""
for val,map in mapping:
print(f" {el}if vk == {map} ;; return Key.{val}")
el = "el"
print(" return Key.None")
*/
MapVKToKey :: (vk: WPARAM): Key
if vk == VK_UP ;; return Key.Up
elif vk == VK_DOWN ;; return Key.Down
elif vk == VK_LEFT ;; return Key.Left
elif vk == VK_RIGHT ;; return Key.Right
elif vk == VK_ESCAPE ;; return Key.Escape
elif vk == VK_CONTROL ;; return Key.Control
elif vk == VK_BACK ;; return Key.Backspace
elif vk == VK_MENU ;; return Key.Alt
elif vk == VK_SHIFT ;; return Key.Shift
elif vk == VK_TAB ;; return Key.Tab
elif vk == VK_F1 ;; return Key.F1
elif vk == VK_F2 ;; return Key.F2
elif vk == VK_F3 ;; return Key.F3
elif vk == VK_F4 ;; return Key.F4
elif vk == VK_F5 ;; return Key.F5
elif vk == VK_F6 ;; return Key.F6
elif vk == VK_F7 ;; return Key.F7
elif vk == VK_F8 ;; return Key.F8
elif vk == VK_F9 ;; return Key.F9
elif vk == VK_F10 ;; return Key.F10
elif vk == VK_F11 ;; return Key.F11
elif vk == VK_F12 ;; return Key.F12
elif vk == 'A' ;; return Key.A
elif vk == 'B' ;; return Key.B
elif vk == 'C' ;; return Key.C
elif vk == 'D' ;; return Key.D
elif vk == 'E' ;; return Key.E
elif vk == 'F' ;; return Key.F
elif vk == 'G' ;; return Key.G
elif vk == 'H' ;; return Key.H
elif vk == 'I' ;; return Key.I
elif vk == 'J' ;; return Key.J
elif vk == 'K' ;; return Key.K
elif vk == 'L' ;; return Key.L
elif vk == 'M' ;; return Key.M
elif vk == 'N' ;; return Key.N
elif vk == 'O' ;; return Key.O
elif vk == 'P' ;; return Key.P
elif vk == 'Q' ;; return Key.Q
elif vk == 'R' ;; return Key.R
elif vk == 'S' ;; return Key.S
elif vk == 'T' ;; return Key.T
elif vk == 'U' ;; return Key.U
elif vk == 'V' ;; return Key.V
elif vk == 'W' ;; return Key.W
elif vk == 'X' ;; return Key.X
elif vk == 'Y' ;; return Key.Y
elif vk == 'Z' ;; return Key.Z
elif vk == '0' ;; return Key.K0
elif vk == '1' ;; return Key.K1
elif vk == '2' ;; return Key.K2
elif vk == '3' ;; return Key.K3
elif vk == '4' ;; return Key.K4
elif vk == '5' ;; return Key.K5
elif vk == '6' ;; return Key.K6
elif vk == '7' ;; return Key.K7
elif vk == '8' ;; return Key.K8
elif vk == '9' ;; return Key.K9
return Key.None
/*END*/