quakeforge/include/QF/scene/transform.h
Bill Currie 35eec0b2e5 [ecs] Implement hierarchies as components
The main goal of this change was to make it easier to tell when a
hierarchy has been deleted, but as a side benefit, it got rid of the use
of PR_RESMAP. Also, it's easy to track the number of hierarchies.

Unfortunately, it showed how brittle the component side of the ECS is
(scene and canvas registries assumed their components were the first (no
long the case), thus the sweeping changes).

Centerprint doesn't work (but it hasn't for a while).
2024-01-02 16:38:01 +09:00

365 lines
11 KiB
C

/*
transform.h
Transform management
Copyright (C) 2021 Bill Currie <bill@taniwha.org>
Author: Bill Currie <bill@taniwha.org>
Date: 2021/02/26
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
*/
#ifndef __QF_scene_transform_h
#define __QF_scene_transform_h
#include "QF/darray.h"
#include "QF/ecs.h"
#include "QF/qtypes.h"
#include "QF/simd/vec4f.h"
#include "QF/simd/mat4f.h"
/** \defgroup transform Transform management
\ingroup utils
*/
///@{
enum {
transform_type_name,
transform_type_tag,
transform_type_modified,
transform_type_localMatrix,
transform_type_localInverse,
transform_type_worldMatrix,
transform_type_worldInverse,
transform_type_localRotation,
transform_type_localScale,
transform_type_worldRotation,
transform_type_count
};
typedef struct transform_s {
ecs_registry_t *reg;
uint32_t id;
uint32_t comp;
} transform_t;
#define nulltransform ((transform_t) {})
#define XFORMINLINE GNU89INLINE inline __attribute__((pure))
XFORMINLINE int Transform_Valid (transform_t transform);
transform_t Transform_New (ecs_system_t ssys, transform_t parent);
/* Deletes all child transforms, and transform names */
void Transform_Delete (transform_t transform);
transform_t Transform_NewNamed (ecs_system_t ssys, transform_t parent,
const char *name);
XFORMINLINE hierref_t Transform_GetRef (transform_t transform);
XFORMINLINE uint32_t Transform_ChildCount (transform_t transform);
XFORMINLINE transform_t Transform_GetChild (transform_t transform,
uint32_t childIndex);
void Transform_SetParent (transform_t transform, transform_t parent);
XFORMINLINE transform_t Transform_GetParent (transform_t transform);
void Transform_SetName (transform_t transform, const char *name);
XFORMINLINE const char *Transform_GetName (transform_t transform);
void Transform_SetTag (transform_t transform, uint32_t tag);
XFORMINLINE uint32_t Transform_GetTag (transform_t transform);
GNU89INLINE inline void Transform_GetLocalMatrix (transform_t transform,
mat4f_t mat);
GNU89INLINE inline void Transform_GetLocalInverse (transform_t transform,
mat4f_t mat);
GNU89INLINE inline void Transform_GetWorldMatrix (transform_t transform,
mat4f_t mat);
// XXX the pointer may be invalidated by hierarchy updates
XFORMINLINE const vec4f_t *Transform_GetWorldMatrixPtr (transform_t transform);
GNU89INLINE inline void Transform_GetWorldInverse (transform_t transform,
mat4f_t mat);
XFORMINLINE vec4f_t Transform_GetLocalPosition (transform_t transform);
void Transform_SetLocalPosition (transform_t transform, vec4f_t position);
XFORMINLINE vec4f_t Transform_GetLocalRotation (transform_t transform);
void Transform_SetLocalRotation (transform_t transform, vec4f_t rotation);
XFORMINLINE vec4f_t Transform_GetLocalScale (transform_t transform);
void Transform_SetLocalScale (transform_t transform, vec4f_t scale);
XFORMINLINE vec4f_t Transform_GetWorldPosition (transform_t transform);
void Transform_SetWorldPosition (transform_t transform, vec4f_t position);
XFORMINLINE vec4f_t Transform_GetWorldRotation (transform_t transform);
void Transform_SetWorldRotation (transform_t transform, vec4f_t rotation);
XFORMINLINE vec4f_t Transform_GetWorldScale (transform_t transform);
void Transform_SetLocalTransform (transform_t transform, vec4f_t scale,
vec4f_t rotation, vec4f_t position);
// NOTE: these use X: forward, -Y: right, Z:up
// aslo, not guaranteed to be normalized or even orthogonal
XFORMINLINE vec4f_t Transform_Forward (transform_t transform);
XFORMINLINE vec4f_t Transform_Right (transform_t transform);
XFORMINLINE vec4f_t Transform_Up (transform_t transform);
// no SetWorldScale because after rotations, non uniform scale becomes shear
#undef XFORMINLINE
#ifndef IMPLEMENT_TRANSFORM_Funcs
#define XFORMINLINE GNU89INLINE inline
#else
#define XFORMINLINE VISIBLE
#endif
XFORMINLINE
int
Transform_Valid (transform_t transform)
{
return transform.reg && ECS_EntValid (transform.id, transform.reg);
}
XFORMINLINE
hierref_t
Transform_GetRef (transform_t transform)
{
return *(hierref_t *) Ent_GetComponent (transform.id, transform.comp,
transform.reg);
}
XFORMINLINE
uint32_t
Transform_ChildCount (transform_t transform)
{
auto ref = Transform_GetRef (transform);
hierarchy_t *h = Ent_GetComponent (ref.id, ecs_hierarchy, transform.reg);
return h->childCount[ref.index];
}
XFORMINLINE
transform_t
Transform_GetChild (transform_t transform, uint32_t childIndex)
{
auto ref = Transform_GetRef (transform);
hierarchy_t *h = Ent_GetComponent (ref.id, ecs_hierarchy, transform.reg);
if (childIndex >= h->childCount[ref.index]) {
return nulltransform;
}
return (transform_t) {
.reg = transform.reg,
.id = h->ent[h->childIndex[ref.index] + childIndex],
.comp = transform.comp,
};
}
XFORMINLINE
transform_t
Transform_GetParent (transform_t transform)
{
auto ref = Transform_GetRef (transform);
if (ref.index == 0) {
return nulltransform;
}
hierarchy_t *h = Ent_GetComponent (ref.id, ecs_hierarchy, transform.reg);
return (transform_t) {
.reg = transform.reg,
.id = h->ent[h->parentIndex[ref.index]],
.comp = transform.comp,
};
}
XFORMINLINE
const char *
Transform_GetName (transform_t transform)
{
auto ref = Transform_GetRef (transform);
hierarchy_t *h = Ent_GetComponent (ref.id, ecs_hierarchy, transform.reg);
char **name = h->components[transform_type_name];
return name[ref.index];
}
XFORMINLINE
uint32_t
Transform_GetTag (transform_t transform)
{
auto ref = Transform_GetRef (transform);
hierarchy_t *h = Ent_GetComponent (ref.id, ecs_hierarchy, transform.reg);
uint32_t *tag = h->components[transform_type_tag];
return tag[ref.index];
}
XFORMINLINE
void
Transform_GetLocalMatrix (transform_t transform, mat4f_t mat)
{
auto ref = Transform_GetRef (transform);
hierarchy_t *h = Ent_GetComponent (ref.id, ecs_hierarchy, transform.reg);
mat4f_t *localMatrix = h->components[transform_type_localMatrix];
vec4f_t *src = localMatrix[ref.index];
mat[0] = src[0];
mat[1] = src[1];
mat[2] = src[2];
mat[3] = src[3];
}
XFORMINLINE
void
Transform_GetLocalInverse (transform_t transform, mat4f_t mat)
{
auto ref = Transform_GetRef (transform);
hierarchy_t *h = Ent_GetComponent (ref.id, ecs_hierarchy, transform.reg);
mat4f_t *localInverse = h->components[transform_type_localInverse];
vec4f_t *src = localInverse[ref.index];
mat[0] = src[0];
mat[1] = src[1];
mat[2] = src[2];
mat[3] = src[3];
}
XFORMINLINE
void
Transform_GetWorldMatrix (transform_t transform, mat4f_t mat)
{
auto ref = Transform_GetRef (transform);
hierarchy_t *h = Ent_GetComponent (ref.id, ecs_hierarchy, transform.reg);
mat4f_t *worldMatrix = h->components[transform_type_worldMatrix];
vec4f_t *src = worldMatrix[ref.index];
mat[0] = src[0];
mat[1] = src[1];
mat[2] = src[2];
mat[3] = src[3];
}
XFORMINLINE
const vec4f_t *
Transform_GetWorldMatrixPtr (transform_t transform)
{
auto ref = Transform_GetRef (transform);
hierarchy_t *h = Ent_GetComponent (ref.id, ecs_hierarchy, transform.reg);
mat4f_t *worldMatrix = h->components[transform_type_worldMatrix];
return worldMatrix[ref.index];
}
XFORMINLINE
void
Transform_GetWorldInverse (transform_t transform, mat4f_t mat)
{
auto ref = Transform_GetRef (transform);
hierarchy_t *h = Ent_GetComponent (ref.id, ecs_hierarchy, transform.reg);
mat4f_t *worldInverse = h->components[transform_type_worldInverse];
vec4f_t *src = worldInverse[ref.index];
mat[0] = src[0];
mat[1] = src[1];
mat[2] = src[2];
mat[3] = src[3];
}
XFORMINLINE
vec4f_t
Transform_GetLocalPosition (transform_t transform)
{
auto ref = Transform_GetRef (transform);
hierarchy_t *h = Ent_GetComponent (ref.id, ecs_hierarchy, transform.reg);
mat4f_t *localMatrix = h->components[transform_type_localMatrix];
return localMatrix[ref.index][3];
}
XFORMINLINE
vec4f_t
Transform_GetLocalRotation (transform_t transform)
{
auto ref = Transform_GetRef (transform);
hierarchy_t *h = Ent_GetComponent (ref.id, ecs_hierarchy, transform.reg);
vec4f_t *localRotation = h->components[transform_type_localRotation];
return localRotation[ref.index];
}
XFORMINLINE
vec4f_t
Transform_GetLocalScale (transform_t transform)
{
auto ref = Transform_GetRef (transform);
hierarchy_t *h = Ent_GetComponent (ref.id, ecs_hierarchy, transform.reg);
vec4f_t *localScale = h->components[transform_type_localScale];
return localScale[ref.index];
}
XFORMINLINE
vec4f_t
Transform_GetWorldPosition (transform_t transform)
{
auto ref = Transform_GetRef (transform);
hierarchy_t *h = Ent_GetComponent (ref.id, ecs_hierarchy, transform.reg);
mat4f_t *worldMatrix = h->components[transform_type_worldMatrix];
return worldMatrix[ref.index][3];
}
XFORMINLINE
vec4f_t
Transform_GetWorldRotation (transform_t transform)
{
auto ref = Transform_GetRef (transform);
hierarchy_t *h = Ent_GetComponent (ref.id, ecs_hierarchy, transform.reg);
vec4f_t *worldRotation = h->components[transform_type_worldRotation];
return worldRotation[ref.index];
}
XFORMINLINE
vec4f_t
Transform_GetWorldScale (transform_t transform)
{
auto ref = Transform_GetRef (transform);
hierarchy_t *h = Ent_GetComponent (ref.id, ecs_hierarchy, transform.reg);
mat4f_t *worldMatrix = h->components[transform_type_worldMatrix];
vec4f_t *m = worldMatrix[ref.index];
vec4f_t s = {
dotf (m[0], m[0])[0],
dotf (m[1], m[1])[0],
dotf (m[2], m[2])[0],
0,
};
return vsqrt4f (s);
}
XFORMINLINE
vec4f_t
Transform_Forward (transform_t transform)
{
auto ref = Transform_GetRef (transform);
hierarchy_t *h = Ent_GetComponent (ref.id, ecs_hierarchy, transform.reg);
mat4f_t *worldMatrix = h->components[transform_type_worldMatrix];
return worldMatrix[ref.index][0];
}
XFORMINLINE
vec4f_t
Transform_Right (transform_t transform)
{
auto ref = Transform_GetRef (transform);
hierarchy_t *h = Ent_GetComponent (ref.id, ecs_hierarchy, transform.reg);
mat4f_t *worldMatrix = h->components[transform_type_worldMatrix];
return -worldMatrix[ref.index][1];
}
XFORMINLINE
vec4f_t
Transform_Up (transform_t transform)
{
auto ref = Transform_GetRef (transform);
hierarchy_t *h = Ent_GetComponent (ref.id, ecs_hierarchy, transform.reg);
mat4f_t *worldMatrix = h->components[transform_type_worldMatrix];
return worldMatrix[ref.index][2];
}
///@}
#endif//__QF_scene_transform_h