f@5
|
1 /*
|
f@5
|
2
|
f@5
|
3 Copyright (C) 2015 Fiore Martin
|
f@5
|
4 Copyright (C) 2016 Queen Mary University of London
|
f@5
|
5 Author: Fiore Martin
|
f@5
|
6
|
f@5
|
7 This file is part of Collidoscope.
|
f@5
|
8
|
f@5
|
9 Collidoscope is free software: you can redistribute it and/or modify
|
f@5
|
10 it under the terms of the GNU General Public License as published by
|
f@5
|
11 the Free Software Foundation, either version 3 of the License, or
|
f@5
|
12 (at your option) any later version.
|
f@5
|
13
|
f@5
|
14 This program is distributed in the hope that it will be useful,
|
f@5
|
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
f@5
|
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
f@5
|
17 GNU General Public License for more details.
|
f@5
|
18
|
f@5
|
19 You should have received a copy of the GNU General Public License
|
f@5
|
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
f@5
|
21
|
f@5
|
22 */
|
f@5
|
23
|
f@0
|
24 #include "ParticleController.h"
|
f@0
|
25 #include "cinder/Rand.h"
|
f@0
|
26
|
f@0
|
27 #include <type_traits>
|
f@0
|
28
|
f@0
|
29 using namespace ci;
|
f@0
|
30 using std::list;
|
f@0
|
31
|
f@0
|
32 ParticleController::ParticleController() :
|
f@0
|
33 mNumParticles( 0 )
|
f@0
|
34
|
f@0
|
35 {
|
f@16
|
36 // uses Cinder (and OpenGL) drawing based on virtual buffer object
|
f@4
|
37 // see ParticleSphereCPU example in Cinder library
|
f@4
|
38
|
f@0
|
39 mParticles.assign( kMaxParticles, Particle() );
|
f@0
|
40 mParticlePositions.assign( kMaxParticles, vec2( -1, -1 ) );
|
f@0
|
41
|
f@0
|
42 mParticleVbo = gl::Vbo::create( GL_ARRAY_BUFFER, mParticlePositions, GL_DYNAMIC_DRAW );
|
f@0
|
43
|
f@0
|
44 geom::BufferLayout particleLayout;
|
f@0
|
45 particleLayout.append( geom::Attrib::POSITION, 2, sizeof( vec2 ), 0 );
|
f@0
|
46
|
f@0
|
47 auto mesh = gl::VboMesh::create( mParticlePositions.size(), GL_POINTS, { { particleLayout, mParticleVbo } } );
|
f@0
|
48
|
f@4
|
49 // creates glsl program to run the batch with
|
f@0
|
50 #if ! defined( CINDER_GL_ES )
|
f@0
|
51 auto glsl = gl::GlslProg::create( gl::GlslProg::Format()
|
f@0
|
52 .vertex( CI_GLSL( 150,
|
f@0
|
53 uniform mat4 ciModelViewProjection;
|
f@0
|
54 in vec4 ciPosition;
|
f@0
|
55
|
f@0
|
56 void main( void ) {
|
f@0
|
57 gl_Position = ciModelViewProjection * ciPosition;
|
f@0
|
58 gl_PointSize = 1.0;
|
f@0
|
59 }
|
f@0
|
60 ) )
|
f@0
|
61 .fragment( CI_GLSL( 150,
|
f@0
|
62 out vec4 oColor;
|
f@0
|
63
|
f@0
|
64 void main( void ) {
|
f@0
|
65 oColor = vec4( 1.0f, 1.0f, 1.0f, 1.0f );
|
f@0
|
66 }
|
f@0
|
67 ) )
|
f@0
|
68 );
|
f@0
|
69
|
f@0
|
70 mParticleBatch = gl::Batch::create( mesh, glsl );
|
f@0
|
71
|
f@0
|
72 #else
|
f@0
|
73 auto glsl = gl::GlslProg::create( gl::GlslProg::Format()
|
f@0
|
74 .vertex( CI_GLSL( 100,
|
f@0
|
75 uniform mat4 ciModelViewProjection;
|
f@0
|
76 attribute vec4 ciPosition;
|
f@0
|
77
|
f@0
|
78 void main( void ) {
|
f@0
|
79 gl_Position = ciModelViewProjection * ciPosition;
|
f@0
|
80 gl_PointSize = 1.0;
|
f@0
|
81 }
|
f@0
|
82 ) )
|
f@0
|
83 .fragment( CI_GLSL( 100,
|
f@0
|
84 precision highp float;
|
f@0
|
85
|
f@0
|
86 void main( void ) {
|
f@0
|
87 gl_FragColor = vec4( 1, 1, 1, 1 );
|
f@0
|
88 }
|
f@0
|
89 ) )
|
f@0
|
90 );
|
f@0
|
91
|
f@0
|
92 mParticleBatch = gl::Batch::create( mesh, glsl );
|
f@0
|
93 #endif
|
f@0
|
94
|
f@0
|
95
|
f@0
|
96 }
|
f@0
|
97
|
f@0
|
98 void ParticleController::updateParticles()
|
f@0
|
99 {
|
f@16
|
100 // update the positions of the particles and dispose them if they've reached their timespan
|
f@0
|
101 for ( size_t i = 0; i < mNumParticles; i++ ){
|
f@0
|
102
|
f@0
|
103 Particle &particle = mParticles[i];
|
f@0
|
104 vec2 &pos = mParticlePositions[i];
|
f@0
|
105
|
f@0
|
106 particle.mAge++;
|
f@0
|
107
|
f@0
|
108
|
f@0
|
109 if ( (!particle.mFlyOver && particle.mAge > particle.mLifespan)
|
f@0
|
110 || (particle.mFlyOver && particle.mAge >= 300) ){
|
f@0
|
111 // dispose particle
|
f@0
|
112 mParticles[i] = mParticles[mNumParticles - 1];
|
f@0
|
113 mParticlePositions[i] = mParticlePositions[mNumParticles - 1];
|
f@0
|
114 mParticlePositions[mNumParticles - 1].x = -1.0f;
|
f@0
|
115 mParticlePositions[mNumParticles - 1].y = -1.0f;
|
f@0
|
116 mNumParticles--;
|
f@0
|
117 continue;
|
f@0
|
118 }
|
f@0
|
119
|
f@0
|
120 pos += particle.mVel;
|
f@0
|
121 if ( ci::distance( pos, particle.mCloudCenter ) > particle.mCloudSize && !particle.mFlyOver ){
|
f@0
|
122 particle.mVel = rotate<float>( particle.mVel, 5 );
|
f@0
|
123 }
|
f@0
|
124 }
|
f@0
|
125
|
f@4
|
126 // Copy particle data onto the GPU.
|
f@4
|
127 // Map the GPU memory and write over it.
|
f@0
|
128 void *gpuMem = mParticleVbo->mapReplace();
|
f@0
|
129 memcpy( gpuMem, mParticlePositions.data(), mParticlePositions.size() * sizeof( vec2 ) );
|
f@0
|
130 mParticleVbo->unmap();
|
f@0
|
131 }
|
f@0
|
132
|
f@0
|
133 void ParticleController::addParticles(int amount, const vec2 &initialLocation, const float cloudSize)
|
f@0
|
134 {
|
f@16
|
135 // reduce the particles linearly to the total number of particles already present
|
f@4
|
136 // the more particles aleary present the less particle are added
|
f@0
|
137 int reduction = ci::lmap<int>(mNumParticles, 0, kMaxParticles, 0, kMaxParticleAdd);
|
f@0
|
138 amount -= reduction;
|
f@0
|
139
|
f@0
|
140 if ( mNumParticles + amount > kMaxParticles ){
|
f@4
|
141 //a.k.a. return if reached kMaxParticles
|
f@0
|
142 amount = kMaxParticles - mNumParticles;
|
f@0
|
143 }
|
f@0
|
144
|
f@0
|
145 if( amount <= 0 )
|
f@0
|
146 return;
|
f@0
|
147
|
f@0
|
148 for( size_t i = 0; i < amount; i++ ){
|
f@0
|
149 // init new particle
|
f@0
|
150 Particle &particle = mParticles[mNumParticles + i];
|
f@0
|
151 vec2 &pos = mParticlePositions[mNumParticles + i];
|
f@0
|
152
|
f@0
|
153 pos = initialLocation + Rand::randVec2() * 5.0f; // find a location nearby the initial location
|
f@0
|
154 particle.mCloudCenter = pos;
|
f@0
|
155 particle.mVel = Rand::randVec2() * Rand::randFloat( 1.0f, 5.0f );
|
f@0
|
156 particle.mCloudSize = cloudSize;
|
f@0
|
157 particle.mAge = 0;
|
f@0
|
158 particle.mLifespan = Rand::randInt( 30, 60 );
|
f@0
|
159 particle.mFlyOver = (Rand::randInt( 500 ) == 0);
|
f@0
|
160
|
f@0
|
161 }
|
f@0
|
162
|
f@0
|
163 mNumParticles += amount ;
|
f@0
|
164
|
f@0
|
165 }
|
f@0
|
166
|
f@0
|
167
|
f@0
|
168
|