From ea81776b1b237f7ac273b6d3a3cdc815f55690a4 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 21 Apr 2025 13:48:51 +0900 Subject: [PATCH] fix xm and add resource --- engine/external/jar/jar_mod.h | 11 +- engine/external/jar/jar_xm.h | 12 +- engine/include/gf_macro.h | 8 ++ engine/include/gf_resource.h | 49 ++++++++ engine/include/gf_type/resource.h | 71 +++++++++++ engine/src/gf_resource.c | 189 ++++++++++++++++++++++++++++++ engine/src/gf_stb_ds.c | 2 + engine/util/pack/pack.c | 111 +++++++++++++++++- engine/util/premake5.lua | 9 +- music/{music.ini => info.ini} | 0 tool/respack.sh | 8 ++ 11 files changed, 459 insertions(+), 11 deletions(-) create mode 100644 engine/include/gf_resource.h create mode 100644 engine/include/gf_type/resource.h create mode 100644 engine/src/gf_resource.c create mode 100644 engine/src/gf_stb_ds.c rename music/{music.ini => info.ini} (100%) create mode 100755 tool/respack.sh diff --git a/engine/external/jar/jar_mod.h b/engine/external/jar/jar_mod.h index fcdffea..90f649f 100644 --- a/engine/external/jar/jar_mod.h +++ b/engine/external/jar/jar_mod.h @@ -1355,15 +1355,18 @@ mulong jar_mod_current_samples(jar_mod_context_t* modctx) { /* Works, however it is very slow, this data should be cached to ensure it is run only once per file */ mulong jar_mod_max_samples(jar_mod_context_t* ctx) { mulong len; - mulong lastcount = ctx->loopcount; + mulong lastcount = ctx->loopcount; + mulong samplenb = ctx->samplenb; + muint tablepos = ctx->tablepos; + muint patternpos = ctx->patternpos; while(ctx->loopcount <= lastcount) jar_mod_fillbuffer(ctx, NULL, 1, 0); len = ctx->samplenb; jar_mod_seek_start(ctx); - ctx->samplenb = 0; - ctx->tablepos = 0; - ctx->patternpos = 0; + ctx->samplenb = samplenb; + ctx->tablepos = tablepos; + ctx->patternpos = patternpos; return len; } diff --git a/engine/external/jar/jar_xm.h b/engine/external/jar/jar_xm.h index 130e362..5f17dbe 100644 --- a/engine/external/jar/jar_xm.h +++ b/engine/external/jar/jar_xm.h @@ -2454,8 +2454,11 @@ void jar_xm_generate_samples(jar_xm_context_t* ctx, float* output, size_t numsam } gf_uint64_t jar_xm_get_remaining_samples(jar_xm_context_t* ctx) { - gf_uint64_t total = 0; - gf_uint8_t currentLoopCount = jar_xm_get_loop_count(ctx); + gf_uint64_t total = 0; + gf_uint8_t currentLoopCount = jar_xm_get_loop_count(ctx); + gf_uint8_t current_tick = ctx->current_tick; + gf_uint8_t current_row = ctx->current_row; + gf_uint8_t current_table_index = ctx->current_table_index; jar_xm_set_max_loop_count(ctx, 0); while(jar_xm_get_loop_count(ctx) == currentLoopCount) { @@ -2464,7 +2467,10 @@ gf_uint64_t jar_xm_get_remaining_samples(jar_xm_context_t* ctx) { jar_xm_tick(ctx); } - ctx->loop_count = currentLoopCount; + ctx->loop_count = currentLoopCount; + ctx->current_tick = current_tick; + ctx->current_row = current_row; + ctx->current_table_index = current_table_index; return total; } diff --git a/engine/include/gf_macro.h b/engine/include/gf_macro.h index 9a80ec0..641001c 100644 --- a/engine/include/gf_macro.h +++ b/engine/include/gf_macro.h @@ -129,6 +129,14 @@ #define GF_EXPOSE_AUDIO #endif +#ifndef GF_EXPOSE_RESOURCE +/** + * @~english + * @brief Expose resource properties + */ +#define GF_EXPOSE_RESOURCE +#endif + #ifndef GF_EXPOSE_GRAPHIC /** * @~english diff --git a/engine/include/gf_resource.h b/engine/include/gf_resource.h new file mode 100644 index 0000000..6ac3198 --- /dev/null +++ b/engine/include/gf_resource.h @@ -0,0 +1,49 @@ +/** + * @file gf_resource.h + * @~english + * @brief Resource + */ + +#ifndef __GF_RESOURCE_H__ +#define __GF_RESOURCE_H__ + +#include +#include + +/* Type */ +#include + +/* Engine */ +#include + +/* Standard */ +#include + +/** + * @~english + * @brief Create resource + * @param engine Engine instance + * @param path Path + * @return Resource + */ +GF_EXPORT gf_resource_t* gf_resource_create(gf_engine_t* engine, const char* path); + +/** + * @~english + * @brief Destroy resource + * @param resource Resource + */ +GF_EXPORT void gf_resource_destroy(gf_resource_t* resource); + +/** + * @~english + * @brief Get data from resource + * @param resource Resource + * @param name Entry name + * @param data Pointer to data result + * @param size Pointer to size result + * @return `0` if successful, otherwise `-1` + */ +GF_EXPORT int gf_resource_get(gf_resource_t* resource, const char* name, void** data, size_t* size); + +#endif diff --git a/engine/include/gf_type/resource.h b/engine/include/gf_type/resource.h new file mode 100644 index 0000000..d339702 --- /dev/null +++ b/engine/include/gf_type/resource.h @@ -0,0 +1,71 @@ +/** + * @file gf_type/resource.h + * @~english + * @brief Type definitions related to resource + */ + +#ifndef __GF_TYPE_RESOURCE_H__ +#define __GF_TYPE_RESOURCE_H__ + +#include +#include + +#ifdef GF_EXPOSE_RESOURCE +typedef struct gf_resource_t gf_resource_t; + +/* External library */ + +/* Engine */ +#include + +/* Standard */ +#include + +/** + * @struct gf_resource_entry_t + * @~english + * @brief Resource entry + * + * @var gf_resource_entry_t::key + * @brief Entry name + * + * @var gf_resource_entry_t::address + * @brief Location in file + * + * @var gf_resource_entry_t::address + * @brief Location in file + * + * @var gf_resource_entry_t::size + * @brief Size + */ +GF_DECLARE_TYPE(resource_entry, { + char* key; + unsigned int address; + unsigned int size; +}); + +/** + * @struct gf_resource_t + * @~english + * @brief Resource + * + * @var gf_resource_t::engine + * @brief Engine instance + * + * @var gf_resource_t::entries + * @brief Resource entries + * + * @var gf_resource_t::data + * @brief Data + */ +GF_DECLARE_TYPE(resource, { + gf_engine_t* engine; + gf_resource_entry_t* entries; + unsigned char* data; +}); +#else +typedef void gf_resource_entry_t; +typedef void gf_resource_t; +#endif + +#endif diff --git a/engine/src/gf_resource.c b/engine/src/gf_resource.c new file mode 100644 index 0000000..608ee3a --- /dev/null +++ b/engine/src/gf_resource.c @@ -0,0 +1,189 @@ +#define GF_EXPOSE_RESOURCE + +#include + +/* External library */ +#include +#include + +/* Interface */ +#include + +/* Engine */ +#include +#include + +/* Standard */ +#include +#include +#include + +#pragma pack(1) + +struct tar_header { + char filename[100]; + char mode[8]; + char uid[8]; + char gid[8]; + char size[12]; + char mtime[12]; + char chksum[8]; + char typeflag[1]; + char linkname[100]; + char ustar[6]; + char ustarv[2]; + char username[32]; + char grpname[32]; + char devmajor[8]; + char devminor[8]; + char prefix[155]; +}; + +#pragma pack() + +unsigned int tar_getsize(const char* input) { + int i; + unsigned int r = 0; + for(i = 0; i < 11; i++) { + r = r << 3; + r = r | (input[i] - '0'); + } + return r; +} + +gf_resource_t* gf_resource_create(gf_engine_t* engine, const char* path) { + struct tar_header* th; + int i; + unsigned int cmpsize = 0; + unsigned int cursize = 0; + unsigned int curseek = 0; + z_stream stream; + int ret; + FILE* f; + gf_resource_t* resource = malloc(sizeof(*resource)); + + memset(resource, 0, sizeof(*resource)); + resource->engine = engine; + resource->entries = NULL; + resource->data = NULL; + sh_new_strdup(resource->entries); + + if(path == NULL) { + gf_log_function(engine, "Created empty resource", ""); + return resource; + } + f = fopen(path, "rb"); + + if(f == NULL) { + gf_log_function(engine, "Failed to create resource", ""); + gf_resource_destroy(resource); + return NULL; + } + + fseek(f, 0, SEEK_END); + cmpsize = ftell(f); + fseek(f, 0, SEEK_SET); + + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.opaque = Z_NULL; + stream.avail_in = 0; + stream.next_in = Z_NULL; + + if(inflateInit(&stream) != Z_OK) { + gf_log_function(engine, "Failed to initialize zlib", ""); + gf_resource_destroy(resource); + return NULL; + } + + gf_log_function(engine, "Created resource", ""); + + do { + unsigned char in[32767]; + unsigned char out[32767]; + stream.avail_in = fread(in, 1, sizeof(in), f); + if(stream.avail_in == 0) break; + stream.next_in = in; + + do { + int have; + stream.avail_out = sizeof(out); + stream.next_out = out; + ret = inflate(&stream, Z_NO_FLUSH); + if(ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) { + inflateEnd(&stream); + gf_log_function(engine, "Failed to decompress", ""); + gf_resource_destroy(resource); + return NULL; + } + have = sizeof(out) - stream.avail_out; + if(resource->data == NULL) { + resource->data = malloc(have); + memcpy(resource->data, out, have); + } else { + unsigned char* old = resource->data; + resource->data = malloc(cursize + have); + memcpy(resource->data, old, cursize); + memcpy(resource->data + cursize, out, have); + free(old); + } + cursize += have; + } while(stream.avail_out == 0); + } while(ret != Z_STREAM_END); + inflateEnd(&stream); + + fclose(f); + + gf_log_function(engine, "Compression made the file size %.2f%%", (double)cmpsize / cursize * 100); + + for(i = 0;; i++) { + unsigned int sz; + gf_resource_entry_t entry; + th = (struct tar_header*)(resource->data + curseek); + if(th->filename[0] == 0) break; + + curseek += 512; + + if(memcmp(th->ustar, "ustar", 6) != 0) { + gf_log_function(engine, "Not USTAR", ""); + gf_resource_destroy(resource); + resource = NULL; + break; + } + + sz = tar_getsize(&th->size[0]); + + gf_log_function(engine, "%s: %u bytes", th->filename, sz); + + entry.key = th->filename; + entry.address = curseek; + entry.size = sz; + shputs(resource->entries, entry); + + if(sz != 0) curseek += ((sz / 512) + 1) * 512; + } + + return resource; +} + +int gf_resource_get(gf_resource_t* resource, const char* name, void** data, size_t* size) { + if(resource->entries != NULL && shgeti(resource->entries, name) != -1) { + gf_resource_entry_t e = shgets(resource->entries, name); + *size = e.size; + *data = malloc(e.size); + memcpy(*data, resource->data + e.address, e.size); + return 0; + } + return -1; +} + +void gf_resource_destroy(gf_resource_t* resource) { + if(resource->entries != NULL) { + shfree(resource->entries); + } + if(resource->data != NULL) { + free(resource->data); + } + gf_log_function(resource->engine, "Destroyed resource", ""); + free(resource); +} diff --git a/engine/src/gf_stb_ds.c b/engine/src/gf_stb_ds.c new file mode 100644 index 0000000..689615c --- /dev/null +++ b/engine/src/gf_stb_ds.c @@ -0,0 +1,2 @@ +#define STB_DS_IMPLEMENTATION +#include diff --git a/engine/util/pack/pack.c b/engine/util/pack/pack.c index 27b20bb..d7ae315 100644 --- a/engine/util/pack/pack.c +++ b/engine/util/pack/pack.c @@ -1,8 +1,117 @@ /* Engine */ +#include +#include /* External library */ /* Standard */ #include +#include +#include +#include +#ifdef _WIN32 +#include +#define gf_stat _stat +#else +#include +#define gf_stat stat +#endif -int main(int argc, char** argv) { return 0; } +char* out = NULL; +char* base = "."; + +int add_all(gf_resource_t* resource, char* path) { +#ifdef _WIN32 +#else + DIR* dir; + struct dirent* d; +#endif + int st = 0; + char* op = malloc(strlen(base) + 1 + strlen(path) + 1); + op[0] = 0; + strcat(op, base); + strcat(op, "/"); + strcat(op, path); + +#ifdef _WIN32 + st = -1; +#else + dir = opendir(op); + if(dir == NULL) { + free(op); + fprintf(stderr, "Could not open directory\n"); + return -1; + } + while((d = readdir(dir)) != NULL) { + if(strcmp(d->d_name, ".") != 0 && strcmp(d->d_name, "..") != 0) { + char* p = malloc(strlen(base) + 1 + strlen(path) + strlen(d->d_name) + 1); + char* np = malloc(strlen(path) + strlen(d->d_name) + 1 + 1); + struct gf_stat s; + p[0] = 0; + strcat(p, base); + strcat(p, "/"); + strcat(p, path); + strcat(p, d->d_name); + + np[0] = 0; + strcat(np, path); + strcat(np, d->d_name); + + printf("%s\n", np); + + gf_stat(p, &s); + + if(S_ISDIR(s.st_mode)) { + strcat(np, "/"); + if((st = add_all(resource, np)) != 0) { + free(np); + break; + } + } else { + } + free(np); + + free(p); + } + } + closedir(dir); +#endif + free(op); + return st; +} + +int main(int argc, char** argv) { + gf_version_t version; + gf_resource_t* resource; + int i; + int st = 0; + + gf_version_get(&version); + printf("GoldFish Engine Resource Packer %s\n", version.full); + for(i = 1; i < argc; i++) { + if(argv[i][0] == '-') { + if(strcmp(argv[i], "-d") == 0) { + base = argv[++i]; + } else { + fprintf(stderr, "Invalid flag: %s\n", argv[i]); + return 1; + } + } else { + out = argv[i]; + } + } + + if(out == NULL || base == NULL) { + fprintf(stderr, "Usage: %s [-d basedir] output\n", argv[0]); + return 1; + } + + resource = gf_resource_create(NULL, NULL); + if(resource != NULL) { + if(add_all(resource, "") != 0) { + st = 1; + } + gf_resource_destroy(resource); + } + return st; +} diff --git a/engine/util/premake5.lua b/engine/util/premake5.lua index bd565fa..c9b9950 100644 --- a/engine/util/premake5.lua +++ b/engine/util/premake5.lua @@ -1,14 +1,18 @@ project("Pack") kind("ConsoleApp") - filter({}) language("C") targetdir("../bin/%{cfg.buildcfg}/%{cfg.platform}") objdir("../obj") targetname("pack") + includedirs({ + "../include" + }) files({ "pack/*.c" }) - -- Call this if you are gonna use my engine... + links({ + "GoldFish" + }) gf_link_stuffs("options:engine=static") filter("system:windows") files({ @@ -56,7 +60,6 @@ project("EngineInfo") links({ "GoldFish" }) - -- Call this if you are gonna use my engine... gf_link_stuffs("options:engine=static") filter("system:windows") files({ diff --git a/music/music.ini b/music/info.ini similarity index 100% rename from music/music.ini rename to music/info.ini diff --git a/tool/respack.sh b/tool/respack.sh new file mode 100755 index 0000000..38fcb40 --- /dev/null +++ b/tool/respack.sh @@ -0,0 +1,8 @@ +#!/bin/sh +old="`pwd`" + +rm -rf /tmp/respack +mkdir -p /tmp/respack +cp -rf music /tmp/respack/music + +exec ./engine/bin/*/*/pack -d /tmp/respack resource.pak