A 3d fps game made in OpenGL
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.
 
 
 
 
Symmetry/src/game/transform.c

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(&copy_to->transform, &copy_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);
}