diff --git a/code/core/platform.h b/code/core/platform.h index 5047a9f..b85cd09 100644 --- a/code/core/platform.h +++ b/code/core/platform.h @@ -70,9 +70,14 @@ #include #pragma warning(disable : 4201) #elif OS_LINUX + #include #include #include #include + #include + #include + #include + #include #endif #endif // LD_CORE_PLATFORM_H_ diff --git a/code/first.c b/code/first.c index 549af0b..a9f4382 100644 --- a/code/first.c +++ b/code/first.c @@ -32,6 +32,7 @@ int main(int argc, char **argv) { Vk_Setup(window); G_State *game = 0; + G_Image *img = 0; { M_Arena *arena = M_ArenaAlloc(GB(64), .initial = MB(4)); game = M_ArenaPush(arena, G_State); @@ -41,6 +42,15 @@ int main(int argc, char **argv) { G_ImagesLoad(game); G_PipelinesLoad(game); + for (U32 it = 0; it < game->n_images; ++it) { + if (Str8_Equal(game->images[it].name, S("saloon_ext"), 0)) { + img = &game->images[it]; + break; + } + } + + if (!img) { img = &game->images[0]; } + Vk_Buffer *vbo = &game->vbo; vbo->size = KB(4096); vbo->usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; @@ -126,7 +136,7 @@ int main(int argc, char **argv) { vbo_info.range = 256; VkDescriptorImageInfo image_info = { 0 }; - image_info.imageView = game->images[6].image.view; + image_info.imageView = img->image.view; image_info.sampler = vk.sampler; image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; diff --git a/code/game/core.c b/code/game/core.c index 61840c7..895c14c 100644 --- a/code/game/core.c +++ b/code/game/core.c @@ -1,6 +1,9 @@ void G_ImagesLoad(G_State *game) { M_TempScope(0, 0) { - FS_List assets = FS_PathList(temp.arena, S("assets")); + Str8 exe_path = FS_SystemPath(temp.arena, FS_SYSTEM_PATH_EXE); + Str8 path = Sf(temp.arena, "%.*s/assets", exe_path); + + FS_List assets = FS_PathList(temp.arena, path); Vk_Buffer staging = { 0 }; staging.size = MB(256); @@ -14,21 +17,15 @@ void G_ImagesLoad(G_State *game) { Vk_CommandBuffer *cmds = Vk_CommandBufferPush(); - U32 n_images = 0; - for (FS_Entry *it = assets.first; it != 0; it = it->next) { if (Str8_EndsWith(it->basename, S("png"))) { - if (Str8_Equal(it->basename, S("saloon_ext.png"), 0)) { - printf("IMAGE SALOON == %d\n", n_images); - } - - n_images += 1; + game->n_images += 1; } } VkBufferImageCopy copy = { 0 }; - game->images = M_ArenaPush(game->arena, G_Image, .count = n_images); - n_images = 0; + game->images = M_ArenaPush(game->arena, G_Image, .count = game->n_images); + game->n_images = 0; // Image upload is sbi_load -> copy to staging -> upload to gpu texture @@ -38,7 +35,7 @@ void G_ImagesLoad(G_State *game) { stbi_uc *data = stbi_load((const char *) it->path.data, &w, &h, &c, 4); if (data) { - G_Image *image = &game->images[n_images]; + G_Image *image = &game->images[game->n_images]; U64 image_sz = 4 * w * h; @@ -62,10 +59,12 @@ void G_ImagesLoad(G_State *game) { Assert(offset <= staging.size); - n_images += 1; + game->n_images += 1; image->name = Str8_Copy(game->arena, Str8_RemoveAfterLast(it->basename, '.')); + printf("[Info] :: Loaded %.*s from %.*s\n", Sv(image->name), Sv(it->basename)); + image->image.width = w; image->image.height = h; @@ -133,8 +132,9 @@ void G_PipelinesLoad(G_State *game) { VkShaderModule vshader = 0, fshader = 0; M_TempScope(0, 0) { - Str8 vshader_code = FS_ReadEntireFile(temp.arena, S("assets/shaders/basic.vert.spv")); - Str8 fshader_code = FS_ReadEntireFile(temp.arena, S("assets/shaders/basic.frag.spv")); + Str8 exe_path = FS_SystemPath(temp.arena, FS_SYSTEM_PATH_EXE); + Str8 vshader_code = FS_ReadEntireFile(temp.arena, Sf(temp.arena, "%.*s/assets/shaders/basic.vert.spv", Sv(exe_path))); + Str8 fshader_code = FS_ReadEntireFile(temp.arena, Sf(temp.arena, "%.*s/assets/shaders/basic.frag.spv", Sv(exe_path))); VkShaderModuleCreateInfo create_info = { 0 }; create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; diff --git a/code/os/filesystem.h b/code/os/filesystem.h index 23694f4..ef4f7d9 100644 --- a/code/os/filesystem.h +++ b/code/os/filesystem.h @@ -46,4 +46,14 @@ function FS_List FS_PathList(M_Arena *arena, Str8 path); function Str8 FS_ReadEntireFile(M_Arena *arena, Str8 path); +typedef U32 FS_SystemPathType; +enum { + FS_SYSTEM_PATH_EXE = 0, + FS_SYSTEM_PATH_WORKING, + FS_SYSTEM_PATH_USER, + FS_SYSTEM_PATH_TEMP +}; + +function Str8 FS_SystemPath(M_Arena *arena, FS_SystemPathType path); + #endif // LD_OS_FILESYSTEM_H_ diff --git a/code/os/impl/linux/core.c b/code/os/impl/linux/core.c index 1dd1cd9..79c0af9 100644 --- a/code/os/impl/linux/core.c +++ b/code/os/impl/linux/core.c @@ -28,4 +28,4 @@ void VM_Release(void *base, U64 size) { munmap(base, size); } - +#include "filesystem.c" diff --git a/code/os/impl/linux/filesystem.c b/code/os/impl/linux/filesystem.c new file mode 100644 index 0000000..ef3a9a4 --- /dev/null +++ b/code/os/impl/linux/filesystem.c @@ -0,0 +1,215 @@ +OS_Handle FS_FileOpen(Str8 path, FS_AccessFlags access) { + OS_Handle result = { 0 }; + + M_TempScope(0, 0) { + Str8 zpath = Str8_Copy(temp.arena, path); + + int mode = 0644; + int flags = 0; + if (access & FS_ACCESS_READ) { + if (access & FS_ACCESS_WRITE) { + flags = O_RDWR | O_CREAT; + } + else { + flags = O_RDONLY; + } + } + else if (access & FS_ACCESS_WRITE) { + flags = O_WRONLY | O_CREAT; + } + + + int fd = open((const char *) zpath.data, flags, mode); + result.v[0] = (fd > 0) ? (U64) fd : 0; + } + + return result; +} +void FS_FileClose(OS_Handle file) { + int fd = cast(int) file.v[0]; + if (fd > 0) { + close(fd); + } +} + +void FS_FileRead(OS_Handle file, void *ptr, U64 size, U64 offset) { + int fd = cast(int) file.v[0]; + if (fd > 0) { + U8 *buffer = ptr; + U64 current = offset; + U64 remainder = size; + + while (remainder != 0) { + S64 nread = pread(fd, buffer, remainder, current); + if (nread <= 0) { + break; + } + + buffer += nread; + current += nread; + remainder -= nread; + } + } +} + +void FS_FileWrite(OS_Handle file, void *ptr, U64 size, U64 offset) { + int fd = cast(int) file.v[0]; + if (fd > 0) { + U8 *buffer = ptr; + U64 current = offset; + U64 remainder = size; + + while (remainder != 0) { + S64 nwritten = pwrite(fd, buffer, remainder, current); + if (nwritten <= 0) { + break; + } + + buffer += nwritten; + current += nwritten; + remainder -= nwritten; + } + } +} + +U64 FS_FileSize(OS_Handle file) { + U64 result = 0; + + int fd = cast(int) file.v[0]; + if (fd > 0) { + struct stat sb; + fstat(fd, &sb); + + result = sb.st_size; + } + + return result; +} + +FS_List FS_PathList(M_Arena *arena, Str8 path) { + FS_List result = { 0 }; + + M_TempScope(1, &arena) { + Str8 zpath = Str8_Copy(temp.arena, path); + + DIR *dir = opendir((const char *) zpath.data); + + struct dirent *ent = readdir(dir); + while (ent != 0) { + if (ent->d_name[0] != '.') { + FS_Entry *entry = M_ArenaPush(arena, FS_Entry); + + entry->basename = Str8_Copy(arena, Sz(ent->d_name)); + entry->path = Sf(arena, "%.*s/%.*s", Sv(path), Sv(entry->basename)); + + struct stat sb; + stat((const char *) entry->path.data, &sb); + + entry->type = ((sb.st_mode & S_IFMT) == S_IFDIR) ? FS_ENTRY_TYPE_DIR : FS_ENTRY_TYPE_FILE; + entry->time = (sb.st_mtim.tv_sec * 1e9) + sb.st_mtim.tv_nsec; + entry->size = sb.st_size; + + SLL_Enqueue(result.first, result.last, entry); + result.count += 1; + } + + ent = readdir(dir); + } + } + + return result; +} + +Str8 FS_SystemPath(M_Arena *arena, FS_SystemPathType path) { + Str8 result = { 0 }; + + switch (path) { + case FS_SYSTEM_PATH_EXE: { + U64 offset = M_ArenaOffset(arena); + + Str8 buffer; + buffer.count = KB(1); + buffer.data = M_ArenaPush(arena, U8, .count = buffer.count); + + ssize_t nwritten = 0; + for (;;) { + nwritten = readlink("/proc/self/exe", cast(char *) buffer.data, buffer.count); + if (nwritten < buffer.count) { + break; + } + + M_ArenaPop(arena, offset); + + buffer.count *= 2; + buffer.data = M_ArenaPush(arena, U8, .count = buffer.count); + } + + if (nwritten > 0) { + // Walk back until the prevous slash, then null-terminate there + while (buffer.data[nwritten] != '/') { nwritten -= 1; } + buffer.data[nwritten] = 0; + + M_ArenaPopSize(arena, buffer.count - nwritten - 1); + + result.count = nwritten; + result.data = buffer.data; + } + else { + M_ArenaPop(arena, offset); + } + } + break; + + case FS_SYSTEM_PATH_WORKING: { + U64 offset = M_ArenaOffset(arena); + + Str8 buffer; + buffer.count = KB(1); + buffer.data = M_ArenaPush(arena, U8, .count = buffer.count); + + char *wd; + + for (;;) { + wd = getcwd((char *) buffer.data, buffer.count); + if (wd != 0) { + break; + } + else if (errno != ERANGE) { + break; + } + + M_ArenaPop(arena, offset); + + buffer.count *= 2; + buffer.data = M_ArenaPush(arena, U8, .count = buffer.count); + } + + if (wd) { + result = Sz(wd); + M_ArenaPopSize(arena, buffer.count - result.count - 1); + } + } + break; + + case FS_SYSTEM_PATH_USER: { + char *home = getenv("HOME"); + if (home) { + result = Sf(arena, "%s/.local/share", home); + } + } + break; + + case FS_SYSTEM_PATH_TEMP: { + char *temp = getenv("TEMP"); + if (temp) { + result = Str8_Copy(arena, Sz(temp)); + } + else { + result = Str8_Copy(arena, S("/tmp")); + } + } + break; + } + + return result; +} diff --git a/linux b/linux index 2930c89..e259fee 100755 --- a/linux +++ b/linux @@ -12,6 +12,7 @@ pushd "build" > /dev/null release=0 deps=0 +assets=0 for a in $* do @@ -23,6 +24,11 @@ then deps=1 fi +if [[ ! -d "assets" ]] +then + assets=1 +fi + if [[ $deps == 1 ]] then # We don't build SDL3 like on windows, this assumes you have it installed instead. We can't @@ -35,10 +41,24 @@ then cp ../thirdparty/stb/*.h deps/stb fi +if [[ $assets == 1 ]] +then + echo "[Copying assets]" + + cp -r "../assets" . +fi + +echo "[Building shaders]" + +[[ ! -d "assets/shaders" ]] && mkdir "assets/shaders" + +glslangValidator -o "assets/shaders/basic.vert.spv" --target-env "vulkan1.3" "../code/vulkan/shaders/basic.vert" +glslangValidator -o "assets/shaders/basic.frag.spv" --target-env "vulkan1.3" "../code/vulkan/shaders/basic.frag" + echo "[Building source]" -COMPILER_OPTS="-Wall -Wno-missing-braces -Wno-unused-function -I'deps/stb'" -LINKER_OPTS="-lSDL3" +COMPILER_OPTS="-Wall -Wno-missing-braces -Wno-unused-function -Ideps/stb -I../code" +LINKER_OPTS="-lSDL3 -lm" if [[ $release == 1 ]] then