Init new repository

This commit is contained in:
Krzosa Karol
2024-04-13 15:29:53 +02:00
commit 5a2e3dcec4
335 changed files with 61571 additions and 0 deletions

View File

@@ -0,0 +1,147 @@
AddActorToArray :: proc(arr: *ArrayOfActors, actor: Actor) {
if arr.len + 1 > arr.cap {
new_cap := arr.cap * 2;
if (new_cap == 0) new_cap = 16;
arr.data = libc.realloc(arr.data, sizeof(:Actor) * :libc.size_t(new_cap));
arr.cap = new_cap;
}
arr.data[arr.len] = actor;
arr.len += 1;
}
TryGrowingActorArray :: proc(a: *ArrayOfActors) {
if a.len + 1 > a.cap {
new_cap := a.cap * 2;
if (new_cap == 0) new_cap = 16;
a.data = libc.realloc(a.data, sizeof(:Actor) * :libc.size_t(new_cap));
a.cap = new_cap;
}
}
InsertActor :: proc(a: *ArrayOfActors, item: Actor, index: int) {
if index == a.len {
AddActorToArray(a, item);
return;
}
Assert(index < a.len);
Assert(index >= 0);
TryGrowingActorArray(a);
right_len := :libc.size_t(a.len - index);
libc.memmove(&a.data[index + 1], &a.data[index], sizeof(:Actor) * right_len);
a.data[index] = item;
a.len += 1;
}
GetLastActor :: proc(a: ArrayOfActors): *Actor {
Assert(a.len > 0);
result := &a.data[a.len - 1];
return result;
}
//
AddPath :: proc(arr: *ArrayOfPaths, actor: Path) {
if arr.len + 1 > arr.cap {
new_cap := arr.cap * 2;
if (new_cap == 0) new_cap = 16;
arr.data = libc.realloc(arr.data, sizeof(:Path) * :libc.size_t(new_cap));
arr.cap = new_cap;
}
arr.data[arr.len] = actor;
arr.len += 1;
}
TryGrowingPathArray :: proc(a: *ArrayOfPaths) {
if a.len + 1 > a.cap {
new_cap := a.cap * 2;
if (new_cap == 0) new_cap = 16;
a.data = libc.realloc(a.data, sizeof(:Path) * :libc.size_t(new_cap));
a.cap = new_cap;
}
}
InsertPath :: proc(a: *ArrayOfPaths, item: Path, index: int) {
if index == a.len {
AddPath(a, item);
return;
}
Assert(index < a.len);
Assert(index >= 0);
TryGrowingPathArray(a);
right_len := :libc.size_t(a.len - index);
libc.memmove(&a.data[index + 1], &a.data[index], sizeof(:Path) * right_len);
a.data[index] = item;
a.len += 1;
}
InsertSortedPath :: proc(a: *ArrayOfPaths, item: Path) {
insert_index := -1;
for i := 0; i < a.len; i += 1 {
it := &a.data[i];
if it.value_to_sort_by <= item.value_to_sort_by {
insert_index = i;
InsertPath(a, item, i);
break;
}
}
if insert_index == -1 {
AddPath(a, item);
}
}
GetLastPath :: proc(a: ArrayOfPaths): *Path {
Assert(a.len > 0);
result := &a.data[a.len - 1];
return result;
}
PopPath :: proc(a: *ArrayOfPaths): Path {
a.len -= 1;
result := a.data[a.len];
return result;
}
//
AddV2I :: proc(arr: *ArrayOfV2Is, item: V2I) {
if arr.len + 1 > arr.cap {
new_cap := arr.cap * 2;
if (new_cap == 0) new_cap = 16;
arr.data = libc.realloc(arr.data, sizeof(:V2I) * :libc.size_t(new_cap));
arr.cap = new_cap;
}
arr.data[arr.len] = item;
arr.len += 1;
}
//
AddAnimationSetTile :: proc(arr: *ArrayOfAnimationSetTiles, item: AnimationSetTile) {
if arr.len + 1 > arr.cap {
new_cap := arr.cap * 2;
if (new_cap == 0) new_cap = 16;
arr.data = libc.realloc(arr.data, sizeof(:AnimationSetTile) * :libc.size_t(new_cap));
arr.cap = new_cap;
}
arr.data[arr.len] = item;
arr.len += 1;
}
UnorderedRemoveAnimationSetTile :: proc(a: *ArrayOfAnimationSetTiles, item: *AnimationSetTile) {
Assert(a.len > 0);
Assert(item >= a.data && item < &a.data[a.len]);
a.len -= 1;
*item = a.data[a.len];
}

