summaryrefslogtreecommitdiff
path: root/scene/2d/particles_2d.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene/2d/particles_2d.cpp')
-rw-r--r--scene/2d/particles_2d.cpp1045
1 files changed, 1045 insertions, 0 deletions
diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp
new file mode 100644
index 0000000000..c10f60f78b
--- /dev/null
+++ b/scene/2d/particles_2d.cpp
@@ -0,0 +1,1045 @@
+/*************************************************************************/
+/* particles_2d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* 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"
+
+
+
+void ParticleAttractor2D::_notification(int p_what) {
+
+ switch(p_what) {
+
+ case NOTIFICATION_ENTER_SCENE: {
+
+ _update_owner();
+
+ } break;
+ case NOTIFICATION_DRAW: {
+
+ if (!get_scene()->is_editor_hint())
+ return;
+
+ Vector2 pv;
+ float dr = MIN(disable_radius,radius);
+ for(int i=0;i<=32;i++) {
+ Vector2 v(Math::sin(i/32.0*Math_PI*2),Math::cos(i/32.0*Math_PI*2));
+ if (i>0) {
+ draw_line(pv*radius,v*radius,Color(0,0,0.5,0.9));
+ if (dr>0) {
+ draw_line(pv*dr,v*dr,Color(0.5,0,0.0,0.9));
+ }
+ }
+ pv=v;
+ }
+
+ } break;
+ case NOTIFICATION_EXIT_SCENE: {
+ if (owner) {
+ _set_owner(NULL);
+ }
+
+ } break;
+ }
+}
+
+void ParticleAttractor2D::_owner_exited() {
+
+ ERR_FAIL_COND(!owner);
+ owner->attractors.erase(this);
+ owner=NULL;
+}
+
+void ParticleAttractor2D::_update_owner() {
+
+ if (!is_inside_scene() || !has_node(path)) {
+ _set_owner(NULL);
+ return;
+ }
+
+ Node *n = get_node(path);
+ ERR_FAIL_COND(!n);
+ Particles2D *pn = n->cast_to<Particles2D>();
+ if (!pn) {
+ _set_owner(NULL);
+ return;
+ }
+
+ _set_owner(pn);
+}
+
+void ParticleAttractor2D::_set_owner(Particles2D* p_owner) {
+
+ if (owner==p_owner)
+ return;
+
+ if (owner) {
+ owner->disconnect("exit_scene",this,"_owner_exited");
+ owner->attractors.erase(this);
+ owner=NULL;
+ }
+ owner=p_owner;
+
+ if (owner) {
+
+ owner->connect("exit_scene",this,"_owner_exited",varray(),CONNECT_ONESHOT);
+ owner->attractors.insert(this);
+ }
+}
+
+void ParticleAttractor2D::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_enabled","enabled"),&ParticleAttractor2D::set_enabled);
+ ObjectTypeDB::bind_method(_MD("is_enabled"),&ParticleAttractor2D::is_enabled);
+
+ ObjectTypeDB::bind_method(_MD("set_radius","radius"),&ParticleAttractor2D::set_radius);
+ ObjectTypeDB::bind_method(_MD("get_radius"),&ParticleAttractor2D::get_radius);
+
+ ObjectTypeDB::bind_method(_MD("set_disable_radius","radius"),&ParticleAttractor2D::set_disable_radius);
+ ObjectTypeDB::bind_method(_MD("get_disable_radius"),&ParticleAttractor2D::get_disable_radius);
+
+ ObjectTypeDB::bind_method(_MD("set_gravity","gravity"),&ParticleAttractor2D::set_gravity);
+ ObjectTypeDB::bind_method(_MD("get_gravity"),&ParticleAttractor2D::get_gravity);
+
+ ObjectTypeDB::bind_method(_MD("set_absorption","absorption"),&ParticleAttractor2D::set_absorption);
+ ObjectTypeDB::bind_method(_MD("get_absorption"),&ParticleAttractor2D::get_absorption);
+
+ ObjectTypeDB::bind_method(_MD("set_particles_path","path"),&ParticleAttractor2D::set_particles_path);
+ ObjectTypeDB::bind_method(_MD("get_particles_path"),&ParticleAttractor2D::get_particles_path);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"radius",PROPERTY_HINT_RANGE,"0.1,16000,0.1"),_SCS("set_radius"),_SCS("get_radius"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"disable_radius",PROPERTY_HINT_RANGE,"0.1,16000,0.1"),_SCS("set_disable_radius"),_SCS("get_disable_radius"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"gravity",PROPERTY_HINT_RANGE,"-512,512,0.01"),_SCS("set_gravity"),_SCS("get_gravity"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"absorption",PROPERTY_HINT_RANGE,"0,512,0.01"),_SCS("set_absorption"),_SCS("get_absorption"));
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"particles_path",PROPERTY_HINT_RESOURCE_TYPE,"Particles2D"),_SCS("set_particles_path"),_SCS("get_particles_path"));
+
+
+
+}
+
+
+void ParticleAttractor2D::set_enabled(bool p_enabled) {
+
+ enabled=p_enabled;
+}
+
+bool ParticleAttractor2D::is_enabled() const{
+
+ return enabled;
+}
+
+void ParticleAttractor2D::set_radius(float p_radius) {
+
+ radius = p_radius;
+ update();
+}
+
+float ParticleAttractor2D::get_radius() const {
+
+ return radius;
+}
+
+void ParticleAttractor2D::set_disable_radius(float p_disable_radius) {
+
+ disable_radius = p_disable_radius;
+ update();
+}
+float ParticleAttractor2D::get_disable_radius() const {
+
+ return disable_radius;
+}
+
+void ParticleAttractor2D::set_gravity(float p_gravity) {
+
+ gravity=p_gravity;
+
+}
+float ParticleAttractor2D::get_gravity() const {
+
+ return gravity;
+}
+
+void ParticleAttractor2D::set_absorption(float p_absorption) {
+
+ absorption=p_absorption;
+
+}
+float ParticleAttractor2D::get_absorption() const {
+
+ return absorption;
+}
+
+void ParticleAttractor2D::set_particles_path(NodePath p_path) {
+
+ path=p_path;
+ _update_owner();
+}
+NodePath ParticleAttractor2D::get_particles_path() const {
+
+ return path;
+}
+
+
+
+ParticleAttractor2D::ParticleAttractor2D() {
+
+ owner=NULL;
+ radius=50;
+ disable_radius=0;
+ gravity=100;
+ absorption=0;
+ path=String("..");
+ enabled=true;
+}
+
+/****************************************/
+
+_FORCE_INLINE_ static float _rand_from_seed(uint32_t *seed) {
+
+ uint32_t k;
+ uint32_t s = (*seed);
+ if (s == 0)
+ s = 0x12345987;
+ k = s / 127773;
+ s = 16807 * (s - k * 127773) - 2836 * k;
+ if (s < 0)
+ s += 2147483647;
+ (*seed) = s;
+
+ float v=((float)((*seed) & 0xFFFFF))/(float)0xFFFFF;
+ v=v*2.0-1.0;
+ return v;
+}
+
+void Particles2D::_process_particles(float p_delta) {
+
+ if (particles.size()==0 || lifetime==0)
+ return;
+
+ p_delta*=time_scale;
+
+ float frame_time=p_delta;
+
+ if (emit_timeout > 0) {
+ time_to_live -= frame_time;
+ if (time_to_live < 0) {
+
+ emitting = false;
+ };
+ };
+
+ float next_time = time+frame_time;
+
+ if (next_time > lifetime)
+ next_time=Math::fmod(next_time,lifetime);
+
+
+ Particle *pdata=&particles[0];
+ int particle_count=particles.size();
+ Matrix32 xform;
+ if (!local_space)
+ xform=get_global_transform();
+
+ active_count=0;
+
+ DVector<Point2>::Read r;
+ int emission_point_count=0;
+ if (emission_points.size()) {
+
+ emission_point_count=emission_points.size();
+ r=emission_points.read();
+ }
+
+ int attractor_count=0;
+ AttractorCache *attractor_ptr=NULL;
+
+ if (attractors.size()) {
+ if (attractors.size()!=attractor_cache.size()) {
+ attractor_cache.resize(attractors.size());
+ }
+
+ int idx=0;
+ Matrix32 m;
+ if (local_space) {
+ m= get_global_transform().affine_inverse();
+ }
+ for (Set<ParticleAttractor2D*>::Element *E=attractors.front();E;E=E->next()) {
+
+ attractor_cache[idx].pos=m.xform( E->get()->get_global_pos() );
+ attractor_cache[idx].attractor=E->get();
+ idx++;
+ }
+
+ attractor_ptr=attractor_cache.ptr();
+ attractor_count=attractor_cache.size();
+ }
+
+ for(int i=0;i<particle_count;i++) {
+
+ Particle &p=pdata[i];
+
+ float restart_time = (i * lifetime / particle_count) * explosiveness;
+
+ bool restart=false;
+
+ if ( next_time < time ) {
+
+ if (restart_time > time || restart_time < next_time )
+ restart=true;
+
+ } else if (restart_time > time && restart_time < next_time ) {
+ restart=true;
+ }
+
+ if (restart) {
+
+
+ if (emitting) {
+
+ p.pos=emissor_offset;
+ if (emission_point_count) {
+
+
+ Vector2 ep = r[Math::rand()%emission_point_count];
+ if (!local_space) {
+ p.pos=xform.xform(p.pos+ep*extents);
+ } else {
+ p.pos+=ep*extents;
+ }
+ } else {
+ if (!local_space) {
+ p.pos=xform.xform(p.pos+Vector2(Math::random(-extents.x,extents.x),Math::random(-extents.y,extents.y)));
+ } else {
+ p.pos+=Vector2(Math::random(-extents.x,extents.x),Math::random(-extents.y,extents.y));
+ }
+ }
+ p.seed=Math::rand() % 12345678;
+ uint32_t rand_seed=p.seed*(i+1);
+
+ float angle = Math::deg2rad(param[PARAM_DIRECTION]+_rand_from_seed(&rand_seed)*param[PARAM_SPREAD]);
+
+ p.velocity=Vector2( Math::sin(angle), Math::cos(angle) );
+ if (!local_space) {
+
+ p.velocity = xform.basis_xform(p.velocity).normalized();
+ }
+
+ p.velocity*=param[PARAM_LINEAR_VELOCITY]+param[PARAM_LINEAR_VELOCITY]*_rand_from_seed(&rand_seed)*randomness[PARAM_LINEAR_VELOCITY];
+ p.velocity+=initial_velocity;
+ p.active=true;
+ p.rot=0;
+ active_count++;
+
+
+ } else {
+
+ p.active=false;
+ }
+
+ } else {
+
+ if (!p.active)
+ continue;
+
+ uint32_t rand_seed=p.seed*(i+1);
+
+ Vector2 force;
+
+ //apply gravity
+ float gravity_dir = Math::deg2rad( param[PARAM_GRAVITY_DIRECTION]+180*randomness[PARAM_GRAVITY_DIRECTION]*_rand_from_seed(&rand_seed));
+ force+=Vector2( Math::sin(gravity_dir), Math::cos(gravity_dir) ) * (param[PARAM_GRAVITY_STRENGTH]+param[PARAM_GRAVITY_STRENGTH]*randomness[PARAM_GRAVITY_STRENGTH]*_rand_from_seed(&rand_seed));
+ //apply radial
+ Vector2 rvec = (p.pos - emissor_offset).normalized();
+ force+=rvec*(param[PARAM_RADIAL_ACCEL]+param[PARAM_RADIAL_ACCEL]*randomness[PARAM_RADIAL_ACCEL]*_rand_from_seed(&rand_seed));
+ //apply orbit
+ float orbitvel = (param[PARAM_ORBIT_VELOCITY]+param[PARAM_ORBIT_VELOCITY]*randomness[PARAM_ORBIT_VELOCITY]*_rand_from_seed(&rand_seed));
+ if (orbitvel!=0) {
+ Vector2 rel = p.pos - xform.elements[2];
+ Matrix32 rot(orbitvel*frame_time,Vector2());
+ p.pos = rot.xform(rel) + xform.elements[2];
+
+ }
+
+ Vector2 tvec=rvec.tangent();
+ force+=tvec*(param[PARAM_TANGENTIAL_ACCEL]+param[PARAM_TANGENTIAL_ACCEL]*randomness[PARAM_TANGENTIAL_ACCEL]*_rand_from_seed(&rand_seed));
+
+ for(int j=0;j<attractor_count;j++) {
+
+ Vector2 vec = (attractor_ptr[j].pos - p.pos);
+ float vl = vec.length();
+
+ if (!attractor_ptr[j].attractor->enabled || vl==0 || vl > attractor_ptr[j].attractor->radius)
+ continue;
+
+
+
+ force+=vec*attractor_ptr[j].attractor->gravity;
+ float fvl = p.velocity.length();
+ if (fvl && attractor_ptr[j].attractor->absorption) {
+ Vector2 target = vec.normalized();
+ p.velocity = p.velocity.normalized().linear_interpolate(target,MIN(frame_time*attractor_ptr[j].attractor->absorption,1))*fvl;
+ }
+
+ if (attractor_ptr[j].attractor->disable_radius && vl < attractor_ptr[j].attractor->disable_radius) {
+ p.active=false;
+ }
+ }
+
+ p.velocity+=force*frame_time;
+
+ if (param[PARAM_DAMPING]) {
+ float dmp = param[PARAM_DAMPING]+param[PARAM_DAMPING]*randomness[PARAM_DAMPING]*_rand_from_seed(&rand_seed);
+ float v = p.velocity.length();
+ v -= dmp * frame_time;
+ if (v<=0) {
+ p.velocity=Vector2();
+ } else {
+ p.velocity=p.velocity.normalized() * v;
+ }
+
+ }
+
+ p.pos+=p.velocity*frame_time;
+ p.rot+=Math::lerp(param[PARAM_SPIN_VELOCITY],param[PARAM_SPIN_VELOCITY]*randomness[PARAM_SPIN_VELOCITY]*_rand_from_seed(&rand_seed),randomness[PARAM_SPIN_VELOCITY])*frame_time;
+
+ active_count++;
+
+ }
+
+
+ }
+
+
+
+ time=Math::fmod( time+frame_time, lifetime );
+ if (!emitting && active_count==0) {
+ set_process(false);
+
+ }
+
+ update();
+
+
+}
+
+
+void Particles2D::_notification(int p_what) {
+
+ switch(p_what) {
+
+ case NOTIFICATION_PROCESS: {
+
+ _process_particles( get_process_delta_time() );
+ } break;
+
+ case NOTIFICATION_ENTER_SCENE: {
+
+ float ppt=preprocess;
+ while(ppt>0) {
+ _process_particles(0.1);
+ ppt-=0.1;
+ }
+ } break;
+ case NOTIFICATION_DRAW: {
+
+
+ if (particles.size()==0 || lifetime==0)
+ return;
+
+ RID ci=get_canvas_item();
+ Size2 size(1,1);
+ Point2 center;
+
+ if (!texture.is_null()) {
+ size=texture->get_size();
+ }
+
+
+ float time_pos=(time/lifetime);
+
+ Particle *pdata=&particles[0];
+ int particle_count=particles.size();
+ Rect2 r(Point2(),size);
+ RID texrid;
+
+ if (texture.is_valid())
+ texrid = texture->get_rid();
+
+ Matrix32 invxform;
+ if (!local_space)
+ invxform=get_global_transform().affine_inverse();
+
+ int col_count=0;
+ float last=-1;
+ ColorPhase cphase[MAX_COLOR_PHASES];
+
+ for(int i=0;i<color_phase_count;i++) {
+
+ if (color_phases[i].pos<=last)
+ break;
+ cphase[i]=color_phases[i];
+ col_count++;
+ }
+
+
+ for(int i=0;i<particle_count;i++) {
+
+ Particle &p=pdata[i];
+ if (!p.active)
+ continue;
+
+ float ptime = ((float)i / particle_count)*explosiveness;
+
+ if (ptime<time_pos)
+ ptime=time_pos-ptime;
+ else
+ ptime=(1.0-ptime)+time_pos;
+
+ uint32_t rand_seed=p.seed*(i+1);
+
+
+ int cpos=0;
+
+ while(cpos<col_count) {
+
+ if (cphase[cpos].pos > ptime)
+ break;
+ cpos++;
+ }
+
+ cpos--;
+
+ Color color;
+ //could be faster..
+ if (cpos==-1)
+ color=Color(1,1,1,1);
+ else {
+ if (cpos==col_count-1)
+ color=cphase[cpos].color;
+ else {
+ float diff = (cphase[cpos+1].pos-cphase[cpos].pos);
+ if (diff>0)
+ color=cphase[cpos].color.linear_interpolate(cphase[cpos+1].color, (ptime - cphase[cpos].pos) / diff );
+ else
+ color=cphase[cpos+1].color;
+ }
+ }
+
+
+ {
+ float huerand=_rand_from_seed(&rand_seed);
+ float huerot = param[PARAM_HUE_VARIATION] + randomness[PARAM_HUE_VARIATION] * huerand;
+
+ if (Math::abs(huerot) > CMP_EPSILON) {
+
+ float h=color.get_h();
+ float s=color.get_s();
+ float v=color.get_v();
+ float a=color.a;
+ //float preh=h;
+ h+=huerot;
+ h=Math::abs(Math::fposmod(h,1.0));
+ //print_line("rand: "+rtos(randomness[PARAM_HUE_VARIATION])+" rand: "+rtos(huerand));
+ //print_line(itos(i)+":hue: "+rtos(preh)+" + "+rtos(huerot)+" = "+rtos(h));
+ color.set_hsv(h,s,v);
+ color.a=a;
+ }
+ }
+
+ float initial_size = param[PARAM_INITIAL_SIZE]+param[PARAM_INITIAL_SIZE]*_rand_from_seed(&rand_seed)*randomness[PARAM_FINAL_SIZE];
+ float final_size = param[PARAM_FINAL_SIZE]+param[PARAM_FINAL_SIZE]*_rand_from_seed(&rand_seed)*randomness[PARAM_FINAL_SIZE];
+
+ float size_mult=initial_size*(1.0-ptime) + final_size*ptime;
+
+ //Size2 rectsize=size * size_mult;
+ //rectsize=rectsize.floor();
+
+ //Rect2 r = Rect2(Vecto,rectsize);
+
+ Matrix32 xform;
+
+ if (p.rot) {
+
+ xform.set_rotation(p.rot);
+ xform.translate(-size*size_mult/2.0);
+ xform.elements[2]+=p.pos;
+ } else {
+ xform.elements[2]=-size*size_mult/2.0;
+ xform.elements[2]+=p.pos;
+ }
+
+ if (!local_space) {
+ xform = invxform * xform;
+ }
+
+
+ xform.scale_basis(Size2(size_mult,size_mult));
+
+
+ VisualServer::get_singleton()->canvas_item_add_set_transform(ci,xform);
+
+
+ if (texrid.is_valid()) {
+
+ VisualServer::get_singleton()->canvas_item_add_texture_rect(ci,r,texrid,false,color);
+ } else {
+ VisualServer::get_singleton()->canvas_item_add_rect(ci,r,color);
+
+ }
+
+ }
+
+
+ } break;
+
+ }
+
+}
+
+static const char* _particlesframe_property_names[Particles2D::PARAM_MAX]={
+ "params/direction",
+ "params/spread",
+ "params/linear_velocity",
+ "params/spin_velocity",
+ "params/orbit_velocity",
+ "params/gravity_direction",
+ "params/gravity_strength",
+ "params/radial_accel",
+ "params/tangential_accel",
+ "params/damping",
+ "params/initial_size",
+ "params/final_size",
+ "params/hue_variation"
+};
+
+static const char* _particlesframe_property_rnames[Particles2D::PARAM_MAX]={
+ "randomness/direction",
+ "randomness/spread",
+ "randomness/linear_velocity",
+ "randomness/spin_velocity",
+ "randomness/orbit_velocity",
+ "randomness/gravity_direction",
+ "randomness/gravity_strength",
+ "randomness/radial_accel",
+ "randomness/tangential_accel",
+ "randomness/damping",
+ "randomness/initial_size",
+ "randomness/final_size",
+ "randomness/hue_variation"
+};
+
+static const char* _particlesframe_property_ranges[Particles2D::PARAM_MAX]={
+ "0,360,0.01",
+ "0,180,0.01",
+ "-1024,1024,0.01",
+ "-1024,1024,0.01",
+ "-1024,1024,0.01",
+ "0,360,0.01",
+ "0,1024,0.01",
+ "-128,128,0.01",
+ "-128,128,0.01",
+ "0,1024,0.001",
+ "0,1024,0.01",
+ "0,1024,0.01",
+ "0,1,0.01"
+};
+
+
+void Particles2D::set_emitting(bool p_emitting) {
+
+ if (emitting==p_emitting)
+ return;
+
+ if (p_emitting) {
+
+ if (active_count==0)
+ time=0;
+ set_process(true);
+ time_to_live = emit_timeout;
+ };
+ emitting=p_emitting;
+}
+
+bool Particles2D::is_emitting() const {
+
+ return emitting;
+}
+
+void Particles2D::set_amount(int p_amount) {
+
+ ERR_FAIL_INDEX(p_amount,1024);
+
+ particles.resize(p_amount);
+}
+int Particles2D::get_amount() const {
+
+ return particles.size();
+}
+
+void Particles2D::set_emit_timeout(float p_timeout) {
+
+ emit_timeout = p_timeout;
+ time_to_live = p_timeout;
+};
+
+float Particles2D::get_emit_timeout() const {
+
+ return emit_timeout;
+};
+
+void Particles2D::set_lifetime(float p_lifetime) {
+
+ ERR_FAIL_INDEX(p_lifetime,3600);
+
+ lifetime=p_lifetime;
+}
+float Particles2D::get_lifetime() const {
+
+ return lifetime;
+}
+
+void Particles2D::set_time_scale(float p_time_scale) {
+
+ time_scale=p_time_scale;
+}
+float Particles2D::get_time_scale() const {
+
+ return time_scale;
+}
+
+void Particles2D::set_pre_process_time(float p_pre_process_time) {
+
+ preprocess=p_pre_process_time;
+}
+
+float Particles2D::get_pre_process_time() const{
+
+ return preprocess;
+}
+
+
+void Particles2D::set_param(Parameter p_param, float p_value) {
+
+ ERR_FAIL_INDEX(p_param,PARAM_MAX);
+ param[p_param]=p_value;
+}
+float Particles2D::get_param(Parameter p_param) const {
+
+ ERR_FAIL_INDEX_V(p_param,PARAM_MAX,0);
+ return param[p_param];
+}
+
+void Particles2D::set_randomness(Parameter p_param, float p_value) {
+
+ ERR_FAIL_INDEX(p_param,PARAM_MAX);
+ randomness[p_param]=p_value;
+
+}
+float Particles2D::get_randomness(Parameter p_param) const {
+
+ ERR_FAIL_INDEX_V(p_param,PARAM_MAX,0);
+ return randomness[p_param];
+
+}
+
+void Particles2D::set_texture(const Ref<Texture>& p_texture) {
+
+ texture=p_texture;
+}
+
+Ref<Texture> Particles2D::get_texture() const {
+
+ return texture;
+}
+
+void Particles2D::set_emissor_offset(const Point2& p_offset) {
+
+ emissor_offset=p_offset;
+}
+
+Point2 Particles2D::get_emissor_offset() const {
+
+ return emissor_offset;
+}
+
+
+void Particles2D::set_use_local_space(bool p_use) {
+
+ local_space=p_use;
+}
+
+bool Particles2D::is_using_local_space() const {
+
+ return local_space;
+}
+
+
+void Particles2D::set_color_phases(int p_phases) {
+
+ ERR_FAIL_INDEX(p_phases,MAX_COLOR_PHASES+1);
+ color_phase_count=p_phases;
+}
+
+int Particles2D::get_color_phases() const {
+
+ return color_phase_count;
+}
+
+void Particles2D::set_color_phase_color(int p_phase,const Color& p_color) {
+
+ ERR_FAIL_INDEX(p_phase,MAX_COLOR_PHASES);
+ color_phases[p_phase].color=p_color;
+
+}
+Color Particles2D::get_color_phase_color(int p_phase) const {
+
+ ERR_FAIL_INDEX_V(p_phase,MAX_COLOR_PHASES,Color());
+ return color_phases[p_phase].color;
+}
+
+void Particles2D::set_color_phase_pos(int p_phase,float p_pos) {
+ ERR_FAIL_INDEX(p_phase,MAX_COLOR_PHASES);
+ ERR_FAIL_COND(p_pos<0.0 || p_pos>1.0);
+ color_phases[p_phase].pos=p_pos;
+
+}
+float Particles2D::get_color_phase_pos(int p_phase) const {
+
+ ERR_FAIL_INDEX_V(p_phase,MAX_COLOR_PHASES,0);
+ return color_phases[p_phase].pos;
+}
+
+void Particles2D::set_emission_half_extents(const Vector2& p_extents) {
+
+ extents=p_extents;
+}
+
+Vector2 Particles2D::get_emission_half_extents() const {
+
+ return extents;
+}
+
+void Particles2D::testee(int a, int b, int c, int d, int e) {
+
+ print_line(itos(a));
+ print_line(itos(b));
+ print_line(itos(c));
+ print_line(itos(d));
+ print_line(itos(e));
+}
+
+void Particles2D::set_initial_velocity(const Vector2& p_velocity) {
+
+
+ initial_velocity=p_velocity;
+}
+Vector2 Particles2D::get_initial_velocity() const{
+
+ return initial_velocity;
+}
+
+
+void Particles2D::pre_process(float p_delta) {
+
+ _process_particles(p_delta);
+}
+
+
+void Particles2D::set_explosiveness(float p_value) {
+
+ explosiveness=p_value;
+}
+
+float Particles2D::get_explosiveness() const{
+
+ return explosiveness;
+}
+
+void Particles2D::set_emission_points(const DVector<Vector2>& p_points) {
+
+ emission_points=p_points;
+}
+
+DVector<Vector2> Particles2D::get_emission_points() const{
+
+ return emission_points;
+}
+
+void Particles2D::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_emitting","active"),&Particles2D::set_emitting);
+ ObjectTypeDB::bind_method(_MD("is_emitting"),&Particles2D::is_emitting);
+
+ ObjectTypeDB::bind_method(_MD("set_amount","amount"),&Particles2D::set_amount);
+ ObjectTypeDB::bind_method(_MD("get_amount"),&Particles2D::get_amount);
+
+ ObjectTypeDB::bind_method(_MD("set_lifetime","lifetime"),&Particles2D::set_lifetime);
+ ObjectTypeDB::bind_method(_MD("get_lifetime"),&Particles2D::get_lifetime);
+
+ ObjectTypeDB::bind_method(_MD("set_time_scale","time_scale"),&Particles2D::set_time_scale);
+ ObjectTypeDB::bind_method(_MD("get_time_scale"),&Particles2D::get_time_scale);
+
+ ObjectTypeDB::bind_method(_MD("set_pre_process_time","time"),&Particles2D::set_pre_process_time);
+ ObjectTypeDB::bind_method(_MD("get_pre_process_time"),&Particles2D::get_pre_process_time);
+
+ ObjectTypeDB::bind_method(_MD("set_emit_timeout","value"),&Particles2D::set_emit_timeout);
+ ObjectTypeDB::bind_method(_MD("get_emit_timeout"),&Particles2D::get_emit_timeout);
+
+ ObjectTypeDB::bind_method(_MD("set_param","param","value"),&Particles2D::set_param);
+ ObjectTypeDB::bind_method(_MD("get_param","param"),&Particles2D::get_param);
+
+ ObjectTypeDB::bind_method(_MD("set_randomness","param","value"),&Particles2D::set_randomness);
+ ObjectTypeDB::bind_method(_MD("get_randomness","param"),&Particles2D::get_randomness);
+
+ ObjectTypeDB::bind_method(_MD("set_texture:Texture","texture"),&Particles2D::set_texture);
+ ObjectTypeDB::bind_method(_MD("get_texture:Texture"),&Particles2D::get_texture);
+
+ ObjectTypeDB::bind_method(_MD("set_emissor_offset","offset"),&Particles2D::set_emissor_offset);
+ ObjectTypeDB::bind_method(_MD("get_emissor_offset"),&Particles2D::get_emissor_offset);
+
+ ObjectTypeDB::bind_method(_MD("set_emission_half_extents","extents"),&Particles2D::set_emission_half_extents);
+ ObjectTypeDB::bind_method(_MD("get_emission_half_extents"),&Particles2D::get_emission_half_extents);
+
+ ObjectTypeDB::bind_method(_MD("set_color_phases","phases"),&Particles2D::set_color_phases);
+ ObjectTypeDB::bind_method(_MD("get_color_phases"),&Particles2D::get_color_phases);
+
+ ObjectTypeDB::bind_method(_MD("set_color_phase_color","phase","color"),&Particles2D::set_color_phase_color);
+ ObjectTypeDB::bind_method(_MD("get_color_phase_color","phase"),&Particles2D::get_color_phase_color);
+
+ ObjectTypeDB::bind_method(_MD("set_color_phase_pos","phase","pos"),&Particles2D::set_color_phase_pos);
+ ObjectTypeDB::bind_method(_MD("get_color_phase_pos","phase"),&Particles2D::get_color_phase_pos);
+
+ ObjectTypeDB::bind_method(_MD("pre_process","time"),&Particles2D::pre_process);
+
+ ObjectTypeDB::bind_method(_MD("set_use_local_space","enable"),&Particles2D::set_use_local_space);
+ ObjectTypeDB::bind_method(_MD("is_using_local_space"),&Particles2D::is_using_local_space);
+
+ ObjectTypeDB::bind_method(_MD("set_initial_velocity","velocity"),&Particles2D::set_initial_velocity);
+ ObjectTypeDB::bind_method(_MD("get_initial_velocity"),&Particles2D::get_initial_velocity);
+
+ ObjectTypeDB::bind_method(_MD("set_explosiveness","amount"),&Particles2D::set_explosiveness);
+ ObjectTypeDB::bind_method(_MD("get_explosiveness"),&Particles2D::get_explosiveness);
+
+ ObjectTypeDB::bind_method(_MD("set_emission_points","points"),&Particles2D::set_emission_points);
+ ObjectTypeDB::bind_method(_MD("get_emission_points"),&Particles2D::get_emission_points);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"config/amount",PROPERTY_HINT_EXP_RANGE,"1,1024"),_SCS("set_amount"),_SCS("get_amount") );
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"config/lifetime",PROPERTY_HINT_EXP_RANGE,"0.1,3600,0.1"),_SCS("set_lifetime"),_SCS("get_lifetime") );
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"config/time_scale",PROPERTY_HINT_EXP_RANGE,"0.01,128,0.01"),_SCS("set_time_scale"),_SCS("get_time_scale") );
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"config/preprocess",PROPERTY_HINT_EXP_RANGE,"0.1,3600,0.1"),_SCS("set_pre_process_time"),_SCS("get_pre_process_time") );
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"config/emit_timeout",PROPERTY_HINT_RANGE,"0,3600,0.1"),_SCS("set_emit_timeout"),_SCS("get_emit_timeout") );
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL,"config/emitting"),_SCS("set_emitting"),_SCS("is_emitting") );
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"config/offset"),_SCS("set_emissor_offset"),_SCS("get_emissor_offset"));
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"config/half_extents"),_SCS("set_emission_half_extents"),_SCS("get_emission_half_extents"));
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL,"config/local_space"),_SCS("set_use_local_space"),_SCS("is_using_local_space"));
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"config/explosiveness",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_explosiveness"),_SCS("get_explosiveness"));
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"config/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"));
+
+
+ for(int i=0;i<PARAM_MAX;i++) {
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,_particlesframe_property_names[i],PROPERTY_HINT_RANGE,_particlesframe_property_ranges[i]),_SCS("set_param"),_SCS("get_param"),i);
+ }
+
+ for(int i=0;i<PARAM_MAX;i++) {
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL,_particlesframe_property_rnames[i],PROPERTY_HINT_RANGE,"-1,1,0.01"),_SCS("set_randomness"),_SCS("get_randomness"),i);
+ }
+
+ ADD_PROPERTY( PropertyInfo( Variant::INT, "color_phases/count",PROPERTY_HINT_RANGE,"0,4,1"), _SCS("set_color_phases"), _SCS("get_color_phases"));
+
+ for(int i=0;i<MAX_COLOR_PHASES;i++) {
+ String phase="phase_"+itos(i)+"/";
+ ADD_PROPERTYI( PropertyInfo( Variant::REAL, phase+"pos", PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_color_phase_pos"),_SCS("get_color_phase_pos"),i );
+ ADD_PROPERTYI( PropertyInfo( Variant::COLOR, phase+"color"),_SCS("set_color_phase_color"),_SCS("get_color_phase_color"),i );
+ }
+
+
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2_ARRAY,"emission_points",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_emission_points"),_SCS("get_emission_points"));
+
+ BIND_CONSTANT( PARAM_DIRECTION );
+ BIND_CONSTANT( PARAM_SPREAD );
+ BIND_CONSTANT( PARAM_LINEAR_VELOCITY );
+ BIND_CONSTANT( PARAM_SPIN_VELOCITY );
+ BIND_CONSTANT( PARAM_GRAVITY_DIRECTION );
+ BIND_CONSTANT( PARAM_GRAVITY_STRENGTH );
+ BIND_CONSTANT( PARAM_RADIAL_ACCEL );
+ BIND_CONSTANT( PARAM_TANGENTIAL_ACCEL );
+ BIND_CONSTANT( PARAM_INITIAL_SIZE );
+ BIND_CONSTANT( PARAM_FINAL_SIZE );
+ BIND_CONSTANT( PARAM_HUE_VARIATION );
+ BIND_CONSTANT( PARAM_MAX );
+
+ BIND_CONSTANT( MAX_COLOR_PHASES );
+
+}
+
+
+
+Particles2D::Particles2D() {
+
+ for(int i=0;i<PARAM_MAX;i++) {
+
+ param[i]=0;
+ randomness[i]=0;
+ }
+
+
+ set_param(PARAM_SPREAD,10);
+ set_param(PARAM_LINEAR_VELOCITY,20);
+ set_param(PARAM_GRAVITY_STRENGTH,9.8);
+ set_param(PARAM_RADIAL_ACCEL,0);
+ set_param(PARAM_TANGENTIAL_ACCEL,0);
+ set_param(PARAM_INITIAL_SIZE,1.0);
+ set_param(PARAM_FINAL_SIZE,1.0);
+
+
+ time=0;
+ lifetime=2;
+ emitting=false;
+ particles.resize(32);
+ active_count=-1;
+ set_emitting(true);
+ local_space=true;
+ preprocess=0;
+ time_scale=1.0;
+
+ color_phase_count=1;
+
+ 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));
+
+ emit_timeout = 0;
+ time_to_live = 0;
+ explosiveness=1.0;
+}