mirror of
https://github.com/enduro2d/enduro2d.git
synced 2026-03-22 04:44:09 +07:00
add local_point and world_point props to mouse_evt
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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();
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
@@ -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{};
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user