add local_point and world_point props to mouse_evt

This commit is contained in:
BlackMATov
2020-05-09 03:16:37 +07:00
parent 408846de25
commit 00b60dd110
8 changed files with 191 additions and 103 deletions

View File

@@ -155,16 +155,27 @@ namespace e2d::touchable_events
(pressed)
(released))
public:
mouse_evt(gobject target, types type, mouse_button button)
mouse_evt(
gobject target,
types type,
mouse_button button,
const v2f& local_point,
const v2f& world_point)
: base_evt(target, true)
, type_(type)
, button_(button) {}
, button_(button)
, local_point_(local_point)
, world_point_(world_point) {}
[[nodiscard]] types type() const noexcept { return type_; }
[[nodiscard]] mouse_button button() const noexcept { return button_; }
[[nodiscard]] const v2f& local_point() const noexcept { return local_point_; }
[[nodiscard]] const v2f& world_point() const noexcept { return world_point_; }
private:
types type_ = types::pressed;
mouse_button button_ = mouse_button::left;
v2f local_point_ = v2f::zero();
v2f world_point_ = v2f::zero();
};
ENUM_HPP_REGISTER_TRAITS(mouse_evt::types)

View File

@@ -78,7 +78,13 @@ local touchable_mouse_evt = {
type = "pressed",
---@type string
button = "left"
button = "left",
---@type v2f
local_point = v2f.zero(),
--@type v2f
world_point = v2f.zero()
}
touchable.touchable_mouse_evt = touchable_mouse_evt

View File

@@ -14,11 +14,13 @@ end
---@param event touchable_event
function M:on_event(go, type, event)
if type == "touchable.mouse_evt" then
the_debug:trace(string.format("event: %q, type: %q, button: %q, target: %q",
the_debug:trace(string.format("event: %q\n-->type: %q\n-->button: %q\n-->target: %q\n-->local_point: %s\n-->world_point: %s",
type,
event.type,
event.button,
event.target.named and event.target.named.name or "[unnamed]"))
event.target.named and event.target.named.name or "[unnamed]",
event.local_point,
event.world_point))
end
end

View File

@@ -210,6 +210,16 @@ namespace e2d::bindings::high
"button", sol::property(
[](const touchable_events::mouse_evt& c) -> str {
return str(enum_hpp::to_string_or_throw(c.button()));
}),
"local_point", sol::property(
[](const touchable_events::mouse_evt& c) -> v2f {
return c.local_point();
}),
"world_point", sol::property(
[](const touchable_events::mouse_evt& c) -> v2f {
return c.world_point();
})
);

View File

