Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added some physics stuff #69

Merged
merged 10 commits into from
Nov 28, 2024
Merged
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,6 @@ subdir('wren_vk')
# subdir('wren_gltf')
# subdir('wren_gui')
subdir('wren')
subdir('wren_physics')
# subdir('wren_ecs')
subdir('editor')
17 changes: 13 additions & 4 deletions wren/include/wren/scene/components.hpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
#pragma once

#include <functional>
#include <flecs.h>

#include "scene.hpp"
namespace wren::scene::components {

namespace wren::scene {
struct Base {
Base() = default;
Base(const Base &) = default;
Base(Base &&) = delete;
auto operator=(const Base &) -> Base & = default;
auto operator=(Base &&) -> Base & = delete;
virtual ~Base() = default;

// virtual void init(const flecs::world &world) = 0;
};

// void iterate_known_components(const Scene& scene, entt::entity entity,
// std::function<void()>);

}
} // namespace wren::scene::components
40 changes: 40 additions & 0 deletions wren/include/wren/scene/components/collider.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#pragma once

#include <flecs.h>

#include <memory>
#include <optional>
#include <wren/math/vector.hpp>
#include <wren/scene/components/transform.hpp>

#include "../components.hpp"

namespace wren::scene::components {

struct Collider : public Base {
using Ptr = std::shared_ptr<Collider>;

[[nodiscard]] virtual auto raycast(const Transform& transform,
const math::Vec3f& origin,
const math::Vec3f& direction) const
-> std::optional<math::Vec3f> = 0;
};

struct BoxCollider2D : public Collider {
static void init(const flecs::world& world) {
static bool inited = false;
if (!inited) {
inited = true;
world.component<BoxCollider2D::Ptr>().is_a<Collider>();
}
}

[[nodiscard]] auto raycast(const Transform& transform,
const math::Vec3f& origin,
const math::Vec3f& direction) const
-> std::optional<math::Vec3f> override;

math::Vec2f size;
};

} // namespace wren::scene::components
17 changes: 14 additions & 3 deletions wren/include/wren/scene/entity.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <flecs.h>

#include "components.hpp"
#include "scene.hpp"

