From b66cf8068ae61da08797e3ee7186818c152698cb Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Sat, 10 Jan 2026 00:55:45 +0900 Subject: [PATCH] add gb_makepak --- engine/CMakeLists.txt | 2 +- engine/include/GearBox/File.h | 19 +++ engine/include/GearBox/Foundation.h | 2 + engine/include/GearBox/Resource.h | 18 +++ engine/include/GearBox/String.h | 17 +++ engine/include/GearBox/TypeDefs.h | 27 +++- engine/resource/{ => shader}/shadow.fs | 0 engine/resource/{ => shader}/shadow.vs | 0 engine/src/core.c | 13 +- engine/src/file.c | 41 ++++++ engine/src/resource.c | 22 ++++ engine/src/stb_ds.c | 2 + engine/src/string.c | 9 ++ engine/tools/CMakeLists.txt | 7 + engine/tools/gb_makepak/main.c | 173 +++++++++++++++++++++++++ engine/tools/gb_makepak/stb_ds.c | 2 + 16 files changed, 349 insertions(+), 5 deletions(-) create mode 100644 engine/include/GearBox/File.h create mode 100644 engine/include/GearBox/Resource.h create mode 100644 engine/include/GearBox/String.h rename engine/resource/{ => shader}/shadow.fs (100%) rename engine/resource/{ => shader}/shadow.vs (100%) create mode 100644 engine/src/resource.c create mode 100644 engine/src/stb_ds.c create mode 100644 engine/src/string.c create mode 100644 engine/tools/gb_makepak/main.c create mode 100644 engine/tools/gb_makepak/stb_ds.c diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index d7dc7b6..9e265c8 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -37,6 +37,6 @@ install( add_subdirectory(tools) install( - FILES resource/shadow.vs resource/shadow.fs + DIRECTORY resource/ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/GearBox ) diff --git a/engine/include/GearBox/File.h b/engine/include/GearBox/File.h new file mode 100644 index 0000000..d04d8e6 --- /dev/null +++ b/engine/include/GearBox/File.h @@ -0,0 +1,19 @@ +#ifndef __GEARBOX_FILE_H__ +#define __GEARBOX_FILE_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +GBDECL GBFile GBFileOpen(GBEngine engine, const char* path); +GBDECL int GBFileRead(GBFile file, void* out, int size); +GBDECL void GBFileClose(GBFile file); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/engine/include/GearBox/Foundation.h b/engine/include/GearBox/Foundation.h index 4595997..6950cb5 100644 --- a/engine/include/GearBox/Foundation.h +++ b/engine/include/GearBox/Foundation.h @@ -11,5 +11,7 @@ #include #include #include +#include +#include #endif diff --git a/engine/include/GearBox/Resource.h b/engine/include/GearBox/Resource.h new file mode 100644 index 0000000..59a4fcf --- /dev/null +++ b/engine/include/GearBox/Resource.h @@ -0,0 +1,18 @@ +#ifndef __GEARBOX_RESOURCE_H__ +#define __GEARBOX_RESOURCE_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +GBDECL GBResource GBResourceOpen(GBEngine engine, const char* path); +GBDECL void GBResourceClose(GBResource resource); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/engine/include/GearBox/String.h b/engine/include/GearBox/String.h new file mode 100644 index 0000000..3ae0026 --- /dev/null +++ b/engine/include/GearBox/String.h @@ -0,0 +1,17 @@ +#ifndef __GEARBOX_STRING_H__ +#define __GEARBOX_STRING_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +GBDECL char* GBStringDuplicate(const char* str); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/engine/include/GearBox/TypeDefs.h b/engine/include/GearBox/TypeDefs.h index e78c72e..1e5c244 100644 --- a/engine/include/GearBox/TypeDefs.h +++ b/engine/include/GearBox/TypeDefs.h @@ -1,16 +1,23 @@ #ifndef __GEARBOX_TYPEDEFS_H__ #define __GEARBOX_TYPEDEFS_H__ +#include + typedef struct _GBVersion GBVersion; typedef struct _GBEngineParam GBEngineParam; +typedef struct _GBResourceKV GBResourceKV; #ifdef _GEARBOX -typedef struct _GBClient* GBClient; -typedef struct _GBServer* GBServer; -typedef struct _GBEngine* GBEngine; +typedef struct _GBClient* GBClient; +typedef struct _GBServer* GBServer; +typedef struct _GBEngine* GBEngine; +typedef struct _GBFile* GBFile; +typedef struct _GBResource* GBResource; #else typedef void* GBClient; typedef void* GBServer; typedef void* GBEngine; +typedef void* GBFile; +typedef void* GBResource; #endif typedef void (*GBGLSwapBufferCallback)(void); @@ -19,6 +26,11 @@ typedef void (*GBTickCallback)(void); typedef long (*GBGetTickCallback)(void); typedef void (*GBSleepCallback)(int ms); +struct _GBResourceKV { + char* key; + GBResource value; +}; + #ifdef _GEARBOX struct _GBClient { GBEngine engine; @@ -32,6 +44,15 @@ struct _GBEngine { GBEngineParam* param; GBClient client; GBServer server; + GBResourceKV* resource; +}; + +struct _GBFile { + FILE* fp; +}; + +struct _GBResource { + GBFile file; }; #endif diff --git a/engine/resource/shadow.fs b/engine/resource/shader/shadow.fs similarity index 100% rename from engine/resource/shadow.fs rename to engine/resource/shader/shadow.fs diff --git a/engine/resource/shadow.vs b/engine/resource/shader/shadow.vs similarity index 100% rename from engine/resource/shadow.vs rename to engine/resource/shader/shadow.vs diff --git a/engine/src/core.c b/engine/src/core.c index 5d56737..06dea59 100644 --- a/engine/src/core.c +++ b/engine/src/core.c @@ -5,6 +5,9 @@ #include #include #include +#include + +#include void GBInit(void) { GBVersion version; @@ -17,7 +20,8 @@ void GBInit(void) { } GBEngine GBEngineCreate(GBEngineParam* param) { - GBEngine engine = malloc(sizeof(*engine)); + GBEngine engine = malloc(sizeof(*engine)); + GBResource resource; memset(engine, 0, sizeof(*engine)); @@ -28,6 +32,11 @@ GBEngine GBEngineCreate(GBEngineParam* param) { param->ready(1024, 768); } + sh_new_strdup(engine->resource); + + resource = GBResourceOpen(engine, "base.pak"); + shput(engine->resource, "base", resource); + if(engine != NULL && param->client && (engine->client = GBClientCreate(engine)) == NULL) { GBLog(GBLogError, "Failed to create client"); @@ -52,6 +61,8 @@ GBEngine GBEngineCreate(GBEngineParam* param) { } void GBEngineDestroy(GBEngine engine) { + shfree(engine->resource); + if(engine->server != NULL) GBServerDestroy(engine->server); if(engine->client != NULL) GBClientDestroy(engine->client); if(engine->param != NULL) free(engine->param); diff --git a/engine/src/file.c b/engine/src/file.c index 6e1edf7..ab264e6 100644 --- a/engine/src/file.c +++ b/engine/src/file.c @@ -1 +1,42 @@ #include + +#include +#include + +GBFile GBFileOpen(GBEngine engine, const char* path) { + GBFile file = malloc(sizeof(*file)); + char* s; + char* nam; + + memset(file, 0, sizeof(*file)); + + GBLog(GBLogInfo, "Opening %s", path); + + s = GBStringDuplicate(path); + if(engine != NULL && ((nam = strstr(s, ":/")) != NULL || (nam = strstr(s, ":\\")) != NULL)) { + nam[0] = 0; + nam[1] = 0; + nam += 2; + + printf("%s\n", nam); + } + free(s); + + if((file->fp = fopen(path, "rb")) != NULL) { + return file; + } + + GBLog(GBLogWarn, "Could not open %s", path); + GBFileClose(file); + return NULL; +} + +int GBFileRead(GBFile file, void* out, int size) { + if(file->fp != NULL) return fread(out, 1, size, file->fp); +} + +void GBFileClose(GBFile file) { + if(file->fp != NULL) fclose(file->fp); + + free(file); +} diff --git a/engine/src/resource.c b/engine/src/resource.c new file mode 100644 index 0000000..05af011 --- /dev/null +++ b/engine/src/resource.c @@ -0,0 +1,22 @@ +#include + +#include + +GBResource GBResourceOpen(GBEngine engine, const char* path) { + GBResource resource = malloc(sizeof(*resource)); + + memset(resource, 0, sizeof(*resource)); + + if((resource->file = GBFileOpen(engine, path)) == NULL) { + GBResourceClose(resource); + return NULL; + } + + return resource; +} + +void GBResourceClose(GBResource resource) { + if(resource->file != NULL) GBFileClose(resource->file); + + free(resource); +} diff --git a/engine/src/stb_ds.c b/engine/src/stb_ds.c new file mode 100644 index 0000000..9df32fd --- /dev/null +++ b/engine/src/stb_ds.c @@ -0,0 +1,2 @@ +#define STB_DS_IMPLEMENTATION +#include "stb_ds.h" diff --git a/engine/src/string.c b/engine/src/string.c new file mode 100644 index 0000000..eee6b26 --- /dev/null +++ b/engine/src/string.c @@ -0,0 +1,9 @@ +#include + +char* GBStringDuplicate(const char* str) { + char* s = malloc(strlen(str) + 1); + + strcpy(s, str); + + return s; +} diff --git a/engine/tools/CMakeLists.txt b/engine/tools/CMakeLists.txt index f324c9d..8dc37a2 100644 --- a/engine/tools/CMakeLists.txt +++ b/engine/tools/CMakeLists.txt @@ -5,6 +5,13 @@ include(GNUInstallDirs) macro(compile_tool name) file(GLOB ${name}_SRC ${name}/*.c) add_executable(${name} ${${name}_SRC}) + install_target(${name}) endmacro() +file(GLOB lz4_SRC ../lz4/*.c) + compile_tool(gb_dumpfont) +compile_tool(gb_makepak) + +target_include_directories(gb_makepak PRIVATE ../lz4) +target_sources(gb_makepak PRIVATE ${lz4_SRC}) diff --git a/engine/tools/gb_makepak/main.c b/engine/tools/gb_makepak/main.c new file mode 100644 index 0000000..39fb2eb --- /dev/null +++ b/engine/tools/gb_makepak/main.c @@ -0,0 +1,173 @@ +#include +#include +#ifdef _WIN32 +#include +#else +#include +#include +#endif +#include + +typedef struct kv { + char* key; + +} kv_t; + +static FILE* out; + +static void scan(const char* path, const char* pre); + +static void pack(const char* fullpath, const char* path) { + int m; + FILE* f = fopen(fullpath, "rb"); + int insz; + int outsz; + unsigned char* input; + unsigned char* output; + + printf("%32s ", path); + fflush(stdout); + + fseek(f, 0, SEEK_END); + insz = ftell(f); + fseek(f, 0, SEEK_SET); + + m = LZ4_compressBound(insz); + + input = malloc(insz); + output = malloc(m); + + fread(input, 1, m, f); + + outsz = LZ4_compress_default(input, output, insz, m); + + if(outsz > 0) { + int sz = outsz; + int i; + char fn[128]; + + memset(fn, 0, 128); + memcpy(fn, path, strlen(path)); + + fwrite(fn, 1, 128, out); + + for(i = 0; i < 4; i++) { + unsigned char n = (sz >> 24) & 0xff; + + fwrite(&n, 1, 1, out); + + sz = sz << 8; + } + + fwrite(output, 1, outsz, out); + + printf("done (%6d -> %6d)\n", insz, outsz); + } else { + printf("failed\n"); + } + + free(input); + free(output); + + fclose(f); +} + +static int is_dir(const char* path) { +#ifdef _WIN32 + DWORD dw; + + if((dw = GetFileAttributes(path)) == INVALID_FILE_ATTRIBUTES && !(dw & FILE_ATTRIBUTE_DIRECTORY)) return 0; + + return 1; +#else + struct stat s; + + if(stat(path, &s) == 0 && S_ISDIR(s.st_mode)) return 1; + + return 0; +#endif +} + +static void found(const char* path, const char* pre, const char* input) { + char* p = malloc(strlen(pre) + strlen(input) + 1 + 1); + char* fp = malloc(strlen(path) + 1 + strlen(input) + 1); + + p[0] = 0; + strcat(p, pre); + strcat(p, input); + + fp[0] = 0; + strcat(fp, path); + strcat(fp, "/"); + strcat(fp, input); + + if(is_dir(fp)) { + strcat(p, "/"); + + scan(fp, p); + } else { + pack(fp, p); + } + + free(fp); + + free(p); +} + +static void scan(const char* path, const char* pre) { +#ifdef _WIN32 + WIN32_FIND_DATA ffd; + HANDLE hFind; + char* w = malloc(strlen(path) + 2 + 1); + + w[0] = 0; + strcat(w, path); + strcat(w, "/*"); + + if((hFind = FindFirstFile(w, &ffd)) == INVALID_HANDLE_VALUE) { + free(w); + return; + } + + do { + if(strcmp(ffd.cFileName, ".") != 0 && strcmp(ffd.cFileName, "..") != 0) { + found(path, pre, ffd.cFileName); + } + } while(FindNextFile(hFind, &ffd) != 0); + FindClose(hFind); +#else + DIR* dir; + if((dir = opendir(path)) != NULL) { + struct dirent* d; + while((d = readdir(dir)) != NULL) { + if(strcmp(d->d_name, "..") != 0 && strcmp(d->d_name, ".") != 0) { + found(path, pre, d->d_name); + } + } + + closedir(dir); + } +#endif +} + +int main(int argc, char** argv) { + unsigned char nul[128]; + + if(argc >= 2) out = fopen(argv[1], "wb"); + if(argc == 2) { + scan(".", ""); + } else if(argc > 2) { + int i; + + for(i = 1; i < argc; i++) scan(argv[i], ""); + } else { + printf("Usage: %s output [input]\n", argv[0]); + + return 1; + } + + memset(nul, 0, 128); + fwrite(nul, 1, 128, out); + + fclose(out); +} diff --git a/engine/tools/gb_makepak/stb_ds.c b/engine/tools/gb_makepak/stb_ds.c new file mode 100644 index 0000000..9df32fd --- /dev/null +++ b/engine/tools/gb_makepak/stb_ds.c @@ -0,0 +1,2 @@ +#define STB_DS_IMPLEMENTATION +#include "stb_ds.h"