@@ -24,19 +24,26 @@ namespace e2d::touch_system_impl
namespace e2d::touch_system_impl
{
class touchable_under_mouse final {};
struct touchable_under_mouse final {
v2f local_point{v2f::zero()};
v2f world_point{v2f::zero()};
};
struct world_space_rect_collider final {
struct world_space_collider_base {
m4f local_to_world{m4f::identity()};
};
struct world_space_rect_collider final : world_space_collider_base {
using local_space_collider_t = rect_collider;
std::array<v3f, 4> points{};
};
struct world_space_circle_collider final {
struct world_space_circle_collider final : world_space_collider_base {
using local_space_collider_t = circle_collider;
std::array<v3f, 12> points{};
};
struct world_space_polygon_collider final {
struct world_space_polygon_collider final : world_space_collider_base {
using local_space_collider_t = polygon_collider;
vector<v3f> points{};
};

View File

@@ -11,10 +11,9 @@
namespace e2d::touch_system_impl::impl
{
void update_world_space_collider(
void update_world_space_collider_points(
world_space_rect_collider& dst,
const rect_collider& src,
const m4f& local_to_world)
const rect_collider& src)
{
const v2f& of = src.offset();
const v2f& hs = src.size() * 0.5f;
@@ -24,16 +23,15 @@ namespace e2d::touch_system_impl::impl
const v2f p3{of.x + hs.x, of.y + hs.y};
const v2f p4{of.x - hs.x, of.y + hs.y};
dst.points[0] = v3f(v4f(p1, 0.f, 1.f) * local_to_world);
dst.points[1] = v3f(v4f(p2, 0.f, 1.f) * local_to_world);
dst.points[2] = v3f(v4f(p3, 0.f, 1.f) * local_to_world);
dst.points[3] = v3f(v4f(p4, 0.f, 1.f) * local_to_world);
dst.points[0] = v3f(v4f(p1, 0.f, 1.f) * dst.local_to_world);
dst.points[1] = v3f(v4f(p2, 0.f, 1.f) * dst.local_to_world);
dst.points[2] = v3f(v4f(p3, 0.f, 1.f) * dst.local_to_world);
dst.points[3] = v3f(v4f(p4, 0.f, 1.f) * dst.local_to_world);
}
void update_world_space_collider(
void update_world_space_collider_points(
world_space_circle_collider& dst,
const circle_collider& src,
const m4f& local_to_world)
const circle_collider& src)
{
const v2f& of = src.offset();
for ( std::size_t i = 0, e = dst.points.size(); i < e; ++i ) {
@@ -45,14 +43,13 @@ namespace e2d::touch_system_impl::impl
of +
v2f(math::cos(a), math::sin(a)) *
src.radius();
dst.points[i] = v3f(v4f(p, 0.f, 1.f) * local_to_world);
dst.points[i] = v3f(v4f(p, 0.f, 1.f) * dst.local_to_world);
}
}
void update_world_space_collider(
void update_world_space_collider_points(
world_space_polygon_collider& dst,
const polygon_collider& src,
const m4f& local_to_world)
const polygon_collider& src)
{
const vector<v2f>& src_points = src.points();
@@ -64,7 +61,7 @@ namespace e2d::touch_system_impl::impl
const v2f& of = src.offset();
for ( std::size_t i = 0, e = src_points.size(); i < e; ++i ) {
const v2f p = of + src_points[i];
dst.points.push_back(v3f(v4f(p, 0.f, 1.f) * local_to_world));
dst.points.push_back(v3f(v4f(p, 0.f, 1.f) * dst.local_to_world));
}
}
}
@@ -80,18 +77,25 @@ namespace e2d::touch_system_impl::impl
std::array<
v2f,
std::tuple_size_v<decltype(c.points)>
> points;
> screen_points;
std::transform(c.points.begin(), c.points.end(), points.begin(), [
bool success = true;
std::transform(c.points.begin(), c.points.end(), screen_points.begin(), [
&success,
&camera_vp,
&camera_viewport
](const v3f& point) noexcept {
return v2f(math::project(point, camera_vp, camera_viewport).first);
const auto& [screen_point, project_success] = math::project(
point,
camera_vp,
camera_viewport);
success = success && project_success;
return v2f(screen_point);
});
return !!pnpoly_aos(
math::numeric_cast<int>(points.size()),
points.data()->data(),
return success && !!pnpoly_aos(
math::numeric_cast<int>(screen_points.size()),
screen_points.data()->data(),
mouse_p.x, mouse_p.y);
}
@@ -104,18 +108,25 @@ namespace e2d::touch_system_impl::impl
std::array<
v2f,
std::tuple_size_v<decltype(c.points)>
> points;
> screen_points;
std::transform(c.points.begin(), c.points.end(), points.begin(), [
bool success = true;
std::transform(c.points.begin(), c.points.end(), screen_points.begin(), [
&success,
&camera_vp,
&camera_viewport
](const v3f& point) noexcept {
return v2f(math::project(point, camera_vp, camera_viewport).first);
const auto& [screen_point, project_success] = math::project(
point,
camera_vp,
camera_viewport);
success = success && project_success;
return v2f(screen_point);
});
return !!pnpoly_aos(
math::numeric_cast<int>(points.size()),
points.data()->data(),
return success && !!pnpoly_aos(
math::numeric_cast<int>(screen_points.size()),
screen_points.data()->data(),
mouse_p.x, mouse_p.y);
}
@@ -125,23 +136,30 @@ namespace e2d::touch_system_impl::impl
const m4f& camera_vp,
const b2f& camera_viewport)
{
static thread_local std::vector<v2f> points;
E2D_DEFER([](){ points.clear(); });
static thread_local std::vector<v2f> screen_points;
E2D_DEFER([](){ screen_points.clear(); });
if ( points.capacity() < c.points.size() ) {
points.reserve(math::max(points.capacity() * 2u, c.points.size()));
if ( screen_points.capacity() < c.points.size() ) {
screen_points.reserve(math::max(screen_points.capacity() * 2u, c.points.size()));
}
std::transform(c.points.begin(), c.points.end(), std::back_inserter(points), [
bool success = true;
std::transform(c.points.begin(), c.points.end(), std::back_inserter(screen_points), [
&success,
&camera_vp,
&camera_viewport
](const v3f& point) noexcept {
return v2f(math::project(point, camera_vp, camera_viewport).first);
const auto& [screen_point, project_success] = math::project(
point,
camera_vp,
camera_viewport);
success = success && project_success;
return v2f(screen_point);
});
return !!pnpoly_aos(
math::numeric_cast<int>(points.size()),
points.data()->data(),
return success && !!pnpoly_aos(
math::numeric_cast<int>(screen_points.size()),
screen_points.data()->data(),
mouse_p.x, mouse_p.y);
}
}

View File

@@ -12,20 +12,17 @@ namespace e2d::touch_system_impl
{
namespace impl
{
void update_world_space_collider(
void update_world_space_collider_points(
world_space_rect_collider& dst,
const rect_collider& src,
const m4f& local_to_world);
const rect_collider& src);
void update_world_space_collider(
void update_world_space_collider_points(
world_space_circle_collider& dst,
const circle_collider& src,
const m4f& local_to_world);
const circle_collider& src);
void update_world_space_collider(
void update_world_space_collider_points(
world_space_polygon_collider& dst,
const polygon_collider& src,
const m4f& local_to_world);
const polygon_collider& src);
template < typename WorldSpaceCollider >
void update_world_space_colliders(ecs::registry& owner) {
@@ -49,10 +46,13 @@ namespace e2d::touch_system_impl
const touchable&,
const actor& a)
{
update_world_space_collider(
e.ensure_component<world_space_collider_t>(),
src,
a.node() ? a.node()->world_matrix() : m4f::identity());
world_space_collider_t& world_space_collider =
e.ensure_component<world_space_collider_t>();
world_space_collider.local_to_world =
a.node() ? a.node()->world_matrix() : m4f::identity();
update_world_space_collider_points(world_space_collider, src);
}, !ecs::exists_any<
disabled<actor>,
disabled<touchable>,
@@ -91,13 +91,42 @@ namespace e2d::touch_system_impl
using world_space_collider_t = WorldSpaceCollider;
using local_space_collider_t = typename WorldSpaceCollider::local_space_collider_t;
m4f inv_camera_vp{m4f::identity()};
bool inv_camera_vp_success{false};
std::tie(inv_camera_vp, inv_camera_vp_success) = math::inversed(camera_vp, 0.f);
if ( !inv_camera_vp_success ) {
return;
}
owner.for_joined_components<touchable, world_space_collider_t>([
&mouse_p,
&camera_vp,
&inv_camera_vp,
&camera_viewport
](ecs::entity e, const touchable&, const world_space_collider_t& c){
if ( is_world_space_collider_under_mouse(c, mouse_p, camera_vp, camera_viewport) ) {
e.ensure_component<touchable_under_mouse>();
const auto& [world_point, world_point_success] = math::unproject(
v3f(mouse_p, 0.f),
inv_camera_vp,
camera_viewport);
if ( !world_point_success ) {
return;
}
const auto& [world_to_local, world_to_local_success] = math::inversed(
c.local_to_world);
if ( !world_to_local_success ) {
return;
}
touchable_under_mouse& under_mouse_c
= e.ensure_component<touchable_under_mouse>();
under_mouse_c.world_point = v2f(world_point);
under_mouse_c.local_point = v2f(v4f(world_point, 1.f) * world_to_local);
}
}, !ecs::exists_any<
disabled<touchable>,

View File

@@ -319,55 +319,60 @@ namespace e2d::touch_system_impl
//
//
for ( const auto& event : collector ) {
std::visit(utils::overloaded {
[](std::monostate){},
[](const collector::mouse_move_event& event){
E2D_UNUSED(event);
},
[](const collector::mouse_scroll_event& event){
E2D_UNUSED(event);
},
[&target](const collector::mouse_button_event& event){
switch ( event.action ) {
case mouse_button_action::press: {
const bool captured = dispatch_event(
target,
touchable_events::mouse_evt(
if ( target ) {
for ( const auto& event : collector ) {
std::visit(utils::overloaded {
[](std::monostate){},
[](const collector::mouse_move_event& event){
E2D_UNUSED(event);
},
[](const collector::mouse_scroll_event& event){
E2D_UNUSED(event);
},
[&target](const collector::mouse_button_event& event){
const auto make_mouse_evt = [
&event,
&target
](touchable_events::mouse_evt::types type){
return touchable_events::mouse_evt(
target,
touchable_events::mouse_evt::types::pressed,
event.button));
if ( captured && event.button == mouse_button::left ) {
target.component<touchable::pushing>().ensure();
}
break;
}
case mouse_button_action::release: {
const bool captured = dispatch_event(
target,
touchable_events::mouse_evt(
type,
event.button,
target.component<touchable_under_mouse>()->local_point,
target.component<touchable_under_mouse>()->world_point);
};
switch ( event.action ) {
case mouse_button_action::press: {
const bool captured = dispatch_event(
target,
touchable_events::mouse_evt::types::released,
event.button));
if ( captured && event.button == mouse_button::left ) {
if ( target.component<touchable::pushing>() ) {
target.component<touchable::pushing>().remove();
dispatch_event(
target,
touchable_events::mouse_evt(
target,
touchable_events::mouse_evt::types::clicked,
event.button));
make_mouse_evt(touchable_events::mouse_evt::types::pressed));
if ( captured && event.button == mouse_button::left ) {
target.component<touchable::pushing>().ensure();
}
break;
}
case mouse_button_action::release: {
const bool captured = dispatch_event(
target,
make_mouse_evt(touchable_events::mouse_evt::types::released));
if ( captured && event.button == mouse_button::left ) {
if ( target.component<touchable::pushing>() ) {
target.component<touchable::pushing>().remove();
dispatch_event(
target,
make_mouse_evt(touchable_events::mouse_evt::types::clicked));
}
}
break;
}
default:
E2D_ASSERT_MSG(false, "unexpected mouse button event action type");
break;
}
break;
}
default:
E2D_ASSERT_MSG(false, "unexpected mouse button event action type");
break;
}
}
}, event);
}, event);
}
}
}
}