1/**************************************************************************/
2/* curve.h */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#ifndef CURVE_H
32#define CURVE_H
33
34#include "core/io/resource.h"
35
36// y(x) curve
37class Curve : public Resource {
38 GDCLASS(Curve, Resource);
39
40public:
41 static const int MIN_X = 0.f;
42 static const int MAX_X = 1.f;
43
44 static const char *SIGNAL_RANGE_CHANGED;
45
46 enum TangentMode {
47 TANGENT_FREE = 0,
48 TANGENT_LINEAR,
49 TANGENT_MODE_COUNT
50 };
51
52 struct Point {
53 Vector2 position;
54 real_t left_tangent = 0.0;
55 real_t right_tangent = 0.0;
56 TangentMode left_mode = TANGENT_FREE;
57 TangentMode right_mode = TANGENT_FREE;
58
59 Point() {
60 }
61
62 Point(const Vector2 &p_position,
63 real_t p_left = 0.0,
64 real_t p_right = 0.0,
65 TangentMode p_left_mode = TANGENT_FREE,
66 TangentMode p_right_mode = TANGENT_FREE) {
67 position = p_position;
68 left_tangent = p_left;
69 right_tangent = p_right;
70 left_mode = p_left_mode;
71 right_mode = p_right_mode;
72 }
73 };
74
75 Curve();
76
77 int get_point_count() const { return _points.size(); }
78
79 void set_point_count(int p_count);
80
81 int add_point(Vector2 p_position,
82 real_t left_tangent = 0,
83 real_t right_tangent = 0,
84 TangentMode left_mode = TANGENT_FREE,
85 TangentMode right_mode = TANGENT_FREE);
86 int add_point_no_update(Vector2 p_position,
87 real_t left_tangent = 0,
88 real_t right_tangent = 0,
89 TangentMode left_mode = TANGENT_FREE,
90 TangentMode right_mode = TANGENT_FREE);
91 void remove_point(int p_index);
92 void clear_points();
93
94 int get_index(real_t p_offset) const;
95
96 void set_point_value(int p_index, real_t p_position);
97 int set_point_offset(int p_index, real_t p_offset);
98 Vector2 get_point_position(int p_index) const;
99
100 Point get_point(int p_index) const;
101
102 real_t get_min_value() const { return _min_value; }
103 void set_min_value(real_t p_min);
104
105 real_t get_max_value() const { return _max_value; }
106 void set_max_value(real_t p_max);
107
108 real_t get_range() const { return _max_value - _min_value; }
109
110 real_t sample(real_t p_offset) const;
111 real_t sample_local_nocheck(int p_index, real_t p_local_offset) const;
112
113 void clean_dupes();
114
115 void set_point_left_tangent(int p_index, real_t p_tangent);
116 void set_point_right_tangent(int p_index, real_t p_tangent);
117 void set_point_left_mode(int p_index, TangentMode p_mode);
118 void set_point_right_mode(int p_index, TangentMode p_mode);
119
120 real_t get_point_left_tangent(int p_index) const;
121 real_t get_point_right_tangent(int p_index) const;
122 TangentMode get_point_left_mode(int p_index) const;
123 TangentMode get_point_right_mode(int p_index) const;
124
125 void update_auto_tangents(int i);
126
127 Array get_data() const;
128 void set_data(Array input);
129
130 void bake();
131 int get_bake_resolution() const { return _bake_resolution; }
132 void set_bake_resolution(int p_resolution);
133 real_t sample_baked(real_t p_offset) const;
134
135 void ensure_default_setup(real_t p_min, real_t p_max);
136
137 bool _set(const StringName &p_name, const Variant &p_value);
138 bool _get(const StringName &p_name, Variant &r_ret) const;
139 void _get_property_list(List<PropertyInfo> *p_list) const;
140
141protected:
142 static void _bind_methods();
143
144private:
145 void mark_dirty();
146 int _add_point(Vector2 p_position,
147 real_t left_tangent = 0,
148 real_t right_tangent = 0,
149 TangentMode left_mode = TANGENT_FREE,
150 TangentMode right_mode = TANGENT_FREE);
151 void _remove_point(int p_index);
152
153 Vector<Point> _points;
154 bool _baked_cache_dirty = false;
155 Vector<real_t> _baked_cache;
156 int _bake_resolution = 100;
157 real_t _min_value = 0.0;
158 real_t _max_value = 1.0;
159 int _minmax_set_once = 0b00; // Encodes whether min and max have been set a first time, first bit for min and second for max.
160};
161
162VARIANT_ENUM_CAST(Curve::TangentMode)
163
164class Curve2D : public Resource {
165 GDCLASS(Curve2D, Resource);
166
167 struct Point {
168 Vector2 in;
169 Vector2 out;
170 Vector2 position;
171 };
172
173 Vector<Point> points;
174
175 struct BakedPoint {
176 real_t ofs = 0.0;
177 Vector2 point;
178 };
179
180 mutable bool baked_cache_dirty = false;
181 mutable PackedVector2Array baked_point_cache;
182 mutable PackedVector2Array baked_forward_vector_cache;
183 mutable Vector<real_t> baked_dist_cache;
184 mutable real_t baked_max_ofs = 0.0;
185
186 void mark_dirty();
187
188 static Vector2 _calculate_tangent(const Vector2 &p_begin, const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t);
189 void _bake() const;
190
191 real_t bake_interval = 5.0;
192
193 struct Interval {
194 int idx;
195 real_t frac;
196 };
197 Interval _find_interval(real_t p_offset) const;
198 Vector2 _sample_baked(Interval p_interval, bool p_cubic) const;
199 Transform2D _sample_posture(Interval p_interval) const;
200
201 void _bake_segment2d(RBMap<real_t, Vector2> &r_bake, real_t p_begin, real_t p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_max_depth, real_t p_tol) const;
202 void _bake_segment2d_even_length(RBMap<real_t, Vector2> &r_bake, real_t p_begin, real_t p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_max_depth, real_t p_length) const;
203 Dictionary _get_data() const;
204 void _set_data(const Dictionary &p_data);
205
206 bool _set(const StringName &p_name, const Variant &p_value);
207 bool _get(const StringName &p_name, Variant &r_ret) const;
208 void _get_property_list(List<PropertyInfo> *p_list) const;
209
210 void _add_point(const Vector2 &p_position, const Vector2 &p_in = Vector2(), const Vector2 &p_out = Vector2(), int p_atpos = -1);
211 void _remove_point(int p_index);
212
213 Vector<RBMap<real_t, Vector2>> _tessellate_even_length(int p_max_stages = 5, real_t p_length = 0.2) const;
214
215protected:
216 static void _bind_methods();
217
218public:
219 int get_point_count() const;
220 void set_point_count(int p_count);
221 void add_point(const Vector2 &p_position, const Vector2 &p_in = Vector2(), const Vector2 &p_out = Vector2(), int p_atpos = -1);
222 void set_point_position(int p_index, const Vector2 &p_position);
223 Vector2 get_point_position(int p_index) const;
224 void set_point_in(int p_index, const Vector2 &p_in);
225 Vector2 get_point_in(int p_index) const;
226 void set_point_out(int p_index, const Vector2 &p_out);
227 Vector2 get_point_out(int p_index) const;
228 void remove_point(int p_index);
229 void clear_points();
230
231 Vector2 sample(int p_index, real_t p_offset) const;
232 Vector2 samplef(real_t p_findex) const;
233
234 void set_bake_interval(real_t p_tolerance);
235 real_t get_bake_interval() const;
236
237 real_t get_baked_length() const;
238 Vector2 sample_baked(real_t p_offset, bool p_cubic = false) const;
239 Transform2D sample_baked_with_rotation(real_t p_offset, bool p_cubic = false) const;
240 PackedVector2Array get_baked_points() const; //useful for going through
241 Vector2 get_closest_point(const Vector2 &p_to_point) const;
242 real_t get_closest_offset(const Vector2 &p_to_point) const;
243
244 PackedVector2Array tessellate(int p_max_stages = 5, real_t p_tolerance = 4) const; //useful for display
245 PackedVector2Array tessellate_even_length(int p_max_stages = 5, real_t p_length = 20.0) const; // Useful for baking.
246
247 Curve2D();
248};
249
250class Curve3D : public Resource {
251 GDCLASS(Curve3D, Resource);
252
253 struct Point {
254 Vector3 in;
255 Vector3 out;
256 Vector3 position;
257 real_t tilt = 0.0;
258 };
259
260 Vector<Point> points;
261#ifdef TOOLS_ENABLED
262 // For Path3DGizmo.
263 mutable Vector<size_t> points_in_cache;
264#endif
265
266 mutable bool baked_cache_dirty = false;
267 mutable PackedVector3Array baked_point_cache;
268 mutable Vector<real_t> baked_tilt_cache;
269 mutable PackedVector3Array baked_up_vector_cache;
270 mutable PackedVector3Array baked_forward_vector_cache;
271 mutable Vector<real_t> baked_dist_cache;
272 mutable real_t baked_max_ofs = 0.0;
273
274 void mark_dirty();
275
276 static Vector3 _calculate_tangent(const Vector3 &p_begin, const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t);
277 void _bake() const;
278
279 struct Interval {
280 int idx;
281 real_t frac;
282 };
283 Interval _find_interval(real_t p_offset) const;
284 Vector3 _sample_baked(Interval p_interval, bool p_cubic) const;
285 real_t _sample_baked_tilt(Interval p_interval) const;
286 Basis _sample_posture(Interval p_interval, bool p_apply_tilt = false) const;
287 Basis _compose_posture(int p_index) const;
288
289 real_t bake_interval = 0.2;
290 bool up_vector_enabled = true;
291
292 void _bake_segment3d(RBMap<real_t, Vector3> &r_bake, real_t p_begin, real_t p_end, const Vector3 &p_a, const Vector3 &p_out, const Vector3 &p_b, const Vector3 &p_in, int p_depth, int p_max_depth, real_t p_tol) const;
293 void _bake_segment3d_even_length(RBMap<real_t, Vector3> &r_bake, real_t p_begin, real_t p_end, const Vector3 &p_a, const Vector3 &p_out, const Vector3 &p_b, const Vector3 &p_in, int p_depth, int p_max_depth, real_t p_length) const;
294 Dictionary _get_data() const;
295 void _set_data(const Dictionary &p_data);
296
297 bool _set(const StringName &p_name, const Variant &p_value);
298 bool _get(const StringName &p_name, Variant &r_ret) const;
299 void _get_property_list(List<PropertyInfo> *p_list) const;
300
301 void _add_point(const Vector3 &p_position, const Vector3 &p_in = Vector3(), const Vector3 &p_out = Vector3(), int p_atpos = -1);
302 void _remove_point(int p_index);
303
304 Vector<RBMap<real_t, Vector3>> _tessellate_even_length(int p_max_stages = 5, real_t p_length = 0.2) const;
305
306protected:
307 static void _bind_methods();
308
309public:
310#ifdef TOOLS_ENABLED
311 // For Path3DGizmo.
312 Basis get_point_baked_posture(int p_index, bool p_apply_tilt = false) const;
313#endif
314
315 int get_point_count() const;
316 void set_point_count(int p_count);
317 void add_point(const Vector3 &p_position, const Vector3 &p_in = Vector3(), const Vector3 &p_out = Vector3(), int p_atpos = -1);
318 void set_point_position(int p_index, const Vector3 &p_position);
319 Vector3 get_point_position(int p_index) const;
320 void set_point_tilt(int p_index, real_t p_tilt);
321 real_t get_point_tilt(int p_index) const;
322 void set_point_in(int p_index, const Vector3 &p_in);
323 Vector3 get_point_in(int p_index) const;
324 void set_point_out(int p_index, const Vector3 &p_out);
325 Vector3 get_point_out(int p_index) const;
326 void remove_point(int p_index);
327 void clear_points();
328
329 Vector3 sample(int p_index, real_t p_offset) const;
330 Vector3 samplef(real_t p_findex) const;
331
332 void set_bake_interval(real_t p_tolerance);
333 real_t get_bake_interval() const;
334 void set_up_vector_enabled(bool p_enable);
335 bool is_up_vector_enabled() const;
336
337 real_t get_baked_length() const;
338 Vector3 sample_baked(real_t p_offset, bool p_cubic = false) const;
339 Transform3D sample_baked_with_rotation(real_t p_offset, bool p_cubic = false, bool p_apply_tilt = false) const;
340 real_t sample_baked_tilt(real_t p_offset) const;
341 Vector3 sample_baked_up_vector(real_t p_offset, bool p_apply_tilt = false) const;
342 PackedVector3Array get_baked_points() const; // Useful for going through.
343 Vector<real_t> get_baked_tilts() const; //useful for going through
344 PackedVector3Array get_baked_up_vectors() const;
345 Vector3 get_closest_point(const Vector3 &p_to_point) const;
346 real_t get_closest_offset(const Vector3 &p_to_point) const;
347
348 PackedVector3Array tessellate(int p_max_stages = 5, real_t p_tolerance = 4) const; // Useful for display.
349 PackedVector3Array tessellate_even_length(int p_max_stages = 5, real_t p_length = 0.2) const; // Useful for baking.
350
351 Curve3D();
352};
353
354#endif // CURVE_H
355