mirror of
https://github.com/Relintai/pandemonium_engine.git
synced 2025-02-02 14:25:55 +01:00
Adding back the gpu based particles pt1.
This commit is contained in:
parent
3cab5b1e09
commit
9af21bf8a5
130
doc/classes/Particles.xml
Normal file
130
doc/classes/Particles.xml
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<class name="Particles" inherits="GeometryInstance" version="3.6" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
|
||||||
|
<brief_description>
|
||||||
|
GPU-based 3D particle emitter.
|
||||||
|
</brief_description>
|
||||||
|
<description>
|
||||||
|
3D particle node used to create a variety of particle systems and effects. [Particles] features an emitter that generates some number of particles at a given rate.
|
||||||
|
Use the [code]process_material[/code] property to add a [ParticlesMaterial] to configure particle appearance and behavior. Alternatively, you can add a [ShaderMaterial] which will be applied to all particles.
|
||||||
|
[b]Note:[/b] [Particles] only work when using the GLES3 renderer. If using the GLES2 renderer, use [CPUParticles] instead. You can convert [Particles] to [CPUParticles] by selecting the node, clicking the [b]Particles[/b] menu at the top of the 3D editor viewport then choosing [b]Convert to CPUParticles[/b].
|
||||||
|
[b]Note:[/b] On macOS, [Particles] rendering is much slower than [CPUParticles] due to transform feedback being implemented on the CPU instead of the GPU. Consider using [CPUParticles] instead when targeting macOS.
|
||||||
|
[b]Note:[/b] After working on a Particles node, remember to update its [member visibility_aabb] by selecting it, clicking the [b]Particles[/b] menu at the top of the 3D editor viewport then choose [b]Generate Visibility AABB[/b]. Otherwise, particles may suddenly disappear depending on the camera position and angle.
|
||||||
|
</description>
|
||||||
|
<tutorials>
|
||||||
|
<link title="Controlling thousands of fish with Particles">$DOCS_URL/tutorials/performance/vertex_animation/controlling_thousands_of_fish.html</link>
|
||||||
|
<link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</link>
|
||||||
|
</tutorials>
|
||||||
|
<methods>
|
||||||
|
<method name="capture_aabb" qualifiers="const">
|
||||||
|
<return type="AABB" />
|
||||||
|
<description>
|
||||||
|
Returns the axis-aligned bounding box that contains all the particles that are active in the current frame.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="get_draw_pass_mesh" qualifiers="const">
|
||||||
|
<return type="Mesh" />
|
||||||
|
<argument index="0" name="pass" type="int" />
|
||||||
|
<description>
|
||||||
|
Returns the [Mesh] that is drawn at index [code]pass[/code].
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="restart">
|
||||||
|
<return type="void" />
|
||||||
|
<description>
|
||||||
|
Restarts the particle emission, clearing existing particles.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="set_draw_pass_mesh">
|
||||||
|
<return type="void" />
|
||||||
|
<argument index="0" name="pass" type="int" />
|
||||||
|
<argument index="1" name="mesh" type="Mesh" />
|
||||||
|
<description>
|
||||||
|
Sets the [Mesh] that is drawn at index [code]pass[/code].
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
</methods>
|
||||||
|
<members>
|
||||||
|
<member name="amount" type="int" setter="set_amount" getter="get_amount" default="8">
|
||||||
|
The number of particles emitted in one emission cycle (corresponding to the [member lifetime]).
|
||||||
|
[b]Note:[/b] Changing [member amount] will reset the particle emission, therefore removing all particles that were already emitted before changing [member amount].
|
||||||
|
</member>
|
||||||
|
<member name="draw_order" type="int" setter="set_draw_order" getter="get_draw_order" enum="Particles.DrawOrder" default="0">
|
||||||
|
Particle draw order. Uses [enum DrawOrder] values.
|
||||||
|
</member>
|
||||||
|
<member name="draw_pass_1" type="Mesh" setter="set_draw_pass_mesh" getter="get_draw_pass_mesh">
|
||||||
|
[Mesh] that is drawn for the first draw pass.
|
||||||
|
</member>
|
||||||
|
<member name="draw_pass_2" type="Mesh" setter="set_draw_pass_mesh" getter="get_draw_pass_mesh">
|
||||||
|
[Mesh] that is drawn for the second draw pass.
|
||||||
|
</member>
|
||||||
|
<member name="draw_pass_3" type="Mesh" setter="set_draw_pass_mesh" getter="get_draw_pass_mesh">
|
||||||
|
[Mesh] that is drawn for the third draw pass.
|
||||||
|
</member>
|
||||||
|
<member name="draw_pass_4" type="Mesh" setter="set_draw_pass_mesh" getter="get_draw_pass_mesh">
|
||||||
|
[Mesh] that is drawn for the fourth draw pass.
|
||||||
|
</member>
|
||||||
|
<member name="draw_passes" type="int" setter="set_draw_passes" getter="get_draw_passes" default="1">
|
||||||
|
The number of draw passes when rendering particles.
|
||||||
|
</member>
|
||||||
|
<member name="emitting" type="bool" setter="set_emitting" getter="is_emitting" default="true">
|
||||||
|
If [code]true[/code], particles are being emitted.
|
||||||
|
</member>
|
||||||
|
<member name="explosiveness" type="float" setter="set_explosiveness_ratio" getter="get_explosiveness_ratio" default="0.0">
|
||||||
|
Time ratio between each emission. If [code]0[/code], particles are emitted continuously. If [code]1[/code], all particles are emitted simultaneously.
|
||||||
|
</member>
|
||||||
|
<member name="fixed_fps" type="int" setter="set_fixed_fps" getter="get_fixed_fps" default="0">
|
||||||
|
The particle system's frame rate is fixed to a value. For instance, changing the value to 2 will make the particles render at 2 frames per second. Note this does not slow down the simulation of the particle system itself.
|
||||||
|
</member>
|
||||||
|
<member name="fract_delta" type="bool" setter="set_fractional_delta" getter="get_fractional_delta" default="true">
|
||||||
|
If [code]true[/code], results in fractional delta calculation which has a smoother particles display effect.
|
||||||
|
</member>
|
||||||
|
<member name="lifetime" type="float" setter="set_lifetime" getter="get_lifetime" default="1.0">
|
||||||
|
The amount of time each particle will exist (in seconds).
|
||||||
|
</member>
|
||||||
|
<member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates" default="true">
|
||||||
|
If [code]true[/code], particles use the parent node's coordinate space. If [code]false[/code], they use global coordinates.
|
||||||
|
</member>
|
||||||
|
<member name="one_shot" type="bool" setter="set_one_shot" getter="get_one_shot" default="false">
|
||||||
|
If [code]true[/code], only [code]amount[/code] particles will be emitted.
|
||||||
|
</member>
|
||||||
|
<member name="preprocess" type="float" setter="set_pre_process_time" getter="get_pre_process_time" default="0.0">
|
||||||
|
Amount of time to preprocess the particles before animation starts. Lets you start the animation some time after particles have started emitting.
|
||||||
|
</member>
|
||||||
|
<member name="process_material" type="Material" setter="set_process_material" getter="get_process_material">
|
||||||
|
[Material] for processing particles. Can be a [ParticlesMaterial] or a [ShaderMaterial].
|
||||||
|
</member>
|
||||||
|
<member name="randomness" type="float" setter="set_randomness_ratio" getter="get_randomness_ratio" default="0.0">
|
||||||
|
Emission randomness ratio.
|
||||||
|
</member>
|
||||||
|
<member name="speed_scale" type="float" setter="set_speed_scale" getter="get_speed_scale" default="1.0">
|
||||||
|
Speed scaling ratio. A value of [code]0[/code] can be used to pause the particles.
|
||||||
|
</member>
|
||||||
|
<member name="visibility_aabb" type="AABB" setter="set_visibility_aabb" getter="get_visibility_aabb" default="AABB( -4, -4, -4, 8, 8, 8 )">
|
||||||
|
The [AABB] that determines the node's region which needs to be visible on screen for the particle system to be active.
|
||||||
|
Grow the box if particles suddenly appear/disappear when the node enters/exits the screen. The [AABB] can be grown via code or with the [b]Particles → Generate AABB[/b] editor tool.
|
||||||
|
[b]Note:[/b] If the [ParticlesMaterial] in use is configured to cast shadows, you may want to enlarge this AABB to ensure the shadow is updated when particles are off-screen.
|
||||||
|
</member>
|
||||||
|
</members>
|
||||||
|
<signals>
|
||||||
|
<signal name="finished">
|
||||||
|
<description>
|
||||||
|
Emitted when all active particles have finished processing. When [member one_shot] is disabled, particles will process continuously, so this is never emitted.
|
||||||
|
[b]Note:[/b] Due to the particles being computed on the GPU there might be a delay before the signal gets emitted.
|
||||||
|
</description>
|
||||||
|
</signal>
|
||||||
|
</signals>
|
||||||
|
<constants>
|
||||||
|
<constant name="DRAW_ORDER_INDEX" value="0" enum="DrawOrder">
|
||||||
|
Particles are drawn in the order emitted.
|
||||||
|
</constant>
|
||||||
|
<constant name="DRAW_ORDER_LIFETIME" value="1" enum="DrawOrder">
|
||||||
|
Particles are drawn in order of remaining lifetime.
|
||||||
|
</constant>
|
||||||
|
<constant name="DRAW_ORDER_VIEW_DEPTH" value="2" enum="DrawOrder">
|
||||||
|
Particles are drawn in order of depth.
|
||||||
|
</constant>
|
||||||
|
<constant name="MAX_DRAW_PASSES" value="4">
|
||||||
|
Maximum number of draw passes supported.
|
||||||
|
</constant>
|
||||||
|
</constants>
|
||||||
|
</class>
|
103
doc/classes/Particles2D.xml
Normal file
103
doc/classes/Particles2D.xml
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<class name="Particles2D" inherits="Node2D" version="3.6" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
|
||||||
|
<brief_description>
|
||||||
|
GPU-based 2D particle emitter.
|
||||||
|
</brief_description>
|
||||||
|
<description>
|
||||||
|
2D particle node used to create a variety of particle systems and effects. [Particles2D] features an emitter that generates some number of particles at a given rate.
|
||||||
|
Use the [code]process_material[/code] property to add a [ParticlesMaterial] to configure particle appearance and behavior. Alternatively, you can add a [ShaderMaterial] which will be applied to all particles.
|
||||||
|
[b]Note:[/b] [Particles2D] only work when using the GLES3 renderer. If using the GLES2 renderer, use [CPUParticles2D] instead. You can convert [Particles2D] to [CPUParticles2D] by selecting the node, clicking the [b]Particles[/b] menu at the top of the 2D editor viewport then choosing [b]Convert to CPUParticles2D[/b].
|
||||||
|
[b]Note:[/b] On macOS, [Particles2D] rendering is much slower than [CPUParticles2D] due to transform feedback being implemented on the CPU instead of the GPU. Consider using [CPUParticles2D] instead when targeting macOS.
|
||||||
|
[b]Note:[/b] After working on a Particles node, remember to update its [member visibility_rect] by selecting it, clicking the [b]Particles[/b] menu at the top of the 2D editor viewport then choose [b]Generate Visibility Rect[/b]. Otherwise, particles may suddenly disappear depending on the camera position and angle.
|
||||||
|
[b]Note:[/b] Unlike [CPUParticles2D], [Particles2D] currently ignore the texture region defined in [AtlasTexture]s.
|
||||||
|
</description>
|
||||||
|
<tutorials>
|
||||||
|
<link title="Particle systems (2D)">$DOCS_URL/tutorials/2d/particle_systems_2d.html</link>
|
||||||
|
<link title="2D Particles Demo">https://godotengine.org/asset-library/asset/118</link>
|
||||||
|
<link title="2D Dodge The Creeps Demo (uses GPUParticles2D for the trail behind the player)">https://godotengine.org/asset-library/asset/515</link>
|
||||||
|
</tutorials>
|
||||||
|
<methods>
|
||||||
|
<method name="capture_rect" qualifiers="const">
|
||||||
|
<return type="Rect2" />
|
||||||
|
<description>
|
||||||
|
Returns a rectangle containing the positions of all existing particles.
|
||||||
|
[b]Note:[/b] When using threaded rendering this method synchronizes the rendering thread. Calling it often may have a negative impact on performance.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="restart">
|
||||||
|
<return type="void" />
|
||||||
|
<description>
|
||||||
|
Restarts all the existing particles.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
</methods>
|
||||||
|
<members>
|
||||||
|
<member name="amount" type="int" setter="set_amount" getter="get_amount" default="8">
|
||||||
|
The number of particles emitted in one emission cycle (corresponding to the [member lifetime]).
|
||||||
|
[b]Note:[/b] Changing [member amount] will reset the particle emission, therefore removing all particles that were already emitted before changing [member amount].
|
||||||
|
</member>
|
||||||
|
<member name="draw_order" type="int" setter="set_draw_order" getter="get_draw_order" enum="Particles2D.DrawOrder" default="0">
|
||||||
|
Particle draw order. Uses [enum DrawOrder] values.
|
||||||
|
</member>
|
||||||
|
<member name="emitting" type="bool" setter="set_emitting" getter="is_emitting" default="true">
|
||||||
|
If [code]true[/code], particles are being emitted.
|
||||||
|
</member>
|
||||||
|
<member name="explosiveness" type="float" setter="set_explosiveness_ratio" getter="get_explosiveness_ratio" default="0.0">
|
||||||
|
How rapidly particles in an emission cycle are emitted. If greater than [code]0[/code], there will be a gap in emissions before the next cycle begins.
|
||||||
|
</member>
|
||||||
|
<member name="fixed_fps" type="int" setter="set_fixed_fps" getter="get_fixed_fps" default="0">
|
||||||
|
The particle system's frame rate is fixed to a value. For instance, changing the value to 2 will make the particles render at 2 frames per second. Note this does not slow down the simulation of the particle system itself.
|
||||||
|
</member>
|
||||||
|
<member name="fract_delta" type="bool" setter="set_fractional_delta" getter="get_fractional_delta" default="true">
|
||||||
|
If [code]true[/code], results in fractional delta calculation which has a smoother particles display effect.
|
||||||
|
</member>
|
||||||
|
<member name="lifetime" type="float" setter="set_lifetime" getter="get_lifetime" default="1.0">
|
||||||
|
The amount of time each particle will exist (in seconds).
|
||||||
|
</member>
|
||||||
|
<member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates" default="true">
|
||||||
|
If [code]true[/code], particles use the parent node's coordinate space. If [code]false[/code], they use global coordinates.
|
||||||
|
</member>
|
||||||
|
<member name="normal_map" type="Texture" setter="set_normal_map" getter="get_normal_map">
|
||||||
|
Normal map to be used for the [member texture] property.
|
||||||
|
[b]Note:[/b] Godot expects the normal map to use X+, Y-, and Z+ coordinates. See [url=http://wiki.polycount.com/wiki/Normal_Map_Technical_Details#Common_Swizzle_Coordinates]this page[/url] for a comparison of normal map coordinates expected by popular engines.
|
||||||
|
</member>
|
||||||
|
<member name="one_shot" type="bool" setter="set_one_shot" getter="get_one_shot" default="false">
|
||||||
|
If [code]true[/code], only one emission cycle occurs. If set [code]true[/code] during a cycle, emission will stop at the cycle's end.
|
||||||
|
</member>
|
||||||
|
<member name="preprocess" type="float" setter="set_pre_process_time" getter="get_pre_process_time" default="0.0">
|
||||||
|
Particle system starts as if it had already run for this many seconds.
|
||||||
|
</member>
|
||||||
|
<member name="process_material" type="Material" setter="set_process_material" getter="get_process_material">
|
||||||
|
[Material] for processing particles. Can be a [ParticlesMaterial] or a [ShaderMaterial].
|
||||||
|
</member>
|
||||||
|
<member name="randomness" type="float" setter="set_randomness_ratio" getter="get_randomness_ratio" default="0.0">
|
||||||
|
Emission lifetime randomness ratio.
|
||||||
|
</member>
|
||||||
|
<member name="speed_scale" type="float" setter="set_speed_scale" getter="get_speed_scale" default="1.0">
|
||||||
|
Particle system's running speed scaling ratio. A value of [code]0[/code] can be used to pause the particles.
|
||||||
|
</member>
|
||||||
|
<member name="texture" type="Texture" setter="set_texture" getter="get_texture">
|
||||||
|
Particle texture. If [code]null[/code], particles will be squares.
|
||||||
|
</member>
|
||||||
|
<member name="visibility_rect" type="Rect2" setter="set_visibility_rect" getter="get_visibility_rect" default="Rect2( -100, -100, 200, 200 )">
|
||||||
|
The [Rect2] that determines the node's region which needs to be visible on screen for the particle system to be active.
|
||||||
|
Grow the rect if particles suddenly appear/disappear when the node enters/exits the screen. The [Rect2] can be grown via code or with the [b]Particles → Generate Visibility Rect[/b] editor tool.
|
||||||
|
</member>
|
||||||
|
</members>
|
||||||
|
<signals>
|
||||||
|
<signal name="finished">
|
||||||
|
<description>
|
||||||
|
Emitted when all active particles have finished processing. When [member one_shot] is disabled, particles will process continuously, so this is never emitted.
|
||||||
|
[b]Note:[/b] Due to the particles being computed on the GPU there might be a delay before the signal gets emitted.
|
||||||
|
</description>
|
||||||
|
</signal>
|
||||||
|
</signals>
|
||||||
|
<constants>
|
||||||
|
<constant name="DRAW_ORDER_INDEX" value="0" enum="DrawOrder">
|
||||||
|
Particles are drawn in the order emitted.
|
||||||
|
</constant>
|
||||||
|
<constant name="DRAW_ORDER_LIFETIME" value="1" enum="DrawOrder">
|
||||||
|
Particles are drawn in order of remaining lifetime.
|
||||||
|
</constant>
|
||||||
|
</constants>
|
||||||
|
</class>
|
@ -553,6 +553,42 @@ public:
|
|||||||
void instance_add_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) {}
|
void instance_add_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) {}
|
||||||
void instance_remove_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) {}
|
void instance_remove_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) {}
|
||||||
|
|
||||||
|
/* PARTICLES */
|
||||||
|
|
||||||
|
RID particles_create() { return RID(); }
|
||||||
|
|
||||||
|
void particles_set_emitting(RID p_particles, bool p_emitting) {}
|
||||||
|
void particles_set_amount(RID p_particles, int p_amount) {}
|
||||||
|
void particles_set_lifetime(RID p_particles, float p_lifetime) {}
|
||||||
|
void particles_set_one_shot(RID p_particles, bool p_one_shot) {}
|
||||||
|
void particles_set_pre_process_time(RID p_particles, float p_time) {}
|
||||||
|
void particles_set_explosiveness_ratio(RID p_particles, float p_ratio) {}
|
||||||
|
void particles_set_randomness_ratio(RID p_particles, float p_ratio) {}
|
||||||
|
void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) {}
|
||||||
|
void particles_set_speed_scale(RID p_particles, float p_scale) {}
|
||||||
|
void particles_set_use_local_coordinates(RID p_particles, bool p_enable) {}
|
||||||
|
void particles_set_process_material(RID p_particles, RID p_material) {}
|
||||||
|
void particles_set_fixed_fps(RID p_particles, int p_fps) {}
|
||||||
|
void particles_set_fractional_delta(RID p_particles, bool p_enable) {}
|
||||||
|
void particles_restart(RID p_particles) {}
|
||||||
|
|
||||||
|
void particles_set_draw_order(RID p_particles, VS::ParticlesDrawOrder p_order) {}
|
||||||
|
|
||||||
|
void particles_set_draw_passes(RID p_particles, int p_count) {}
|
||||||
|
void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) {}
|
||||||
|
|
||||||
|
void particles_request_process(RID p_particles) {}
|
||||||
|
AABB particles_get_current_aabb(RID p_particles) { return AABB(); }
|
||||||
|
AABB particles_get_aabb(RID p_particles) const { return AABB(); }
|
||||||
|
|
||||||
|
void particles_set_emission_transform(RID p_particles, const Transform &p_transform) {}
|
||||||
|
|
||||||
|
bool particles_get_emitting(RID p_particles) { return false; }
|
||||||
|
int particles_get_draw_passes(RID p_particles) const { return 0; }
|
||||||
|
RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const { return RID(); }
|
||||||
|
|
||||||
|
virtual bool particles_is_inactive(RID p_particles) const { return false; }
|
||||||
|
|
||||||
/* LIGHTMAP CAPTURE */
|
/* LIGHTMAP CAPTURE */
|
||||||
struct Instantiable : public RID_Data {
|
struct Instantiable : public RID_Data {
|
||||||
SelfList<RasterizerScene::InstanceBase>::List instance_list;
|
SelfList<RasterizerScene::InstanceBase>::List instance_list;
|
||||||
|
@ -1159,6 +1159,10 @@ void RasterizerCanvasGLES2::render_batches(Item *p_current_clip, bool &r_reclip,
|
|||||||
state.uniforms.extra_matrix = transform->xform;
|
state.uniforms.extra_matrix = transform->xform;
|
||||||
state.canvas_shader.set_uniform(CanvasShaderGLES2::EXTRA_MATRIX, state.uniforms.extra_matrix);
|
state.canvas_shader.set_uniform(CanvasShaderGLES2::EXTRA_MATRIX, state.uniforms.extra_matrix);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case Item::Command::TYPE_PARTICLES: {
|
||||||
|
} break;
|
||||||
|
|
||||||
case Item::Command::TYPE_CLIP_IGNORE: {
|
case Item::Command::TYPE_CLIP_IGNORE: {
|
||||||
Item::CommandClipIgnore *ci = static_cast<Item::CommandClipIgnore *>(command);
|
Item::CommandClipIgnore *ci = static_cast<Item::CommandClipIgnore *>(command);
|
||||||
if (p_current_clip) {
|
if (p_current_clip) {
|
||||||
|
@ -4669,6 +4669,96 @@ int RasterizerStorageGLES2::reflection_probe_get_resolution(RID p_probe) const {
|
|||||||
|
|
||||||
///////
|
///////
|
||||||
|
|
||||||
|
RID RasterizerStorageGLES2::particles_create() {
|
||||||
|
return RID();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerStorageGLES2::particles_set_emitting(RID p_particles, bool p_emitting) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RasterizerStorageGLES2::particles_get_emitting(RID p_particles) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerStorageGLES2::particles_set_amount(RID p_particles, int p_amount) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerStorageGLES2::particles_set_lifetime(RID p_particles, float p_lifetime) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerStorageGLES2::particles_set_one_shot(RID p_particles, bool p_one_shot) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerStorageGLES2::particles_set_pre_process_time(RID p_particles, float p_time) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerStorageGLES2::particles_set_explosiveness_ratio(RID p_particles, float p_ratio) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerStorageGLES2::particles_set_randomness_ratio(RID p_particles, float p_ratio) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerStorageGLES2::particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerStorageGLES2::particles_set_speed_scale(RID p_particles, float p_scale) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerStorageGLES2::particles_set_use_local_coordinates(RID p_particles, bool p_enable) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerStorageGLES2::particles_set_fixed_fps(RID p_particles, int p_fps) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerStorageGLES2::particles_set_fractional_delta(RID p_particles, bool p_enable) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerStorageGLES2::particles_set_process_material(RID p_particles, RID p_material) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerStorageGLES2::particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerStorageGLES2::particles_set_draw_passes(RID p_particles, int p_passes) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerStorageGLES2::particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerStorageGLES2::particles_restart(RID p_particles) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerStorageGLES2::particles_request_process(RID p_particles) {
|
||||||
|
}
|
||||||
|
|
||||||
|
AABB RasterizerStorageGLES2::particles_get_current_aabb(RID p_particles) {
|
||||||
|
return AABB();
|
||||||
|
}
|
||||||
|
|
||||||
|
AABB RasterizerStorageGLES2::particles_get_aabb(RID p_particles) const {
|
||||||
|
return AABB();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerStorageGLES2::particles_set_emission_transform(RID p_particles, const Transform &p_transform) {
|
||||||
|
}
|
||||||
|
|
||||||
|
int RasterizerStorageGLES2::particles_get_draw_passes(RID p_particles) const {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
RID RasterizerStorageGLES2::particles_get_draw_pass_mesh(RID p_particles, int p_pass) const {
|
||||||
|
return RID();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerStorageGLES2::update_particles() {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RasterizerStorageGLES2::particles_is_inactive(RID p_particles) const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////
|
||||||
|
|
||||||
RID RasterizerStorageGLES2::lightmap_capture_create() {
|
RID RasterizerStorageGLES2::lightmap_capture_create() {
|
||||||
LightmapCapture *capture = memnew(LightmapCapture);
|
LightmapCapture *capture = memnew(LightmapCapture);
|
||||||
return lightmap_capture_data_owner.make_rid(capture);
|
return lightmap_capture_data_owner.make_rid(capture);
|
||||||
@ -4819,6 +4909,10 @@ void RasterizerStorageGLES2::instance_add_dependency(RID p_base, RasterizerScene
|
|||||||
inst = immediate_owner.getornull(p_base);
|
inst = immediate_owner.getornull(p_base);
|
||||||
ERR_FAIL_COND(!inst);
|
ERR_FAIL_COND(!inst);
|
||||||
} break;
|
} break;
|
||||||
|
/*case RS::INSTANCE_PARTICLES: {
|
||||||
|
inst = particles_owner.getornull(p_base);
|
||||||
|
ERR_FAIL_COND(!inst);
|
||||||
|
} break;*/
|
||||||
case RS::INSTANCE_REFLECTION_PROBE: {
|
case RS::INSTANCE_REFLECTION_PROBE: {
|
||||||
inst = reflection_probe_owner.getornull(p_base);
|
inst = reflection_probe_owner.getornull(p_base);
|
||||||
ERR_FAIL_COND(!inst);
|
ERR_FAIL_COND(!inst);
|
||||||
@ -4855,6 +4949,10 @@ void RasterizerStorageGLES2::instance_remove_dependency(RID p_base, RasterizerSc
|
|||||||
inst = immediate_owner.getornull(p_base);
|
inst = immediate_owner.getornull(p_base);
|
||||||
ERR_FAIL_COND(!inst);
|
ERR_FAIL_COND(!inst);
|
||||||
} break;
|
} break;
|
||||||
|
/*case RS::INSTANCE_PARTICLES: {
|
||||||
|
inst = particles_owner.getornull(p_base);
|
||||||
|
ERR_FAIL_COND(!inst);
|
||||||
|
} break;*/
|
||||||
case RS::INSTANCE_REFLECTION_PROBE: {
|
case RS::INSTANCE_REFLECTION_PROBE: {
|
||||||
inst = reflection_probe_owner.getornull(p_base);
|
inst = reflection_probe_owner.getornull(p_base);
|
||||||
ERR_FAIL_COND(!inst);
|
ERR_FAIL_COND(!inst);
|
||||||
@ -6540,3 +6638,4 @@ RasterizerStorageGLES2::RasterizerStorageGLES2() {
|
|||||||
RasterizerStorageGLES2::system_fbo = 0;
|
RasterizerStorageGLES2::system_fbo = 0;
|
||||||
config.should_orphan = true;
|
config.should_orphan = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1052,6 +1052,45 @@ public:
|
|||||||
virtual float reflection_probe_get_origin_max_distance(RID p_probe) const;
|
virtual float reflection_probe_get_origin_max_distance(RID p_probe) const;
|
||||||
virtual bool reflection_probe_renders_shadows(RID p_probe) const;
|
virtual bool reflection_probe_renders_shadows(RID p_probe) const;
|
||||||
|
|
||||||
|
/* PARTICLES */
|
||||||
|
|
||||||
|
void update_particles();
|
||||||
|
|
||||||
|
virtual RID particles_create();
|
||||||
|
|
||||||
|
virtual void particles_set_emitting(RID p_particles, bool p_emitting);
|
||||||
|
virtual bool particles_get_emitting(RID p_particles);
|
||||||
|
|
||||||
|
virtual void particles_set_amount(RID p_particles, int p_amount);
|
||||||
|
virtual void particles_set_lifetime(RID p_particles, float p_lifetime);
|
||||||
|
virtual void particles_set_one_shot(RID p_particles, bool p_one_shot);
|
||||||
|
virtual void particles_set_pre_process_time(RID p_particles, float p_time);
|
||||||
|
virtual void particles_set_explosiveness_ratio(RID p_particles, float p_ratio);
|
||||||
|
virtual void particles_set_randomness_ratio(RID p_particles, float p_ratio);
|
||||||
|
virtual void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb);
|
||||||
|
virtual void particles_set_speed_scale(RID p_particles, float p_scale);
|
||||||
|
virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable);
|
||||||
|
virtual void particles_set_process_material(RID p_particles, RID p_material);
|
||||||
|
virtual void particles_set_fixed_fps(RID p_particles, int p_fps);
|
||||||
|
virtual void particles_set_fractional_delta(RID p_particles, bool p_enable);
|
||||||
|
virtual void particles_restart(RID p_particles);
|
||||||
|
|
||||||
|
virtual void particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order);
|
||||||
|
|
||||||
|
virtual void particles_set_draw_passes(RID p_particles, int p_passes);
|
||||||
|
virtual void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh);
|
||||||
|
|
||||||
|
virtual void particles_request_process(RID p_particles);
|
||||||
|
virtual AABB particles_get_current_aabb(RID p_particles);
|
||||||
|
virtual AABB particles_get_aabb(RID p_particles) const;
|
||||||
|
|
||||||
|
virtual void particles_set_emission_transform(RID p_particles, const Transform &p_transform);
|
||||||
|
|
||||||
|
virtual int particles_get_draw_passes(RID p_particles) const;
|
||||||
|
virtual RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const;
|
||||||
|
|
||||||
|
virtual bool particles_is_inactive(RID p_particles) const;
|
||||||
|
|
||||||
/* LIGHTMAP */
|
/* LIGHTMAP */
|
||||||
|
|
||||||
struct LightmapCapture : public Instantiable {
|
struct LightmapCapture : public Instantiable {
|
||||||
|
@ -117,6 +117,9 @@ String get_command_type_string(const RasterizerCanvas::Item::Command &p_command)
|
|||||||
case RasterizerCanvas::Item::Command::TYPE_MULTIMESH: {
|
case RasterizerCanvas::Item::Command::TYPE_MULTIMESH: {
|
||||||
sz = "MM";
|
sz = "MM";
|
||||||
} break;
|
} break;
|
||||||
|
case RasterizerCanvas::Item::Command::TYPE_PARTICLES: {
|
||||||
|
sz = "PA";
|
||||||
|
} break;
|
||||||
case RasterizerCanvas::Item::Command::TYPE_CIRCLE: {
|
case RasterizerCanvas::Item::Command::TYPE_CIRCLE: {
|
||||||
sz = "c";
|
sz = "c";
|
||||||
} break;
|
} break;
|
||||||
|
453
editor/plugins/particles_2d_editor_plugin.cpp
Normal file
453
editor/plugins/particles_2d_editor_plugin.cpp
Normal file
@ -0,0 +1,453 @@
|
|||||||
|
/**************************************************************************/
|
||||||
|
/* particles_2d_editor_plugin.cpp */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||||
|
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#include "particles_2d_editor_plugin.h"
|
||||||
|
|
||||||
|
#include "canvas_item_editor_plugin.h"
|
||||||
|
#include "core/io/image_loader.h"
|
||||||
|
#include "scene/2d/cpu_particles_2d.h"
|
||||||
|
#include "scene/gui/separator.h"
|
||||||
|
#include "scene/resources/material/particles_material.h"
|
||||||
|
#include "scene/2d/particles_2d.h"
|
||||||
|
#include "scene/gui/box_container.h"
|
||||||
|
#include "scene/gui/file_dialog.h"
|
||||||
|
#include "editor/editor_file_dialog.h"
|
||||||
|
#include "scene/gui/option_button.h"
|
||||||
|
#include "scene/gui/check_box.h"
|
||||||
|
#include "scene/gui/popup_menu.h"
|
||||||
|
#include "scene/gui/spin_box.h"
|
||||||
|
|
||||||
|
void Particles2DEditorPlugin::edit(Object *p_object) {
|
||||||
|
particles = Object::cast_to<Particles2D>(p_object);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Particles2DEditorPlugin::handles(Object *p_object) const {
|
||||||
|
return p_object->is_class("Particles2D");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles2DEditorPlugin::make_visible(bool p_visible) {
|
||||||
|
if (p_visible) {
|
||||||
|
toolbar->show();
|
||||||
|
} else {
|
||||||
|
toolbar->hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles2DEditorPlugin::_file_selected(const String &p_file) {
|
||||||
|
source_emission_file = p_file;
|
||||||
|
emission_mask->popup_centered_minsize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles2DEditorPlugin::_selection_changed() {
|
||||||
|
List<Node *> selected_nodes = editor->get_editor_selection()->get_selected_node_list();
|
||||||
|
|
||||||
|
if (selected_particles.empty() && selected_nodes.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < selected_particles.size(); i++) {
|
||||||
|
selected_particles[i]->set_show_visibility_rect(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
selected_particles.clear();
|
||||||
|
|
||||||
|
for (int i = 0; i < selected_nodes.size(); i++) {
|
||||||
|
Particles2D *selected_particle = Object::cast_to<Particles2D>(selected_nodes[i]);
|
||||||
|
if (selected_particle != nullptr) {
|
||||||
|
selected_particle->set_show_visibility_rect(true);
|
||||||
|
selected_particles.push_back(selected_particle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles2DEditorPlugin::_menu_callback(int p_idx) {
|
||||||
|
switch (p_idx) {
|
||||||
|
case MENU_GENERATE_VISIBILITY_RECT: {
|
||||||
|
// Add one second to the default generation lifetime, since the progress is updated every second.
|
||||||
|
generate_seconds->set_value(MAX(1.0, trunc(particles->get_lifetime()) + 1.0));
|
||||||
|
|
||||||
|
if (generate_seconds->get_value() >= 11.0 + CMP_EPSILON) {
|
||||||
|
// Only pop up the time dialog if the particle's lifetime is long enough to warrant shortening it.
|
||||||
|
generate_visibility_rect->popup_centered_minsize();
|
||||||
|
} else {
|
||||||
|
// Generate the visibility rect immediately.
|
||||||
|
_generate_visibility_rect();
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case MENU_LOAD_EMISSION_MASK: {
|
||||||
|
file->popup_centered_ratio();
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case MENU_CLEAR_EMISSION_MASK: {
|
||||||
|
emission_mask->popup_centered_minsize();
|
||||||
|
} break;
|
||||||
|
case MENU_OPTION_CONVERT_TO_CPU_PARTICLES: {
|
||||||
|
CPUParticles2D *cpu_particles = memnew(CPUParticles2D);
|
||||||
|
//TODO
|
||||||
|
//cpu_particles->convert_from_particles(particles);
|
||||||
|
cpu_particles->set_name(particles->get_name());
|
||||||
|
cpu_particles->set_transform(particles->get_transform());
|
||||||
|
cpu_particles->set_visible(particles->is_visible());
|
||||||
|
cpu_particles->set_pause_mode(particles->get_pause_mode());
|
||||||
|
cpu_particles->set_z_index(particles->get_z_index());
|
||||||
|
|
||||||
|
UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
|
||||||
|
ur->create_action(TTR("Convert to CPUParticles"));
|
||||||
|
ur->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", particles, cpu_particles, true, false);
|
||||||
|
ur->add_do_reference(cpu_particles);
|
||||||
|
ur->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", cpu_particles, particles, false, false);
|
||||||
|
ur->add_undo_reference(particles);
|
||||||
|
ur->commit_action();
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case MENU_RESTART: {
|
||||||
|
particles->restart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles2DEditorPlugin::_generate_visibility_rect() {
|
||||||
|
float time = generate_seconds->get_value();
|
||||||
|
|
||||||
|
float running = 0.0;
|
||||||
|
|
||||||
|
EditorProgress ep("gen_vrect", TTR("Generating Visibility Rect (Waiting for Particle Simulation)"), int(time));
|
||||||
|
|
||||||
|
bool was_emitting = particles->is_emitting();
|
||||||
|
if (!was_emitting) {
|
||||||
|
particles->set_emitting(true);
|
||||||
|
OS::get_singleton()->delay_usec(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect2 rect;
|
||||||
|
while (running < time) {
|
||||||
|
uint64_t ticks = OS::get_singleton()->get_ticks_usec();
|
||||||
|
ep.step("Generating...", int(running), true);
|
||||||
|
OS::get_singleton()->delay_usec(1000);
|
||||||
|
|
||||||
|
Rect2 capture = particles->capture_rect();
|
||||||
|
if (rect == Rect2()) {
|
||||||
|
rect = capture;
|
||||||
|
} else {
|
||||||
|
rect = rect.merge(capture);
|
||||||
|
}
|
||||||
|
|
||||||
|
running += (OS::get_singleton()->get_ticks_usec() - ticks) / 1000000.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!was_emitting) {
|
||||||
|
particles->set_emitting(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
undo_redo->create_action(TTR("Generate Visibility Rect"));
|
||||||
|
undo_redo->add_do_method(particles, "set_visibility_rect", rect);
|
||||||
|
undo_redo->add_undo_method(particles, "set_visibility_rect", particles->get_visibility_rect());
|
||||||
|
undo_redo->commit_action();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles2DEditorPlugin::_generate_emission_mask() {
|
||||||
|
Ref<ParticlesMaterial> pm = particles->get_process_material();
|
||||||
|
if (!pm.is_valid()) {
|
||||||
|
EditorNode::get_singleton()->show_warning(TTR("Can only set point into a ParticlesMaterial process material"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<Image> img;
|
||||||
|
img.instance();
|
||||||
|
Error err = ImageLoader::load_image(source_emission_file, img);
|
||||||
|
ERR_FAIL_COND_MSG(err != OK, "Error loading image '" + source_emission_file + "'.");
|
||||||
|
|
||||||
|
if (img->is_compressed()) {
|
||||||
|
img->decompress();
|
||||||
|
}
|
||||||
|
img->convert(Image::FORMAT_RGBA8);
|
||||||
|
ERR_FAIL_COND(img->get_format() != Image::FORMAT_RGBA8);
|
||||||
|
Size2i s = Size2(img->get_width(), img->get_height());
|
||||||
|
ERR_FAIL_COND(s.width == 0 || s.height == 0);
|
||||||
|
|
||||||
|
Vector<Point2> valid_positions;
|
||||||
|
Vector<Point2> valid_normals;
|
||||||
|
Vector<uint8_t> valid_colors;
|
||||||
|
|
||||||
|
valid_positions.resize(s.width * s.height);
|
||||||
|
|
||||||
|
EmissionMode emode = (EmissionMode)emission_mask_mode->get_selected();
|
||||||
|
|
||||||
|
if (emode == EMISSION_MODE_BORDER_DIRECTED) {
|
||||||
|
valid_normals.resize(s.width * s.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool capture_colors = emission_colors->is_pressed();
|
||||||
|
|
||||||
|
if (capture_colors) {
|
||||||
|
valid_colors.resize(s.width * s.height * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
int vpc = 0;
|
||||||
|
|
||||||
|
{
|
||||||
|
PoolVector<uint8_t> data = img->get_data();
|
||||||
|
PoolVector<uint8_t>::Read r = data.read();
|
||||||
|
|
||||||
|
for (int i = 0; i < s.width; i++) {
|
||||||
|
for (int j = 0; j < s.height; j++) {
|
||||||
|
uint8_t a = r[(j * s.width + i) * 4 + 3];
|
||||||
|
|
||||||
|
if (a > 128) {
|
||||||
|
if (emode == EMISSION_MODE_SOLID) {
|
||||||
|
if (capture_colors) {
|
||||||
|
valid_colors.write[vpc * 4 + 0] = r[(j * s.width + i) * 4 + 0];
|
||||||
|
valid_colors.write[vpc * 4 + 1] = r[(j * s.width + i) * 4 + 1];
|
||||||
|
valid_colors.write[vpc * 4 + 2] = r[(j * s.width + i) * 4 + 2];
|
||||||
|
valid_colors.write[vpc * 4 + 3] = r[(j * s.width + i) * 4 + 3];
|
||||||
|
}
|
||||||
|
valid_positions.write[vpc++] = Point2(i, j);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
bool on_border = false;
|
||||||
|
for (int x = i - 1; x <= i + 1; x++) {
|
||||||
|
for (int y = j - 1; y <= j + 1; y++) {
|
||||||
|
if (x < 0 || y < 0 || x >= s.width || y >= s.height || r[(y * s.width + x) * 4 + 3] <= 128) {
|
||||||
|
on_border = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (on_border) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (on_border) {
|
||||||
|
valid_positions.write[vpc] = Point2(i, j);
|
||||||
|
|
||||||
|
if (emode == EMISSION_MODE_BORDER_DIRECTED) {
|
||||||
|
Vector2 normal;
|
||||||
|
for (int x = i - 2; x <= i + 2; x++) {
|
||||||
|
for (int y = j - 2; y <= j + 2; y++) {
|
||||||
|
if (x == i && y == j) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x < 0 || y < 0 || x >= s.width || y >= s.height || r[(y * s.width + x) * 4 + 3] <= 128) {
|
||||||
|
normal += Vector2(x - i, y - j).normalized();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
normal.normalize();
|
||||||
|
valid_normals.write[vpc] = normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (capture_colors) {
|
||||||
|
valid_colors.write[vpc * 4 + 0] = r[(j * s.width + i) * 4 + 0];
|
||||||
|
valid_colors.write[vpc * 4 + 1] = r[(j * s.width + i) * 4 + 1];
|
||||||
|
valid_colors.write[vpc * 4 + 2] = r[(j * s.width + i) * 4 + 2];
|
||||||
|
valid_colors.write[vpc * 4 + 3] = r[(j * s.width + i) * 4 + 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
vpc++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
valid_positions.resize(vpc);
|
||||||
|
if (valid_normals.size()) {
|
||||||
|
valid_normals.resize(vpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERR_FAIL_COND_MSG(valid_positions.size() == 0, "No pixels with transparency > 128 in image...");
|
||||||
|
|
||||||
|
PoolVector<uint8_t> texdata;
|
||||||
|
|
||||||
|
int w = 2048;
|
||||||
|
int h = (vpc / 2048) + 1;
|
||||||
|
|
||||||
|
texdata.resize(w * h * 2 * sizeof(float));
|
||||||
|
|
||||||
|
{
|
||||||
|
PoolVector<uint8_t>::Write tw = texdata.write();
|
||||||
|
float *twf = (float *)tw.ptr();
|
||||||
|
for (int i = 0; i < vpc; i++) {
|
||||||
|
twf[i * 2 + 0] = valid_positions[i].x;
|
||||||
|
twf[i * 2 + 1] = valid_positions[i].y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
img.instance();
|
||||||
|
img->create(w, h, false, Image::FORMAT_RGF, texdata);
|
||||||
|
|
||||||
|
Ref<ImageTexture> imgt;
|
||||||
|
imgt.instance();
|
||||||
|
imgt->create_from_image(img, 0);
|
||||||
|
|
||||||
|
pm->set_emission_point_texture(imgt);
|
||||||
|
pm->set_emission_point_count(vpc);
|
||||||
|
|
||||||
|
if (capture_colors) {
|
||||||
|
PoolVector<uint8_t> colordata;
|
||||||
|
colordata.resize(w * h * 4); //use RG texture
|
||||||
|
|
||||||
|
{
|
||||||
|
PoolVector<uint8_t>::Write tw = colordata.write();
|
||||||
|
for (int i = 0; i < vpc * 4; i++) {
|
||||||
|
tw[i] = valid_colors[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
img.instance();
|
||||||
|
img->create(w, h, false, Image::FORMAT_RGBA8, colordata);
|
||||||
|
|
||||||
|
imgt.instance();
|
||||||
|
imgt->create_from_image(img, 0);
|
||||||
|
pm->set_emission_color_texture(imgt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valid_normals.size()) {
|
||||||
|
pm->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_DIRECTED_POINTS);
|
||||||
|
|
||||||
|
PoolVector<uint8_t> normdata;
|
||||||
|
normdata.resize(w * h * 2 * sizeof(float)); //use RG texture
|
||||||
|
|
||||||
|
{
|
||||||
|
PoolVector<uint8_t>::Write tw = normdata.write();
|
||||||
|
float *twf = (float *)tw.ptr();
|
||||||
|
for (int i = 0; i < vpc; i++) {
|
||||||
|
twf[i * 2 + 0] = valid_normals[i].x;
|
||||||
|
twf[i * 2 + 1] = valid_normals[i].y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
img.instance();
|
||||||
|
img->create(w, h, false, Image::FORMAT_RGF, normdata);
|
||||||
|
|
||||||
|
imgt.instance();
|
||||||
|
imgt->create_from_image(img, 0);
|
||||||
|
pm->set_emission_normal_texture(imgt);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
pm->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_POINTS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles2DEditorPlugin::_notification(int p_what) {
|
||||||
|
if (p_what == NOTIFICATION_ENTER_TREE) {
|
||||||
|
menu->get_popup()->connect("id_pressed", this, "_menu_callback");
|
||||||
|
menu->set_icon(menu->get_popup()->get_theme_icon("Particles2D", "EditorIcons"));
|
||||||
|
file->connect("file_selected", this, "_file_selected");
|
||||||
|
EditorNode::get_singleton()->get_editor_selection()->connect("selection_changed", this, "_selection_changed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles2DEditorPlugin::_bind_methods() {
|
||||||
|
ClassDB::bind_method(D_METHOD("_menu_callback"), &Particles2DEditorPlugin::_menu_callback);
|
||||||
|
ClassDB::bind_method(D_METHOD("_file_selected"), &Particles2DEditorPlugin::_file_selected);
|
||||||
|
ClassDB::bind_method(D_METHOD("_selection_changed"), &Particles2DEditorPlugin::_selection_changed);
|
||||||
|
ClassDB::bind_method(D_METHOD("_generate_visibility_rect"), &Particles2DEditorPlugin::_generate_visibility_rect);
|
||||||
|
ClassDB::bind_method(D_METHOD("_generate_emission_mask"), &Particles2DEditorPlugin::_generate_emission_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
Particles2DEditorPlugin::Particles2DEditorPlugin(EditorNode *p_node) {
|
||||||
|
particles = nullptr;
|
||||||
|
editor = p_node;
|
||||||
|
undo_redo = editor->get_undo_redo();
|
||||||
|
|
||||||
|
toolbar = memnew(HBoxContainer);
|
||||||
|
add_control_to_container(CONTAINER_CANVAS_EDITOR_MENU, toolbar);
|
||||||
|
toolbar->hide();
|
||||||
|
|
||||||
|
toolbar->add_child(memnew(VSeparator));
|
||||||
|
|
||||||
|
menu = memnew(MenuButton);
|
||||||
|
menu->get_popup()->add_item(TTR("Generate Visibility Rect"), MENU_GENERATE_VISIBILITY_RECT);
|
||||||
|
menu->get_popup()->add_separator();
|
||||||
|
menu->get_popup()->add_item(TTR("Load Emission Mask"), MENU_LOAD_EMISSION_MASK);
|
||||||
|
// menu->get_popup()->add_item(TTR("Clear Emission Mask"), MENU_CLEAR_EMISSION_MASK);
|
||||||
|
menu->get_popup()->add_separator();
|
||||||
|
menu->get_popup()->add_item(TTR("Convert to CPUParticles2D"), MENU_OPTION_CONVERT_TO_CPU_PARTICLES);
|
||||||
|
menu->get_popup()->add_separator();
|
||||||
|
menu->get_popup()->add_item(TTR("Restart"), MENU_RESTART);
|
||||||
|
menu->set_text(TTR("Particles"));
|
||||||
|
menu->set_switch_on_hover(true);
|
||||||
|
toolbar->add_child(menu);
|
||||||
|
|
||||||
|
file = memnew(EditorFileDialog);
|
||||||
|
List<String> ext;
|
||||||
|
ImageLoader::get_recognized_extensions(&ext);
|
||||||
|
for (List<String>::Element *E = ext.front(); E; E = E->next()) {
|
||||||
|
file->add_filter("*." + E->get() + "; " + E->get().to_upper());
|
||||||
|
}
|
||||||
|
file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
|
||||||
|
toolbar->add_child(file);
|
||||||
|
|
||||||
|
epoints = memnew(SpinBox);
|
||||||
|
epoints->set_min(1);
|
||||||
|
epoints->set_max(8192);
|
||||||
|
epoints->set_step(1);
|
||||||
|
epoints->set_value(512);
|
||||||
|
file->get_vbox()->add_margin_child(TTR("Generated Point Count:"), epoints);
|
||||||
|
|
||||||
|
generate_visibility_rect = memnew(ConfirmationDialog);
|
||||||
|
generate_visibility_rect->set_title(TTR("Generate Visibility Rect"));
|
||||||
|
VBoxContainer *genvb = memnew(VBoxContainer);
|
||||||
|
generate_visibility_rect->add_child(genvb);
|
||||||
|
generate_seconds = memnew(SpinBox);
|
||||||
|
genvb->add_margin_child(TTR("Generation Time (sec):"), generate_seconds);
|
||||||
|
generate_seconds->set_min(0.1);
|
||||||
|
generate_seconds->set_max(25);
|
||||||
|
generate_seconds->set_value(2);
|
||||||
|
|
||||||
|
toolbar->add_child(generate_visibility_rect);
|
||||||
|
|
||||||
|
generate_visibility_rect->connect("confirmed", this, "_generate_visibility_rect");
|
||||||
|
|
||||||
|
emission_mask = memnew(ConfirmationDialog);
|
||||||
|
emission_mask->set_title(TTR("Load Emission Mask"));
|
||||||
|
VBoxContainer *emvb = memnew(VBoxContainer);
|
||||||
|
emission_mask->add_child(emvb);
|
||||||
|
emission_mask_mode = memnew(OptionButton);
|
||||||
|
emvb->add_margin_child(TTR("Emission Mask"), emission_mask_mode);
|
||||||
|
emission_mask_mode->add_item(TTR("Solid Pixels"), EMISSION_MODE_SOLID);
|
||||||
|
emission_mask_mode->add_item(TTR("Border Pixels"), EMISSION_MODE_BORDER);
|
||||||
|
emission_mask_mode->add_item(TTR("Directed Border Pixels"), EMISSION_MODE_BORDER_DIRECTED);
|
||||||
|
emission_colors = memnew(CheckBox);
|
||||||
|
emission_colors->set_text(TTR("Capture from Pixel"));
|
||||||
|
emvb->add_margin_child(TTR("Emission Colors"), emission_colors);
|
||||||
|
|
||||||
|
toolbar->add_child(emission_mask);
|
||||||
|
|
||||||
|
emission_mask->connect("confirmed", this, "_generate_emission_mask");
|
||||||
|
}
|
||||||
|
|
||||||
|
Particles2DEditorPlugin::~Particles2DEditorPlugin() {
|
||||||
|
}
|
102
editor/plugins/particles_2d_editor_plugin.h
Normal file
102
editor/plugins/particles_2d_editor_plugin.h
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
/**************************************************************************/
|
||||||
|
/* particles_2d_editor_plugin.h */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||||
|
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#ifndef PARTICLES_2D_EDITOR_PLUGIN_H
|
||||||
|
#define PARTICLES_2D_EDITOR_PLUGIN_H
|
||||||
|
|
||||||
|
#include "editor/editor_node.h"
|
||||||
|
#include "editor/editor_plugin.h"
|
||||||
|
#include "scene/2d/collision_polygon_2d.h"
|
||||||
|
|
||||||
|
class SpinBox;
|
||||||
|
class EditorFileDialog;
|
||||||
|
class Particles2D;
|
||||||
|
|
||||||
|
class Particles2DEditorPlugin : public EditorPlugin {
|
||||||
|
GDCLASS(Particles2DEditorPlugin, EditorPlugin);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
|
||||||
|
MENU_GENERATE_VISIBILITY_RECT,
|
||||||
|
MENU_LOAD_EMISSION_MASK,
|
||||||
|
MENU_CLEAR_EMISSION_MASK,
|
||||||
|
MENU_OPTION_CONVERT_TO_CPU_PARTICLES,
|
||||||
|
MENU_RESTART
|
||||||
|
};
|
||||||
|
|
||||||
|
enum EmissionMode {
|
||||||
|
EMISSION_MODE_SOLID,
|
||||||
|
EMISSION_MODE_BORDER,
|
||||||
|
EMISSION_MODE_BORDER_DIRECTED
|
||||||
|
};
|
||||||
|
|
||||||
|
Particles2D *particles;
|
||||||
|
List<Particles2D *> selected_particles;
|
||||||
|
|
||||||
|
EditorFileDialog *file;
|
||||||
|
EditorNode *editor;
|
||||||
|
|
||||||
|
HBoxContainer *toolbar;
|
||||||
|
MenuButton *menu;
|
||||||
|
|
||||||
|
SpinBox *epoints;
|
||||||
|
|
||||||
|
ConfirmationDialog *generate_visibility_rect;
|
||||||
|
SpinBox *generate_seconds;
|
||||||
|
|
||||||
|
ConfirmationDialog *emission_mask;
|
||||||
|
OptionButton *emission_mask_mode;
|
||||||
|
CheckBox *emission_colors;
|
||||||
|
|
||||||
|
String source_emission_file;
|
||||||
|
|
||||||
|
UndoRedo *undo_redo;
|
||||||
|
void _file_selected(const String &p_file);
|
||||||
|
void _menu_callback(int p_idx);
|
||||||
|
void _generate_visibility_rect();
|
||||||
|
void _generate_emission_mask();
|
||||||
|
void _selection_changed();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void _notification(int p_what);
|
||||||
|
static void _bind_methods();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual String get_name() const { return "Particles2D"; }
|
||||||
|
bool has_main_screen() const { return false; }
|
||||||
|
virtual void edit(Object *p_object);
|
||||||
|
virtual bool handles(Object *p_object) const;
|
||||||
|
virtual void make_visible(bool p_visible);
|
||||||
|
|
||||||
|
Particles2DEditorPlugin(EditorNode *p_node);
|
||||||
|
~Particles2DEditorPlugin();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PARTICLES_2D_EDITOR_PLUGIN_H
|
468
scene/2d/particles_2d.cpp
Normal file
468
scene/2d/particles_2d.cpp
Normal file
@ -0,0 +1,468 @@
|
|||||||
|
/**************************************************************************/
|
||||||
|
/* particles_2d.cpp */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||||
|
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#include "particles_2d.h"
|
||||||
|
|
||||||
|
#include "core/os/os.h"
|
||||||
|
#include "scene/resources/material/particles_material.h"
|
||||||
|
#include "scene/main/scene_string_names.h"
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
#include "core/config/engine.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void Particles2D::set_emitting(bool p_emitting) {
|
||||||
|
// Do not return even if `p_emitting == emitting` because `emitting` is just an approximation.
|
||||||
|
|
||||||
|
if (p_emitting && one_shot) {
|
||||||
|
if (!active && !emitting) {
|
||||||
|
// Last cycle ended.
|
||||||
|
active = true;
|
||||||
|
time = 0;
|
||||||
|
signal_canceled = false;
|
||||||
|
emission_time = lifetime;
|
||||||
|
active_time = lifetime * (2 - explosiveness_ratio);
|
||||||
|
} else {
|
||||||
|
signal_canceled = true;
|
||||||
|
}
|
||||||
|
set_process_internal(true);
|
||||||
|
} else if (!p_emitting) {
|
||||||
|
if (one_shot) {
|
||||||
|
set_process_internal(true);
|
||||||
|
} else {
|
||||||
|
set_process_internal(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emitting = p_emitting;
|
||||||
|
RS::get_singleton()->particles_set_emitting(particles, p_emitting);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles2D::set_amount(int p_amount) {
|
||||||
|
ERR_FAIL_COND_MSG(p_amount < 1, "Amount of particles cannot be smaller than 1.");
|
||||||
|
amount = p_amount;
|
||||||
|
RS::get_singleton()->particles_set_amount(particles, amount);
|
||||||
|
}
|
||||||
|
void Particles2D::set_lifetime(float p_lifetime) {
|
||||||
|
ERR_FAIL_COND_MSG(p_lifetime <= 0, "Particles lifetime must be greater than 0.");
|
||||||
|
lifetime = p_lifetime;
|
||||||
|
RS::get_singleton()->particles_set_lifetime(particles, lifetime);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles2D::set_one_shot(bool p_enable) {
|
||||||
|
one_shot = p_enable;
|
||||||
|
RS::get_singleton()->particles_set_one_shot(particles, one_shot);
|
||||||
|
|
||||||
|
if (is_emitting()) {
|
||||||
|
set_process_internal(true);
|
||||||
|
if (!one_shot) {
|
||||||
|
RenderingServer::get_singleton()->particles_restart(particles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!one_shot) {
|
||||||
|
set_process_internal(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Particles2D::set_pre_process_time(float p_time) {
|
||||||
|
pre_process_time = p_time;
|
||||||
|
RS::get_singleton()->particles_set_pre_process_time(particles, pre_process_time);
|
||||||
|
}
|
||||||
|
void Particles2D::set_explosiveness_ratio(float p_ratio) {
|
||||||
|
explosiveness_ratio = p_ratio;
|
||||||
|
RS::get_singleton()->particles_set_explosiveness_ratio(particles, explosiveness_ratio);
|
||||||
|
}
|
||||||
|
void Particles2D::set_randomness_ratio(float p_ratio) {
|
||||||
|
randomness_ratio = p_ratio;
|
||||||
|
RS::get_singleton()->particles_set_randomness_ratio(particles, randomness_ratio);
|
||||||
|
}
|
||||||
|
void Particles2D::set_visibility_rect(const Rect2 &p_visibility_rect) {
|
||||||
|
visibility_rect = p_visibility_rect;
|
||||||
|
AABB aabb;
|
||||||
|
aabb.position.x = p_visibility_rect.position.x;
|
||||||
|
aabb.position.y = p_visibility_rect.position.y;
|
||||||
|
aabb.size.x = p_visibility_rect.size.x;
|
||||||
|
aabb.size.y = p_visibility_rect.size.y;
|
||||||
|
|
||||||
|
RS::get_singleton()->particles_set_custom_aabb(particles, aabb);
|
||||||
|
|
||||||
|
_change_notify("visibility_rect");
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
void Particles2D::set_use_local_coordinates(bool p_enable) {
|
||||||
|
local_coords = p_enable;
|
||||||
|
RS::get_singleton()->particles_set_use_local_coordinates(particles, local_coords);
|
||||||
|
set_notify_transform(!p_enable);
|
||||||
|
if (!p_enable && is_inside_tree()) {
|
||||||
|
_update_particle_emission_transform();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles2D::_update_particle_emission_transform() {
|
||||||
|
Transform2D xf2d = get_global_transform();
|
||||||
|
Transform xf;
|
||||||
|
xf.basis.set_axis(0, Vector3(xf2d.get_axis(0).x, xf2d.get_axis(0).y, 0));
|
||||||
|
xf.basis.set_axis(1, Vector3(xf2d.get_axis(1).x, xf2d.get_axis(1).y, 0));
|
||||||
|
xf.set_origin(Vector3(xf2d.get_origin().x, xf2d.get_origin().y, 0));
|
||||||
|
|
||||||
|
RS::get_singleton()->particles_set_emission_transform(particles, xf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles2D::set_process_material(const Ref<Material> &p_material) {
|
||||||
|
process_material = p_material;
|
||||||
|
Ref<ParticlesMaterial> pm = p_material;
|
||||||
|
if (pm.is_valid() && !pm->get_flag(ParticlesMaterial::FLAG_DISABLE_Z) && pm->get_gravity() == Vector3(0, -9.8, 0)) {
|
||||||
|
// Likely a new (3D) material, modify it to match 2D space
|
||||||
|
pm->set_flag(ParticlesMaterial::FLAG_DISABLE_Z, true);
|
||||||
|
pm->set_gravity(Vector3(0, 98, 0));
|
||||||
|
}
|
||||||
|
RID material_rid;
|
||||||
|
if (process_material.is_valid()) {
|
||||||
|
material_rid = process_material->get_rid();
|
||||||
|
}
|
||||||
|
RS::get_singleton()->particles_set_process_material(particles, material_rid);
|
||||||
|
|
||||||
|
update_configuration_warning();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles2D::set_speed_scale(float p_scale) {
|
||||||
|
speed_scale = p_scale;
|
||||||
|
RS::get_singleton()->particles_set_speed_scale(particles, p_scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
void Particles2D::set_show_visibility_rect(bool p_show_visibility_rect) {
|
||||||
|
show_visibility_rect = p_show_visibility_rect;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool Particles2D::is_emitting() const {
|
||||||
|
return emitting;
|
||||||
|
}
|
||||||
|
int Particles2D::get_amount() const {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
float Particles2D::get_lifetime() const {
|
||||||
|
return lifetime;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Particles2D::get_one_shot() const {
|
||||||
|
return one_shot;
|
||||||
|
}
|
||||||
|
float Particles2D::get_pre_process_time() const {
|
||||||
|
return pre_process_time;
|
||||||
|
}
|
||||||
|
float Particles2D::get_explosiveness_ratio() const {
|
||||||
|
return explosiveness_ratio;
|
||||||
|
}
|
||||||
|
float Particles2D::get_randomness_ratio() const {
|
||||||
|
return randomness_ratio;
|
||||||
|
}
|
||||||
|
Rect2 Particles2D::get_visibility_rect() const {
|
||||||
|
return visibility_rect;
|
||||||
|
}
|
||||||
|
bool Particles2D::get_use_local_coordinates() const {
|
||||||
|
return local_coords;
|
||||||
|
}
|
||||||
|
Ref<Material> Particles2D::get_process_material() const {
|
||||||
|
return process_material;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Particles2D::get_speed_scale() const {
|
||||||
|
return speed_scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles2D::set_draw_order(DrawOrder p_order) {
|
||||||
|
draw_order = p_order;
|
||||||
|
RS::get_singleton()->particles_set_draw_order(particles, RS::ParticlesDrawOrder(p_order));
|
||||||
|
}
|
||||||
|
|
||||||
|
Particles2D::DrawOrder Particles2D::get_draw_order() const {
|
||||||
|
return draw_order;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles2D::set_fixed_fps(int p_count) {
|
||||||
|
fixed_fps = p_count;
|
||||||
|
RS::get_singleton()->particles_set_fixed_fps(particles, p_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Particles2D::get_fixed_fps() const {
|
||||||
|
return fixed_fps;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles2D::set_fractional_delta(bool p_enable) {
|
||||||
|
fractional_delta = p_enable;
|
||||||
|
RS::get_singleton()->particles_set_fractional_delta(particles, p_enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Particles2D::get_fractional_delta() const {
|
||||||
|
return fractional_delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
String Particles2D::get_configuration_warning() const {
|
||||||
|
String warning = Node2D::get_configuration_warning();
|
||||||
|
|
||||||
|
if (OS::get_singleton()->get_current_video_driver() == OS::VIDEO_DRIVER_GLES2) {
|
||||||
|
if (warning != String()) {
|
||||||
|
warning += "\n\n";
|
||||||
|
}
|
||||||
|
warning += "- " + TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles2D node instead. You can use the \"Convert to CPUParticles2D\" toolbar option for this purpose.");
|
||||||
|
return warning;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef OSX_ENABLED
|
||||||
|
if (warning != String()) {
|
||||||
|
warning += "\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
warning += "- " + TTR("On macOS, Particles2D rendering is much slower than CPUParticles2D due to transform feedback being implemented on the CPU instead of the GPU.\nConsider using CPUParticles2D instead when targeting macOS.\nYou can use the \"Convert to CPUParticles2D\" toolbar option for this purpose.");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (process_material.is_null()) {
|
||||||
|
if (warning != String()) {
|
||||||
|
warning += "\n\n";
|
||||||
|
}
|
||||||
|
warning += "- " + TTR("A material to process the particles is not assigned, so no behavior is imprinted.");
|
||||||
|
} else {
|
||||||
|
CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr());
|
||||||
|
|
||||||
|
if (get_material().is_null() || (mat && !mat->get_particles_animation())) {
|
||||||
|
const ParticlesMaterial *process = Object::cast_to<ParticlesMaterial>(process_material.ptr());
|
||||||
|
if (process &&
|
||||||
|
(process->get_param(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 ||
|
||||||
|
process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) {
|
||||||
|
if (warning != String()) {
|
||||||
|
warning += "\n\n";
|
||||||
|
}
|
||||||
|
warning += "- " + TTR("Particles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return warning;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect2 Particles2D::capture_rect() const {
|
||||||
|
AABB aabb = RS::get_singleton()->particles_get_current_aabb(particles);
|
||||||
|
Rect2 r;
|
||||||
|
r.position.x = aabb.position.x;
|
||||||
|
r.position.y = aabb.position.y;
|
||||||
|
r.size.x = aabb.size.x;
|
||||||
|
r.size.y = aabb.size.y;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles2D::set_texture(const Ref<Texture> &p_texture) {
|
||||||
|
texture = p_texture;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<Texture> Particles2D::get_texture() const {
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles2D::set_normal_map(const Ref<Texture> &p_normal_map) {
|
||||||
|
normal_map = p_normal_map;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<Texture> Particles2D::get_normal_map() const {
|
||||||
|
return normal_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles2D::_validate_property(PropertyInfo &property) const {
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles2D::restart() {
|
||||||
|
RS::get_singleton()->particles_restart(particles);
|
||||||
|
RS::get_singleton()->particles_set_emitting(particles, true);
|
||||||
|
|
||||||
|
emitting = true;
|
||||||
|
active = true;
|
||||||
|
signal_canceled = false;
|
||||||
|
time = 0;
|
||||||
|
emission_time = lifetime;
|
||||||
|
active_time = lifetime * (2 - explosiveness_ratio);
|
||||||
|
if (one_shot) {
|
||||||
|
set_process_internal(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles2D::_notification(int p_what) {
|
||||||
|
if (p_what == NOTIFICATION_DRAW) {
|
||||||
|
RID texture_rid;
|
||||||
|
if (texture.is_valid()) {
|
||||||
|
texture_rid = texture->get_rid();
|
||||||
|
}
|
||||||
|
RID normal_rid;
|
||||||
|
if (normal_map.is_valid()) {
|
||||||
|
normal_rid = normal_map->get_rid();
|
||||||
|
}
|
||||||
|
|
||||||
|
RS::get_singleton()->canvas_item_add_particles(get_canvas_item(), particles, texture_rid, normal_rid);
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
if (show_visibility_rect) {
|
||||||
|
draw_rect(visibility_rect, Color(0, 0.7, 0.9, 0.4), false);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_what == NOTIFICATION_PAUSED || p_what == NOTIFICATION_UNPAUSED) {
|
||||||
|
if (can_process()) {
|
||||||
|
RS::get_singleton()->particles_set_speed_scale(particles, speed_scale);
|
||||||
|
} else {
|
||||||
|
RS::get_singleton()->particles_set_speed_scale(particles, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
|
||||||
|
_update_particle_emission_transform();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
|
||||||
|
if (one_shot) {
|
||||||
|
time += get_process_delta_time();
|
||||||
|
if (time > emission_time) {
|
||||||
|
emitting = false;
|
||||||
|
if (!active) {
|
||||||
|
set_process_internal(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (time > active_time) {
|
||||||
|
if (active && !signal_canceled) {
|
||||||
|
emit_signal(SceneStringNames::get_singleton()->finished);
|
||||||
|
}
|
||||||
|
active = false;
|
||||||
|
if (!emitting) {
|
||||||
|
set_process_internal(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles2D::_bind_methods() {
|
||||||
|
ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &Particles2D::set_emitting);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_amount", "amount"), &Particles2D::set_amount);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_lifetime", "secs"), &Particles2D::set_lifetime);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_one_shot", "secs"), &Particles2D::set_one_shot);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &Particles2D::set_pre_process_time);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &Particles2D::set_explosiveness_ratio);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &Particles2D::set_randomness_ratio);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_visibility_rect", "visibility_rect"), &Particles2D::set_visibility_rect);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_use_local_coordinates", "enable"), &Particles2D::set_use_local_coordinates);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_fixed_fps", "fps"), &Particles2D::set_fixed_fps);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &Particles2D::set_fractional_delta);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_process_material", "material"), &Particles2D::set_process_material);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &Particles2D::set_speed_scale);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("is_emitting"), &Particles2D::is_emitting);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_amount"), &Particles2D::get_amount);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_lifetime"), &Particles2D::get_lifetime);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_one_shot"), &Particles2D::get_one_shot);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_pre_process_time"), &Particles2D::get_pre_process_time);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_explosiveness_ratio"), &Particles2D::get_explosiveness_ratio);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_randomness_ratio"), &Particles2D::get_randomness_ratio);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_visibility_rect"), &Particles2D::get_visibility_rect);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_use_local_coordinates"), &Particles2D::get_use_local_coordinates);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_fixed_fps"), &Particles2D::get_fixed_fps);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_fractional_delta"), &Particles2D::get_fractional_delta);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_process_material"), &Particles2D::get_process_material);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_speed_scale"), &Particles2D::get_speed_scale);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("set_draw_order", "order"), &Particles2D::set_draw_order);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_draw_order"), &Particles2D::get_draw_order);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("set_texture", "texture"), &Particles2D::set_texture);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_texture"), &Particles2D::get_texture);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("set_normal_map", "texture"), &Particles2D::set_normal_map);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_normal_map"), &Particles2D::get_normal_map);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("capture_rect"), &Particles2D::capture_rect);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("restart"), &Particles2D::restart);
|
||||||
|
|
||||||
|
ADD_SIGNAL(MethodInfo("finished"));
|
||||||
|
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount");
|
||||||
|
ADD_GROUP("Time", "");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
|
||||||
|
ADD_GROUP("Drawing", "");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::RECT2, "visibility_rect"), "set_visibility_rect", "get_visibility_rect");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime"), "set_draw_order", "get_draw_order");
|
||||||
|
ADD_GROUP("Process Material", "process_");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticlesMaterial"), "set_process_material", "get_process_material");
|
||||||
|
ADD_GROUP("Textures", "");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_normal_map", "get_normal_map");
|
||||||
|
|
||||||
|
BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX);
|
||||||
|
BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
Particles2D::Particles2D() {
|
||||||
|
particles = RID_PRIME(RS::get_singleton()->particles_create());
|
||||||
|
|
||||||
|
one_shot = false; // Needed so that set_emitting doesn't access uninitialized values
|
||||||
|
set_emitting(true);
|
||||||
|
set_one_shot(false);
|
||||||
|
set_amount(8);
|
||||||
|
set_lifetime(1);
|
||||||
|
set_fixed_fps(0);
|
||||||
|
set_fractional_delta(true);
|
||||||
|
set_pre_process_time(0);
|
||||||
|
set_explosiveness_ratio(0);
|
||||||
|
set_randomness_ratio(0);
|
||||||
|
set_visibility_rect(Rect2(Vector2(-100, -100), Vector2(200, 200)));
|
||||||
|
set_use_local_coordinates(true);
|
||||||
|
set_draw_order(DRAW_ORDER_INDEX);
|
||||||
|
set_speed_scale(1);
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
show_visibility_rect = false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
Particles2D::~Particles2D() {
|
||||||
|
if (particles.is_valid()) {
|
||||||
|
RS::get_singleton()->free(particles);
|
||||||
|
}
|
||||||
|
}
|
142
scene/2d/particles_2d.h
Normal file
142
scene/2d/particles_2d.h
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
/**************************************************************************/
|
||||||
|
/* particles_2d.h */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||||
|
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#ifndef PARTICLES_2D_H
|
||||||
|
#define PARTICLES_2D_H
|
||||||
|
|
||||||
|
#include "core/containers/rid.h"
|
||||||
|
#include "scene/main/node_2d.h"
|
||||||
|
#include "scene/resources/texture.h"
|
||||||
|
|
||||||
|
class Particles2D : public Node2D {
|
||||||
|
private:
|
||||||
|
GDCLASS(Particles2D, Node2D);
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum DrawOrder {
|
||||||
|
DRAW_ORDER_INDEX,
|
||||||
|
DRAW_ORDER_LIFETIME,
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
RID particles;
|
||||||
|
|
||||||
|
bool emitting = false;
|
||||||
|
bool active = false;
|
||||||
|
bool signal_canceled = false;
|
||||||
|
bool one_shot = false;
|
||||||
|
int amount;
|
||||||
|
float lifetime;
|
||||||
|
float pre_process_time;
|
||||||
|
float explosiveness_ratio;
|
||||||
|
float randomness_ratio;
|
||||||
|
float speed_scale;
|
||||||
|
Rect2 visibility_rect;
|
||||||
|
bool local_coords;
|
||||||
|
int fixed_fps;
|
||||||
|
bool fractional_delta;
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
bool show_visibility_rect;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Ref<Material> process_material;
|
||||||
|
|
||||||
|
DrawOrder draw_order;
|
||||||
|
|
||||||
|
Ref<Texture> texture;
|
||||||
|
Ref<Texture> normal_map;
|
||||||
|
|
||||||
|
void _update_particle_emission_transform();
|
||||||
|
|
||||||
|
double time = 0.0;
|
||||||
|
double emission_time = 0.0;
|
||||||
|
double active_time = 0.0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static void _bind_methods();
|
||||||
|
virtual void _validate_property(PropertyInfo &property) const;
|
||||||
|
void _notification(int p_what);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void set_emitting(bool p_emitting);
|
||||||
|
void set_amount(int p_amount);
|
||||||
|
void set_lifetime(float p_lifetime);
|
||||||
|
void set_one_shot(bool p_enable);
|
||||||
|
void set_pre_process_time(float p_time);
|
||||||
|
void set_explosiveness_ratio(float p_ratio);
|
||||||
|
void set_randomness_ratio(float p_ratio);
|
||||||
|
void set_visibility_rect(const Rect2 &p_visibility_rect);
|
||||||
|
void set_use_local_coordinates(bool p_enable);
|
||||||
|
void set_process_material(const Ref<Material> &p_material);
|
||||||
|
void set_speed_scale(float p_scale);
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
void set_show_visibility_rect(bool p_show_visibility_rect);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool is_emitting() const;
|
||||||
|
int get_amount() const;
|
||||||
|
float get_lifetime() const;
|
||||||
|
bool get_one_shot() const;
|
||||||
|
float get_pre_process_time() const;
|
||||||
|
float get_explosiveness_ratio() const;
|
||||||
|
float get_randomness_ratio() const;
|
||||||
|
Rect2 get_visibility_rect() const;
|
||||||
|
bool get_use_local_coordinates() const;
|
||||||
|
Ref<Material> get_process_material() const;
|
||||||
|
float get_speed_scale() const;
|
||||||
|
|
||||||
|
void set_fixed_fps(int p_count);
|
||||||
|
int get_fixed_fps() const;
|
||||||
|
|
||||||
|
void set_fractional_delta(bool p_enable);
|
||||||
|
bool get_fractional_delta() const;
|
||||||
|
|
||||||
|
void set_draw_order(DrawOrder p_order);
|
||||||
|
DrawOrder get_draw_order() const;
|
||||||
|
|
||||||
|
void set_texture(const Ref<Texture> &p_texture);
|
||||||
|
Ref<Texture> get_texture() const;
|
||||||
|
|
||||||
|
void set_normal_map(const Ref<Texture> &p_normal_map);
|
||||||
|
Ref<Texture> get_normal_map() const;
|
||||||
|
|
||||||
|
virtual String get_configuration_warning() const;
|
||||||
|
|
||||||
|
void restart();
|
||||||
|
Rect2 capture_rect() const;
|
||||||
|
Particles2D();
|
||||||
|
~Particles2D();
|
||||||
|
};
|
||||||
|
|
||||||
|
VARIANT_ENUM_CAST(Particles2D::DrawOrder)
|
||||||
|
|
||||||
|
#endif // PARTICLES_2D_H
|
470
scene/3d/particles.cpp
Normal file
470
scene/3d/particles.cpp
Normal file
@ -0,0 +1,470 @@
|
|||||||
|
/**************************************************************************/
|
||||||
|
/* particles.cpp */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||||
|
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#include "particles.h"
|
||||||
|
|
||||||
|
#include "core/os/os.h"
|
||||||
|
#include "scene/resources/material/particles_material.h"
|
||||||
|
#include "scene/resources/material/spatial_material.h"
|
||||||
|
#include "scene/resources/material/shader_material.h"
|
||||||
|
#include "scene/main/scene_string_names.h"
|
||||||
|
#include "scene/resources/mesh/mesh.h"
|
||||||
|
|
||||||
|
#include "servers/rendering_server.h"
|
||||||
|
|
||||||
|
AABB Particles::get_aabb() const {
|
||||||
|
return AABB();
|
||||||
|
}
|
||||||
|
PoolVector<Face3> Particles::get_faces(uint32_t p_usage_flags) const {
|
||||||
|
return PoolVector<Face3>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles::set_emitting(bool p_emitting) {
|
||||||
|
// Do not return even if `p_emitting == emitting` because `emitting` is just an approximation.
|
||||||
|
|
||||||
|
if (p_emitting && one_shot) {
|
||||||
|
if (!active && !emitting) {
|
||||||
|
// Last cycle ended.
|
||||||
|
active = true;
|
||||||
|
time = 0;
|
||||||
|
signal_canceled = false;
|
||||||
|
emission_time = lifetime;
|
||||||
|
active_time = lifetime * (2 - explosiveness_ratio);
|
||||||
|
} else {
|
||||||
|
signal_canceled = true;
|
||||||
|
}
|
||||||
|
set_process_internal(true);
|
||||||
|
} else if (!p_emitting) {
|
||||||
|
set_process_internal(false);
|
||||||
|
if (one_shot) {
|
||||||
|
set_process_internal(true);
|
||||||
|
} else {
|
||||||
|
set_process_internal(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emitting = p_emitting;
|
||||||
|
RS::get_singleton()->particles_set_emitting(particles, p_emitting);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles::set_amount(int p_amount) {
|
||||||
|
ERR_FAIL_COND_MSG(p_amount < 1, "Amount of particles cannot be smaller than 1.");
|
||||||
|
amount = p_amount;
|
||||||
|
RS::get_singleton()->particles_set_amount(particles, amount);
|
||||||
|
}
|
||||||
|
void Particles::set_lifetime(float p_lifetime) {
|
||||||
|
ERR_FAIL_COND_MSG(p_lifetime <= 0, "Particles lifetime must be greater than 0.");
|
||||||
|
lifetime = p_lifetime;
|
||||||
|
RS::get_singleton()->particles_set_lifetime(particles, lifetime);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles::set_one_shot(bool p_one_shot) {
|
||||||
|
one_shot = p_one_shot;
|
||||||
|
RS::get_singleton()->particles_set_one_shot(particles, one_shot);
|
||||||
|
|
||||||
|
if (is_emitting()) {
|
||||||
|
set_process_internal(true);
|
||||||
|
if (!one_shot) {
|
||||||
|
RenderingServer::get_singleton()->particles_restart(particles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!one_shot) {
|
||||||
|
set_process_internal(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles::set_pre_process_time(float p_time) {
|
||||||
|
pre_process_time = p_time;
|
||||||
|
RS::get_singleton()->particles_set_pre_process_time(particles, pre_process_time);
|
||||||
|
}
|
||||||
|
void Particles::set_explosiveness_ratio(float p_ratio) {
|
||||||
|
explosiveness_ratio = p_ratio;
|
||||||
|
RS::get_singleton()->particles_set_explosiveness_ratio(particles, explosiveness_ratio);
|
||||||
|
}
|
||||||
|
void Particles::set_randomness_ratio(float p_ratio) {
|
||||||
|
randomness_ratio = p_ratio;
|
||||||
|
RS::get_singleton()->particles_set_randomness_ratio(particles, randomness_ratio);
|
||||||
|
}
|
||||||
|
void Particles::set_visibility_aabb(const AABB &p_aabb) {
|
||||||
|
visibility_aabb = p_aabb;
|
||||||
|
RS::get_singleton()->particles_set_custom_aabb(particles, visibility_aabb);
|
||||||
|
update_gizmos();
|
||||||
|
_change_notify("visibility_aabb");
|
||||||
|
}
|
||||||
|
void Particles::set_use_local_coordinates(bool p_enable) {
|
||||||
|
local_coords = p_enable;
|
||||||
|
RS::get_singleton()->particles_set_use_local_coordinates(particles, local_coords);
|
||||||
|
}
|
||||||
|
void Particles::set_process_material(const Ref<Material> &p_material) {
|
||||||
|
process_material = p_material;
|
||||||
|
RID material_rid;
|
||||||
|
if (process_material.is_valid()) {
|
||||||
|
material_rid = process_material->get_rid();
|
||||||
|
}
|
||||||
|
RS::get_singleton()->particles_set_process_material(particles, material_rid);
|
||||||
|
|
||||||
|
update_configuration_warning();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles::set_speed_scale(float p_scale) {
|
||||||
|
speed_scale = p_scale;
|
||||||
|
RS::get_singleton()->particles_set_speed_scale(particles, p_scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Particles::is_emitting() const {
|
||||||
|
return emitting;
|
||||||
|
}
|
||||||
|
int Particles::get_amount() const {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
float Particles::get_lifetime() const {
|
||||||
|
return lifetime;
|
||||||
|
}
|
||||||
|
bool Particles::get_one_shot() const {
|
||||||
|
return one_shot;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Particles::get_pre_process_time() const {
|
||||||
|
return pre_process_time;
|
||||||
|
}
|
||||||
|
float Particles::get_explosiveness_ratio() const {
|
||||||
|
return explosiveness_ratio;
|
||||||
|
}
|
||||||
|
float Particles::get_randomness_ratio() const {
|
||||||
|
return randomness_ratio;
|
||||||
|
}
|
||||||
|
AABB Particles::get_visibility_aabb() const {
|
||||||
|
return visibility_aabb;
|
||||||
|
}
|
||||||
|
bool Particles::get_use_local_coordinates() const {
|
||||||
|
return local_coords;
|
||||||
|
}
|
||||||
|
Ref<Material> Particles::get_process_material() const {
|
||||||
|
return process_material;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Particles::get_speed_scale() const {
|
||||||
|
return speed_scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles::set_draw_order(DrawOrder p_order) {
|
||||||
|
draw_order = p_order;
|
||||||
|
RS::get_singleton()->particles_set_draw_order(particles, RS::ParticlesDrawOrder(p_order));
|
||||||
|
}
|
||||||
|
|
||||||
|
Particles::DrawOrder Particles::get_draw_order() const {
|
||||||
|
return draw_order;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles::set_draw_passes(int p_count) {
|
||||||
|
ERR_FAIL_COND(p_count < 1);
|
||||||
|
draw_passes.resize(p_count);
|
||||||
|
RS::get_singleton()->particles_set_draw_passes(particles, p_count);
|
||||||
|
_change_notify();
|
||||||
|
}
|
||||||
|
int Particles::get_draw_passes() const {
|
||||||
|
return draw_passes.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles::set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh) {
|
||||||
|
ERR_FAIL_INDEX(p_pass, draw_passes.size());
|
||||||
|
|
||||||
|
draw_passes.write[p_pass] = p_mesh;
|
||||||
|
|
||||||
|
RID mesh_rid;
|
||||||
|
if (p_mesh.is_valid()) {
|
||||||
|
mesh_rid = p_mesh->get_rid();
|
||||||
|
}
|
||||||
|
|
||||||
|
RS::get_singleton()->particles_set_draw_pass_mesh(particles, p_pass, mesh_rid);
|
||||||
|
|
||||||
|
update_configuration_warning();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<Mesh> Particles::get_draw_pass_mesh(int p_pass) const {
|
||||||
|
ERR_FAIL_INDEX_V(p_pass, draw_passes.size(), Ref<Mesh>());
|
||||||
|
|
||||||
|
return draw_passes[p_pass];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles::set_fixed_fps(int p_count) {
|
||||||
|
fixed_fps = p_count;
|
||||||
|
RS::get_singleton()->particles_set_fixed_fps(particles, p_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Particles::get_fixed_fps() const {
|
||||||
|
return fixed_fps;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles::set_fractional_delta(bool p_enable) {
|
||||||
|
fractional_delta = p_enable;
|
||||||
|
RS::get_singleton()->particles_set_fractional_delta(particles, p_enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Particles::get_fractional_delta() const {
|
||||||
|
return fractional_delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
String Particles::get_configuration_warning() const {
|
||||||
|
String warnings = GeometryInstance::get_configuration_warning();
|
||||||
|
|
||||||
|
if (OS::get_singleton()->get_current_video_driver() == OS::VIDEO_DRIVER_GLES2) {
|
||||||
|
if (warnings != String()) {
|
||||||
|
warnings += "\n\n";
|
||||||
|
}
|
||||||
|
warnings += "- " + TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles node instead. You can use the \"Convert to CPUParticles\" toolbar option for this purpose.");
|
||||||
|
return warnings;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef OSX_ENABLED
|
||||||
|
if (warnings != String()) {
|
||||||
|
warnings += "\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
warnings += "- " + TTR("On macOS, Particles rendering is much slower than CPUParticles due to transform feedback being implemented on the CPU instead of the GPU.\nConsider using CPUParticles instead when targeting macOS.\nYou can use the \"Convert to CPUParticles\" toolbar option for this purpose.");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool meshes_found = false;
|
||||||
|
bool anim_material_found = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < draw_passes.size(); i++) {
|
||||||
|
if (draw_passes[i].is_valid()) {
|
||||||
|
meshes_found = true;
|
||||||
|
for (int j = 0; j < draw_passes[i]->get_surface_count(); j++) {
|
||||||
|
anim_material_found = Object::cast_to<ShaderMaterial>(draw_passes[i]->surface_get_material(j).ptr()) != nullptr;
|
||||||
|
SpatialMaterial *spat = Object::cast_to<SpatialMaterial>(draw_passes[i]->surface_get_material(j).ptr());
|
||||||
|
anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == SpatialMaterial::BILLBOARD_PARTICLES);
|
||||||
|
}
|
||||||
|
if (anim_material_found) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
anim_material_found = anim_material_found || Object::cast_to<ShaderMaterial>(get_material_override().ptr()) != nullptr;
|
||||||
|
SpatialMaterial *spat = Object::cast_to<SpatialMaterial>(get_material_override().ptr());
|
||||||
|
anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == SpatialMaterial::BILLBOARD_PARTICLES);
|
||||||
|
|
||||||
|
if (!meshes_found) {
|
||||||
|
if (warnings != String()) {
|
||||||
|
warnings += "\n\n";
|
||||||
|
}
|
||||||
|
warnings += "- " + TTR("Nothing is visible because meshes have not been assigned to draw passes.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process_material.is_null()) {
|
||||||
|
if (warnings != String()) {
|
||||||
|
warnings += "\n";
|
||||||
|
}
|
||||||
|
warnings += "- " + TTR("A material to process the particles is not assigned, so no behavior is imprinted.");
|
||||||
|
} else {
|
||||||
|
const ParticlesMaterial *process = Object::cast_to<ParticlesMaterial>(process_material.ptr());
|
||||||
|
if (!anim_material_found && process &&
|
||||||
|
(process->get_param(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 ||
|
||||||
|
process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) {
|
||||||
|
if (warnings != String()) {
|
||||||
|
warnings += "\n";
|
||||||
|
}
|
||||||
|
warnings += "- " + TTR("Particles animation requires the usage of a SpatialMaterial whose Billboard Mode is set to \"Particle Billboard\".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return warnings;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles::restart() {
|
||||||
|
RenderingServer::get_singleton()->particles_restart(particles);
|
||||||
|
RenderingServer::get_singleton()->particles_set_emitting(particles, true);
|
||||||
|
|
||||||
|
emitting = true;
|
||||||
|
active = true;
|
||||||
|
signal_canceled = false;
|
||||||
|
time = 0;
|
||||||
|
emission_time = lifetime * (1 - explosiveness_ratio);
|
||||||
|
active_time = lifetime * (2 - explosiveness_ratio);
|
||||||
|
if (one_shot) {
|
||||||
|
set_process_internal(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AABB Particles::capture_aabb() const {
|
||||||
|
return RS::get_singleton()->particles_get_current_aabb(particles);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles::_validate_property(PropertyInfo &property) const {
|
||||||
|
if (property.name.begins_with("draw_pass_")) {
|
||||||
|
int index = property.name.get_slicec('_', 2).to_int() - 1;
|
||||||
|
if (index >= draw_passes.size()) {
|
||||||
|
property.usage = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles::_notification(int p_what) {
|
||||||
|
if (p_what == NOTIFICATION_PAUSED || p_what == NOTIFICATION_UNPAUSED) {
|
||||||
|
if (can_process()) {
|
||||||
|
RS::get_singleton()->particles_set_speed_scale(particles, speed_scale);
|
||||||
|
} else {
|
||||||
|
RS::get_singleton()->particles_set_speed_scale(particles, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use internal process when emitting and one_shot are on so that when
|
||||||
|
// the shot ends the editor can properly update
|
||||||
|
if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
|
||||||
|
if (one_shot) {
|
||||||
|
time += get_process_delta_time();
|
||||||
|
if (time > emission_time) {
|
||||||
|
emitting = false;
|
||||||
|
if (!active) {
|
||||||
|
set_process_internal(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (time > active_time) {
|
||||||
|
if (active && !signal_canceled) {
|
||||||
|
emit_signal(SceneStringNames::get_singleton()->finished);
|
||||||
|
}
|
||||||
|
active = false;
|
||||||
|
if (!emitting) {
|
||||||
|
set_process_internal(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
|
||||||
|
// make sure particles are updated before rendering occurs if they were active before
|
||||||
|
if (is_visible_in_tree() && !RS::get_singleton()->particles_is_inactive(particles)) {
|
||||||
|
RS::get_singleton()->particles_request_process(particles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Particles::_bind_methods() {
|
||||||
|
ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &Particles::set_emitting);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_amount", "amount"), &Particles::set_amount);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_lifetime", "secs"), &Particles::set_lifetime);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_one_shot", "enable"), &Particles::set_one_shot);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &Particles::set_pre_process_time);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &Particles::set_explosiveness_ratio);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &Particles::set_randomness_ratio);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_visibility_aabb", "aabb"), &Particles::set_visibility_aabb);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_use_local_coordinates", "enable"), &Particles::set_use_local_coordinates);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_fixed_fps", "fps"), &Particles::set_fixed_fps);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &Particles::set_fractional_delta);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_process_material", "material"), &Particles::set_process_material);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &Particles::set_speed_scale);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("is_emitting"), &Particles::is_emitting);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_amount"), &Particles::get_amount);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_lifetime"), &Particles::get_lifetime);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_one_shot"), &Particles::get_one_shot);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_pre_process_time"), &Particles::get_pre_process_time);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_explosiveness_ratio"), &Particles::get_explosiveness_ratio);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_randomness_ratio"), &Particles::get_randomness_ratio);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_visibility_aabb"), &Particles::get_visibility_aabb);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_use_local_coordinates"), &Particles::get_use_local_coordinates);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_fixed_fps"), &Particles::get_fixed_fps);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_fractional_delta"), &Particles::get_fractional_delta);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_process_material"), &Particles::get_process_material);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_speed_scale"), &Particles::get_speed_scale);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("set_draw_order", "order"), &Particles::set_draw_order);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("get_draw_order"), &Particles::get_draw_order);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("set_draw_passes", "passes"), &Particles::set_draw_passes);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_draw_pass_mesh", "pass", "mesh"), &Particles::set_draw_pass_mesh);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("get_draw_passes"), &Particles::get_draw_passes);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_draw_pass_mesh", "pass"), &Particles::get_draw_pass_mesh);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("restart"), &Particles::restart);
|
||||||
|
ClassDB::bind_method(D_METHOD("capture_aabb"), &Particles::capture_aabb);
|
||||||
|
|
||||||
|
ADD_SIGNAL(MethodInfo("finished"));
|
||||||
|
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount");
|
||||||
|
ADD_GROUP("Time", "");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_EXP_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
|
||||||
|
ADD_GROUP("Drawing", "");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::AABB, "visibility_aabb"), "set_visibility_aabb", "get_visibility_aabb");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime,View Depth"), "set_draw_order", "get_draw_order");
|
||||||
|
ADD_GROUP("Process Material", "");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticlesMaterial"), "set_process_material", "get_process_material");
|
||||||
|
ADD_GROUP("Draw Passes", "draw_");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_passes", PROPERTY_HINT_RANGE, "0," + itos(MAX_DRAW_PASSES) + ",1"), "set_draw_passes", "get_draw_passes");
|
||||||
|
for (int i = 0; i < MAX_DRAW_PASSES; i++) {
|
||||||
|
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "draw_pass_" + itos(i + 1), PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_draw_pass_mesh", "get_draw_pass_mesh", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX);
|
||||||
|
BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME);
|
||||||
|
BIND_ENUM_CONSTANT(DRAW_ORDER_VIEW_DEPTH);
|
||||||
|
|
||||||
|
BIND_CONSTANT(MAX_DRAW_PASSES);
|
||||||
|
}
|
||||||
|
|
||||||
|
Particles::Particles() {
|
||||||
|
particles = RID_PRIME(RS::get_singleton()->particles_create());
|
||||||
|
set_base(particles);
|
||||||
|
one_shot = false; // Needed so that set_emitting doesn't access uninitialized values
|
||||||
|
set_emitting(true);
|
||||||
|
set_one_shot(false);
|
||||||
|
set_amount(8);
|
||||||
|
set_lifetime(1);
|
||||||
|
set_fixed_fps(0);
|
||||||
|
set_fractional_delta(true);
|
||||||
|
set_pre_process_time(0);
|
||||||
|
set_explosiveness_ratio(0);
|
||||||
|
set_randomness_ratio(0);
|
||||||
|
set_visibility_aabb(AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8)));
|
||||||
|
set_use_local_coordinates(true);
|
||||||
|
set_draw_passes(1);
|
||||||
|
set_draw_order(DRAW_ORDER_INDEX);
|
||||||
|
set_speed_scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Particles::~Particles() {
|
||||||
|
if (particles.is_valid()) {
|
||||||
|
RS::get_singleton()->free(particles);
|
||||||
|
}
|
||||||
|
}
|
140
scene/3d/particles.h
Normal file
140
scene/3d/particles.h
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
/**************************************************************************/
|
||||||
|
/* particles.h */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||||
|
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#ifndef PARTICLES_H
|
||||||
|
#define PARTICLES_H
|
||||||
|
|
||||||
|
#include "core/containers/rid.h"
|
||||||
|
#include "scene/3d/visual_instance.h"
|
||||||
|
#include "scene/resources/material/material.h"
|
||||||
|
|
||||||
|
class Particles : public GeometryInstance {
|
||||||
|
private:
|
||||||
|
GDCLASS(Particles, GeometryInstance);
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum DrawOrder {
|
||||||
|
DRAW_ORDER_INDEX,
|
||||||
|
DRAW_ORDER_LIFETIME,
|
||||||
|
DRAW_ORDER_VIEW_DEPTH,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MAX_DRAW_PASSES = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
RID particles;
|
||||||
|
|
||||||
|
bool emitting = false;
|
||||||
|
bool active = false;
|
||||||
|
bool signal_canceled = false;
|
||||||
|
bool one_shot = false;
|
||||||
|
int amount;
|
||||||
|
float lifetime;
|
||||||
|
float pre_process_time;
|
||||||
|
float explosiveness_ratio;
|
||||||
|
float randomness_ratio;
|
||||||
|
float speed_scale;
|
||||||
|
AABB visibility_aabb;
|
||||||
|
bool local_coords;
|
||||||
|
int fixed_fps;
|
||||||
|
bool fractional_delta;
|
||||||
|
|
||||||
|
Ref<Material> process_material;
|
||||||
|
|
||||||
|
DrawOrder draw_order;
|
||||||
|
|
||||||
|
Vector<Ref<Mesh>> draw_passes;
|
||||||
|
|
||||||
|
double time = 0.0;
|
||||||
|
double emission_time = 0.0;
|
||||||
|
double active_time = 0.0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static void _bind_methods();
|
||||||
|
void _notification(int p_what);
|
||||||
|
virtual void _validate_property(PropertyInfo &property) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AABB get_aabb() const;
|
||||||
|
PoolVector<Face3> get_faces(uint32_t p_usage_flags) const;
|
||||||
|
|
||||||
|
void set_emitting(bool p_emitting);
|
||||||
|
void set_amount(int p_amount);
|
||||||
|
void set_lifetime(float p_lifetime);
|
||||||
|
void set_one_shot(bool p_one_shot);
|
||||||
|
void set_pre_process_time(float p_time);
|
||||||
|
void set_explosiveness_ratio(float p_ratio);
|
||||||
|
void set_randomness_ratio(float p_ratio);
|
||||||
|
void set_visibility_aabb(const AABB &p_aabb);
|
||||||
|
void set_use_local_coordinates(bool p_enable);
|
||||||
|
void set_process_material(const Ref<Material> &p_material);
|
||||||
|
void set_speed_scale(float p_scale);
|
||||||
|
|
||||||
|
bool is_emitting() const;
|
||||||
|
int get_amount() const;
|
||||||
|
float get_lifetime() const;
|
||||||
|
bool get_one_shot() const;
|
||||||
|
float get_pre_process_time() const;
|
||||||
|
float get_explosiveness_ratio() const;
|
||||||
|
float get_randomness_ratio() const;
|
||||||
|
AABB get_visibility_aabb() const;
|
||||||
|
bool get_use_local_coordinates() const;
|
||||||
|
Ref<Material> get_process_material() const;
|
||||||
|
float get_speed_scale() const;
|
||||||
|
|
||||||
|
void set_fixed_fps(int p_count);
|
||||||
|
int get_fixed_fps() const;
|
||||||
|
|
||||||
|
void set_fractional_delta(bool p_enable);
|
||||||
|
bool get_fractional_delta() const;
|
||||||
|
|
||||||
|
void set_draw_order(DrawOrder p_order);
|
||||||
|
DrawOrder get_draw_order() const;
|
||||||
|
|
||||||
|
void set_draw_passes(int p_count);
|
||||||
|
int get_draw_passes() const;
|
||||||
|
|
||||||
|
void set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh);
|
||||||
|
Ref<Mesh> get_draw_pass_mesh(int p_pass) const;
|
||||||
|
|
||||||
|
virtual String get_configuration_warning() const;
|
||||||
|
|
||||||
|
void restart();
|
||||||
|
|
||||||
|
AABB capture_aabb() const;
|
||||||
|
Particles();
|
||||||
|
~Particles();
|
||||||
|
};
|
||||||
|
|
||||||
|
VARIANT_ENUM_CAST(Particles::DrawOrder)
|
||||||
|
|
||||||
|
#endif // PARTICLES_H
|
@ -518,6 +518,43 @@ public:
|
|||||||
virtual void instance_add_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) = 0;
|
virtual void instance_add_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) = 0;
|
||||||
virtual void instance_remove_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) = 0;
|
virtual void instance_remove_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) = 0;
|
||||||
|
|
||||||
|
/* PARTICLES */
|
||||||
|
|
||||||
|
virtual RID particles_create() = 0;
|
||||||
|
|
||||||
|
virtual void particles_set_emitting(RID p_particles, bool p_emitting) = 0;
|
||||||
|
virtual bool particles_get_emitting(RID p_particles) = 0;
|
||||||
|
|
||||||
|
virtual void particles_set_amount(RID p_particles, int p_amount) = 0;
|
||||||
|
virtual void particles_set_lifetime(RID p_particles, float p_lifetime) = 0;
|
||||||
|
virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) = 0;
|
||||||
|
virtual void particles_set_pre_process_time(RID p_particles, float p_time) = 0;
|
||||||
|
virtual void particles_set_explosiveness_ratio(RID p_particles, float p_ratio) = 0;
|
||||||
|
virtual void particles_set_randomness_ratio(RID p_particles, float p_ratio) = 0;
|
||||||
|
virtual void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) = 0;
|
||||||
|
virtual void particles_set_speed_scale(RID p_particles, float p_scale) = 0;
|
||||||
|
virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable) = 0;
|
||||||
|
virtual void particles_set_process_material(RID p_particles, RID p_material) = 0;
|
||||||
|
virtual void particles_set_fixed_fps(RID p_particles, int p_fps) = 0;
|
||||||
|
virtual void particles_set_fractional_delta(RID p_particles, bool p_enable) = 0;
|
||||||
|
virtual void particles_restart(RID p_particles) = 0;
|
||||||
|
|
||||||
|
virtual bool particles_is_inactive(RID p_particles) const = 0;
|
||||||
|
|
||||||
|
virtual void particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) = 0;
|
||||||
|
|
||||||
|
virtual void particles_set_draw_passes(RID p_particles, int p_count) = 0;
|
||||||
|
virtual void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) = 0;
|
||||||
|
|
||||||
|
virtual void particles_request_process(RID p_particles) = 0;
|
||||||
|
virtual AABB particles_get_current_aabb(RID p_particles) = 0;
|
||||||
|
virtual AABB particles_get_aabb(RID p_particles) const = 0;
|
||||||
|
|
||||||
|
virtual void particles_set_emission_transform(RID p_particles, const Transform &p_transform) = 0;
|
||||||
|
|
||||||
|
virtual int particles_get_draw_passes(RID p_particles) const = 0;
|
||||||
|
virtual RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const = 0;
|
||||||
|
|
||||||
/* LIGHTMAP CAPTURE */
|
/* LIGHTMAP CAPTURE */
|
||||||
|
|
||||||
struct LightmapCaptureOctree {
|
struct LightmapCaptureOctree {
|
||||||
@ -720,6 +757,7 @@ public:
|
|||||||
TYPE_POLYGON,
|
TYPE_POLYGON,
|
||||||
TYPE_MESH,
|
TYPE_MESH,
|
||||||
TYPE_MULTIMESH,
|
TYPE_MULTIMESH,
|
||||||
|
TYPE_PARTICLES,
|
||||||
TYPE_CIRCLE,
|
TYPE_CIRCLE,
|
||||||
TYPE_TRANSFORM,
|
TYPE_TRANSFORM,
|
||||||
TYPE_CLIP_IGNORE,
|
TYPE_CLIP_IGNORE,
|
||||||
@ -874,6 +912,13 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CommandParticles : public Command {
|
||||||
|
RID particles;
|
||||||
|
RID texture;
|
||||||
|
RID normal_map;
|
||||||
|
CommandParticles() { type = TYPE_PARTICLES; }
|
||||||
|
};
|
||||||
|
|
||||||
struct CommandCircle : public Command {
|
struct CommandCircle : public Command {
|
||||||
Point2 pos;
|
Point2 pos;
|
||||||
float radius;
|
float radius;
|
||||||
@ -1133,6 +1178,14 @@ public:
|
|||||||
|
|
||||||
r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y);
|
r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y);
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case Item::Command::TYPE_PARTICLES: {
|
||||||
|
const Item::CommandParticles *particles_cmd = static_cast<const Item::CommandParticles *>(c);
|
||||||
|
if (particles_cmd->particles.is_valid()) {
|
||||||
|
AABB aabb = RasterizerStorage::base_singleton->particles_get_aabb(particles_cmd->particles);
|
||||||
|
r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y);
|
||||||
|
}
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case Item::Command::TYPE_CIRCLE: {
|
case Item::Command::TYPE_CIRCLE: {
|
||||||
const Item::CommandCircle *circle = static_cast<const Item::CommandCircle *>(c);
|
const Item::CommandCircle *circle = static_cast<const Item::CommandCircle *>(c);
|
||||||
|
@ -324,7 +324,7 @@ void RenderingServerCanvas::_finalize_and_merge_local_bound_to_branch(Item *p_ca
|
|||||||
if (p_canvas_item->use_identity_xform) {
|
if (p_canvas_item->use_identity_xform) {
|
||||||
// This is incredibly inefficient, but should only occur for e.g. CPUParticles2D,
|
// This is incredibly inefficient, but should only occur for e.g. CPUParticles2D,
|
||||||
// and is difficult to avoid because global transform is not usually kept track of
|
// and is difficult to avoid because global transform is not usually kept track of
|
||||||
// in VisualServer (only final transform which is combinated with camera, and that
|
// in RenderingServer (only final transform which is combinated with camera, and that
|
||||||
// is only calculated on render, so is no use for culling purposes).
|
// is only calculated on render, so is no use for culling purposes).
|
||||||
Transform2D global_xform = _calculate_item_global_xform(p_canvas_item);
|
Transform2D global_xform = _calculate_item_global_xform(p_canvas_item);
|
||||||
this_rect = global_xform.affine_inverse().xform(this_rect);
|
this_rect = global_xform.affine_inverse().xform(this_rect);
|
||||||
@ -1492,6 +1492,24 @@ void RenderingServerCanvas::canvas_item_add_mesh(RID p_item, const RID &p_mesh,
|
|||||||
_make_bound_dirty(canvas_item);
|
_make_bound_dirty(canvas_item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RenderingServerCanvas::canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal) {
|
||||||
|
Item *canvas_item = canvas_item_owner.getornull(p_item);
|
||||||
|
ERR_FAIL_COND(!canvas_item);
|
||||||
|
|
||||||
|
Item::CommandParticles *part = memnew(Item::CommandParticles);
|
||||||
|
ERR_FAIL_COND(!part);
|
||||||
|
part->particles = p_particles;
|
||||||
|
part->texture = p_texture;
|
||||||
|
part->normal_map = p_normal;
|
||||||
|
|
||||||
|
//take the chance and request processing for them, at least once until they become visible again
|
||||||
|
RSG::storage->particles_request_process(p_particles);
|
||||||
|
|
||||||
|
canvas_item->rect_dirty = true;
|
||||||
|
canvas_item->commands.push_back(part);
|
||||||
|
_make_bound_dirty(canvas_item);
|
||||||
|
}
|
||||||
|
|
||||||
void RenderingServerCanvas::canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture, RID p_normal_map) {
|
void RenderingServerCanvas::canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture, RID p_normal_map) {
|
||||||
Item *canvas_item = canvas_item_owner.getornull(p_item);
|
Item *canvas_item = canvas_item_owner.getornull(p_item);
|
||||||
ERR_FAIL_COND(!canvas_item);
|
ERR_FAIL_COND(!canvas_item);
|
||||||
|
@ -247,6 +247,7 @@ public:
|
|||||||
void canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID(), bool p_antialiased = false, bool p_antialiasing_use_indices = false);
|
void canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID(), bool p_antialiased = false, bool p_antialiasing_use_indices = false);
|
||||||
void canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), RID p_texture = RID(), RID p_normal_map = RID());
|
void canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), RID p_texture = RID(), RID p_normal_map = RID());
|
||||||
void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture = RID(), RID p_normal_map = RID());
|
void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture = RID(), RID p_normal_map = RID());
|
||||||
|
void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal);
|
||||||
void canvas_item_add_texture_rect_animation(RID p_item, const Array &p_animation_data, const real_t p_start_time = 0.0);
|
void canvas_item_add_texture_rect_animation(RID p_item, const Array &p_animation_data, const real_t p_start_time = 0.0);
|
||||||
|
|
||||||
void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform);
|
void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform);
|
||||||
|
@ -360,6 +360,36 @@ public:
|
|||||||
BIND2(reflection_probe_set_cull_mask, RID, uint32_t)
|
BIND2(reflection_probe_set_cull_mask, RID, uint32_t)
|
||||||
BIND2(reflection_probe_set_resolution, RID, int)
|
BIND2(reflection_probe_set_resolution, RID, int)
|
||||||
|
|
||||||
|
/* PARTICLES */
|
||||||
|
|
||||||
|
BIND0R(RID, particles_create)
|
||||||
|
|
||||||
|
BIND2(particles_set_emitting, RID, bool)
|
||||||
|
BIND1R(bool, particles_get_emitting, RID)
|
||||||
|
BIND2(particles_set_amount, RID, int)
|
||||||
|
BIND2(particles_set_lifetime, RID, float)
|
||||||
|
BIND2(particles_set_one_shot, RID, bool)
|
||||||
|
BIND2(particles_set_pre_process_time, RID, float)
|
||||||
|
BIND2(particles_set_explosiveness_ratio, RID, float)
|
||||||
|
BIND2(particles_set_randomness_ratio, RID, float)
|
||||||
|
BIND2(particles_set_custom_aabb, RID, const AABB &)
|
||||||
|
BIND2(particles_set_speed_scale, RID, float)
|
||||||
|
BIND2(particles_set_use_local_coordinates, RID, bool)
|
||||||
|
BIND2(particles_set_process_material, RID, RID)
|
||||||
|
BIND2(particles_set_fixed_fps, RID, int)
|
||||||
|
BIND2(particles_set_fractional_delta, RID, bool)
|
||||||
|
BIND1R(bool, particles_is_inactive, RID)
|
||||||
|
BIND1(particles_request_process, RID)
|
||||||
|
BIND1(particles_restart, RID)
|
||||||
|
|
||||||
|
BIND2(particles_set_draw_order, RID, RS::ParticlesDrawOrder)
|
||||||
|
|
||||||
|
BIND2(particles_set_draw_passes, RID, int)
|
||||||
|
BIND3(particles_set_draw_pass_mesh, RID, int, RID)
|
||||||
|
|
||||||
|
BIND1R(AABB, particles_get_current_aabb, RID)
|
||||||
|
BIND2(particles_set_emission_transform, RID, const Transform &)
|
||||||
|
|
||||||
/* LIGHTMAP CAPTURE */
|
/* LIGHTMAP CAPTURE */
|
||||||
|
|
||||||
BIND0R(RID, lightmap_capture_create)
|
BIND0R(RID, lightmap_capture_create)
|
||||||
@ -630,6 +660,7 @@ public:
|
|||||||
BIND12(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, const Vector<int> &, const Vector<float> &, RID, int, RID, bool, bool)
|
BIND12(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, const Vector<int> &, const Vector<float> &, RID, int, RID, bool, bool)
|
||||||
BIND6(canvas_item_add_mesh, RID, const RID &, const Transform2D &, const Color &, RID, RID)
|
BIND6(canvas_item_add_mesh, RID, const RID &, const Transform2D &, const Color &, RID, RID)
|
||||||
BIND4(canvas_item_add_multimesh, RID, RID, RID, RID)
|
BIND4(canvas_item_add_multimesh, RID, RID, RID, RID)
|
||||||
|
BIND4(canvas_item_add_particles, RID, RID, RID, RID)
|
||||||
BIND3(canvas_item_add_texture_rect_animation, RID, const Array &, const real_t)
|
BIND3(canvas_item_add_texture_rect_animation, RID, const Array &, const real_t)
|
||||||
|
|
||||||
BIND2(canvas_item_add_set_transform, RID, const Transform2D &)
|
BIND2(canvas_item_add_set_transform, RID, const Transform2D &)
|
||||||
|
@ -542,7 +542,8 @@ void RenderingServerScene::instance_set_base(RID p_instance, RID p_base) {
|
|||||||
} break;
|
} break;
|
||||||
case RS::INSTANCE_MESH:
|
case RS::INSTANCE_MESH:
|
||||||
case RS::INSTANCE_MULTIMESH:
|
case RS::INSTANCE_MULTIMESH:
|
||||||
case RS::INSTANCE_IMMEDIATE: {
|
case RS::INSTANCE_IMMEDIATE:
|
||||||
|
case RS::INSTANCE_PARTICLES: {
|
||||||
InstanceGeometryData *geom = memnew(InstanceGeometryData);
|
InstanceGeometryData *geom = memnew(InstanceGeometryData);
|
||||||
instance->base_data = geom;
|
instance->base_data = geom;
|
||||||
if (instance->base_type == RS::INSTANCE_MESH) {
|
if (instance->base_type == RS::INSTANCE_MESH) {
|
||||||
@ -1012,7 +1013,7 @@ void RenderingServerScene::instance_set_visible(RID p_instance, bool p_visible)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
inline bool is_geometry_instance(RenderingServer::InstanceType p_type) {
|
inline bool is_geometry_instance(RenderingServer::InstanceType p_type) {
|
||||||
return p_type == RS::INSTANCE_MESH || p_type == RS::INSTANCE_MULTIMESH || p_type == RS::INSTANCE_IMMEDIATE;
|
return p_type == RS::INSTANCE_MESH || p_type == RS::INSTANCE_MULTIMESH || p_type == RS::INSTANCE_IMMEDIATE || p_type == RS::INSTANCE_PARTICLES;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingServerScene::instance_set_use_lightmap(RID p_instance, RID p_lightmap_instance, RID p_lightmap, int p_lightmap_slice, const Rect2 &p_lightmap_uv_rect) {
|
void RenderingServerScene::instance_set_use_lightmap(RID p_instance, RID p_lightmap_instance, RID p_lightmap, int p_lightmap_slice, const Rect2 &p_lightmap_uv_rect) {
|
||||||
@ -1810,6 +1811,10 @@ void RenderingServerScene::_update_instance(Instance *p_instance) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (p_instance->base_type == RS::INSTANCE_PARTICLES) {
|
||||||
|
RSG::storage->particles_set_emission_transform(p_instance->base, *instance_xform);
|
||||||
|
}
|
||||||
|
|
||||||
if (p_instance->aabb.has_no_surface()) {
|
if (p_instance->aabb.has_no_surface()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1906,6 +1911,14 @@ void RenderingServerScene::_update_instance_aabb(Instance *p_instance) {
|
|||||||
new_aabb = RSG::storage->immediate_get_aabb(p_instance->base);
|
new_aabb = RSG::storage->immediate_get_aabb(p_instance->base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case RenderingServer::INSTANCE_PARTICLES: {
|
||||||
|
if (p_instance->custom_aabb) {
|
||||||
|
new_aabb = *p_instance->custom_aabb;
|
||||||
|
} else {
|
||||||
|
new_aabb = RSG::storage->particles_get_aabb(p_instance->base);
|
||||||
|
}
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case RenderingServer::INSTANCE_LIGHT: {
|
case RenderingServer::INSTANCE_LIGHT: {
|
||||||
new_aabb = RSG::storage->light_get_aabb(p_instance->base);
|
new_aabb = RSG::storage->light_get_aabb(p_instance->base);
|
||||||
@ -2030,6 +2043,38 @@ void RenderingServerScene::_update_dirty_instance(Instance *p_instance) {
|
|||||||
if (mat.is_valid() && RSG::storage->material_is_animated(mat)) {
|
if (mat.is_valid() && RSG::storage->material_is_animated(mat)) {
|
||||||
is_animated = true;
|
is_animated = true;
|
||||||
}
|
}
|
||||||
|
} else if (p_instance->base_type == RS::INSTANCE_PARTICLES) {
|
||||||
|
bool cast_shadows = false;
|
||||||
|
|
||||||
|
int dp = RSG::storage->particles_get_draw_passes(p_instance->base);
|
||||||
|
|
||||||
|
for (int i = 0; i < dp; i++) {
|
||||||
|
RID mesh = RSG::storage->particles_get_draw_pass_mesh(p_instance->base, i);
|
||||||
|
if (!mesh.is_valid()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sc = RSG::storage->mesh_get_surface_count(mesh);
|
||||||
|
for (int j = 0; j < sc; j++) {
|
||||||
|
RID mat = RSG::storage->mesh_surface_get_material(mesh, j);
|
||||||
|
|
||||||
|
if (!mat.is_valid()) {
|
||||||
|
cast_shadows = true;
|
||||||
|
} else {
|
||||||
|
if (RSG::storage->material_casts_shadows(mat)) {
|
||||||
|
cast_shadows = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RSG::storage->material_is_animated(mat)) {
|
||||||
|
is_animated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cast_shadows) {
|
||||||
|
can_cast_shadows = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2890,6 +2935,20 @@ void RenderingServerScene::_prepare_scene(const Transform p_cam_transform, const
|
|||||||
RenderingServerRaster::redraw_request(false);
|
RenderingServerRaster::redraw_request(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ins->base_type == RS::INSTANCE_PARTICLES) {
|
||||||
|
//particles visible? process them
|
||||||
|
if (RSG::storage->particles_is_inactive(ins->base)) {
|
||||||
|
//but if nothing is going on, don't do it.
|
||||||
|
keep = false;
|
||||||
|
} else {
|
||||||
|
if (OS::get_singleton()->is_update_pending(true)) {
|
||||||
|
RSG::storage->particles_request_process(ins->base);
|
||||||
|
//particles visible? request redraw
|
||||||
|
RenderingServerRaster::redraw_request(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (geom->lighting_dirty) {
|
if (geom->lighting_dirty) {
|
||||||
int l = 0;
|
int l = 0;
|
||||||
//only called when lights AABB enter/exit this geometry
|
//only called when lights AABB enter/exit this geometry
|
||||||
|
@ -153,6 +153,7 @@ void RenderingServerWrapMT::finish() {
|
|||||||
omni_light_free_cached_ids();
|
omni_light_free_cached_ids();
|
||||||
spot_light_free_cached_ids();
|
spot_light_free_cached_ids();
|
||||||
reflection_probe_free_cached_ids();
|
reflection_probe_free_cached_ids();
|
||||||
|
particles_free_cached_ids();
|
||||||
lightmap_capture_free_cached_ids();
|
lightmap_capture_free_cached_ids();
|
||||||
camera_free_cached_ids();
|
camera_free_cached_ids();
|
||||||
viewport_free_cached_ids();
|
viewport_free_cached_ids();
|
||||||
|
@ -284,6 +284,36 @@ public:
|
|||||||
FUNC2(reflection_probe_set_cull_mask, RID, uint32_t)
|
FUNC2(reflection_probe_set_cull_mask, RID, uint32_t)
|
||||||
FUNC2(reflection_probe_set_resolution, RID, int)
|
FUNC2(reflection_probe_set_resolution, RID, int)
|
||||||
|
|
||||||
|
/* PARTICLES */
|
||||||
|
|
||||||
|
FUNCRID(particles)
|
||||||
|
|
||||||
|
FUNC2(particles_set_emitting, RID, bool)
|
||||||
|
FUNC1R(bool, particles_get_emitting, RID)
|
||||||
|
FUNC2(particles_set_amount, RID, int)
|
||||||
|
FUNC2(particles_set_lifetime, RID, float)
|
||||||
|
FUNC2(particles_set_one_shot, RID, bool)
|
||||||
|
FUNC2(particles_set_pre_process_time, RID, float)
|
||||||
|
FUNC2(particles_set_explosiveness_ratio, RID, float)
|
||||||
|
FUNC2(particles_set_randomness_ratio, RID, float)
|
||||||
|
FUNC2(particles_set_custom_aabb, RID, const AABB &)
|
||||||
|
FUNC2(particles_set_speed_scale, RID, float)
|
||||||
|
FUNC2(particles_set_use_local_coordinates, RID, bool)
|
||||||
|
FUNC2(particles_set_process_material, RID, RID)
|
||||||
|
FUNC2(particles_set_fixed_fps, RID, int)
|
||||||
|
FUNC2(particles_set_fractional_delta, RID, bool)
|
||||||
|
FUNC1R(bool, particles_is_inactive, RID)
|
||||||
|
FUNC1(particles_request_process, RID)
|
||||||
|
FUNC1(particles_restart, RID)
|
||||||
|
|
||||||
|
FUNC2(particles_set_draw_order, RID, RS::ParticlesDrawOrder)
|
||||||
|
|
||||||
|
FUNC2(particles_set_draw_passes, RID, int)
|
||||||
|
FUNC3(particles_set_draw_pass_mesh, RID, int, RID)
|
||||||
|
FUNC2(particles_set_emission_transform, RID, const Transform &)
|
||||||
|
|
||||||
|
FUNC1R(AABB, particles_get_current_aabb, RID)
|
||||||
|
|
||||||
/* LIGHTMAP CAPTURE */
|
/* LIGHTMAP CAPTURE */
|
||||||
|
|
||||||
FUNCRID(lightmap_capture)
|
FUNCRID(lightmap_capture)
|
||||||
@ -536,6 +566,7 @@ public:
|
|||||||
FUNC12(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, const Vector<int> &, const Vector<float> &, RID, int, RID, bool, bool)
|
FUNC12(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, const Vector<int> &, const Vector<float> &, RID, int, RID, bool, bool)
|
||||||
FUNC6(canvas_item_add_mesh, RID, const RID &, const Transform2D &, const Color &, RID, RID)
|
FUNC6(canvas_item_add_mesh, RID, const RID &, const Transform2D &, const Color &, RID, RID)
|
||||||
FUNC4(canvas_item_add_multimesh, RID, RID, RID, RID)
|
FUNC4(canvas_item_add_multimesh, RID, RID, RID, RID)
|
||||||
|
FUNC4(canvas_item_add_particles, RID, RID, RID, RID)
|
||||||
FUNC2(canvas_item_add_set_transform, RID, const Transform2D &)
|
FUNC2(canvas_item_add_set_transform, RID, const Transform2D &)
|
||||||
FUNC2(canvas_item_add_clip_ignore, RID, bool)
|
FUNC2(canvas_item_add_clip_ignore, RID, bool)
|
||||||
FUNC2(canvas_item_set_sort_children_by_y, RID, bool)
|
FUNC2(canvas_item_set_sort_children_by_y, RID, bool)
|
||||||
|
@ -2039,6 +2039,30 @@ void RenderingServer::_bind_methods() {
|
|||||||
ClassDB::bind_method(D_METHOD("lightmap_capture_is_interior", "capture"), &RenderingServer::lightmap_capture_is_interior);
|
ClassDB::bind_method(D_METHOD("lightmap_capture_is_interior", "capture"), &RenderingServer::lightmap_capture_is_interior);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("particles_create"), &RenderingServer::particles_create);
|
||||||
|
ClassDB::bind_method(D_METHOD("particles_set_emitting", "particles", "emitting"), &RenderingServer::particles_set_emitting);
|
||||||
|
ClassDB::bind_method(D_METHOD("particles_get_emitting", "particles"), &RenderingServer::particles_get_emitting);
|
||||||
|
ClassDB::bind_method(D_METHOD("particles_set_amount", "particles", "amount"), &RenderingServer::particles_set_amount);
|
||||||
|
ClassDB::bind_method(D_METHOD("particles_set_lifetime", "particles", "lifetime"), &RenderingServer::particles_set_lifetime);
|
||||||
|
ClassDB::bind_method(D_METHOD("particles_set_one_shot", "particles", "one_shot"), &RenderingServer::particles_set_one_shot);
|
||||||
|
ClassDB::bind_method(D_METHOD("particles_set_pre_process_time", "particles", "time"), &RenderingServer::particles_set_pre_process_time);
|
||||||
|
ClassDB::bind_method(D_METHOD("particles_set_explosiveness_ratio", "particles", "ratio"), &RenderingServer::particles_set_explosiveness_ratio);
|
||||||
|
ClassDB::bind_method(D_METHOD("particles_set_randomness_ratio", "particles", "ratio"), &RenderingServer::particles_set_randomness_ratio);
|
||||||
|
ClassDB::bind_method(D_METHOD("particles_set_custom_aabb", "particles", "aabb"), &RenderingServer::particles_set_custom_aabb);
|
||||||
|
ClassDB::bind_method(D_METHOD("particles_set_speed_scale", "particles", "scale"), &RenderingServer::particles_set_speed_scale);
|
||||||
|
ClassDB::bind_method(D_METHOD("particles_set_use_local_coordinates", "particles", "enable"), &RenderingServer::particles_set_use_local_coordinates);
|
||||||
|
ClassDB::bind_method(D_METHOD("particles_set_process_material", "particles", "material"), &RenderingServer::particles_set_process_material);
|
||||||
|
ClassDB::bind_method(D_METHOD("particles_set_fixed_fps", "particles", "fps"), &RenderingServer::particles_set_fixed_fps);
|
||||||
|
ClassDB::bind_method(D_METHOD("particles_set_fractional_delta", "particles", "enable"), &RenderingServer::particles_set_fractional_delta);
|
||||||
|
ClassDB::bind_method(D_METHOD("particles_is_inactive", "particles"), &RenderingServer::particles_is_inactive);
|
||||||
|
ClassDB::bind_method(D_METHOD("particles_request_process", "particles"), &RenderingServer::particles_request_process);
|
||||||
|
ClassDB::bind_method(D_METHOD("particles_restart", "particles"), &RenderingServer::particles_restart);
|
||||||
|
ClassDB::bind_method(D_METHOD("particles_set_draw_order", "particles", "order"), &RenderingServer::particles_set_draw_order);
|
||||||
|
ClassDB::bind_method(D_METHOD("particles_set_draw_passes", "particles", "count"), &RenderingServer::particles_set_draw_passes);
|
||||||
|
ClassDB::bind_method(D_METHOD("particles_set_draw_pass_mesh", "particles", "pass", "mesh"), &RenderingServer::particles_set_draw_pass_mesh);
|
||||||
|
ClassDB::bind_method(D_METHOD("particles_get_current_aabb", "particles"), &RenderingServer::particles_get_current_aabb);
|
||||||
|
ClassDB::bind_method(D_METHOD("particles_set_emission_transform", "particles", "transform"), &RenderingServer::particles_set_emission_transform);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("camera_create"), &RenderingServer::camera_create);
|
ClassDB::bind_method(D_METHOD("camera_create"), &RenderingServer::camera_create);
|
||||||
ClassDB::bind_method(D_METHOD("camera_set_perspective", "camera", "fovy_degrees", "z_near", "z_far"), &RenderingServer::camera_set_perspective);
|
ClassDB::bind_method(D_METHOD("camera_set_perspective", "camera", "fovy_degrees", "z_near", "z_far"), &RenderingServer::camera_set_perspective);
|
||||||
ClassDB::bind_method(D_METHOD("camera_set_orthogonal", "camera", "size", "z_near", "z_far"), &RenderingServer::camera_set_orthogonal);
|
ClassDB::bind_method(D_METHOD("camera_set_orthogonal", "camera", "size", "z_near", "z_far"), &RenderingServer::camera_set_orthogonal);
|
||||||
@ -2166,6 +2190,7 @@ void RenderingServer::_bind_methods() {
|
|||||||
ClassDB::bind_method(D_METHOD("canvas_item_add_triangle_array", "item", "indices", "points", "colors", "uvs", "bones", "weights", "texture", "count", "normal_map", "antialiased", "antialiasing_use_indices"), &RenderingServer::canvas_item_add_triangle_array, DEFVAL(Vector<Point2>()), DEFVAL(Vector<int>()), DEFVAL(Vector<float>()), DEFVAL(RID()), DEFVAL(-1), DEFVAL(RID()), DEFVAL(false), DEFVAL(false));
|
ClassDB::bind_method(D_METHOD("canvas_item_add_triangle_array", "item", "indices", "points", "colors", "uvs", "bones", "weights", "texture", "count", "normal_map", "antialiased", "antialiasing_use_indices"), &RenderingServer::canvas_item_add_triangle_array, DEFVAL(Vector<Point2>()), DEFVAL(Vector<int>()), DEFVAL(Vector<float>()), DEFVAL(RID()), DEFVAL(-1), DEFVAL(RID()), DEFVAL(false), DEFVAL(false));
|
||||||
ClassDB::bind_method(D_METHOD("canvas_item_add_mesh", "item", "mesh", "transform", "modulate", "texture", "normal_map"), &RenderingServer::canvas_item_add_mesh, DEFVAL(Transform2D()), DEFVAL(Color(1, 1, 1)), DEFVAL(RID()), DEFVAL(RID()));
|
ClassDB::bind_method(D_METHOD("canvas_item_add_mesh", "item", "mesh", "transform", "modulate", "texture", "normal_map"), &RenderingServer::canvas_item_add_mesh, DEFVAL(Transform2D()), DEFVAL(Color(1, 1, 1)), DEFVAL(RID()), DEFVAL(RID()));
|
||||||
ClassDB::bind_method(D_METHOD("canvas_item_add_multimesh", "item", "mesh", "texture", "normal_map"), &RenderingServer::canvas_item_add_multimesh, DEFVAL(RID()));
|
ClassDB::bind_method(D_METHOD("canvas_item_add_multimesh", "item", "mesh", "texture", "normal_map"), &RenderingServer::canvas_item_add_multimesh, DEFVAL(RID()));
|
||||||
|
ClassDB::bind_method(D_METHOD("canvas_item_add_particles", "item", "particles", "texture", "normal_map"), &RenderingServer::canvas_item_add_particles);
|
||||||
ClassDB::bind_method(D_METHOD("canvas_item_add_texture_rect_animation", "item", "animation_data", "start_time"), &RenderingServer::canvas_item_add_texture_rect_animation, DEFVAL(0.0));
|
ClassDB::bind_method(D_METHOD("canvas_item_add_texture_rect_animation", "item", "animation_data", "start_time"), &RenderingServer::canvas_item_add_texture_rect_animation, DEFVAL(0.0));
|
||||||
ClassDB::bind_method(D_METHOD("canvas_item_add_set_transform", "item", "transform"), &RenderingServer::canvas_item_add_set_transform);
|
ClassDB::bind_method(D_METHOD("canvas_item_add_set_transform", "item", "transform"), &RenderingServer::canvas_item_add_set_transform);
|
||||||
ClassDB::bind_method(D_METHOD("canvas_item_add_clip_ignore", "item", "ignore"), &RenderingServer::canvas_item_add_clip_ignore);
|
ClassDB::bind_method(D_METHOD("canvas_item_add_clip_ignore", "item", "ignore"), &RenderingServer::canvas_item_add_clip_ignore);
|
||||||
@ -2420,6 +2445,7 @@ void RenderingServer::_bind_methods() {
|
|||||||
BIND_ENUM_CONSTANT(INSTANCE_MESH);
|
BIND_ENUM_CONSTANT(INSTANCE_MESH);
|
||||||
BIND_ENUM_CONSTANT(INSTANCE_MULTIMESH);
|
BIND_ENUM_CONSTANT(INSTANCE_MULTIMESH);
|
||||||
BIND_ENUM_CONSTANT(INSTANCE_IMMEDIATE);
|
BIND_ENUM_CONSTANT(INSTANCE_IMMEDIATE);
|
||||||
|
BIND_ENUM_CONSTANT(INSTANCE_PARTICLES);
|
||||||
BIND_ENUM_CONSTANT(INSTANCE_LIGHT);
|
BIND_ENUM_CONSTANT(INSTANCE_LIGHT);
|
||||||
BIND_ENUM_CONSTANT(INSTANCE_REFLECTION_PROBE);
|
BIND_ENUM_CONSTANT(INSTANCE_REFLECTION_PROBE);
|
||||||
BIND_ENUM_CONSTANT(INSTANCE_LIGHTMAP_CAPTURE);
|
BIND_ENUM_CONSTANT(INSTANCE_LIGHTMAP_CAPTURE);
|
||||||
@ -2486,6 +2512,10 @@ void RenderingServer::_bind_methods() {
|
|||||||
BIND_ENUM_CONSTANT(REFLECTION_PROBE_UPDATE_ONCE);
|
BIND_ENUM_CONSTANT(REFLECTION_PROBE_UPDATE_ONCE);
|
||||||
BIND_ENUM_CONSTANT(REFLECTION_PROBE_UPDATE_ALWAYS);
|
BIND_ENUM_CONSTANT(REFLECTION_PROBE_UPDATE_ALWAYS);
|
||||||
|
|
||||||
|
BIND_ENUM_CONSTANT(PARTICLES_DRAW_ORDER_INDEX);
|
||||||
|
BIND_ENUM_CONSTANT(PARTICLES_DRAW_ORDER_LIFETIME);
|
||||||
|
BIND_ENUM_CONSTANT(PARTICLES_DRAW_ORDER_VIEW_DEPTH);
|
||||||
|
|
||||||
BIND_ENUM_CONSTANT(ENV_BG_CLEAR_COLOR);
|
BIND_ENUM_CONSTANT(ENV_BG_CLEAR_COLOR);
|
||||||
BIND_ENUM_CONSTANT(ENV_BG_COLOR);
|
BIND_ENUM_CONSTANT(ENV_BG_COLOR);
|
||||||
BIND_ENUM_CONSTANT(ENV_BG_SKY);
|
BIND_ENUM_CONSTANT(ENV_BG_SKY);
|
||||||
|
@ -551,6 +551,43 @@ public:
|
|||||||
virtual void lightmap_capture_set_interior(RID p_capture, bool p_interior) = 0;
|
virtual void lightmap_capture_set_interior(RID p_capture, bool p_interior) = 0;
|
||||||
virtual bool lightmap_capture_is_interior(RID p_capture) const = 0;
|
virtual bool lightmap_capture_is_interior(RID p_capture) const = 0;
|
||||||
|
|
||||||
|
/* PARTICLES API */
|
||||||
|
|
||||||
|
virtual RID particles_create() = 0;
|
||||||
|
|
||||||
|
virtual void particles_set_emitting(RID p_particles, bool p_emitting) = 0;
|
||||||
|
virtual bool particles_get_emitting(RID p_particles) = 0;
|
||||||
|
virtual void particles_set_amount(RID p_particles, int p_amount) = 0;
|
||||||
|
virtual void particles_set_lifetime(RID p_particles, float p_lifetime) = 0;
|
||||||
|
virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) = 0;
|
||||||
|
virtual void particles_set_pre_process_time(RID p_particles, float p_time) = 0;
|
||||||
|
virtual void particles_set_explosiveness_ratio(RID p_particles, float p_ratio) = 0;
|
||||||
|
virtual void particles_set_randomness_ratio(RID p_particles, float p_ratio) = 0;
|
||||||
|
virtual void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) = 0;
|
||||||
|
virtual void particles_set_speed_scale(RID p_particles, float p_scale) = 0;
|
||||||
|
virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable) = 0;
|
||||||
|
virtual void particles_set_process_material(RID p_particles, RID p_material) = 0;
|
||||||
|
virtual void particles_set_fixed_fps(RID p_particles, int p_fps) = 0;
|
||||||
|
virtual void particles_set_fractional_delta(RID p_particles, bool p_enable) = 0;
|
||||||
|
virtual bool particles_is_inactive(RID p_particles) = 0;
|
||||||
|
virtual void particles_request_process(RID p_particles) = 0;
|
||||||
|
virtual void particles_restart(RID p_particles) = 0;
|
||||||
|
|
||||||
|
enum ParticlesDrawOrder {
|
||||||
|
PARTICLES_DRAW_ORDER_INDEX,
|
||||||
|
PARTICLES_DRAW_ORDER_LIFETIME,
|
||||||
|
PARTICLES_DRAW_ORDER_VIEW_DEPTH,
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual void particles_set_draw_order(RID p_particles, ParticlesDrawOrder p_order) = 0;
|
||||||
|
|
||||||
|
virtual void particles_set_draw_passes(RID p_particles, int p_count) = 0;
|
||||||
|
virtual void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) = 0;
|
||||||
|
|
||||||
|
virtual AABB particles_get_current_aabb(RID p_particles) = 0;
|
||||||
|
|
||||||
|
virtual void particles_set_emission_transform(RID p_particles, const Transform &p_transform) = 0; //this is only used for 2D, in 3D it's automatic
|
||||||
|
|
||||||
/* CAMERA API */
|
/* CAMERA API */
|
||||||
|
|
||||||
virtual RID camera_create() = 0;
|
virtual RID camera_create() = 0;
|
||||||
@ -780,12 +817,13 @@ public:
|
|||||||
INSTANCE_MESH,
|
INSTANCE_MESH,
|
||||||
INSTANCE_MULTIMESH,
|
INSTANCE_MULTIMESH,
|
||||||
INSTANCE_IMMEDIATE,
|
INSTANCE_IMMEDIATE,
|
||||||
|
INSTANCE_PARTICLES,
|
||||||
INSTANCE_LIGHT,
|
INSTANCE_LIGHT,
|
||||||
INSTANCE_REFLECTION_PROBE,
|
INSTANCE_REFLECTION_PROBE,
|
||||||
INSTANCE_LIGHTMAP_CAPTURE,
|
INSTANCE_LIGHTMAP_CAPTURE,
|
||||||
INSTANCE_MAX,
|
INSTANCE_MAX,
|
||||||
|
|
||||||
INSTANCE_GEOMETRY_MASK = (1 << INSTANCE_MESH) | (1 << INSTANCE_MULTIMESH) | (1 << INSTANCE_IMMEDIATE)
|
INSTANCE_GEOMETRY_MASK = (1 << INSTANCE_MESH) | (1 << INSTANCE_MULTIMESH) | (1 << INSTANCE_IMMEDIATE) | (1 << INSTANCE_PARTICLES)
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual RID instance_create2(RID p_base, RID p_scenario);
|
virtual RID instance_create2(RID p_base, RID p_scenario);
|
||||||
@ -967,6 +1005,7 @@ public:
|
|||||||
virtual void canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID(), bool p_antialiased = false, bool p_antialiasing_use_indices = false) = 0;
|
virtual void canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID(), bool p_antialiased = false, bool p_antialiasing_use_indices = false) = 0;
|
||||||
virtual void canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), RID p_texture = RID(), RID p_normal_map = RID()) = 0;
|
virtual void canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), RID p_texture = RID(), RID p_normal_map = RID()) = 0;
|
||||||
virtual void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture = RID(), RID p_normal_map = RID()) = 0;
|
virtual void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture = RID(), RID p_normal_map = RID()) = 0;
|
||||||
|
virtual void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal_map) = 0;
|
||||||
virtual void canvas_item_add_texture_rect_animation(RID p_item, const Array &p_animation_data, const real_t p_start_time = 0.0) = 0;
|
virtual void canvas_item_add_texture_rect_animation(RID p_item, const Array &p_animation_data, const real_t p_start_time = 0.0) = 0;
|
||||||
|
|
||||||
virtual void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform) = 0;
|
virtual void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform) = 0;
|
||||||
@ -1194,6 +1233,7 @@ VARIANT_ENUM_CAST(RenderingServer::LightOmniShadowDetail);
|
|||||||
VARIANT_ENUM_CAST(RenderingServer::LightDirectionalShadowMode);
|
VARIANT_ENUM_CAST(RenderingServer::LightDirectionalShadowMode);
|
||||||
VARIANT_ENUM_CAST(RenderingServer::LightDirectionalShadowDepthRangeMode);
|
VARIANT_ENUM_CAST(RenderingServer::LightDirectionalShadowDepthRangeMode);
|
||||||
VARIANT_ENUM_CAST(RenderingServer::ReflectionProbeUpdateMode);
|
VARIANT_ENUM_CAST(RenderingServer::ReflectionProbeUpdateMode);
|
||||||
|
VARIANT_ENUM_CAST(RenderingServer::ParticlesDrawOrder);
|
||||||
VARIANT_ENUM_CAST(RenderingServer::Environment3DBG);
|
VARIANT_ENUM_CAST(RenderingServer::Environment3DBG);
|
||||||
VARIANT_ENUM_CAST(RenderingServer::Environment3DDOFBlurQuality);
|
VARIANT_ENUM_CAST(RenderingServer::Environment3DDOFBlurQuality);
|
||||||
VARIANT_ENUM_CAST(RenderingServer::Environment3DGlowBlendMode);
|
VARIANT_ENUM_CAST(RenderingServer::Environment3DGlowBlendMode);
|
||||||
|
Loading…
Reference in New Issue
Block a user