-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDekiInputSystem.cpp
More file actions
137 lines (117 loc) · 4.02 KB
/
DekiInputSystem.cpp
File metadata and controls
137 lines (117 loc) · 4.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include "DekiInputSystem.h"
#include "InputCollider.h"
#include "DekiEngine.h"
#include "DekiObject.h"
#include "Prefab.h"
#include "deki-rendering/CameraComponent.h"
#include "providers/DekiInput.h"
#include "providers/IDekiRenderSystem.h"
DekiInputSystem::DekiInputSystem()
{
}
DekiInputSystem::~DekiInputSystem()
{
Shutdown();
}
void DekiInputSystem::Initialize()
{
if (m_Initialized)
return;
// Register callback on DekiInput to receive input events
DekiInput::RegisterEventCallback([this](const InputEvent& event) {
OnInputEvent(event);
});
m_Initialized = true;
}
void DekiInputSystem::Shutdown()
{
// Clear callbacks BEFORE DLL unload — the std::function objects in
// DekiInput::global_callbacks hold lambdas whose code lives
// in this DLL. After FreeLibrary, those function pointers are stale
// and any operation on them (move, copy, destroy) will crash.
DekiInput::ClearEventCallbacks();
m_Initialized = false;
}
void DekiInputSystem::OnInputEvent(const InputEvent& event)
{
DekiEngine& engine = DekiEngine::GetInstance();
if (!engine.IsInitialized())
return;
Prefab* prefab = engine.GetRootPrefab();
if (!prefab)
return;
bool isDown = (event.type == InputEventType::MOUSE_BUTTON_DOWN);
bool isMove = (event.type == InputEventType::MOUSE_MOVE);
bool isUp = (event.type == InputEventType::MOUSE_BUTTON_UP);
if (!isDown && !isMove && !isUp)
return;
// Find camera for screen-to-world coordinate conversion (search recursively)
CameraComponent* cam = nullptr;
std::function<CameraComponent*(DekiObject*)> findCamera = [&](DekiObject* obj) -> CameraComponent* {
CameraComponent* c = obj->GetComponent<CameraComponent>();
if (c) return c;
for (auto* child : obj->GetChildren())
{
c = findCamera(child);
if (c) return c;
}
return nullptr;
};
for (DekiObject* obj : prefab->GetObjects())
{
cam = findCamera(obj);
if (cam) break;
}
float worldX = static_cast<float>(event.x);
float worldY = static_cast<float>(event.y);
if (cam && engine.GetRenderSystem())
{
cam->ScreenToWorld(static_cast<float>(event.x), static_cast<float>(event.y),
engine.GetRenderSystem()->GetScreenWidth(),
engine.GetRenderSystem()->GetScreenHeight(),
worldX, worldY);
}
DispatchInput(prefab, worldX, worldY, isDown, isMove, isUp);
}
void DekiInputSystem::DispatchInput(Prefab* prefab, float x, float y,
bool down, bool move, bool up)
{
if (!prefab)
return;
for (DekiObject* obj : prefab->GetObjects())
{
DispatchToObject(obj, x, y, down, move, up);
}
}
bool DekiInputSystem::DispatchToObject(DekiObject* obj, float x, float y,
bool down, bool move, bool up)
{
if (!obj)
return false;
// Phase 1: Recurse to children FIRST (deepest child gets priority)
// All siblings are dispatched so they can track hover state (pointer_exit).
bool childConsumed = false;
for (DekiObject* child : obj->GetChildren())
{
if (DispatchToObject(child, x, y, down, move, up))
childConsumed = true;
}
// Phase 2: Process this object's InputCollider
for (DekiComponent* comp : obj->GetComponents())
{
if (comp->getType() == InputCollider::StaticType ||
comp->getBaseType() == InputCollider::StaticType)
{
auto* collider = static_cast<InputCollider*>(comp);
// Process if: no child consumed, OR this is a non-consuming collider (e.g. scroll)
if (!childConsumed || !collider->consume_input)
{
bool handled = collider->ProcessInput(x, y, down, move, up);
if (handled && collider->consume_input)
return true;
}
break;
}
}
return childConsumed;
}