basic touch system impl

This commit is contained in:
2020-02-05 11:12:30 +07:00
parent 89415081eb
commit 7f731f99bc
14 changed files with 668 additions and 327 deletions

View File

@@ -50,12 +50,12 @@
#include "systems/flipbook_system.hpp"
#include "systems/frame_system.hpp"
#include "systems/gizmos_system.hpp"
#include "systems/input_system.hpp"
#include "systems/label_system.hpp"
#include "systems/physics_system.hpp"
#include "systems/render_system.hpp"
#include "systems/script_system.hpp"
#include "systems/spine_system.hpp"
#include "systems/touch_system.hpp"
#include "systems/world_system.hpp"
#include "address.hpp"

View File

@@ -70,12 +70,12 @@ namespace e2d
class flipbook_system;
class frame_system;
class gizmos_system;
class input_system;
class label_system;
class physics_system;
class render_system;
class script_system;
class spine_system;
class touch_system;
class world_system;
template < typename Asset, typename Content >

View File

@@ -10,11 +10,11 @@
namespace e2d
{
class input_system final
class touch_system final
: public ecs::system<ecs::before<systems::update_event>> {
public:
input_system();
~input_system() noexcept final;
touch_system();
~touch_system() noexcept final;
void process(
ecs::registry& owner,

View File

@@ -51,14 +51,36 @@
"rigid_body" : {
"type" : "dynamic"
},
"rect_collider" : {
"size" : [66,113]
},
"circle_collider" : {
"offset" : [50,25],
"offset" : [10,15],
"radius" : 33
}
}
},
"children" : [{
"prototype" : "../prefabs/ship_prefab.json",
"components" : {
"named" : {
"name" : "ship(11)"
},
"actor" : {
"translation" : [0,0],
"rotation" : 1,
"scale" : [0.5,0.5]
},
"behaviour" : {
"script" : "../scripts/sample_08/ship.lua"
},
"touchable" : {},
"rigid_body" : {
"type" : "dynamic"
},
"circle_collider" : {
"offset" : [10,15],
"radius" : 33
}
},
"children" : []
}]
},{
"prototype" : "../prefabs/ship_prefab.json",
"components" : {

View File

@@ -11,8 +11,15 @@ end
---@param go gobject
---@param type string
---@param event any
---@param event touchable_input_evt | touchable_mouse_evt
function M:on_event(go, type, event)
if type == "touchable.mouse_evt" then
the_debug:trace(string.format(
"scene %q touched(%s %s)",
go.named and go.named.name or "---",
event.type,
event.button))
end
end
---@param go gobject

View File

@@ -24,4 +24,18 @@ end
function M.on_update(meta, go)
end
---@param go gobject
---@param type string
---@param event touchable_mouse_evt
function M:on_event(go, type, event)
if type == "touchable.mouse_evt" then
the_debug:trace(string.format(
"ship %q touched(%s %s) - %s",
go.named and go.named.name or "---",
event.type,
event.button,
go == event.target and "self" or "other"))
end
end
return M

View File

@@ -36,12 +36,12 @@
#include <enduro2d/high/systems/flipbook_system.hpp>
#include <enduro2d/high/systems/frame_system.hpp>
#include <enduro2d/high/systems/gizmos_system.hpp>
#include <enduro2d/high/systems/input_system.hpp>
#include <enduro2d/high/systems/label_system.hpp>
#include <enduro2d/high/systems/physics_system.hpp>
#include <enduro2d/high/systems/render_system.hpp>
#include <enduro2d/high/systems/script_system.hpp>
#include <enduro2d/high/systems/spine_system.hpp>
#include <enduro2d/high/systems/touch_system.hpp>
#include <enduro2d/high/systems/world_system.hpp>
namespace
@@ -70,8 +70,6 @@ namespace
.add_system<frame_system>())
.feature<struct gizmos_feature>(ecs::feature()
.add_system<gizmos_system>())
.feature<struct input_feature>(ecs::feature()
.add_system<input_system>())
.feature<struct label_feature>(ecs::feature()
.add_system<label_system>())
.feature<struct physics_feature>(ecs::feature()
@@ -82,6 +80,8 @@ namespace
.add_system<script_system>())
.feature<struct spine_feature>(ecs::feature()
.add_system<spine_system>())
.feature<struct touch_feature>(ecs::feature()
.add_system<touch_system>())
.feature<struct world_feature>(ecs::feature()
.add_system<world_system>());
return !application_ || application_->initialize();

View File

@@ -1,313 +0,0 @@
/*******************************************************************************
* This file is part of the "Enduro2D"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2018-2019, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include <enduro2d/high/systems/input_system.hpp>
#include <enduro2d/high/components/actor.hpp>
#include <enduro2d/high/components/camera.hpp>
#include <enduro2d/high/components/colliders.hpp>
#include <enduro2d/high/components/disabled.hpp>
#include <enduro2d/high/components/scene.hpp>
#include <enduro2d/high/components/touchable.hpp>
#include <enduro2d/high/gobject.hpp>
#include <enduro2d/high/node.hpp>
#define PNPOLY_IMPLEMENTATION
#include <3rdparty/pnpoly.h/pnpoly.h>
namespace
{
using namespace e2d;
struct world_space_rect_collider {
using local_space_collider_t = rect_collider;
std::array<v3f, 4> points{};
};
struct world_space_circle_collider {
using local_space_collider_t = circle_collider;
std::array<v3f, 12> points{};
};
struct world_space_polygon_collider {
using local_space_collider_t = polygon_collider;
vector<v3f> points{};
};
void update_world_space_collider(
world_space_rect_collider& dst,
const rect_collider& src,
const m4f& local_to_world)
{
const v2f& of = src.offset();
const v2f& hs = src.size() * 0.5f;
const v2f p1{of.x - hs.x, of.y - hs.y};
const v2f p2{of.x + hs.x, of.y - hs.y};
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);
}
void update_world_space_collider(
world_space_circle_collider& dst,
const circle_collider& src,
const m4f& local_to_world)
{
const v2f& of = src.offset();
for ( std::size_t i = 0, e = dst.points.size(); i < e; ++i ) {
const radf a =
math::two_pi<f32>() /
math::numeric_cast<f32>(e) *
math::numeric_cast<f32>(i);
const v2f p =
of +
v2f(math::cos(a), math::sin(a)) *
src.radius();
dst.points[i] = v3f(v4f(p, 0.f, 1.f) * local_to_world);
}
}
void update_world_space_collider(
world_space_polygon_collider& dst,
const polygon_collider& src,
const m4f& local_to_world)
{
const vector<v2f>& src_points = src.points();
dst.points.clear();
if ( dst.points.capacity() < src_points.size() ) {
dst.points.reserve(math::max(dst.points.capacity() * 2u, src_points.size()));
}
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));
}
}
template < typename WorldSpaceCollider >
void update_world_space_colliders(ecs::registry& owner) {
using world_space_collider_t = WorldSpaceCollider;
using local_space_collider_t = typename WorldSpaceCollider::local_space_collider_t;
ecsex::remove_all_components<world_space_collider_t>(
owner,
!ecs::exists_all<touchable, local_space_collider_t>());
owner.for_joined_components<touchable, local_space_collider_t, actor>([](
ecs::entity e,
const touchable&,
const local_space_collider_t& src,
const actor& a)
{
update_world_space_collider(
e.ensure_component<world_space_collider_t>(),
src,
a.node() ? a.node()->world_matrix() : m4f::identity());
}, !ecs::exists_any<
disabled<touchable>,
disabled<world_space_collider_t>,
disabled<local_space_collider_t>>());
}
}
namespace
{
using namespace e2d;
bool is_collider_under_mouse(
const world_space_rect_collider& c,
const v2f& mouse_p,
const m4f& camera_vp,
const b2f& camera_viewport) noexcept
{
std::array<
v2f,
std::tuple_size_v<decltype(c.points)>
> points;
std::transform(c.points.begin(), c.points.end(), points.begin(), [
&camera_vp,
&camera_viewport
](const v3f& point) noexcept {
return v2f(math::project(point, camera_vp, camera_viewport).first);
});
return !!pnpoly_aos(
math::numeric_cast<int>(points.size()),
points.data()->data(),
mouse_p.x, mouse_p.y);
}
bool is_collider_under_mouse(
const world_space_circle_collider& c,
const v2f& mouse_p,
const m4f& camera_vp,
const b2f& camera_viewport) noexcept
{
std::array<
v2f,
std::tuple_size_v<decltype(c.points)>
> points;
std::transform(c.points.begin(), c.points.end(), points.begin(), [
&camera_vp,
&camera_viewport
](const v3f& point) noexcept {
return v2f(math::project(point, camera_vp, camera_viewport).first);
});
return !!pnpoly_aos(
math::numeric_cast<int>(points.size()),
points.data()->data(),
mouse_p.x, mouse_p.y);
}
bool is_collider_under_mouse(
const world_space_polygon_collider& c,
const v2f& mouse_p,
const m4f& camera_vp,
const b2f& camera_viewport) noexcept
{
static thread_local std::vector<v2f> points;
points.clear();
if ( points.capacity() < c.points.size() ) {
points.reserve(math::max(points.capacity() * 2u, c.points.size()));
}
std::transform(c.points.begin(), c.points.end(), std::back_inserter(points), [
&camera_vp,
&camera_viewport
](const v3f& point) noexcept {
return v2f(math::project(point, camera_vp, camera_viewport).first);
});
return !!pnpoly_aos(
math::numeric_cast<int>(points.size()),
points.data()->data(),
mouse_p.x, mouse_p.y);
}
template < typename WorldSpaceCollider >
void update_colliders_under_mouse(
ecs::registry& owner,
const v2f& mouse_p,
const m4f& camera_vp,
const b2f& camera_viewport)
{
using world_space_collider_t = WorldSpaceCollider;
using local_space_collider_t = typename WorldSpaceCollider::local_space_collider_t;
owner.for_joined_components<touchable, world_space_collider_t>([
&mouse_p,
&camera_vp,
&camera_viewport
](ecs::entity e, const touchable&, const world_space_collider_t& c){
if ( is_collider_under_mouse(c, mouse_p, camera_vp, camera_viewport) ) {
e.ensure_component<touchable::under_mouse>();
}
}, !ecs::exists_any<
disabled<touchable>,
disabled<world_space_collider_t>,
disabled<local_space_collider_t>>());
}
}
namespace e2d
{
//
// input_system::internal_state
//
class input_system::internal_state final : private noncopyable {
public:
internal_state(input& i, window& w)
: input_(i)
, window_(w) {}
~internal_state() noexcept = default;
void process_update(ecs::registry& owner) {
owner.remove_all_components<touchable::touched>();
owner.remove_all_components<touchable::under_mouse>();
update_world_space_colliders<world_space_rect_collider>(owner);
update_world_space_colliders<world_space_circle_collider>(owner);
update_world_space_colliders<world_space_polygon_collider>(owner);
owner.for_joined_components<camera::input, camera>([this, &owner](
const ecs::const_entity&,
const camera::input&,
const camera& camera)
{
const v2u& target_size = camera.target()
? camera.target()->size()
: window_.framebuffer_size();
const v2f& mouse_p = math::normalized_to_point(
b2f(target_size.cast_to<f32>()),
math::point_to_normalized(
b2f(window_.real_size().cast_to<f32>()),
input_.mouse().cursor_pos()));
const m4f& camera_vp =
camera.view() * camera.projection();
const b2f& camera_viewport = b2f(
camera.viewport().position * target_size.cast_to<f32>(),
camera.viewport().size * target_size.cast_to<f32>());
if ( !math::inside(camera_viewport, mouse_p) ) {
return;
}
update_colliders_under_mouse<world_space_rect_collider>(
owner,
mouse_p,
camera_vp,
camera_viewport);
update_colliders_under_mouse<world_space_circle_collider>(
owner,
mouse_p,
camera_vp,
camera_viewport);
update_colliders_under_mouse<world_space_polygon_collider>(
owner,
mouse_p,
camera_vp,
camera_viewport);
}, !ecs::exists<disabled<camera>>());
}
private:
input& input_;
window& window_;
};
//
// input_system
//
input_system::input_system()
: state_(new internal_state(the<input>(), the<window>())) {}
input_system::~input_system() noexcept = default;
void input_system::process(
ecs::registry& owner,
const ecs::before<systems::update_event>& trigger)
{
E2D_UNUSED(trigger);
E2D_PROFILER_SCOPE("input_system.process_update");
state_->process_update(owner);
}
}

View File

@@ -0,0 +1,63 @@
/*******************************************************************************
* This file is part of the "Enduro2D"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2018-2019, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include <enduro2d/high/systems/touch_system.hpp>
#include "touch_system_impl/touch_system_base.hpp"
#include "touch_system_impl/touch_system_colliders.hpp"
#include "touch_system_impl/touch_system_dispatcher.hpp"
namespace
{
using namespace e2d;
using namespace e2d::touch_system_impl;
}
namespace e2d
{
//
// touch_system::internal_state
//
class touch_system::internal_state final : private noncopyable {
public:
internal_state(input& i, window& w)
: input_(i)
, window_(w)
, dispatcher_(window_.register_event_listener<dispatcher>()) {}
~internal_state() noexcept {
window_.unregister_event_listener(dispatcher_);
}
void process_update(ecs::registry& owner) {
update_world_space_colliders(owner);
update_world_space_colliders_under_mouse(input_, window_, owner);
dispatcher_.dispatch_all_events(owner);
}
private:
input& input_;
window& window_;
dispatcher& dispatcher_;
};
//
// touch_system
//
touch_system::touch_system()
: state_(new internal_state(the<input>(), the<window>())) {}
touch_system::~touch_system() noexcept = default;
void touch_system::process(
ecs::registry& owner,
const ecs::before<systems::update_event>& trigger)
{
E2D_UNUSED(trigger);
E2D_PROFILER_SCOPE("touch_system.process_update");
state_->process_update(owner);
}
}

View File

@@ -0,0 +1,38 @@
/*******************************************************************************
* This file is part of the "Enduro2D"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2018-2019, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include <enduro2d/high/_high.hpp>
#include <enduro2d/high/components/actor.hpp>
#include <enduro2d/high/components/camera.hpp>
#include <enduro2d/high/components/colliders.hpp>
#include <enduro2d/high/components/disabled.hpp>
#include <enduro2d/high/components/events.hpp>
#include <enduro2d/high/components/scene.hpp>
#include <enduro2d/high/components/touchable.hpp>
namespace e2d::touch_system_impl
{
class touchable_under_mouse final {
};
struct world_space_rect_collider final {
using local_space_collider_t = rect_collider;
std::array<v3f, 4> points{};
};
struct world_space_circle_collider final {
using local_space_collider_t = circle_collider;
std::array<v3f, 12> points{};
};
struct world_space_polygon_collider final {
using local_space_collider_t = polygon_collider;
vector<v3f> points{};
};
}

View File

@@ -0,0 +1,206 @@
/*******************************************************************************
* This file is part of the "Enduro2D"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2018-2019, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include "touch_system_colliders.hpp"
#define PNPOLY_IMPLEMENTATION
#include <3rdparty/pnpoly.h/pnpoly.h>
namespace e2d::touch_system_impl::impl
{
void update_world_space_collider(
world_space_rect_collider& dst,
const rect_collider& src,
const m4f& local_to_world)
{
const v2f& of = src.offset();
const v2f& hs = src.size() * 0.5f;
const v2f p1{of.x - hs.x, of.y - hs.y};
const v2f p2{of.x + hs.x, of.y - hs.y};
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);
}
void update_world_space_collider(
world_space_circle_collider& dst,
const circle_collider& src,
const m4f& local_to_world)
{
const v2f& of = src.offset();
for ( std::size_t i = 0, e = dst.points.size(); i < e; ++i ) {
const radf a =
math::two_pi<f32>() /
math::numeric_cast<f32>(e) *
math::numeric_cast<f32>(i);
const v2f p =
of +
v2f(math::cos(a), math::sin(a)) *
src.radius();
dst.points[i] = v3f(v4f(p, 0.f, 1.f) * local_to_world);
}
}
void update_world_space_collider(
world_space_polygon_collider& dst,
const polygon_collider& src,
const m4f& local_to_world)
{
const vector<v2f>& src_points = src.points();
dst.points.clear();
if ( dst.points.capacity() < src_points.size() ) {
dst.points.reserve(math::max(dst.points.capacity() * 2u, src_points.size()));
}
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));
}
}
}
namespace e2d::touch_system_impl::impl
{
bool is_world_space_collider_under_mouse(
const world_space_rect_collider& c,
const v2f& mouse_p,
const m4f& camera_vp,
const b2f& camera_viewport)
{
std::array<
v2f,
std::tuple_size_v<decltype(c.points)>
> points;
std::transform(c.points.begin(), c.points.end(), points.begin(), [
&camera_vp,
&camera_viewport
](const v3f& point) noexcept {
return v2f(math::project(point, camera_vp, camera_viewport).first);
});
return !!pnpoly_aos(
math::numeric_cast<int>(points.size()),
points.data()->data(),
mouse_p.x, mouse_p.y);
}
bool is_world_space_collider_under_mouse(
const world_space_circle_collider& c,
const v2f& mouse_p,
const m4f& camera_vp,
const b2f& camera_viewport)
{
std::array<
v2f,
std::tuple_size_v<decltype(c.points)>
> points;
std::transform(c.points.begin(), c.points.end(), points.begin(), [
&camera_vp,
&camera_viewport
](const v3f& point) noexcept {
return v2f(math::project(point, camera_vp, camera_viewport).first);
});
return !!pnpoly_aos(
math::numeric_cast<int>(points.size()),
points.data()->data(),
mouse_p.x, mouse_p.y);
}
bool is_world_space_collider_under_mouse(
const world_space_polygon_collider& c,
const v2f& mouse_p,
const m4f& camera_vp,
const b2f& camera_viewport)
{
static thread_local std::vector<v2f> points;
E2D_DEFER([](){ points.clear(); });
if ( points.capacity() < c.points.size() ) {
points.reserve(math::max(points.capacity() * 2u, c.points.size()));
}
std::transform(c.points.begin(), c.points.end(), std::back_inserter(points), [
&camera_vp,
&camera_viewport
](const v3f& point) noexcept {
return v2f(math::project(point, camera_vp, camera_viewport).first);
});
return !!pnpoly_aos(
math::numeric_cast<int>(points.size()),
points.data()->data(),
mouse_p.x, mouse_p.y);
}
}
namespace e2d::touch_system_impl
{
void update_world_space_colliders(ecs::registry& owner) {
impl::update_world_space_colliders<world_space_rect_collider>(owner);
impl::update_world_space_colliders<world_space_circle_collider>(owner);
impl::update_world_space_colliders<world_space_polygon_collider>(owner);
}
void update_world_space_colliders_under_mouse(input& input, window& window, ecs::registry& owner) {
owner.remove_all_components<touchable_under_mouse>();
owner.for_joined_components<camera::input, camera>([&input, &window, &owner](
const ecs::const_entity&,
const camera::input&,
const camera& camera)
{
const v2u& target_size = camera.target()
? camera.target()->size()
: window.framebuffer_size();
const v2f& mouse_p = math::normalized_to_point(
b2f(target_size.cast_to<f32>()),
math::point_to_normalized(
b2f(window.real_size().cast_to<f32>()),
input.mouse().cursor_pos()));
const m4f& camera_vp =
camera.view() * camera.projection();
const b2f& camera_viewport = b2f(
camera.viewport().position * target_size.cast_to<f32>(),
camera.viewport().size * target_size.cast_to<f32>());
if ( !math::inside(camera_viewport, mouse_p) ) {
return;
}
impl::update_world_space_colliders_under_mouse<world_space_rect_collider>(
owner,
mouse_p,
camera_vp,
camera_viewport);
impl::update_world_space_colliders_under_mouse<world_space_circle_collider>(
owner,
mouse_p,
camera_vp,
camera_viewport);
impl::update_world_space_colliders_under_mouse<world_space_polygon_collider>(
owner,
mouse_p,
camera_vp,
camera_viewport);
}, !ecs::exists_any<
disabled<actor>,
disabled<camera>>());
}
}

View File

@@ -0,0 +1,111 @@
/*******************************************************************************
* This file is part of the "Enduro2D"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2018-2019, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "touch_system_base.hpp"
namespace e2d::touch_system_impl
{
namespace impl
{
void update_world_space_collider(
world_space_rect_collider& dst,
const rect_collider& src,
const m4f& local_to_world);
void update_world_space_collider(
world_space_circle_collider& dst,
const circle_collider& src,
const m4f& local_to_world);
void update_world_space_collider(
world_space_polygon_collider& dst,
const polygon_collider& src,
const m4f& local_to_world);
template < typename WorldSpaceCollider >
void update_world_space_colliders(ecs::registry& owner) {
using world_space_collider_t = WorldSpaceCollider;
using local_space_collider_t = typename WorldSpaceCollider::local_space_collider_t;
ecsex::remove_all_components<world_space_collider_t>(
owner,
!ecs::exists_all<
touchable,
local_space_collider_t>() ||
ecs::exists_any<
disabled<actor>,
disabled<touchable>,
disabled<world_space_collider_t>,
disabled<local_space_collider_t>>());
owner.for_joined_components<local_space_collider_t, touchable, actor>([](
ecs::entity e,
const local_space_collider_t& src,
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());
}, !ecs::exists_any<
disabled<actor>,
disabled<touchable>,
disabled<world_space_collider_t>,
disabled<local_space_collider_t>>());
}
}
namespace impl
{
bool is_world_space_collider_under_mouse(
const world_space_rect_collider& c,
const v2f& mouse_p,
const m4f& camera_vp,
const b2f& camera_viewport);
bool is_world_space_collider_under_mouse(
const world_space_circle_collider& c,
const v2f& mouse_p,
const m4f& camera_vp,
const b2f& camera_viewport);
bool is_world_space_collider_under_mouse(
const world_space_polygon_collider& c,
const v2f& mouse_p,
const m4f& camera_vp,
const b2f& camera_viewport);
template < typename WorldSpaceCollider >
void update_world_space_colliders_under_mouse(
ecs::registry& owner,
const v2f& mouse_p,
const m4f& camera_vp,
const b2f& camera_viewport)
{
using world_space_collider_t = WorldSpaceCollider;
using local_space_collider_t = typename WorldSpaceCollider::local_space_collider_t;
owner.for_joined_components<touchable, world_space_collider_t>([
&mouse_p,
&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>();
}
}, !ecs::exists_any<
disabled<touchable>,
disabled<world_space_collider_t>,
disabled<local_space_collider_t>>());
}
}
void update_world_space_colliders(ecs::registry& owner);
void update_world_space_colliders_under_mouse(input& input, window& window, ecs::registry& owner);
}

View File

@@ -0,0 +1,168 @@
/*******************************************************************************
* This file is part of the "Enduro2D"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2018-2019, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include "touch_system_dispatcher.hpp"
namespace
{
using namespace e2d;
using namespace e2d::touch_system_impl;
gobject find_event_target(const ecs::registry& owner) {
static thread_local vector<std::tuple<
ecs::const_entity,
scene,
actor>> scenes;
E2D_DEFER([](){ scenes.clear(); });
ecsex::extract_components<scene, actor>(
owner,
std::back_inserter(scenes),
!ecs::exists_any<
disabled<scene>,
disabled<actor>>());
std::sort(scenes.begin(), scenes.end(), [](const auto& l, const auto& r){
return std::get<scene>(l).depth() >= std::get<scene>(r).depth();
});
for ( const auto& t : scenes ) {
gobject target = nodes::find_component_from_children<touchable_under_mouse>(
std::get<actor>(t).node(),
nodes::options()
.reversed(true)
.recursive(true)
.include_root(true)).owner();
if ( target ) {
return target;
}
}
return gobject();
}
template < typename E >
void dispatch_event(E&& event) {
gobject target = event.target();
if ( !target ) {
return;
}
const_gcomponent<actor> target_actor = target.component<actor>();
const_gcomponent<touchable> target_touchable = target.component<touchable>();
if ( !target_actor || !target_touchable ) {
return;
}
//
// parents
//
static thread_local std::vector<const_gcomponent<touchable>> parents;
E2D_DEFER([](){ parents.clear(); });
nodes::extract_components_from_parents<touchable>(
target_actor->node(),
std::back_inserter(parents),
nodes::options().recursive(true));
//
// capturing
//
if ( event.capturing() ) {
for ( auto iter = parents.rbegin(); iter != parents.rend(); ++iter ) {
const bool parent_disabled = ecs::exists_any<
disabled<actor>,
disabled<touchable>
>()(iter->owner().raw_entity());
if ( !parent_disabled && !(*iter)->capturing() ) {
return;
}
}
}
//
// targeting
//
target.component<events<touchable_events::event>>().ensure().add(event);
//
// bubbling
//
if ( event.bubbling() && target_touchable->bubbling() ) {
for ( auto iter = parents.begin(); iter != parents.end(); ++iter ) {
const bool parent_disabled = ecs::exists_any<
disabled<actor>,
disabled<touchable>
>()(iter->owner().raw_entity());
if ( !parent_disabled ) {
iter->owner().component<events<touchable_events::event>>().ensure().add(event);
if ( !(*iter)->bubbling() ) {
return;
}
}
}
}
}
}
namespace e2d::touch_system_impl
{
void dispatcher::dispatch_all_events(ecs::registry& owner) {
E2D_DEFER([this](){ events_.clear(); });
owner.for_each_component<events<touchable_events::event>>([
](const ecs::const_entity&, events<touchable_events::event>& es) {
es.clear();
});
if ( events_.empty() ) {
return;
}
gobject target = find_event_target(owner);
if ( !target ) {
return;
}
for ( const auto& event : events_ ) {
std::visit(utils::overloaded {
[](std::monostate){},
[&target](auto event_copy){
dispatch_event(event_copy.target(target));
}
}, event);
}
}
void dispatcher::on_mouse_button(
mouse_button button,
mouse_button_action action) noexcept
{
switch ( action ) {
case mouse_button_action::press:
events_.push_back(touchable_events::mouse_evt(
gobject(),
touchable_events::mouse_evt::types::pressed,
button));
break;
case mouse_button_action::release:
events_.push_back(touchable_events::mouse_evt(
gobject(),
touchable_events::mouse_evt::types::released,
button));
break;
case mouse_button_action::unknown:
break;
default:
E2D_ASSERT_MSG(false, "unexpected mouse action");
break;
}
}
}

View File

@@ -0,0 +1,25 @@
/*******************************************************************************
* This file is part of the "Enduro2D"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2018-2019, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "touch_system_base.hpp"
namespace e2d::touch_system_impl
{
class dispatcher final : public window::event_listener {
public:
dispatcher() = default;
void dispatch_all_events(ecs::registry& owner);
private:
void on_mouse_button(
mouse_button button,
mouse_button_action action) noexcept final;
private:
vector<touchable_events::event> events_;
};
}