diff --git a/.gitignore b/.gitignore index da450b2..13325ed 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *~ /.cache/ /compile_commands.json +*.c# diff --git a/build.bat b/build.bat index cbae06f..5acacf3 100644 --- a/build.bat +++ b/build.bat @@ -2,5 +2,9 @@ REM cd build && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -GNinja .. && ninja && copy compile_commands.json .. && skunkworks.exe -cd build && meson compile && copy compile_commands.json .. && cd .. && build\gsa.exe +REM cd build && meson compile && copy compile_commands.json .. && cd .. && build\gsa.exe +clang build.c src/str.c -Iinclude -Wno-everything -obuild.exe && build.exe && del build.exe +EXIT /B %ERRORLEVEL% +REM build\skip.exe c src && exit /b 1 +REM build\gsa.exe diff --git a/build.c b/build.c new file mode 100644 index 0000000..2c947fa --- /dev/null +++ b/build.c @@ -0,0 +1,117 @@ +#include "str.h" +#include "types.h" +#include +#include +#include + +void cmake(char *dep, char *libpath, char *lib, char *cmake_dir, char *params); +bool file_exists(char *dir); +void sys(char *cmd); + +int main(int argc, char *argv[]) { + printf("SkunkWorks build system v0.0\n"); + fflush(stdout); + chdir("build"); + sys("if not exist deps md deps"); + // system("cl ../src/*.c /I../include"); + // system("copy ..\\subprojects\\zlib-1.2.13\\zconf.h.in zconf.h"); + + // putenv("CC=clang"); + cmake("glfw-3.3.8", "src\\Release\\glfw3.lib", "glfw3.lib", "", ""); + cmake("zlib-1.2.13", "Release\\zlibstatic.lib", "zlib.lib", "", ""); + cmake( + "lpng1639", + "Release\\libpng16_static.lib", + "png.lib", + "", + "-D ZLIB_INCLUDE_DIR=../../subprojects/zlib-1.2.13 " + "-D ZLIB_LIBRARY=.. " + "-D CMAKE_C_FLAGS=/I\"../zlib-1.2.13\"" + ); + cmake( + "glew-2.1.0", + "lib\\Release\\libglew32.lib", + "glew.lib", + "build/cmake", + "" + ); + + sys("cl /c /MD /O2 /Za " + "../src/*.c " + "/I../include " + "/I../subprojects/glew-2.1.0/include " + "/I../subprojects/glfw-3.3.8/include " + "/I../subprojects/lpng1639 " + "/I../subprojects/zlib-1.2.13 " + "/Ilpng1639 "); + sys("del skunkworks.lib "); + sys("lib " + "*.obj " + "deps/*.lib " + "/OUT:skunkworks.lib"); + sys("cl /MD /O2 " + "../tools/skip.c " + "skunkworks.lib " + "/I../include "); + sys("cl /MD /O2 " + "../examples/gsa_simple.c " + "skunkworks.lib " + "/I../include " + "/I. "); + sys("del *.obj"); + + /* + system("clang " + "-static " + "-Wl,-nodefaultlib:msvcrt " + "../src/*.c " + "-D_CRT_SECURE_NO_WARNINGS " + "-oskunkworks.lib " + "-I../include " + "-I../subprojects/glew-2.1.0/include " + "-I../subprojects/glfw-3.3.8/include " + "-I../subprojects/lpng1639 " + "-I../subprojects/zlib-1.2.13 " + "-Ilpng1639 " + "-L. -lpng -lzlib -lglew -lglfw3 -lopengl32 -luser32 -lkernel32 " + "-lgdi32 -lshell32 " + "-llibcmt -llibvcruntime -llibucrt"); + */ + return 0; +} + +void cmake(char *dep, char *libpath, char *lib, char *cmake_dir, char *params) { + if(file_exists(sw_concat("deps\\", lib))) { + printf("%s already exists, not compiling dependency\n", lib); + return; + } + + printf("compiling %s", lib); + + sys(sw_concat("md ", dep)); + chdir(dep); + sys(sw_concat4( + "cmake ", + params, + // " + //-DCMAKE_MSVC_RUNTIME_LIBRARY=\"MultiThreaded$<$:Debug>" + // "\" " + " ../../subprojects/", + sw_concat3(dep, "/", cmake_dir) + )); + sys("cmake --build . --config Release"); + chdir(".."); + sys(sw_concat4(sw_concat3("copy ", dep, "\\"), libpath, " deps\\", lib)); +} + +bool file_exists(char *dir) { + DWORD attrib = GetFileAttributes(dir); + + return attrib != INVALID_FILE_ATTRIBUTES; +} + +void sys(char *cmd) { + if(system(cmd) != 0) { + exit(-1); + } +} diff --git a/examples/gsa_simple.c b/examples/gsa_simple.c index e850ad3..504da18 100644 --- a/examples/gsa_simple.c +++ b/examples/gsa_simple.c @@ -1,7 +1,9 @@ #include "color32.h" +#include "error.h" #include "gamepad.h" #include "gsa_map.h" #include "gsa_text.h" +#include "skip.h" #include sw_color32 pal[GSA_PALETTE_SIZE]; @@ -16,9 +18,23 @@ void fade_palette(f32 amount) { bool tick_fade_in(); +void test() { + struct sw_skip *skip; + u32 len; + u8 *str; + + skip = sw_skip_load("build/gsa.exe"); + str = sw_skip_get(skip, "test.c", &len); + sw_log("%i", str); + + sw_log("%.*s", len, str); +} + void init() { i32 x, y; + // test(); + gsa_copy_palette_to(pal); for(y = 0; y < 11; ++y) { diff --git a/include/file.h b/include/file.h index 24bbfcc..8416ba7 100644 --- a/include/file.h +++ b/include/file.h @@ -5,9 +5,9 @@ #include struct sw_filebuffer { - u8 *_data; u32 pos; u32 size; + u8 *_data; }; /* TODO: use skunkworks overlay paths */ diff --git a/include/gsa.h b/include/gsa.h index 698910e..4fa29dc 100644 --- a/include/gsa.h +++ b/include/gsa.h @@ -24,6 +24,7 @@ #include "gsa_input.h" #include "gsa_map.h" #include "gsa_text.h" +#include "msvc.h" #include "skunkworks.h" #include "vec2i.h" #include "window.h" diff --git a/include/msvc.h b/include/msvc.h new file mode 100644 index 0000000..a7928bd --- /dev/null +++ b/include/msvc.h @@ -0,0 +1,11 @@ +#ifndef GUARD_61D02F9213AECDE4C71F56E08AEAB638 +#define GUARD_61D02F9213AECDE4C71F56E08AEAB638 + +#ifdef _MSC_VER +#pragma comment(lib, "opengl32.lib") +#pragma comment(lib, "gdi32.lib") +#pragma comment(lib, "user32.lib") +#pragma comment(lib, "shell32.lib") +#endif + +#endif /* GUARD_61D02F9213AECDE4C71F56E08AEAB638 */ diff --git a/include/skip.h b/include/skip.h index 6d6b846..6493d94 100644 --- a/include/skip.h +++ b/include/skip.h @@ -35,6 +35,7 @@ #ifndef GUARD_62F584E45B48B8F6069643FC44702ED5 #define GUARD_62F584E45B48B8F6069643FC44702ED5 +#include "file.h" #include "types.h" struct sw_skip { @@ -52,6 +53,12 @@ struct sw_skip *sw_skip_create(); struct sw_skip *sw_skip_load(char *filename); void sw_skip_destroy(struct sw_skip *skip); +void sw_skip_add(struct sw_skip *skip, u8 *data, u32 data_size, char *name); +void sw_skip_add_file(struct sw_skip *skip, char *name, char *filename); +void sw_skip_attach(struct sw_skip *skip, char *filename); +void sw_skip_dettach(char *filename); +/* returns 0 if file not avaible */ +u8 *sw_skip_get(struct sw_skip *skip, char *name, u32 *out_size); void sw_skip_save(struct sw_skip *skip, char *filename); #endif /* GUARD_62F584E45B48B8F6069643FC44702ED5 */ diff --git a/include/skunkworks.h b/include/skunkworks.h index a104330..ef8bcff 100644 --- a/include/skunkworks.h +++ b/include/skunkworks.h @@ -7,10 +7,14 @@ #include "gamepad.h" #include "image32.h" #include "image8.h" +#include "skip.h" +#include "str.h" #include "types.h" #include "vec2i.h" #include "window.h" +#include "msvc.h" + void sw_init(); #endif /* GUARD_9C1995B9551EFCCDC93F439C46AEF061 */ diff --git a/include/str.h b/include/str.h new file mode 100644 index 0000000..42292e2 --- /dev/null +++ b/include/str.h @@ -0,0 +1,9 @@ +#ifndef GUARD_0941C997CB4D2297C8FEA1374912B5D1 +#define GUARD_0941C997CB4D2297C8FEA1374912B5D1 + +char *sw_concat(char *a, char *b); +char *sw_concat3(char *a, char *b, char *c); +char *sw_concat4(char *a, char *b, char *c, char *d); +char *sw_strdup(char *str); + +#endif /* GUARD_0941C997CB4D2297C8FEA1374912B5D1 */ diff --git a/meson.build b/meson.build index ddb6e23..cbdcd0e 100644 --- a/meson.build +++ b/meson.build @@ -54,13 +54,16 @@ skunk_sources = [ 'src/scaler.c', 'src/shader.c', 'src/shaders.c', + 'src/skip.c', 'src/skunkworks.c', + 'src/str.c', 'src/types.c', 'src/vec2i.c', 'src/window.c' ] xxd = find_program('xxd') +cmd = find_program('cmd') embed_gfx = custom_target('embed-gfx', input: ['gfx.png'], output: ['embed_gfx.h'], command: [xxd, '-i', '@INPUT@', '@OUTPUT@']) @@ -75,6 +78,14 @@ if host_machine.system() == 'emscripten' executable('skunktest', link_with: lib, include_directories: 'include', dependencies: deps, link_args: ['-lglfw', '-lGL', '-s', 'USE_GLFW=3'], name_suffix: 'html') executable('gsa', 'examples/gsa_simple.c', embed_gfx, link_with: lib, include_directories: 'include', dependencies: deps, link_args: ['-lglfw', '-lGL', '-s', 'USE_GLFW=3', '-s', 'ALLOW_MEMORY_GROWTH', '-s', 'FULL_ES3'], name_suffix: 'html') else + skip = executable('skip', 'tools/skip.c', link_with: lib, include_directories: 'include', dependencies: deps) executable('skunktest', 'src/test.c', link_with: lib, include_directories: 'include', dependencies: deps) - executable('gsa', 'examples/gsa_simple.c', embed_gfx, link_with: lib, include_directories: 'include', dependencies: deps) -endif \ No newline at end of file + gsa = executable('gsa', 'examples/gsa_simple.c', embed_gfx, link_with: lib, include_directories: 'include', dependencies: deps) +# custom_target( +# 'gsa skip', +# input: gsa, +# output: 'fake', +# command: ['skip.exe', 'ca1', '..\src', gsa], +# build_by_default: true +# ) +endif diff --git a/src/gl.h b/src/gl.h index 11f8168..9438fdb 100644 --- a/src/gl.h +++ b/src/gl.h @@ -1,7 +1,17 @@ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Weverything" +// #pragma clang diagnostic push +#define GLEW_STATIC + +#ifdef _MSC_VER + +#pragma warning(push) +#pragma warning(disable : 4224) #include -#pragma clang diagnostic pop +#pragma warning(pop) + +#else +#include +#endif + #include #ifdef __EMSCRIPTEN__ diff --git a/src/skip.c b/src/skip.c index cc87fcb..5cd5fa5 100644 --- a/src/skip.c +++ b/src/skip.c @@ -2,6 +2,7 @@ #include "error.h" #include "file.h" +#include "str.h" #include #include #include @@ -22,9 +23,13 @@ struct sw_skip *sw_skip_load(char *filename) { u16 i; char str[257]; u8 str_len; + u32 off; skip = sw_skip_create(); fil = fopen(filename, "rb"); + fseek(fil, -4, SEEK_END); + fread(&off, 4, 1, fil); + fseek(fil, -off, SEEK_END); fread(magic, 1, 4, fil); if(strcmp("SWZP", magic) != 0) { @@ -59,10 +64,15 @@ struct sw_skip *sw_skip_load(char *filename) { strcpy(skip->files[i].name, str); } + skip->data = malloc(skip->data_size); + fread(skip->data, 1, skip->data_size, fil); + fclose(fil); return skip; } +static void sw_skip_save_to(struct sw_skip *skip, FILE *fil); + void sw_skip_destroy(struct sw_skip *skip) { i32 i; @@ -74,22 +84,106 @@ void sw_skip_destroy(struct sw_skip *skip) { free(skip); } -void sw_skip_save(struct sw_skip *skip, char *filename) { +void sw_skip_add(struct sw_skip *skip, u8 *data, u32 data_size, char *name) { + u32 off; + + off = skip->data_size + 1; + + skip->data_size += data_size; + skip->data = realloc(skip->data, skip->data_size); + memcpy(skip->data + off, data, data_size); + + skip->file_count += 1; + skip->files = + realloc(skip->files, sizeof(skip->files[0]) * skip->file_count); + skip->files[skip->file_count - 1].name = sw_strdup(name); + skip->files[skip->file_count - 1].offset = off; + skip->files[skip->file_count - 1].size = data_size; +} + +void sw_skip_add_file(struct sw_skip *skip, char *name, char *filename) { FILE *fil; - u32 size; - u16 i; + u32 len; + u8 *data; - size = 0; - for(i = 0; i < skip->file_count; ++i) { - size += skip->files[i].size; + fil = fopen(filename, "rb"); + fseek(fil, 0, SEEK_END); + len = ftell(fil); + fseek(fil, 0, SEEK_SET); + + data = malloc(len); + fread(data, 1, len, fil); + fclose(fil); + + sw_skip_add(skip, data, len, name); + + free(data); +} + +void sw_skip_attach(struct sw_skip *skip, char *filename) { + FILE *fil; + + fil = fopen(filename, "rb+"); + fseek(fil, 0, SEEK_END); + sw_skip_save_to(skip, fil); +} + +void sw_skip_dettach(char *filename) { + FILE *fil; + char magic[5] = {0}; + u32 off; + u32 len; + u8 *data; + + fil = fopen(filename, "rb"); + fseek(fil, -4, SEEK_END); + fread(&off, 4, 1, fil); + fseek(fil, -off, SEEK_END); + + fread(magic, 1, 4, fil); + sw_log("magic: [%s]", magic); + sw_log("off: %i", off); + if(strcmp("SWZP", magic) == 0) { + sw_log("detaching .skip from %s", filename); + len = ftell(fil) - 4; + fseek(fil, 0, SEEK_SET); + data = malloc(len); + fread(data, 1, len, fil); + fclose(fil); + fil = fopen(filename, "wb"); + fwrite(data, 1, len, fil); } + fclose(fil); +} - fil = fopen(filename, "wb"); +u8 *sw_skip_get(struct sw_skip *skip, char *name, u32 *out_size) { + u32 i; + + for(i = 0; i < skip->file_count; ++i) { + if(strcmp(name, skip->files[i].name) == 0) { + if(out_size) { + *out_size = skip->files[i].size; + } + return skip->data + skip->files[i].offset; + } + } + return 0; +} + +void sw_skip_save(struct sw_skip *skip, char *filename) { + sw_skip_save_to(skip, fopen(filename, "wb")); +} + +static void sw_skip_save_to(struct sw_skip *skip, FILE *fil) { + u16 i; + u32 start; + + start = ftell(fil); sw_fwrite_str_nozero(fil, "SWZP"); sw_fwrite_u8(fil, 0); /* version */ sw_fwrite_u8(fil, 0); /* compression */ - sw_fwrite_u32(fil, size); /* uncompressed size */ - sw_fwrite_u32(fil, size); /* compressed size */ + sw_fwrite_u32(fil, skip->data_size); /* uncompressed size */ + sw_fwrite_u32(fil, skip->data_size); /* compressed size */ sw_fwrite_u16(fil, skip->file_count); /* file count */ for(i = 0; i < skip->file_count; ++i) { @@ -98,7 +192,9 @@ void sw_skip_save(struct sw_skip *skip, char *filename) { sw_fwrite_str_prefix8(fil, skip->files[i].name); /* file name */ } - sw_fwrite_u32(fil, ftell(fil) + 4); /* file length */ + fwrite(skip->data, 1, skip->data_size, fil); + + sw_fwrite_u32(fil, ftell(fil) + 4 - start); /* file length */ fclose(fil); } diff --git a/src/str.c b/src/str.c new file mode 100644 index 0000000..ace3d3f --- /dev/null +++ b/src/str.c @@ -0,0 +1,66 @@ +#include "str.h" +#include "types.h" +#include +#include + +char *sw_concat(char *a, char *b) { + char *str; + u32 len_a, len_b; + + len_a = strlen(a); + len_b = strlen(b); + + str = malloc(len_a + len_b + 1); + memcpy(str, a, len_a); + memcpy(str + len_a, b, len_b); + str[len_a + len_b] = 0; + + return str; +} + +char *sw_concat3(char *a, char *b, char *c) { + char *str; + u32 len_a, len_b, len_c; + + len_a = strlen(a); + len_b = strlen(b); + len_c = strlen(c); + + str = malloc(len_a + len_b + len_c + 1); + memcpy(str, a, len_a); + memcpy(str + len_a, b, len_b); + memcpy(str + len_a + len_b, c, len_c); + str[len_a + len_b + len_c] = 0; + + return str; +} + +char *sw_concat4(char *a, char *b, char *c, char *d) { + char *str; + u32 len_a, len_b, len_c, len_d; + + len_a = strlen(a); + len_b = strlen(b); + len_c = strlen(c); + len_d = strlen(d); + + str = malloc(len_a + len_b + len_c + len_d + 1); + memcpy(str, a, len_a); + memcpy(str + len_a, b, len_b); + memcpy(str + len_a + len_b, c, len_c); + memcpy(str + len_a + len_b + len_c, d, len_d); + str[len_a + len_b + len_c + len_d] = 0; + + return str; +} + +char *sw_strdup(char *str) { + char *out; + u32 len; + + len = strlen(str) + 1; + + out = malloc(len); + memcpy(out, str, len); + return out; +} diff --git a/subprojects/glew-2.1.0/glew.pc b/subprojects/glew-2.1.0/glew.pc new file mode 100644 index 0000000..58b6b24 --- /dev/null +++ b/subprojects/glew-2.1.0/glew.pc @@ -0,0 +1,11 @@ +prefix=C:/Program Files (x86)/glew +exec_prefix=${prefix} +libdir=C:/Program Files (x86)/glew/lib +includedir=${prefix}/include + +Name: glew +Description: The OpenGL Extension Wrangler library +Version: 2.1.0 +Cflags: -I${includedir} +Libs: -L${libdir} -lglew32 +Requires: glu diff --git a/tools/skip.c b/tools/skip.c new file mode 100644 index 0000000..9b612cd --- /dev/null +++ b/tools/skip.c @@ -0,0 +1,161 @@ +#include "skip.h" +#include "skunkworks.h" +#include "str.h" + +#include +#include +#include + +#define _AMD64_ +#define WIN32_LEAN_AND_MEAN +#include +#include +#include + +static const char *usage = "Usage:\n\ +skip x file.skip -- extracts file.skip into a directory called file\n\ +skip c dir -- compresses contents of dir into dir.skip\n"; + +static struct sw_skip *skip; + +void usage_and_exit() { + printf("%s", usage); + exit(0); +} + +bool file_exists(char *dir) { + DWORD attrib = GetFileAttributes(dir); + + return attrib != INVALID_FILE_ATTRIBUTES; +} + +bool is_dir(char *dir) { + DWORD attrib = GetFileAttributes(dir); + + return attrib != INVALID_FILE_ATTRIBUTES && + attrib == FILE_ATTRIBUTE_DIRECTORY; +} + +bool has_skip_ext(char *file) { + i32 len; + + len = strlen(file); + file += len - 5; + + return strcmp(file, ".skip") == 0; +} + +char *remove_skip_ext(char *file) { + char *str; + i32 len; + + len = strlen(file); + + str = malloc(len - 4); + memcpy(str, file, len - 5); + str[len - 5] = 0; + return str; +} + +char *add_skip_ext(char *file) { + char *str; + i32 len; + + len = strlen(file); + + str = malloc(len + 6); + memcpy(str, file, len); + memcpy(str + len, ".skip", 5); + str[len + 5] = 0; + + return str; +} + +void crawl(char *dst, char *part_path) { + WIN32_FIND_DATA data; + HANDLE find; + + if(is_dir(dst)) { + char *dir; + char *path; + char *new_part_path; + + dir = sw_concat(dst, "/*.*"); + find = FindFirstFile(dir, &data); + do { + if(strcmp(data.cFileName, ".") != 0 && + strcmp(data.cFileName, "..") != 0) { + path = sw_concat3(dst, "/", data.cFileName); + if(part_path) { + new_part_path = sw_concat3(part_path, "/", data.cFileName); + } else { + new_part_path = sw_strdup(data.cFileName); + } + crawl(path, new_part_path); + free(path); + free(new_part_path); + } + } while(FindNextFile(find, &data)); + free(dir); + } else { + sw_skip_add_file(skip, part_path, dst); + } +} + +int main(int argc, char *argv[]) { + printf("Skip v0.0\n"); + if(argc < 3) { + usage_and_exit(); + } + + if(strcmp(argv[1], "x") == 0) { + /* TODO: implement */ + sw_error("extracting not yet implemented"); + /* + char *dst; + + dst = remove_skip_ext(argv[2]); + skip = sw_skip_load(argv[2]); + + if(file_exists(dst)) { + sw_error("destination %s already exists", dst); + } + + for(i = 0; i < skip->file_count; ++i) { + } + */ + } else if(strcmp(argv[1], "c") == 0) { + char *filename; + + skip = sw_skip_create(); + if(!is_dir(argv[2])) { + sw_error("argument not a directory"); + } + crawl(argv[2], 0); + filename = sw_concat(argv[2], ".skip"); + sw_skip_save(skip, filename); + printf("%s created\n", filename); + free(filename); + } else if(strcmp(argv[1], "ca") == 0) { + skip = sw_skip_create(); + if(!is_dir(argv[2])) { + sw_error("argument not a directory"); + } + crawl(argv[2], 0); + sw_skip_attach(skip, argv[3]); + printf("skip data attached to %s\n", argv[3]); + } else if(strcmp(argv[1], "ca1") == 0) { + skip = sw_skip_create(); + if(!is_dir(argv[2])) { + sw_error("argument not a directory"); + } + crawl(argv[2], 0); + sw_skip_dettach(argv[3]); + sw_skip_attach(skip, argv[3]); + printf("skip data attached to %s\n", argv[3]); + } else { + usage_and_exit(); + } + + return 0; +}