Files
DX12/Engine/Components/Transform.cpp
2026-03-19 18:27:49 +08:00

213 lines
4.9 KiB
C++

#include "Transform.h"
#include "Entity.h"
namespace XEngine::transform {
namespace {
utl::vector<math::m4x4> to_world;
utl::vector<math::m4x4> inv_world;
utl::vector<math::v3> positions;
utl::vector<math::v3> orientations;
utl::vector<math::v4> rotations;
utl::vector<math::v3> scales;
utl::vector<u8> has_transform;
utl::vector<u8> changes_from_previous_frame;
u8 read_write_flag;
void
calculate_transform_matrices(id::id_type index)
{
assert(rotations.size() >= index);
assert(positions.size() >= index);
assert(scales.size() >= index);
using namespace DirectX;
XMVECTOR r{ XMLoadFloat4(&rotations[index]) };
XMVECTOR t{ XMLoadFloat3(&positions[index]) };
XMVECTOR s{ XMLoadFloat3(&scales[index]) };
XMMATRIX world{ XMMatrixAffineTransformation(s, XMQuaternionIdentity(), r, t) };
XMStoreFloat4x4(&to_world[index], world);
world.r[3] = XMVectorSet(0.f, 0.f, 0.f, 1.f);
XMMATRIX inverse_world{ XMMatrixInverse(nullptr,world) };
XMStoreFloat4x4(&inv_world[index], inverse_world);
has_transform[index] = 1;
}
math::v3
calculate_orientation(math::v4 rotation)
{
using namespace DirectX;
XMVECTOR rotation_quat{ XMLoadFloat4(&rotation) };
XMVECTOR front{ XMVectorSet(0.f,0.f,1.f,0.f) };
math::v3 orientation;
XMStoreFloat3(&orientation, XMVector3Rotate(front, rotation_quat));
return orientation;
}
void
set_rotation(transform_id id, const math::v4& rotation_quaternion)
{
const u32 index{ id::index(id) };
rotations[index] = rotation_quaternion;
orientations[index] = calculate_orientation(rotation_quaternion);
has_transform[index] = 0;
changes_from_previous_frame[index] |= component_flags::rotation;
}
void
set_orientation(transform_id id, const math::v3& rotation_quaternion)
{
}
void
set_position(transform_id id, const math::v3& position)
{
const u32 index{ id::index(id) };
positions[index] = position;
has_transform[index] = 0;
changes_from_previous_frame[index] |= component_flags::position;
}
void
set_scale(transform_id id, const math::v3& scale)
{
const u32 index{ id::index(id) };
scales[index] = scale;
has_transform[index] = 0;
changes_from_previous_frame[index] |= component_flags::scale;
}
} // namespace
component
create(init_info info, game_entity::entity entity)
{
assert(entity.is_valid());
const id::id_type entity_index{ id::index(entity.get_id()) };
if (positions.size() > entity_index)
{
math::v4 rotation{ info.rotation };
rotations[entity_index] = rotation;
orientations[entity_index] = calculate_orientation(rotation);
positions[entity_index] = math::v3{ info.position };
scales[entity_index] = math::v3{ info.scale };
has_transform[entity_index] = 0;
changes_from_previous_frame[entity_index] = (u8)component_flags::all;
}
else
{
assert(positions.size() == entity_index);
rotations.emplace_back(info.rotation);
orientations.emplace_back(calculate_orientation(math::v4{ info.rotation }));
positions.emplace_back(info.position);
scales.emplace_back(info.scale);
has_transform.emplace_back((u8)0);
to_world.emplace_back();
inv_world.emplace_back();
changes_from_previous_frame.emplace_back((u8)component_flags::all);
}
return component{ transform_id{ entity.get_id() } };
}
void
remove([[maybe_unused]] component c)
{
assert(c.is_valid());
}
void
get_transform_matrices(const game_entity::entity_id id, math::m4x4& world, math::m4x4& inverse_world)
{
assert(game_entity::entity{ id }.is_valid());
const id::id_type entity_index{ id::index(id) };
if (!has_transform[entity_index])
{
calculate_transform_matrices(entity_index);
}
world = to_world[entity_index];
inverse_world = inv_world[entity_index];
}
void
get_update_component_flags(const game_entity::entity_id *const ids, u32 count, u8 *const flags)
{
assert(ids && count && flags);
read_write_flag = 1;
for (u32 i{ 0 }; i < count; ++i)
{
assert(game_entity::entity{ ids[i] }.is_valid());
flags[i] = changes_from_previous_frame[id::index(ids[i])];
}
}
void
update(const component_cache *const cache, u32 count)
{
assert(cache && count);
if (read_write_flag)
{
memset(changes_from_previous_frame.data(), 0, changes_from_previous_frame.size());
read_write_flag = 0;
}
for (u32 i{ 0 }; i < count; ++i)
{
const component_cache& c{ cache[i] };
assert(component{ c.id }.is_valid());
if (c.flags & component_flags::rotation)
{
set_rotation(c.id, c.rotation);
}
if (c.flags & component_flags::orientation)
{
set_orientation(c.id, c.orientation);
}
if (c.flags & component_flags::position)
{
set_position(c.id, c.position);
}
if (c.flags & component_flags::scale)
{
set_scale(c.id, c.scale);
}
}
}
math::v3
component::orientation() const
{
assert(is_valid());
return orientations[id::index(_id)];
}
math::v3
component::position() const
{
assert(is_valid());
return positions[id::index(_id)];
}
math::v3
component::scale() const
{
assert(is_valid());
return scales[id::index(_id)];
}
math::v4
component::rotation() const
{
assert(is_valid());
return rotations[id::index(_id)];
}
}