diff --git a/polymer/eduke32/Makefile b/polymer/eduke32/Makefile index d68ef1e95..3b43146b3 100644 --- a/polymer/eduke32/Makefile +++ b/polymer/eduke32/Makefile @@ -43,6 +43,7 @@ ENGINE_OBJS = \ crc32 \ defs \ engine \ + hash \ polymost \ texcache \ dxtfilter \ diff --git a/polymer/eduke32/Makefile.msvc b/polymer/eduke32/Makefile.msvc index db415d23c..bb22d869d 100644 --- a/polymer/eduke32/Makefile.msvc +++ b/polymer/eduke32/Makefile.msvc @@ -137,6 +137,7 @@ ENGINE_OBJS= \ $(ENGINE_OBJ)\defs.$o \ $(ENGINE_OBJ)\colmatch.$o \ $(ENGINE_OBJ)\engine.$o \ + $(ENGINE_OBJ)\hash.$o \ $(ENGINE_OBJ)\glbuild.$o \ $(ENGINE_OBJ)\texcache.$o \ $(ENGINE_OBJ)\kplib.$o \ diff --git a/polymer/eduke32/build/Makefile.deps b/polymer/eduke32/build/Makefile.deps index b415837ca..0122bcc00 100644 --- a/polymer/eduke32/build/Makefile.deps +++ b/polymer/eduke32/build/Makefile.deps @@ -10,6 +10,7 @@ $(ENGINE_OBJ)/config.$o: $(ENGINE_SRC)/config.c $(ENGINE_INC)/compat.h $(ENGINE_ $(ENGINE_OBJ)/crc32.$o: $(ENGINE_SRC)/crc32.c $(ENGINE_INC)/crc32.h $(ENGINE_OBJ)/defs.$o: $(ENGINE_SRC)/defs.c $(ENGINE_INC)/build.h $(ENGINE_INC)/buildtypes.h $(ENGINE_INC)/baselayer.h $(ENGINE_INC)/scriptfile.h $(ENGINE_INC)/compat.h $(ENGINE_OBJ)/engine.$o: $(ENGINE_SRC)/engine.c $(ENGINE_INC)/compat.h $(ENGINE_INC)/build.h $(ENGINE_INC)/buildtypes.h $(ENGINE_INC)/pragmas.h $(ENGINE_INC)/cache1d.h $(ENGINE_INC)/a.h $(ENGINE_INC)/osd.h $(ENGINE_INC)/baselayer.h $(ENGINE_SRC)/engine_priv.h $(ENGINE_SRC)/engine_oldmap.h $(ENGINE_INC)/polymost.h $(ENGINE_INC)/hightile.h $(ENGINE_INC)/mdsprite.h $(ENGINE_INC)/polymer.h +$(ENGINE_OBJ)/hash.$o: $(ENGINE_SRC)/hash.c $(ENGINE_INC)/hash.h $(ENGINE_OBJ)/polymost.$o: $(ENGINE_SRC)/polymost.c $(ENGINE_INC)/lz4.h $(ENGINE_INC)/compat.h $(ENGINE_INC)/build.h $(ENGINE_INC)/buildtypes.h $(ENGINE_SRC)/engine_priv.h $(ENGINE_INC)/polymost.h $(ENGINE_INC)/hightile.h $(ENGINE_INC)/mdsprite.h $(ENGINE_INC)/texcache.h $(ENGINE_OBJ)/texcache.$o: $(ENGINE_SRC)/texcache.c $(ENGINE_INC)/texcache.h $(ENGINE_INC)/polymost.h $(ENGINE_INC)/dxtfilter.h $(ENGINE_INC)/kplib.h $(ENGINE_OBJ)/dxtfilter.$o: $(ENGINE_SRC)/dxtfilter.c $(ENGINE_INC)/dxtfilter.h $(ENGINE_INC)/texcache.h diff --git a/polymer/eduke32/build/include/build.h b/polymer/eduke32/build/include/build.h index c3ca2edbd..0c144835d 100644 --- a/polymer/eduke32/build/include/build.h +++ b/polymer/eduke32/build/include/build.h @@ -1405,56 +1405,7 @@ int32_t loaddefinitionsfile(const char *fn); // -2, board is dodgy int32_t loadoldboard(const char *filename, char fromwhere, vec3_t *dapos, int16_t *daang, int16_t *dacursectnum); - -// Hash functions - -typedef struct hashitem_ // size is 12/24 bytes. -{ - char *string; - intptr_t key; - struct hashitem_ *next; -} hashitem_t; - -typedef struct -{ - int32_t size; - hashitem_t **items; -} hashtable_t; - -void hash_init(hashtable_t *t); -void hash_loop(hashtable_t *t, void (*func)(const char *, intptr_t)); -void hash_free(hashtable_t *t); -intptr_t hash_findcase(hashtable_t const * const t, char const * const s); -intptr_t hash_find(hashtable_t const * const t, char const * const s); -void hash_add(hashtable_t *t, const char *s, intptr_t key, int32_t replace); -void hash_delete(hashtable_t *t, const char *s); - - -// Hash functions -// modified for raw binary keys and one big allocation, and maximum find() performance - -typedef struct inthashitem_ -{ - intptr_t key; - intptr_t value; - struct inthashitem_ *collision; // use NULL to signify empty and pointer identity to signify end of linked list -} inthashitem_t; - -typedef struct -{ - inthashitem_t * items; - uint32_t count; -} inthashtable_t; - -void inthash_init(inthashtable_t *t); -void inthash_loop(inthashtable_t const *t, void (*func)(intptr_t, intptr_t)); -void inthash_free(inthashtable_t *t); -intptr_t inthash_find(inthashtable_t const *t, intptr_t key); -void inthash_add(inthashtable_t *t, intptr_t key, intptr_t value, int32_t replace); -void inthash_delete(inthashtable_t *t, intptr_t key); -// keep the load factor below 0.75 and make sure the size is odd -// ideally we would find the next largest prime number -#define INTHASH_SIZE(size) ((size * 4u / 3u) | 1u) +#include "hash.h" #ifdef POLYMER # include "polymer.h" diff --git a/polymer/eduke32/build/include/hash.h b/polymer/eduke32/build/include/hash.h new file mode 100644 index 000000000..9e37df63f --- /dev/null +++ b/polymer/eduke32/build/include/hash.h @@ -0,0 +1,65 @@ + +#pragma once + +#ifndef hash_h_ +#define hash_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +// Hash functions + +typedef struct hashitem_ // size is 12/24 bytes. +{ + char *string; + intptr_t key; + struct hashitem_ *next; +} hashitem_t; + +typedef struct +{ + int32_t size; + hashitem_t **items; +} hashtable_t; + +void hash_init(hashtable_t *t); +void hash_loop(hashtable_t *t, void(*func)(const char *, intptr_t)); +void hash_free(hashtable_t *t); +intptr_t hash_findcase(hashtable_t const * const t, char const * const s); +intptr_t hash_find(hashtable_t const * const t, char const * const s); +void hash_add(hashtable_t *t, const char *s, intptr_t key, int32_t replace); +void hash_delete(hashtable_t *t, const char *s); + + +// Hash functions +// modified for raw binary keys and one big allocation, and maximum find() performance + +typedef struct inthashitem_ +{ + intptr_t key; + intptr_t value; + struct inthashitem_ *collision; // use NULL to signify empty and pointer identity to signify end of linked list +} inthashitem_t; + +typedef struct +{ + inthashitem_t * items; + uint32_t count; +} inthashtable_t; + +void inthash_init(inthashtable_t *t); +void inthash_loop(inthashtable_t const *t, void(*func)(intptr_t, intptr_t)); +void inthash_free(inthashtable_t *t); +intptr_t inthash_find(inthashtable_t const *t, intptr_t key); +void inthash_add(inthashtable_t *t, intptr_t key, intptr_t value, int32_t replace); +void inthash_delete(inthashtable_t *t, intptr_t key); +// keep the load factor below 0.75 and make sure the size is odd +// ideally we would find the next largest prime number +#define INTHASH_SIZE(size) ((size * 4u / 3u) | 1u) + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/polymer/eduke32/build/src/engine.c b/polymer/eduke32/build/src/engine.c index 809555f78..0573bbf6c 100644 --- a/polymer/eduke32/build/src/engine.c +++ b/polymer/eduke32/build/src/engine.c @@ -18373,371 +18373,6 @@ void setpolymost2dview(void) #endif } -void hash_init(hashtable_t *t) -{ - hash_free(t); - t->items=(hashitem_t **)Xcalloc(1, t->size * sizeof(hashitem_t)); -} - -void hash_loop(hashtable_t *t, void (*func)(const char *, intptr_t)) -{ - if (t->items == NULL) - return; - - for (int32_t i=0; i < t->size; i++) - for (hashitem_t *item=t->items[i]; item != NULL; item = item->next) - func(item->string, item->key); -} - -void hash_free(hashtable_t *t) -{ - if (t->items == NULL) - return; - - int remaining = t->size - 1; - - do - { - hashitem_t *cur = t->items[remaining]; - - int num = 0; - - while (cur) - { - hashitem_t * const tmp = cur; - cur = cur->next; - - Bfree(tmp->string); - Bfree(tmp); - num++; - } - } while (--remaining >= 0); - - DO_FREE_AND_NULL(t->items); -} - -// djb3 algorithm -static inline uint32_t hash_getcode(const char *s) -{ - uint32_t h = 5381; - int32_t ch; - - while ((ch = *s++) != '\0') - h = ((h << 5) + h) ^ ch; - - return h; -} - -void hash_add(hashtable_t *t, const char *s, intptr_t key, int32_t replace) -{ -#ifdef DEBUGGINGAIDS - Bassert(t->items != NULL); -#else - if (EDUKE32_PREDICT_FALSE(t->items == NULL)) - { - initprintf("hash_add(): table not initialized!\n"); - return; - } -#endif - - uint32_t code = hash_getcode(s) % t->size; - hashitem_t *cur = t->items[code]; - - if (!cur) - { - cur = (hashitem_t *)Xcalloc(1,sizeof(hashitem_t)); - cur->string = Xstrdup(s); - cur->key = key; - cur->next = NULL; - t->items[code] = cur; - return; - } - - hashitem_t *prev = NULL; - - do - { - if (Bstrcmp(s,cur->string) == 0) - { - if (replace) cur->key = key; - return; - } - prev = cur; - } - while ((cur = cur->next)); - - cur = (hashitem_t *)Xcalloc(1,sizeof(hashitem_t)); - cur->string = Xstrdup(s); - cur->key = key; - cur->next = NULL; - prev->next = cur; -} - -// delete at most once -void hash_delete(hashtable_t *t, const char *s) -{ -#ifdef DEBUGGINGAIDS - Bassert(t->items != NULL); -#else - if (t->items == NULL) - { - initprintf("hash_delete(): table not initialized!\n"); - return; - } -#endif - - uint32_t code = hash_getcode(s) % t->size; - hashitem_t *cur = t->items[code]; - - if (!cur) - return; - - hashitem_t *prev = NULL; - - do - { - if (Bstrcmp(s, cur->string) == 0) - { - Bfree(cur->string); - - if (!prev) - t->items[code] = cur->next; - else - prev->next = cur->next; - - Bfree(cur); - - break; - } - prev = cur; - } - while ((cur = cur->next)); -} - -intptr_t hash_find(const hashtable_t * const t, char const * const s) -{ -#ifdef DEBUGGINGAIDS - Bassert(t->items != NULL); -#else - if (t->items == NULL) - { - initprintf("hash_find(): table not initialized!\n"); - return -1; - } -#endif - - hashitem_t *cur = t->items[hash_getcode(s) % t->size]; - - if (!cur) - return -1; - - do - if (Bstrcmp(s, cur->string) == 0) - return cur->key; - while ((cur = cur->next)); - - return -1; -} - -intptr_t hash_findcase(const hashtable_t * const t, char const * const s) -{ -#ifdef DEBUGGINGAIDS - Bassert(t->items != NULL); -#else - if (t->items == NULL) - { - initprintf("hash_findcase(): table not initialized!\n"); - return -1; - } -#endif - - hashitem_t *cur = t->items[hash_getcode(s) % t->size]; - - if (!cur) - return -1; - - do - if (Bstrcasecmp(s, cur->string) == 0) - return cur->key; - while ((cur = cur->next)); - - return -1; -} - - -void inthash_init(inthashtable_t *t) -{ - if (EDUKE32_PREDICT_FALSE(!t->count)) - { - initputs("inthash_add(): count is zero!\n"); - return; - } - - inthash_free(t); - - t->items = (inthashitem_t *)Xcalloc(t->count, sizeof(inthashitem_t)); -} - -void inthash_loop(inthashtable_t const *t, void (*func)(intptr_t, intptr_t)) -{ -#ifdef DEBUGGINGAIDS - Bassert(t->items != NULL); -#else - if (EDUKE32_PREDICT_FALSE(t->items == NULL)) - { - initputs("inthash_loop(): table not initialized!\n"); - return; - } -#endif - - for (inthashitem_t const * item = t->items, * const items_end = t->items + t->count; item < items_end; ++item) - func(item->key, item->value); -} - -void inthash_free(inthashtable_t *t) -{ - DO_FREE_AND_NULL(t->items); -} - -// djb3 algorithm -static inline uint32_t inthash_getcode(intptr_t key) -{ - uint32_t h = 5381; - - for (uint8_t const * keybuf = (uint8_t *)&key, * const keybuf_end = keybuf + sizeof(intptr_t); keybuf < keybuf_end; ++keybuf) - h = ((h << 5) + h) ^ (uint32_t)*keybuf; - - return h; -} - -void inthash_add(inthashtable_t *t, intptr_t key, intptr_t value, int32_t replace) -{ -#ifdef DEBUGGINGAIDS - Bassert(t->items != NULL); -#else - if (EDUKE32_PREDICT_FALSE(t->items == NULL)) - { - initputs("inthash_add(): table not initialized!\n"); - return; - } -#endif - - inthashitem_t * seeker = t->items + inthash_getcode(key) % t->count; - - if (seeker->collision == NULL) - { - seeker->key = key; - seeker->value = value; - seeker->collision = seeker; - - return; - } - - if (seeker->key == key) - { - if (replace) - seeker->value = value; - return; - } - - while (seeker != seeker->collision) - { - seeker = seeker->collision; - - if (seeker->key == key) - { - if (replace) - seeker->value = value; - return; - } - } - - inthashitem_t *tail = seeker; - - do - tail = t->items + (tail - t->items + 1) % t->count; - while (tail->collision != NULL && tail != seeker); - - if (EDUKE32_PREDICT_FALSE(tail == seeker)) - { - initputs("inthash_add(): table full!\n"); - return; - } - - tail->key = key; - tail->value = value; - tail->collision = seeker->collision = tail; -} - -// delete at most once -void inthash_delete(inthashtable_t *t, intptr_t key) -{ -#ifdef DEBUGGINGAIDS - Bassert(t->items != NULL); -#else - if (EDUKE32_PREDICT_FALSE(t->items == NULL)) - { - initputs("inthash_delete(): table not initialized!\n"); - return; - } -#endif - - inthashitem_t * seeker = t->items + inthash_getcode(key) % t->count; - - if (seeker->collision == NULL) - return; - - if (seeker->key == key) - { - seeker->collision = NULL; - return; - } - - while (seeker != seeker->collision) - { - inthashitem_t * const prev = seeker; - seeker = seeker->collision; - - if (seeker->key == key) - { - prev->collision = seeker == seeker->collision ? prev : seeker->collision; - seeker->collision = NULL; - return; - } - } -} - -intptr_t inthash_find(inthashtable_t const *t, intptr_t key) -{ -#ifdef DEBUGGINGAIDS - Bassert(t->items != NULL); -#else - if (EDUKE32_PREDICT_FALSE(t->items == NULL)) - { - initputs("inthash_find(): table not initialized!\n"); - return -1; - } -#endif - - inthashitem_t const * seeker = t->items + inthash_getcode(key) % t->count; - - if (seeker->collision == NULL) - return -1; - - if (seeker->key == key) - return seeker->value; - - while (seeker != seeker->collision) - { - seeker = seeker->collision; - - if (seeker->key == key) - return seeker->value; - } - - return -1; -} - /* * vim:ts=8: */ diff --git a/polymer/eduke32/build/src/hash.c b/polymer/eduke32/build/src/hash.c new file mode 100644 index 000000000..4ad39b588 --- /dev/null +++ b/polymer/eduke32/build/src/hash.c @@ -0,0 +1,367 @@ + +#include "compat.h" +#include "hash.h" +#include "baselayer.h" + +void hash_init(hashtable_t *t) +{ + hash_free(t); + t->items=(hashitem_t **) Xcalloc(1, t->size * sizeof(hashitem_t)); +} + +void hash_loop(hashtable_t *t, void(*func)(const char *, intptr_t)) +{ + if (t->items == NULL) + return; + + for (int32_t i=0; i < t->size; i++) + for (hashitem_t *item=t->items[i]; item != NULL; item = item->next) + func(item->string, item->key); +} + +void hash_free(hashtable_t *t) +{ + if (t->items == NULL) + return; + + int remaining = t->size - 1; + + do + { + hashitem_t *cur = t->items[remaining]; + + int num = 0; + + while (cur) + { + hashitem_t * const tmp = cur; + cur = cur->next; + + Bfree(tmp->string); + Bfree(tmp); + num++; + } + } while (--remaining >= 0); + + DO_FREE_AND_NULL(t->items); +} + +// djb3 algorithm +static inline uint32_t hash_getcode(const char *s) +{ + uint32_t h = 5381; + int32_t ch; + + while ((ch = *s++) != '\0') + h = ((h << 5) + h) ^ ch; + + return h; +} + +void hash_add(hashtable_t *t, const char *s, intptr_t key, int32_t replace) +{ +#ifdef DEBUGGINGAIDS + Bassert(t->items != NULL); +#else + if (EDUKE32_PREDICT_FALSE(t->items == NULL)) + { + initprintf("hash_add(): table not initialized!\n"); + return; + } +#endif + + uint32_t code = hash_getcode(s) % t->size; + hashitem_t *cur = t->items[code]; + + if (!cur) + { + cur = (hashitem_t *) Xcalloc(1, sizeof(hashitem_t)); + cur->string = Xstrdup(s); + cur->key = key; + cur->next = NULL; + t->items[code] = cur; + return; + } + + hashitem_t *prev = NULL; + + do + { + if (Bstrcmp(s, cur->string) == 0) + { + if (replace) cur->key = key; + return; + } + prev = cur; + } while ((cur = cur->next)); + + cur = (hashitem_t *) Xcalloc(1, sizeof(hashitem_t)); + cur->string = Xstrdup(s); + cur->key = key; + cur->next = NULL; + prev->next = cur; +} + +// delete at most once +void hash_delete(hashtable_t *t, const char *s) +{ +#ifdef DEBUGGINGAIDS + Bassert(t->items != NULL); +#else + if (t->items == NULL) + { + initprintf("hash_delete(): table not initialized!\n"); + return; + } +#endif + + uint32_t code = hash_getcode(s) % t->size; + hashitem_t *cur = t->items[code]; + + if (!cur) + return; + + hashitem_t *prev = NULL; + + do + { + if (Bstrcmp(s, cur->string) == 0) + { + Bfree(cur->string); + + if (!prev) + t->items[code] = cur->next; + else + prev->next = cur->next; + + Bfree(cur); + + break; + } + prev = cur; + } while ((cur = cur->next)); +} + +intptr_t hash_find(const hashtable_t * const t, char const * const s) +{ +#ifdef DEBUGGINGAIDS + Bassert(t->items != NULL); +#else + if (t->items == NULL) + { + initprintf("hash_find(): table not initialized!\n"); + return -1; + } +#endif + + hashitem_t *cur = t->items[hash_getcode(s) % t->size]; + + if (!cur) + return -1; + + do + if (Bstrcmp(s, cur->string) == 0) + return cur->key; + while ((cur = cur->next)); + + return -1; +} + +intptr_t hash_findcase(const hashtable_t * const t, char const * const s) +{ +#ifdef DEBUGGINGAIDS + Bassert(t->items != NULL); +#else + if (t->items == NULL) + { + initprintf("hash_findcase(): table not initialized!\n"); + return -1; + } +#endif + + hashitem_t *cur = t->items[hash_getcode(s) % t->size]; + + if (!cur) + return -1; + + do + if (Bstrcasecmp(s, cur->string) == 0) + return cur->key; + while ((cur = cur->next)); + + return -1; +} + + +void inthash_init(inthashtable_t *t) +{ + if (EDUKE32_PREDICT_FALSE(!t->count)) + { + initputs("inthash_add(): count is zero!\n"); + return; + } + + inthash_free(t); + + t->items = (inthashitem_t *) Xcalloc(t->count, sizeof(inthashitem_t)); +} + +void inthash_loop(inthashtable_t const *t, void(*func)(intptr_t, intptr_t)) +{ +#ifdef DEBUGGINGAIDS + Bassert(t->items != NULL); +#else + if (EDUKE32_PREDICT_FALSE(t->items == NULL)) + { + initputs("inthash_loop(): table not initialized!\n"); + return; + } +#endif + + for (inthashitem_t const * item = t->items, *const items_end = t->items + t->count; item < items_end; ++item) + func(item->key, item->value); +} + +void inthash_free(inthashtable_t *t) +{ + DO_FREE_AND_NULL(t->items); +} + +// djb3 algorithm +static inline uint32_t inthash_getcode(intptr_t key) +{ + uint32_t h = 5381; + + for (uint8_t const * keybuf = (uint8_t *) &key, *const keybuf_end = keybuf + sizeof(intptr_t); keybuf < keybuf_end; ++keybuf) + h = ((h << 5) + h) ^ (uint32_t) *keybuf; + + return h; +} + +void inthash_add(inthashtable_t *t, intptr_t key, intptr_t value, int32_t replace) +{ +#ifdef DEBUGGINGAIDS + Bassert(t->items != NULL); +#else + if (EDUKE32_PREDICT_FALSE(t->items == NULL)) + { + initputs("inthash_add(): table not initialized!\n"); + return; + } +#endif + + inthashitem_t * seeker = t->items + inthash_getcode(key) % t->count; + + if (seeker->collision == NULL) + { + seeker->key = key; + seeker->value = value; + seeker->collision = seeker; + + return; + } + + if (seeker->key == key) + { + if (replace) + seeker->value = value; + return; + } + + while (seeker != seeker->collision) + { + seeker = seeker->collision; + + if (seeker->key == key) + { + if (replace) + seeker->value = value; + return; + } + } + + inthashitem_t *tail = seeker; + + do + tail = t->items + (tail - t->items + 1) % t->count; + while (tail->collision != NULL && tail != seeker); + + if (EDUKE32_PREDICT_FALSE(tail == seeker)) + { + initputs("inthash_add(): table full!\n"); + return; + } + + tail->key = key; + tail->value = value; + tail->collision = seeker->collision = tail; +} + +// delete at most once +void inthash_delete(inthashtable_t *t, intptr_t key) +{ +#ifdef DEBUGGINGAIDS + Bassert(t->items != NULL); +#else + if (EDUKE32_PREDICT_FALSE(t->items == NULL)) + { + initputs("inthash_delete(): table not initialized!\n"); + return; + } +#endif + + inthashitem_t * seeker = t->items + inthash_getcode(key) % t->count; + + if (seeker->collision == NULL) + return; + + if (seeker->key == key) + { + seeker->collision = NULL; + return; + } + + while (seeker != seeker->collision) + { + inthashitem_t * const prev = seeker; + seeker = seeker->collision; + + if (seeker->key == key) + { + prev->collision = seeker == seeker->collision ? prev : seeker->collision; + seeker->collision = NULL; + return; + } + } +} + +intptr_t inthash_find(inthashtable_t const *t, intptr_t key) +{ +#ifdef DEBUGGINGAIDS + Bassert(t->items != NULL); +#else + if (EDUKE32_PREDICT_FALSE(t->items == NULL)) + { + initputs("inthash_find(): table not initialized!\n"); + return -1; + } +#endif + + inthashitem_t const * seeker = t->items + inthash_getcode(key) % t->count; + + if (seeker->collision == NULL) + return -1; + + if (seeker->key == key) + return seeker->value; + + while (seeker != seeker->collision) + { + seeker = seeker->collision; + + if (seeker->key == key) + return seeker->value; + } + + return -1; +} diff --git a/polymer/eduke32/eduke32.vcxproj b/polymer/eduke32/eduke32.vcxproj index 7e7e1242c..ed867aac2 100644 --- a/polymer/eduke32/eduke32.vcxproj +++ b/polymer/eduke32/eduke32.vcxproj @@ -115,6 +115,7 @@ + @@ -265,6 +266,7 @@ + diff --git a/polymer/eduke32/eduke32.vcxproj.filters b/polymer/eduke32/eduke32.vcxproj.filters index 61cd119a9..e60f51248 100644 --- a/polymer/eduke32/eduke32.vcxproj.filters +++ b/polymer/eduke32/eduke32.vcxproj.filters @@ -528,6 +528,9 @@ eduke32\headers + + build\headers + @@ -926,6 +929,9 @@ eduke32\source + + build\source +