From 14321c71b80507181f05b9b6c33e81ee3505c45b Mon Sep 17 00:00:00 2001 From: James Bulman Date: Sat, 4 Oct 2025 00:56:55 +0100 Subject: [PATCH 1/5] Added virtual memory on Linux --- code/core/platform.h | 2 ++ code/os/core.c | 2 ++ code/os/impl/linux/core.c | 31 +++++++++++++++++++++++++++++++ linux | 2 +- 4 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 code/os/impl/linux/core.c diff --git a/code/core/platform.h b/code/core/platform.h index a6cbda1..5047a9f 100644 --- a/code/core/platform.h +++ b/code/core/platform.h @@ -71,6 +71,8 @@ #pragma warning(disable : 4201) #elif OS_LINUX #include + #include + #include #endif #endif // LD_CORE_PLATFORM_H_ diff --git a/code/os/core.c b/code/os/core.c index e442952..0ebb8a9 100644 --- a/code/os/core.c +++ b/code/os/core.c @@ -1,3 +1,5 @@ #if OS_WINDOWS #include "impl/windows/core.c" +#elif OS_LINUX + #include "impl/linux/core.c" #endif diff --git a/code/os/impl/linux/core.c b/code/os/impl/linux/core.c new file mode 100644 index 0000000..1dd1cd9 --- /dev/null +++ b/code/os/impl/linux/core.c @@ -0,0 +1,31 @@ +U64 VM_PageSize() { + U64 result = getpagesize(); + return result; +} + +U64 VM_AllocationGranularity() { + U64 result = getpagesize(); + return result; +} + +void *VM_Reserve(U64 size) { + void *addr = mmap(0, size, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0); + + void *result = (addr == MAP_FAILED) ? 0 : addr; + return result; +} + +B32 VM_Commit(void *base, U64 size) { + B32 result = mprotect(base, size, PROT_READ | PROT_WRITE) == 0; + return result; +} + +void VM_Decommit(void *base, U64 size) { + mprotect(base, size, PROT_NONE); +} + +void VM_Release(void *base, U64 size) { + munmap(base, size); +} + + diff --git a/linux b/linux index b44be73..2930c89 100755 --- a/linux +++ b/linux @@ -37,7 +37,7 @@ fi echo "[Building source]" -COMPILER_OPTS="-Wall -Wno-missing-braces -I'deps/stb'" +COMPILER_OPTS="-Wall -Wno-missing-braces -Wno-unused-function -I'deps/stb'" LINKER_OPTS="-lSDL3" if [[ $release == 1 ]] From a9f12532b4319ca26520e8283dc98d791a767d6c Mon Sep 17 00:00:00 2001 From: Matt Date: Sat, 4 Oct 2025 14:57:09 +0100 Subject: [PATCH 2/5] feat: collision functions added --- code/core/types.h | 12 ++++++++++++ code/first.c | 1 + code/game/aabb.h | 17 +++++++++++++++++ code/game/impl/aabb.c | 15 +++++++++++++++ 4 files changed, 45 insertions(+) create mode 100644 code/game/aabb.h create mode 100644 code/game/impl/aabb.c diff --git a/code/core/types.h b/code/core/types.h index 08436db..a5bc66d 100644 --- a/code/core/types.h +++ b/code/core/types.h @@ -29,4 +29,16 @@ struct Str8 { U8 *data; }; +typedef struct V2f V2f; +struct V2f { + F32 x; + F32 y; +}; + +typedef struct V2i V2i; +struct V2i { + U32 x; + U32 y; +}; + #endif // LD_CORE_TYPES_H_ diff --git a/code/first.c b/code/first.c index 3202aea..6d714a8 100644 --- a/code/first.c +++ b/code/first.c @@ -3,6 +3,7 @@ #include #include "core/core.h" +#include "core/types.h" #include "os/core.h" #include "vulkan/core.h" diff --git a/code/game/aabb.h b/code/game/aabb.h new file mode 100644 index 0000000..060cb53 --- /dev/null +++ b/code/game/aabb.h @@ -0,0 +1,17 @@ +#if !defined(LD_CORE_AABB_H_) +#define LD_CORE_AABB_H_ +#include "types.h" +#include "../core/macros.h" + + +typedef struct AABB AABB; +struct AABB { + V2f pos; + V2f size; +}; + + +function bool AABB_Collide(AABB a, AABB b); +function bool AABB_Point(AABB a, V2f v); + +#endif // LD_CORE_AABB_H_ diff --git a/code/game/impl/aabb.c b/code/game/impl/aabb.c new file mode 100644 index 0000000..3637513 --- /dev/null +++ b/code/game/impl/aabb.c @@ -0,0 +1,15 @@ +#include "../aabb.h" +#include "../types.h" + +bool AABB_Collide(AABB a, AABB b) { + bool collision_x = a.pos.x + a.size.x >= b.pos.x && b.pos.x + b.size.x >= a.pos.x; + bool collision_y = a.pos.y + a.size.x >= b.pos.y && b.pos.y + b.size.y >= a.pos.y; + return collision_x && collision_y; +} + +bool AABB_Point(AABB a, V2f v) { + bool collision_x = a.pos.x + a.size.x >= v.x && a.pos.x <= v.x; + bool collision_y = a.pos.x + a.size.y >= v.y && a.pos.y <= v.y; + return collision_x && collision_y; +} + From 7a27309c5b8295ee123b50c920a8e82061cdc611 Mon Sep 17 00:00:00 2001 From: Matt Date: Sat, 4 Oct 2025 15:13:31 +0100 Subject: [PATCH 3/5] chore: Update aabb header guard to game rather than core --- code/game/aabb.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/game/aabb.h b/code/game/aabb.h index 060cb53..5f9848a 100644 --- a/code/game/aabb.h +++ b/code/game/aabb.h @@ -1,5 +1,5 @@ -#if !defined(LD_CORE_AABB_H_) -#define LD_CORE_AABB_H_ +#if !defined(LD_GAME_AABB_H_) +#define LD_GAME_AABB_H_ #include "types.h" #include "../core/macros.h" @@ -14,4 +14,4 @@ struct AABB { function bool AABB_Collide(AABB a, AABB b); function bool AABB_Point(AABB a, V2f v); -#endif // LD_CORE_AABB_H_ +#endif // LD_GAME_AABB_H_ From a6266a336b53644520bbec54df71af6eed72a6a0 Mon Sep 17 00:00:00 2001 From: declan Date: Sat, 4 Oct 2025 15:53:55 +0100 Subject: [PATCH 4/5] movey boy --- code/first.c | 93 +++++++++++++++++++++++------------------ code/game/impl/player.c | 22 ++++++++++ code/game/player.h | 11 +++++ 3 files changed, 86 insertions(+), 40 deletions(-) create mode 100644 code/game/impl/player.c create mode 100644 code/game/player.h diff --git a/code/first.c b/code/first.c index 6d714a8..2e7c94d 100644 --- a/code/first.c +++ b/code/first.c @@ -8,17 +8,22 @@ #include "vulkan/core.h" -int main(int argc, char **argv) { - (void) argc; - (void) argv; +#include "game/impl/player.c" - if (!SDL_Init(SDL_INIT_VIDEO)) { +int main(int argc, char **argv) +{ + (void)argc; + (void)argv; + + if (!SDL_Init(SDL_INIT_VIDEO)) + { printf("[Error] :: Failed to initialise SDL3 (%s)\n", SDL_GetError()); return 1; } SDL_Window *window = SDL_CreateWindow("Ludum", 1280, 720, SDL_WINDOW_HIGH_PIXEL_DENSITY); - if (!window) { + if (!window) + { printf("[Error] :: Failed to create window (%s)\n", SDL_GetError()); return 1; } @@ -26,10 +31,19 @@ int main(int argc, char **argv) { Vk_Setup(window); bool running = true; - while (running) { + Player player; + player.pos.x = 0; + player.pos.y = 0; + while (running) + { SDL_Event e; - while (SDL_PollEvent(&e)) { - if (e.type == SDL_EVENT_QUIT) { running = false; } + while (SDL_PollEvent(&e)) + { + PlayerUpdate(&e, &player); + if (e.type == SDL_EVENT_QUIT) + { + running = false; + } } int w, h; @@ -37,25 +51,24 @@ int main(int argc, char **argv) { Vk_Frame *frame = Vk_FrameBegin(window); VkCommandBuffer cmd = frame->cmd; - - VkImageMemoryBarrier2 colour_optimal = { 0 }; - colour_optimal.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2; - colour_optimal.srcStageMask = VK_PIPELINE_STAGE_2_NONE; + VkImageMemoryBarrier2 colour_optimal = {0}; + colour_optimal.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2; + colour_optimal.srcStageMask = VK_PIPELINE_STAGE_2_NONE; colour_optimal.srcAccessMask = VK_ACCESS_2_NONE; - colour_optimal.dstStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; + colour_optimal.dstStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; colour_optimal.dstAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT; - colour_optimal.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - colour_optimal.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - colour_optimal.image = vk.swapchain.images[frame->image]; + colour_optimal.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + colour_optimal.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + colour_optimal.image = vk.swapchain.images[frame->image]; colour_optimal.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; colour_optimal.subresourceRange.layerCount = 1; colour_optimal.subresourceRange.levelCount = 1; - VkDependencyInfo colour_barrier = { 0 }; - colour_barrier.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; + VkDependencyInfo colour_barrier = {0}; + colour_barrier.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; colour_barrier.imageMemoryBarrierCount = 1; - colour_barrier.pImageMemoryBarriers = &colour_optimal; + colour_barrier.pImageMemoryBarriers = &colour_optimal; vk.CmdPipelineBarrier2(cmd, &colour_barrier); @@ -65,43 +78,43 @@ int main(int argc, char **argv) { clear_colour.color.float32[2] = 0.0f; clear_colour.color.float32[3] = 1.0f; - VkRenderingAttachmentInfo colour_attachment = { 0 }; - colour_attachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO; - colour_attachment.imageView = vk.swapchain.views[frame->image]; + VkRenderingAttachmentInfo colour_attachment = {0}; + colour_attachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO; + colour_attachment.imageView = vk.swapchain.views[frame->image]; colour_attachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - colour_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - colour_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - colour_attachment.clearValue = clear_colour; + colour_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + colour_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + colour_attachment.clearValue = clear_colour; - VkRenderingInfo rendering_info = { 0 }; - rendering_info.sType = VK_STRUCTURE_TYPE_RENDERING_INFO; - rendering_info.renderArea = (VkRect2D) { 0, 0, w, h }; - rendering_info.layerCount = 1; + VkRenderingInfo rendering_info = {0}; + rendering_info.sType = VK_STRUCTURE_TYPE_RENDERING_INFO; + rendering_info.renderArea = (VkRect2D){0, 0, w, h}; + rendering_info.layerCount = 1; rendering_info.colorAttachmentCount = 1; - rendering_info.pColorAttachments = &colour_attachment; + rendering_info.pColorAttachments = &colour_attachment; vk.CmdBeginRendering(cmd, &rendering_info); vk.CmdEndRendering(cmd); - VkImageMemoryBarrier2 present_src = { 0 }; - present_src.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2; - present_src.srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; + VkImageMemoryBarrier2 present_src = {0}; + present_src.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2; + present_src.srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; present_src.srcAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT; - present_src.dstStageMask = VK_PIPELINE_STAGE_2_NONE; + present_src.dstStageMask = VK_PIPELINE_STAGE_2_NONE; present_src.dstAccessMask = VK_ACCESS_2_NONE; - present_src.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - present_src.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - present_src.image = vk.swapchain.images[frame->image]; + present_src.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + present_src.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + present_src.image = vk.swapchain.images[frame->image]; present_src.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; present_src.subresourceRange.layerCount = 1; present_src.subresourceRange.levelCount = 1; - VkDependencyInfo to_present = { 0 }; - to_present.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; + VkDependencyInfo to_present = {0}; + to_present.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; to_present.imageMemoryBarrierCount = 1; - to_present.pImageMemoryBarriers = &present_src; + to_present.pImageMemoryBarriers = &present_src; vk.CmdPipelineBarrier2(cmd, &to_present); diff --git a/code/game/impl/player.c b/code/game/impl/player.c new file mode 100644 index 0000000..4c26667 --- /dev/null +++ b/code/game/impl/player.c @@ -0,0 +1,22 @@ +#include "../player.h" + +void PlayerUpdate(SDL_Event *event, Player *player) +{ + SDL_KeyboardEvent key = event->key; + if (key.key == SDLK_W) + { + player->pos.y += 10; + } + if (key.key == SDLK_A) + { + player->pos.x -= 10; + } + if (key.key == SDLK_D) + { + player->pos.x += 10; + } + if (key.key == SDLK_S) + { + player->pos.y -= 10; + } +} diff --git a/code/game/player.h b/code/game/player.h new file mode 100644 index 0000000..b1fb884 --- /dev/null +++ b/code/game/player.h @@ -0,0 +1,11 @@ +#include "core/types.h" +#include +#include "../core/macros.h" + +typedef struct Player Player; +struct Player +{ + V2f pos; +}; + +function void PlayerUpdate(SDL_Event *event, Player *player); \ No newline at end of file From d0d79d05519063e06a0b1c2c7fcfcf7a843a6638 Mon Sep 17 00:00:00 2001 From: Matt Date: Sat, 4 Oct 2025 21:08:52 +0100 Subject: [PATCH 5/5] feat: Added nav and start of npc stuff --- code/.vscode/launch.json | 24 ++++++++++ code/.vscode/tasks.json | 20 ++++++++ code/core/macros.h | 10 ++++ code/game/impl/nav.c | 100 +++++++++++++++++++++++++++++++++++++++ code/game/nav.h | 40 ++++++++++++++++ code/game/npc.h | 10 ++++ code/game/world.h | 10 ++++ 7 files changed, 214 insertions(+) create mode 100644 code/.vscode/launch.json create mode 100644 code/.vscode/tasks.json create mode 100644 code/game/impl/nav.c create mode 100644 code/game/nav.h create mode 100644 code/game/npc.h create mode 100644 code/game/world.h diff --git a/code/.vscode/launch.json b/code/.vscode/launch.json new file mode 100644 index 0000000..407f136 --- /dev/null +++ b/code/.vscode/launch.json @@ -0,0 +1,24 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug 'main.c' Project", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/../build/ldebug", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + "preLaunchTask": "Build" + } + ] +} diff --git a/code/.vscode/tasks.json b/code/.vscode/tasks.json new file mode 100644 index 0000000..b17da5a --- /dev/null +++ b/code/.vscode/tasks.json @@ -0,0 +1,20 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Build", + "type": "shell", + "command": "/home/matt/Repos/ld58/linux", + "group": { + "kind": "build", + "isDefault": true + }, + "presentation": { + "reveal": "never" + }, + "problemMatcher": [ + "$gcc" + ] + } + ] +} diff --git a/code/core/macros.h b/code/core/macros.h index f2d89ff..fed60b8 100644 --- a/code/core/macros.h +++ b/code/core/macros.h @@ -45,4 +45,14 @@ #define thread_var __thread #endif +#define S(x) Str8_Wrap(sizeof(x) - sizeof(*(x)), (U8 *) (x)) +Str8 Str8_Wrap(S64 count, U8 *data) { + Str8 result; + result.data = data; + result.count = count; + + return result; +} +#define Sv(x) (int) (x).count, (x).data + #endif // LD_CORE_MACROS_H_ diff --git a/code/game/impl/nav.c b/code/game/impl/nav.c new file mode 100644 index 0000000..090eb09 --- /dev/null +++ b/code/game/impl/nav.c @@ -0,0 +1,100 @@ +#include "../nav.h" +#include "../../core/types.h" +#include + +#define MAX_UNFINISHED 128 + +typedef struct navSearchNodeState navSearchNodeState; +struct navSearchNodeState{ + bool visited; + U64 distance; + U32 shortest; + bool addedToUnvisited; +}; + +typedef struct navSearchState navSearchState; +struct navSearchState{ + navSearchNodeState nodeStates[NAV_MAX_NODES]; +}; + +navSearchState initState(U32 start, U32 meshSize) { + navSearchState state = {}; + for(int i = 0; i < meshSize; i++) { + state.nodeStates[i].visited = false; + state.nodeStates[i].addedToUnvisited = false; + // underflow to the max :) + state.nodeStates[i].distance = -1; + state.nodeStates[i].shortest = 0; + } + state.nodeStates[start].distance = 0; + return state; +} + +U32 getLowestState(U32 unfinishedIndexes[128], U32 unfinishedCount, navSearchState state, U32 *offset) { + U32 lowest = -1; + U32 lowestI = -1; + bool startFound = false; + for(int i = *offset; i < unfinishedCount; i++) { + navSearchNodeState checkNode = state.nodeStates[unfinishedIndexes[i]]; + if(checkNode.visited) { + if(!startFound) { + *offset = i; + } + continue; + } + startFound = true; + if (lowest > checkNode.distance) { + lowest = checkNode.distance; + lowestI = unfinishedIndexes[i]; + } + } + return lowestI; +} + +// Generate a path to follow between the start and end node. +NavPath Nav_Path(NavMesh mesh, U32 start, U32 end) { + navSearchState state = initState(start, mesh.nodeCount); + U32 unfinishedCount = 1; + U32 unfinishedIndexes[NAV_MAX_NODES] = {start}; + // I don't want to spend time removing items from + // the unfinished nodes, so when checking for a lowest + // if I find the first N items have been checked, I'll mark + // an offset to skip the first N items. + U32 unfinishedOffset = 0; + U32 lowestNodeIndex = start; + bool found = false; + while(!found) { + for(int connectionI = 0 ; connectionI < mesh.nodes[lowestNodeIndex].connectionCount; connectionI++) { + NavConnection connection = mesh.nodes[lowestNodeIndex].connections[connectionI]; + navSearchNodeState *testNode = &state.nodeStates[connection.NodeIndex]; + if(testNode->visited) {continue;} + U32 distance = state.nodeStates[lowestNodeIndex].distance + connection.Cost; + distance += mesh.nodes[end].pos.x - mesh.nodes[connection.NodeIndex].pos.x; + distance += mesh.nodes[end].pos.y - mesh.nodes[connection.NodeIndex].pos.y; + if(testNode->distance > distance) { + testNode->distance = distance; + testNode->shortest = lowestNodeIndex; + } + if(!testNode->addedToUnvisited) { + unfinishedIndexes[unfinishedCount] = connection.NodeIndex; + unfinishedCount++; + testNode->addedToUnvisited = true; + } + } + state.nodeStates[lowestNodeIndex].visited = true; + lowestNodeIndex = getLowestState(unfinishedIndexes, unfinishedCount, state, &unfinishedOffset); + if(lowestNodeIndex == end) { + found = true; + } + } + NavPath res_path = {0}; + U32 index = end; + while(index!=start) { + res_path.indexes[res_path.nodeCount] = index; + res_path.nodeCount++; + index = state.nodeStates[index].shortest; + } + res_path.indexes[res_path.nodeCount] = start; + res_path.nodeCount++; + return res_path; +} diff --git a/code/game/nav.h b/code/game/nav.h new file mode 100644 index 0000000..5820cb6 --- /dev/null +++ b/code/game/nav.h @@ -0,0 +1,40 @@ +#if !defined(LD_GAME_NAV_H_) +#define LD_GAME_NAV_H_ + +#include "../core/types.h" +#include "../core/macros.h" + +#define NAV_MAX_PATH 1024 +#define NAV_MAX_CONNECTIONS 8 +#define NAV_MAX_NODES 4096 + +typedef struct NavNode NavNode; + +typedef struct NavConnection NavConnection; +struct NavConnection{ + F32 Cost; + U32 NodeIndex; +}; + +struct NavNode { + V2f pos; + U8 connectionCount; + NavConnection connections[NAV_MAX_CONNECTIONS]; +}; + +typedef struct NavPath NavPath; +struct NavPath { + U32 nodeCount; + U32 indexes[NAV_MAX_PATH]; +}; + +typedef struct NavMesh NavMesh; +struct NavMesh{ + U32 nodeCount; + NavNode nodes[NAV_MAX_NODES]; +}; + + +function NavPath Nav_Path(NavMesh mesh, U32 start, U32 end); + +#endif diff --git a/code/game/npc.h b/code/game/npc.h new file mode 100644 index 0000000..a50868a --- /dev/null +++ b/code/game/npc.h @@ -0,0 +1,10 @@ +#if !defined(LD_GAME_NPC_H_) +#define LD_GAME_NPC_H_ +#include "aabb.h" + +typedef struct NPC NPC; +struct NPC { + AABB collision; +}; + +#endif // LD_GAME_NPC_H_ diff --git a/code/game/world.h b/code/game/world.h new file mode 100644 index 0000000..cb74ded --- /dev/null +++ b/code/game/world.h @@ -0,0 +1,10 @@ +#if !defined(LD_GAME_WORLD_H_) +#define LD_GAME_WORLD_H_ + +typedef struct World World; +struct World { + NPC[128] npcs; + u32 npcCount; +}; + +#endif // LD_GAME_WORLD_H_