1 | /**************************************************************************/ |
2 | /* particle_process_material.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 PARTICLE_PROCESS_MATERIAL_H |
32 | #define PARTICLE_PROCESS_MATERIAL_H |
33 | |
34 | #include "core/templates/rid.h" |
35 | #include "scene/resources/material.h" |
36 | |
37 | /* |
38 | TODO: |
39 | -Path following |
40 | -Emitter positions deformable by bones |
41 | -Proper trails |
42 | */ |
43 | |
44 | class ParticleProcessMaterial : public Material { |
45 | GDCLASS(ParticleProcessMaterial, Material); |
46 | |
47 | public: |
48 | enum Parameter { |
49 | PARAM_INITIAL_LINEAR_VELOCITY, |
50 | PARAM_ANGULAR_VELOCITY, |
51 | PARAM_ORBIT_VELOCITY, |
52 | PARAM_LINEAR_ACCEL, |
53 | PARAM_RADIAL_ACCEL, |
54 | PARAM_TANGENTIAL_ACCEL, |
55 | PARAM_DAMPING, |
56 | PARAM_ANGLE, |
57 | PARAM_SCALE, |
58 | PARAM_HUE_VARIATION, |
59 | PARAM_ANIM_SPEED, |
60 | PARAM_ANIM_OFFSET, |
61 | PARAM_TURB_INFLUENCE_OVER_LIFE, |
62 | PARAM_TURB_VEL_INFLUENCE, |
63 | PARAM_TURB_INIT_DISPLACEMENT, |
64 | PARAM_MAX |
65 | }; |
66 | |
67 | // When extending, make sure not to overflow the size of the MaterialKey below. |
68 | enum ParticleFlags { |
69 | PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, |
70 | PARTICLE_FLAG_ROTATE_Y, |
71 | PARTICLE_FLAG_DISABLE_Z, |
72 | PARTICLE_FLAG_MAX |
73 | }; |
74 | |
75 | // When extending, make sure not to overflow the size of the MaterialKey below. |
76 | enum EmissionShape { |
77 | EMISSION_SHAPE_POINT, |
78 | EMISSION_SHAPE_SPHERE, |
79 | EMISSION_SHAPE_SPHERE_SURFACE, |
80 | EMISSION_SHAPE_BOX, |
81 | EMISSION_SHAPE_POINTS, |
82 | EMISSION_SHAPE_DIRECTED_POINTS, |
83 | EMISSION_SHAPE_RING, |
84 | EMISSION_SHAPE_MAX |
85 | }; |
86 | |
87 | // When extending, make sure not to overflow the size of the MaterialKey below. |
88 | enum SubEmitterMode { |
89 | SUB_EMITTER_DISABLED, |
90 | SUB_EMITTER_CONSTANT, |
91 | SUB_EMITTER_AT_END, |
92 | SUB_EMITTER_AT_COLLISION, |
93 | SUB_EMITTER_MAX |
94 | }; |
95 | |
96 | // When extending, make sure not to overflow the size of the MaterialKey below. |
97 | enum CollisionMode { |
98 | COLLISION_DISABLED, |
99 | COLLISION_RIGID, |
100 | COLLISION_HIDE_ON_CONTACT, |
101 | COLLISION_MAX |
102 | }; |
103 | |
104 | private: |
105 | union MaterialKey { |
106 | // The bit size of the struct must be kept below or equal to 32 bits. |
107 | // Consider this when extending ParticleFlags, EmissionShape, or SubEmitterMode. |
108 | struct { |
109 | uint32_t texture_mask : 16; |
110 | uint32_t texture_color : 1; |
111 | uint32_t particle_flags : 4; |
112 | uint32_t emission_shape : 3; |
113 | uint32_t invalid_key : 1; |
114 | uint32_t has_emission_color : 1; |
115 | uint32_t sub_emitter : 2; |
116 | uint32_t attractor_enabled : 1; |
117 | uint32_t collision_mode : 2; |
118 | uint32_t collision_scale : 1; |
119 | uint32_t turbulence_enabled : 1; |
120 | }; |
121 | |
122 | uint64_t key = 0; |
123 | |
124 | static uint32_t hash(const MaterialKey &p_key) { |
125 | return hash_murmur3_one_32(p_key.key); |
126 | } |
127 | |
128 | bool operator==(const MaterialKey &p_key) const { |
129 | return key == p_key.key; |
130 | } |
131 | |
132 | bool operator<(const MaterialKey &p_key) const { |
133 | return key < p_key.key; |
134 | } |
135 | }; |
136 | |
137 | struct ShaderData { |
138 | RID shader; |
139 | int users = 0; |
140 | }; |
141 | |
142 | static HashMap<MaterialKey, ShaderData, MaterialKey> shader_map; |
143 | |
144 | MaterialKey current_key; |
145 | |
146 | _FORCE_INLINE_ MaterialKey _compute_key() const { |
147 | MaterialKey mk; |
148 | mk.key = 0; |
149 | for (int i = 0; i < PARAM_MAX; i++) { |
150 | if (tex_parameters[i].is_valid()) { |
151 | mk.texture_mask |= (1 << i); |
152 | } |
153 | } |
154 | for (int i = 0; i < PARTICLE_FLAG_MAX; i++) { |
155 | if (particle_flags[i]) { |
156 | mk.particle_flags |= (1 << i); |
157 | } |
158 | } |
159 | |
160 | mk.texture_color = color_ramp.is_valid() ? 1 : 0; |
161 | mk.emission_shape = emission_shape; |
162 | mk.has_emission_color = emission_shape >= EMISSION_SHAPE_POINTS && emission_color_texture.is_valid(); |
163 | mk.sub_emitter = sub_emitter_mode; |
164 | mk.collision_mode = collision_mode; |
165 | mk.attractor_enabled = attractor_interaction_enabled; |
166 | mk.collision_scale = collision_scale; |
167 | mk.turbulence_enabled = turbulence_enabled; |
168 | |
169 | return mk; |
170 | } |
171 | |
172 | static Mutex material_mutex; |
173 | static SelfList<ParticleProcessMaterial>::List *dirty_materials; |
174 | |
175 | struct ShaderNames { |
176 | StringName direction; |
177 | StringName spread; |
178 | StringName flatness; |
179 | StringName initial_linear_velocity_min; |
180 | StringName initial_angle_min; |
181 | StringName angular_velocity_min; |
182 | StringName orbit_velocity_min; |
183 | StringName linear_accel_min; |
184 | StringName radial_accel_min; |
185 | StringName tangent_accel_min; |
186 | StringName damping_min; |
187 | StringName scale_min; |
188 | StringName hue_variation_min; |
189 | StringName anim_speed_min; |
190 | StringName anim_offset_min; |
191 | |
192 | StringName initial_linear_velocity_max; |
193 | StringName initial_angle_max; |
194 | StringName angular_velocity_max; |
195 | StringName orbit_velocity_max; |
196 | StringName linear_accel_max; |
197 | StringName radial_accel_max; |
198 | StringName tangent_accel_max; |
199 | StringName damping_max; |
200 | StringName scale_max; |
201 | StringName hue_variation_max; |
202 | StringName anim_speed_max; |
203 | StringName anim_offset_max; |
204 | |
205 | StringName angle_texture; |
206 | StringName angular_velocity_texture; |
207 | StringName orbit_velocity_texture; |
208 | StringName linear_accel_texture; |
209 | StringName radial_accel_texture; |
210 | StringName tangent_accel_texture; |
211 | StringName damping_texture; |
212 | StringName scale_texture; |
213 | StringName hue_variation_texture; |
214 | StringName anim_speed_texture; |
215 | StringName anim_offset_texture; |
216 | |
217 | StringName color; |
218 | StringName color_ramp; |
219 | StringName color_initial_ramp; |
220 | |
221 | StringName emission_sphere_radius; |
222 | StringName emission_box_extents; |
223 | StringName emission_texture_point_count; |
224 | StringName emission_texture_points; |
225 | StringName emission_texture_normal; |
226 | StringName emission_texture_color; |
227 | StringName emission_ring_axis; |
228 | StringName emission_ring_height; |
229 | StringName emission_ring_radius; |
230 | StringName emission_ring_inner_radius; |
231 | |
232 | StringName turbulence_enabled; |
233 | StringName turbulence_noise_strength; |
234 | StringName turbulence_noise_scale; |
235 | StringName turbulence_noise_speed; |
236 | StringName turbulence_noise_speed_random; |
237 | StringName turbulence_influence_over_life; |
238 | StringName turbulence_influence_min; |
239 | StringName turbulence_influence_max; |
240 | StringName turbulence_initial_displacement_min; |
241 | StringName turbulence_initial_displacement_max; |
242 | |
243 | StringName gravity; |
244 | |
245 | StringName lifetime_randomness; |
246 | |
247 | StringName sub_emitter_frequency; |
248 | StringName sub_emitter_amount_at_end; |
249 | StringName sub_emitter_amount_at_collision; |
250 | StringName sub_emitter_keep_velocity; |
251 | |
252 | StringName collision_friction; |
253 | StringName collision_bounce; |
254 | }; |
255 | |
256 | static ShaderNames *shader_names; |
257 | |
258 | SelfList<ParticleProcessMaterial> element; |
259 | |
260 | void _update_shader(); |
261 | _FORCE_INLINE_ void _queue_shader_change(); |
262 | _FORCE_INLINE_ bool _is_shader_dirty() const; |
263 | |
264 | Vector3 direction; |
265 | float spread = 0.0f; |
266 | float flatness = 0.0f; |
267 | |
268 | float params_min[PARAM_MAX] = {}; |
269 | float params_max[PARAM_MAX] = {}; |
270 | float params[PARAM_MAX] = {}; |
271 | |
272 | Ref<Texture2D> tex_parameters[PARAM_MAX]; |
273 | Color color; |
274 | Ref<Texture2D> color_ramp; |
275 | Ref<Texture2D> color_initial_ramp; |
276 | |
277 | bool particle_flags[PARTICLE_FLAG_MAX]; |
278 | |
279 | EmissionShape emission_shape; |
280 | float emission_sphere_radius = 0.0f; |
281 | Vector3 emission_box_extents; |
282 | Ref<Texture2D> emission_point_texture; |
283 | Ref<Texture2D> emission_normal_texture; |
284 | Ref<Texture2D> emission_color_texture; |
285 | Vector3 emission_ring_axis; |
286 | real_t emission_ring_height = 0.0f; |
287 | real_t emission_ring_radius = 0.0f; |
288 | real_t emission_ring_inner_radius = 0.0f; |
289 | int emission_point_count = 1; |
290 | |
291 | bool anim_loop = false; |
292 | |
293 | bool turbulence_enabled; |
294 | Vector3 turbulence_noise_speed; |
295 | Ref<Texture2D> turbulence_color_ramp; |
296 | float turbulence_noise_strength = 0.0f; |
297 | float turbulence_noise_scale = 0.0f; |
298 | float turbulence_noise_speed_random = 0.0f; |
299 | |
300 | Vector3 gravity; |
301 | |
302 | double lifetime_randomness = 0.0; |
303 | |
304 | SubEmitterMode sub_emitter_mode; |
305 | double sub_emitter_frequency = 0.0; |
306 | int sub_emitter_amount_at_end = 0; |
307 | int sub_emitter_amount_at_collision = 0; |
308 | bool sub_emitter_keep_velocity = false; |
309 | //do not save emission points here |
310 | |
311 | bool attractor_interaction_enabled = false; |
312 | CollisionMode collision_mode; |
313 | bool collision_scale = false; |
314 | float collision_friction = 0.0f; |
315 | float collision_bounce = 0.0f; |
316 | |
317 | protected: |
318 | static void _bind_methods(); |
319 | void _validate_property(PropertyInfo &p_property) const; |
320 | |
321 | public: |
322 | void set_direction(Vector3 p_direction); |
323 | Vector3 get_direction() const; |
324 | |
325 | void set_spread(float p_spread); |
326 | float get_spread() const; |
327 | |
328 | void set_flatness(float p_flatness); |
329 | float get_flatness() const; |
330 | |
331 | void set_param_min(Parameter p_param, float p_value); |
332 | float get_param_min(Parameter p_param) const; |
333 | |
334 | void set_param_max(Parameter p_param, float p_value); |
335 | float get_param_max(Parameter p_param) const; |
336 | |
337 | void set_param_texture(Parameter p_param, const Ref<Texture2D> &p_texture); |
338 | Ref<Texture2D> get_param_texture(Parameter p_param) const; |
339 | |
340 | void set_color(const Color &p_color); |
341 | Color get_color() const; |
342 | |
343 | void set_color_ramp(const Ref<Texture2D> &p_texture); |
344 | Ref<Texture2D> get_color_ramp() const; |
345 | |
346 | void set_color_initial_ramp(const Ref<Texture2D> &p_texture); |
347 | Ref<Texture2D> get_color_initial_ramp() const; |
348 | |
349 | void set_particle_flag(ParticleFlags p_particle_flag, bool p_enable); |
350 | bool get_particle_flag(ParticleFlags p_particle_flag) const; |
351 | |
352 | void set_emission_shape(EmissionShape p_shape); |
353 | void set_emission_sphere_radius(real_t p_radius); |
354 | void set_emission_box_extents(Vector3 p_extents); |
355 | void set_emission_point_texture(const Ref<Texture2D> &p_points); |
356 | void set_emission_normal_texture(const Ref<Texture2D> &p_normals); |
357 | void set_emission_color_texture(const Ref<Texture2D> &p_colors); |
358 | void set_emission_ring_axis(Vector3 p_axis); |
359 | void set_emission_ring_height(real_t p_height); |
360 | void set_emission_ring_radius(real_t p_radius); |
361 | void set_emission_ring_inner_radius(real_t p_radius); |
362 | void set_emission_point_count(int p_count); |
363 | |
364 | EmissionShape get_emission_shape() const; |
365 | real_t get_emission_sphere_radius() const; |
366 | Vector3 get_emission_box_extents() const; |
367 | Ref<Texture2D> get_emission_point_texture() const; |
368 | Ref<Texture2D> get_emission_normal_texture() const; |
369 | Ref<Texture2D> get_emission_color_texture() const; |
370 | Vector3 get_emission_ring_axis() const; |
371 | real_t get_emission_ring_height() const; |
372 | real_t get_emission_ring_radius() const; |
373 | real_t get_emission_ring_inner_radius() const; |
374 | int get_emission_point_count() const; |
375 | |
376 | void set_turbulence_enabled(bool p_turbulence_enabled); |
377 | void set_turbulence_noise_strength(float p_turbulence_noise_strength); |
378 | void set_turbulence_noise_scale(float p_turbulence_noise_scale); |
379 | void set_turbulence_noise_speed_random(float p_turbulence_noise_speed_random); |
380 | void set_turbulence_noise_speed(const Vector3 &p_turbulence_noise_speed); |
381 | |
382 | bool get_turbulence_enabled() const; |
383 | float get_turbulence_noise_strength() const; |
384 | float get_turbulence_noise_scale() const; |
385 | float get_turbulence_noise_speed_random() const; |
386 | Vector3 get_turbulence_noise_speed() const; |
387 | |
388 | void set_gravity(const Vector3 &p_gravity); |
389 | Vector3 get_gravity() const; |
390 | |
391 | void set_lifetime_randomness(double p_lifetime); |
392 | double get_lifetime_randomness() const; |
393 | |
394 | void set_attractor_interaction_enabled(bool p_enable); |
395 | bool is_attractor_interaction_enabled() const; |
396 | |
397 | void set_collision_mode(CollisionMode p_collision_mode); |
398 | CollisionMode get_collision_mode() const; |
399 | |
400 | void set_collision_use_scale(bool p_scale); |
401 | bool is_collision_using_scale() const; |
402 | |
403 | void set_collision_friction(float p_friction); |
404 | float get_collision_friction() const; |
405 | |
406 | void set_collision_bounce(float p_bounce); |
407 | float get_collision_bounce() const; |
408 | |
409 | static void init_shaders(); |
410 | static void finish_shaders(); |
411 | static void flush_changes(); |
412 | |
413 | void set_sub_emitter_mode(SubEmitterMode p_sub_emitter_mode); |
414 | SubEmitterMode get_sub_emitter_mode() const; |
415 | |
416 | void set_sub_emitter_frequency(double p_frequency); |
417 | double get_sub_emitter_frequency() const; |
418 | |
419 | void set_sub_emitter_amount_at_end(int p_amount); |
420 | int get_sub_emitter_amount_at_end() const; |
421 | |
422 | void set_sub_emitter_amount_at_collision(int p_amount); |
423 | int get_sub_emitter_amount_at_collision() const; |
424 | |
425 | void set_sub_emitter_keep_velocity(bool p_enable); |
426 | bool get_sub_emitter_keep_velocity() const; |
427 | |
428 | virtual RID get_shader_rid() const override; |
429 | |
430 | virtual Shader::Mode get_shader_mode() const override; |
431 | |
432 | ParticleProcessMaterial(); |
433 | ~ParticleProcessMaterial(); |
434 | }; |
435 | |
436 | VARIANT_ENUM_CAST(ParticleProcessMaterial::Parameter) |
437 | VARIANT_ENUM_CAST(ParticleProcessMaterial::ParticleFlags) |
438 | VARIANT_ENUM_CAST(ParticleProcessMaterial::EmissionShape) |
439 | VARIANT_ENUM_CAST(ParticleProcessMaterial::SubEmitterMode) |
440 | VARIANT_ENUM_CAST(ParticleProcessMaterial::CollisionMode) |
441 | |
442 | #endif // PARTICLE_PROCESS_MATERIAL_H |
443 | |