Added filesystem stuff on Linux
More includes for Linux Update build script to copy assets and compile shaders Added base code directory as include path Added FS_SystemPath Made asset loading work directory agnostic
This commit is contained in:
@@ -70,9 +70,14 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#pragma warning(disable : 4201)
|
#pragma warning(disable : 4201)
|
||||||
#elif OS_LINUX
|
#elif OS_LINUX
|
||||||
|
#include <sys/types.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <dirent.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // LD_CORE_PLATFORM_H_
|
#endif // LD_CORE_PLATFORM_H_
|
||||||
|
|||||||
12
code/first.c
12
code/first.c
@@ -32,6 +32,7 @@ int main(int argc, char **argv) {
|
|||||||
Vk_Setup(window);
|
Vk_Setup(window);
|
||||||
|
|
||||||
G_State *game = 0;
|
G_State *game = 0;
|
||||||
|
G_Image *img = 0;
|
||||||
{
|
{
|
||||||
M_Arena *arena = M_ArenaAlloc(GB(64), .initial = MB(4));
|
M_Arena *arena = M_ArenaAlloc(GB(64), .initial = MB(4));
|
||||||
game = M_ArenaPush(arena, G_State);
|
game = M_ArenaPush(arena, G_State);
|
||||||
@@ -41,6 +42,15 @@ int main(int argc, char **argv) {
|
|||||||
G_ImagesLoad(game);
|
G_ImagesLoad(game);
|
||||||
G_PipelinesLoad(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;
|
Vk_Buffer *vbo = &game->vbo;
|
||||||
vbo->size = KB(4096);
|
vbo->size = KB(4096);
|
||||||
vbo->usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
vbo->usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
||||||
@@ -126,7 +136,7 @@ int main(int argc, char **argv) {
|
|||||||
vbo_info.range = 256;
|
vbo_info.range = 256;
|
||||||
|
|
||||||
VkDescriptorImageInfo image_info = { 0 };
|
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.sampler = vk.sampler;
|
||||||
image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
void G_ImagesLoad(G_State *game) {
|
void G_ImagesLoad(G_State *game) {
|
||||||
M_TempScope(0, 0) {
|
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 };
|
Vk_Buffer staging = { 0 };
|
||||||
staging.size = MB(256);
|
staging.size = MB(256);
|
||||||
@@ -14,21 +17,15 @@ void G_ImagesLoad(G_State *game) {
|
|||||||
|
|
||||||
Vk_CommandBuffer *cmds = Vk_CommandBufferPush();
|
Vk_CommandBuffer *cmds = Vk_CommandBufferPush();
|
||||||
|
|
||||||
U32 n_images = 0;
|
|
||||||
|
|
||||||
for (FS_Entry *it = assets.first; it != 0; it = it->next) {
|
for (FS_Entry *it = assets.first; it != 0; it = it->next) {
|
||||||
if (Str8_EndsWith(it->basename, S("png"))) {
|
if (Str8_EndsWith(it->basename, S("png"))) {
|
||||||
if (Str8_Equal(it->basename, S("saloon_ext.png"), 0)) {
|
game->n_images += 1;
|
||||||
printf("IMAGE SALOON == %d\n", n_images);
|
|
||||||
}
|
|
||||||
|
|
||||||
n_images += 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VkBufferImageCopy copy = { 0 };
|
VkBufferImageCopy copy = { 0 };
|
||||||
game->images = M_ArenaPush(game->arena, G_Image, .count = n_images);
|
game->images = M_ArenaPush(game->arena, G_Image, .count = game->n_images);
|
||||||
n_images = 0;
|
game->n_images = 0;
|
||||||
|
|
||||||
// Image upload is sbi_load -> copy to staging -> upload to gpu texture
|
// 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);
|
stbi_uc *data = stbi_load((const char *) it->path.data, &w, &h, &c, 4);
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
G_Image *image = &game->images[n_images];
|
G_Image *image = &game->images[game->n_images];
|
||||||
|
|
||||||
U64 image_sz = 4 * w * h;
|
U64 image_sz = 4 * w * h;
|
||||||
|
|
||||||
@@ -62,10 +59,12 @@ void G_ImagesLoad(G_State *game) {
|
|||||||
|
|
||||||
Assert(offset <= staging.size);
|
Assert(offset <= staging.size);
|
||||||
|
|
||||||
n_images += 1;
|
game->n_images += 1;
|
||||||
|
|
||||||
image->name = Str8_Copy(game->arena, Str8_RemoveAfterLast(it->basename, '.'));
|
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.width = w;
|
||||||
image->image.height = h;
|
image->image.height = h;
|
||||||
|
|
||||||
@@ -133,8 +132,9 @@ void G_PipelinesLoad(G_State *game) {
|
|||||||
|
|
||||||
VkShaderModule vshader = 0, fshader = 0;
|
VkShaderModule vshader = 0, fshader = 0;
|
||||||
M_TempScope(0, 0) {
|
M_TempScope(0, 0) {
|
||||||
Str8 vshader_code = FS_ReadEntireFile(temp.arena, S("assets/shaders/basic.vert.spv"));
|
Str8 exe_path = FS_SystemPath(temp.arena, FS_SYSTEM_PATH_EXE);
|
||||||
Str8 fshader_code = FS_ReadEntireFile(temp.arena, S("assets/shaders/basic.frag.spv"));
|
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 };
|
VkShaderModuleCreateInfo create_info = { 0 };
|
||||||
create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||||
|
|||||||
@@ -46,4 +46,14 @@ function FS_List FS_PathList(M_Arena *arena, Str8 path);
|
|||||||
|
|
||||||
function Str8 FS_ReadEntireFile(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_
|
#endif // LD_OS_FILESYSTEM_H_
|
||||||
|
|||||||
@@ -28,4 +28,4 @@ void VM_Release(void *base, U64 size) {
|
|||||||
munmap(base, size);
|
munmap(base, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "filesystem.c"
|
||||||
|
|||||||
215
code/os/impl/linux/filesystem.c
Normal file
215
code/os/impl/linux/filesystem.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
24
linux
24
linux
@@ -12,6 +12,7 @@ pushd "build" > /dev/null
|
|||||||
|
|
||||||
release=0
|
release=0
|
||||||
deps=0
|
deps=0
|
||||||
|
assets=0
|
||||||
|
|
||||||
for a in $*
|
for a in $*
|
||||||
do
|
do
|
||||||
@@ -23,6 +24,11 @@ then
|
|||||||
deps=1
|
deps=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ ! -d "assets" ]]
|
||||||
|
then
|
||||||
|
assets=1
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ $deps == 1 ]]
|
if [[ $deps == 1 ]]
|
||||||
then
|
then
|
||||||
# We don't build SDL3 like on windows, this assumes you have it installed instead. We can't
|
# 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
|
cp ../thirdparty/stb/*.h deps/stb
|
||||||
fi
|
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]"
|
echo "[Building source]"
|
||||||
|
|
||||||
COMPILER_OPTS="-Wall -Wno-missing-braces -Wno-unused-function -I'deps/stb'"
|
COMPILER_OPTS="-Wall -Wno-missing-braces -Wno-unused-function -Ideps/stb -I../code"
|
||||||
LINKER_OPTS="-lSDL3"
|
LINKER_OPTS="-lSDL3 -lm"
|
||||||
|
|
||||||
if [[ $release == 1 ]]
|
if [[ $release == 1 ]]
|
||||||
then
|
then
|
||||||
|
|||||||
Reference in New Issue
Block a user