Previously it wasnt working but now its working, TRUST ME
This commit is contained in:
293
build/examples/_demo1.core
Normal file
293
build/examples/_demo1.core
Normal 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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
90
build/examples/_polymorphism.core
Normal file
90
build/examples/_polymorphism.core
Normal 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
|
||||
97
build/examples/any_and_variadic_args.core
Normal file
97
build/examples/any_and_variadic_args.core
Normal 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
|
||||
55
build/examples/arrays_and_slices.core
Normal file
55
build/examples/arrays_and_slices.core
Normal 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
|
||||
40
build/examples/constant_expressions.core
Normal file
40
build/examples/constant_expressions.core
Normal 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
|
||||
76
build/examples/drawing_to_screen_using_windows_api.core
Normal file
76
build/examples/drawing_to_screen_using_windows_api.core
Normal 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)
|
||||
55
build/examples/dynamic_typing.core
Normal file
55
build/examples/dynamic_typing.core
Normal 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
|
||||
103
build/examples/language_basics.core
Normal file
103
build/examples/language_basics.core
Normal 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
|
||||
26
build/examples/operator_overloading.core
Normal file
26
build/examples/operator_overloading.core
Normal 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
|
||||
74
build/examples/order_independent_declarations.core
Normal file
74
build/examples/order_independent_declarations.core
Normal 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
|
||||
|
||||
|
||||
|
||||
|
||||
15
build/examples/push_struct.core
Normal file
15
build/examples/push_struct.core
Normal 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
|
||||
210
build/examples/raymarcher.core
Normal file
210
build/examples/raymarcher.core
Normal 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
|
||||
69
build/examples/runtime_type_information.core
Normal file
69
build/examples/runtime_type_information.core
Normal 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
|
||||
|
||||
48
build/examples/types_as_first_class_values.core
Normal file
48
build/examples/types_as_first_class_values.core
Normal 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
|
||||
|
||||
|
||||
|
||||
40
build/examples/unions.core
Normal file
40
build/examples/unions.core
Normal 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
|
||||
12
build/examples/using_multimedia.core
Normal file
12
build/examples/using_multimedia.core
Normal 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
42
build/modules/Arena.core
Normal 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
124
build/modules/Base.core
Normal 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
41
build/modules/GDI32.core
Normal 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
130
build/modules/KERNEL32.core
Normal 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
|
||||
60
build/modules/Language.core
Normal file
60
build/modules/Language.core
Normal 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
17
build/modules/LibC.core
Normal 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
|
||||
34
build/modules/MathF32.core
Normal file
34
build/modules/MathF32.core
Normal 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
|
||||
32
build/modules/MathVec2.core
Normal file
32
build/modules/MathVec2.core
Normal 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}
|
||||
46
build/modules/MathVec3.core
Normal file
46
build/modules/MathVec3.core
Normal 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
|
||||
64
build/modules/Multimedia.core
Normal file
64
build/modules/Multimedia.core
Normal 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"
|
||||
65
build/modules/OSWin32.core
Normal file
65
build/modules/OSWin32.core
Normal 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
200
build/modules/USER32.core
Normal 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
6
build/modules/WINMM.core
Normal file
@@ -0,0 +1,6 @@
|
||||
#import "KERNEL32.core"
|
||||
#link "winmm"
|
||||
|
||||
MMRESULT :: UINT
|
||||
TIMERR_NOERROR :: 0
|
||||
timeBeginPeriod :: #foreign (uPeriod: UINT): MMRESULT
|
||||
355
build/modules/win32_multimedia.core
Normal file
355
build/modules/win32_multimedia.core
Normal 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*/
|
||||
Reference in New Issue
Block a user