• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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