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 |
37 | class Curve : public Resource { |
38 | GDCLASS(Curve, Resource); |
39 | |
40 | public: |
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 | |
141 | protected: |
142 | static void _bind_methods(); |
143 | |
144 | private: |
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 | |
162 | VARIANT_ENUM_CAST(Curve::TangentMode) |
163 | |
164 | class 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 | |
215 | protected: |
216 | static void _bind_methods(); |
217 | |
218 | public: |
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 | |
250 | class 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 | |
306 | protected: |
307 | static void _bind_methods(); |
308 | |
309 | public: |
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 | |