View File

@@ -0,0 +1,42 @@
bool pathfinding_visualizer() {
LC_Lang *lang = LC_LangAlloc();
lang->use_colored_terminal_output = UseColoredIO;
lang->breakpoint_on_error = BreakpointOnError;
LC_LangBegin(lang);
LC_RegisterPackageDir("../examples/");
LC_RegisterPackageDir("../pkgs");
LC_Intern name = LC_ILit("pathfinding_visualizer");
LC_ASTRefList packages = LC_ResolvePackageByName(name);
LC_FindUnusedLocalsAndRemoveUnusedGlobalDecls();
if (L->errors) {
LC_LangEnd(lang);
return false;
}
DebugVerifyAST(packages);
if (L->errors) {
LC_LangEnd(lang);
return false;
}
OS_MakeDir("examples");
OS_MakeDir("examples/pathfinding_visualizer");
S8_String code = LC_GenerateUnityBuild(packages);
S8_String path = "examples/pathfinding_visualizer/pathfinding_visualizer.c";
OS_WriteFile(path, code);
if (!UseCL) {
LC_LangEnd(lang);
return true;
}
S8_String cmd = Fmt("cl %.*s -Zi -std:c11 -nologo -FC -Fd:examples/pathfinding_visualizer/a.pdb -Fe:examples/pathfinding_visualizer/pathfinding_visualizer.exe %.*s", S8_Expand(path), S8_Expand(RaylibLIB));
int errcode = Run(cmd);
OS_CopyFile(RaylibDLL, "examples/pathfinding_visualizer/raylib.dll", true);
LC_LangEnd(lang);
bool result = errcode == 0;
return result;
}

View File

