From a4d9b349143e1d81d3957bbd0224837d94364cbd Mon Sep 17 00:00:00 2001 From: Joseph Walton-Rivers <joseph@walton-rivers.uk> Date: Sun, 5 Jun 2022 00:38:22 +0100 Subject: [PATCH] clean transform - which somehow fixed the sphere --- demo/data/rollball.yml | 16 ++++--- demo/demo/rollball.cpp | 41 ++++++++++------ demo/include/rollball.hpp | 11 ++++- fggl/phys/bullet/simulation.cpp | 10 +++- include/fggl/ecs3/prototype/loader.hpp | 65 +++++++++++++++++++++----- include/fggl/math/types.hpp | 65 ++++++++++++++++---------- 6 files changed, 149 insertions(+), 59 deletions(-) diff --git a/demo/data/rollball.yml b/demo/data/rollball.yml index 0a58e7f..ee508ba 100644 --- a/demo/data/rollball.yml +++ b/demo/data/rollball.yml @@ -6,7 +6,7 @@ prefabs: StaticMesh: pipeline: phong shape: - type: cube + type: box scale: [1.0, 5.0, 41] phys::Body: type: static @@ -20,7 +20,7 @@ prefabs: StaticMesh: pipeline: phong shape: - type: cube + type: box scale: [39, 5, 1] phys::Body: type: static @@ -33,13 +33,13 @@ prefabs: StaticMesh: pipeline: phong shape: - type: cube # we don't (currently) support planes... - scale: [40, 0.5, 40] + type: box # we don't (currently) support planes... + scale: [39, 0.5, 39] phys::Body: type: static shape: type: box # we don't (currently) support planes... - extents: [20, 0.25, 20] + extents: [19.5, 0.25, 19.5] - name: player components: Transform: @@ -57,8 +57,10 @@ prefabs: StaticMesh: pipeline: phong shape: - type: cube + type: box phys::Body: type: kinematic shape: - type: box \ No newline at end of file + type: box + phys::Callbacks: + phys::Cache: \ No newline at end of file diff --git a/demo/demo/rollball.cpp b/demo/demo/rollball.cpp index 5d8851c..c4fb400 100644 --- a/demo/demo/rollball.cpp +++ b/demo/demo/rollball.cpp @@ -24,12 +24,14 @@ #include "fggl/util/service.h" #include "fggl/ecs3/prototype/loader.hpp" +#include <array> + struct Prefabs { fggl::ecs3::entity_t collectable; fggl::ecs3::entity_t player; }; -static void setupPrefabs(fggl::ecs3::World& world, Prefabs& prefabs) { +static void setup_prefabs(fggl::ecs3::World& world, Prefabs& prefabs) { auto storage = fggl::util::ServiceLocator::instance().get<fggl::data::Storage>(); fggl::ecs3::load_prototype_file(world, *storage, "rollball.yml"); @@ -51,7 +53,7 @@ static void setupPrefabs(fggl::ecs3::World& world, Prefabs& prefabs) { } -static void setupCamera(fggl::ecs3::World& world) { +static void setup_camera(fggl::ecs3::World& world) { auto prototype = world.create(false); // setup camera position/transform @@ -64,7 +66,7 @@ static void setupCamera(fggl::ecs3::World& world) { world.add<fggl::gfx::Camera>(prototype); } -static fggl::ecs3::entity_t setupEnvironment(fggl::ecs3::World& world, fggl::math::vec2& size) { +static fggl::ecs3::entity_t setup_environment(fggl::ecs3::World& world, fggl::math::vec2& size, demo::RollState& state) { { auto northWall = world.createFromPrototype("wallX"); auto* transform = world.get<fggl::math::Transform>(northWall); @@ -95,10 +97,9 @@ static fggl::ecs3::entity_t setupEnvironment(fggl::ecs3::World& world, fggl::mat transform->origin({0.0f, -2.5f, 0.0f}); } - auto player = fggl::ecs3::NULL_ENTITY; { // player just starts off as the prefab dictates - player = world.createFromPrototype("player"); + state.player = world.createFromPrototype("player"); } { @@ -110,14 +111,17 @@ static fggl::ecs3::entity_t setupEnvironment(fggl::ecs3::World& world, fggl::mat }}; // build the collectables + int collectCount = 0; for (auto& pos : collectPos) { auto collectable = world.createFromPrototype("collectable"); auto* transform = world.get<fggl::math::Transform>(collectable); transform->origin(pos); + + state.collectables[collectCount++] = collectable; } } - return player; + return state.player; } @@ -130,22 +134,22 @@ namespace demo { Game::activate(); Prefabs prefabs{}; - setupPrefabs(world(), prefabs); + setup_prefabs(world(), prefabs); // collectable callbacks auto* collectableCallbacks = world().get<fggl::phys::CollisionCallbacks>(prefabs.collectable); collectableCallbacks->onEnter = [this](auto ourID, auto theirID) { - if ( theirID == player) { + if ( theirID == state.player) { this->world().destroy(ourID); } }; // actual scene objects - setupCamera(world()); + setup_camera(world()); // create a 20x20 grid fggl::math::vec2 size{40.0f, 40.0f}; - player = setupEnvironment(world(), size); + setup_environment(world(), size, state); } @@ -153,7 +157,7 @@ namespace demo { Game::update(); auto& input = this->input(); - if ( player != fggl::ecs3::NULL_ENTITY ) { + if ( state.player != fggl::ecs3::NULL_ENTITY ) { auto &world = this->world(); const fggl::math::vec3 forward = fggl::math::FORWARD; @@ -185,7 +189,7 @@ namespace demo { if ( moved ) { float forceFactor = 3.0F; force = glm::normalize(force) * forceFactor; - auto *dynamics = world.get<fggl::phys::Dynamics>(player); + auto *dynamics = world.get<fggl::phys::Dynamics>(state.player); dynamics->force += force; } @@ -193,12 +197,23 @@ namespace demo { auto cameras = world.findMatching<fggl::gfx::Camera>(); fggl::ecs3::entity_t cam = cameras[0]; auto *camComp = world.get<fggl::gfx::Camera>(cam); - camComp->target = world.get<fggl::math::Transform>(player)->origin(); + camComp->target = world.get<fggl::math::Transform>(state.player)->origin(); auto *camTransform = world.get<fggl::math::Transform>(cam); camTransform->origin( camComp->target + cameraOffset ); } + // rotation + for ( auto& entity : state.collectables ) { + if ( world.alive(entity) ) { + auto* transform = world.get<fggl::math::Transform>(entity); + + // rotate the cubes + fggl::math::vec3 angles{1.0F, 2.0F, 3.0F}; + transform->rotateEuler( angles * (60.0F / 1000) ); + } + } + state.time += (60.0f / 1000); } } diff --git a/demo/include/rollball.hpp b/demo/include/rollball.hpp index d1523de..de86c64 100644 --- a/demo/include/rollball.hpp +++ b/demo/include/rollball.hpp @@ -29,6 +29,15 @@ namespace demo { + struct RollState { + fggl::ecs::entity_t player = fggl::ecs::NULL_ENTITY; + std::array<fggl::ecs3::entity_t, 3> collectables { + fggl::ecs::NULL_ENTITY, + fggl::ecs::NULL_ENTITY, + fggl::ecs::NULL_ENTITY }; + float time = 0.0f; + }; + class RollBall : public fggl::scenes::Game { public: @@ -40,7 +49,7 @@ namespace demo { void render(fggl::gfx::Graphics& gfx) override; private: - fggl::ecs3::entity_t player = fggl::ecs3::NULL_ENTITY; + RollState state; fggl::math::vec3 cameraOffset = {-15.0F, 15.0F, 0.0F}; }; diff --git a/fggl/phys/bullet/simulation.cpp b/fggl/phys/bullet/simulation.cpp index da1291a..e771e5d 100644 --- a/fggl/phys/bullet/simulation.cpp +++ b/fggl/phys/bullet/simulation.cpp @@ -159,6 +159,10 @@ namespace fggl::phys::bullet { auto* transform = m_ecs->get<math::Transform>(ent); auto* physBody = m_ecs->get<BulletBody>(ent); + if ( physBody->body->isKinematicObject() ) { + continue; + } + btTransform bTransform; physBody->motion->getWorldTransform(bTransform); @@ -169,8 +173,10 @@ namespace fggl::phys::bullet { // set the rotation const auto& btRot = bTransform.getRotation(); - math::quat rot{btRot.x(), btRot.y(), btRot.z(), btRot.w()}; - transform->setRotation(rot); + + math::vec3 rot; + btRot.getEulerZYX(rot.x, rot.y, rot.z); + transform->euler(rot); } } diff --git a/include/fggl/ecs3/prototype/loader.hpp b/include/fggl/ecs3/prototype/loader.hpp index 10f3346..1a39331 100644 --- a/include/fggl/ecs3/prototype/loader.hpp +++ b/include/fggl/ecs3/prototype/loader.hpp @@ -86,6 +86,30 @@ namespace YAML { } }; + template<> + struct convert<fggl::math::quat> { + static Node encode(const fggl::math::quat& rhs){ + Node node; + node.push_back(rhs.x); + node.push_back(rhs.y); + node.push_back(rhs.z); + node.push_back(rhs.w); + return node; + } + + static bool decode(const Node& node, fggl::math::quat& rhs) { + if ( !node.IsSequence() || node.size() != 3) { + return false; + } + + rhs.x = node[0].as<float>(); + rhs.y = node[1].as<float>(); + rhs.z = node[2].as<float>(); + rhs.w = node[3].as<float>(); + return true; + } + }; + template<> struct convert<fggl::phys::BodyType> { const static std::string TYPE_KINEMATIC; @@ -124,10 +148,10 @@ namespace YAML { namespace fggl::ecs { - template<> - bool restore_config(math::Transform* comp, const YAML::Node& node) { - return true; - } + constexpr int DEFAULT_STACKS = 16; + constexpr int DEFAULT_SLICES = 16; + constexpr const char* SHAPE_SPHERE_VALUE{"sphere"}; + constexpr const char* SHAPE_BOX_VALUE{"box"}; static void process_mesh(data::Mesh& out, const YAML::Node& shape) { auto transform = data::OFFSET_NONE; @@ -143,15 +167,23 @@ namespace fggl::ecs { // now the shape itself auto shapeType = shape["type"].as<std::string>(); - if ( shapeType == "cube" ) { + if ( shapeType == SHAPE_BOX_VALUE ) { data::make_cube(out, transform); - } else if ( shapeType == "sphere" ) { - int stacks = shape["stacks"].as<int>(16); - int slices = shape["slices"].as<int>(16); + } else if ( shapeType == SHAPE_SPHERE_VALUE ) { + int stacks = shape["stacks"].as<int>(DEFAULT_STACKS); + int slices = shape["slices"].as<int>(DEFAULT_SLICES); data::make_sphere(out, transform, stacks, slices); } } + template<> + bool restore_config(math::Transform* comp, const YAML::Node& node) { + comp->origin(node["origin"].as<math::vec3>( math::VEC3_ZERO )); + comp->euler(node["rotation"].as<math::vec3>(math::VEC3_ZERO)); + comp->scale(node["scale"].as<math::vec3>(math::VEC3_ONES)); + return true; + } + template<> bool restore_config(data::StaticMesh* meshComp, const YAML::Node& node) { if ( !node["pipeline"] ) { @@ -182,7 +214,6 @@ namespace fggl::ecs { return true; } - template<> bool restore_config(phys::RigidBody* body, const YAML::Node& node) { body->type = node["type"].as<fggl::phys::BodyType>(fggl::phys::BodyType::DYNAMIC); @@ -196,11 +227,11 @@ namespace fggl::ecs { if ( node["shape"] ) { auto type = node["shape"]["type"].as< std::string >(); - if (type == "box") { + if ( type == SHAPE_BOX_VALUE ) { // assume unit box if extents are missing auto extents = node["shape"]["extents"].as<math::vec3>(phys::UNIT_EXTENTS); body->shape = new phys::Box(extents); - } else if (type == "sphere") { + } else if ( type == SHAPE_SPHERE_VALUE ) { auto radius = node["shape"]["radius"].as<float>(0.5F); body->shape = new phys::Sphere(radius); } else { @@ -211,6 +242,18 @@ namespace fggl::ecs { return true; } + template<> + bool restore_config(phys::CollisionCallbacks* callbacks, const YAML::Node& node) { + // TODO implement callback scripting + return true; + } + + template<> + bool restore_config(phys::CollisionCache* cache, const YAML::Node& node){ + // probably nothing needed here. Ideally, this should be automatically added when callbacks are. + return true; + } + } #endif //FGGL_ECS3_PROTOTYPE_LOADER_HPP diff --git a/include/fggl/math/types.hpp b/include/fggl/math/types.hpp index 4b635c1..82bcfec 100644 --- a/include/fggl/math/types.hpp +++ b/include/fggl/math/types.hpp @@ -2,9 +2,11 @@ #define FGGL_MATH_TYPES_H #include <tuple> +#include <iostream> #include <glm/glm.hpp> #include <glm/ext/matrix_transform.hpp> +#include <glm/gtx/transform.hpp> #include <glm/gtc/quaternion.hpp> #include <glm/gtx/quaternion.hpp> @@ -46,6 +48,10 @@ namespace fggl::math { constexpr static const math::vec2 VEC2_ZERO {0.0F, 0.0F}; constexpr static const math::vec3 VEC3_ZERO {0.0F, 0.0F, 0.0F}; + constexpr static const math::vec3 VEC3_ONES {1.0F, 1.0F, 1.0F}; + + constexpr static const math::mat4 IDENTITY_M4 {1.0F}; + constexpr static const math::quat IDENTITY_Q {1.0F, 0.0, 0.0, 0.0}; // fastFloor from OpenSimplex2 inline int fastFloor(double x) { @@ -90,33 +96,35 @@ namespace fggl::math { struct Transform { constexpr static const char name[] = "Transform"; - Transform() : m_local(1.0f), m_model(1.0f), m_origin(0.0f), m_rotation(1.0f, 0.0f, 0.0f, 0.0f) { + Transform() : + m_model(IDENTITY_M4), + m_origin(math::VEC3_ZERO), + m_euler(math::VEC3_ZERO), + m_scale(math::VEC3_ONES) { } // local reference vectors [[nodiscard]] inline vec3 up() const { - return vec4(UP, 1.0) * m_local; + return vec4(UP, 1.0) * model(); } [[nodiscard]] inline vec3 forward() const { - return vec4(FORWARD, 1.0) * m_local; + return vec4(FORWARD, 1.0) * model(); } [[nodiscard]] inline vec3 right() const { - return vec4(RIGHT, 1.0) * m_local; + return vec4(RIGHT, 1.0) * model(); } inline void translate(const vec3 change) { m_origin += change; - update(); } inline void origin(const vec3 pos) { m_origin = pos; - update(); } [[nodiscard]] @@ -124,44 +132,51 @@ namespace fggl::math { return m_origin; } - void setRotation(const math::quat& newRot) { - m_rotation = newRot; - update(); + inline void scale(const vec3 scale) { + m_scale = scale; + } + + [[nodiscard]] + inline vec3 scale() const { + return m_scale; } - inline void rotate(math::vec3 axis, float angle) { + inline void rotate(math::vec3 axis, float radianAngle) { // documentation claims this is in degrees, based on experimentation this actually appears to be radians... - m_rotation = glm::rotate(m_rotation, angle, axis); - update(); + auto angles = axis * radianAngle; + m_euler += angles; + } + + inline void rotateEuler(vec3 angles) { + m_euler += angles; } inline void euler(vec3 angles) { - m_rotation = quat(angles); - update(); + m_euler = angles; } [[nodiscard]] inline glm::vec3 euler() const { - return glm::eulerAngles(m_rotation); + return m_euler; } inline mat4 model() const { - return glm::translate(glm::mat4(1.0F), m_origin) - * glm::toMat4(m_rotation); + const glm::mat4 transformX = glm::rotate( math::IDENTITY_M4,glm::radians(m_euler.x), glm::vec3(1.0f, 0.0f, 0.0f) ); + const glm::mat4 transformY = glm::rotate( math::IDENTITY_M4, glm::radians(m_euler.y), glm::vec3(0.0f, 1.0f, 0.0f) ); + const glm::mat4 transformZ = glm::rotate( math::IDENTITY_M4, glm::radians(m_euler.z), glm::vec3(0.0f, 0.0f, 1.0f) ); + + const auto rotation = transformY * transformX * transformZ; + return glm::translate(math::IDENTITY_M4, m_origin) + * rotation + * glm::scale( math::IDENTITY_M4, m_scale ); } private: - mat4 m_local; // us -> parent mat4 m_model; // us -> world vec3 m_origin; - quat m_rotation; + vec3 m_euler; + vec3 m_scale; - inline void update() { - mat4 t(1.0f); - t *= glm::toMat4(m_rotation); - t = glm::translate(t, m_origin); - m_local = t; - } }; } -- GitLab