diff --git a/include/parts.h b/include/parts.h index a294d96..fe28f98 100644 --- a/include/parts.h +++ b/include/parts.h @@ -25,6 +25,7 @@ struct string; // parts.c bool PE_Init(void); void PE_Update(int passed_time, bool message_window_show); +void PE_UpdateComponent(int passed_time); void PE_UpdateParts(int passed_time, bool is_skip, bool message_window_show); void PE_SetDelegateIndex(int parts_no, int delegate_index); int PE_GetDelegateIndex(int parts_no); diff --git a/src/hll/GUIEngine.c b/src/hll/GUIEngine.c index 938855a..26d111e 100644 --- a/src/hll/GUIEngine.c +++ b/src/hll/GUIEngine.c @@ -39,7 +39,6 @@ static void GUIEngine_ModuleFini(void) //static void GUIEngine_PushController(void); //static void GUIEngine_PopController(ref array EraseNumberList); //static void GUIEngine_UpdateComponent(possibly_unused int passed_time) -HLL_QUIET_UNIMPLEMENTED(, void, GUIEngine, UpdateComponent, int passed_time); //static void GUIEngine_BeginInput(void); //static void GUIEngine_EndInput(void); //static void GUIEngine_UpdateInputState(int PassedTime); @@ -510,7 +509,7 @@ HLL_LIBRARY(GUIEngine, HLL_EXPORT(IsExist, PE_IsExist), HLL_TODO_EXPORT(PushController, GUIEngine_PushController), HLL_TODO_EXPORT(PopController, GUIEngine_PopController), - HLL_EXPORT(UpdateComponent, GUIEngine_UpdateComponent), + HLL_EXPORT(UpdateComponent, PE_UpdateComponent), HLL_EXPORT(BeginInput, PE_BeginInput), HLL_EXPORT(EndInput, PE_EndInput), HLL_EXPORT(UpdateInputState, PE_UpdateInputState), diff --git a/src/parts/debug.c b/src/parts/debug.c index 6e2c9a5..03ff95a 100644 --- a/src/parts/debug.c +++ b/src/parts/debug.c @@ -164,9 +164,6 @@ static void parts_print_state(struct parts_state *state, int indent) struct parts_common *com = &state->common; - indent_printf(indent, "texture = "); - gfx_print_texture(&state->common.texture, indent); - printf(",\n"); indent_printf(indent, "dims = {w=%d,h=%d},\n", state->common.w, state->common.h); indent_printf(indent, "origin_offset = "); gfx_print_point(&com->origin_offset); printf(",\n"); indent_printf(indent, "hitbox = "); gfx_print_rectangle(&com->hitbox); printf(",\n"); @@ -263,6 +260,40 @@ static void parts_print_motion(struct parts_motion *motion, int indent) indent_printf(indent, "}"); } +static void parts_print_params(struct parts_params *global, struct parts_params *local, int indent) +{ + printf("{\n"); + indent++; + + indent_printf(indent, "z = %d (%d),\n", global->z, local->z); + indent_printf(indent, "pos = "); + gfx_print_point(&global->pos); + printf(" ("); + gfx_print_point(&local->pos); + printf("),\n"); + indent_printf(indent, "show = %s (%s),\n", global->show ? "true" : "false", + local->show ? "true" : "false"); + indent_printf(indent, "alpha = %u (%u),\n", (unsigned)global->alpha, (unsigned)local->alpha); + indent_printf(indent, "scale = {x=%f,y=%f} ({x=%f,y=%f}),\n", global->scale.x, global->scale.y, + local->scale.x, local->scale.y); + indent_printf(indent, "rotation = {x=%f,y=%f,z=%f} ({x=%f,y=%f,z=%f}),\n", + global->rotation.x, global->rotation.y, global->rotation.z, + local->rotation.x, local->rotation.y, local->rotation.z); + indent_printf(indent, "add_color = "); + gfx_print_color(&global->add_color); + printf(" ("); + gfx_print_color(&local->add_color); + printf("),\n"); + indent_printf(indent, "multiply_color = "); + gfx_print_color(&global->multiply_color); + printf(" ("); + gfx_print_color(&local->multiply_color); + printf("),\n"); + + indent--; + indent_printf(indent, "}"); +} + static void _parts_print(struct parts *parts, int indent) { static const char *state_names[PARTS_NR_STATES] = { @@ -280,30 +311,33 @@ static void _parts_print(struct parts *parts, int indent) // print states indent_printf(indent, "state = %s,\n", state); for (int i = 0; i < PARTS_NR_STATES; i++) { + if (parts->states[i].type == PARTS_UNINITIALIZED && i != parts->state) + continue; indent_printf(indent, "state[%s] = ", state_names[i]); parts_print_state(&parts->states[i], indent); printf(",\n"); } + // print params + indent_printf(indent, "local = "); + parts_print_params(&parts->global, &parts->local, indent); + printf(",\n"); + // print misc. data - indent_printf(indent, "delegate_index = %d,\n", parts->delegate_index); + if (parts->delegate_index >= 0) + indent_printf(indent, "delegate_index = %d,\n", parts->delegate_index); indent_printf(indent, "sprite_deform = %d,\n", parts->sprite_deform); indent_printf(indent, "clickable = %s,\n", parts->clickable ? "true" : "false"); - indent_printf(indent, "on_cursor_sound = %d,\n", parts->on_cursor_sound); - indent_printf(indent, "on_click_sound = %d,\n", parts->on_click_sound); + if (parts->on_cursor_sound >= 0) + indent_printf(indent, "on_cursor_sound = %d,\n", parts->on_cursor_sound); + if (parts->on_click_sound >= 0) + indent_printf(indent, "on_click_sound = %d,\n", parts->on_click_sound); indent_printf(indent, "origin_mode = %d,\n", parts->origin_mode); - indent_printf(indent, "parent = %d,\n", parts->parent); - indent_printf(indent, "linked_to = %d,\n", parts->linked_to); - indent_printf(indent, "linked_from = %d,\n", parts->linked_from); - indent_printf(indent, "alpha = %u,\n", (unsigned)parts->alpha); - indent_printf(indent, "pos = "); gfx_print_point(&parts->pos); printf(",\n"); - indent_printf(indent, "z = %d,\n", parts->z); - indent_printf(indent, "show = %s,\n", parts->show ? "true" : "false"); - indent_printf(indent, "scale = {x=%f,y=%f},\n", parts->scale.x, parts->scale.y); - indent_printf(indent, "rotation = {x=%f,y=%f,z=%f},\n", - parts->rotation.x, parts->rotation.y, parts->rotation.z); - indent_printf(indent, "add_color = "); gfx_print_color(&parts->add_color); printf(",\n"); - indent_printf(indent, "multiply_color = "); gfx_print_color(&parts->multiply_color); printf(",\n"); + indent_printf(indent, "parent = %d,\n", parts->parent ? parts->parent->no : -1); + if (parts->linked_to >= 0) + indent_printf(indent, "linked_to = %d,\n", parts->linked_to); + if (parts->linked_from >= 0) + indent_printf(indent, "linked_from = %d,\n", parts->linked_from); indent_printf(indent, "draw_filter = %d,\n", parts->draw_filter); // print motion data @@ -348,7 +382,7 @@ void parts_engine_print(void) { struct parts *parts; PARTS_LIST_FOREACH(parts) { - if (parts->parent < 0) + if (!parts->parent) parts_print(parts); } } @@ -376,7 +410,7 @@ static void parts_cmd_parts(unsigned nr_args, char **args) static void parts_list_print(struct parts *parts, int indent) { - indent_printf(indent, parts->show ? "+ " : "- "); + indent_printf(indent, parts->local.show ? "+ " : "- "); printf("parts %d ", parts->no); struct parts_state *state = &parts->states[parts->state]; switch (state->type) { @@ -443,7 +477,7 @@ static void parts_list_print(struct parts *parts, int indent) } } - printf(" @ z=%d (%d)\n", parts->global_z, parts->z); + printf(" @ z=%d (%d)\n", parts->global.z, parts->local.z); struct parts *child; PARTS_FOREACH_CHILD(child, parts) { @@ -455,7 +489,7 @@ static void parts_cmd_parts_list(unsigned nr_args, char **args) { struct parts *parts; PARTS_LIST_FOREACH(parts) { - if (parts->parent < 0) + if (!parts->parent) parts_list_print(parts, 0); } } diff --git a/src/parts/input.c b/src/parts/input.c index c296325..767707b 100644 --- a/src/parts/input.c +++ b/src/parts/input.c @@ -180,11 +180,9 @@ bool PE_IsCursorIn(int parts_no, int mouse_x, int mouse_y, int state) // TODO: this could be cached Rectangle hitbox = parts->states[state].common.hitbox; - struct parts *parent = parts; - while (parent->parent >= 0) { - parent = parts_get(parent->parent); - hitbox.x += parent->pos.x; - hitbox.y += parent->pos.y; + for (struct parts *parent = parts->parent; parent; parent = parent->parent) { + hitbox.x += parent->local.pos.x; + hitbox.y += parent->local.pos.y; } Point mouse_pos = { mouse_x, mouse_y }; diff --git a/src/parts/parts.c b/src/parts/parts.c index 012a5e3..5164935 100644 --- a/src/parts/parts.c +++ b/src/parts/parts.c @@ -27,27 +27,31 @@ #include "parts_internal.h" struct parts_list parts_list = TAILQ_HEAD_INITIALIZER(parts_list); +static struct parts_list dirty_list = TAILQ_HEAD_INITIALIZER(dirty_list); static struct hash_table *parts_table = NULL; +#define PARTS_PARAMS_INITIALIZER (struct parts_params) { \ + .z = 1, \ + .pos = { 0, 0 }, \ + .show = true, \ + .alpha = 255, \ + .scale = { 1.0f, 1.0f }, \ + .rotation = { 0.0f, 0.0f, 0.0f }, \ + .add_color = { 0, 0, 0, 0 }, \ + .multiply_color = { 255, 255, 255, 255 } \ +} + static void parts_init(struct parts *parts) { + parts->local = PARTS_PARAMS_INITIALIZER; + parts->global = PARTS_PARAMS_INITIALIZER; parts->delegate_index = -1; parts->on_cursor_sound = -1; parts->on_click_sound = -1; parts->origin_mode = 1; - parts->z = 1; - parts->global_z = 1; - parts->show = true; - parts->alpha = 255; - parts->parent = -1; + parts->pending_parent = -1; parts->linked_to = -1; parts->linked_from = -1; - parts->scale.x = 1.0; - parts->scale.y = 1.0; - parts->rotation.x = 0.0; - parts->rotation.y = 0.0; - parts->rotation.z = 0.0; - parts->multiply_color = (SDL_Color) { 255, 255, 255, 255 }; TAILQ_INIT(&parts->children); TAILQ_INIT(&parts->motion); } @@ -59,11 +63,19 @@ static struct parts *parts_alloc(void) return parts; } +static void parts_component_dirty(struct parts *parts) +{ + if (parts->dirty) + return; + parts->dirty = true; + TAILQ_INSERT_TAIL(&dirty_list, parts, dirty_list_entry); +} + static void parts_list_insert(struct parts *parts) { struct parts *p; PARTS_LIST_FOREACH(p) { - if (p->global_z > parts->global_z) { + if (p->global.z > parts->global.z) { TAILQ_INSERT_BEFORE(p, parts, parts_list_entry); parts_engine_dirty(); return; @@ -85,33 +97,6 @@ static void parts_list_resort(struct parts *parts) parts_list_insert(parts); } -static void parts_update_global_z(struct parts *parts, int parent_z) -{ - parts->global_z = parent_z + parts->z; - parts_list_resort(parts); - - struct parts *child; - PARTS_FOREACH_CHILD(child, parts) { - parts_update_global_z(child, parts->global_z); - } -} - -static void parts_set_parent(struct parts *child, struct parts *parent) -{ - if (child->parent >= 0) { - struct parts *old_parent = parts_get(child->parent); - TAILQ_REMOVE(&old_parent->children, child, child_list_entry); - } - if (parent) { - TAILQ_INSERT_TAIL(&parent->children, child, child_list_entry); - child->parent = parent->no; - parts_update_global_z(child, parent->global_z); - } else { - child->parent = -1; - parts_update_global_z(child, 0); - } -} - struct parts *parts_try_get(int parts_no) { struct ht_slot *slot = ht_put_int(parts_table, parts_no, NULL); @@ -309,13 +294,13 @@ static void parts_common_recalculate_hitbox(struct parts *parts, struct parts_co SDL_IntersectRect(&r, &common->surface_area, &common->hitbox); common->origin_offset.x -= common->surface_area.x; common->origin_offset.y -= common->surface_area.y; - common->hitbox.x += parts->pos.x + common->origin_offset.x; - common->hitbox.y += parts->pos.y + common->origin_offset.y; + common->hitbox.x += parts->local.pos.x + common->origin_offset.x; + common->hitbox.y += parts->local.pos.y + common->origin_offset.y; } else { common->origin_offset = calculate_offset(parts->origin_mode, common->w, common->h); common->hitbox = (Rectangle) { - .x = parts->pos.x + common->origin_offset.x, - .y = parts->pos.y + common->origin_offset.y, + .x = parts->local.pos.x + common->origin_offset.x, + .y = parts->local.pos.y + common->origin_offset.y, .w = common->w, .h = common->h, }; @@ -329,11 +314,189 @@ static void parts_recalculate_hitbox(struct parts *parts) } } +static void parts_update_global_pos(struct parts *parts, Point parent_pos) +{ + parts->global.pos = (Point) { + parent_pos.x + parts->local.pos.x, + parent_pos.y + parts->local.pos.y + }; + + struct parts *child; + PARTS_FOREACH_CHILD(child, parts) { + parts_update_global_pos(child, parts->global.pos); + } +} + void parts_set_pos(struct parts *parts, Point pos) { - parts->pos.x = pos.x; - parts->pos.y = pos.y; + parts->local.pos.x = pos.x; + parts->local.pos.y = pos.y; parts_recalculate_hitbox(parts); + parts_update_global_pos(parts, parts->parent ? parts->parent->global.pos : (Point){0,0}); + parts_dirty(parts); +} + +static void parts_update_global_z(struct parts *parts, int parent_z) +{ + parts->global.z = parent_z + parts->local.z; + parts_list_resort(parts); + + struct parts *child; + PARTS_FOREACH_CHILD(child, parts) { + parts_update_global_z(child, parts->global.z); + } +} + +void parts_set_z(struct parts *parts, int z) +{ + if (parts->local.z == z) + return; + + parts->local.z = z; + parts_update_global_z(parts, parts->parent ? parts->parent->global.z : 0); + parts_dirty(parts); +} + +static void parts_update_global_show(struct parts *parts, bool parent_show) +{ + parts->global.show = parent_show && parts->local.show; + + struct parts *child; + PARTS_FOREACH_CHILD(child, parts) { + parts_update_global_show(child, parts->global.show); + } +} + +void parts_set_show(struct parts *parts, bool show) +{ + if (parts->local.show == show) + return; + + parts->local.show = show; + parts_update_global_show(parts, parts->parent ? parts->parent->global.show : true); + parts_dirty(parts); +} + +static void parts_update_global_alpha(struct parts *parts, int parent_alpha) +{ + parts->global.alpha = parent_alpha * (parts->local.alpha / 255.0f); + + struct parts *child; + PARTS_FOREACH_CHILD(child, parts) { + parts_update_global_alpha(child, parts->global.alpha); + } +} + +void parts_set_alpha(struct parts *parts, int alpha) +{ + parts->local.alpha = max(0, min(255, alpha)); + parts_update_global_alpha(parts, parts->parent ? parts->parent->global.alpha : 255); + parts_dirty(parts); +} + +static void parts_update_global_add_color(struct parts *parts, SDL_Color parent_color) +{ + parts->global.add_color = (SDL_Color) { + parent_color.r * (parts->local.add_color.r / 255.0f), + parent_color.g * (parts->local.add_color.g / 255.0f), + parent_color.b * (parts->local.add_color.b / 255.0f), + 0 + }; + + struct parts *child; + PARTS_FOREACH_CHILD(child, parts) { + parts_update_global_add_color(child, parts->global.add_color); + } +} + +void parts_set_add_color(struct parts *parts, SDL_Color color) +{ + parts->local.add_color = color; + parts_update_global_add_color(parts, parts->parent ? parts->parent->global.add_color + : (SDL_Color){0,0,0,0}); + parts_dirty(parts); +} + +static void parts_update_global_multiply_color(struct parts *parts, SDL_Color parent_color) +{ + parts->global.multiply_color = (SDL_Color) { + parent_color.r * (parts->local.multiply_color.r / 255.0f), + parent_color.g * (parts->local.multiply_color.g / 255.0f), + parent_color.b * (parts->local.multiply_color.b / 255.0f), + 255 + }; + + struct parts *child; + PARTS_FOREACH_CHILD(child, parts) { + parts_update_global_multiply_color(child, parts->global.multiply_color); + } +} + +void parts_set_multiply_color(struct parts *parts, SDL_Color color) +{ + parts->local.multiply_color = color; + parts_update_global_multiply_color(parts, parts->parent ? parts->parent->global.multiply_color + : (SDL_Color){255,255,255,255}); + parts_dirty(parts); +} + +void parts_set_origin_mode(struct parts *parts, int origin_mode) +{ + parts->origin_mode = origin_mode; + parts_recalculate_hitbox(parts); + parts_dirty(parts); +} + +static void parts_update_global_scale_x(struct parts *parts, float parent_scale_x) +{ + parts->global.scale.x = parent_scale_x * parts->local.scale.x; + + struct parts *child; + PARTS_FOREACH_CHILD(child, parts) { + parts_update_global_scale_x(child, parts->global.scale.x); + } +} + +void parts_set_scale_x(struct parts *parts, float mag) +{ + parts->local.scale.x = mag; + parts_recalculate_hitbox(parts); + parts_update_global_scale_x(parts, parts->parent ? parts->parent->global.scale.x : 1.0f); + parts_dirty(parts); +} + +static void parts_update_global_scale_y(struct parts *parts, float parent_scale_y) +{ + parts->global.scale.y = parent_scale_y * parts->local.scale.y; + + struct parts *child; + PARTS_FOREACH_CHILD(child, parts) { + parts_update_global_scale_y(child, parts->global.scale.y); + } +} + +void parts_set_scale_y(struct parts *parts, float mag) +{ + parts->local.scale.y = mag; + parts_recalculate_hitbox(parts); + parts_update_global_scale_y(parts, parts->parent ? parts->parent->global.scale.y : 1.0f); + parts_dirty(parts); +} + +static void parts_update_global_rotate_z(struct parts *parts, float parent_rot_z) +{ + parts->global.rotation.z = parent_rot_z + parts->local.rotation.z; + + struct parts *child; + PARTS_FOREACH_CHILD(child, parts) { + parts_update_global_rotate_z(child, parts->global.rotation.z); + } +} + +void parts_set_rotation_z(struct parts *parts, float rot) +{ + parts->local.rotation.z = rot; + parts_update_global_rotate_z(parts, parts->parent ? parts->parent->global.rotation.z : 0.0f); parts_dirty(parts); } @@ -344,47 +507,6 @@ void parts_set_dims(struct parts *parts, struct parts_common *common, int w, int parts_common_recalculate_hitbox(parts, common); } -void parts_set_origin_mode(struct parts *parts, int origin_mode) -{ - parts->origin_mode = origin_mode; - parts_recalculate_hitbox(parts); -} - -void parts_set_scale_x(struct parts *parts, float mag) -{ - parts->scale.x = mag; - parts_recalculate_hitbox(parts); - parts_dirty(parts); -} - -void parts_set_scale_y(struct parts *parts, float mag) -{ - parts->scale.y = mag; - parts_recalculate_hitbox(parts); - parts_dirty(parts); -} - -void parts_set_rotation_z(struct parts *parts, float rot) -{ - parts->rotation.z = rot; - parts_dirty(parts); -} - -void parts_set_alpha(struct parts *parts, int alpha) -{ - parts->alpha = max(0, min(255, alpha)); - for (int i = 0; i < PARTS_NR_STATES; i++) { - struct parts_state *s = &parts->states[i]; - s->common.texture.alpha_mod = parts->alpha; - if (s->type == PARTS_ANIMATION) { - for (unsigned i = 0; i < s->anim.nr_frames; i++) { - s->anim.frames[i].alpha_mod = parts->alpha; - } - } - } - parts_dirty(parts); -} - static bool parts_set_cg(struct parts *parts, struct cg *cg, int cg_no, struct string *name, int state) { if (!cg) @@ -598,9 +720,13 @@ void parts_release(int parts_no) // break parent/child relationships while (!TAILQ_EMPTY(&parts->children)) { struct parts *child = TAILQ_FIRST(&parts->children); - parts_set_parent(child, NULL); + TAILQ_REMOVE(&parts->children, child, child_list_entry); + child->parent = NULL; + } + if (parts->parent) { + TAILQ_REMOVE(&parts->parent->children, parts, child_list_entry); + parts->parent = NULL; } - parts_set_parent(parts, NULL); parts_list_remove(parts); free(parts); @@ -627,8 +753,88 @@ bool PE_Init(void) return true; } +static bool parts_has_dirty_parent(struct parts *parts) +{ + for (struct parts *parent = parts->parent; parent; parent = parent->parent) { + if (parent->dirty) + return true; + } + return false; +} + +static void parts_combine_params(struct parts_params *parent, struct parts_params *child, + struct parts_params *out) +{ + out->z = parent->z + child->z; + out->pos = (Point) { parent->pos.x + child->pos.x, parent->pos.y + child->pos.y }; + out->show = parent->show && child->show; + out->alpha = parent->alpha * (child->alpha / 255.0f); + out->scale.x = parent->scale.x * child->scale.x; + out->scale.y = parent->scale.y * child->scale.y; + out->rotation.x = parent->rotation.x + child->rotation.x; + out->rotation.y = parent->rotation.y + child->rotation.y; + out->rotation.z = parent->rotation.z + child->rotation.z; + out->add_color.r = parent->add_color.r * (child->add_color.r / 255.0f); + out->add_color.g = parent->add_color.g * (child->add_color.g / 255.0f); + out->add_color.b = parent->add_color.b * (child->add_color.b / 255.0f); + out->multiply_color.r = parent->multiply_color.r * (child->multiply_color.r / 255.0f); + out->multiply_color.g = parent->multiply_color.g * (child->multiply_color.g / 255.0f); + out->multiply_color.b = parent->multiply_color.b * (child->multiply_color.b / 255.0f); +} + +static void parts_update_component(struct parts *parts) +{ + if (parts->parent) { + int old_z = parts->global.z; + parts_combine_params(&parts->parent->global, &parts->local, &parts->global); + if (parts->global.z != old_z) + parts_list_resort(parts); + } + + if (parts->dirty) { + TAILQ_REMOVE(&dirty_list, parts, dirty_list_entry); + parts->dirty = false; + } + + struct parts *child; + PARTS_FOREACH_CHILD(child, parts) { + parts_update_component(child); + } +} + +void PE_UpdateComponent(possibly_unused int passed_time) +{ + while (!TAILQ_EMPTY(&dirty_list)) { + // pop parts object from dirty list + struct parts *parts = TAILQ_FIRST(&dirty_list); + TAILQ_REMOVE(&dirty_list, parts, dirty_list_entry); + parts->dirty = false; + + // update parent + struct parts *parent; + if (parts->pending_parent >= 0 && (parent = parts_try_get(parts->pending_parent))) { + if (parts->parent) { + TAILQ_REMOVE(&parts->parent->children, parts, child_list_entry); + } + parts->parent = parent; + TAILQ_INSERT_TAIL(&parent->children, parts, child_list_entry); + } + // TODO: should the child be orphaned if it already has a parent and an invalid + // parent no is given? + parts->pending_parent = -1; + + // don't do anything here if parent is dirty + if (parts_has_dirty_parent(parts)) + continue; + + // update child params + parts_update_component(parts); + } +} + void PE_Update(int passed_time, possibly_unused bool message_window_show) { + PE_UpdateComponent(passed_time); audio_update(); parts_update_animation(passed_time); PE_UpdateInputState(passed_time); @@ -1050,36 +1256,14 @@ void PE_SetPos(int parts_no, int x, int y) parts_set_pos(parts_get(parts_no), (Point){ x, y }); } -/* - * NOTE: If a ChipmunkSpriteEngine sprite is at Z=0, it's drawn behind; - * otherwise it's drawn in front, regardless of the parts Z-value. - * This is implemented by giving GoatGUIEngine sprites a Z-value of - * 0 and a secondary Z-value of 1 + the value given here. - */ void PE_SetZ(int parts_no, int z) { - struct parts *parts = parts_get(parts_no); - if (parts->z == z) - return; - - int diff = z - parts->z; - parts->z = z; - parts->global_z += diff; - parts_list_resort(parts); - - struct parts *child; - PARTS_FOREACH_CHILD(child, parts) { - parts_update_global_z(child, parts->global_z); - } + parts_set_z(parts_get(parts_no), z); } void PE_SetShow(int parts_no, bool show) { - struct parts *parts = parts_get(parts_no); - if (parts->show != show) { - parts->show = show; - parts_dirty(parts); - } + parts_set_show(parts_get(parts_no), show); } void PE_SetAlpha(int parts_no, int alpha) @@ -1096,32 +1280,34 @@ void PE_SetPartsDrawFilter(int parts_no, int draw_filter) void PE_SetAddColor(int parts_no, int r, int g, int b) { - parts_get(parts_no)->add_color = (SDL_Color) { + SDL_Color add_color = { min(255, max(0, r)), min(255, max(0, g)), min(255, max(0, b)), 255 }; + parts_set_add_color(parts_get(parts_no), add_color); } void PE_SetMultiplyColor(int parts_no, int r, int g, int b) { - parts_get(parts_no)->multiply_color = (SDL_Color) { + SDL_Color multiply_color = { min(255, max(0, r)), min(255, max(0, g)), min(255, max(0, b)), 255 }; + parts_set_multiply_color(parts_get(parts_no), multiply_color); } int PE_GetPartsX(int parts_no) { - return parts_get(parts_no)->pos.x; + return parts_get(parts_no)->local.pos.x; } int PE_GetPartsY(int parts_no) { - return parts_get(parts_no)->pos.y; + return parts_get(parts_no)->local.pos.y; } int PE_GetPartsWidth(int parts_no, int state) @@ -1154,17 +1340,17 @@ int PE_GetPartsUpperLeftPosY(int parts_no, int state) int PE_GetPartsZ(int parts_no) { - return parts_get(parts_no)->z; + return parts_get(parts_no)->local.z; } bool PE_GetPartsShow(int parts_no) { - return parts_get(parts_no)->show; + return parts_get(parts_no)->local.show; } int PE_GetPartsAlpha(int parts_no) { - return parts_get(parts_no)->alpha; + return parts_get(parts_no)->local.alpha; } void PE_GetAddColor(int PartsNumber, int *nR, int *nG, int *nB); @@ -1185,10 +1371,8 @@ int PE_GetPartsOriginPosMode(int parts_no) void PE_SetParentPartsNumber(int parts_no, int parent_parts_no) { struct parts *parts = parts_get(parts_no); - if (parts->parent == parent_parts_no) - return; - - parts_set_parent(parts, parts_get(parent_parts_no)); + parts->pending_parent = parent_parts_no; + parts_component_dirty(parts); } bool PE_SetPartsGroupNumber(possibly_unused int PartsNumber, possibly_unused int GroupNumber) @@ -1206,12 +1390,14 @@ bool PE_GetPartsMessageWindowShowLink(int PartsNumber); void PE_SetPartsMagX(int parts_no, float scale_x) { - parts_set_scale_x(parts_get(parts_no), scale_x); + struct parts *parts = parts_get(parts_no); + parts_set_scale_x(parts, scale_x); } void PE_SetPartsMagY(int parts_no, float scale_y) { - parts_set_scale_y(parts_get(parts_no), scale_y); + struct parts *parts = parts_get(parts_no); + parts_set_scale_y(parts, scale_y); } void PE_SetPartsRotateX(int parts_no, float rot_x) @@ -1226,7 +1412,8 @@ void PE_SetPartsRotateY(int parts_no, float rot_y) void PE_SetPartsRotateZ(int parts_no, float rot_z) { - parts_set_rotation_z(parts_get(parts_no), rot_z); + struct parts *parts = parts_get(parts_no); + parts_set_rotation_z(parts, rot_z); } void PE_SetPartsAlphaClipperPartsNumber(int PartsNumber, int AlphaClipperPartsNumber); diff --git a/src/parts/parts_internal.h b/src/parts/parts_internal.h index 3d1f4e8..f1a3a4f 100644 --- a/src/parts/parts_internal.h +++ b/src/parts/parts_internal.h @@ -210,13 +210,29 @@ struct parts_state { TAILQ_HEAD(parts_list, parts); +struct parts_params { + int z; + Point pos; + bool show; + uint8_t alpha; + struct { float x, y; } scale; + struct { float x, y, z; } rotation; + SDL_Color add_color; + SDL_Color multiply_color; +}; + struct parts { //struct sprite sp; enum parts_state_type state; struct parts_state states[PARTS_NR_STATES]; TAILQ_ENTRY(parts) parts_list_entry; TAILQ_ENTRY(parts) child_list_entry; + TAILQ_ENTRY(parts) dirty_list_entry; struct parts_list children; + struct parts_params local; + struct parts_params global; + struct parts *parent; + int dirty; int no; int delegate_index; int sprite_deform; @@ -224,18 +240,9 @@ struct parts { int on_cursor_sound; int on_click_sound; int origin_mode; - int parent; + int pending_parent; int linked_to; int linked_from; - uint8_t alpha; - int z; - int global_z; - bool show; - Point pos; - struct { float x, y; } scale; - struct { float x, y, z; } rotation; - SDL_Color add_color; - SDL_Color multiply_color; int draw_filter; TAILQ_HEAD(, parts_motion) motion; }; diff --git a/src/parts/render.c b/src/parts/render.c index 4626779..2d61e68 100644 --- a/src/parts/render.c +++ b/src/parts/render.c @@ -29,14 +29,6 @@ // Goat sprites are integrated into the scene via a single (virtual) sprite static struct sprite goat_sprite; -struct parts_render_params { - Point offset; - uint8_t alpha; - struct { float x, y; } scale; - SDL_Color add_color; - SDL_Color multiply_color; -}; - static struct { struct shader shader; GLint alpha_mod; @@ -46,20 +38,18 @@ static struct { GLint multiply_color; } parts_shader; -static void parts_render_text(struct parts *parts, struct parts_common *common, - struct parts_render_params *params) +static void parts_render_text(struct parts *parts, struct parts_common *common) { Rectangle rect = { - .x = params->offset.x + common->origin_offset.x, - .y = params->offset.y + common->origin_offset.y, + .x = parts->global.pos.x + common->origin_offset.x, + .y = parts->global.pos.y + common->origin_offset.y, .w = common->w, .h = common->h }; gfx_render_texture(&parts->states[parts->state].common.texture, &rect); } -static void parts_render_cg(struct parts *parts, struct parts_common *common, - struct parts_render_params *params) +static void parts_render_cg(struct parts *parts, struct parts_common *common) { switch (parts->draw_filter) { case 1: @@ -70,12 +60,12 @@ static void parts_render_cg(struct parts *parts, struct parts_common *common, } mat4 mw_transform = GLM_MAT4_IDENTITY_INIT; - glm_translate(mw_transform, (vec3) { params->offset.x, params->offset.y, 0 }); + glm_translate(mw_transform, (vec3) { parts->global.pos.x, parts->global.pos.y, 0 }); // FIXME: need perspective for 3D rotate //glm_rotate_x(mw_transform, parts->rotation.x, mw_transform); //glm_rotate_y(mw_transform, parts->rotation.y, mw_transform); - glm_rotate_z(mw_transform, parts->rotation.z, mw_transform); - glm_scale(mw_transform, (vec3){ params->scale.x, params->scale.y, 1.0 }); + glm_rotate_z(mw_transform, parts->local.rotation.z, mw_transform); + glm_scale(mw_transform, (vec3){ parts->global.scale.x, parts->global.scale.y, 1.0 }); glm_translate(mw_transform, (vec3){ common->origin_offset.x, common->origin_offset.y, 0 }); glm_scale(mw_transform, (vec3){ common->w, common->h, 1.0 }); mat4 wv_transform = WV_TRANSFORM(config.view_width, config.view_height); @@ -94,13 +84,13 @@ static void parts_render_cg(struct parts *parts, struct parts_common *common, } gfx_prepare_job(&job); - glUniform1f(parts_shader.alpha_mod, params->alpha / 255.0); + glUniform1f(parts_shader.alpha_mod, parts->global.alpha / 255.0); glUniform2f(parts_shader.bot_left, r.x, r.y); glUniform2f(parts_shader.top_right, r.x + r.w, r.y + r.h); - glUniform3f(parts_shader.add_color, params->add_color.r / 255.0f, - params->add_color.g / 255.0f, params->add_color.b / 255.0f); - glUniform3f(parts_shader.multiply_color, params->multiply_color.r / 255.0f, - params->multiply_color.g / 255.0f, params->multiply_color.b / 255.0f); + glUniform3f(parts_shader.add_color, parts->global.add_color.r / 255.0f, + parts->global.add_color.g / 255.0f, parts->global.add_color.b / 255.0f); + glUniform3f(parts_shader.multiply_color, parts->global.multiply_color.r / 255.0f, + parts->global.multiply_color.g / 255.0f, parts->global.multiply_color.b / 255.0f); gfx_run_job(&job); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO); @@ -108,7 +98,7 @@ static void parts_render_cg(struct parts *parts, struct parts_common *common, void parts_render(struct parts *parts) { - if (!parts->show) + if (!parts->global.show) return; if (parts->linked_to >= 0) { struct parts *link_parts = parts_get(parts->linked_to); @@ -117,33 +107,6 @@ void parts_render(struct parts *parts) return; } - struct parts_render_params params = { - .offset = parts->pos, - .alpha = parts->alpha, - .scale = { parts->scale.x, parts->scale.y }, - .add_color = parts->add_color, - .multiply_color = parts->multiply_color, - }; - - // adjust pos/alpha per parent parts - struct parts *parent = parts; - while (parent->parent >= 0) { - parent = parts_get(parent->parent); - if (!parent->show) - return; - params.alpha *= parent->alpha / 255.0f; - params.offset.x += parent->pos.x; - params.offset.y += parent->pos.y; - params.scale.x *= parent->scale.x; - params.scale.y *= parent->scale.y; - params.add_color.r *= parent->add_color.r / 255.0f; - params.add_color.g *= parent->add_color.g / 255.0f; - params.add_color.b *= parent->add_color.b / 255.0f; - params.multiply_color.r *= parent->multiply_color.r / 255.0f; - params.multiply_color.g *= parent->multiply_color.g / 255.0f; - params.multiply_color.b *= parent->multiply_color.b / 255.0f; - } - // render struct parts_state *state = &parts->states[parts->state]; if (state->common.texture.handle) { @@ -156,10 +119,10 @@ void parts_render(struct parts *parts) case PARTS_HGAUGE: case PARTS_VGAUGE: case PARTS_CONSTRUCTION_PROCESS: - parts_render_cg(parts, &state->common, ¶ms); + parts_render_cg(parts, &state->common); break; case PARTS_TEXT: - parts_render_text(parts, &state->common, ¶ms); + parts_render_text(parts, &state->common); break; } }