quakeforge/libs/scene/transform.c

346 lines
8.8 KiB
C

/*
transform.c
General transform handling
Copyright (C) 2021 Bill Currke
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include "QF/scene/hierarchy.h"
#include "QF/scene/transform.h"
transform_t *
Transform_New (transform_t *parent)
{
transform_t *transform = malloc (sizeof (transform_t));
if (parent) {
transform->hierarchy = parent->hierarchy;
transform->index = Hierarchy_InsertHierarchy (parent->hierarchy, 0,
parent->index, 0);
} else {
transform->hierarchy = Hierarchy_New (16, 1);//FIXME should be config
transform->index = 0;
}
transform->hierarchy->transform.a[transform->index] = transform;
Hierarchy_UpdateMatrices (transform->hierarchy);
return transform;
}
void
Transform_Delete (transform_t *transform)
{
if (transform->index != 0) {
// The transform is not the root, so pull it out of its current
// hierarchy so deleting it is easier
Transform_SetParent (transform, 0);
}
Hierarchy_Delete (transform->hierarchy);
}
transform_t *
Transform_NewNamed (transform_t *parent, const char *name)
{
transform_t *transform = Transform_New (parent);
Transform_SetName (transform, name);
return transform;
}
uint32_t
Transform_ChildCount (const transform_t *transform)
{
hierarchy_t *h = transform->hierarchy;
return h->childCount.a[transform->index];
}
transform_t *
Transform_GetChild (const transform_t *transform, uint32_t childIndex)
{
hierarchy_t *h = transform->hierarchy;
if (childIndex >= h->childCount.a[transform->index]) {
return 0;
}
return h->transform.a[h->childIndex.a[transform->index] + childIndex];
}
void
Transform_SetParent (transform_t *transform, transform_t *parent)
{
if (parent) {
hierarchy_t *hierarchy = transform->hierarchy;
uint32_t index = transform->index;
Hierarchy_InsertHierarchy (parent->hierarchy, hierarchy,
parent->index, index);
Hierarchy_RemoveHierarchy (hierarchy, index);
if (!hierarchy->name.size) {
Hierarchy_Delete (hierarchy);
}
} else {
// null parent -> make transform root
if (!transform->index) {
// already root
return;
}
hierarchy_t *hierarchy = transform->hierarchy;
uint32_t index = transform->index;
hierarchy_t *new_hierarchy = Hierarchy_New (16, 0);
Hierarchy_InsertHierarchy (new_hierarchy, hierarchy, null_transform,
index);
Hierarchy_RemoveHierarchy (hierarchy, index);
}
}
transform_t *
Transform_GetParent (const transform_t *transform)
{
if (transform->index == 0) {
return 0;
}
hierarchy_t *h = transform->hierarchy;
return h->transform.a[h->parentIndex.a[transform->index]];
}
void
Transform_SetName (transform_t *transform, const char *name)
{
hierarchy_t *h = transform->hierarchy;
//FIXME create a string pool (similar to qfcc's, or even move that to util)
if (h->name.a[transform->index]) {
free (h->name.a[transform->index]);
}
h->name.a[transform->index] = strdup (name);
}
const char *
Transform_GetName (const transform_t *transform)
{
hierarchy_t *h = transform->hierarchy;
return h->name.a[transform->index];
}
void
Transform_SetTag (transform_t *transform, uint32_t tag)
{
hierarchy_t *h = transform->hierarchy;
h->tag.a[transform->index] = tag;
}
uint32_t
Transform_GetTag (const transform_t *transform)
{
hierarchy_t *h = transform->hierarchy;
return h->tag.a[transform->index];
}
void
Transform_GetLocalMatrix (const transform_t *transform, mat4f_t mat)
{
hierarchy_t *h = transform->hierarchy;
memcpy (mat, h->localMatrix.a[transform->index], sizeof (mat4f_t));
}
void
Transform_GetLocalInverse (const transform_t *transform, mat4f_t mat)
{
hierarchy_t *h = transform->hierarchy;
memcpy (mat, h->localInverse.a[transform->index], sizeof (mat4f_t));
}
void
Transform_GetWorldMatrix (const transform_t *transform, mat4f_t mat)
{
hierarchy_t *h = transform->hierarchy;
memcpy (mat, h->worldMatrix.a[transform->index], sizeof (mat4f_t));
}
const vec4f_t *
Transform_GetWorldMatrixPtr (const transform_t *transform)
{
hierarchy_t *h = transform->hierarchy;
return h->worldMatrix.a[transform->index];
}
void
Transform_GetWorldInverse (const transform_t *transform, mat4f_t mat)
{
hierarchy_t *h = transform->hierarchy;
memcpy (mat, h->worldInverse.a[transform->index], sizeof (mat4f_t));
}
vec4f_t
Transform_GetLocalPosition (const transform_t *transform)
{
hierarchy_t *h = transform->hierarchy;
return h->localMatrix.a[transform->index][3];
}
void
Transform_SetLocalPosition (transform_t *transform, vec4f_t position)
{
hierarchy_t *h = transform->hierarchy;
h->localMatrix.a[transform->index][3] = position;
h->modified.a[transform->index] = 1;
Hierarchy_UpdateMatrices (h);
}
vec4f_t
Transform_GetLocalRotation (const transform_t *transform)
{
hierarchy_t *h = transform->hierarchy;
return h->localRotation.a[transform->index];
}
void
Transform_SetLocalRotation (transform_t *transform, vec4f_t rotation)
{
hierarchy_t *h = transform->hierarchy;
vec4f_t scale = h->localScale.a[transform->index];
mat4f_t mat;
mat4fquat (mat, rotation);
h->localRotation.a[transform->index] = rotation;
h->localMatrix.a[transform->index][0] = mat[0] * scale[0];
h->localMatrix.a[transform->index][1] = mat[1] * scale[1];
h->localMatrix.a[transform->index][2] = mat[2] * scale[2];
h->modified.a[transform->index] = 1;
Hierarchy_UpdateMatrices (h);
}
vec4f_t
Transform_GetLocalScale (const transform_t *transform)
{
hierarchy_t *h = transform->hierarchy;
return h->localScale.a[transform->index];
}
void
Transform_SetLocalScale (transform_t *transform, vec4f_t scale)
{
hierarchy_t *h = transform->hierarchy;
vec4f_t rotation = h->localRotation.a[transform->index];
mat4f_t mat;
mat4fquat (mat, rotation);
h->localScale.a[transform->index] = scale;
h->localMatrix.a[transform->index][0] = mat[0] * scale[0];
h->localMatrix.a[transform->index][1] = mat[1] * scale[1];
h->localMatrix.a[transform->index][2] = mat[2] * scale[2];
h->modified.a[transform->index] = 1;
Hierarchy_UpdateMatrices (h);
}
vec4f_t
Transform_GetWorldPosition (const transform_t *transform)
{
hierarchy_t *h = transform->hierarchy;
return h->worldMatrix.a[transform->index][3];
}
void
Transform_SetWorldPosition (transform_t *transform, vec4f_t position)
{
if (transform->index) {
hierarchy_t *h = transform->hierarchy;
uint32_t parent = h->parentIndex.a[transform->index];
position = mvmulf (h->worldInverse.a[parent], position);
}
Transform_SetLocalPosition (transform, position);
}
vec4f_t
Transform_GetWorldRotation (const transform_t *transform)
{
hierarchy_t *h = transform->hierarchy;
return h->worldRotation.a[transform->index];
}
void
Transform_SetWorldRotation (transform_t *transform, vec4f_t rotation)
{
if (transform->index) {
hierarchy_t *h = transform->hierarchy;
uint32_t parent = h->parentIndex.a[transform->index];
rotation = qmulf (qconjf (h->worldRotation.a[parent]), rotation);
}
Transform_SetLocalRotation (transform, rotation);
}
vec4f_t
Transform_GetWorldScale (const transform_t *transform)
{
hierarchy_t *h = transform->hierarchy;
return h->worldScale.a[transform->index];
}
void
Transform_SetLocalTransform (transform_t *transform, vec4f_t scale,
vec4f_t rotation, vec4f_t position)
{
hierarchy_t *h = transform->hierarchy;
mat4f_t mat;
mat4fquat (mat, rotation);
position[3] = 1;
h->localRotation.a[transform->index] = rotation;
h->localScale.a[transform->index] = scale;
h->localMatrix.a[transform->index][0] = mat[0] * scale[0];
h->localMatrix.a[transform->index][1] = mat[1] * scale[1];
h->localMatrix.a[transform->index][2] = mat[2] * scale[2];
h->localMatrix.a[transform->index][3] = position;
h->modified.a[transform->index] = 1;
Hierarchy_UpdateMatrices (h);
}
vec4f_t
Transform_Forward (const transform_t *transform)
{
hierarchy_t *h = transform->hierarchy;
return h->worldMatrix.a[transform->index][0];
}
vec4f_t
Transform_Right (const transform_t *transform)
{
hierarchy_t *h = transform->hierarchy;
return -h->worldMatrix.a[transform->index][1];
}
vec4f_t
Transform_Up (const transform_t *transform)
{
hierarchy_t *h = transform->hierarchy;
return h->worldMatrix.a[transform->index][2];
}