Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* PARTICLE SYSTEM
- Specification format:
- {
- looptime
- looptime_rand
- emitters =
- [
- {
- spawncount
- spawncount_rand
- tempslots
- maxparticles
- spawn_code =
- [
- "RANDBOX; position; vec2(-5,-5); vec2(5,5)"
- "DIRDVG; velocity; vec2(1,0); 1; randf() * 10"
- ]
- tick_code =
- [
- "MAD; velocity; vec2(0,1); dt"
- ]
- }
- ]
- }
- */
- global ParticleSystem =
- {
- ReqArgCounts =
- {
- SET = 2, // assign
- RANDBOX = 3, // randbox
- RANDEXT = 3, // randext
- ADDA = 2, // add_assign
- SUBA = 2, // sub_assign
- MULA = 2, // mul_assign
- DIVA = 2, // div_assign
- ADD = 3, // add
- SUB = 3, // sub
- MUL = 3, // mul
- DIV = 3, // div
- MAD = 3, // multiply_add_assign
- LERPTO = 3, // lerp_to
- DBG = 1, // - (custom code)
- },
- };
- // PUBLIC
- function ParticleSystem.create( psspec )
- {
- PS =
- {
- // spec
- emitters = [],
- looptime = if( @psspec.looptime !== null, toreal( psspec.looptime ), null ),
- looptime_rand = toreal( @psspec.looptime_rand ),
- // state
- playing = false,
- time = 0.0,
- curlooptime = null,
- renderbuf = SS_CreateRenderBuffer(),
- // settings
- offset = vec2(0,0),
- xdir = vec2(1,0),
- emitpos = vec2(0,0),
- emitdir = vec2(1,0),
- };
- foreach( em : psspec.emitters )
- {
- cem = this._compileEmitter( em );
- PS.emitters.push( cem );
- }
- return class( PS, ParticleSystem );
- }
- function ParticleSystem.tick( delta )
- {
- if( this.playing )
- {
- this.time += delta;
- if( this.curlooptime !== null && this.time >= this.curlooptime )
- {
- this.time -= this.curlooptime;
- this._spawn();
- this._regenLoopTime();
- }
- }
- foreach( em : this.emitters )
- em.tick( this, delta );
- }
- function ParticleSystem.draw()
- {
- rb = this.renderbuf;
- foreach( em : this.emitters )
- {
- vcnt = 0;
- rb.begin();
- for( i = 0; i < em.maxparticles; ++i )
- {
- readpos = i * 4;
- if( em.timeleft[ readpos ] <= 0 )
- continue;
- pos = vec2( em.position[ readpos ], em.position[ readpos + 1 ] );
- vel = vec2( em.velocity[ readpos ], em.velocity[ readpos + 1 ] );
- halfsize = em.size[ readpos ] * 0.5;
- angle = em.angle[ readpos ] / M_PI * 180;
- xaxis = vec2( cos( angle ), sin( angle ) ) * halfsize;
- yaxis = xaxis.perp;
- col_r = em.color[ readpos+0 ];
- col_g = em.color[ readpos+1 ];
- col_b = em.color[ readpos+2 ];
- col_a = em.color[ readpos+3 ];
- p1 = pos - xaxis - yaxis;
- p2 = pos + xaxis - yaxis;
- p3 = pos + xaxis + yaxis;
- p4 = pos - xaxis + yaxis;
- rb.f( p1.x, p1.y, 0, 0 ).cf2b( col_r, col_g, col_b, col_a );
- rb.f( p2.x, p2.y, 1, 0 ).cf2b( col_r, col_g, col_b, col_a );
- rb.f( p3.x, p3.y, 1, 1 ).cf2b( col_r, col_g, col_b, col_a );
- rb.f( p3.x, p3.y, 1, 1 ).cf2b( col_r, col_g, col_b, col_a );
- rb.f( p4.x, p4.y, 0, 1 ).cf2b( col_r, col_g, col_b, col_a );
- rb.f( p1.x, p1.y, 0, 0 ).cf2b( col_r, col_g, col_b, col_a );
- vcnt += 6;
- }
- if( em.rendermode == "additive" )
- SS_SetBlending( SS_BLENDOP_ADD, SS_BLEND_SRCALPHA, SS_BLEND_ONE );
- else
- SS_SetBlending( SS_BLENDOP_ADD, SS_BLEND_SRCALPHA, SS_BLEND_INVSRCALPHA );
- rb.draw( em.texture, g_VD_P2T2CC4, 0, vcnt, SS_PT_TRIANGLES );
- }
- SS_SetBlending( SS_BLENDOP_ADD, SS_BLEND_SRCALPHA, SS_BLEND_INVSRCALPHA );
- }
- function ParticleSystem.play()
- {
- this.playing = true;
- this._regenLoopTime();
- this._spawn();
- }
- function ParticleSystem.stop()
- {
- this.playing = false;
- }
- // PRIVATE
- function ParticleSystem._regenLoopTime()
- {
- if( this.looptime !== null )
- {
- this.curlooptime = this.looptime + randf() * this.looptime_rand;
- }
- }
- function ParticleSystem._spawn()
- {
- foreach( em : this.emitters )
- {
- count = toint( em.spawncount + em.spawncount_rand * randf() );
- em.spawn( this, count );
- }
- }
- function ParticleSystem._compileEmitter( emitspec )
- {
- EM =
- {
- // data
- keys = ["position","size","color","angle","timeleft","velocity"],
- spawncount = toreal( @emitspec.spawncount ),
- spawncount_rand = toreal( @emitspec.spawncount_rand ),
- maxparticles = toint( @emitspec.maxparticles ),
- texture = if( @emitspec.texture, SS_CreateTexture( emitspec.texture ), null ),
- rendermode = @emitspec.rendermode,
- // state
- lastparticle = -1,
- };
- if( EM.maxparticles < 1 )
- EM.maxparticles = 100;
- tempslots = toint( @emitspec.tempslots );
- for( i = 0; i < tempslots; ++i )
- EM.keys.push( "tmp" $ i );
- foreach( key : EM.keys )
- EM.(key) = floatarray_buffer( 4 * EM.maxparticles );
- EM.spawn = ParticleSystem._compileEmitterCode( EM, "spawn", emitspec.spawn_code );
- EM.tick = ParticleSystem._compileEmitterCode( EM, "tick", emitspec.tick_code );
- return EM;
- }
- function ParticleSystem._compileEmitterCode( EM, funcname, codelines )
- {
- args = "";
- if( funcname == "tick" ) args = "PS, delta";
- else if( funcname == "spawn" ) args = "PS, count";
- // INTRO
- code = "pse = {}; function pse." $ funcname $ "(" $ args $ "){\n";
- if( funcname == "spawn" )
- {
- foreach( key : EM.keys )
- code $= key $ " = floatarray_buffer( 4 * count );\n";
- }
- else if( funcname == "tick" )
- {
- foreach( key : EM.keys )
- code $= key $ " = this." $ key $ ";\n";
- }
- // PROGRAMMABLE OPS
- code $= "/// BEGIN CODE\n";
- foreach( line : codelines )
- {
- items = array_filter( array_process( string_explode( line, ";" ), function(x){ return string_trim(x); } ) );
- if( !items )
- continue;
- op = string_toupper( items.shift() );
- reqargs = @this.ReqArgCounts[ op ];
- if( reqargs === null )
- return ERROR( "op '" $ op $ "' was not found" );
- if( items.size != reqargs )
- return ERROR( "'" $ op $ "' requires " $ reqargs $ " arguments, " $ items.size $ " given" );
- if( op == "SET" ) code $= items[0] $ ".assign(" $ items[1] $ ");";
- else if( op == "RANDBOX" ) code $= items[0] $ ".randbox(" $ items[1] $ "," $ items[2] $ ");";
- else if( op == "RANDEXT" ) code $= items[0] $ ".randext(" $ items[1] $ "," $ items[2] $ ");";
- else if( op == "ADDA" ) code $= items[0] $ ".add_assign(" $ items[1] $ ");";
- else if( op == "SUBA" ) code $= items[0] $ ".sub_assign(" $ items[1] $ ");";
- else if( op == "MULA" ) code $= items[0] $ ".mul_assign(" $ items[1] $ ");";
- else if( op == "DIVA" ) code $= items[0] $ ".div_assign(" $ items[1] $ ");";
- else if( op == "ADD" ) code $= items[0] $ ".add(" $ items[1] $ "," $ items[2] $ ");";
- else if( op == "SUB" ) code $= items[0] $ ".sub(" $ items[1] $ "," $ items[2] $ ");";
- else if( op == "MUL" ) code $= items[0] $ ".mul(" $ items[1] $ "," $ items[2] $ ");";
- else if( op == "DIV" ) code $= items[0] $ ".div(" $ items[1] $ "," $ items[2] $ ");";
- else if( op == "MAD" ) code $= items[0] $ ".multiply_add_assign(" $ items[1] $ "," $ items[2] $ ");";
- else if( op == "LERPTO" ) code $= items[0] $ ".lerp_to(" $ items[1] $ "," $ items[2] $ ");";
- else if( op == "DBG" ) code $= items[0] $ ";";
- code $= "\n";
- }
- code $= "/// END CODE\n";
- // OUTRO
- if( funcname == "spawn" )
- {
- code $= "for( i = 0; i < count; ++i ){"
- $ "\n\tthis.lastparticle++;"
- $ "\n\tif( this.lastparticle >= this.maxparticles ) this.lastparticle = 0;"
- $ "\n\tfor( j = 0; j < 4; ++j ){"
- $ "\n\t\treadpos = i * 4 + j;"
- $ "\n\t\twritepos = this.lastparticle * 4 + j;";
- foreach( key : EM.keys )
- {
- code $= "\n\t\tthis." $ key $ "[writepos] = " $ key $ "[readpos];";
- }
- code $= "\n\t}";
- code $= "\n}\n";
- }
- else if( funcname == "tick" )
- {
- }
- code $= "}\nreturn pse." $ funcname $ ";";
- // printlns("=========",code,"-------");
- return eval( code );
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement