You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
336 lines
9.7 KiB
336 lines
9.7 KiB
#include "transform.h"
|
|
#include "../common/log.h"
|
|
#include "../common/array.h"
|
|
#include "entity.h"
|
|
#include "../common/utils.h"
|
|
#include "../common/num_types.h"
|
|
#include "bounding_volumes.h"
|
|
#include "geometry.h"
|
|
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include <float.h>
|
|
|
|
void transform_init(struct Entity* entity, struct Entity* parent)
|
|
{
|
|
struct Transform* transform = &entity->transform;
|
|
vec3_fill(&transform->position, 0.f, 0.f, 0.f);
|
|
vec3_fill(&transform->scale, 1.f, 1.f, 1.f);
|
|
quat_identity(&transform->rotation);
|
|
mat4_identity(&transform->trans_mat);
|
|
transform->children = array_new(struct Entity*);
|
|
transform->parent = NULL;
|
|
if(parent)
|
|
transform_parent_set(entity, parent, false);
|
|
transform_update_transmat(entity);
|
|
}
|
|
|
|
void transform_child_add(struct Entity* parent, struct Entity* child, bool update_transmat)
|
|
{
|
|
struct Transform* parent_transform = &parent->transform;
|
|
struct Transform* child_transform = &child->transform;
|
|
|
|
/* Check if already added */
|
|
for(int i = 0; i < array_len(parent_transform->children); i++)
|
|
{
|
|
if(parent_transform->children[i] == child)
|
|
{
|
|
log_warning("Parent : %s already has a child named %s", parent->name, parent_transform->children[i]->name);
|
|
return;
|
|
}
|
|
}
|
|
|
|
struct Entity** new_child_loc = array_grow(parent_transform->children, struct Entity*);
|
|
*new_child_loc = child;
|
|
child_transform->parent = parent;
|
|
if(update_transmat) transform_update_transmat(child);
|
|
}
|
|
|
|
bool transform_child_remove(struct Entity* parent, struct Entity* child)
|
|
{
|
|
bool success = false;
|
|
struct Transform* parent_transform = &parent->transform;
|
|
for(int i = 0; i < array_len(parent_transform->children); i++)
|
|
{
|
|
if(parent_transform->children[i] == child)
|
|
{
|
|
array_remove_at(parent_transform->children, i);
|
|
child->transform.parent = NULL;
|
|
success = true;
|
|
return success;
|
|
};
|
|
}
|
|
return success;
|
|
}
|
|
|
|
void transform_parent_set(struct Entity* child, struct Entity* parent, bool update_transmat)
|
|
{
|
|
if(child->transform.parent == NULL)
|
|
{
|
|
transform_child_add(parent, child, false);
|
|
}
|
|
else
|
|
{
|
|
transform_child_remove(parent, child);
|
|
transform_child_add(parent, child, false);
|
|
}
|
|
|
|
if(update_transmat) transform_update_transmat(child);
|
|
}
|
|
|
|
void transform_copy(struct Entity* copy_to, struct Entity* copy_from, bool copy_parent)
|
|
{
|
|
/* Bear in mind that we can't copy the children because that would mean
|
|
those children have more than one parent and we don't support that.*/
|
|
struct Entity* current_parent = copy_to->transform.parent;
|
|
struct Entity** current_children = copy_to->transform.children;
|
|
|
|
memcpy(©_to->transform, ©_from->transform, sizeof(struct Transform));
|
|
if(copy_parent)
|
|
{
|
|
transform_child_remove(current_parent, copy_to);
|
|
transform_parent_set(copy_to, copy_from->transform.parent, true);
|
|
}
|
|
else
|
|
{
|
|
copy_to->transform.parent = current_parent;
|
|
}
|
|
copy_to->transform.is_modified = true;
|
|
copy_to->transform.children = current_children;
|
|
transform_update_transmat(copy_to);
|
|
}
|
|
|
|
void transform_translate(struct Entity* entity, vec3* amount, enum Transform_Space space)
|
|
{
|
|
struct Transform* transform = &entity->transform;
|
|
vec3 translation_amount;
|
|
vec3_assign(&translation_amount, amount);
|
|
if(space == TS_LOCAL)
|
|
{
|
|
quat_mul_vec3(&translation_amount, &transform->rotation, &translation_amount);
|
|
}
|
|
else if(space == TS_PARENT)
|
|
{
|
|
struct Entity* parent = transform->parent;
|
|
if(parent)
|
|
{
|
|
struct Transform* parent_tran = &parent->transform;
|
|
quat_mul_vec3(&translation_amount, &parent_tran->rotation, &translation_amount);
|
|
}
|
|
}
|
|
vec3_add(&transform->position, &transform->position, &translation_amount);
|
|
transform_update_transmat(entity);
|
|
}
|
|
|
|
void transform_rotate(struct Entity* entity,
|
|
vec3* axis,
|
|
float angle,
|
|
enum Transform_Space space)
|
|
{
|
|
struct Transform* transform = &entity->transform;
|
|
quat new_rot;
|
|
quat_identity(&new_rot);
|
|
quat_axis_angle(&new_rot, axis, angle);
|
|
|
|
if(space == TS_LOCAL)
|
|
quat_mul(&transform->rotation, &transform->rotation, &new_rot);
|
|
else
|
|
quat_mul(&transform->rotation, &new_rot, &transform->rotation);
|
|
quat_norm(&transform->rotation, &transform->rotation);
|
|
transform_update_transmat(entity);
|
|
}
|
|
|
|
void transform_scale(struct Entity* entity, vec3* scale)
|
|
{
|
|
struct Transform* transform = &entity->transform;
|
|
vec3_assign(&transform->scale, scale);
|
|
transform_update_transmat(entity);
|
|
}
|
|
|
|
void transform_get_forward(struct Entity* entity, vec3* res)
|
|
{
|
|
struct Transform* transform = &entity->transform;
|
|
vec3_fill(res, 0.f, 0.f, -1.f);
|
|
quat_get_forward_rh(res, &transform->rotation);
|
|
}
|
|
|
|
void transform_get_lookat(struct Entity* entity, vec3* res)
|
|
{
|
|
struct Transform* transform = &entity->transform;
|
|
transform_get_forward(entity, res);
|
|
vec3_add(res, &transform->position, res);
|
|
}
|
|
|
|
void transform_get_absolute_forward(struct Entity* entity, vec3* res)
|
|
{
|
|
quat abs_rot;
|
|
quat_identity(&abs_rot);
|
|
transform_get_absolute_rotation(entity, &abs_rot);
|
|
quat_get_forward_rh(res, &abs_rot);
|
|
}
|
|
|
|
void transform_get_absolute_lookat(struct Entity* entity, vec3* res)
|
|
{
|
|
vec3 abs_position = {0.f, 0.f, 0.f};
|
|
transform_get_absolute_position(entity, &abs_position);
|
|
transform_get_absolute_forward(entity, res);
|
|
vec3_add(res, &abs_position, res);
|
|
}
|
|
|
|
void transform_get_up(struct Entity* entity, vec3* res)
|
|
{
|
|
struct Transform* transform = &entity->transform;
|
|
vec3_fill(res, 0.f, 1.f, 0.f);
|
|
quat_get_up(res, &transform->rotation);
|
|
}
|
|
|
|
void transform_get_absolute_up(struct Entity* entity, vec3* res)
|
|
{
|
|
quat abs_rot;
|
|
quat_identity(&abs_rot);
|
|
transform_get_absolute_rotation(entity, &abs_rot);
|
|
quat_get_up(res, &abs_rot);
|
|
}
|
|
|
|
void transform_get_absolute_right(struct Entity* entity, vec3* res)
|
|
{
|
|
quat abs_rot;
|
|
quat_identity(&abs_rot);
|
|
transform_get_absolute_rotation(entity, &abs_rot);
|
|
quat_get_right(res, &abs_rot);
|
|
}
|
|
|
|
|
|
void transform_get_right(struct Entity* entity, vec3* res)
|
|
{
|
|
struct Transform* transform = &entity->transform;
|
|
vec3_fill(res, 1.f, 0.f, 0.f);
|
|
quat_get_right(res, &transform->rotation);
|
|
}
|
|
|
|
void transform_update_transmat(struct Entity* entity)
|
|
{
|
|
static mat4 scale, translation, rotation;
|
|
struct Transform* transform = &entity->transform;
|
|
mat4_identity(&scale);
|
|
mat4_identity(&translation);
|
|
mat4_identity(&rotation);
|
|
mat4_identity(&transform->trans_mat);
|
|
mat4_scale(&scale, transform->scale.x, transform->scale.y, transform->scale.z);
|
|
mat4_translate(&translation, transform->position.x, transform->position.y, transform->position.z);
|
|
mat4_from_quat(&rotation, &transform->rotation);
|
|
|
|
mat4_mul(&transform->trans_mat, &transform->trans_mat, &translation);
|
|
mat4_mul(&transform->trans_mat, &transform->trans_mat, &rotation);
|
|
mat4_mul(&transform->trans_mat, &transform->trans_mat, &scale);
|
|
|
|
if(transform->parent)
|
|
{
|
|
struct Transform* parent_tran = &transform->parent->transform;
|
|
mat4_mul(&transform->trans_mat, &parent_tran->trans_mat, &transform->trans_mat);
|
|
}
|
|
|
|
entity_update_derived_bounding_box(entity);
|
|
|
|
/* Update all children */
|
|
int children = array_len(transform->children);
|
|
if(children > 0)
|
|
{
|
|
for(int i = 0; i < children; i++)
|
|
transform_update_transmat(entity->transform.children[i]);
|
|
}
|
|
transform->is_modified = true;
|
|
}
|
|
|
|
void transform_destroy(struct Entity* entity)
|
|
{
|
|
struct Transform* transform = &entity->transform;
|
|
// Remove children
|
|
if(transform->children)
|
|
{
|
|
int children = array_len(transform->children);
|
|
if(children > 0)
|
|
{
|
|
for(int i = 0; i < children; i++)
|
|
{
|
|
struct Entity* child = transform->children[i];
|
|
child->flags |= EF_MARKED_FOR_DELETION;
|
|
child->transform.parent = NULL;
|
|
}
|
|
}
|
|
array_free(transform->children);
|
|
}
|
|
|
|
// Remove this entity from parent's children
|
|
if(transform->parent)
|
|
transform_child_remove(entity->transform.parent, entity);
|
|
|
|
/* Remove transform */
|
|
vec3_fill(&transform->position, 0.f, 0.f, 0.f);
|
|
vec3_fill(&transform->scale, 1.f, 1.f, 1.f);
|
|
quat_identity(&transform->rotation);
|
|
mat4_identity(&transform->trans_mat);
|
|
transform->parent = NULL;
|
|
transform->children = NULL;
|
|
transform->is_modified = false;
|
|
}
|
|
|
|
void transform_set_position(struct Entity* entity, vec3* new_position)
|
|
{
|
|
struct Transform* transform = &entity->transform;
|
|
vec3_assign(&transform->position, new_position);
|
|
transform_update_transmat(entity);
|
|
}
|
|
|
|
void transform_get_absolute_position(struct Entity* entity, vec3* res)
|
|
{
|
|
res->x = entity->transform.trans_mat.mat[12];
|
|
res->y = entity->transform.trans_mat.mat[13];
|
|
res->z = entity->transform.trans_mat.mat[14];
|
|
}
|
|
|
|
void transform_get_absolute_scale(struct Entity* entity, vec3* res)
|
|
{
|
|
struct Transform* transform = &entity->transform;
|
|
vec3_assign(res, &transform->scale);
|
|
bool done = false;
|
|
struct Entity* parent = transform->parent;
|
|
while(!done)
|
|
{
|
|
if(!parent)
|
|
{
|
|
done = true;
|
|
break;
|
|
}
|
|
vec3_mul(res, res, &parent->transform.scale);
|
|
parent = parent->transform.parent;
|
|
}
|
|
|
|
}
|
|
|
|
void transform_get_absolute_rotation(struct Entity* entity, quat* res)
|
|
{
|
|
quat_assign(res, &entity->transform.rotation);
|
|
bool done = false;
|
|
struct Entity* parent = entity->transform.parent;
|
|
while(!done)
|
|
{
|
|
if(!parent)
|
|
{
|
|
done = true;
|
|
break;
|
|
}
|
|
//quat_mul(res, res, &parent->transform.rotation);
|
|
quat_mul(res, &parent->transform.rotation, res);
|
|
parent = parent->transform.parent;
|
|
}
|
|
}
|
|
|
|
void transform_reset(struct Entity* entity)
|
|
{
|
|
/* Does remove/change parent or children, only modifies that transformation data */
|
|
vec3_fill(&entity->transform.position, 0.f, 0.f, 0.f);
|
|
vec3_fill(&entity->transform.scale, 0.f, 0.f, 0.f);
|
|
quat_identity(&entity->transform.rotation);
|
|
transform_update_transmat(entity);
|
|
}
|
|
|