@@ -0,0 +1,266 @@
import "raylib";
import libc "libc";
import "std_types";
WinX := 1280;
WinY := 720;
Mode := 0;
RectX :: 16;
RectY :: 16;
Dt: float;
MouseX:= 0;
MouseY:= 0;
MouseP: Vector2 = {0, 0};
MouseSelecting := false;
MouseSelectionPivot: Vector2;
MouseSelectionBox: Rectangle;
MouseSelectedActors: ArrayOfActors;
AnimationSetTiles: ArrayOfAnimationSetTiles;
AnimationSetTile :: struct {
set: bool;
p: V2I;
t: float;
}
ArrayOfAnimationSetTiles :: struct {
data: *AnimationSetTile;
len: int;
cap: int;
}
main :: proc(): int {
InitMap();
InitWindow(WinX, WinY, "pathfinding visualizer");
SetTargetFPS(60);
orange := ORANGE;
orange.a = 255/2;
brown := BROWN;
brown.a = 255/2;
dark_green := DARKGREEN;
dark_green.a = 255/2;
blue := BLUE;
blue.a = 255/2;
green := GREEN;
green.a = 255/2;
red := RED;
red.a = 255/2;
actor_color := dark_green;
past_actor_color := blue;
target_color := red;
selection_box_color := green;
selected_color := selection_box_color;
for !WindowShouldClose() {
WinX = GetScreenHeight();
WinY = GetScreenWidth();
MouseX = GetMouseX();
MouseY = GetMouseY();
MouseP = GetMousePosition();
Dt = GetFrameTime();
@unused map := &CurrentMap;
MouseSelecting = false;
if IsMouseButtonDown(MOUSE_BUTTON_LEFT) {
MouseSelecting = true;
if IsMouseButtonPressed(MOUSE_BUTTON_LEFT) {
MouseSelectionPivot = MouseP;
}
MouseSelectionBox = {
MouseSelectionPivot.x,
MouseSelectionPivot.y,
MouseP.x - MouseSelectionPivot.x,
MouseP.y - MouseSelectionPivot.y,
};
if MouseSelectionBox.width < 0 {
MouseSelectionBox.x += MouseSelectionBox.width;
MouseSelectionBox.width = -MouseSelectionBox.width;
}
if MouseSelectionBox.height < 0 {
MouseSelectionBox.y += MouseSelectionBox.height;
MouseSelectionBox.height = -MouseSelectionBox.height;
}
}
if IsKeyPressed(KEY_F1) {
Mode = 0;
}
if IsKeyPressed(KEY_F2) {
Mode = 1;
}
if IsKeyPressed(KEY_F3) {
for i := 0; i < map.actors.len; i += 1 {
it := &map.actors.data[i];
MoveTowardsTarget(it);
}
}
PathFindUpdate(map);
if IsKeyPressed(KEY_F4) {
RandomizeActors();
}
BeginDrawing();
ClearBackground(RAYWHITE);
map_rectangle: Rectangle = {0, 0, :float(map.x) * RectX, :float(map.y) * RectY};
DrawRectangleRec(map_rectangle, LIGHTGRAY);
for x := 0; x < map.x; x += 1 {
for y := 0; y < map.y; y += 1 {
it := map.data[x + y*map.x];
r : Rectangle = {:float(x) * RectX, :float(y) * RectY, RectX, RectY};
r2: Rectangle = {r.x + 1, r.y + 1, r.width - 2, r.height - 2};
colliding := CheckCollisionPointRec(MouseP, r);
color := RAYWHITE;
if it == 1 { color = GRAY; }
if Mode == 0 {
if colliding && IsMouseButtonDown(MOUSE_BUTTON_LEFT) {
AddAnimationSetTile(&AnimationSetTiles, {true, {x,y}});
}
if colliding && IsMouseButtonDown(MOUSE_BUTTON_RIGHT) {
AddAnimationSetTile(&AnimationSetTiles, {false, {x,y}});
}
if colliding {
color.a = 100;
}
}
DrawRectangleRec(r2, color);
}
}
for tile_i := 0; tile_i < AnimationSetTiles.len; tile_i += 1 {
tile_it := &AnimationSetTiles.data[tile_i];
remove := false;
t := tile_it.t;
if tile_it.set == false {
t = 1 - t;
}
x := :float(tile_it.p.x) * RectX + 1;
y := :float(tile_it.p.y) * RectY + 1;
w: float = RectX - 2;
h: float = RectY - 2;
wt := w * t;
ht := h * t;
wd := w - wt;
hd := h - ht;
r: Rectangle = {x + wd/2, y + hd/2, wt, ht};
DrawRectangleRec(r, GRAY);
if tile_it.t > 1 {
map_tile := &map.data[tile_it.p.x + tile_it.p.y*map.x];
if tile_it.set {*map_tile |= TILE_BLOCKER;}
else {*map_tile &= ~TILE_BLOCKER;}
remove = true;
}
tile_it.t += Dt*8;
if remove {
UnorderedRemoveAnimationSetTile(&AnimationSetTiles, tile_it);
tile_i -= 1;
}
}
for actor_i := 0; actor_i < map.actors.len; actor_i += 1 {
actor_it := &map.actors.data[actor_i];
target_r := Rect(actor_it.target_p);
main_p := Circle(actor_it.p);
DrawCircleV(main_p, RectX/2, actor_color);
DrawRectangleRec(target_r, target_color);
smaller_the_further: float;
for tile_i := actor_it.tiles_visited.len - 1; tile_i >= 0; tile_i -= 1 {
tile_it := &actor_it.tiles_visited.data[tile_i];
p := Circle({tile_it.x, tile_it.y});
DrawCircleV(p, RectX/2 - smaller_the_further, past_actor_color);
smaller_the_further += 0.5;
}
for path_i := 0; path_i < actor_it.open_paths.len; path_i += 1 {
path_it := &actor_it.open_paths.data[path_i];
path_r := Rect(path_it.p);
DrawRectangleRec(path_r, orange);
s := TextFormat("%d", :int(libc.sqrtf(:float(path_it.value_to_sort_by))));
DrawText(s, :int(path_r.x), :int(path_r.y), 1, RAYWHITE);
}
for path_i := 0; path_i < actor_it.close_paths.len; path_i += 1 {
path_it := &actor_it.close_paths.data[path_i];
path_r := Rect(path_it.p);
DrawRectangleRec(path_r, brown);
}
for path_i := 0; path_i < actor_it.history.len; path_i += 1 {
path_it := &actor_it.history.data[path_i];
p0 := Circle(path_it.came_from);
p1 := Circle(path_it.p);
DrawLineEx(p0, p1, 5, LIGHTGRAY);
DrawCircleV(p0, 4, LIGHTGRAY);
DrawCircleV(p1, 4, LIGHTGRAY);
}
}
if Mode == 1 {
for actor_i := 0; actor_i < MouseSelectedActors.len; actor_i += 1 {
actor_it := &MouseSelectedActors.data[actor_i];
actor_box := Rect(actor_it.p);
DrawRectangleRec(actor_box, selected_color);
if IsMouseButtonPressed(MOUSE_BUTTON_RIGHT) {
p := ScreenToMap(MouseP);
SetTargetP(actor_it, p);
}
}
if MouseSelecting {
MouseSelectedActors.len = 0;
for actor_i := 0; actor_i < MouseSelectedActors.len; actor_i += 1 {
actor_it := &MouseSelectedActors.data[actor_i];
actor_box := Rect(actor_it.p);
if CheckCollisionRecs(actor_box, MouseSelectionBox) {
AddActorToArray(&MouseSelectedActors, *actor_it);
}
}
DrawRectangleRec(MouseSelectionBox, selection_box_color);
}
}
text_size := 24;
text_p := 4;
text_y := text_size * 2;
DrawText("F4 :: Randomize actors", text_p, text_y, text_size, GRAY);
text_y -= text_size;
DrawText("F3 :: Simulate actors", text_p, text_y, text_size, GRAY);
text_y -= text_size;
text: *char = "Mode(F1) :: Block placing";
if Mode == 1 { text = "Mode(F2) :: Actor placing"; }
DrawText(text, text_p, text_y, text_size, GRAY);
text_y -= text_size;
EndDrawing();
}
return 0;
}

