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