Skip to content

Commit a89b77e

Browse files
committed
change api to use function pointers, for performance
1 parent 83cccff commit a89b77e

File tree

2 files changed

+141
-93
lines changed

2 files changed

+141
-93
lines changed

include/API.hpp

Lines changed: 47 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -29,32 +29,29 @@ namespace devtools {
2929
};
3030

3131
template <typename T>
32-
struct HandlePropertyEvent final : geode::Event {
33-
HandlePropertyEvent(const char* n, T* p) : prop(p), name(n) {}
34-
T* prop;
35-
const char* name = nullptr;
36-
bool changed = false;
32+
struct PropertyFnEvent final : geode::Event {
33+
PropertyFnEvent() {}
34+
using Fn = bool(const char* name, T&);
35+
Fn* fn = nullptr;
3736
};
3837

39-
struct DrawLabelEvent final : geode::Event {
40-
DrawLabelEvent(const char* t) : text(t) {}
41-
const char* text = nullptr;
38+
struct DrawLabelFnEvent final : geode::Event {
39+
DrawLabelFnEvent() {}
40+
using Fn = void(const char* text);
41+
Fn* fn = nullptr;
4242
};
4343

4444
template <typename T>
45-
struct EnumerableEvent final : geode::Event {
46-
EnumerableEvent(const char* l, T* v, std::initializer_list<std::pair<T, const char*>> i)
47-
: label(l), value(v), items(i) {}
48-
const char* label = nullptr;
49-
T* value;
50-
std::initializer_list<std::pair<T, const char*>> items;
51-
bool changed = false;
45+
struct EnumerableFnEvent final : geode::Event {
46+
EnumerableFnEvent() {}
47+
using Fn = bool(const char* label, T* value, std::span<std::pair<T, const char*> const> items);
48+
Fn* fn = nullptr;
5249
};
5350

54-
struct ButtonEvent final : geode::Event {
55-
ButtonEvent(const char* l) : label(l) {}
56-
const char* label = nullptr;
57-
bool clicked = false;
51+
struct ButtonFnEvent final : geode::Event {
52+
ButtonFnEvent() {}
53+
using Fn = bool(const char* label);
54+
Fn* fn = nullptr;
5855
};
5956

6057
/// @brief Checks if DevTools is currently loaded.
@@ -101,16 +98,24 @@ namespace devtools {
10198
/// @warning This function should only ever be called from within a registered node callback.
10299
template <typename T> requires SupportedProperty<T>
103100
bool property(const char* name, T& prop) {
104-
HandlePropertyEvent event(name, &prop);
105-
event.post();
106-
return event.changed;
101+
static auto fn = ([] {
102+
PropertyFnEvent<T> event;
103+
event.post();
104+
return event.fn;
105+
})();
106+
return fn ? fn(name, prop) : false;
107107
}
108108

109109
/// @brief Renders a label in the DevTools UI.
110110
/// @param text The text to display in the label.
111111
/// @warning This function should only ever be called from within a registered node callback.
112112
inline void label(const char* text) {
113-
DrawLabelEvent(text).post();
113+
static auto fn = ([] {
114+
DrawLabelFnEvent event;
115+
event.post();
116+
return event.fn;
117+
})();
118+
if (fn) fn(text);
114119
}
115120

116121
/// @brief Renders an enumerable property editor using radio buttons for the given value in the DevTools UI.
@@ -122,22 +127,32 @@ namespace devtools {
122127
template <typename T> requires std::is_integral_v<std::underlying_type_t<T>>
123128
bool enumerable(const char* label, T& value, std::initializer_list<std::pair<T, const char*>> items) {
124129
using ValueType = std::underlying_type_t<T>;
125-
EnumerableEvent<ValueType> event(
126-
label, reinterpret_cast<ValueType*>(&value),
127-
*reinterpret_cast<std::initializer_list<std::pair<ValueType, const char*>>*>(&items)
128-
);
129-
event.post();
130-
return event.changed;
130+
static auto fn = ([] {
131+
EnumerableFnEvent<ValueType> event;
132+
event.post();
133+
return event.fn;
134+
})();
135+
return fn ? fn(
136+
label,
137+
reinterpret_cast<ValueType*>(&value),
138+
std::span(
139+
reinterpret_cast<std::pair<ValueType, const char*> const*>(&*items.begin()),
140+
reinterpret_cast<std::pair<ValueType, const char*> const*>(&*items.end())
141+
)
142+
) : false;
131143
}
132144

133145
/// @brief Renders a button in the DevTools UI.
134146
/// @param label The label for the button.
135147
/// @return True if the button was clicked, false otherwise.
136148
/// @warning This function should only ever be called from within a registered node callback.
137149
inline bool button(const char* label) {
138-
ButtonEvent event(label);
139-
event.post();
140-
return event.clicked;
150+
static auto fn = ([] {
151+
ButtonFnEvent event;
152+
event.post();
153+
return event.fn;
154+
})();
155+
return fn ? fn(label) : false;
141156
}
142157

143158
/// @brief Renders a button in the DevTools UI and calls the provided callback if the button is clicked.

src/API.cpp

Lines changed: 94 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,35 @@ using namespace geode::prelude;
77

88
template <typename T>
99
static void handleType() {
10-
new EventListener<EventFilter<devtools::HandlePropertyEvent<T>>>(+[](devtools::HandlePropertyEvent<T>* event) {
10+
new EventListener<EventFilter<devtools::PropertyFnEvent<T>>>(+[](devtools::PropertyFnEvent<T>* event) {
1111
constexpr bool isSigned = std::is_signed_v<T>;
1212
constexpr ImGuiDataType dataType = sizeof(T) == 1 ? (isSigned ? ImGuiDataType_S8 : ImGuiDataType_U8) :
1313
sizeof(T) == 2 ? (isSigned ? ImGuiDataType_S16 : ImGuiDataType_U16) :
1414
sizeof(T) == 4 ? (isSigned ? ImGuiDataType_S32 : ImGuiDataType_U32) :
1515
isSigned ? ImGuiDataType_S64 : ImGuiDataType_U64;
16-
event->changed = ImGui::InputScalar(event->name, dataType, event->prop);
16+
event->fn = +[](const char* name, T& prop) {
17+
return ImGui::InputScalar(name, dataType, &prop);
18+
};
1719
return ListenerResult::Stop;
1820
});
1921

20-
new EventListener<EventFilter<devtools::EnumerableEvent<T>>>(+[](devtools::EnumerableEvent<T>* event) {
21-
ImGui::Text("%s:", event->label);
22-
size_t i = 0;
23-
for (auto& [value, label] : event->items) {
24-
if (ImGui::RadioButton(label, *event->value == value)) {
25-
*event->value = value;
26-
event->changed = true;
22+
new EventListener<EventFilter<devtools::EnumerableFnEvent<T>>>(+[](devtools::EnumerableFnEvent<T>* event) {
23+
event->fn = +[](const char* label, T* value, std::span<std::pair<T, const char*>> items) {
24+
ImGui::Text("%s:", label);
25+
size_t i = 0;
26+
bool changed = false;
27+
for (auto& [itemValue, itemLabel] : items) {
28+
if (ImGui::RadioButton(itemLabel, *value == itemValue)) {
29+
*value = itemValue;
30+
changed = true;
31+
}
32+
if (i < items.size() - 1) {
33+
ImGui::SameLine();
34+
}
35+
i++;
2736
}
28-
if (i < event->items.size() - 1) {
29-
ImGui::SameLine();
30-
}
31-
i++;
32-
}
37+
return changed;
38+
};
3339
return ListenerResult::Stop;
3440
});
3541
}
@@ -53,87 +59,114 @@ static void handleType() {
5359
handleType<unsigned long>();
5460

5561
// checkbox
56-
new EventListener<EventFilter<devtools::HandlePropertyEvent<bool>>>(+[](devtools::HandlePropertyEvent<bool>* event) {
57-
event->changed = ImGui::Checkbox(event->name, event->prop);
62+
new EventListener<EventFilter<devtools::PropertyFnEvent<bool>>>(+[](devtools::PropertyFnEvent<bool>* event) {
63+
event->fn = +[](const char* name, bool& prop) {
64+
return ImGui::Checkbox(name, &prop);
65+
};
5866
return ListenerResult::Stop;
5967
});
6068

6169
// float and double
62-
new EventListener<EventFilter<devtools::HandlePropertyEvent<float>>>(+[](devtools::HandlePropertyEvent<float>* event) {
63-
event->changed = ImGui::InputFloat(event->name, event->prop);
70+
new EventListener<EventFilter<devtools::PropertyFnEvent<float>>>(+[](devtools::PropertyFnEvent<float>* event) {
71+
event->fn = +[](const char* name, float& prop) {
72+
return ImGui::InputFloat(name, &prop);
73+
};
6474
return ListenerResult::Stop;
6575
});
66-
new EventListener<EventFilter<devtools::HandlePropertyEvent<double>>>(+[](devtools::HandlePropertyEvent<double>* event) {
67-
event->changed = ImGui::InputDouble(event->name, event->prop);
76+
new EventListener<EventFilter<devtools::PropertyFnEvent<double>>>(+[](devtools::PropertyFnEvent<double>* event) {
77+
event->fn = +[](const char* name, double& prop) {
78+
return ImGui::InputDouble(name, &prop);
79+
};
6880
return ListenerResult::Stop;
6981
});
7082

7183
// string
72-
new EventListener<EventFilter<devtools::HandlePropertyEvent<std::string>>>(+[](devtools::HandlePropertyEvent<std::string>* event) {
73-
event->changed = ImGui::InputText(event->name, event->prop);
84+
new EventListener<EventFilter<devtools::PropertyFnEvent<std::string>>>(+[](devtools::PropertyFnEvent<std::string>* event) {
85+
event->fn = +[](const char* name, std::string& prop) {
86+
return ImGui::InputText(name, &prop);
87+
};
7488
return ListenerResult::Stop;
7589
});
7690

7791
// colors
78-
new EventListener<EventFilter<devtools::HandlePropertyEvent<ccColor3B>>>(+[](devtools::HandlePropertyEvent<ccColor3B>* event) {
79-
auto color = ImVec4(
80-
event->prop->r / 255.f,
81-
event->prop->g / 255.f,
82-
event->prop->b / 255.f,
83-
1.0f
84-
);
85-
if (ImGui::ColorEdit3(event->name, &color.x)) {
86-
event->changed = true;
87-
event->prop->r = static_cast<GLubyte>(color.x * 255);
88-
event->prop->g = static_cast<GLubyte>(color.y * 255);
89-
event->prop->b = static_cast<GLubyte>(color.z * 255);
90-
}
92+
new EventListener<EventFilter<devtools::PropertyFnEvent<ccColor3B>>>(+[](devtools::PropertyFnEvent<ccColor3B>* event) {
93+
event->fn = +[](const char* name, ccColor3B& prop) {
94+
auto color = ImVec4(
95+
prop.r / 255.f,
96+
prop.g / 255.f,
97+
prop.b / 255.f,
98+
1.0f
99+
);
100+
if (ImGui::ColorEdit3(name, &color.x)) {
101+
prop.r = static_cast<GLubyte>(color.x * 255);
102+
prop.g = static_cast<GLubyte>(color.y * 255);
103+
prop.b = static_cast<GLubyte>(color.z * 255);
104+
return true;
105+
}
106+
return false;
107+
};
91108
return ListenerResult::Stop;
92109
});
93-
new EventListener<EventFilter<devtools::HandlePropertyEvent<ccColor4B>>>(+[](devtools::HandlePropertyEvent<ccColor4B>* event) {
94-
auto color = ImVec4(
95-
event->prop->r / 255.f,
96-
event->prop->g / 255.f,
97-
event->prop->b / 255.f,
98-
event->prop->a / 255.f
99-
);
100-
if (ImGui::ColorEdit4(event->name, &color.x)) {
101-
event->changed = true;
102-
event->prop->r = static_cast<GLubyte>(color.x * 255);
103-
event->prop->g = static_cast<GLubyte>(color.y * 255);
104-
event->prop->b = static_cast<GLubyte>(color.z * 255);
105-
event->prop->a = static_cast<GLubyte>(color.w * 255);
106-
}
110+
new EventListener<EventFilter<devtools::PropertyFnEvent<ccColor4B>>>(+[](devtools::PropertyFnEvent<ccColor4B>* event) {
111+
event->fn = +[](const char* name, ccColor4B& prop) {
112+
auto color = ImVec4(
113+
prop.r / 255.f,
114+
prop.g / 255.f,
115+
prop.b / 255.f,
116+
prop.a / 255.f
117+
);
118+
if (ImGui::ColorEdit4(name, &color.x)) {
119+
prop.r = static_cast<GLubyte>(color.x * 255);
120+
prop.g = static_cast<GLubyte>(color.y * 255);
121+
prop.b = static_cast<GLubyte>(color.z * 255);
122+
prop.a = static_cast<GLubyte>(color.w * 255);
123+
return true;
124+
}
125+
return false;
126+
};
107127
return ListenerResult::Stop;
108128
});
109-
new EventListener<EventFilter<devtools::HandlePropertyEvent<ccColor4F>>>(+[](devtools::HandlePropertyEvent<ccColor4F>* event) {
110-
event->changed = ImGui::ColorEdit4(event->name, reinterpret_cast<float*>(event->prop));
129+
new EventListener<EventFilter<devtools::PropertyFnEvent<ccColor4F>>>(+[](devtools::PropertyFnEvent<ccColor4F>* event) {
130+
event->fn = +[](const char* name, ccColor4F& prop) {
131+
return ImGui::ColorEdit4(name, reinterpret_cast<float*>(&prop));
132+
};
111133
return ListenerResult::Stop;
112134
});
113135

114136
// points/sizes
115-
new EventListener<EventFilter<devtools::HandlePropertyEvent<CCPoint>>>(+[](devtools::HandlePropertyEvent<CCPoint>* event) {
116-
event->changed = ImGui::InputFloat2(event->name, reinterpret_cast<float*>(event->prop));
137+
new EventListener<EventFilter<devtools::PropertyFnEvent<CCPoint>>>(+[](devtools::PropertyFnEvent<CCPoint>* event) {
138+
event->fn = +[](const char* name, CCPoint& prop) {
139+
return ImGui::InputFloat2(name, reinterpret_cast<float*>(&prop));
140+
};
117141
return ListenerResult::Stop;
118142
});
119-
new EventListener<EventFilter<devtools::HandlePropertyEvent<CCSize>>>(+[](devtools::HandlePropertyEvent<CCSize>* event) {
120-
event->changed = ImGui::InputFloat2(event->name, reinterpret_cast<float*>(event->prop));
143+
144+
new EventListener<EventFilter<devtools::PropertyFnEvent<CCSize>>>(+[](devtools::PropertyFnEvent<CCSize>* event) {
145+
event->fn = +[](const char* name, CCSize& prop) {
146+
return ImGui::InputFloat2(name, reinterpret_cast<float*>(&prop));
147+
};
121148
return ListenerResult::Stop;
122149
});
123-
new EventListener<EventFilter<devtools::HandlePropertyEvent<CCRect>>>(+[](devtools::HandlePropertyEvent<CCRect>* event) {
124-
event->changed = ImGui::InputFloat4(event->name, reinterpret_cast<float*>(event->prop));
150+
new EventListener<EventFilter<devtools::PropertyFnEvent<CCRect>>>(+[](devtools::PropertyFnEvent<CCRect>* event) {
151+
event->fn = +[](const char* name, CCRect& prop) {
152+
return ImGui::InputFloat4(name, reinterpret_cast<float*>(&prop));
153+
};
125154
return ListenerResult::Stop;
126155
});
127156

128157
// label
129-
new EventListener<EventFilter<devtools::DrawLabelEvent>>(+[](devtools::DrawLabelEvent* event) {
130-
ImGui::Text("%s", event->text);
158+
new EventListener<EventFilter<devtools::DrawLabelFnEvent>>(+[](devtools::DrawLabelFnEvent* event) {
159+
event->fn = +[](const char* text) {
160+
ImGui::Text("%s", text);
161+
};
131162
return ListenerResult::Stop;
132163
});
133164

134165
// button
135-
new EventListener<EventFilter<devtools::ButtonEvent>>(+[](devtools::ButtonEvent* event) {
136-
event->clicked = ImGui::Button(event->label);
166+
new EventListener<EventFilter<devtools::ButtonFnEvent>>(+[](devtools::ButtonFnEvent* event) {
167+
event->fn = +[](const char* label) {
168+
return ImGui::Button(label);
169+
};
137170
return ListenerResult::Stop;
138171
});
139172
}

0 commit comments

Comments
 (0)