child xform fixes
This commit is contained in:
parent
f5e28a04af
commit
0f113f640f
129
src/entity.c
129
src/entity.c
@ -14,8 +14,16 @@ READONLY struct entity_store _g_entity_store_nil = {
|
||||
READONLY struct entity _g_entity_nil = {
|
||||
.local_xform = XFORM_IDENT_NOCAST,
|
||||
.cached_global_xform = XFORM_IDENT_NOCAST,
|
||||
.cached_global_xform_clean = true,
|
||||
.sprite_xform = XFORM_IDENT_NOCAST,
|
||||
.sprite_local_xform = XFORM_IDENT_NOCAST,
|
||||
.sprite_tint = COLOR_WHITE
|
||||
};
|
||||
|
||||
GLOBAL READONLY struct entity g_entity_default = {
|
||||
.valid = true,
|
||||
.local_xform = XFORM_IDENT_NOCAST,
|
||||
.cached_global_xform = XFORM_IDENT_NOCAST,
|
||||
.cached_global_xform_dirty = true,
|
||||
.sprite_local_xform = XFORM_IDENT_NOCAST,
|
||||
.sprite_tint = COLOR_WHITE
|
||||
};
|
||||
|
||||
@ -32,9 +40,10 @@ struct entity_store *entity_store_alloc(void)
|
||||
ASSERT((u64)store->entities - (u64)store == STORE_ENTITIES_OFFSET); /* Offset must be correct */
|
||||
|
||||
struct entity *root = entity_alloc_unlinked(store);
|
||||
root->root = true;
|
||||
root->cached_global_xform = root->local_xform;
|
||||
root->cached_global_xform_clean = true;
|
||||
root->is_root = true;
|
||||
root->local_xform = XFORM_IDENT;
|
||||
root->cached_global_xform = XFORM_IDENT;
|
||||
root->cached_global_xform_dirty = false;
|
||||
store->root = root->handle;
|
||||
|
||||
return store;
|
||||
@ -74,10 +83,8 @@ struct entity *entity_alloc_unlinked(struct entity_store *store)
|
||||
entity = arena_push(&store->arena, struct entity);
|
||||
handle = (struct entity_handle) { .gen = 1, .idx = store->count++ };
|
||||
}
|
||||
*entity = *entity_nil();
|
||||
*entity = g_entity_default;
|
||||
entity->handle = handle;
|
||||
entity->valid = true;
|
||||
entity->cached_global_xform_clean = false;
|
||||
return entity;
|
||||
}
|
||||
|
||||
@ -85,7 +92,7 @@ struct entity *entity_alloc_top(struct entity_store *store)
|
||||
{
|
||||
struct entity *e = entity_alloc_unlinked(store);
|
||||
struct entity *root = entity_from_handle(store, store->root);
|
||||
entity_link(root, e);
|
||||
entity_link_parent_child(root, e);
|
||||
return e;
|
||||
}
|
||||
|
||||
@ -93,22 +100,25 @@ struct entity *entity_alloc_child(struct entity *parent)
|
||||
{
|
||||
struct entity_store *store = entity_get_store(parent);
|
||||
struct entity *e = entity_alloc_unlinked(store);
|
||||
entity_link(parent, e);
|
||||
entity_link_parent_child(parent, e);
|
||||
return e;
|
||||
}
|
||||
|
||||
void entity_release(struct entity_store *store, struct entity *entity)
|
||||
void entity_release(struct entity_store *store, struct entity *ent)
|
||||
{
|
||||
++entity->handle.gen;
|
||||
entity->valid = false;
|
||||
entity->next_free = store->first_free;
|
||||
store->first_free = entity->handle;
|
||||
/* Release children */
|
||||
if (entity->first.gen) {
|
||||
for (struct entity *child = entity_from_handle(store, entity->first); child->valid; child = entity_from_handle(store, child->next)) {
|
||||
if (ent->first.gen) {
|
||||
for (struct entity *child = entity_from_handle(store, ent->first); child->valid; child = entity_from_handle(store, child->next)) {
|
||||
entity_release(store, child);
|
||||
}
|
||||
}
|
||||
/* Unlink */
|
||||
entity_unlink(ent);
|
||||
/* Release */
|
||||
++ent->handle.gen;
|
||||
ent->valid = false;
|
||||
ent->next_free = store->first_free;
|
||||
store->first_free = ent->handle;
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
@ -178,42 +188,51 @@ struct entity *entity_find_first_match_all(struct entity_store *store, struct en
|
||||
* Xform
|
||||
* ========================== */
|
||||
|
||||
INTERNAL void entity_mark_xform_dirty(struct entity_store *store, struct entity *ent)
|
||||
INTERNAL void entity_mark_child_xforms_dirty(struct entity_store *store, struct entity *ent)
|
||||
{
|
||||
ent->cached_global_xform_clean = false;
|
||||
for (struct entity *child = entity_from_handle(store, ent->first); child->valid; child = entity_from_handle(store, child->next)) {
|
||||
if (child->cached_global_xform_clean) {
|
||||
entity_mark_xform_dirty(store, ent);
|
||||
} else {
|
||||
if (child->cached_global_xform_dirty) {
|
||||
break;
|
||||
} else {
|
||||
child->cached_global_xform_dirty = true;
|
||||
entity_mark_child_xforms_dirty(store, child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
INTERNAL struct xform entity_get_xform_w_store(struct entity_store *store, struct entity *ent)
|
||||
{
|
||||
struct entity_handle parent_handle = ent->parent;
|
||||
|
||||
struct xform xf;
|
||||
if (entity_handle_eq(parent_handle, store->root)) {
|
||||
if (ent->is_top) {
|
||||
xf = ent->local_xform;
|
||||
} else if (ent->cached_global_xform_clean) {
|
||||
} else if (!ent->cached_global_xform_dirty) {
|
||||
xf = ent->cached_global_xform;
|
||||
} else {
|
||||
struct entity_handle parent_handle = ent->parent;
|
||||
struct entity *parent = entity_from_handle(store, parent_handle);
|
||||
xf = entity_get_xform_w_store(store, parent);
|
||||
xf = xform_mul(xf, ent->local_xform);
|
||||
ent->cached_global_xform = xf;
|
||||
ent->cached_global_xform_clean = true;
|
||||
ent->cached_global_xform_dirty = false;
|
||||
}
|
||||
|
||||
return xf;
|
||||
}
|
||||
|
||||
struct xform entity_get_xform(struct entity *ent)
|
||||
{
|
||||
struct xform xf;
|
||||
if (ent->is_top) {
|
||||
xf = ent->local_xform;
|
||||
} else if (!ent->cached_global_xform_dirty) {
|
||||
xf = ent->cached_global_xform;
|
||||
} else {
|
||||
struct entity_store *store = entity_get_store(ent);
|
||||
struct xform xf = entity_get_xform_w_store(store, ent);
|
||||
struct entity *parent = entity_from_handle(store, ent->parent);
|
||||
xf = entity_get_xform_w_store(store, parent);
|
||||
xf = xform_mul(xf, ent->local_xform);
|
||||
ent->cached_global_xform = xf;
|
||||
ent->cached_global_xform_dirty = false;
|
||||
}
|
||||
return xf;
|
||||
}
|
||||
|
||||
@ -224,31 +243,34 @@ struct xform entity_get_local_xform(struct entity *ent)
|
||||
|
||||
void entity_set_xform(struct entity *ent, struct xform xf)
|
||||
{
|
||||
/* TODO: Instead of calculating & storing derived local xform, maybe just cache global xform and update local if retrieved? */
|
||||
struct entity_store *store = entity_get_store(ent);
|
||||
if (ent->is_top) {
|
||||
ent->local_xform = xf;
|
||||
} else {
|
||||
/* Update child local xform */
|
||||
struct entity *parent = entity_from_handle(store, ent->parent);
|
||||
|
||||
struct xform child_global = xf;
|
||||
|
||||
struct xform parent_global = entity_get_xform_w_store(store, parent);
|
||||
struct xform child_local = xform_mul(xform_invert(parent_global), child_global);
|
||||
ent->local_xform = xform_mul(xform_invert(parent_global), xf);
|
||||
|
||||
ent->local_xform = child_local;
|
||||
ent->cached_global_xform = child_global;
|
||||
ent->cached_global_xform_clean = true;
|
||||
/* Set child global xform */
|
||||
ent->cached_global_xform = xf;
|
||||
ent->cached_global_xform_dirty = false;
|
||||
}
|
||||
entity_mark_child_xforms_dirty(store, ent);
|
||||
}
|
||||
|
||||
void entity_set_local_xform(struct entity *ent, struct xform xf)
|
||||
{
|
||||
ent->local_xform = xf;
|
||||
entity_mark_xform_dirty(entity_get_store(ent), ent);
|
||||
ent->cached_global_xform_dirty = true;
|
||||
entity_mark_child_xforms_dirty(entity_get_store(ent), ent);
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Tree
|
||||
* ========================== */
|
||||
|
||||
void entity_link(struct entity *parent, struct entity *child)
|
||||
void entity_link_parent_child(struct entity *parent, struct entity *child)
|
||||
{
|
||||
struct entity_store *store = entity_get_store(parent);
|
||||
|
||||
@ -268,6 +290,8 @@ void entity_link(struct entity *parent, struct entity *child)
|
||||
last_child->next = child_handle;
|
||||
}
|
||||
parent->last = child_handle;
|
||||
|
||||
child->is_top = parent->is_root;
|
||||
}
|
||||
|
||||
void entity_unlink(struct entity *ent)
|
||||
@ -275,7 +299,9 @@ void entity_unlink(struct entity *ent)
|
||||
struct entity_store *store = entity_get_store(ent);
|
||||
ASSERT(!entity_handle_eq(ent->handle, store->root));
|
||||
|
||||
struct entity *parent = entity_from_handle(store, ent->parent);
|
||||
struct entity_handle parent_handle = ent->parent;
|
||||
|
||||
struct entity *parent = entity_from_handle(store, parent_handle);
|
||||
struct entity *prev = entity_from_handle(store, ent->prev);
|
||||
struct entity *next = entity_from_handle(store, ent->next);
|
||||
|
||||
@ -290,12 +316,29 @@ void entity_unlink(struct entity *ent)
|
||||
} else {
|
||||
parent->last = prev->handle;
|
||||
}
|
||||
ent->is_top = false;
|
||||
ent->is_root = false;
|
||||
|
||||
/* Link children to grandparent */
|
||||
if (ent->first.gen) {
|
||||
struct entity_handle parent_handle = parent->handle;
|
||||
for (struct entity *child = entity_from_handle(store, ent->first); child->valid; child = entity_from_handle(store, child->next)) {
|
||||
struct entity_handle child_first_handle = ent->first;
|
||||
if (child_first_handle.gen) {
|
||||
struct entity_handle child_last_handle = ent->last;
|
||||
|
||||
struct entity_handle parent_last_handle = parent->last;
|
||||
struct entity *parent_last = entity_from_handle(store, parent_last_handle);
|
||||
if (parent_last->valid) {
|
||||
parent_last->next = child_first_handle;
|
||||
} else {
|
||||
parent->first = child_first_handle;
|
||||
}
|
||||
|
||||
parent->last = child_last_handle;
|
||||
|
||||
/* Set children parent & is_top */
|
||||
b32 parent_is_root = parent->is_root;
|
||||
for (struct entity *child = entity_from_handle(store, child_first_handle); child->valid; child = entity_from_handle(store, child->next)) {
|
||||
child->parent = parent_handle;
|
||||
child->is_top = parent_is_root;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
13
src/entity.h
13
src/entity.h
@ -45,7 +45,10 @@ struct entity {
|
||||
u64 store_offset;
|
||||
|
||||
/* Is this the root entity */
|
||||
b32 root;
|
||||
b32 is_root;
|
||||
|
||||
/* Is the parent the root entity */
|
||||
b32 is_top;
|
||||
|
||||
/* Tree */
|
||||
struct entity_handle parent;
|
||||
@ -58,7 +61,7 @@ struct entity {
|
||||
|
||||
struct xform local_xform; /* Transform in relation to parent entity (or the world if entity has no parent) */
|
||||
struct xform cached_global_xform; /* Calculated from entity tree */
|
||||
b32 cached_global_xform_clean;
|
||||
b32 cached_global_xform_dirty;
|
||||
|
||||
/* ====================================================================== */
|
||||
/* Physics */
|
||||
@ -78,8 +81,8 @@ struct entity {
|
||||
struct string sprite_span_name;
|
||||
u32 sprite_tint;
|
||||
|
||||
struct xform sprite_xform; /* Sprite transform in relation to xform_world */
|
||||
struct xform sprite_xform_world; /* Calculated from world xform */
|
||||
struct xform sprite_local_xform; /* Sprite transform in relation to xform_world */
|
||||
struct xform sprite_global_xform;
|
||||
|
||||
/* ====================================================================== */
|
||||
/* Animation */
|
||||
@ -208,7 +211,7 @@ struct entity *entity_find_first_match_one(struct entity_store *store, enum enti
|
||||
struct entity *entity_find_first_match_all(struct entity_store *store, struct entity_prop_array props);
|
||||
|
||||
/* Tree */
|
||||
void entity_link(struct entity *parent, struct entity *child);
|
||||
void entity_link_parent_child(struct entity *parent, struct entity *child);
|
||||
void entity_unlink(struct entity *ent);
|
||||
|
||||
#endif
|
||||
|
||||
54
src/game.c
54
src/game.c
@ -130,6 +130,28 @@ INTERNAL void spawn_test_entities(void)
|
||||
//entity_enable_prop(e, ENTITY_PROP_TEST);
|
||||
}
|
||||
|
||||
/* Child ent */
|
||||
{
|
||||
struct v2 pos = V2(0, 0);
|
||||
struct v2 size = V2(1, 1);
|
||||
f32 r = 0;
|
||||
|
||||
struct xform xf = XFORM_TRS(.t = pos, .r = r, .s = size);
|
||||
|
||||
struct entity *e = entity_alloc_child(player_ent);
|
||||
entity_set_xform(e, xf);
|
||||
|
||||
e->sprite = sprite_tag_from_path(STR("res/graphics/tim.ase"));
|
||||
e->sprite_span_name = STR("idle.unarmed");
|
||||
//e->sprite_span_name = STR("idle.one_handed");
|
||||
//e->sprite_span_name = STR("idle.two_handed");
|
||||
e->sprite_tint = RGBA_32_F(1, 0, 0, 0.5);
|
||||
|
||||
entity_enable_prop(e, ENTITY_PROP_ANIMATING);
|
||||
|
||||
//entity_enable_prop(e, ENTITY_PROP_TEST);
|
||||
}
|
||||
|
||||
/* Camera ent */
|
||||
{
|
||||
struct entity *e = entity_alloc_top(G.world.entity_store);
|
||||
@ -207,9 +229,14 @@ INTERNAL void recalculate_world_xforms_recurse(struct entity *parent)
|
||||
#else
|
||||
INTERNAL void recalculate_world_xforms_recurse(struct entity *ent)
|
||||
{
|
||||
struct xform xform_global = entity_get_xform(ent);
|
||||
//struct xform xform_local = entity_get_local_xform(ent);
|
||||
(UNUSED)xform_global;
|
||||
//(UNUSED)xform_local;
|
||||
|
||||
struct entity_store *store = G.world.entity_store;
|
||||
struct xform sprite_xform_world = xform_mul(entity_get_xform(ent), ent->sprite_xform);
|
||||
ent->sprite_xform_world = sprite_xform_world;
|
||||
struct xform sprite_global_xform = xform_mul(xform_global, ent->sprite_local_xform);
|
||||
ent->sprite_global_xform = sprite_global_xform;
|
||||
for (struct entity *child = entity_from_handle(store, ent->first); child->valid; child = entity_from_handle(store, child->next)) {
|
||||
recalculate_world_xforms_recurse(child);
|
||||
}
|
||||
@ -269,7 +296,7 @@ INTERNAL void game_update(void)
|
||||
logf_info("Clearing level");
|
||||
for (u64 i = 0; i < G.world.entity_store->count; ++i) {
|
||||
struct entity *ent = &G.world.entity_store->entities[i];
|
||||
if (ent->valid && !ent->root) {
|
||||
if (ent->valid && !ent->is_root) {
|
||||
entity_release(G.world.entity_store, ent);
|
||||
}
|
||||
}
|
||||
@ -293,7 +320,6 @@ INTERNAL void game_update(void)
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
struct entity_handle root_handle = G.world.entity_store->root;
|
||||
struct entity_array entities_array = entity_store_as_array(G.world.entity_store);
|
||||
|
||||
/* ========================== *
|
||||
@ -303,7 +329,7 @@ INTERNAL void game_update(void)
|
||||
/* Recalculate world xforms */
|
||||
for (u64 entity_index = 0; entity_index < entities_array.count; ++entity_index) {
|
||||
struct entity *ent = &entities_array.entities[entity_index];
|
||||
if (ent->valid && entity_handle_eq(ent->parent, root_handle)) {
|
||||
if (ent->valid && ent->is_top) {
|
||||
recalculate_world_xforms_recurse(ent);
|
||||
}
|
||||
}
|
||||
@ -350,7 +376,7 @@ INTERNAL void game_update(void)
|
||||
struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("pivot"), ent->animation_frame);
|
||||
struct v2 sprite_size = v2_div(sheet->frame_size, (f32)PIXELS_PER_UNIT);
|
||||
struct v2 pivot_pos = v2_mul_v2(slice.center, sprite_size);
|
||||
ent->sprite_xform = xform_with_scale(XFORM_POS(v2_neg(pivot_pos)), sprite_size);
|
||||
ent->sprite_local_xform = xform_with_scale(XFORM_POS(v2_neg(pivot_pos)), sprite_size);
|
||||
}
|
||||
|
||||
|
||||
@ -361,7 +387,7 @@ INTERNAL void game_update(void)
|
||||
/* Recalculate world xforms */
|
||||
for (u64 entity_index = 0; entity_index < entities_array.count; ++entity_index) {
|
||||
struct entity *ent = &entities_array.entities[entity_index];
|
||||
if (ent->valid && entity_handle_eq(ent->parent, root_handle)) {
|
||||
if (ent->valid && ent->is_top) {
|
||||
recalculate_world_xforms_recurse(ent);
|
||||
}
|
||||
}
|
||||
@ -378,7 +404,7 @@ INTERNAL void game_update(void)
|
||||
if (entity_has_prop(ent, ENTITY_PROP_TEST) && !ent->test_initialized) {
|
||||
ent->test_initialized = true;
|
||||
ent->test_start_local_xform = entity_get_local_xform(ent);
|
||||
ent->test_start_sprite_xform = ent->sprite_xform;
|
||||
ent->test_start_sprite_xform = ent->sprite_local_xform;
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
@ -400,15 +426,15 @@ INTERNAL void game_update(void)
|
||||
f32 forward_hold_angle_offset;
|
||||
{
|
||||
struct xform xf_unrotated = xform_with_rotation(xf, 0);
|
||||
struct v2 hold_pos_unrotated = xform_mul_v2(xf_unrotated, xform_mul_v2(ent->sprite_xform, slice.center));
|
||||
struct v2 hold_pos_unrotated = xform_mul_v2(xf_unrotated, xform_mul_v2(ent->sprite_local_xform, slice.center));
|
||||
forward_hold_angle_offset = v2_angle_from_dirs(V2(0, -1), v2_sub(hold_pos_unrotated, xf_unrotated.og));
|
||||
}
|
||||
|
||||
struct v2 ent_pos = xf.og;
|
||||
struct v2 focus_pos = v2_add(ent_pos, ent->focus);
|
||||
struct v2 hold_pos = xform_mul_v2(xf, xform_mul_v2(ent->sprite_xform, slice.center));
|
||||
struct v2 hold_pos = xform_mul_v2(xf, xform_mul_v2(ent->sprite_local_xform, slice.center));
|
||||
|
||||
struct v2 hold_dir = xform_basis_mul_v2(xf, xform_basis_mul_v2(ent->sprite_xform, slice.dir));
|
||||
struct v2 hold_dir = xform_basis_mul_v2(xf, xform_basis_mul_v2(ent->sprite_local_xform, slice.dir));
|
||||
struct v2 hold_ent_dir = v2_sub(ent_pos, hold_pos);
|
||||
struct v2 focus_ent_dir = v2_sub(ent_pos, focus_pos);
|
||||
|
||||
@ -461,7 +487,7 @@ INTERNAL void game_update(void)
|
||||
/* Recalculate world xforms */
|
||||
for (u64 entity_index = 0; entity_index < entities_array.count; ++entity_index) {
|
||||
struct entity *ent = &entities_array.entities[entity_index];
|
||||
if (ent->valid && entity_handle_eq(ent->parent, root_handle)) {
|
||||
if (ent->valid && ent->is_top) {
|
||||
recalculate_world_xforms_recurse(ent);
|
||||
}
|
||||
}
|
||||
@ -508,7 +534,7 @@ INTERNAL void game_update(void)
|
||||
/* Recalculate world xforms */
|
||||
for (u64 entity_index = 0; entity_index < entities_array.count; ++entity_index) {
|
||||
struct entity *ent = &entities_array.entities[entity_index];
|
||||
if (ent->valid && entity_handle_eq(ent->parent, root_handle)) {
|
||||
if (ent->valid && ent->is_top) {
|
||||
recalculate_world_xforms_recurse(ent);
|
||||
}
|
||||
}
|
||||
@ -587,7 +613,7 @@ INTERNAL void game_update(void)
|
||||
/* Recalculate world xforms */
|
||||
for (u64 entity_index = 0; entity_index < entities_array.count; ++entity_index) {
|
||||
struct entity *ent = &entities_array.entities[entity_index];
|
||||
if (ent->valid && entity_handle_eq(ent->parent, root_handle)) {
|
||||
if (ent->valid && ent->is_top) {
|
||||
recalculate_world_xforms_recurse(ent);
|
||||
}
|
||||
}
|
||||
|
||||
18
src/user.c
18
src/user.c
@ -461,8 +461,8 @@ INTERNAL void user_update(void)
|
||||
e->player_acceleration = math_lerp(e0->player_acceleration, e1->player_acceleration, tick_blend);
|
||||
e->focus = v2_lerp(e0->focus, e1->focus, tick_blend);
|
||||
|
||||
e->sprite_xform = xform_lerp(e0->sprite_xform, e1->sprite_xform, tick_blend);
|
||||
e->sprite_xform_world = xform_lerp(e0->sprite_xform_world, e1->sprite_xform_world, tick_blend);
|
||||
e->sprite_local_xform = xform_lerp(e0->sprite_local_xform, e1->sprite_local_xform, tick_blend);
|
||||
e->sprite_global_xform = xform_lerp(e0->sprite_global_xform, e1->sprite_global_xform, tick_blend);
|
||||
e->animation_time_in_frame = math_lerp64(e0->animation_time_in_frame, e1->animation_time_in_frame, (f64)tick_blend);
|
||||
e->animation_frame = (u32)math_round_to_int(math_lerp(e0->animation_frame, e1->animation_frame, tick_blend));
|
||||
|
||||
@ -773,7 +773,7 @@ INTERNAL void user_update(void)
|
||||
|
||||
struct entity *ent = &entities_array.entities[entity_index];
|
||||
if (!ent->valid) continue;
|
||||
if (ent->root) continue;
|
||||
if (ent->is_root) continue;
|
||||
|
||||
struct entity *parent = entity_from_handle(G.world.entity_store, ent->parent);
|
||||
|
||||
@ -795,7 +795,7 @@ INTERNAL void user_update(void)
|
||||
/* TODO: Fade in placeholder if texture isn't loaded */
|
||||
if (sheet->loaded) {
|
||||
struct sprite_sheet_frame frame = sprite_sheet_get_frame(sheet, ent->animation_frame);
|
||||
struct quad quad = quad_mul_xform(QUAD_UNIT_SQUARE_CENTERED, ent->sprite_xform_world);
|
||||
struct quad quad = quad_mul_xform(QUAD_UNIT_SQUARE_CENTERED, ent->sprite_global_xform);
|
||||
struct draw_sprite_params params = DRAW_SPRITE_PARAMS(.sprite = sprite, .tint = ent->sprite_tint, .clip = frame.clip);
|
||||
draw_sprite_quad(G.world_canvas, params, quad);
|
||||
}
|
||||
@ -852,7 +852,7 @@ INTERNAL void user_update(void)
|
||||
if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) {
|
||||
struct sprite_sheet *sheet = sprite_sheet_from_tag_async(sprite_frame_scope, ent->sprite);
|
||||
struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("hold"), ent->animation_frame);
|
||||
struct v2 start = xform_mul_v2(ent->sprite_xform_world, slice.center);
|
||||
struct v2 start = xform_mul_v2(ent->sprite_global_xform, slice.center);
|
||||
start = xform_mul_v2(G.world_view, start);
|
||||
struct v2 end = v2_add(xf.og, ent->focus);
|
||||
end = xform_mul_v2(G.world_view, end);
|
||||
@ -871,12 +871,12 @@ INTERNAL void user_update(void)
|
||||
for (u32 j = 0; j < group->per_frame_count; ++j) {
|
||||
struct sprite_sheet_slice slice = group->frame_slices[(ent->animation_frame * group->per_frame_count) + j];
|
||||
|
||||
struct v2 center = xform_mul_v2(ent->sprite_xform_world, slice.center);
|
||||
struct v2 center = xform_mul_v2(ent->sprite_global_xform, slice.center);
|
||||
center = xform_mul_v2(G.world_view, center);
|
||||
|
||||
if (!slice.has_ray) {
|
||||
struct quad quad = quad_from_rect(slice.rect);
|
||||
quad = quad_mul_xform(quad, ent->sprite_xform_world);
|
||||
quad = quad_mul_xform(quad, ent->sprite_global_xform);
|
||||
quad = quad_mul_xform(quad, G.world_view);
|
||||
draw_solid_quad_line(G.viewport_canvas, quad, 2, RGBA_32_F(1, 0, 0.5, 1));
|
||||
}
|
||||
@ -884,7 +884,7 @@ INTERNAL void user_update(void)
|
||||
draw_solid_circle(G.viewport_canvas, center, 3, RGBA_32_F(1, 0, 0, 1), 20);
|
||||
|
||||
if (slice.has_ray) {
|
||||
struct v2 ray = xform_basis_mul_v2(ent->sprite_xform_world, slice.dir);
|
||||
struct v2 ray = xform_basis_mul_v2(ent->sprite_global_xform, slice.dir);
|
||||
ray = xform_basis_mul_v2(G.world_view, ray);
|
||||
ray = v2_mul(v2_norm(ray), 25);
|
||||
draw_solid_arrow_ray(G.viewport_canvas, center, ray, 2, 10, RGBA_32_F(1, 0, 0.5, 1));
|
||||
@ -894,7 +894,7 @@ INTERNAL void user_update(void)
|
||||
}
|
||||
|
||||
/* Draw hierarchy */
|
||||
if (parent->valid && !parent->root) {
|
||||
if (parent->valid && !parent->is_root) {
|
||||
u32 color = RGBA_32_F(0.6, 0.6, 1, 0.75);
|
||||
f32 thickness = 5;
|
||||
f32 arrow_height = 15;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user