Author:ptrace
Comitter:ptrace
Date:2026-05-02 09:16:49 UTC
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..805c007
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
# Jai
.build
/bin
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/README.md
diff --git a/build.jai b/build.jai
new file mode 100644
index 0000000..1abc4f7
--- /dev/null
+++ b/build.jai
@@ -0,0 +1,140 @@
#import "Basic";
#import "Compiler";
#import "File";
#import "Autorun";
build :: () {
args := get_build_options().compile_time_command_line;
// args
args_help := array_find(args, "help");
args_compiler_silent := array_find(args, "silent");
args_program_run := array_find(args, "run");
args_build_release := array_find(args, "release");
args_memory_debug := array_find(args, "memory");
// program args
program_args := program_args_collect(args);
defer array_free(program_args);
// -----------------------------------------
w := compiler_create_workspace();
if !w {
log("Workspace creation failed.");
return;
}
set_build_options_dc(.{ do_output = false });
if args_help {
args_help_print();
return;
}
print("The workspace w is %\n", w);
make_directory_if_it_does_not_exist("bin");
make_directory_if_it_does_not_exist("bin/debug");
make_directory_if_it_does_not_exist("bin/release");
target_options := get_build_options(w);
target_options.output_executable_name = "program";
if args_compiler_silent target_options.text_output_flags = 0;
if args_build_release {
build_release(w, *target_options);
} else {
build_debug(w, *target_options);
}
compiler_begin_intercept(w);
add_build_file(tprint("%src/main.jai", #filepath), w);
add_build_string(tprint("MEMORY_DEBUGGER_ENABLED :: %;", args_memory_debug), w);
compiler_response := message_loop();
compiler_end_intercept(w);
if !compiler_response {
log("Compiler response failed.");
return;
}
if args_program_run run_build_result_of_workspace(w, program_args);
}
build_debug :: (w: Workspace, target_options: *Build_Options) {
log("Choosing debug options...");
target_options.backend =.X64;
target_options.output_path = "bin/debug";
set_optimization(target_options, Optimization_Type.DEBUG, true);
set_build_options(target_options.*, w);
}
build_release :: (w: Workspace, target_options: *Build_Options) {
log("Choosing release options...");
target_options.backend = .LLVM;
target_options.output_path = "bin/release";
set_optimization(target_options, Optimization_Type.VERY_OPTIMIZED);
set_build_options(target_options.*, w);
}
args_help_print :: () {
help_message := #string _END_
Usage: jai build.jai - [OPTIONS] :: [PROGRAM ARGS]
Options:
help Prints this help menu.
silent Disables compiler/linker statistics.
run Runs your program afterwards.
release Builds with release options. If omitted, it builds a debug build.
memory Enables the memory leak detector.
Passing Args to your Program:
If you want to supply args to your program, pass it like that:
`jai build.jai - run :: my_arg1 foo bar abc ABC`
Everything after the `::` get's forwarded to your program.
_END_;
log(help_message);
}
program_args_collect :: (args: []string, divider: string = "::") -> [..]string {
buf: [..]string;
success, match := array_find(args, divider);
if success for i: match+1..args.count-1 array_add(*buf, args[i]);
return buf;
}
message_loop :: () -> success: bool {
while true {
message := compiler_wait_for_message();
if !message break;
if message.kind == {
case .COMPLETE;
message_complete := cast(*Message_Complete) message;
return message_complete.error_code == 0;
}
}
return false;
}
#placeholder MEMORY_DEBUGGER_ENABLED;
main :: () {}
#run build();
diff --git a/modules/raylib b/modules/raylib
new file mode 120000
index 0000000..30ac3f9
--- /dev/null
+++ b/modules/raylib
@@ -0,0 +1 @@
/home/ptrace/dev/_LIBS/jai/raylib-jai/Raylib
\ No newline at end of file
diff --git a/src/main.jai b/src/main.jai
new file mode 100644
index 0000000..6d88628
--- /dev/null
+++ b/src/main.jai
@@ -0,0 +1,220 @@
#import "Basic"()(
MEMORY_DEBUGGER = MEMORY_DEBUGGER_ENABLED
);
#import "Math";
#import "Print_Vars";
#import "raylib";
/*
(0)
/ \
(1) (2)
/ \
(3, 4) (5, 6)
l = 2 * i + 1
r = 2 * i + 2
parent = floor((i - 1) / 2)
[
0, 1, 2,
]
*/
rects := Rectangle.[
{ -200.0, -160.0, 40.0, 45.0 },
{ -140.0, -100.0, 25.0, 25.0 },
{ -7.0, 60.0, 70.0, 50.0 },
{ 55.0, 75.0, 25.0, 25.0 },
{ -180.0, 40.0, 45.0, 25.0 },
{ 120.0, 20.0, 9.0, 16.0 },
{ 10.0, 35.0, 25.0, 15.0 },
{ -80.0, 100.0, 21.0, 32.0 },
{ 30.0, -70.0, 9.0, 16.0 },
];
color_choice := Color.[
ORANGE,
YELLOW,
GREEN,
BLUE,
];
NODE_INTERNAL :: -6;
NODE_ROOT :: -9;
NODE_EMPTY :: -1;
DRAW_BV :: true;
Aabb :: struct {
upper_bound: Vector2;
lower_bound: Vector2;
}
Tree :: struct {
data: [..]int;
}
Node :: struct {
parent: int = NODE_EMPTY;
left: int = NODE_EMPTY;
right: int = NODE_EMPTY;
}
#if false main :: () {
#if MEMORY_DEBUGGER_ENABLED defer report_memory_leaks();
log("Hello, Sailor!");
camera: Camera2D;
camera.offset = { 400.0, 300.0 };
camera.zoom = 1.0;
SetTraceLogLevel(.LOG_NONE);
SetConfigFlags(.FLAG_MSAA_4X_HINT);
InitWindow(800, 600, "Template");
defer CloseWindow();
SetTargetFPS(60);
push_allocator(temp);
while !WindowShouldClose() {
BeginDrawing();
defer EndDrawing();
ClearBackground({ 42, 42, 60, 255 });
{
BeginMode2D(camera);
defer EndMode2D();
// box1 := make_aabb(rects[0]);
// box2 := make_aabb(rects[1]);
// u := aabb_bv_union(box1, box2);
// Make AABBs
aabbs: [..]Aabb;
for rects array_add(*aabbs, make_aabb(it));
for rects DrawRectangleLinesEx(
it,
1.0,
color_choice[it_index % color_choice.count]
);
// sleep_milliseconds(500);
}
DrawFPS(10, 10);
DrawText(TextFormat("Frame Time: %f s", GetFrameTime()), 10, 30, 20, WHITE);
reset_temporary_storage();
}
} else main :: () {
log("Offline");
tree: Tree;
array_add(*tree.data, 100);
array_add(*tree.data, 110);
array_add(*tree.data, 120);
array_add(*tree.data, 111);
array_add(*tree.data, 112);
array_add(*tree.data, 121);
array_add(*tree.data, 122);
log_vars(tree.data);
t := tree_access_node(tree, 0);
log_vars(t);
tree_split_node(*tree, 2, 400, 401);
log_vars(tree.data);
t = tree_access_node(tree, 2);
log_vars(t);
}
/** Continue:
- Refit
- Rotate
- Collapse
*/
tree_split_node :: (tree: *Tree, index: int, left: int, right: int) {
i_left := 2 * index + 1;
i_right := 2 * index + 2;
while tree.data.count <= i_right {
array_add(*tree.data, NODE_EMPTY);
}
tree.data[i_left] = left;
tree.data[i_right] = right;
tree.data[index] = NODE_INTERNAL;
// tree.data[index] becomes an internal node — refit its bounding volume
}
tree_access_node :: (tree: Tree, index: int) -> Node {
node: Node;
i_left := 2 * index + 1;
i_right := 2 * index + 2;
i_parent := cast(int)floor((index - 1.0) / 2.0);
for int.[i_left, i_right] {
if it > tree.data.count return node;
}
node.left = tree.data[i_left];
node.right = tree.data[i_right];
node.parent = ifx i_parent < 0 then NODE_ROOT else tree.data[i_parent];
return node;
}
make_aabb :: (rect: Rectangle) -> Aabb {
a: Aabb;
a.upper_bound = { rect.x, rect.y };
a.lower_bound = { rect.x + rect.width , rect.y + rect.height };
return a;
}
aabb_draw :: (a: Aabb) {
#if !DRAW_BV return;
rect := Rectangle.{
a.upper_bound.x,
a.upper_bound.y,
a.lower_bound.x - a.upper_bound.x,
a.lower_bound.y - a.upper_bound.y
};
DrawRectangleLinesEx(rect, 1.0, RED);
}
aabb_bv_compute_surface_area :: (a: Aabb) -> float {
d := a.upper_bound - a.lower_bound;
return 2.0 * (d.x * d.y);
}
aabb_bv_union :: (a: Aabb, b: Aabb) -> Aabb {
c: Aabb;
c.upper_bound = min(a.upper_bound, b.upper_bound);
c.lower_bound = max(a.lower_bound, b.lower_bound);
return c;
}