#include "Transform.h" #include "Entity.h" namespace XEngine::transform { namespace { utl::vector to_world; utl::vector inv_world; utl::vector positions; utl::vector orientations; utl::vector rotations; utl::vector scales; utl::vector has_transform; utl::vector 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)]; } }