View File

@@ -0,0 +1,286 @@
CurrentMap: Map;
Tile :: typedef int;
TILE_BLOCKER :: 1;
TILE_ACTOR_IS_STANDING :: <<;
Map :: struct {
data: *Tile;
x: int;
y: int;
actors: ArrayOfActors;
}
V2I :: struct {
x: int;
y: int;
}
Actor :: struct {
p: V2I;
target_p: V2I;
map: *Map;
open_paths: ArrayOfPaths;
close_paths: ArrayOfPaths;
tiles_visited: ArrayOfV2Is;
history: ArrayOfPaths;
}
Path :: struct {
value_to_sort_by: int;
p: V2I;
came_from: V2I;
}
ArrayOfActors :: struct {
data: *Actor;
len: int;
cap: int;
}
ArrayOfPaths :: struct {
data: *Path;
len: int;
cap: int;
}
ArrayOfV2Is :: struct {
data: *V2I;
len: int;
cap: int;
}
Rect :: proc(p: V2I): Rectangle {
result: Rectangle = {:float(p.x) * RectX, :float(p.y) * RectY, RectX, RectY};
return result;
}
Circle :: proc(p: V2I): Vector2 {
result: Vector2 = {:float(p.x) * RectX + RectX/2, :float(p.y) * RectY + RectY/2};
return result;
}
ScreenToMap :: proc(p: Vector2): V2I {
x := p.x / RectX;
y := p.y / RectY;
result: V2I = {:int(x), :int(y)};
return result;
}
MaxInt :: proc(x: int, y: int): int {
if x > y return x;
return y;
}
Assert :: proc(x: bool) {
if (!x) {
libc.printf("assertion failed\n");
libc.fflush(libc.stdout);
libc.debug_break();
}
}
InvalidCodepath :: proc() {
libc.printf("invalid codepath\n");
libc.fflush(libc.stdout);
libc.debug_break();
}
AddActor :: proc(map: *Map, p: V2I): *Actor {
AddActorToArray(&map.actors, {p, p, map});
map.data[p.x + p.y * map.x] |= TILE_ACTOR_IS_STANDING;
result := GetLastActor(map.actors);
return result;
}
SetActorP :: proc(actor: *Actor, p: V2I) {
map := actor.map;
new_tile := &map.data[p.x + p.y * map.x];
if *new_tile != 0 return;
tile := &map.data[actor.p.x + actor.p.y * map.x];
Assert((*tile & TILE_ACTOR_IS_STANDING) != 0);
*tile &= ~TILE_ACTOR_IS_STANDING;
*new_tile |= TILE_ACTOR_IS_STANDING;
actor.p = p;
actor.tiles_visited.len = 0;
actor.history.len = 0;
actor.open_paths.len = 0;
actor.close_paths.len = 0;
}
SetTargetP :: proc(actor: *Actor, p: V2I) {
actor.target_p = p;
actor.tiles_visited.len = 0;
actor.history.len = 0;
actor.open_paths.len = 0;
actor.close_paths.len = 0;
}
GetRandomP :: proc(m: *Map): V2I {
result: V2I = {GetRandomInt(0, m.x - 1), GetRandomInt(0, m.y - 1)};
return result;
}
GetRandomUnblockedP :: proc(m: *Map): V2I {
for i := 0; i < 128; i += 1 {
p := GetRandomP(m);
if m.data[p.x + p.y * m.x] == 0 {
return p;
}
}
Assert(!:ullong(:*char("invalid codepath")));
return {};
}
InitMap :: proc() {
CurrentMap.x = WinX / RectX;
CurrentMap.y = WinY / RectY;
bytes := sizeof(:Tile) * CurrentMap.x * CurrentMap.y;
CurrentMap.data = libc.malloc(:libc.size_t(bytes));
libc.memset(CurrentMap.data, 0, :libc.size_t(bytes));
actor := AddActor(&CurrentMap, GetRandomUnblockedP(&CurrentMap));
actor.target_p = GetRandomUnblockedP(&CurrentMap);
actor2 := AddActor(&CurrentMap, GetRandomUnblockedP(&CurrentMap));
actor2.target_p = GetRandomUnblockedP(&CurrentMap);
}
RandomizeActors :: proc() {
map := &CurrentMap;
for i := 0; i < map.actors.len; i += 1 {
it := &map.actors.data[i];
p := GetRandomUnblockedP(&CurrentMap);
SetActorP(it, p);
it.target_p = GetRandomUnblockedP(&CurrentMap);
}
}
InsertOpenPath :: proc(actor: *Actor, p: V2I, came_from: V2I, ignore_blocks: bool = false) {
if p.x < 0 || p.x >= actor.map.x return;
if p.y < 0 || p.y >= actor.map.y return;
if ignore_blocks == false && actor.map.data[p.x + p.y * actor.map.x] != 0 return;
for i := 0; i < actor.close_paths.len; i += 1 {
it := &actor.close_paths.data[i];
if it.p.x == p.x && it.p.y == p.y return;
}
for i := 0; i < actor.open_paths.len; i += 1 {
it := &actor.open_paths.data[i];
if it.p.x == p.x && it.p.y == p.y return;
}
dx := actor.target_p.x - p.x;
dy := actor.target_p.y - p.y;
d := dx*dx + dy*dy;
InsertSortedPath(&actor.open_paths, {d, p, came_from});
}
GetCloseP :: proc(actor: *Actor, p: V2I): *Path {
for i := 0; i < actor.close_paths.len; i += 1 {
it := &actor.close_paths.data[i];
if it.p.x == p.x && it.p.y == p.y return it;
}
InvalidCodepath();
return nil;
}
RecomputeHistory :: proc(actor: *Actor) {
if actor.close_paths.len > 1 {
actor.history.len = 0;
it := GetLastPath(actor.close_paths);
AddPath(&actor.history, *it);
for i := 0;;i += 1 {
if it.p.x == actor.p.x && it.p.y == actor.p.y { break; }
if i > 512 { actor.history.len = 0; break; } // @todo: Pop after this and error?
it = GetCloseP(actor, it.came_from);
AddPath(&actor.history, *it);
}
PopPath(&actor.history);
}
}
MoveTowardsTarget :: proc(actor: *Actor) {
tile := &actor.map.data[actor.p.x + actor.p.y * actor.map.x];
if actor.history.len > 0 {
step := PopPath(&actor.history);
new_tile := &actor.map.data[step.p.x + step.p.y * actor.map.x];
if *new_tile == 0 {
AddV2I(&actor.tiles_visited, actor.p);
actor.p = step.p;
*tile &= ~TILE_ACTOR_IS_STANDING;
*new_tile |= TILE_ACTOR_IS_STANDING;
}
}
}
PathFindUpdate :: proc(map: *Map) {
for actor_i := 0; actor_i < map.actors.len; actor_i += 1 {
actor_it := &map.actors.data[actor_i];
for i := 0; i < actor_it.history.len; i += 1 {
history_it := &actor_it.history.data[i];
tile := actor_it.map.data[history_it.p.x + history_it.p.y * actor_it.map.x];
if tile != 0 {
actor_it.close_paths.len = 0;
actor_it.open_paths.len = 0;
actor_it.history.len = 0;
break;
}
}
PathFind(actor_it);
}
}
PathFindStep :: proc(s: *Actor, compute_history: bool = true): bool {
if s.open_paths.len == 0 {
// Reset if we didn't find solution
if s.close_paths.len != 0 {
last := GetLastPath(s.close_paths);
reached_target := last.p.x == s.target_p.x && last.p.y == s.target_p.y;
if reached_target == false {
s.close_paths.len = 0;
s.open_paths.len = 0;
s.history.len = 0;
}
}
InsertOpenPath(s, s.p, s.p, ignore_blocks = true);
}
if s.close_paths.len != 0 {
last := GetLastPath(s.close_paths);
reached_target := last.p.x == s.target_p.x && last.p.y == s.target_p.y;
if reached_target return true;
}
it := PopPath(&s.open_paths);
AddPath(&s.close_paths, it);
for y := -1; y <= 1; y += 1 {
for x := -1; x <= 1; x += 1 {
if x == 0 && y == 0 continue;
p: V2I = {it.p.x + x, it.p.y + y};
InsertOpenPath(s, p, it.p);
}
}
if compute_history RecomputeHistory(s);
return false;
}
PathFind :: proc(actor: *Actor) {
for i := 0; i < 32; i += 1 {
done := PathFindStep(actor, false);
if done break;
}
RecomputeHistory(actor);
}

View File

@@ -0,0 +1,22 @@
RandomSeedValue: RandomSeed = {121521923492};
RandomSeed :: struct {
a: u64;
}
GetRandomU64 :: proc(s: *RandomSeed): u64 {
x := s.a;
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
s.a = x;
return x;
}
GetRandomInt :: proc(min: int, max: int): int {
random := GetRandomU64(&RandomSeedValue);
range_size: u64 = :u64(max - min) + 1;
result := :int(random % range_size);
result = result + min;
return result;
}