Merge branch 'master' into rebalance
This commit is contained in:
commit
02469cf722
13 changed files with 296 additions and 100 deletions
|
@ -5,7 +5,7 @@ varying vec4 TexCoord0;
|
|||
void main(void) {
|
||||
gl_Position = ftransform();
|
||||
|
||||
TexCoord0 = gl_TextureMatrix[0] * gl_MultiTexCoord0;
|
||||
TexCoord0 = gl_MultiTexCoord0;
|
||||
}
|
||||
|
||||
%% -- FRAG
|
||||
|
@ -25,7 +25,7 @@ void main(void) {
|
|||
pos += (f*0.05*sin(10.0*(length(f)+t)))*(1.0-t);
|
||||
|
||||
pos = clamp(pos,0.0,1.0);
|
||||
vec4 texel = texture2D(tex, pos);
|
||||
vec4 texel = texture2D(tex, (gl_TextureMatrix[0]*vec4(pos,0.0,1.0)).xy);
|
||||
|
||||
texel.a *= clamp((texture2D(trans, pos).r+0.5)*2.5*t-0.5, 0.0, 1.0);
|
||||
gl_FragColor = vec4(color,1.0)*texel;
|
||||
|
|
|
@ -127,7 +127,7 @@ endif()
|
|||
|
||||
message(STATUS "Build configuration: ${CMAKE_BUILD_TYPE}")
|
||||
|
||||
set(DEBUG_FLAGS "-ggdb -fsanitize=undefined -fno-sanitize-recover=undefined -fsanitize-recover=float-divide-by-zero -fno-omit-frame-pointer")
|
||||
set(DEBUG_FLAGS "-ggdb -fsanitize=undefined -fsanitize-recover=float-divide-by-zero -fno-omit-frame-pointer")
|
||||
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG ${DEBUG_FLAGS}")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} ${DEBUG_FLAGS}")
|
||||
|
|
249
src/hashtable.c
249
src/hashtable.c
|
@ -32,6 +32,8 @@ struct Hashtable {
|
|||
HTFreeFunc free_func;
|
||||
SDL_atomic_t cur_operation;
|
||||
SDL_atomic_t num_operations;
|
||||
size_t num_elements;
|
||||
bool dynamic_size;
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -50,12 +52,38 @@ typedef struct HashtableIterator {
|
|||
* Generic functions
|
||||
*/
|
||||
|
||||
Hashtable* hashtable_new(size_t size, HTCmpFunc cmp_func, HTHashFunc hash_func, HTCopyFunc copy_func, HTFreeFunc free_func) {
|
||||
assert(size > 0);
|
||||
static size_t constraint_size(size_t size) {
|
||||
if(size < HT_MIN_SIZE)
|
||||
return HT_MIN_SIZE;
|
||||
|
||||
if(size > HT_MAX_SIZE)
|
||||
return HT_MAX_SIZE;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
Hashtable* hashtable_new(size_t size, HTCmpFunc cmp_func, HTHashFunc hash_func, HTCopyFunc copy_func, HTFreeFunc free_func) {
|
||||
Hashtable *ht = malloc(sizeof(Hashtable));
|
||||
|
||||
if(size == HT_DYNAMIC_SIZE) {
|
||||
size = constraint_size(0);
|
||||
ht->dynamic_size = true;
|
||||
} else {
|
||||
size = constraint_size(size);
|
||||
ht->dynamic_size = false;
|
||||
}
|
||||
|
||||
if(!cmp_func) {
|
||||
cmp_func = hashtable_cmpfunc_ptr;
|
||||
}
|
||||
|
||||
if(!copy_func) {
|
||||
copy_func = hashtable_copyfunc_ptr;
|
||||
}
|
||||
|
||||
ht->table = calloc(size, sizeof(HashtableElement*));
|
||||
ht->table_size = size;
|
||||
ht->num_elements = 0;
|
||||
ht->cmp_func = cmp_func;
|
||||
ht->hash_func = hash_func;
|
||||
ht->copy_func = copy_func;
|
||||
|
@ -68,6 +96,7 @@ Hashtable* hashtable_new(size_t size, HTCmpFunc cmp_func, HTHashFunc hash_func,
|
|||
|
||||
return ht;
|
||||
}
|
||||
|
||||
static bool hashtable_try_enter_state(Hashtable *ht, int state, bool mutex) {
|
||||
SDL_atomic_t *ptr = &ht->cur_operation;
|
||||
|
||||
|
@ -109,15 +138,18 @@ static void hashtable_delete_callback(void **vlist, void *velem, void *vht) {
|
|||
delete_element(vlist, velem);
|
||||
}
|
||||
|
||||
void hashtable_unset_all(Hashtable *ht) {
|
||||
assert(ht != NULL);
|
||||
|
||||
hashtable_enter_state(ht, HT_OP_WRITE, true);
|
||||
|
||||
static void hashtable_unset_all_internal(Hashtable *ht) {
|
||||
for(size_t i = 0; i < ht->table_size; ++i) {
|
||||
delete_all_elements_witharg((void**)(ht->table + i), hashtable_delete_callback, ht);
|
||||
}
|
||||
|
||||
ht->num_elements = 0;
|
||||
}
|
||||
|
||||
void hashtable_unset_all(Hashtable *ht) {
|
||||
assert(ht != NULL);
|
||||
hashtable_enter_state(ht, HT_OP_WRITE, true);
|
||||
hashtable_unset_all_internal(ht);
|
||||
hashtable_idle_state(ht);
|
||||
}
|
||||
|
||||
|
@ -132,14 +164,6 @@ void hashtable_free(Hashtable *ht) {
|
|||
free(ht);
|
||||
}
|
||||
|
||||
static bool hashtable_compare(Hashtable *ht, void *key1, void *key2) {
|
||||
if(ht->cmp_func) {
|
||||
return ht->cmp_func(key1, key2);
|
||||
}
|
||||
|
||||
return (key1 == key2);
|
||||
}
|
||||
|
||||
void* hashtable_get(Hashtable *ht, void *key) {
|
||||
assert(ht != NULL);
|
||||
|
||||
|
@ -148,7 +172,7 @@ void* hashtable_get(Hashtable *ht, void *key) {
|
|||
HashtableElement *elems = ht->table[hash % ht->table_size];
|
||||
|
||||
for(HashtableElement *e = elems; e; e = e->next) {
|
||||
if(hash == e->hash && hashtable_compare(ht, key, e->key)) {
|
||||
if(hash == e->hash && ht->cmp_func(key, e->key)) {
|
||||
hashtable_idle_state(ht);
|
||||
return e->data;
|
||||
}
|
||||
|
@ -158,40 +182,134 @@ void* hashtable_get(Hashtable *ht, void *key) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void hashtable_set(Hashtable *ht, void *key, void *data) {
|
||||
assert(ht != NULL);
|
||||
static bool hashtable_set_internal(Hashtable *ht, HashtableElement **table, size_t table_size, hash_t hash, void *key, void *data) {
|
||||
bool collisions_updated = false;
|
||||
size_t idx = hash % table_size;
|
||||
|
||||
hash_t hash = ht->hash_func(key);
|
||||
size_t idx = hash % ht->table_size;
|
||||
|
||||
hashtable_enter_state(ht, HT_OP_WRITE, true);
|
||||
|
||||
HashtableElement *elems = ht->table[idx], *elem;
|
||||
HashtableElement *elems = table[idx], *elem;
|
||||
|
||||
for(HashtableElement *e = elems; e; e = e->next) {
|
||||
if(hash == e->hash && hashtable_compare(ht, key, e->key)) {
|
||||
if(hash == e->hash && ht->cmp_func(key, e->key)) {
|
||||
if(ht->free_func) {
|
||||
ht->free_func(e->key);
|
||||
}
|
||||
|
||||
delete_element((void**)&elems, e);
|
||||
ht->num_elements--;
|
||||
|
||||
if(elems) {
|
||||
// we have just deleted an element from a bucket that had collisions.
|
||||
collisions_updated = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(data) {
|
||||
elem = create_element((void**)&elems, sizeof(HashtableElement));
|
||||
|
||||
if(ht->copy_func) {
|
||||
ht->copy_func(&elem->key, key);
|
||||
} else {
|
||||
elem->key = key;
|
||||
if(elems) {
|
||||
// we are adding an element to a non-empty bucket.
|
||||
// normally this is a new collision, unless we are replacing an existing element.
|
||||
collisions_updated = !collisions_updated;
|
||||
}
|
||||
|
||||
elem = create_element((void**)&elems, sizeof(HashtableElement));
|
||||
ht->copy_func(&elem->key, key);
|
||||
elem->hash = ht->hash_func(elem->key);
|
||||
elem->data = data;
|
||||
|
||||
ht->num_elements++;
|
||||
}
|
||||
|
||||
ht->table[idx] = elems;
|
||||
table[idx] = elems;
|
||||
return collisions_updated;
|
||||
}
|
||||
|
||||
static int hashtable_check_collisions_with_new_size(Hashtable *ht, size_t size) {
|
||||
int *ctable = calloc(sizeof(int), size);
|
||||
int cols = 0;
|
||||
|
||||
for(size_t i = 0; i < ht->table_size; ++i) {
|
||||
for(HashtableElement *e = ht->table[i]; e; e = e->next) {
|
||||
size_t idx = e->hash % size;
|
||||
++ctable[idx];
|
||||
|
||||
if(ctable[idx] > 1) {
|
||||
++cols;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(ctable);
|
||||
return cols;
|
||||
}
|
||||
|
||||
static size_t hashtable_find_optimal_size(Hashtable *ht) {
|
||||
size_t best_size = ht->table_size;
|
||||
int col_tolerance = min(HT_COLLISION_TOLERANCE + 1, max(ht->num_elements / 2, 1));
|
||||
int min_cols = 0;
|
||||
|
||||
for(size_t s = best_size; s < HT_MAX_SIZE; s += HT_RESIZE_STEP) {
|
||||
int cols = hashtable_check_collisions_with_new_size(ht, s);
|
||||
|
||||
if(cols < col_tolerance) {
|
||||
log_debug("Optimal size for %p is %llu (%i collisions)", (void*)ht, (unsigned long long)s, cols);
|
||||
return s;
|
||||
}
|
||||
|
||||
if(cols < min_cols) {
|
||||
min_cols = cols;
|
||||
best_size = s;
|
||||
}
|
||||
}
|
||||
|
||||
log_debug("Optimal size for %p is %llu (%i collisions)", (void*)ht, (unsigned long long)best_size, min_cols);
|
||||
return best_size;
|
||||
}
|
||||
|
||||
static void hashtable_resize_internal(Hashtable *ht, size_t new_size) {
|
||||
new_size = constraint_size(new_size);
|
||||
|
||||
if(new_size == ht->table_size) {
|
||||
return;
|
||||
}
|
||||
|
||||
HashtableElement **new_table = calloc(new_size, sizeof(HashtableElement*));
|
||||
|
||||
for(size_t i = 0; i < ht->table_size; ++i) {
|
||||
for(HashtableElement *e = ht->table[i]; e; e = e->next) {
|
||||
hashtable_set_internal(ht, new_table, new_size, e->hash, e->key, e->data);
|
||||
}
|
||||
}
|
||||
|
||||
hashtable_unset_all_internal(ht);
|
||||
free(ht->table);
|
||||
|
||||
ht->table = new_table;
|
||||
|
||||
log_debug("Resized hashtable at %p: %llu -> %llu",
|
||||
(void*)ht, (unsigned long long)ht->table_size, (unsigned long long)new_size);
|
||||
|
||||
ht->table_size = new_size;
|
||||
}
|
||||
|
||||
void hashtable_resize(Hashtable *ht, size_t new_size) {
|
||||
hashtable_enter_state(ht, HT_OP_WRITE, true);
|
||||
hashtable_resize_internal(ht, new_size);
|
||||
hashtable_idle_state(ht);
|
||||
}
|
||||
|
||||
void hashtable_set(Hashtable *ht, void *key, void *data) {
|
||||
assert(ht != NULL);
|
||||
|
||||
hash_t hash = ht->hash_func(key);
|
||||
|
||||
hashtable_enter_state(ht, HT_OP_WRITE, true);
|
||||
bool update = hashtable_set_internal(ht, ht->table, ht->table_size, hash, key, data);
|
||||
|
||||
if(ht->dynamic_size && update) {
|
||||
hashtable_resize_internal(ht, hashtable_find_optimal_size(ht));
|
||||
}
|
||||
|
||||
hashtable_idle_state(ht);
|
||||
}
|
||||
|
@ -202,14 +320,8 @@ void hashtable_unset(Hashtable *ht, void *key) {
|
|||
|
||||
void hashtable_unset_deferred(Hashtable *ht, void *key, ListContainer **list) {
|
||||
assert(ht != NULL);
|
||||
|
||||
ListContainer *c = create_element((void**)list, sizeof(ListContainer));
|
||||
|
||||
if(ht->copy_func) {
|
||||
ht->copy_func(&c->data, key);
|
||||
} else {
|
||||
c->data = key;
|
||||
}
|
||||
ht->copy_func(&c->data, key);
|
||||
}
|
||||
|
||||
void hashtable_unset_deferred_now(Hashtable *ht, ListContainer **list) {
|
||||
|
@ -295,9 +407,7 @@ bool hashtable_cmpfunc_string(void *str1, void *str2) {
|
|||
}
|
||||
|
||||
hash_t hashtable_hashfunc_string(void *vstr) {
|
||||
const char *str = vstr;
|
||||
size_t len = strlen(str);
|
||||
return adler32(0, (const Bytef*)str, (uInt)len);
|
||||
return crc32str(0, (const char*)vstr);
|
||||
}
|
||||
|
||||
void hashtable_copyfunc_string(void **dst, void *src) {
|
||||
|
@ -337,10 +447,44 @@ void* hashtable_iter_free_data(void *key, void *data, void *arg) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
bool hashtable_cmpfunc_ptr(void *p1, void *p2) {
|
||||
return p1 == p2;
|
||||
}
|
||||
|
||||
void hashtable_copyfunc_ptr(void **dst, void *src) {
|
||||
*dst = src;
|
||||
}
|
||||
|
||||
/*
|
||||
* Diagnostic functions
|
||||
*/
|
||||
|
||||
void hashtable_get_stats(Hashtable *ht, HashtableStats *stats) {
|
||||
assert(ht != NULL);
|
||||
assert(stats != NULL);
|
||||
|
||||
memset(stats, 0, sizeof(HashtableStats));
|
||||
|
||||
for(size_t i = 0; i < ht->table_size; ++i) {
|
||||
int elems = 0;
|
||||
|
||||
for(HashtableElement *e = ht->table[i]; e; e = e->next) {
|
||||
++elems;
|
||||
++stats->num_elements;
|
||||
}
|
||||
|
||||
if(elems > 1) {
|
||||
stats->collisions += elems - 1;
|
||||
}
|
||||
|
||||
if(!elems) {
|
||||
++stats->free_buckets;
|
||||
} else if(elems > stats->max_per_bucket) {
|
||||
stats->max_per_bucket = elems;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t hashtable_get_approx_overhead(Hashtable *ht) {
|
||||
size_t o = sizeof(Hashtable) + sizeof(HashtableElement*) * ht->table_size;
|
||||
|
||||
|
@ -352,35 +496,20 @@ size_t hashtable_get_approx_overhead(Hashtable *ht) {
|
|||
}
|
||||
|
||||
void hashtable_print_stringkeys(Hashtable *ht) {
|
||||
int free_buckets = 0;
|
||||
int max_elems = 0;
|
||||
int total = 0;
|
||||
int collisions = 0;
|
||||
HashtableStats stats;
|
||||
hashtable_get_stats(ht, &stats);
|
||||
|
||||
log_debug("------ %p:", (void*)ht);
|
||||
for(size_t i = 0; i < ht->table_size; ++i) {
|
||||
int elems = 0;
|
||||
log_debug("[bucket %lu] %p", (unsigned long)i, (void*)ht->table[i]);
|
||||
|
||||
for(HashtableElement *e = ht->table[i]; e; e = e->next) {
|
||||
log_debug(" -- %s (%lu): %p", (char*)e->key, (unsigned long)e->hash, e->data);
|
||||
++elems;
|
||||
++total;
|
||||
}
|
||||
|
||||
if(elems > 1) {
|
||||
collisions += elems - 1;
|
||||
}
|
||||
|
||||
if(!elems) {
|
||||
++free_buckets;
|
||||
} else if(elems > max_elems) {
|
||||
max_elems = elems;
|
||||
}
|
||||
}
|
||||
|
||||
log_debug("%i total elements, %i unused buckets, %i collisions, max %i elems per bucket, %lu approx overhead",
|
||||
total, free_buckets, collisions, max_elems,
|
||||
stats.num_elements, stats.free_buckets, stats.collisions, stats.max_per_bucket,
|
||||
(unsigned long int)hashtable_get_approx_overhead(ht));
|
||||
}
|
||||
|
||||
|
|
|
@ -15,10 +15,24 @@
|
|||
|
||||
#include "list.h"
|
||||
|
||||
#define HT_MIN_SIZE 15
|
||||
#define HT_MAX_SIZE 4095
|
||||
#define HT_COLLISION_TOLERANCE 5
|
||||
#define HT_DYNAMIC_SIZE 0
|
||||
#define HT_RESIZE_STEP 1
|
||||
|
||||
typedef struct Hashtable Hashtable;
|
||||
typedef struct HashtableIterator HashtableIterator;
|
||||
typedef struct HashtableStats HashtableStats;
|
||||
typedef uint32_t hash_t;
|
||||
|
||||
struct HashtableStats {
|
||||
unsigned int free_buckets;
|
||||
unsigned int collisions;
|
||||
unsigned int max_per_bucket;
|
||||
unsigned int num_elements;
|
||||
};
|
||||
|
||||
typedef bool (*HTCmpFunc)(void *key1, void *key2);
|
||||
typedef hash_t (*HTHashFunc)(void *key);
|
||||
typedef void (*HTCopyFunc)(void **dstkey, void *srckey);
|
||||
|
@ -52,11 +66,14 @@ void hashtable_unset_string(Hashtable *ht, const char *key);
|
|||
void hashtable_unset_deferred_string(Hashtable *ht, const char *key);
|
||||
|
||||
void* hashtable_iter_free_data(void *key, void *data, void *arg);
|
||||
bool hashtable_cmpfunc_ptr(void *p1, void *p2);
|
||||
void hashtable_copyfunc_ptr(void **dst, void *src);
|
||||
|
||||
int hashtable_test(void);
|
||||
|
||||
void hashtable_print_stringkeys(Hashtable *ht);
|
||||
size_t hashtable_get_approx_overhead(Hashtable *ht);
|
||||
void hashtable_get_stats(Hashtable *ht, HashtableStats *stats);
|
||||
|
||||
void hashtable_lock(Hashtable *ht);
|
||||
void hashtable_unlock(Hashtable *ht);
|
||||
|
|
|
@ -130,6 +130,9 @@ int main(int argc, char **argv) {
|
|||
const char *replay_path = NULL;
|
||||
int replay_stage = 0;
|
||||
|
||||
init_paths();
|
||||
init_log();
|
||||
|
||||
if(argc >= 2 && !strcmp(argv[1], "replay")) {
|
||||
if(argc < 3) {
|
||||
tsfprintf(stderr, "Usage: %s replay /path/to/replay.tsr [stage num]\n", argv[0]);
|
||||
|
@ -147,8 +150,6 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
}
|
||||
|
||||
init_paths();
|
||||
init_log();
|
||||
log_args(argc, argv);
|
||||
|
||||
if(run_tests()) {
|
||||
|
|
|
@ -51,10 +51,6 @@ troll2:
|
|||
if(info) {
|
||||
stage_loop(info);
|
||||
} else {
|
||||
for(StageInfo *s = stages; s->type == STAGE_STORY; ++s) {
|
||||
s->procs->preload();
|
||||
}
|
||||
|
||||
for(StageInfo *s = stages; s->type == STAGE_STORY; ++s) {
|
||||
stage_loop(s);
|
||||
}
|
||||
|
|
30
src/replay.c
30
src/replay.c
|
@ -189,14 +189,10 @@ static int replay_write_stage(ReplayStage *stg, SDL_RWops *file) {
|
|||
}
|
||||
|
||||
int replay_write(Replay *rpy, SDL_RWops *file, bool compression) {
|
||||
uint8_t *u8_p;
|
||||
uint16_t version = REPLAY_STRUCT_VERSION;
|
||||
int i, j;
|
||||
|
||||
for(u8_p = replay_magic_header; *u8_p; ++u8_p) {
|
||||
SDL_WriteU8(file, *u8_p);
|
||||
}
|
||||
|
||||
uint16_t version = REPLAY_STRUCT_VERSION;
|
||||
SDL_RWwrite(file, replay_magic_header, sizeof(replay_magic_header), 1);
|
||||
|
||||
if(compression) {
|
||||
version |= REPLAY_VERSION_COMPRESSION_BIT;
|
||||
|
@ -276,12 +272,14 @@ static void replay_read_string(SDL_RWops *file, char **ptr) {
|
|||
}
|
||||
|
||||
static int replay_read_header(Replay *rpy, SDL_RWops *file, int64_t filesize, size_t *ofs) {
|
||||
for(uint8_t *u8_p = replay_magic_header; *u8_p; ++u8_p) {
|
||||
++(*ofs);
|
||||
if(SDL_ReadU8(file) != *u8_p) {
|
||||
log_warn("Incorrect header");
|
||||
return false;
|
||||
}
|
||||
uint8_t header[sizeof(replay_magic_header)];
|
||||
(*ofs) += sizeof(header);
|
||||
|
||||
SDL_RWread(file, header, sizeof(header), 1);
|
||||
|
||||
if(memcmp(header, replay_magic_header, sizeof(header))) {
|
||||
log_warn("Incorrect header");
|
||||
return false;
|
||||
}
|
||||
|
||||
CHECKPROP(rpy->version = SDL_ReadLE16(file), u);
|
||||
|
@ -590,14 +588,10 @@ int replay_test(void) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
uint8_t *u8_p, *buf = malloc(sz + headsz);
|
||||
uint8_t *buf = malloc(sz + headsz);
|
||||
SDL_RWops *handle = SDL_RWFromMem(buf, sz + headsz);
|
||||
|
||||
// SDL_RWwrite(handle, replay_magic_header, 1, sizeof(replay_magic_header));
|
||||
|
||||
for(u8_p = replay_magic_header; *u8_p; ++u8_p) {
|
||||
SDL_WriteU8(handle, *u8_p);
|
||||
}
|
||||
SDL_RWwrite(handle, replay_magic_header, sizeof(replay_magic_header), 1);
|
||||
|
||||
SDL_WriteLE16(handle, REPLAY_STRUCT_VERSION);
|
||||
SDL_WriteLE16(handle, 4);
|
||||
|
|
|
@ -57,7 +57,7 @@ void fontrenderer_draw(FontRenderer *f, const char *text,TTF_Font *font) {
|
|||
assert(surf != NULL);
|
||||
|
||||
if(surf->w > FONTREN_MAXW || surf->h > FONTREN_MAXH) {
|
||||
log_fatal("Text drawn (%dx%d) is too big for the internal buffer (%dx%d).", surf->pitch, surf->h, FONTREN_MAXW, FONTREN_MAXH);
|
||||
log_fatal("Text drawn (\"%s\" %dx%d) is too big for the internal buffer (%dx%d).", text, surf->w, surf->h, FONTREN_MAXW, FONTREN_MAXH);
|
||||
}
|
||||
f->tex.w = surf->w;
|
||||
f->tex.h = surf->h;
|
||||
|
|
|
@ -18,9 +18,9 @@ typedef enum {
|
|||
} Alignment;
|
||||
|
||||
|
||||
// Size of the buffer used by the font renderer. No text larger than this can be drawn.
|
||||
// Size of the buffer used by the font renderer. No text larger than this can be drawn.
|
||||
enum {
|
||||
FONTREN_MAXW = 512,
|
||||
FONTREN_MAXW = 1024,
|
||||
FONTREN_MAXH = 512
|
||||
};
|
||||
|
||||
|
|
|
@ -127,6 +127,8 @@ static int load_resource_async_thread(void *vdata) {
|
|||
static Resource* load_resource_finish(void *opaque, ResourceHandler *handler, const char *path, const char *name, char *allocated_path, char *allocated_name, ResourceFlags flags);
|
||||
|
||||
bool resource_sdl_event(SDL_Event *evt) {
|
||||
assert(SDL_ThreadID() == main_thread_id);
|
||||
|
||||
if(evt->type != sdlevent_finalize_load) {
|
||||
return false;
|
||||
}
|
||||
|
@ -134,7 +136,6 @@ bool resource_sdl_event(SDL_Event *evt) {
|
|||
ResourceAsyncLoadData *data = evt->user.data1;
|
||||
|
||||
if(!data) {
|
||||
free(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -333,30 +334,28 @@ void preload_resources(ResourceType type, ResourceFlags flags, const char *first
|
|||
}
|
||||
|
||||
void init_resources(void) {
|
||||
// hashtable sizes were carefully pulled out of my ass to reduce collisions a bit
|
||||
|
||||
register_handler(
|
||||
RES_TEXTURE, TEX_PATH_PREFIX, load_texture_begin, load_texture_end, (ResourceUnloadFunc)free_texture, NULL, texture_path, check_texture_path, 227
|
||||
RES_TEXTURE, TEX_PATH_PREFIX, load_texture_begin, load_texture_end, (ResourceUnloadFunc)free_texture, NULL, texture_path, check_texture_path, HT_DYNAMIC_SIZE
|
||||
);
|
||||
|
||||
register_handler(
|
||||
RES_ANIM, ANI_PATH_PREFIX, load_animation_begin, load_animation_end, free, NULL, animation_path, check_animation_path, 23
|
||||
RES_ANIM, ANI_PATH_PREFIX, load_animation_begin, load_animation_end, free, NULL, animation_path, check_animation_path, HT_DYNAMIC_SIZE
|
||||
);
|
||||
|
||||
register_handler(
|
||||
RES_SHADER, SHA_PATH_PREFIX, load_shader_begin, load_shader_end, unload_shader, NULL, shader_path, check_shader_path, 29
|
||||
RES_SHADER, SHA_PATH_PREFIX, load_shader_begin, load_shader_end, unload_shader, NULL, shader_path, check_shader_path, HT_DYNAMIC_SIZE
|
||||
);
|
||||
|
||||
register_handler(
|
||||
RES_MODEL, MDL_PATH_PREFIX, load_model_begin, load_model_end, unload_model, NULL, model_path, check_model_path, 17
|
||||
RES_MODEL, MDL_PATH_PREFIX, load_model_begin, load_model_end, unload_model, NULL, model_path, check_model_path, HT_DYNAMIC_SIZE
|
||||
);
|
||||
|
||||
register_handler(
|
||||
RES_SFX, SFX_PATH_PREFIX, load_sound_begin, load_sound_end, unload_sound, NULL, sound_path, check_sound_path, 16
|
||||
RES_SFX, SFX_PATH_PREFIX, load_sound_begin, load_sound_end, unload_sound, NULL, sound_path, check_sound_path, HT_DYNAMIC_SIZE
|
||||
);
|
||||
|
||||
register_handler(
|
||||
RES_BGM, BGM_PATH_PREFIX, load_music_begin, load_music_end, unload_music, NULL, music_path, check_music_path, 16
|
||||
RES_BGM, BGM_PATH_PREFIX, load_music_begin, load_music_end, unload_music, NULL, music_path, check_music_path, HT_DYNAMIC_SIZE
|
||||
);
|
||||
|
||||
main_thread_id = SDL_ThreadID();
|
||||
|
|
|
@ -533,7 +533,8 @@ void elly_unbound(Boss *b, int t) {
|
|||
|
||||
AT(100) {
|
||||
int i;
|
||||
Enemy *e, *last = NULL, *first, *middle;
|
||||
Enemy *e, *last = NULL, *first = NULL, *middle = NULL;
|
||||
|
||||
for(i = 0; i < 6; i++) {
|
||||
e = create_enemy3c(b->pos, ENEMY_IMMUNE, Baryon, baryon_unfold, 1.5*cexp(2.0*I*M_PI/6*i), i != 0 ? add_ref(last) : 0, i);
|
||||
if(i == 0)
|
||||
|
|
57
src/util.c
57
src/util.c
|
@ -491,3 +491,60 @@ static void png_warning_handler(png_structp png_ptr, png_const_charp warning_msg
|
|||
void png_setup_error_handlers(png_structp png) {
|
||||
png_set_error_fn(png, NULL, png_error_handler, png_warning_handler);
|
||||
}
|
||||
|
||||
static uint32_t crc32_tab[] = {
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
|
||||
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
|
||||
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
|
||||
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
|
||||
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
|
||||
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
|
||||
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
|
||||
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
|
||||
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
|
||||
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
|
||||
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
|
||||
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
|
||||
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
|
||||
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
|
||||
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
|
||||
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
|
||||
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
|
||||
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
|
||||
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
|
||||
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
|
||||
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
|
||||
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||
};
|
||||
|
||||
uint32_t crc32str(uint32_t crc, const char *str) {
|
||||
const uint8_t *p = (uint8_t*)str;
|
||||
crc = crc ^ ~0U;
|
||||
|
||||
while(*p) {
|
||||
crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
|
||||
}
|
||||
|
||||
return crc ^ ~0U;
|
||||
}
|
||||
|
|
|
@ -116,6 +116,8 @@ void tsfprintf(FILE *out, const char *restrict fmt, ...) __attribute__((format(p
|
|||
|
||||
int getenvint(const char *v) __attribute__((pure));
|
||||
void png_setup_error_handlers(png_structp png);
|
||||
uint32_t crc32str(uint32_t crc, const char *str);
|
||||
|
||||
noreturn void _ts_assert_fail(const char *cond, const char *func, const char *file, int line, bool use_log);
|
||||
|
||||
#undef assert
|
||||
|
|
Loading…
Reference in a new issue