namespace wren::scene {
Expand Down Expand Up @@ -30,18 +31,28 @@ class Entity {

template <typename T>
auto Entity::has_component() const -> bool {
// return scene_->world().all_of<T>();
return entity_.has<T>();
}

template <typename T>
auto Entity::get_component() -> T& {
return scene_->world().get<T>(entity_);
return *entity_.get_mut<T>();
}

template <typename T>
concept HasInit = requires() { T::init(); };

template <typename T, typename... Args>
void Entity::add_component(Args&&... args) {
entity_.add<T>();
entity_.set<T>(T(std::forward<Args>(args)...));
if (sizeof...(args) > 0) {
T t(std::forward<Args...>(args)...);
entity_.set<T>(t);
}

if constexpr (HasInit<T>) {
T::init(scene_->world());
}
}

} // namespace wren::scene
2 changes: 1 addition & 1 deletion wren/include/wren/scene/scene.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class Scene : public std::enable_shared_from_this<Scene> {
public:
static auto create() { return std::shared_ptr<Scene>(new Scene()); }

auto create_entity(const std::string& name = "entity") -> flecs::entity;
auto create_entity(const std::string& name = "entity") -> Entity;

auto world() const -> const flecs::world& { return ecs_; }
auto world() -> flecs::world& { return ecs_; }
Expand Down
1 change: 1 addition & 0 deletions wren/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ wren = library(
'src/render_pass.cpp',
'src/render_target.cpp',
'src/renderer.cpp',
'src/scene/components/collider.cpp',
'src/scene/deserialization.cpp',
'src/scene/scene.cpp',
'src/scene/serialization.cpp',
Expand Down
26 changes: 26 additions & 0 deletions wren/src/scene/components/collider.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include "scene/components/collider.hpp"

namespace wren::scene::components {

auto BoxCollider2D::raycast(const Transform& transform,
const math::Vec3f& origin,
const math::Vec3f& direction) const
-> std::optional<math::Vec3f> {
math::Vec3f normal =
math::Quaternionf{transform.rotation}.to_mat() * math::Vec3f{0, 0, 1};

float denominator = normal.dot(direction);
if (std::abs(denominator) < 0.0001) {
return {};

Check warning on line 14 in wren/src/scene/components/collider.cpp

View check run for this annotation

Codecov / codecov/patch

wren/src/scene/components/collider.cpp#L14

Added line #L14 was not covered by tests
}

float t = normal.dot(transform.position - origin) / denominator;
if (t < 0) {
// Intersection points is behind the ray's origin
return {};

Check warning on line 20 in wren/src/scene/components/collider.cpp

View check run for this annotation

Codecov / codecov/patch

wren/src/scene/components/collider.cpp#L20

Added line #L20 was not covered by tests
}

return origin + direction * t;
}

} // namespace wren::scene::components
4 changes: 2 additions & 2 deletions wren/src/scene/deserialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@

for (const auto& [key, val] : entity_table) {
if (key.str() == "transform") {
auto& t = *entity.get_mut<components::Transform>();
auto& t = entity.get_component<components::Transform>();

Check warning on line 32 in wren/src/scene/deserialization.cpp

View check run for this annotation

Codecov / codecov/patch

wren/src/scene/deserialization.cpp#L32

Added line #L32 was not covered by tests
deserialize(*val.as_table(), t);
} else if (key.str() == "mesh_renderer") {
components::MeshRenderer mesh_renderer{};
deserialize(*val.as_table(), project_root, mesh_renderer);
entity.emplace<components::MeshRenderer>(mesh_renderer);
entity.add_component<components::MeshRenderer>(mesh_renderer);

Check warning on line 37 in wren/src/scene/deserialization.cpp

View check run for this annotation

Codecov / codecov/patch

wren/src/scene/deserialization.cpp#L37

Added line #L37 was not covered by tests
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions wren/src/scene/scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@

namespace wren::scene {

auto Scene::create_entity(const std::string& name) -> flecs::entity {
auto Scene::create_entity(const std::string& name) -> Entity {
auto entity = ecs_.entity(name.c_str());

// entity.add_component<components::Tag>(name);
entity.add<components::Transform>();

return entity;
return {entity, shared_from_this()};
}

} // namespace wren::scene
21 changes: 21 additions & 0 deletions wren_physics/include/wren/physics/ray.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

#include <flecs.h>

#include <wren/math/vector.hpp>

namespace wren::physics {

struct RayHit {
bool hit = false;
math::Vec3f point;
};

struct Ray {
math::Vec3f origin;
math::Vec3f direction;
};

auto raycast(const flecs::world& world, const Ray& ray, RayHit& hit) -> bool;

} // namespace wren::physics
12 changes: 12 additions & 0 deletions wren_physics/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
wren_physics = static_library(
'wren_physics',
'src/ray.cpp',
dependencies: [wren_dep, flecs],
include_directories: ['include/wren', 'include/wren/physics'],
)
wren_physics_dep = declare_dependency(
include_directories: 'include',
link_with: wren_physics,
)

subdir('tests')
28 changes: 28 additions & 0 deletions wren_physics/src/ray.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include "physics/ray.hpp"

#include <wren/scene/components/collider.hpp>
#include <wren/scene/components/transform.hpp>

namespace wren::physics {

auto raycast(const flecs::world& world, const Ray& ray, RayHit& hit) -> bool {
const auto q = world.query<const scene::components::Transform,
const scene::components::Collider::Ptr>();

q.each([ray, &hit](const scene::components::Transform& transform,
const scene::components::Collider::Ptr& collider) {
if (hit.hit) {
return;

Check warning on line 15 in wren_physics/src/ray.cpp

View check run for this annotation

Codecov / codecov/patch

wren_physics/src/ray.cpp#L15

Added line #L15 was not covered by tests
}

auto pos = collider->raycast(transform, ray.origin, ray.direction);
if (pos.has_value()) {
hit.hit = true;
hit.point = pos.value();
}
});

return hit.hit;
}

} // namespace wren::physics
12 changes: 12 additions & 0 deletions wren_physics/tests/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
tests = ['raycast']
foreach test : tests
test(
'wren_physics_@0@'.format(test),
executable(
'wren_physics_@0@_test'.format(test),
'@[email protected]'.format(test),
dependencies: [wren_physics_dep, wren_dep, boost_test],
cpp_args: ['-DBOOST_TEST_MODULE=@0@'.format(test)],
),
)
endforeach
43 changes: 43 additions & 0 deletions wren_physics/tests/raycast.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include <boost/test/unit_test.hpp>
#include <wren/physics/ray.hpp>
#include <wren/scene/components.hpp>
#include <wren/scene/components/collider.hpp>
#include <wren/scene/components/transform.hpp>
#include <wren/scene/entity.hpp>
#include <wren/scene/scene.hpp>

namespace physics = wren::physics;
namespace components = wren::scene::components;
namespace math = wren::math;

BOOST_AUTO_TEST_SUITE(raycasting)

BOOST_AUTO_TEST_CASE(RaycastBoxCollider) {
const auto scene = wren::scene::Scene::create();

auto box = scene->create_entity("box");

box.add_component<components::BoxCollider2D::Ptr>(
new components::BoxCollider2D());
auto& transform = box.get_component<components::Transform>();
transform.position.z(-10);
// transform.position.x(1000);

BOOST_TEST(box.has_component<components::BoxCollider2D::Ptr>());

const auto q = scene->world().query<const components::Collider::Ptr>();
BOOST_TEST(q.count() == 1);

physics::Ray ray;
ray.direction = (transform.position - math::Vec3f(0));

physics::RayHit hit{};
physics::raycast(scene->world(), ray, hit);

BOOST_TEST(hit.hit);

const float length = (hit.point - math::Vec3f{0, 0, -10}).length();
BOOST_TEST(length <= 0.001);
}

BOOST_AUTO_TEST_SUITE_END()
Loading