f@0
|
1 #include "ParticleController.h"
|
f@0
|
2 #include "cinder/Rand.h"
|
f@0
|
3
|
f@0
|
4 #include <type_traits>
|
f@0
|
5
|
f@0
|
6 using namespace ci;
|
f@0
|
7 using std::list;
|
f@0
|
8
|
f@0
|
9 ParticleController::ParticleController() :
|
f@0
|
10 mNumParticles( 0 )
|
f@0
|
11
|
f@0
|
12 {
|
f@4
|
13 // uses Cinder (and OpenGL) virtual buffer object based drawing
|
f@4
|
14 // see ParticleSphereCPU example in Cinder library
|
f@4
|
15
|
f@0
|
16 mParticles.assign( kMaxParticles, Particle() );
|
f@0
|
17 mParticlePositions.assign( kMaxParticles, vec2( -1, -1 ) );
|
f@0
|
18
|
f@0
|
19 mParticleVbo = gl::Vbo::create( GL_ARRAY_BUFFER, mParticlePositions, GL_DYNAMIC_DRAW );
|
f@0
|
20
|
f@0
|
21 geom::BufferLayout particleLayout;
|
f@0
|
22 particleLayout.append( geom::Attrib::POSITION, 2, sizeof( vec2 ), 0 );
|
f@0
|
23
|
f@0
|
24 auto mesh = gl::VboMesh::create( mParticlePositions.size(), GL_POINTS, { { particleLayout, mParticleVbo } } );
|
f@0
|
25
|
f@4
|
26 // creates glsl program to run the batch with
|
f@0
|
27 #if ! defined( CINDER_GL_ES )
|
f@0
|
28 auto glsl = gl::GlslProg::create( gl::GlslProg::Format()
|
f@0
|
29 .vertex( CI_GLSL( 150,
|
f@0
|
30 uniform mat4 ciModelViewProjection;
|
f@0
|
31 in vec4 ciPosition;
|
f@0
|
32
|
f@0
|
33 void main( void ) {
|
f@0
|
34 gl_Position = ciModelViewProjection * ciPosition;
|
f@0
|
35 gl_PointSize = 1.0;
|
f@0
|
36 }
|
f@0
|
37 ) )
|
f@0
|
38 .fragment( CI_GLSL( 150,
|
f@0
|
39 out vec4 oColor;
|
f@0
|
40
|
f@0
|
41 void main( void ) {
|
f@0
|
42 oColor = vec4( 1.0f, 1.0f, 1.0f, 1.0f );
|
f@0
|
43 }
|
f@0
|
44 ) )
|
f@0
|
45 );
|
f@0
|
46
|
f@0
|
47 mParticleBatch = gl::Batch::create( mesh, glsl );
|
f@0
|
48
|
f@0
|
49 #else
|
f@0
|
50 auto glsl = gl::GlslProg::create( gl::GlslProg::Format()
|
f@0
|
51 .vertex( CI_GLSL( 100,
|
f@0
|
52 uniform mat4 ciModelViewProjection;
|
f@0
|
53 attribute vec4 ciPosition;
|
f@0
|
54
|
f@0
|
55 void main( void ) {
|
f@0
|
56 gl_Position = ciModelViewProjection * ciPosition;
|
f@0
|
57 gl_PointSize = 1.0;
|
f@0
|
58 }
|
f@0
|
59 ) )
|
f@0
|
60 .fragment( CI_GLSL( 100,
|
f@0
|
61 precision highp float;
|
f@0
|
62
|
f@0
|
63 void main( void ) {
|
f@0
|
64 gl_FragColor = vec4( 1, 1, 1, 1 );
|
f@0
|
65 }
|
f@0
|
66 ) )
|
f@0
|
67 );
|
f@0
|
68
|
f@0
|
69 mParticleBatch = gl::Batch::create( mesh, glsl );
|
f@0
|
70 #endif
|
f@0
|
71
|
f@0
|
72
|
f@0
|
73 }
|
f@0
|
74
|
f@0
|
75 void ParticleController::updateParticles()
|
f@0
|
76 {
|
f@4
|
77 // update the positions of the particles and dispose them if they're reached their timespan
|
f@0
|
78 for ( size_t i = 0; i < mNumParticles; i++ ){
|
f@0
|
79
|
f@0
|
80 Particle &particle = mParticles[i];
|
f@0
|
81 vec2 &pos = mParticlePositions[i];
|
f@0
|
82
|
f@0
|
83 particle.mAge++;
|
f@0
|
84
|
f@0
|
85
|
f@0
|
86 if ( (!particle.mFlyOver && particle.mAge > particle.mLifespan)
|
f@0
|
87 || (particle.mFlyOver && particle.mAge >= 300) ){
|
f@0
|
88 // dispose particle
|
f@0
|
89 mParticles[i] = mParticles[mNumParticles - 1];
|
f@0
|
90 mParticlePositions[i] = mParticlePositions[mNumParticles - 1];
|
f@0
|
91 mParticlePositions[mNumParticles - 1].x = -1.0f;
|
f@0
|
92 mParticlePositions[mNumParticles - 1].y = -1.0f;
|
f@0
|
93 mNumParticles--;
|
f@0
|
94 continue;
|
f@0
|
95 }
|
f@0
|
96
|
f@0
|
97 pos += particle.mVel;
|
f@0
|
98 if ( ci::distance( pos, particle.mCloudCenter ) > particle.mCloudSize && !particle.mFlyOver ){
|
f@0
|
99 particle.mVel = rotate<float>( particle.mVel, 5 );
|
f@0
|
100 }
|
f@0
|
101 }
|
f@0
|
102
|
f@4
|
103 // Copy particle data onto the GPU.
|
f@4
|
104 // Map the GPU memory and write over it.
|
f@0
|
105 void *gpuMem = mParticleVbo->mapReplace();
|
f@0
|
106 memcpy( gpuMem, mParticlePositions.data(), mParticlePositions.size() * sizeof( vec2 ) );
|
f@0
|
107 mParticleVbo->unmap();
|
f@0
|
108 }
|
f@0
|
109
|
f@0
|
110 void ParticleController::addParticles(int amount, const vec2 &initialLocation, const float cloudSize)
|
f@0
|
111 {
|
f@4
|
112 // reduce the particles liearly to the total number of particles already present
|
f@4
|
113 // the more particles aleary present the less particle are added
|
f@0
|
114 int reduction = ci::lmap<int>(mNumParticles, 0, kMaxParticles, 0, kMaxParticleAdd);
|
f@0
|
115 amount -= reduction;
|
f@0
|
116
|
f@0
|
117 if ( mNumParticles + amount > kMaxParticles ){
|
f@4
|
118 //a.k.a. return if reached kMaxParticles
|
f@0
|
119 amount = kMaxParticles - mNumParticles;
|
f@0
|
120 }
|
f@0
|
121
|
f@0
|
122 if( amount <= 0 )
|
f@0
|
123 return;
|
f@0
|
124
|
f@0
|
125 for( size_t i = 0; i < amount; i++ ){
|
f@0
|
126 // init new particle
|
f@0
|
127 Particle &particle = mParticles[mNumParticles + i];
|
f@0
|
128 vec2 &pos = mParticlePositions[mNumParticles + i];
|
f@0
|
129
|
f@0
|
130 pos = initialLocation + Rand::randVec2() * 5.0f; // find a location nearby the initial location
|
f@0
|
131 particle.mCloudCenter = pos;
|
f@0
|
132 particle.mVel = Rand::randVec2() * Rand::randFloat( 1.0f, 5.0f );
|
f@0
|
133 particle.mCloudSize = cloudSize;
|
f@0
|
134 particle.mAge = 0;
|
f@0
|
135 particle.mLifespan = Rand::randInt( 30, 60 );
|
f@0
|
136 particle.mFlyOver = (Rand::randInt( 500 ) == 0);
|
f@0
|
137
|
f@0
|
138 }
|
f@0
|
139
|
f@0
|
140 mNumParticles += amount ;
|
f@0
|
141
|
f@0
|
142 }
|
f@0
|
143
|
f@0
|
144
|
f@0
|
145
|