Toast Engine
Loading...
Searching...
No Matches
modifier.hpp
Go to the documentation of this file.
1
8
9#pragma once
10
11#include "parse_util.hpp"
12#include "value.hpp"
13
14#include <cmath>
15#include <glm/glm.hpp>
16#include <string_view>
17#include <toast/time.hpp>
18#include <toml++/toml.hpp>
19
20namespace input {
21
25class TOAST_API IModifier {
26public:
27 IModifier() = default;
28 IModifier(const IModifier&) = default;
29 auto operator=(const IModifier&) -> IModifier& = default;
30 virtual ~IModifier() = default;
31
37 virtual void apply(Value& value, const EvalContext& ctx) = 0;
38
40 [[nodiscard]]
41 virtual auto name() const -> std::string_view = 0;
42
48 static auto fromToml(const toml::table& table) -> std::shared_ptr<IModifier>;
49};
50
51namespace detail {
52
53inline auto modifierHeld(ModifierKey mask, ModifierKey key) -> bool {
54 return (mask & key) == key;
55}
56
57}
58
62class DeadzoneModifier : public IModifier {
63public:
64 explicit DeadzoneModifier(const toml::table& t)
65 : m_lower(parse::number(t["lower_threshold"], 0.2f)),
66 m_upper(parse::number(t["upper_threshold"], 1.0f)) { }
67
68 void apply(Value& value, const EvalContext& /*ctx*/) override {
69 value.data.x = remap(value.data.x);
70 value.data.y = remap(value.data.y);
71 }
72
73 [[nodiscard]]
74 auto name() const -> std::string_view override {
75 return "deadzone";
76 }
77
78private:
79 [[nodiscard]]
80 auto remap(float v) const -> float {
81 const float mag = std::abs(v);
82 if (mag < m_lower) {
83 return 0.0f;
84 }
85 const float span = std::max(m_upper - m_lower, 0.0001f);
86 const float t = glm::clamp((mag - m_lower) / span, 0.0f, 1.0f);
87 return std::copysign(t, v);
88 }
89
90 float m_lower = 0.2f;
91 float m_upper = 1.0f;
92};
93
97class InvertModifier : public IModifier {
98public:
99 explicit InvertModifier(const toml::table& t) : m_x(parse::boolean(t["x"], true)), m_y(parse::boolean(t["y"], false)) { }
100
101 void apply(Value& value, const EvalContext& /*ctx*/) override {
102 if (m_x) {
103 value.data.x *= -1.0f;
104 }
105 if (m_y) {
106 value.data.y *= -1.0f;
107 }
108 }
109
110 [[nodiscard]]
111 auto name() const -> std::string_view override {
112 return "invert";
113 }
114
115private:
116 bool m_x = true;
117 bool m_y = false;
118};
119
123class ExponentialModifier : public IModifier {
124public:
125 explicit ExponentialModifier(const toml::table& t) : m_power(parse::number(t["power"], 2.0f)) { }
126
127 void apply(Value& value, const EvalContext& /*ctx*/) override {
128 value.data.x = curve(value.data.x);
129 value.data.y = curve(value.data.y);
130 }
131
132 [[nodiscard]]
133 auto name() const -> std::string_view override {
134 return "exponential";
135 }
136
137private:
138 [[nodiscard]]
139 auto curve(float v) const -> float {
140 return std::copysign(std::pow(std::abs(v), m_power), v);
141 }
142
143 float m_power = 2.0f;
144};
145
149class ScaleModifier : public IModifier {
150public:
151 explicit ScaleModifier(const toml::table& t) : m_x(parse::number(t["x"], 1.0f)), m_y(parse::number(t["y"], 1.0f)) { }
152
153 void apply(Value& value, const EvalContext& /*ctx*/) override {
154 value.data.x *= m_x;
155 value.data.y *= m_y;
156 }
157
158 [[nodiscard]]
159 auto name() const -> std::string_view override {
160 return "scale";
161 }
162
163private:
164 float m_x = 1.0f;
165 float m_y = 1.0f;
166};
167
171class ScaleByDeltaTimeModifier : public IModifier {
172public:
173 explicit ScaleByDeltaTimeModifier(const toml::table& t)
174 : m_x(parse::boolean(t["x"], true)),
175 m_y(parse::boolean(t["y"], true)) { }
176
177 void apply(Value& value, const EvalContext& /*ctx*/) override {
178 float delta = Time::delta();
179 if (m_x) {
180 value.data.x *= delta;
181 }
182 if (m_y) {
183 value.data.y *= delta;
184 }
185 }
186
187 [[nodiscard]]
188 auto name() const -> std::string_view override {
189 return "scale_by_deltatime";
190 }
191
192private:
193 bool m_x = true;
194 bool m_y = true;
195};
196
200class SmoothModifier : public IModifier {
201public:
202 explicit SmoothModifier(const toml::table& t)
203 : m_x(parse::boolean(t["x"], true)),
204 m_y(parse::boolean(t["y"], true)),
205 m_speed(parse::number(t["speed"], 10.0f)) { }
206
207 void apply(Value& value, const EvalContext& /*ctx*/) override {
208 float delta = Time::delta();
209 const float t = glm::clamp(m_speed * delta, 0.0f, 1.0f);
210 if (m_x) {
211 m_current.x = glm::mix(m_current.x, value.data.x, t);
212 value.data.x = m_current.x;
213 }
214 if (m_y) {
215 m_current.y = glm::mix(m_current.y, value.data.y, t);
216 value.data.y = m_current.y;
217 }
218 }
219
220 [[nodiscard]]
221 auto name() const -> std::string_view override {
222 return "smooth";
223 }
224
225private:
226 bool m_x = true;
227 bool m_y = true;
228 float m_speed = 10.0f;
229 glm::vec2 m_current {0.0f};
230};
231
235class KeyModifier : public IModifier {
236public:
237 explicit KeyModifier(const toml::table& t)
238 : m_control(parse::boolean(t["control"], false)),
239 m_shift(parse::boolean(t["shift"], false)),
240 m_alt(parse::boolean(t["alt"], false)) { }
241
242 void apply(Value& value, const EvalContext& ctx) override {
243 const bool ok = (!m_control || detail::modifierHeld(ctx.mods, ModifierKey::control)) &&
244 (!m_shift || detail::modifierHeld(ctx.mods, ModifierKey::shift)) &&
245 (!m_alt || detail::modifierHeld(ctx.mods, ModifierKey::alt));
246 if (!ok) {
247 value.data = glm::vec2 {0.0f};
248 }
249 }
250
251 [[nodiscard]]
252 auto name() const -> std::string_view override {
253 return "key";
254 }
255
256private:
257 bool m_control = false;
258 bool m_shift = false;
259 bool m_alt = false;
260};
261
262}
static auto delta() noexcept -> double
Definition time.cpp:68
void apply(Value &value, const EvalContext &) override
Transforms a value in place.
Definition modifier.hpp:68
auto name() const -> std::string_view override
Definition modifier.hpp:74
auto name() const -> std::string_view override
Definition modifier.hpp:133
void apply(Value &value, const EvalContext &) override
Transforms a value in place.
Definition modifier.hpp:127
virtual auto name() const -> std::string_view=0
virtual void apply(Value &value, const EvalContext &ctx)=0
Transforms a value in place.
static auto fromToml(const toml::table &table) -> std::shared_ptr< IModifier >
Builds a modifier from a TOML table keyed by its "name" field.
Definition modifier.cpp:7
auto name() const -> std::string_view override
Definition modifier.hpp:111
void apply(Value &value, const EvalContext &) override
Transforms a value in place.
Definition modifier.hpp:101
auto name() const -> std::string_view override
Definition modifier.hpp:252
void apply(Value &value, const EvalContext &ctx) override
Transforms a value in place.
Definition modifier.hpp:242
void apply(Value &value, const EvalContext &) override
Transforms a value in place.
Definition modifier.hpp:177
auto name() const -> std::string_view override
Definition modifier.hpp:188
auto name() const -> std::string_view override
Definition modifier.hpp:159
void apply(Value &value, const EvalContext &) override
Transforms a value in place.
Definition modifier.hpp:153
auto name() const -> std::string_view override
Definition modifier.hpp:221
void apply(Value &value, const EvalContext &) override
Transforms a value in place.
Definition modifier.hpp:207
ModifierKey
Bit flags for the keyboard modifier keys held during an input.
Definition keycodes.hpp:28
Small helpers shared by the TOML parsing paths of triggers, modifiers and binds.
Per-frame context passed down to triggers and modifiers during evaluation.
Definition value.hpp:140
ModifierKey mods
keyboard modifier keys held this frame
Definition value.hpp:142
A tagged value that may represent a bool, a float or a glm::vec2.
Definition value.hpp:31
Controls the time of the application.
Value type shared by triggers, modifiers and actionsg.