diff --git a/engine/v4k.c b/engine/v4k.c index 2879831..7b3f039 100644 --- a/engine/v4k.c +++ b/engine/v4k.c @@ -20146,6 +20146,27 @@ bool model_load_textures(iqm_t *q, const struct iqmheader *hdr, model_t *model) for(int i = 0; i < (int)hdr->num_meshes; i++) { struct iqmmesh *m = &meshes[i]; + // reuse texture+material if already decoded + bool reused = 0; + for( int j = 0; !reused && j < model->num_textures; ++j ) { + if( !strcmpi(model->texture_names[j], &str[m->material])) { + + *out++ = model->materials[j].layer[0].texture; + + { + model->num_textures++; + array_push(model->texture_names, STRDUP(&str[m->material])); + + array_push(model->materials, model->materials[j]); + array_back(model->materials)->name = STRDUP(&str[m->material]); + } + + reused = true; + } + } + if( reused ) continue; + + // decode texture+material int flags = TEXTURE_MIPMAPS|TEXTURE_REPEAT; // LINEAR, NEAREST int invalid = texture_checker().id; @@ -20157,7 +20178,7 @@ bool model_load_textures(iqm_t *q, const struct iqmheader *hdr, model_t *model) array(char) embedded_texture = base64_decode(material_embedded_texture, strlen(material_embedded_texture)); //printf("%s %d\n", material_embedded_texture, array_count(embedded_texture)); //hexdump(embedded_texture, array_count(embedded_texture)); - *out = texture_compressed_from_mem( embedded_texture, array_count(embedded_texture), 0 ).id; + *out = texture_compressed_from_mem( embedded_texture, array_count(embedded_texture), flags ).id; array_free(embedded_texture); } @@ -20210,6 +20231,7 @@ bool model_load_textures(iqm_t *q, const struct iqmheader *hdr, model_t *model) *out = texture_checker().id; // placeholder } + inscribe_tex:; { model->num_textures++; array_push(model->texture_names, STRDUP(&str[m->material])); @@ -20277,7 +20299,7 @@ model_t model_from_mem(const void *mem, int len, int flags) { // if( shaderprog < 0 ) { const char *symbols[] = { "{{include-shadowmap}}", vfs_read("shaders/fs_0_0_shadowmap_lit.glsl") }; // #define RIM int shaderprog = shader(strlerp(1,symbols,vfs_read("shaders/vs_323444143_16_3322_model.glsl")), strlerp(1,symbols,vfs_read("shaders/fs_32_4_model.glsl")), //fs, - "att_position,att_texcoord,att_normal,att_tangent,att_instanced_matrix,,,,att_indexes,att_weights,att_vertexindex,att_color,att_texcoord2,att_bitangent","fragColor", + "att_position,att_texcoord,att_normal,att_tangent,att_instanced_matrix,,,,att_indexes,att_weights,att_vertexindex,att_color,att_bitangent,att_texcoord2","fragColor", va("SHADING_PHONG,%s", (flags&MODEL_RIMLIGHT)?"RIM":"")); // } // ASSERT(shaderprog > 0); @@ -20686,7 +20708,7 @@ lightmap_t lightmap(int hmsize, float cnear, float cfar, vec3 color, int passes, const char *symbols[] = { "{{include-shadowmap}}", vfs_read("shaders/fs_0_0_shadowmap_lit.glsl") }; // #define RIM lm.shader = shader(strlerp(1,symbols,vfs_read("shaders/vs_323444143_16_3322_model.glsl")), strlerp(1,symbols,vfs_read("shaders/fs_32_4_model.glsl")), //fs, - "att_position,att_texcoord,att_normal,att_tangent,att_instanced_matrix,,,,att_indexes,att_weights,att_vertexindex,att_color,att_texcoord2,att_bitangent","fragColor", + "att_position,att_texcoord,att_normal,att_tangent,att_instanced_matrix,,,,att_indexes,att_weights,att_vertexindex,att_color,att_bitangent,att_texcoord2","fragColor", va("%s", "LIGHTMAP_BAKING")); return lm; @@ -20720,6 +20742,10 @@ void lightmap_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm texture_destroy(&m->lightmap); } m->lightmap = texture_create(w, h, 4, 0, TEXTURE_LINEAR|TEXTURE_FLOAT); + glBindTexture(GL_TEXTURE_2D, m->lightmap.id); + unsigned char emissive[] = { 0, 0, 0, 255 }; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, emissive); + glBindTexture(GL_TEXTURE_2D, 0); } for (int b = 0; b < bounces; b++) { @@ -28758,42 +28784,6 @@ vec3 editor_pick(float mouse_x, float mouse_y) { #endif } -#if 0 -int editor_ui_bits8(const char *label, uint8_t *enabled) { // @to deprecate - int clicked = 0; - uint8_t copy = *enabled; - - // @fixme: better way to retrieve widget width? nk_layout_row_dynamic() seems excessive - nk_layout_row_dynamic(ui_ctx, 1, 1); - struct nk_rect bounds = nk_widget_bounds(ui_ctx); - - // actual widget: label + 8 checkboxes - enum { HEIGHT = 18, BITS = 8, SPAN = 118 }; // bits widget below needs at least 118px wide - nk_layout_row_begin(ui_ctx, NK_STATIC, HEIGHT, 1+BITS); - - int offset = bounds.w > SPAN ? bounds.w - SPAN : 0; - nk_layout_row_push(ui_ctx, offset); - if( ui_label_(label, NK_TEXT_LEFT) ) clicked = 1<<31; - - for( int i = 0; i < BITS; ++i ) { - nk_layout_row_push(ui_ctx, 10); - // bit - int val = (*enabled >> i) & 1; - int chg = nk_checkbox_label(ui_ctx, "", &val); - *enabled = (*enabled & ~(1 << i)) | ((!!val) << i); - // tooltip - struct nk_rect bb = { offset + 10 + i * 14, bounds.y, 14, HEIGHT }; // 10:padding,14:width - if (nk_input_is_mouse_hovering_rect(&ui_ctx->input, bb) && !ui_popups()) { - const char *tips[BITS] = {"Init","Tick","Draw","Quit","","","",""}; - if(tips[i][0]) nk_tooltipf(ui_ctx, "%s", tips[i]); - } - } - - nk_layout_row_end(ui_ctx); - return clicked | (copy ^ *enabled); -} -#endif - typedef union engine_var { int i; diff --git a/tools/MAKE_assimp.bat b/tools/MAKE_assimp.bat index 4d74cab..0965c24 100644 --- a/tools/MAKE_assimp.bat +++ b/tools/MAKE_assimp.bat @@ -14,8 +14,11 @@ cp bin/libassimp.dylib ../libassimp.5.dylib cp bin/libassimp.dylib ../libassimp.5.0.1.dylib cd .. -cc ass2iqe.c -o ass2iqe.linux -O2 -I assimp/include/ libassimp.so -lm -cc ass2iqe.c -o ass2iqe.osx -O2 -I assimp/include/ libassimp.dylib -lm +cc ass2iqe.c -o ass2iqe.linux -O2 -I. -I ../engine/split -I assimp/include/ libassimp.so -lm +cc ass2iqe.c -o ass2iqe.osx -O2 -I. -I ../engine/split -I assimp/include/ libassimp.dylib -lm + +cc iqe2iqm.c -o iqe2iqm.linux -O2 -I. -I ../engine/split -lm +cc iqe2iqm.c -o iqe2iqm.osx -O2 -I. -I ../engine/split -lm exit @@ -24,12 +27,19 @@ exit @echo off cd "%~dp0" +if not exist assimp-vc14?-mt.lib ( +if not exist "fart.exe" echo fart tool required && exit /b + git clone https://github.com/assimp/assimp && md assimp\.build && pushd assimp\.build && git checkout 05115b07 cmake .. -DCMAKE_BUILD_TYPE=Release && (make || msbuild assimp.sln -m -p:Configuration=Release) popd -xcopy /y assimp\.build\bin\release\*.dll -xcopy /y assimp\.build\lib\release\*.lib +xcopy /y assimp\.build\bin\release\*.dll +xcopy /y assimp\.build\lib\release\*.lib copy /y assimp\include\assimp\config.h.in assimp\config.h && fart -- assimp\config.h "cmakedefine" "//#define" -cl ass2iqe.c -I . -I assimp\include assimp-vc14?-mt.lib /O2 /Oy /MT /DNDEBUG +) + +cl ass2iqe.c -I. -I ..\engine\split -I assimp\include assimp-vc14?-mt.lib /O2 /Oy /MT /DNDEBUG + +cl iqe2iqm.cpp /O2 /Oy /MT /DNDEBUG diff --git a/tools/MAKE_glslcc.bat b/tools/MAKE_glslcc.bat index 638f758..3b82d65 100644 --- a/tools/MAKE_glslcc.bat +++ b/tools/MAKE_glslcc.bat @@ -17,8 +17,20 @@ exit @echo off cd "%~dp0" -git clone https://github.com/septag/glslcc && md glslcc\.build && pushd glslcc\.build -cmake .. -B . -DCMAKE_BUILD_TYPE=Release && (make || msbuild glslcc.sln -m -p:Configuration=Release) -popd +if not exist glslcc ( +git clone https://github.com/septag/glslcc +) -xcopy /y glslcc\.build\src\Release\glslcc.exe \ No newline at end of file +if "%1"=="debug" ( + if not exist glslcc\.debug md glslcc\.debug + pushd glslcc\.debug + cmake .. -B . && (make || msbuild glslcc.sln) + popd + xcopy /y glslcc\.debug\src\Debug\glslcc.exe +) else ( + if not exist glslcc\.build md glslcc\.build + pushd glslcc\.build + cmake .. -B . -DCMAKE_BUILD_TYPE=Release && (make || msbuild glslcc.sln -m -p:Configuration=Release) + popd + xcopy /y glslcc\.build\src\Release\glslcc.exe +) diff --git a/tools/ase2ini.c b/tools/ase2ini.c index a36460f..fc760e4 100644 --- a/tools/ase2ini.c +++ b/tools/ase2ini.c @@ -231,7 +231,8 @@ int main(int argc, char* argv[]) { return error ? fprintf(stderr, "%s\n", error), -1 : 0; } -// cl ase2ini.c -I ..\engine\split /DNDEBUG /O2 /Ox /MT -// cl ase2ini.c -I ..\engine\split /DNDEBUG /O2 /Ox /MT /LD // tcc ase2ini.c -I ..\engine\split -DNDEBUG +// cl ase2ini.c -I ..\engine\split /DNDEBUG /O2 /Ox /MT /LD +// cl ase2ini.c -I ..\engine\split /DNDEBUG /O2 /Ox /MT // cc ase2ini.c -I ../engine/split -lm -O3 -oase2ini.linux +// cc ase2ini.c -I ../engine/split -lm -O3 -oase2ini.osx diff --git a/tools/ase2ini.exe b/tools/ase2ini.exe index 85a2051..0cc5213 100644 Binary files a/tools/ase2ini.exe and b/tools/ase2ini.exe differ diff --git a/tools/ass2iqe.c b/tools/ass2iqe.c index d9e87bf..7f1dbf0 100644 --- a/tools/ass2iqe.c +++ b/tools/ass2iqe.c @@ -16,8 +16,12 @@ #define FREE free #define MALLOC malloc #include "3rd_base64.h" -#define STB_IMAGE_IMPLEMENTATION -#include "3rd_stb_image.h" +// +#ifdef _MSC_VER +#define strcmpi _stricmp +#else +#define strcmpi strcasecmp +#endif int verbose = 0; int need_to_bake_skin = 0; @@ -37,6 +41,9 @@ int doaxis = 0; // flip bone axis from X to Y to match blender int dounscale = 0; // remove scaling from bind pose int dohips = 0; // reparent thighs to pelvis (see zo_hom_marche) +char *output = NULL; // output filename +char *input = NULL; // input filename + char *only_one_node = NULL; int list_all_meshes = 0; int list_all_positions = 0; @@ -1085,57 +1092,48 @@ void export_node(FILE *out, const struct aiScene *scene, const struct aiNode *no // look for embedded textures. referenced like *1, *2, *3... where N is texture ID // note: mHeight can be zero, in this case texture->pcData is not RGB values but - // compressed JPEG/PNG/etc. data. Using stb_image to decode such image in that case. + // compressed JPEG/PNG/etc. data. Could use stb_image to decode such image in that case. - if( !strchr(buffer, '*') ) { - for( int j = 0; j < scene->mNumTextures; ++j ) { - struct aiTexture *tex = scene->mTextures[j]; - if( strstr(tex->mFilename.data, buffer + !isalpha(buffer[0])) ) { - snprintf(buffer, sizeof(buffer-1), "*%d", j); - break; + unsigned tex_id = ~0u; + + if( buffer[0] ) { + if( strchr(buffer, '*') ) { + tex_id = atoi(buffer+1); + } else { + const char *fname = buffer + (buffer[0] == '+'); + + for( int j = 0; j < scene->mNumTextures; ++j ) { + struct aiTexture *tex = scene->mTextures[j]; + + const char *basename = tex->mFilename.data; + if( strrchr(basename, '/') ) basename = strrchr(basename, '/')+1; + if( strrchr(basename,'\\') ) basename = strrchr(basename,'\\')+1; + + if( !strcmpi(basename, fname) ) { + tex_id = j; + break; + } } } } - if( strchr(buffer, '*') ) { - int tex_id = atoi(buffer+1); - if( tex_id < scene->mNumTextures ) { - struct aiTexture *tex = scene->mTextures[tex_id]; - struct aiTexel *data = tex->pcData; - const char *hint = tex->achFormatHint; // "rgba8888" or "png" - unsigned w = tex->mWidth + !tex->mWidth; - unsigned h = tex->mHeight + !tex->mHeight; + if( tex_id < scene->mNumTextures ) { + struct aiTexture *tex = scene->mTextures[tex_id]; + const char *hint = tex->achFormatHint; // "rgba8888" or "png", "bmp", etc. -// stbi_uc *decoded = 0; - if( !tex->mHeight ) - { - int len = (int)w; - embedded = base64_encode(data, len); // leak -// int x = 0, y = 0, n = 0; -// decoded = stbi_load_from_memory((const stbi_uc *)data, len, &x, &y, &n, 4); -// w = x; h = y; data = (struct aiTexel *)decoded; - } - - #if 1 - if(!embedded) - embedded = base64_encode(data, w * h * sizeof(struct aiTexel)); // leak - #else - fprintf(stderr, "%dx%d (%s)\n", w,h,hint); - char name[260]; sprintf(name, "tex_%d.%s", tex_id, hint); - FILE *out = fopen(name, "wb"); - for(unsigned y = 0; y < h; ++y) - for(unsigned x = 0; x < w; ++x) - fwrite(&data[x+y*w].b, 1, 4, out); - fclose(out); - #endif - -// if( decoded ) stbi_image_free(decoded); + if( !tex->mHeight ) + { + embedded = base64_encode(tex->pcData, (int)tex->mWidth ); // @leak + } + else + { + embedded = base64_encode(tex->pcData, (int)(tex->mWidth * tex->mHeight * sizeof(struct aiTexel))); // @leak } } #endif aiGetMaterialString(material, AI_MATKEY_NAME, &str); - fprintf(out, "material \"%s%s%s%s%s\"\n", str.data, buffer, colorbuffer, embedded ? "+b64:":"", embedded ? embedded:""); + fprintf(out, "material \"%s%s%s%s%s\"\n", buffer[0] == '*' ? "" : str.data, buffer, colorbuffer, embedded ? "+b64:":"", embedded ? embedded:""); } struct vb *vb = (struct vb*) malloc(mesh->mNumVertices * sizeof(*vb)); @@ -1348,8 +1346,6 @@ int main(int argc, char **argv) char *p; int c; - char *output = NULL; - char *input = NULL; int onlyanim = 0; int onlymesh = 0; diff --git a/tools/ass2iqe.exe b/tools/ass2iqe.exe index 159be71..b6a5ff9 100644 Binary files a/tools/ass2iqe.exe and b/tools/ass2iqe.exe differ diff --git a/tools/cook.c b/tools/cook.c index ade20fe..c1737ba 100644 --- a/tools/cook.c +++ b/tools/cook.c @@ -30,9 +30,9 @@ int main(int argc, const char **argv) { /* compiled with: - cc -ObjC cook.c -I../engine -o cook.osx -framework Cocoa -framework IOKit -framework audiotoolbox -O3 + cc -ObjC cook.c -I../engine -o cook.osx -framework Cocoa -framework IOKit -framework audiotoolbox -framework coreaudio -O3 cc cook.c -I../engine -o cook.linux -lm -lpthread -ldl -lX11 -O3 tcc cook.c -I..\engine cl cook.c -I..\engine /openmp /Os /Ox /O2 /Oy /MT /DNDEBUG /GL /GF /Gw /arch:AVX2 /link /OPT:ICF /LTCG - del cook.o & del cook.obj & del cook.lib & del cook.exp -*/ \ No newline at end of file + del *.o & del *.obj & del *.lib & del *.exp & del *.pdb +*/ diff --git a/tools/glslcc.exe b/tools/glslcc.exe index 85318c2..2739407 100644 Binary files a/tools/glslcc.exe and b/tools/glslcc.exe differ diff --git a/tools/iqe2iqm.cpp b/tools/iqe2iqm.cpp index 205f34f..0c83ced 100644 --- a/tools/iqe2iqm.cpp +++ b/tools/iqe2iqm.cpp @@ -17,6 +17,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI // - So, I increased the vector growsize & removed all deallocations to "fix" random crashes // - Not quite sure still, so I also removed custom allocators // - Also, switched string hashing to fnv1a, hoping to distribute hashmap buckets more uniformly +// - Note: crashes behaves worse on x64. x86 seems to be more predictable. #include #include @@ -29,11 +30,108 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #define _CRT_SECURE_NO_WARNINGS 1 -//#define ASSERT assert -#define ASSERT(x) do{}while(0) -#define delete_array (0),(void) // hac +#define ASSERT(x) do{ if(!(x)) exit(-fprintf(stderr, "assertion failed: `" #x "` %s:%d\n%s\n", __FILE__, __LINE__, callstack(+16))); } while(0) // assert(x) +//#define ASSERT(x) do{}while(0) // hack +#define delete_array (0),(void) // hack to minimize crashes //#define delete_array delete[] +#ifdef _WIN32 // && !defined __TINYC__ +#define SYS_MEM_REALLOC realloc +#define __thread __declspec(thread) +#define concat(a,b) conc4t(a,b) +#define conc4t(a,b) a##b ///- +#define macro(name) concat(name, __LINE__) +#define do_once static int macro(init) = 1; for(;macro(init);macro(init) = 0) +#include // windows.h alternative +#include +#pragma comment(lib, "DbgHelp") +#pragma comment(lib, "Kernel32") +static int backtrace( void **addr, int maxtraces ) { + static bool init = 0; + do_once SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_INCLUDE_32BIT_MODULES); + do_once init = SymInitialize(GetCurrentProcess(), NULL, TRUE); + if(!init) return 0; // error: cannot initialize DbgHelp.lib + + typedef USHORT (WINAPI *pFN)(__in ULONG, __in ULONG, __out PVOID*, __out_opt PULONG); // _MSC_VER + static pFN rtlCaptureStackBackTrace = 0; + if( !rtlCaptureStackBackTrace ) { + rtlCaptureStackBackTrace = (pFN)GetProcAddress(LoadLibraryA("kernel32.dll"), "RtlCaptureStackBackTrace"); + } + if( !rtlCaptureStackBackTrace ) { + return 0; + } + return rtlCaptureStackBackTrace(1, maxtraces, (PVOID *)addr, (DWORD *) 0); +} +static char **backtrace_symbols(void *const *list,int size) { + HANDLE process = GetCurrentProcess(); + + struct symbol_t { + SYMBOL_INFO info; + TCHAR symbolname[256], terminator; + } si = { {0} }; + si.info.SizeOfStruct = sizeof(SYMBOL_INFO); + si.info.MaxNameLen = sizeof(si.symbolname) / sizeof(TCHAR); // number of chars, not bytes + + IMAGEHLP_LINE l64 = { 0 }; + l64.SizeOfStruct = sizeof(IMAGEHLP_LINE); + + static __thread char **symbols = 0; //[32][64] = {0}; + if( !symbols ) { + symbols = (char**)SYS_MEM_REALLOC(0, 128 * sizeof(char*)); + for( int i = 0; i < 128; ++i) symbols[i] = (char*)SYS_MEM_REALLOC(0, 128 * sizeof(char)); + } + + if(size > 128) size = 128; + for( int i = 0; i < size; ++i ) { + + char *ptr = symbols[i]; + *ptr = '\0'; + + if (SymFromAddr(process, (DWORD64)(uintptr_t)list[i], 0, &si.info)) { + //char undecorated[1024]; + //UnDecorateSymbolName(si.info.Name, undecorated, sizeof(undecorated)-1, UNDNAME_COMPLETE); + char* undecorated = (char*)si.info.Name; + ptr += snprintf(ptr, 128, "%s", undecorated); + } else { + ptr += snprintf(ptr, 128, "%s", "(?""?)"); + } + + DWORD dw = 0; + if (SymGetLineFromAddr(process, (DWORD64)(uintptr_t)list[i], &dw, &l64)) { + ptr += snprintf(ptr, 128 - (ptr - symbols[i]), " (%s:%u)", l64.FileName, (unsigned)l64.LineNumber); + } + } + + return symbols; +} +char *callstack( int traces ) { + static __thread char *output = 0; + if(!output ) output = (char*)SYS_MEM_REALLOC( 0, 128 * (64+2) ); + if( output ) output[0] = '\0'; + char *ptr = output; + + enum { skip = 1 }; /* exclude 1 trace from stack (this function) */ + enum { maxtraces = 128 }; + + int inc = 1; + if( traces < 0 ) traces = -traces, inc = -1; + if( traces == 0 ) return ""; + if( traces > maxtraces ) traces = maxtraces; + + void* stacks[maxtraces/* + 1*/]; // = { 0 }; + traces = backtrace( stacks, traces ); + char **symbols = backtrace_symbols( stacks, traces ); // @todo: optimization: map(void*,char*) cache; and retrieve only symbols not in cache + + char demangled[1024] = "??"; + int L = 0, B = inc>0 ? skip - 1 : traces, E = inc>0 ? traces : skip - 1; + for( int i = B; ( i += inc ) != E; ) { + ptr += sprintf(ptr, "%03d: %#016llx %s\n", ++L, (unsigned long long)(uintptr_t)stacks[i], symbols[i]); // format gymnastics because %p is not standard when printing pointers + } + + return output ? output : ""; +} +#endif + #ifndef __IQM_H__ #define __IQM_H__ @@ -308,7 +406,9 @@ template struct vector : public std::vector { static const int MINSIZE = 8; +mutable //< @r-lyeh T *buf; +mutable //< @r-lyeh int alen, ulen; vector() : buf(NULL), alen(0), ulen(0) @@ -327,6 +427,9 @@ template struct vector : public std::vector setsize(0); if(v.length() > alen) growbuf(v.length()); loopv(v) add(v[i]); + + if(ulen==alen) growbuf(ulen+1); //< @r-lyeh + return *this; } @@ -361,8 +464,14 @@ template struct vector : public std::vector bool empty() const { return ulen==0; } int capacity() const { return alen; } int length() const { return ulen; } - T &operator[](int i) { ASSERT(i>=0 && i= 0 && i=0 && i= 0 && i struct vector : public std::vector bool inbuf(const T *e) const { return e >= buf && e < &buf[ulen]; } void growbuf(int sz) +const //< @r-lyeh { int olen = alen; if(!alen) alen = max(MINSIZE, sz); @@ -393,6 +503,7 @@ template struct vector : public std::vector } T *reserve(int sz) +const //< @r-lyeh { if(ulen+sz > alen) growbuf(ulen+sz); return &buf[ulen]; @@ -487,7 +598,7 @@ template struct hashtable typedef T value; typedef const T const_value; - enum { CHUNKSIZE = 64, MAXLOADFACTOR = 75, RESIZEFACTOR = 4, MAXSIZE = 64<<20 }; + enum { CHUNKSIZE = 64, MAXLOADFACTOR = 75, RESIZERATIO = 4, MAXSIZE = 128<<20 }; struct chain { T data; K key; chain *next; }; struct chainchunk { chain chains[CHUNKSIZE]; chainchunk *next; }; @@ -517,7 +628,12 @@ template struct hashtable chain *insert(const K &key, uint h) { - if(size <= MAXSIZE / RESIZEFACTOR && numelems * 100 > size * MAXLOADFACTOR) { rehash(); h = hthash(key)&(size-1); } + if(size*RESIZERATIO < MAXSIZE && float(++numelems) / size * 100.0 > MAXLOADFACTOR) { rehash(); h = hthash(key)&(size-1); } + return insert(unused, chunks, table, key, h); + } + + static chain *insert(chain *&unused, chainchunk *&chunks, chain **&table, const K& key, uint h) + { if(!unused) { chainchunk *chunk = new chainchunk; @@ -532,7 +648,6 @@ template struct hashtable c->key = key; c->next = table[h]; table[h] = c; - numelems++; return c; } @@ -612,23 +727,27 @@ template struct hashtable void rehash() { - int oldsize = size; - chain **oldtable = table; + int newsize = size*RESIZERATIO; + chain **newtable = new chain* [newsize]; + loopi(newsize) newtable[i] = NULL; - size *= RESIZEFACTOR; - table = new chain*[size]; - loopi(size) table[i] = NULL; - - loopi(oldsize) for (chain *c = oldtable[i]; c;) + chainchunk *newchunks = NULL; + chain *newunused = NULL; + loopi(size) for (chain *c = table[i]; c;) { - chain *p = c; + const K& k = c->key; + uint h = hthash(k)&(newsize-1); + insert(newunused, newchunks, newtable, k, h)->data = c->data; c = c->next; - uint h = hthash(p->key)&(size-1); - p->next = table[h]; - table[h] = p; } - delete_array oldtable; + delete[] table; + deletechunks(); + + size = newsize; + table = newtable; + chunks = newchunks; + unused = newunused; } }; @@ -2552,13 +2671,16 @@ struct filespec bool parseiqe(stream *f) { + enum { sizeof_tex = (8*1024) * (8*1024) * (4) }; // max cap: 8K texture, RGBA8888, + const unsigned sizeof_buf = ceil(sizeof_tex / 3) * 4; // then, max capacity encoded as base64 + static char *buf = new char [sizeof_buf]; + const char *curmesh = getnamekey(""), *curmaterial = getnamekey(""); bool needmesh = true; int fmoffset = 0; - char buf[512]; - if(!f->getline(buf, sizeof(buf))) return false; + if(!f->getline(buf, sizeof_buf)) return false; if(!strchr(buf, '#') || strstr(buf, "# Inter-Quake Export") != strchr(buf, '#')) return false; - while(f->getline(buf, sizeof(buf))) + while(f->getline(buf, sizeof_buf)) { char *c = buf; while(isspace(*c)) ++c; @@ -3339,3 +3461,6 @@ int main(int argc, char **argv) return EXIT_SUCCESS; } + +// cl iqe2iqm.cpp /DDEBUG /MT /Zi /fsanitize=address +// cl iqe2iqm.cpp /O2 /Oy /MT /DNDEBUG diff --git a/tools/iqe2iqm.exe b/tools/iqe2iqm.exe index 1b70186..e58f429 100644 Binary files a/tools/iqe2iqm.exe and b/tools/iqe2iqm.exe differ