1 //
2 // Copyright 2014 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // Based on ParticleSystem.c from
8 // Book: OpenGL(R) ES 2.0 Programming Guide
9 // Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
10 // ISBN-10: 0321502795
11 // ISBN-13: 9780321502797
12 // Publisher: Addison-Wesley Professional
13 // URLs: http://safari.informit.com/9780321563835
14 // http://www.opengles-book.com
15
16 #include "SampleApplication.h"
17
18 #include "common/vector_utils.h"
19 #include "tga_utils.h"
20 #include "util/random_utils.h"
21 #include "util/shader_utils.h"
22
23 #define _USE_MATH_DEFINES
24 #include <math.h>
25
26 #include <string>
27
28 using namespace angle;
29
30 class ParticleSystemSample : public SampleApplication
31 {
32 public:
ParticleSystemSample(int argc,char ** argv)33 ParticleSystemSample(int argc, char **argv) : SampleApplication("ParticleSystem", argc, argv) {}
34
initialize()35 bool initialize() override
36 {
37 constexpr char kVS[] = R"(uniform float u_time;
38 uniform vec3 u_centerPosition;
39 attribute float a_lifetime;
40 attribute vec3 a_startPosition;
41 attribute vec3 a_endPosition;
42 varying float v_lifetime;
43 void main()
44 {
45 if (u_time <= a_lifetime)
46 {
47 gl_Position.xyz = a_startPosition + (u_time * a_endPosition);
48 gl_Position.xyz += u_centerPosition;
49 gl_Position.w = 1.0;
50 }
51 else
52 {
53 gl_Position = vec4(-1000, -1000, 0, 0);
54 }
55 v_lifetime = 1.0 - (u_time / a_lifetime);
56 v_lifetime = clamp(v_lifetime, 0.0, 1.0);
57 gl_PointSize = (v_lifetime * v_lifetime) * 40.0;
58 })";
59
60 constexpr char kFS[] = R"(precision mediump float;
61 uniform vec4 u_color;
62 varying float v_lifetime;
63 uniform sampler2D s_texture;
64 void main()
65 {
66 vec4 texColor;
67 texColor = texture2D(s_texture, gl_PointCoord);
68 gl_FragColor = vec4(u_color) * texColor;
69 gl_FragColor.a *= v_lifetime;
70 })";
71
72 mProgram = CompileProgram(kVS, kFS);
73 if (!mProgram)
74 {
75 return false;
76 }
77
78 // Get the attribute locations
79 mLifetimeLoc = glGetAttribLocation(mProgram, "a_lifetime");
80 mStartPositionLoc = glGetAttribLocation(mProgram, "a_startPosition");
81 mEndPositionLoc = glGetAttribLocation(mProgram, "a_endPosition");
82
83 // Get the uniform locations
84 mTimeLoc = glGetUniformLocation(mProgram, "u_time");
85 mCenterPositionLoc = glGetUniformLocation(mProgram, "u_centerPosition");
86 mColorLoc = glGetUniformLocation(mProgram, "u_color");
87 mSamplerLoc = glGetUniformLocation(mProgram, "s_texture");
88
89 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
90
91 // Fill in particle data array
92 for (size_t i = 0; i < mParticleCount; i++)
93 {
94 mParticles[i].lifetime = mRNG.randomFloatBetween(0.0f, 1.0f);
95
96 float endAngle = mRNG.randomFloatBetween(0, 2.0f * float(M_PI));
97 float endRadius = mRNG.randomFloatBetween(0.0f, 2.0f);
98 mParticles[i].endPosition.x() = sinf(endAngle) * endRadius;
99 mParticles[i].endPosition.y() = cosf(endAngle) * endRadius;
100 mParticles[i].endPosition.z() = 0.0f;
101
102 float startAngle = mRNG.randomFloatBetween(0, 2.0f * float(M_PI));
103 float startRadius = mRNG.randomFloatBetween(0.0f, 0.25f);
104 mParticles[i].startPosition.x() = sinf(startAngle) * startRadius;
105 mParticles[i].startPosition.y() = cosf(startAngle) * startRadius;
106 mParticles[i].startPosition.z() = 0.0f;
107 }
108
109 mParticleTime = 1.0f;
110
111 std::stringstream smokeStr;
112 smokeStr << angle::GetExecutableDirectory() << "/smoke.tga";
113
114 TGAImage img;
115 if (!LoadTGAImageFromFile(smokeStr.str(), &img))
116 {
117 return false;
118 }
119 mTextureID = LoadTextureFromTGAImage(img);
120 if (!mTextureID)
121 {
122 return false;
123 }
124
125 return true;
126 }
127
destroy()128 void destroy() override { glDeleteProgram(mProgram); }
129
step(float dt,double totalTime)130 void step(float dt, double totalTime) override
131 {
132 // Use the program object
133 glUseProgram(mProgram);
134
135 mParticleTime += dt;
136 if (mParticleTime >= 1.0f)
137 {
138 mParticleTime = 0.0f;
139
140 // Pick a new start location and color
141 Vector3 centerPos(mRNG.randomFloatBetween(-0.5f, 0.5f),
142 mRNG.randomFloatBetween(-0.5f, 0.5f),
143 mRNG.randomFloatBetween(-0.5f, 0.5f));
144 glUniform3fv(mCenterPositionLoc, 1, centerPos.data());
145
146 // Random color
147 Vector4 color(mRNG.randomFloatBetween(0.0f, 1.0f), mRNG.randomFloatBetween(0.0f, 1.0f),
148 mRNG.randomFloatBetween(0.0f, 1.0f), 0.5f);
149 glUniform4fv(mColorLoc, 1, color.data());
150 }
151
152 // Load uniform time variable
153 glUniform1f(mTimeLoc, mParticleTime);
154 }
155
draw()156 void draw() override
157 {
158 // Set the viewport
159 glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
160
161 // Clear the color buffer
162 glClear(GL_COLOR_BUFFER_BIT);
163
164 // Use the program object
165 glUseProgram(mProgram);
166
167 // Load the vertex attributes
168 glVertexAttribPointer(mLifetimeLoc, 1, GL_FLOAT, GL_FALSE, sizeof(Particle),
169 &mParticles[0].lifetime);
170 glVertexAttribPointer(mEndPositionLoc, 3, GL_FLOAT, GL_FALSE, sizeof(Particle),
171 &mParticles[0].endPosition);
172 glVertexAttribPointer(mStartPositionLoc, 3, GL_FLOAT, GL_FALSE, sizeof(Particle),
173 &mParticles[0].startPosition);
174
175 glEnableVertexAttribArray(mLifetimeLoc);
176 glEnableVertexAttribArray(mEndPositionLoc);
177 glEnableVertexAttribArray(mStartPositionLoc);
178
179 // Blend particles
180 glEnable(GL_BLEND);
181 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
182
183 // Bind the texture
184 glActiveTexture(GL_TEXTURE0);
185 glBindTexture(GL_TEXTURE_2D, mTextureID);
186
187 // Set the sampler texture unit to 0
188 glUniform1i(mSamplerLoc, 0);
189
190 glDrawArrays(GL_POINTS, 0, mParticleCount);
191 }
192
193 private:
194 // Handle to a program object
195 GLuint mProgram;
196
197 // Attribute locations
198 GLint mLifetimeLoc;
199 GLint mStartPositionLoc;
200 GLint mEndPositionLoc;
201
202 // Uniform location
203 GLint mTimeLoc;
204 GLint mColorLoc;
205 GLint mCenterPositionLoc;
206 GLint mSamplerLoc;
207
208 // Texture handle
209 GLuint mTextureID;
210
211 // Particle vertex data
212 struct Particle
213 {
214 float lifetime;
215 Vector3 startPosition;
216 Vector3 endPosition;
217 };
218 static const size_t mParticleCount = 1024;
219 std::array<Particle, mParticleCount> mParticles;
220 float mParticleTime;
221 RNG mRNG;
222 };
223
main(int argc,char ** argv)224 int main(int argc, char **argv)
225 {
226 ParticleSystemSample app(argc, argv);
227 return app.run();
228 }
229