diff --git a/text_rendering/ren.c b/text_rendering/ren.c index 8637b2c..1c3134d 100644 --- a/text_rendering/ren.c +++ b/text_rendering/ren.c @@ -58,7 +58,7 @@ const char * ren_err_msg[] = { }; -#define ELEM(x...) [x] = #x, +#define ELEM(x) [x] = #x, const char *glerr[] = { ELEM(GL_INVALID_ENUM) ELEM(GL_INVALID_VALUE) @@ -432,12 +432,21 @@ static int ren_draw_font_stack(void) GL_FALSE, sizeof(struct v_text), (void*)sizeof(vec2_i))) - // TODO: implement size and damage tracking on stacks - GL(glBufferData( - GL_ARRAY_BUFFER, - ren.font_stack.idx*sizeof(struct v_text), - ren.font_stack.items, - GL_DYNAMIC_DRAW)) + if (vtstack_changed(&ren.font_stack)) { + if (vtstack_size_changed(&ren.font_stack)) { + GL(glBufferData( + GL_ARRAY_BUFFER, + ren.font_stack.idx*sizeof(struct v_text), + ren.font_stack.items, + GL_DYNAMIC_DRAW)) + } else { + GL(glBufferSubData( + GL_ARRAY_BUFFER, + 0, + ren.font_stack.idx*sizeof(struct v_text), + ren.font_stack.items)) + } + } GL(glDrawArrays(GL_TRIANGLES, 0, ren.font_stack.idx)) GL(glDisableVertexAttribArray(REN_VERTEX_IDX)) @@ -478,12 +487,21 @@ static int ren_draw_box_stack(void) GL_TRUE, sizeof(struct v_col), (void*)sizeof(vec2_i))) - // TODO: implement size and damage tracking on stacks - GL(glBufferData( - GL_ARRAY_BUFFER, - ren.box_stack.idx*sizeof(struct v_col), - ren.box_stack.items, - GL_DYNAMIC_DRAW)) + if(vcstack_changed(&ren.box_stack)) { + if (vcstack_size_changed(&ren.box_stack)) { + GL(glBufferData( + GL_ARRAY_BUFFER, + ren.box_stack.idx*sizeof(struct v_col), + ren.box_stack.items, + GL_DYNAMIC_DRAW)) + } else { + GL(glBufferSubData( + GL_ARRAY_BUFFER, + 0, + ren.box_stack.idx*sizeof(struct v_col), + ren.box_stack.items)) + } + } GL(glDrawArrays(GL_TRIANGLES, 0, ren.box_stack.idx)) GL(glDisableVertexAttribArray(REN_VERTEX_IDX)) diff --git a/text_rendering/stack.h b/text_rendering/stack.h index 63cfd25..816565c 100644 --- a/text_rendering/stack.h +++ b/text_rendering/stack.h @@ -3,17 +3,38 @@ #define STACK_STEP 8 +#define STACK_SALT 0xbabb0cac + +// FIXME: find a way to not re-hash the whole stack when removing one item + +// incremental hash for every grow +#define HASH(p, s, h) \ +{ \ + unsigned char *v = (unsigned char *)(p); \ + for (int x = (s); x; x--) { \ + (h) += v[x-1]; \ + (h) += (h) << 10; \ + (h) ^= (h) >> 6; \ + } \ + (h) += (h) << 3; \ + (h) ^= (h) >> 11; \ + (h) += (h) << 15; \ +} // TODO: add a rolling hash #define STACK_DECL(stackname, type) \ struct stackname { \ type *items; \ - int size, idx; \ + int size, idx, old_idx; \ + unsigned int hash, old_hash; \ }; \ \ \ -struct stackname stackname##_init(void) { return (struct stackname){0}; } \ +struct stackname stackname##_init(void) \ +{ \ + return (struct stackname){0, .hash = STACK_SALT}; \ +} \ \ \ int stackname##_grow(struct stackname *stack, int step) \ @@ -37,6 +58,7 @@ int stackname##_push(struct stackname *stack, type *e) \ if (stackname##_grow(stack, STACK_STEP)) \ return -1; \ stack->items[stack->idx++] = *e; \ + HASH(e, sizeof(type), stack->hash); \ return 0; \ } \ \ @@ -45,6 +67,8 @@ type stackname##_pop(struct stackname *stack) \ { \ if (!stack || stack->idx == 0 || stack->size == 0) \ return (type){0}; \ + stack->hash = STACK_SALT; \ + HASH(stack->items, sizeof(type)*(stack->idx-1), stack->hash); \ return stack->items[stack->idx--]; \ } \ \ @@ -53,11 +77,30 @@ int stackname##_clear(struct stackname *stack) \ { \ if (!stack) \ return -1; \ + stack->old_idx = stack->idx; \ + stack->old_hash = stack->hash; \ + stack->hash = STACK_SALT; \ stack->idx = 0; \ return 0; \ } \ \ \ +int stackname##_changed(struct stackname *stack) \ +{ \ + if (!stack) \ + return -1; \ + return stack->hash != stack->old_hash; \ +} \ +\ +\ +int stackname##_size_changed(struct stackname *stack) \ +{ \ + if (!stack) \ + return -1; \ + return stack->size != stack->old_idx; \ +} \ +\ +\ int stackname##_free(struct stackname *stack) \ { \ if (stack) { \ @@ -68,5 +111,4 @@ int stackname##_free(struct stackname *stack) \ return 0; \ } \ - #endif diff --git a/ugui.c b/ugui.c index 270e49a..7e09c0e 100644 --- a/ugui.c +++ b/ugui.c @@ -105,6 +105,7 @@ static ug_style_t style_cache = {0}; } \ +// FIXME: is it really necessary to clear (memset) the stack #define RESET_STACK(S) \ { \ memset(S.items, 0, S.idx*sizeof(*(S.items))); \