diff options
Diffstat (limited to 'scene/3d/particles.cpp')
-rw-r--r-- | scene/3d/particles.cpp | 1547 |
1 files changed, 1184 insertions, 363 deletions
diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp index ea61253ac7..2a92d6652c 100644 --- a/scene/3d/particles.cpp +++ b/scene/3d/particles.cpp @@ -30,532 +30,1353 @@ #include "scene/resources/surface_tool.h" #include "servers/visual_server.h" -#if 0 -/* -static const char* _var_names[Particles::VAR_MAX]={ - "vars/lifetime", - "vars/spread", - "vars/gravity", - "vars/linear_vel", - "vars/angular_vel", - "vars/linear_accel", - "vars/radial_accel", - "vars/tan_accel", - "vars/initial_size", - "vars/final_size", - "vars/initial_angle", - "vars/height", - "vars/height_speed_scale", -}; -*/ -static const char* _rand_names[Particles::VAR_MAX]={ - "rand/lifetime", - "rand/spread", - "rand/gravity", - "rand/linear_vel", - "rand/angular_vel", - "rand/linear_accel", - "rand/radial_accel", - "rand/tan_accel", - "rand/damping", - "rand/initial_size", - "rand/final_size", - "rand/initial_angle", - "rand/height", - "rand/height_speed_scale", -}; - -static const Particles::Variable _var_indices[Particles::VAR_MAX]={ - Particles::VAR_LIFETIME, - Particles::VAR_SPREAD, - Particles::VAR_GRAVITY, - Particles::VAR_LINEAR_VELOCITY, - Particles::VAR_ANGULAR_VELOCITY, - Particles::VAR_LINEAR_ACCELERATION, - Particles::VAR_DRAG, - Particles::VAR_TANGENTIAL_ACCELERATION, - Particles::VAR_DAMPING, - Particles::VAR_INITIAL_SIZE, - Particles::VAR_FINAL_SIZE, - Particles::VAR_INITIAL_ANGLE, - Particles::VAR_HEIGHT, - Particles::VAR_HEIGHT_SPEED_SCALE, -}; - - - -AABB Particles::get_aabb() const { - - return AABB( Vector3(-1,-1,-1), Vector3(2, 2, 2 ) ); +Rect3 Particles::get_aabb() const { + + return Rect3(); } PoolVector<Face3> Particles::get_faces(uint32_t p_usage_flags) const { return PoolVector<Face3>(); } +void Particles::set_emitting(bool p_emitting) { + + emitting = p_emitting; + VS::get_singleton()->particles_set_emitting(particles, emitting); +} void Particles::set_amount(int p_amount) { - ERR_FAIL_INDEX(p_amount,1024); - amount=p_amount; - VisualServer::get_singleton()->particles_set_amount(particles,p_amount); + amount = p_amount; + VS::get_singleton()->particles_set_amount(particles, amount); } -int Particles::get_amount() const { +void Particles::set_lifetime(float p_lifetime) { - return amount; + lifetime = p_lifetime; + VS::get_singleton()->particles_set_lifetime(particles, lifetime); } +void Particles::set_pre_process_time(float p_time) { -void Particles::set_emitting(bool p_emitting) { + pre_process_time = p_time; + VS::get_singleton()->particles_set_pre_process_time(particles, pre_process_time); +} +void Particles::set_explosiveness_ratio(float p_ratio) { + + explosiveness_ratio = p_ratio; + VS::get_singleton()->particles_set_explosiveness_ratio(particles, explosiveness_ratio); +} +void Particles::set_randomness_ratio(float p_ratio) { - emitting=p_emitting; - VisualServer::get_singleton()->particles_set_emitting(particles,p_emitting); + randomness_ratio = p_ratio; + VS::get_singleton()->particles_set_randomness_ratio(particles, randomness_ratio); +} +void Particles::set_custom_aabb(const Rect3 &p_aabb) { + + custom_aabb = p_aabb; + VS::get_singleton()->particles_set_custom_aabb(particles, custom_aabb); +} +void Particles::set_gravity(const Vector3 &p_gravity) { + + gravity = p_gravity; + VS::get_singleton()->particles_set_gravity(particles, gravity); +} +void Particles::set_use_local_coordinates(bool p_enable) { - setup_timer(); + local_coords = p_enable; + VS::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(); + VS::get_singleton()->particles_set_process_material(particles, material_rid); +} + bool Particles::is_emitting() const { return emitting; } +int Particles::get_amount() const { -void Particles::set_visibility_aabb(const AABB& p_aabb) { + return amount; +} +float Particles::get_lifetime() const { + + return lifetime; +} +float Particles::get_pre_process_time() const { + + return pre_process_time; +} +float Particles::get_explosiveness_ratio() const { - visibility_aabb=p_aabb; - VisualServer::get_singleton()->particles_set_visibility_aabb(particles,p_aabb); - update_gizmo(); + return explosiveness_ratio; +} +float Particles::get_randomness_ratio() const { + return randomness_ratio; } -AABB Particles::get_visibility_aabb() const { +Rect3 Particles::get_custom_aabb() const { - return visibility_aabb; + return custom_aabb; } +Vector3 Particles::get_gravity() const { + return gravity; +} +bool Particles::get_use_local_coordinates() const { -void Particles::set_emission_points(const PoolVector<Vector3>& p_points) { + return local_coords; +} +Ref<Material> Particles::get_process_material() const { - using_points = p_points.size(); - VisualServer::get_singleton()->particles_set_emission_points(particles,p_points); + return process_material; } -PoolVector<Vector3> Particles::get_emission_points() const { +void Particles::set_draw_order(DrawOrder p_order) { - if (!using_points) - return PoolVector<Vector3>(); + draw_order = p_order; + VS::get_singleton()->particles_set_draw_order(particles, VS::ParticlesDrawOrder(p_order)); +} - return VisualServer::get_singleton()->particles_get_emission_points(particles); +Particles::DrawOrder Particles::get_draw_order() const { + return draw_order; } -void Particles::set_emission_half_extents(const Vector3& p_half_extents) { +void Particles::set_draw_passes(int p_count) { - emission_half_extents=p_half_extents; - VisualServer::get_singleton()->particles_set_emission_half_extents(particles,p_half_extents); + ERR_FAIL_COND(p_count < 1); + draw_passes.resize(p_count); + VS::get_singleton()->particles_set_draw_passes(particles, p_count); + _change_notify(); +} +int Particles::get_draw_passes() const { + return draw_passes.size(); } -Vector3 Particles::get_emission_half_extents() const { +void Particles::set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh) { - return emission_half_extents; + ERR_FAIL_INDEX(p_pass, draw_passes.size()); + + draw_passes[p_pass] = p_mesh; + + RID mesh_rid; + if (p_mesh.is_valid()) + mesh_rid = p_mesh->get_rid(); + + VS::get_singleton()->particles_set_draw_pass_mesh(particles, p_pass, mesh_rid); } -void Particles::set_emission_base_velocity(const Vector3& p_base_velocity) { +Ref<Mesh> Particles::get_draw_pass_mesh(int p_pass) const { - emission_base_velocity=p_base_velocity; - VisualServer::get_singleton()->particles_set_emission_base_velocity(particles,p_base_velocity); + ERR_FAIL_INDEX_V(p_pass, draw_passes.size(), Ref<Mesh>()); + return draw_passes[p_pass]; } -Vector3 Particles::get_emission_base_velocity() const { +void Particles::set_fixed_fps(int p_count) { + fixed_fps = p_count; + VS::get_singleton()->particles_set_fixed_fps(particles, p_count); +} - return emission_base_velocity; +int Particles::get_fixed_fps() const { + return fixed_fps; } -void Particles::set_gravity_normal(const Vector3& p_normal) { +void Particles::set_fractional_delta(bool p_enable) { + fractional_delta = p_enable; + VS::get_singleton()->particles_set_fractional_delta(particles, p_enable); +} - gravity_normal=p_normal; - VisualServer::get_singleton()->particles_set_gravity_normal(particles,p_normal); +bool Particles::get_fractional_delta() const { + return fractional_delta; +} + +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; + } + } } -Vector3 Particles::get_gravity_normal() const { +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_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_custom_aabb", "aabb"), &Particles::set_custom_aabb); + ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &Particles::set_gravity); + 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:Material"), &Particles::set_process_material); + + 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_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_custom_aabb"), &Particles::get_custom_aabb); + ClassDB::bind_method(D_METHOD("get_gravity"), &Particles::get_gravity); + 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:Material"), &Particles::get_process_material); + + 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: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:Mesh", "pass"), &Particles::get_draw_pass_mesh); + + ADD_GROUP("Parameters", ""); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,100000,1"), "set_amount", "get_amount"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime"); + 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, "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::RECT3, "custom_aabb"), "set_custom_aabb", "get_custom_aabb"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity"), "set_gravity", "get_gravity"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates"); + 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_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ParticlesMaterial,ShaderMaterial"), "set_process_material", "get_process_material"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime,View Depth"), "set_draw_order", "get_draw_order"); + 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_CONSTANT(DRAW_ORDER_INDEX); + BIND_CONSTANT(DRAW_ORDER_LIFETIME); + BIND_CONSTANT(DRAW_ORDER_VIEW_DEPTH); + BIND_CONSTANT(MAX_DRAW_PASSES); +} - return gravity_normal; +Particles::Particles() { + particles = VS::get_singleton()->particles_create(); + set_base(particles); + set_emitting(true); + set_amount(100); + 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_gravity(Vector3(0, -9.8, 0)); + set_use_local_coordinates(true); + set_draw_passes(1); } -void Particles::set_variable(Variable p_variable,float p_value) { +Particles::~Particles() { - ERR_FAIL_INDEX(p_variable,VAR_MAX); - var[p_variable]=p_value; - VisualServer::get_singleton()->particles_set_variable(particles,(VS::ParticleVariable)p_variable,p_value); - if (p_variable==VAR_SPREAD) - update_gizmo(); + VS::get_singleton()->free(particles); } -float Particles::get_variable(Variable p_variable) const { +////////////////////////////////////// - ERR_FAIL_INDEX_V(p_variable,VAR_MAX,-1); - return var[p_variable]; +Mutex *ParticlesMaterial::material_mutex = NULL; +SelfList<ParticlesMaterial>::List ParticlesMaterial::dirty_materials; +Map<ParticlesMaterial::MaterialKey, ParticlesMaterial::ShaderData> ParticlesMaterial::shader_map; +ParticlesMaterial::ShaderNames *ParticlesMaterial::shader_names = NULL; +void ParticlesMaterial::init_shaders() { + +#ifndef NO_THREADS + material_mutex = Mutex::create(); +#endif + + shader_names = memnew(ShaderNames); + + shader_names->spread = "spread"; + shader_names->flatness = "flatness"; + shader_names->initial_linear_velocity = "initial_linear_velocity"; + shader_names->initial_angle = "initial_angle"; + shader_names->angular_velocity = "angular_velocity"; + shader_names->orbit_velocity = "orbit_velocity"; + shader_names->linear_accel = "linear_accel"; + shader_names->radial_accel = "radial_accel"; + shader_names->tangent_accel = "tangent_accel"; + shader_names->damping = "damping"; + shader_names->scale = "scale"; + shader_names->hue_variation = "hue_variation"; + shader_names->anim_speed = "anim_speed"; + shader_names->anim_offset = "anim_offset"; + + shader_names->initial_linear_velocity = "initial_linear_velocity_random"; + shader_names->initial_angle_random = "initial_angle_random"; + shader_names->angular_velocity_random = "angular_velocity_random"; + shader_names->orbit_velocity_random = "orbit_velocity_random"; + shader_names->linear_accel_random = "linear_accel_random"; + shader_names->radial_accel_random = "radial_accel_random"; + shader_names->tangent_accel_random = "tangent_accel_random"; + shader_names->damping_random = "damping_random"; + shader_names->scale_random = "scale_random"; + shader_names->hue_variation_random = "hue_variation_random"; + shader_names->anim_speed_random = "anim_speed_random"; + shader_names->anim_offset_random = "anim_offset_random"; + + shader_names->angle_texture = "angle_texture"; + shader_names->angular_velocity_texture = "angular_velocity_texture"; + shader_names->orbit_velocity_texture = "orbit_velocity_texture"; + shader_names->linear_accel_texture = "linear_accel_texture"; + shader_names->radial_accel_texture = "radial_accel_texture"; + shader_names->tangent_accel_texture = "tangent_accel_texture"; + shader_names->damping_texture = "damping_texture"; + shader_names->scale_texture = "scale_texture"; + shader_names->hue_variation_texture = "hue_variation_texture"; + shader_names->anim_speed_texture = "anim_speed_texture"; + shader_names->anim_offset_texture = "anim_offset_texture"; + + shader_names->color = "color_value"; + shader_names->color_ramp = "color_ramp"; + + shader_names->emission_sphere_radius = "emission_sphere_radius"; + shader_names->emission_box_extents = "emission_box_extents"; + shader_names->emission_texture_point_count = "emission_texture_point_count"; + shader_names->emission_texture_points = "emission_texture_points"; + shader_names->emission_texture_normal = "emission_texture_normal"; + + shader_names->trail_divisor = "trail_divisor"; + shader_names->trail_size_modifier = "trail_size_modifier"; + shader_names->trail_color_modifier = "trail_color_modifier"; } -void Particles::set_randomness(Variable p_variable,float p_randomness) { +void ParticlesMaterial::finish_shaders() { - ERR_FAIL_INDEX(p_variable,VAR_MAX); - var_random[p_variable]=p_randomness; - VisualServer::get_singleton()->particles_set_randomness(particles,(VS::ParticleVariable)p_variable,p_randomness); +#ifndef NO_THREADS + memdelete(material_mutex); +#endif + memdelete(shader_names); } -float Particles::get_randomness(Variable p_variable) const { - ERR_FAIL_INDEX_V(p_variable,VAR_MAX,-1); - return var_random[p_variable]; +void ParticlesMaterial::_update_shader() { + + print_line("updating shader"); + + dirty_materials.remove(&element); + + MaterialKey mk = _compute_key(); + if (mk.key == current_key.key) + return; //no update required in the end + + if (shader_map.has(current_key)) { + shader_map[current_key].users--; + if (shader_map[current_key].users == 0) { + //deallocate shader, as it's no longer in use + VS::get_singleton()->free(shader_map[current_key].shader); + shader_map.erase(current_key); + } + } + current_key = mk; + + if (shader_map.has(mk)) { + + VS::get_singleton()->material_set_shader(_get_material(), shader_map[mk].shader); + shader_map[mk].users++; + return; + } + + //must create a shader! + + String code = "shader_type particles;\n"; + + code += "uniform float spread;\n"; + code += "uniform float flatness;\n"; + code += "uniform float initial_linear_velocity;\n"; + code += "uniform float initial_angle;\n"; + code += "uniform float angular_velocity;\n"; + code += "uniform float orbit_velocity;\n"; + code += "uniform float linear_accel;\n"; + code += "uniform float radial_accel;\n"; + code += "uniform float tangent_accel;\n"; + code += "uniform float damping;\n"; + code += "uniform float scale;\n"; + code += "uniform float hue_variation;\n"; + code += "uniform float anim_speed;\n"; + code += "uniform float anim_offset;\n"; + + code += "uniform float initial_linear_velocity_random;\n"; + code += "uniform float initial_angle_random;\n"; + code += "uniform float angular_velocity_random;\n"; + code += "uniform float orbit_velocity_random;\n"; + code += "uniform float linear_accel_random;\n"; + code += "uniform float radial_accel_random;\n"; + code += "uniform float tangent_accel_random;\n"; + code += "uniform float damping_random;\n"; + code += "uniform float scale_random;\n"; + code += "uniform float hue_variation_random;\n"; + code += "uniform float anim_speed_random;\n"; + code += "uniform float anim_offset_random;\n"; + + code += "uniform vec4 color_value : hint_color;\n"; + + code += "uniform int trail_divisor;\n"; + + if (color_ramp.is_valid()) + code += "uniform sampler2D color_ramp;\n"; + + if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) + code += "uniform sampler2D linear_velocity_texture;\n"; + if (tex_parameters[PARAM_ORBIT_VELOCITY].is_valid()) + code += "uniform sampler2D orbit_velocity_texture;\n"; + if (tex_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) + code += "uniform sampler2D angular_velocity_texture;\n"; + if (tex_parameters[PARAM_LINEAR_ACCEL].is_valid()) + code += "uniform sampler2D linear_accel_texture;\n"; + if (tex_parameters[PARAM_RADIAL_ACCEL].is_valid()) + code += "uniform sampler2D radial_accel_texture;\n"; + if (tex_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) + code += "uniform sampler2D tangent_accel_texture;\n"; + if (tex_parameters[PARAM_DAMPING].is_valid()) + code += "uniform sampler2D damping_texture;\n"; + if (tex_parameters[PARAM_ANGLE].is_valid()) + code += "uniform sampler2D angle_texture;\n"; + if (tex_parameters[PARAM_SCALE].is_valid()) + code += "uniform sampler2D scale_texture;\n"; + if (tex_parameters[PARAM_HUE_VARIATION].is_valid()) + code += "uniform sampler2D hue_variation_texture;\n"; + if (tex_parameters[PARAM_ANIM_SPEED].is_valid()) + code += "uniform sampler2D anim_speed_texture;\n"; + if (tex_parameters[PARAM_ANIM_OFFSET].is_valid()) + code += "uniform sampler2D anim_offset_texture;\n"; + + switch (emission_shape) { + case EMISSION_SHAPE_POINT: { + //do none + } break; + case EMISSION_SHAPE_SPHERE: { + code += "uniform float emission_sphere_radius;\n"; + } break; + case EMISSION_SHAPE_BOX: { + code += "uniform vec3 emission_box_extents;\n"; + } break; + case EMISSION_SHAPE_DIRECTED_POINTS: { + code += "uniform sampler2D emission_texture_normal : hint_black;\n"; + } //fallthrough + case EMISSION_SHAPE_POINTS: { + code += "uniform sampler2D emission_texture_points : hint_black;\n"; + code += "uniform int emission_texture_point_count;\n"; + } break; + } + + if (trail_size_modifier.is_valid()) { + code += "uniform sampler2D trail_size_modifier;\n"; + } + + if (trail_color_modifier.is_valid()) { + code += "uniform sampler2D trail_color_modifier;\n"; + } + + //need a random function + code += "\n\n"; + code += "float rand_from_seed(inout uint seed) {\n"; + code += " int k;\n"; + code += " int s = int(seed);\n"; + code += " if (s == 0)\n"; + code += " s = 305420679;\n"; + code += " k = s / 127773;\n"; + code += " s = 16807 * (s - k * 127773) - 2836 * k;\n"; + code += " if (s < 0)\n"; + code += " s += 2147483647;\n"; + code += " seed = uint(s);\n"; + code += " return float(seed % uint(65536))/65535.0;\n"; + code += "}\n"; + //improve seed quality + code += "uint hash(uint x) {\n"; + code += " x = ((x >> uint(16)) ^ x) * uint(73244475);\n"; + code += " x = ((x >> uint(16)) ^ x) * uint(73244475);\n"; + code += " x = (x >> uint(16)) ^ x;\n"; + code += " return x;\n"; + code += "}\n"; + code += "void vertex() {\n\n"; + code += "\n"; + + code += " uint base_number=NUMBER/uint(trail_divisor);\n"; + code += " uint alt_seed=hash(base_number+uint(1));\n"; + code += " float angle_rand=rand_from_seed(alt_seed);\n"; + code += " float scale_rand=rand_from_seed(alt_seed);\n"; + code += " float hue_rot_rand=rand_from_seed(alt_seed);\n"; + code += " float anim_offset_rand=rand_from_seed(alt_seed);\n"; + code += "\n"; + code += "\n"; + code += "\n"; + code += "\n"; + code += " if (RESTART) {\n"; + + if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) + code += " float tex_linear_velocity = textureLod(linear_velocity_texture,vec2(0.0,0.0),0.0).r;\n"; + else + code += " float tex_linear_velocity = 0.0;\n"; + + if (tex_parameters[PARAM_ANGLE].is_valid()) + code += " float tex_angle = textureLod(angle_texture,vec2(0.0,0.0),0.0).r;\n"; + else + code += " float tex_angle = 0.0;\n"; + + if (tex_parameters[PARAM_ANIM_OFFSET].is_valid()) + code += " float tex_anim_offset = textureLod(anim_offset_texture,vec2(0.0,0.0),0.0).r;\n"; + else + code += " float tex_anim_offset = 0.0;\n"; + + code += " float angle1 = rand_from_seed(alt_seed)*spread*3.1416;\n"; + code += " float angle2 = rand_from_seed(alt_seed)*20.0*3.1416; // make it more random like\n"; + code += " vec3 rot_xz=vec3( sin(angle1), 0.0, cos(angle1) );\n"; + code += " vec3 rot = vec3( cos(angle2)*rot_xz.x,sin(angle2)*rot_xz.x, rot_xz.z);\n"; + code += " VELOCITY=(rot*initial_linear_velocity+rot*initial_linear_velocity_random*rand_from_seed(alt_seed));\n"; + code += " float base_angle=(initial_angle+tex_angle)*mix(1.0,angle_rand,initial_angle_random);\n"; + code += " CUSTOM.x=base_angle*3.1416/180.0;\n"; //angle + code += " CUSTOM.y=0.0;\n"; //phase + code += " CUSTOM.z=(anim_offset+tex_anim_offset)*mix(1.0,anim_offset_rand,anim_offset_random);\n"; //animation offset (0-1) + switch (emission_shape) { + case EMISSION_SHAPE_POINT: { + //do none + } break; + case EMISSION_SHAPE_SPHERE: { + code += " TRANSFORM[3].xyz = normalize(vec3(rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0-1.0, rand_from_seed(alt_seed) * 2.0-1.0 ))*emission_sphere_radius;\n"; + } break; + case EMISSION_SHAPE_BOX: { + code += " TRANSFORM[3].xyz = vec3(rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0-1.0, rand_from_seed(alt_seed) * 2.0-1.0)*emission_box_extents;\n"; + } break; + case EMISSION_SHAPE_POINTS: + case EMISSION_SHAPE_DIRECTED_POINTS: { + code += " int point = min(emission_texture_point_count-1,int(rand_from_seed(alt_seed) * float(emission_texture_point_count)));\n"; + code += " ivec2 tex_size = textureSize( emission_texture_points, 0 );\n"; + code += " ivec2 tex_ofs = ivec2( point % tex_size.x, point / tex_size.x );\n"; + code += " TRANSFORM[3].xyz = texelFetch(emission_texture_points, tex_ofs,0).xyz;\n"; + if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS) { + code += " vec3 normal = texelFetch(emission_texture_normal, tex_ofs,0).xyz;\n"; + code += " vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0, 1.0, 0.0);\n"; + code += " vec3 tangent = normalize(cross(v0, normal));\n"; + code += " vec3 bitangent = normalize(cross(tangent, normal));\n"; + code += " VELOCITY = mat3(tangent,bitangent,normal) * VELOCITY;\n"; + } + } break; + } + code += " VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY,0.0)).xyz;\n"; + code += " TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n"; + + code += " } else {\n"; + + code += " CUSTOM.y+=DELTA/LIFETIME;\n"; + if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) + code += " float tex_linear_velocity = textureLod(linear_velocity_texture,vec2(CUSTOM.y,0.0),0.0).r;\n"; + else + code += " float tex_linear_velocity = 0.0;\n"; + + if (tex_parameters[PARAM_ORBIT_VELOCITY].is_valid()) + code += " float tex_orbit_velocity = textureLod(orbit_velocity_texture,vec2(CUSTOM.y,0.0),0.0).r;\n"; + else + code += " float tex_orbit_velocity = 0.0;\n"; + + if (tex_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) + code += " float tex_angular_velocity = textureLod(angular_velocity_texture,vec2(CUSTOM.y,0.0),0.0).r;\n"; + else + code += " float tex_angular_velocity = 0.0;\n"; + + if (tex_parameters[PARAM_LINEAR_ACCEL].is_valid()) + code += " float tex_linear_accel = textureLod(linear_accel_texture,vec2(CUSTOM.y,0.0),0.0).r;\n"; + else + code += " float tex_linear_accel = 0.0;\n"; + + if (tex_parameters[PARAM_RADIAL_ACCEL].is_valid()) + code += " float tex_radial_accel = textureLod(radial_accel_texture,vec2(CUSTOM.y,0.0),0.0).r;\n"; + else + code += " float tex_radial_accel = 0.0;\n"; + + if (tex_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) + code += " float tex_tangent_accel = textureLod(tangent_accel_texture,vec2(CUSTOM.y,0.0),0.0).r;\n"; + else + code += " float tex_tangent_accel = 0.0;\n"; + + if (tex_parameters[PARAM_DAMPING].is_valid()) + code += " float tex_damping = textureLod(damping_texture,vec2(CUSTOM.y,0.0),0.0).r;\n"; + else + code += " float tex_damping = 0.0;\n"; + + if (tex_parameters[PARAM_ANGLE].is_valid()) + code += " float tex_angle = textureLod(angle_texture,vec2(CUSTOM.y,0.0),0.0).r;\n"; + else + code += " float tex_angle = 0.0;\n"; + + if (tex_parameters[PARAM_ANIM_SPEED].is_valid()) + code += " float tex_anim_speed = textureLod(anim_speed_texture,vec2(CUSTOM.y,0.0),0.0).r;\n"; + else + code += " float tex_anim_speed = 0.0;\n"; + + if (tex_parameters[PARAM_ANIM_OFFSET].is_valid()) + code += " float tex_anim_offset = textureLod(anim_offset_texture,vec2(CUSTOM.y,0.0),0.0).r;\n"; + else + code += " float tex_anim_offset = 0.0;\n"; + + code += " vec3 force = vec3(0.0); \n"; + code += " vec3 pos = TRANSFORM[3].xyz; \n"; + code += " //apply linear acceleration\n"; + code += " force+=normalize(VELOCITY) * (linear_accel+tex_linear_accel)*mix(1.0,rand_from_seed(alt_seed),linear_accel_random);\n"; + code += " //apply radial acceleration\n"; + code += " vec3 org = vec3(0.0);\n"; + code += " // if (!p_system->local_coordinates)\n"; + code += " //org=p_transform.origin;\n"; + code += " force+=normalize(pos-org) * (radial_accel+tex_radial_accel)*mix(1.0,rand_from_seed(alt_seed),radial_accel_random);\n"; + code += " //apply tangential acceleration;\n"; + code += " force+=normalize(cross(normalize(pos-org),normalize(GRAVITY))) * ((tangent_accel+tex_tangent_accel)*mix(1.0,rand_from_seed(alt_seed),radial_accel_random));\n"; + code += " //apply attractor forces\n"; + code += " VELOCITY+=force * DELTA;\n"; + if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) + code += " VELOCITY=normalize(VELOCITY)*tex_linear_velocity;\n"; + code += " if (damping+tex_damping>0.0) {\n"; + code += " \n"; + code += " float v = length(VELOCITY);\n"; + code += " float damp = (damping+tex_damping)*mix(1.0,rand_from_seed(alt_seed),damping_random);\n"; + code += " v -= damp * DELTA;\n"; + code += " if (v<0.0) {\n"; + code += " VELOCITY=vec3(0.0);\n"; + code += " } else {\n"; + code += " VELOCITY=normalize(VELOCITY) * v;\n"; + code += " }\n"; + code += " }\n"; + code += " float base_angle=(initial_angle+tex_angle)*mix(1.0,angle_rand,initial_angle_random)*3.1416/180.0;\n"; + code += " CUSTOM.x=((base_angle+tex_angle)+CUSTOM.y*LIFETIME*(angular_velocity+tex_angular_velocity)*mix(1.0,rand_from_seed(alt_seed)*2.0-1.0,angular_velocity_random))*3.1416/180.0;\n"; //angle + code += " CUSTOM.z=(anim_offset+tex_anim_offset)*mix(1.0,anim_offset_rand,anim_offset_random)+CUSTOM.y*LIFETIME*(anim_speed+tex_anim_speed)*mix(1.0,rand_from_seed(alt_seed),anim_speed_random);\n"; //angle + code += " }\n"; + //apply color + //apply hue rotation + if (tex_parameters[PARAM_SCALE].is_valid()) + code += " float tex_scale = textureLod(scale_texture,vec2(CUSTOM.y,0.0),0.0).r;\n"; + else + code += " float tex_scale = 1.0;\n"; + + if (tex_parameters[PARAM_HUE_VARIATION].is_valid()) + code += " float tex_hue_variation = textureLod(hue_variation_texture,vec2(CUSTOM.y,0.0),0.0).r;\n"; + else + code += " float tex_hue_variation = 0.0;\n"; + + code += " float hue_rot_angle = (hue_variation+tex_hue_variation)*3.1416*2.0*mix(1.0,hue_rot_rand*2.0-1.0,hue_variation_random);\n"; + code += " float hue_rot_c = cos(hue_rot_angle);\n"; + code += " float hue_rot_s = sin(hue_rot_angle);\n"; + code += " mat4 hue_rot_mat = mat4( vec4(0.299, 0.587, 0.114, 0.0),\n"; + code += " vec4(0.299, 0.587, 0.114, 0.0),\n"; + code += " vec4(0.299, 0.587, 0.114, 0.0),\n"; + code += " vec4(0.000, 0.000, 0.000, 1.0)) +\n"; + code += " \n"; + code += " mat4( vec4(0.701, -0.587, -0.114, 0.0),\n"; + code += " vec4(-0.299, 0.413, -0.114, 0.0),\n"; + code += " vec4(-0.300, -0.588, 0.886, 0.0),\n"; + code += " vec4(0.000, 0.000, 0.000, 0.0)) * hue_rot_c +\n"; + code += "\n"; + code += " mat4( vec4(0.168, 0.330, -0.497, 0.0),\n"; + code += " vec4(-0.328, 0.035, 0.292, 0.0),\n"; + code += " vec4(1.250, -1.050, -0.203, 0.0),\n"; + code += " vec4(0.000, 0.000, 0.000, 0.0)) * hue_rot_s;\n"; + if (color_ramp.is_valid()) { + code += " COLOR = textureLod(color_ramp,vec2(CUSTOM.y,0.0),0.0) * hue_rot_mat;\n"; + } else { + code += " COLOR = color_value * hue_rot_mat;\n"; + } + if (trail_color_modifier.is_valid()) { + code += "if (trail_divisor>1) { COLOR*=textureLod(trail_color_modifier,vec2(float(int(NUMBER)%trail_divisor)/float(trail_divisor-1),0.0),0.0); }\n"; + } + code += "\n"; + //orient particle Y towards velocity + if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) { + code += " if (length(VELOCITY)>0.0) {TRANSFORM[1].xyz=normalize(VELOCITY);} else {TRANSFORM[1].xyz=normalize(TRANSFORM[1].xyz);}\n"; + code += " if (TRANSFORM[1].xyz==normalize(TRANSFORM[0].xyz)) {\n"; + code += "\tTRANSFORM[0].xyz=normalize(cross(normalize(TRANSFORM[1].xyz),normalize(TRANSFORM[2].xyz)));\n"; + code += "\tTRANSFORM[2].xyz=normalize(cross(normalize(TRANSFORM[0].xyz),normalize(TRANSFORM[1].xyz)));\n"; + code += " } else {\n"; + code += "\tTRANSFORM[2].xyz=normalize(cross(normalize(TRANSFORM[0].xyz),normalize(TRANSFORM[1].xyz)));\n"; + code += "\tTRANSFORM[0].xyz=normalize(cross(normalize(TRANSFORM[1].xyz),normalize(TRANSFORM[2].xyz)));\n"; + code += " }\n"; + } else { + code += "\tTRANSFORM[0].xyz=normalize(TRANSFORM[0].xyz);\n"; + code += "\tTRANSFORM[1].xyz=normalize(TRANSFORM[1].xyz);\n"; + code += "\tTRANSFORM[2].xyz=normalize(TRANSFORM[2].xyz);\n"; + } + //turn particle by rotation in Y + if (flags[FLAG_ROTATE_Y]) { + code += "\tTRANSFORM = TRANSFORM * mat4( vec4(cos(CUSTOM.x),0.0,-sin(CUSTOM.x),0.0), vec4(0.0,1.0,0.0,0.0),vec4(sin(CUSTOM.x),0.0,cos(CUSTOM.x),0.0),vec4(0.0,0.0,0.0,1.0));\n"; + } + //scale by scale + code += " float base_scale=mix(scale*tex_scale,1.0,scale_random*scale_rand);\n"; + if (trail_size_modifier.is_valid()) { + code += "if (trail_divisor>1) { base_scale*=textureLod(trail_size_modifier,vec2(float(int(NUMBER)%trail_divisor)/float(trail_divisor-1),0.0),0.0).r; } \n"; + } + + code += " TRANSFORM[0].xyz*=base_scale;\n"; + code += " TRANSFORM[1].xyz*=base_scale;\n"; + code += " TRANSFORM[2].xyz*=base_scale;\n"; + code += "}\n"; + code += "\n"; + + ShaderData shader_data; + shader_data.shader = VS::get_singleton()->shader_create(); + shader_data.users = 1; + + VS::get_singleton()->shader_set_code(shader_data.shader, code); + + shader_map[mk] = shader_data; + + VS::get_singleton()->material_set_shader(_get_material(), shader_data.shader); } -void Particles::set_color_phase_pos(int p_phase, float p_pos) { +void ParticlesMaterial::flush_changes() { - ERR_FAIL_INDEX(p_phase,VS::MAX_PARTICLE_COLOR_PHASES); - color_phase[p_phase].pos=p_pos; - VisualServer::get_singleton()->particles_set_color_phase_pos(particles,p_phase,p_pos); + if (material_mutex) + material_mutex->lock(); + while (dirty_materials.first()) { + + dirty_materials.first()->self()->_update_shader(); + } + + if (material_mutex) + material_mutex->unlock(); } -float Particles::get_color_phase_pos(int p_phase) const { - ERR_FAIL_INDEX_V(p_phase,VS::MAX_PARTICLE_COLOR_PHASES,-1); - return color_phase[p_phase].pos; +void ParticlesMaterial::_queue_shader_change() { + + if (material_mutex) + material_mutex->lock(); + + print_line("queuing change"); + if (!element.in_list()) { + print_line("not in list, adding"); + dirty_materials.add(&element); + } + + if (material_mutex) + material_mutex->unlock(); } -void Particles::set_color_phase_color(int p_phase, const Color& p_color) { +bool ParticlesMaterial::_is_shader_dirty() const { + + bool dirty = false; + + if (material_mutex) + material_mutex->lock(); + + dirty = element.in_list(); - ERR_FAIL_INDEX(p_phase,VS::MAX_PARTICLE_COLOR_PHASES); - color_phase[p_phase].color=p_color; - VisualServer::get_singleton()->particles_set_color_phase_color(particles,p_phase,p_color); + if (material_mutex) + material_mutex->unlock(); + return dirty; } -Color Particles::get_color_phase_color(int p_phase) const { - ERR_FAIL_INDEX_V(p_phase,VS::MAX_PARTICLE_COLOR_PHASES,Color()); - return color_phase[p_phase].color; +void ParticlesMaterial::set_spread(float p_spread) { + spread = p_spread; + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->spread, p_spread); } -void Particles::set_material(const Ref<Material>& p_material) { +float ParticlesMaterial::get_spread() const { - material=p_material; - if(material.is_null()) { - VisualServer::get_singleton()->particles_set_material(particles,RID()); - } else { - VisualServer::get_singleton()->particles_set_material(particles,material->get_rid()); + return spread; +} + +void ParticlesMaterial::set_flatness(float p_flatness) { + + flatness = p_flatness; + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->flatness, p_flatness); +} +float ParticlesMaterial::get_flatness() const { + + return flatness; +} + +void ParticlesMaterial::set_param(Parameter p_param, float p_value) { + + ERR_FAIL_INDEX(p_param, PARAM_MAX); + + parameters[p_param] = p_value; + + switch (p_param) { + case PARAM_INITIAL_LINEAR_VELOCITY: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_linear_velocity, p_value); + } break; + case PARAM_ANGULAR_VELOCITY: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity, p_value); + } break; + case PARAM_ORBIT_VELOCITY: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity, p_value); + } break; + case PARAM_LINEAR_ACCEL: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel, p_value); + } break; + case PARAM_RADIAL_ACCEL: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel, p_value); + } break; + case PARAM_TANGENTIAL_ACCEL: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel, p_value); + } break; + case PARAM_DAMPING: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->damping, p_value); + } break; + case PARAM_ANGLE: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_angle, p_value); + } break; + case PARAM_SCALE: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->scale, p_value); + } break; + case PARAM_HUE_VARIATION: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation, p_value); + } break; + case PARAM_ANIM_SPEED: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed, p_value); + } break; + case PARAM_ANIM_OFFSET: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset, p_value); + } break; + case PARAM_MAX: { + }; } +} +float ParticlesMaterial::get_param(Parameter p_param) const { + + ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); + return parameters[p_param]; } -void Particles::setup_timer() { +void ParticlesMaterial::set_param_randomness(Parameter p_param, float p_value) { + + ERR_FAIL_INDEX(p_param, PARAM_MAX); + + randomness[p_param] = p_value; + + switch (p_param) { + case PARAM_INITIAL_LINEAR_VELOCITY: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_linear_velocity_random, p_value); + } break; + case PARAM_ANGULAR_VELOCITY: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity_random, p_value); + } break; + case PARAM_ORBIT_VELOCITY: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity_random, p_value); + } break; + case PARAM_LINEAR_ACCEL: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel_random, p_value); + } break; + case PARAM_RADIAL_ACCEL: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel_random, p_value); + } break; + case PARAM_TANGENTIAL_ACCEL: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel_random, p_value); + } break; + case PARAM_DAMPING: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->damping_random, p_value); + } break; + case PARAM_ANGLE: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_angle_random, p_value); + } break; + case PARAM_SCALE: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_random, p_value); + } break; + case PARAM_HUE_VARIATION: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation_random, p_value); + } break; + case PARAM_ANIM_SPEED: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed_random, p_value); + } break; + case PARAM_ANIM_OFFSET: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_random, p_value); + } break; + case PARAM_MAX: { + }; + } +} +float ParticlesMaterial::get_param_randomness(Parameter p_param) const { - if (emitting && emit_timeout > 0) { + ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); - timer->set_wait_time(emit_timeout); - timer->start(); - timer->set_one_shot(true); - }; -}; + return randomness[p_param]; +} -void Particles::set_emit_timeout(float p_timeout) { +static void _adjust_curve_range(const Ref<Texture> &p_texture, float p_min, float p_max) { - emit_timeout = p_timeout; - setup_timer(); -}; + Ref<CurveTexture> curve = p_texture; + if (!curve.is_valid()) + return; -float Particles::get_emit_timeout() const { + if (curve->get_max() == 1.0) { + curve->set_max(p_max); + } + if (curve->get_min() == 0.0) { + curve->set_min(p_min); + } +} - return emit_timeout; -}; +void ParticlesMaterial::set_param_texture(Parameter p_param, const Ref<Texture> &p_texture) { + + ERR_FAIL_INDEX(p_param, PARAM_MAX); + + tex_parameters[p_param] = p_texture; + + switch (p_param) { + case PARAM_INITIAL_LINEAR_VELOCITY: { + //do none for this one + } break; + case PARAM_ANGULAR_VELOCITY: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity_texture, p_texture); + _adjust_curve_range(p_texture, -360, 360); + } break; + case PARAM_ORBIT_VELOCITY: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity_texture, p_texture); + _adjust_curve_range(p_texture, -500, 500); + } break; + case PARAM_LINEAR_ACCEL: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel_texture, p_texture); + _adjust_curve_range(p_texture, -200, 200); + } break; + case PARAM_RADIAL_ACCEL: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel_texture, p_texture); + _adjust_curve_range(p_texture, -200, 200); + } break; + case PARAM_TANGENTIAL_ACCEL: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel_texture, p_texture); + _adjust_curve_range(p_texture, -200, 200); + } break; + case PARAM_DAMPING: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->damping_texture, p_texture); + _adjust_curve_range(p_texture, 0, 100); + } break; + case PARAM_ANGLE: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->angle_texture, p_texture); + _adjust_curve_range(p_texture, -360, 360); + } break; + case PARAM_SCALE: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_texture, p_texture); + + Ref<CurveTexture> curve = p_texture; + if (curve.is_valid()) { + if (curve->get_min() == 0 && curve->get_max() == 1) { + + curve->set_max(32); + PoolVector<Vector2> points; + points.push_back(Vector2(0, 1)); + points.push_back(Vector2(1, 1)); + curve->set_points(points); + } + } + } break; + case PARAM_HUE_VARIATION: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation_texture, p_texture); + _adjust_curve_range(p_texture, -1, 1); + } break; + case PARAM_ANIM_SPEED: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed_texture, p_texture); + _adjust_curve_range(p_texture, 0, 200); + } break; + case PARAM_ANIM_OFFSET: { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_texture, p_texture); + } break; + case PARAM_MAX: { + }; + } + + _queue_shader_change(); +} +Ref<Texture> ParticlesMaterial::get_param_texture(Parameter p_param) const { -Ref<Material> Particles::get_material() const { + ERR_FAIL_INDEX_V(p_param, PARAM_MAX, Ref<Texture>()); - return material; + return tex_parameters[p_param]; } -void Particles::set_height_from_velocity(bool p_enable) { +void ParticlesMaterial::set_color(const Color &p_color) { - height_from_velocity=p_enable; - VisualServer::get_singleton()->particles_set_height_from_velocity(particles,height_from_velocity); + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->color, p_color); + color = p_color; } -bool Particles::has_height_from_velocity() const { +Color ParticlesMaterial::get_color() const { - return height_from_velocity; + return color; } -void Particles::set_color_phases(int p_phases) { +void ParticlesMaterial::set_color_ramp(const Ref<Texture> &p_texture) { - color_phase_count=p_phases; - VisualServer::get_singleton()->particles_set_color_phases(particles,p_phases); + color_ramp = p_texture; + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->color_ramp, p_texture); + _queue_shader_change(); + _change_notify(); } -int Particles::get_color_phases() const{ +Ref<Texture> ParticlesMaterial::get_color_ramp() const { - return color_phase_count; + return color_ramp; } -bool Particles::_can_gizmo_scale() const { +void ParticlesMaterial::set_flag(Flags p_flag, bool p_enable) { + ERR_FAIL_INDEX(p_flag, FLAG_MAX); + flags[p_flag] = p_enable; + _queue_shader_change(); +} - return false; +bool ParticlesMaterial::get_flag(Flags p_flag) const { + ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false); + return flags[p_flag]; } -void Particles::set_use_local_coordinates(bool p_use) { +void ParticlesMaterial::set_emission_shape(EmissionShape p_shape) { - local_coordinates=p_use; - VisualServer::get_singleton()->particles_set_use_local_coordinates(particles,local_coordinates); + emission_shape = p_shape; + _change_notify(); + _queue_shader_change(); } -bool Particles::is_using_local_coordinates() const{ +void ParticlesMaterial::set_emission_sphere_radius(float p_radius) { - return local_coordinates; + emission_sphere_radius = p_radius; + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_sphere_radius, p_radius); } +void ParticlesMaterial::set_emission_box_extents(Vector3 p_extents) { -RES Particles::_get_gizmo_geometry() const { + emission_box_extents = p_extents; + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_box_extents, p_extents); +} - Ref<SurfaceTool> surface_tool( memnew( SurfaceTool )); +void ParticlesMaterial::set_emission_point_texture(const Ref<Texture> &p_points) { - Ref<FixedSpatialMaterial> mat( memnew( FixedSpatialMaterial )); + emission_point_texture = p_points; + RID texture; + if (p_points.is_valid()) + texture = p_points->get_rid(); + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_points, texture); +} - mat->set_parameter( FixedSpatialMaterial::PARAM_DIFFUSE,Color(0.0,0.6,0.7,0.2) ); - mat->set_parameter( FixedSpatialMaterial::PARAM_EMISSION,Color(0.5,0.7,0.8) ); - mat->set_blend_mode( Material::BLEND_MODE_ADD ); - mat->set_flag(Material::FLAG_DOUBLE_SIDED,true); - //mat->set_hint(Material::HINT_NO_DEPTH_DRAW,true); +void ParticlesMaterial::set_emission_normal_texture(const Ref<Texture> &p_normals) { + emission_normal_texture = p_normals; + RID texture; + if (p_normals.is_valid()) + texture = p_normals->get_rid(); + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_normal, texture); +} - surface_tool->begin(Mesh::PRIMITIVE_TRIANGLES); - surface_tool->set_material(mat); +void ParticlesMaterial::set_emission_point_count(int p_count) { - int sides=16; - int sections=24; + emission_point_count = p_count; + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_point_count, p_count); +} - //float len=1; - float deg=Math::deg2rad(var[VAR_SPREAD]*180); - if (deg==180) - deg=179.5; +ParticlesMaterial::EmissionShape ParticlesMaterial::get_emission_shape() const { - Vector3 to=Vector3(0,0,-1); + return emission_shape; +} - for(int j=0;j<sections;j++) { +float ParticlesMaterial::get_emission_sphere_radius() const { - Vector3 p1=Matrix3(Vector3(1,0,0),deg*j/sections).xform(to); - Vector3 p2=Matrix3(Vector3(1,0,0),deg*(j+1)/sections).xform(to); + return emission_sphere_radius; +} +Vector3 ParticlesMaterial::get_emission_box_extents() const { - for(int i=0;i<sides;i++) { + return emission_box_extents; +} +Ref<Texture> ParticlesMaterial::get_emission_point_texture() const { - Vector3 p1r = Matrix3(Vector3(0,0,1),Math_PI*2*float(i)/sides).xform(p1); - Vector3 p1s = Matrix3(Vector3(0,0,1),Math_PI*2*float(i+1)/sides).xform(p1); - Vector3 p2s = Matrix3(Vector3(0,0,1),Math_PI*2*float(i+1)/sides).xform(p2); - Vector3 p2r = Matrix3(Vector3(0,0,1),Math_PI*2*float(i)/sides).xform(p2); + return emission_point_texture; +} +Ref<Texture> ParticlesMaterial::get_emission_normal_texture() const { - surface_tool->add_normal(p1r.normalized()); - surface_tool->add_vertex(p1r); - surface_tool->add_normal(p1s.normalized()); - surface_tool->add_vertex(p1s); - surface_tool->add_normal(p2s.normalized()); - surface_tool->add_vertex(p2s); + return emission_normal_texture; +} - surface_tool->add_normal(p1r.normalized()); - surface_tool->add_vertex(p1r); - surface_tool->add_normal(p2s.normalized()); - surface_tool->add_vertex(p2s); - surface_tool->add_normal(p2r.normalized()); - surface_tool->add_vertex(p2r); +int ParticlesMaterial::get_emission_point_count() const { - if (j==sections-1) { + return emission_point_count; +} - surface_tool->add_normal(p2r.normalized()); - surface_tool->add_vertex(p2r); - surface_tool->add_normal(p2s.normalized()); - surface_tool->add_vertex(p2s); - surface_tool->add_normal(Vector3(0,0,1)); - surface_tool->add_vertex(Vector3()); - } - } - } +void ParticlesMaterial::set_trail_divisor(int p_divisor) { + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_divisor, p_divisor); + trail_divisor = p_divisor; + _change_notify(); +} - Ref<Mesh> mesh = surface_tool->commit(); +int ParticlesMaterial::get_trail_divisor() const { - Ref<FixedSpatialMaterial> mat_aabb( memnew( FixedSpatialMaterial )); + return trail_divisor; +} - mat_aabb->set_parameter( FixedSpatialMaterial::PARAM_DIFFUSE,Color(0.8,0.8,0.9,0.7) ); - mat_aabb->set_line_width(3); - mat_aabb->set_flag( Material::FLAG_UNSHADED, true ); +void ParticlesMaterial::set_trail_size_modifier(const Ref<CurveTexture> &p_trail_size_modifier) { - surface_tool->begin(Mesh::PRIMITIVE_LINES); - surface_tool->set_material(mat_aabb); + trail_size_modifier = p_trail_size_modifier; - for(int i=0;i<12;i++) { + Ref<CurveTexture> curve = trail_size_modifier; + if (curve.is_valid()) { + if (curve->get_min() == 0 && curve->get_max() == 1) { - Vector3 f,t; - visibility_aabb.get_edge(i,f,t); - surface_tool->add_vertex(f); - surface_tool->add_vertex(t); + curve->set_max(32); + PoolVector<Vector2> points; + points.push_back(Vector2(0, 1)); + points.push_back(Vector2(1, 1)); + curve->set_points(points); + } } - return surface_tool->commit(mesh); - + RID texture; + if (p_trail_size_modifier.is_valid()) + texture = p_trail_size_modifier->get_rid(); + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_size_modifier, texture); + _queue_shader_change(); } +Ref<CurveTexture> ParticlesMaterial::get_trail_size_modifier() const { -void Particles::_bind_methods() { + return trail_size_modifier; +} - ClassDB::bind_method(D_METHOD("set_amount","amount"),&Particles::set_amount); - ClassDB::bind_method(D_METHOD("get_amount"),&Particles::get_amount); - ClassDB::bind_method(D_METHOD("set_emitting","enabled"),&Particles::set_emitting); - ClassDB::bind_method(D_METHOD("is_emitting"),&Particles::is_emitting); - ClassDB::bind_method(D_METHOD("set_visibility_aabb","aabb"),&Particles::set_visibility_aabb); - ClassDB::bind_method(D_METHOD("get_visibility_aabb"),&Particles::get_visibility_aabb); - ClassDB::bind_method(D_METHOD("set_emission_half_extents","half_extents"),&Particles::set_emission_half_extents); - ClassDB::bind_method(D_METHOD("get_emission_half_extents"),&Particles::get_emission_half_extents); - ClassDB::bind_method(D_METHOD("set_emission_base_velocity","base_velocity"),&Particles::set_emission_base_velocity); - ClassDB::bind_method(D_METHOD("get_emission_base_velocity"),&Particles::get_emission_base_velocity); - ClassDB::bind_method(D_METHOD("set_emission_points","points"),&Particles::set_emission_points); - ClassDB::bind_method(D_METHOD("get_emission_points"),&Particles::get_emission_points); - ClassDB::bind_method(D_METHOD("set_gravity_normal","normal"),&Particles::set_gravity_normal); - ClassDB::bind_method(D_METHOD("get_gravity_normal"),&Particles::get_gravity_normal); - ClassDB::bind_method(D_METHOD("set_variable","variable","value"),&Particles::set_variable); - ClassDB::bind_method(D_METHOD("get_variable","variable"),&Particles::get_variable); - ClassDB::bind_method(D_METHOD("set_randomness","variable","randomness"),&Particles::set_randomness); - ClassDB::bind_method(D_METHOD("get_randomness","variable"),&Particles::get_randomness); - ClassDB::bind_method(D_METHOD("set_color_phase_pos","phase","pos"),&Particles::set_color_phase_pos); - ClassDB::bind_method(D_METHOD("get_color_phase_pos","phase"),&Particles::get_color_phase_pos); - ClassDB::bind_method(D_METHOD("set_color_phase_color","phase","color"),&Particles::set_color_phase_color); - ClassDB::bind_method(D_METHOD("get_color_phase_color","phase"),&Particles::get_color_phase_color); - ClassDB::bind_method(D_METHOD("set_material","material:Material"),&Particles::set_material); - ClassDB::bind_method(D_METHOD("get_material:Material"),&Particles::get_material); - ClassDB::bind_method(D_METHOD("set_emit_timeout","timeout"),&Particles::set_emit_timeout); - ClassDB::bind_method(D_METHOD("get_emit_timeout"),&Particles::get_emit_timeout); - ClassDB::bind_method(D_METHOD("set_height_from_velocity","enable"),&Particles::set_height_from_velocity); - ClassDB::bind_method(D_METHOD("has_height_from_velocity"),&Particles::has_height_from_velocity); - ClassDB::bind_method(D_METHOD("set_use_local_coordinates","enable"),&Particles::set_use_local_coordinates); - ClassDB::bind_method(D_METHOD("is_using_local_coordinates"),&Particles::is_using_local_coordinates); - - ClassDB::bind_method(D_METHOD("set_color_phases","count"),&Particles::set_color_phases); - ClassDB::bind_method(D_METHOD("get_color_phases"),&Particles::get_color_phases); - - ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "Material" ), "set_material", "get_material") ; - - ADD_PROPERTY( PropertyInfo( Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1024,1" ), "set_amount", "get_amount") ; - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "emitting" ), "set_emitting", "is_emitting") ; - ADD_PROPERTY( PropertyInfo( Variant::_AABB, "visibility" ), "set_visibility_aabb", "get_visibility_aabb") ; - ADD_PROPERTY( PropertyInfo( Variant::VECTOR3, "emission_extents" ), "set_emission_half_extents", "get_emission_half_extents") ; - ADD_PROPERTY( PropertyInfo( Variant::VECTOR3, "emission_base_velocity" ), "set_emission_base_velocity", "get_emission_base_velocity") ; - ADD_PROPERTY( PropertyInfo( Variant::VECTOR3_ARRAY, "emission_points" ), "set_emission_points", "get_emission_points") ; - ADD_PROPERTY( PropertyInfo( Variant::VECTOR3, "gravity_normal" ), "set_gravity_normal", "get_gravity_normal") ; - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "local_coords" ), "set_use_local_coordinates", "is_using_local_coordinates") ; - ADD_PROPERTY( PropertyInfo( Variant::REAL, "emit_timeout",PROPERTY_HINT_RANGE,"0,256,0.01"), "set_emit_timeout", "get_emit_timeout") ; - - - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/lifetime", PROPERTY_HINT_RANGE,"0.1,60,0.01"), "set_variable", "get_variable", VAR_LIFETIME ); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/spread", PROPERTY_HINT_RANGE,"0,1,0.01"), "set_variable", "get_variable", VAR_SPREAD ); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/gravity", PROPERTY_HINT_RANGE,"-48,48,0.01"), "set_variable", "get_variable", VAR_GRAVITY ); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/linear_vel", PROPERTY_HINT_RANGE,"-100,100,0.01"), "set_variable", "get_variable", VAR_LINEAR_VELOCITY ); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/angular_vel", PROPERTY_HINT_RANGE,"-100,100,0.01"), "set_variable", "get_variable", VAR_ANGULAR_VELOCITY ); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/linear_accel", PROPERTY_HINT_RANGE,"-100,100,0.01"), "set_variable", "get_variable", VAR_LINEAR_ACCELERATION ); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/radial_accel", PROPERTY_HINT_RANGE,"-100,100,0.01"), "set_variable", "get_variable", VAR_DRAG ); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/tan_accel", PROPERTY_HINT_RANGE,"-100,100,0.01"), "set_variable", "get_variable", VAR_TANGENTIAL_ACCELERATION ); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/damping", PROPERTY_HINT_RANGE,"0,128,0.01"), "set_variable", "get_variable", VAR_DAMPING ); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/initial_size", PROPERTY_HINT_RANGE,"0,100,0.01"), "set_variable", "get_variable", VAR_INITIAL_SIZE ); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/final_size", PROPERTY_HINT_RANGE,"0,100,0.01"), "set_variable", "get_variable", VAR_FINAL_SIZE ); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/initial_angle",PROPERTY_HINT_RANGE,"0,1,0.01"), "set_variable", "get_variable", VAR_INITIAL_ANGLE ); - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "vars/height_from_velocity"), "set_height_from_velocity", "has_height_from_velocity") ; - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/height",PROPERTY_HINT_RANGE,"0,4096,0.01"), "set_variable", "get_variable", VAR_HEIGHT); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "vars/height_speed_scale",PROPERTY_HINT_RANGE,"0,4096,0.01"), "set_variable", "get_variable", VAR_HEIGHT_SPEED_SCALE ); - - for(int i=0;i<VAR_MAX;i++) - ADD_PROPERTYI( PropertyInfo( Variant::REAL, _rand_names[i], PROPERTY_HINT_RANGE,"-16.0,16.0,0.01"),"set_randomness", "get_randomness",_var_indices[i] ); - - - ADD_PROPERTY( PropertyInfo( Variant::INT, "color_phases/count",PROPERTY_HINT_RANGE,"0,4,1"), "set_color_phases", "get_color_phases"); - - for(int i=0;i<VS::MAX_PARTICLE_COLOR_PHASES;i++) { - String phase="phase_"+itos(i)+"/"; - ADD_PROPERTYI( PropertyInfo( Variant::REAL, phase+"pos", PROPERTY_HINT_RANGE,"0,1,0.01"),"set_color_phase_pos","get_color_phase_pos",i ); - ADD_PROPERTYI( PropertyInfo( Variant::COLOR, phase+"color"),"set_color_phase_color","get_color_phase_color",i ); - } +void ParticlesMaterial::set_trail_color_modifier(const Ref<GradientTexture> &p_trail_color_modifier) { + + trail_color_modifier = p_trail_color_modifier; + RID texture; + if (p_trail_color_modifier.is_valid()) + texture = p_trail_color_modifier->get_rid(); + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_color_modifier, texture); + _queue_shader_change(); +} - BIND_CONSTANT( VAR_LIFETIME ); - BIND_CONSTANT( VAR_SPREAD ); - BIND_CONSTANT( VAR_GRAVITY ); - BIND_CONSTANT( VAR_LINEAR_VELOCITY ); - BIND_CONSTANT( VAR_ANGULAR_VELOCITY ); - BIND_CONSTANT( VAR_LINEAR_ACCELERATION ); - BIND_CONSTANT( VAR_DRAG ); - BIND_CONSTANT( VAR_TANGENTIAL_ACCELERATION ); - BIND_CONSTANT( VAR_INITIAL_SIZE ); - BIND_CONSTANT( VAR_FINAL_SIZE ); - BIND_CONSTANT( VAR_INITIAL_ANGLE ); - BIND_CONSTANT( VAR_HEIGHT ); - BIND_CONSTANT( VAR_HEIGHT_SPEED_SCALE ); - BIND_CONSTANT( VAR_MAX ); +Ref<GradientTexture> ParticlesMaterial::get_trail_color_modifier() const { + return trail_color_modifier; } -Particles::Particles() { +void ParticlesMaterial::_validate_property(PropertyInfo &property) const { - particles = VisualServer::get_singleton()->particles_create(); - timer = memnew(Timer); - add_child(timer); - emit_timeout = 0; + if (property.name == "color" && color_ramp.is_valid()) { + property.usage = 0; + } - set_amount(64); - set_emitting(true); - set_visibility_aabb(AABB( Vector3(-4,-4,-4), Vector3(8,8,8) ) ); + if (property.name == "emission_sphere_radius" && emission_shape != EMISSION_SHAPE_SPHERE) { + property.usage = 0; + } - for (int i=0;i<VAR_MAX;i++) { - set_randomness((Variable)i,0.0); + if (property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) { + property.usage = 0; } - set_variable( VAR_LIFETIME, 5.0); - set_variable( VAR_SPREAD, 0.2); - set_variable( VAR_GRAVITY, 9.8); - set_variable( VAR_LINEAR_VELOCITY, 0.2); - set_variable( VAR_ANGULAR_VELOCITY, 0.0); - set_variable( VAR_LINEAR_ACCELERATION, 0.0); - set_variable( VAR_DRAG, 0.0); - set_variable( VAR_TANGENTIAL_ACCELERATION, 0.0); - set_variable( VAR_DAMPING, 0.0); - set_variable( VAR_INITIAL_SIZE, 1.0); - set_variable( VAR_FINAL_SIZE, 1.0); - set_variable( VAR_INITIAL_ANGLE, 0.0); - set_variable( VAR_HEIGHT, 1.0); - set_variable( VAR_HEIGHT_SPEED_SCALE, 0.0); - - color_phase_count=0; - - set_color_phase_pos(0,0.0); - set_color_phase_pos(1,1.0); - set_color_phase_pos(2,1.0); - set_color_phase_pos(3,1.0); - - set_color_phase_color(0,Color(1,1,1)); - set_color_phase_color(1,Color(0,0,0)); - set_color_phase_color(2,Color(0,0,0)); - set_color_phase_color(3,Color(0,0,0)); - - set_gravity_normal(Vector3(0,-1.0,0)); - set_emission_half_extents(Vector3(0.1,0.1,0.1)); - - height_from_velocity=false; - - Vector<Variant> pars; - pars.push_back(false); - timer->connect("timeout", this, "set_emitting", pars); - set_base(particles); - local_coordinates=false; + if (property.name == "emission_point_texture" && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) { + property.usage = 0; + } + + if (property.name == "emission_normal_texture" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { + property.usage = 0; + } + + if (property.name == "emission_point_count" && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) { + property.usage = 0; + } } +void ParticlesMaterial::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_spread", "degrees"), &ParticlesMaterial::set_spread); + ClassDB::bind_method(D_METHOD("get_spread"), &ParticlesMaterial::get_spread); + + ClassDB::bind_method(D_METHOD("set_flatness", "amount"), &ParticlesMaterial::set_flatness); + ClassDB::bind_method(D_METHOD("get_flatness"), &ParticlesMaterial::get_flatness); + + ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &ParticlesMaterial::set_param); + ClassDB::bind_method(D_METHOD("get_param", "param"), &ParticlesMaterial::get_param); + + ClassDB::bind_method(D_METHOD("set_param_randomness", "param", "randomness"), &ParticlesMaterial::set_param_randomness); + ClassDB::bind_method(D_METHOD("get_param_randomness", "param"), &ParticlesMaterial::get_param_randomness); + + ClassDB::bind_method(D_METHOD("set_param_texture", "param", "texture"), &ParticlesMaterial::set_param_texture); + ClassDB::bind_method(D_METHOD("get_param_texture", "param"), &ParticlesMaterial::get_param_texture); + + ClassDB::bind_method(D_METHOD("set_color", "color"), &ParticlesMaterial::set_color); + ClassDB::bind_method(D_METHOD("get_color"), &ParticlesMaterial::get_color); + + ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp:Texture"), &ParticlesMaterial::set_color_ramp); + ClassDB::bind_method(D_METHOD("get_color_ramp:Texture"), &ParticlesMaterial::get_color_ramp); + + ClassDB::bind_method(D_METHOD("set_flag", "flag", "enable"), &ParticlesMaterial::set_flag); + ClassDB::bind_method(D_METHOD("get_flag", "flag"), &ParticlesMaterial::get_flag); + + ClassDB::bind_method(D_METHOD("set_emission_shape", "shape"), &ParticlesMaterial::set_emission_shape); + ClassDB::bind_method(D_METHOD("get_emission_shape"), &ParticlesMaterial::get_emission_shape); + + ClassDB::bind_method(D_METHOD("set_emission_sphere_radius", "radius"), &ParticlesMaterial::set_emission_sphere_radius); + ClassDB::bind_method(D_METHOD("get_emission_sphere_radius"), &ParticlesMaterial::get_emission_sphere_radius); + + ClassDB::bind_method(D_METHOD("set_emission_box_extents", "extents"), &ParticlesMaterial::set_emission_box_extents); + ClassDB::bind_method(D_METHOD("get_emission_box_extents"), &ParticlesMaterial::get_emission_box_extents); + + ClassDB::bind_method(D_METHOD("set_emission_point_texture", "texture:Texture"), &ParticlesMaterial::set_emission_point_texture); + ClassDB::bind_method(D_METHOD("get_emission_point_texture:Texture"), &ParticlesMaterial::get_emission_point_texture); + + ClassDB::bind_method(D_METHOD("set_emission_normal_texture", "texture:Texture"), &ParticlesMaterial::set_emission_normal_texture); + ClassDB::bind_method(D_METHOD("get_emission_normal_texture:Texture"), &ParticlesMaterial::get_emission_normal_texture); + + ClassDB::bind_method(D_METHOD("set_emission_point_count", "point_count"), &ParticlesMaterial::set_emission_point_count); + ClassDB::bind_method(D_METHOD("get_emission_point_count"), &ParticlesMaterial::get_emission_point_count); + + ClassDB::bind_method(D_METHOD("set_trail_divisor", "divisor"), &ParticlesMaterial::set_trail_divisor); + ClassDB::bind_method(D_METHOD("get_trail_divisor"), &ParticlesMaterial::get_trail_divisor); + + ClassDB::bind_method(D_METHOD("set_trail_size_modifier", "texture:CurveTexture"), &ParticlesMaterial::set_trail_size_modifier); + ClassDB::bind_method(D_METHOD("get_trail_size_modifier:CurveTexture"), &ParticlesMaterial::get_trail_size_modifier); + + ClassDB::bind_method(D_METHOD("set_trail_color_modifier", "texture:GradientTexture"), &ParticlesMaterial::set_trail_color_modifier); + ClassDB::bind_method(D_METHOD("get_trail_color_modifier:GradientTexture"), &ParticlesMaterial::get_trail_color_modifier); + + ADD_GROUP("Trail", "trail_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "trail_divisor", PROPERTY_HINT_RANGE, "1,1000000,1"), "set_trail_divisor", "get_trail_divisor"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "trail_size_modifier", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_trail_size_modifier", "get_trail_size_modifier"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "trail_color_modifier", PROPERTY_HINT_RESOURCE_TYPE, "GradientTexture"), "set_trail_color_modifier", "get_trail_color_modifier"); + ADD_GROUP("Emission Shape", "emission_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Box,Points,Directed Points"), "set_emission_shape", "get_emission_shape"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01"), "set_emission_sphere_radius", "get_emission_sphere_radius"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "emission_box_extents"), "set_emission_box_extents", "get_emission_box_extents"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_point_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_emission_point_texture", "get_emission_point_texture"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_normal_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_emission_normal_texture", "get_emission_normal_texture"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_point_count", PROPERTY_HINT_RANGE, "0,1000000,1"), "set_emission_point_count", "get_emission_point_count"); + ADD_GROUP("Flags", "flag_"); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_align_y"), "set_flag", "get_flag", FLAG_ALIGN_Y_TO_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_rotate_y"), "set_flag", "get_flag", FLAG_ROTATE_Y); + ADD_GROUP("Spread", ""); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "spread", PROPERTY_HINT_RANGE, "0,180,0.01"), "set_spread", "get_spread"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "flatness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_flatness", "get_flatness"); + ADD_GROUP("Initial Velocity", "initial_"); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity", PROPERTY_HINT_RANGE, "0,1000,0.01"), "set_param", "get_param", PARAM_INITIAL_LINEAR_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_INITIAL_LINEAR_VELOCITY); + ADD_GROUP("Angular Velocity", "angular_"); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity", PROPERTY_HINT_RANGE, "-360,360,0.01"), "set_param", "get_param", PARAM_ANGULAR_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGULAR_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGULAR_VELOCITY); + ADD_GROUP("Orbit Velocity", "orbit_"); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "orbit_velocity", PROPERTY_HINT_RANGE, "-1000,1000,0.01"), "set_param", "get_param", PARAM_ORBIT_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "orbit_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ORBIT_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ORBIT_VELOCITY); + ADD_GROUP("Linear Accel", "linear_"); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_accel", PROPERTY_HINT_RANGE, "-100,100,0.01"), "set_param", "get_param", PARAM_LINEAR_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_LINEAR_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_LINEAR_ACCEL); + ADD_GROUP("Radial Accel", "radial_"); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "radial_accel", PROPERTY_HINT_RANGE, "-100,100,0.01"), "set_param", "get_param", PARAM_RADIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "radial_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_RADIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_RADIAL_ACCEL); + ADD_GROUP("Tangential Accel", "tangential_"); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "tangential_accel", PROPERTY_HINT_RANGE, "-100,100,0.01"), "set_param", "get_param", PARAM_TANGENTIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "tangential_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_TANGENTIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_TANGENTIAL_ACCEL); + ADD_GROUP("Damping", ""); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "damping", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param", "get_param", PARAM_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "damping_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_DAMPING); + ADD_GROUP("Angle", ""); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angle", PROPERTY_HINT_RANGE, "-720,720,0.1"), "set_param", "get_param", PARAM_ANGLE); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angle_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGLE); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGLE); + ADD_GROUP("Scale", ""); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale", PROPERTY_HINT_RANGE, "0,1000,0.01"), "set_param", "get_param", PARAM_SCALE); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_SCALE); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "scale_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_SCALE); + ADD_GROUP("Color", ""); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "GradientTexture"), "set_color_ramp", "get_color_ramp"); + + ADD_GROUP("Hue Variation", "hue_"); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "hue_variation", PROPERTY_HINT_RANGE, "-1,1,0.1"), "set_param", "get_param", PARAM_HUE_VARIATION); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "hue_variation_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_HUE_VARIATION); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_HUE_VARIATION); + ADD_GROUP("Animation", "anim_"); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_speed", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_SPEED); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_speed_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_SPEED); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_SPEED); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_OFFSET); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_OFFSET); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_OFFSET); + + BIND_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY); + BIND_CONSTANT(PARAM_ANGULAR_VELOCITY); + BIND_CONSTANT(PARAM_ORBIT_VELOCITY); + BIND_CONSTANT(PARAM_LINEAR_ACCEL); + BIND_CONSTANT(PARAM_RADIAL_ACCEL); + BIND_CONSTANT(PARAM_TANGENTIAL_ACCEL); + BIND_CONSTANT(PARAM_DAMPING); + BIND_CONSTANT(PARAM_ANGLE); + BIND_CONSTANT(PARAM_SCALE); + BIND_CONSTANT(PARAM_HUE_VARIATION); + BIND_CONSTANT(PARAM_ANIM_SPEED); + BIND_CONSTANT(PARAM_ANIM_OFFSET); + BIND_CONSTANT(PARAM_MAX); + + BIND_CONSTANT(FLAG_ALIGN_Y_TO_VELOCITY); + BIND_CONSTANT(FLAG_ROTATE_Y); + BIND_CONSTANT(FLAG_MAX); + + BIND_CONSTANT(EMISSION_SHAPE_POINT); + BIND_CONSTANT(EMISSION_SHAPE_SPHERE); + BIND_CONSTANT(EMISSION_SHAPE_BOX); + BIND_CONSTANT(EMISSION_SHAPE_POINTS); + BIND_CONSTANT(EMISSION_SHAPE_DIRECTED_POINTS); +} -Particles::~Particles() { +ParticlesMaterial::ParticlesMaterial() + : element(this) { + + set_spread(45); + set_flatness(0); + set_param(PARAM_INITIAL_LINEAR_VELOCITY, 1); + set_param(PARAM_ORBIT_VELOCITY, 0); + set_param(PARAM_LINEAR_ACCEL, 0); + set_param(PARAM_RADIAL_ACCEL, 0); + set_param(PARAM_TANGENTIAL_ACCEL, 0); + set_param(PARAM_DAMPING, 0); + set_param(PARAM_ANGLE, 0); + set_param(PARAM_SCALE, 1); + set_param(PARAM_HUE_VARIATION, 0); + set_param(PARAM_ANIM_SPEED, 0); + set_param(PARAM_ANIM_OFFSET, 0); + set_emission_shape(EMISSION_SHAPE_POINT); + set_emission_sphere_radius(1); + set_emission_box_extents(Vector3(1, 1, 1)); + set_trail_divisor(1); + emission_point_count = 1; + + for (int i = 0; i < PARAM_MAX; i++) { + set_param_randomness(Parameter(i), 0); + } + + for (int i = 0; i < FLAG_MAX; i++) { + flags[i] = false; + } - VisualServer::get_singleton()->free(particles); + set_color(Color(1, 1, 1, 1)); + + current_key.key = 0; + current_key.invalid_key = 1; + + _queue_shader_change(); } -#endif +ParticlesMaterial::~ParticlesMaterial() { +} |