1 //
2 // Book: OpenGL(R) ES 2.0 Programming Guide
3 // Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
4 // ISBN-10: 0321502795
5 // ISBN-13: 9780321502797
6 // Publisher: Addison-Wesley Professional
7 // URLs: http://safari.informit.com/9780321563835
8 // http://www.opengles-book.com
9 //
10
11 // ParticleSystem.c
12 //
13 // This is an example that demonstrates rendering a particle system
14 // using a vertex shader and point sprites.
15 //
16 #include <stdlib.h>
17 #include <math.h>
18 #include "esUtil.h"
19
20 #define NUM_PARTICLES 2000
21 #define PARTICLE_SIZE 7
22
23 int randomTemp = 8765;
myrandom()24 float myrandom() {
25 int curr = randomTemp;
26 randomTemp = (1140671485 * randomTemp + 12820163) % 4294967296;
27 return ((float)curr) / 4294967296;
28 }
29
30 typedef struct
31 {
32 // Handle to a program object
33 GLuint programObject;
34
35 // Attribute locations
36 GLint lifetimeLoc;
37 GLint startPositionLoc;
38 GLint endPositionLoc;
39
40 // Uniform location
41 GLint timeLoc;
42 GLint colorLoc;
43 GLint centerPositionLoc;
44 GLint samplerLoc;
45
46 // Texture handle
47 GLuint textureId;
48
49 // Particle vertex data
50 GLfloat particleData[ NUM_PARTICLES * PARTICLE_SIZE ];
51
52 // Current time
53 float time;
54
55 GLuint vertexObject;
56 } UserData;
57
58 ///
59 // Load texture from disk
60 //
LoadTexture(char * fileName)61 GLuint LoadTexture ( char *fileName )
62 {
63 int width,
64 height;
65 char *buffer = esLoadTGA ( fileName, &width, &height );
66 GLuint texId;
67
68 if ( buffer == NULL )
69 {
70 esLogMessage ( "Error loading (%s) image.\n", fileName );
71 return 0;
72 }
73
74 glGenTextures ( 1, &texId );
75 glBindTexture ( GL_TEXTURE_2D, texId );
76
77 glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer );
78 glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
79 glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
80 glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
81 glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
82
83 free ( buffer );
84
85 return texId;
86 }
87
88
89 ///
90 // Initialize the shader and program object
91 //
Init(ESContext * esContext)92 int Init ( ESContext *esContext )
93 {
94 UserData *userData = esContext->userData;
95 int i;
96
97 GLbyte vShaderStr[] =
98 "uniform float u_time; \n"
99 "uniform vec3 u_centerPosition; \n"
100 "attribute float a_lifetime; \n"
101 "attribute vec3 a_startPosition; \n"
102 "attribute vec3 a_endPosition; \n"
103 "varying float v_lifetime; \n"
104 "void main() \n"
105 "{ \n"
106 " if ( u_time <= a_lifetime ) \n"
107 " { \n"
108 " gl_Position.xyz = a_startPosition + \n"
109 " (u_time * a_endPosition); \n"
110 " gl_Position.xyz += u_centerPosition; \n"
111 " gl_Position.w = 1.0; \n"
112 " } \n"
113 " else \n"
114 " gl_Position = vec4( -1000, -1000, 0, 0 ); \n"
115 " v_lifetime = 1.0 - ( u_time / a_lifetime ); \n"
116 " v_lifetime = clamp ( v_lifetime, 0.0, 1.0 ); \n"
117 " gl_PointSize = ( v_lifetime * v_lifetime ) * 40.0; \n"
118 "}";
119
120 GLbyte fShaderStr[] =
121 "precision mediump float; \n"
122 "uniform vec4 u_color; \n"
123 "varying float v_lifetime; \n"
124 "uniform sampler2D s_texture; \n"
125 "void main() \n"
126 "{ \n"
127 " vec4 texColor; \n"
128 " texColor = texture2D( s_texture, gl_PointCoord ); \n"
129 " gl_FragColor = vec4( u_color ) * texColor; \n"
130 " gl_FragColor.a *= v_lifetime; \n"
131 "} \n";
132
133 // Load the shaders and get a linked program object
134 userData->programObject = esLoadProgram ( vShaderStr, fShaderStr );
135
136 // Get the attribute locations
137 userData->lifetimeLoc = glGetAttribLocation ( userData->programObject, "a_lifetime" );
138 userData->startPositionLoc = glGetAttribLocation ( userData->programObject, "a_startPosition" );
139 userData->endPositionLoc = glGetAttribLocation ( userData->programObject, "a_endPosition" );
140
141 // Get the uniform locations
142 userData->timeLoc = glGetUniformLocation ( userData->programObject, "u_time" );
143 userData->centerPositionLoc = glGetUniformLocation ( userData->programObject, "u_centerPosition" );
144 userData->colorLoc = glGetUniformLocation ( userData->programObject, "u_color" );
145 userData->samplerLoc = glGetUniformLocation ( userData->programObject, "s_texture" );
146
147 glClearColor ( 0.0f, 0.0f, 0.0f, 1.0f );
148
149 // Fill in particle data array
150 for ( i = 0; i < NUM_PARTICLES; i++ )
151 {
152 GLfloat *particleData = &userData->particleData[i * PARTICLE_SIZE];
153
154 // Lifetime of particle
155 (*particleData++) = myrandom();
156
157 // End position of particle
158 (*particleData++) = myrandom() * 2 - 1.0f;
159 (*particleData++) = myrandom() * 2 - 1.0f;
160 (*particleData++) = myrandom() * 2 - 1.0f;
161
162 // Start position of particle
163 (*particleData++) = myrandom() * 0.25 - 0.125f;
164 (*particleData++) = myrandom() * 0.25 - 0.125f;
165 (*particleData++) = myrandom() * 0.25 - 0.125f;
166 }
167
168 glGenBuffers(1, &userData->vertexObject);
169 glBindBuffer( GL_ARRAY_BUFFER, userData->vertexObject );
170 glBufferData( GL_ARRAY_BUFFER, NUM_PARTICLES * PARTICLE_SIZE * 4, userData->particleData, GL_STATIC_DRAW );
171
172 // Initialize time to cause reset on first update
173 userData->time = 1.0f;
174
175 userData->textureId = LoadTexture ( "smoke.tga" );
176 if ( userData->textureId <= 0 )
177 {
178 return FALSE;
179 }
180
181 return TRUE;
182 }
183
184 ///
185 // Update time-based variables
186 //
Update(ESContext * esContext,float deltaTime)187 void Update ( ESContext *esContext, float deltaTime )
188 {
189 // deltaTime = 0.1;
190 UserData *userData = esContext->userData;
191
192 userData->time += deltaTime;
193
194 if ( userData->time >= 1.0f )
195 {
196 float centerPos[3];
197 float color[4];
198
199 userData->time = 0.0f;
200
201 // Pick a new start location and color
202 centerPos[0] = myrandom() - 0.5f;
203 centerPos[1] = myrandom() - 0.5f;
204 centerPos[2] = myrandom() - 0.5f;
205
206 glUniform3fv ( userData->centerPositionLoc, 1, ¢erPos[0] );
207
208 // Random color
209 color[0] = myrandom() * 0.5 + 0.5f;
210 color[1] = myrandom() * 0.5 + 0.5f;
211 color[2] = myrandom() * 0.5 + 0.5f;
212 color[3] = 1.0;
213
214 glUniform4fv ( userData->colorLoc, 1, &color[0] );
215 }
216
217 // Load uniform time variable
218 glUniform1f ( userData->timeLoc, userData->time );
219 }
220
221 ///
222 // Draw a triangle using the shader pair created in Init()
223 //
Draw(ESContext * esContext)224 void Draw ( ESContext *esContext )
225 {
226 UserData *userData = esContext->userData;
227
228 // Set the viewport
229 glViewport ( 0, 0, esContext->width, esContext->height );
230
231 // Clear the color buffer
232 glClear ( GL_COLOR_BUFFER_BIT );
233
234 // Use the program object
235 glUseProgram ( userData->programObject );
236
237 // Load the vertex attributes
238 glBindBuffer( GL_ARRAY_BUFFER, userData->vertexObject );
239 glVertexAttribPointer ( userData->lifetimeLoc, 1, GL_FLOAT,
240 GL_FALSE, PARTICLE_SIZE * sizeof(GLfloat),
241 0 );
242
243 glVertexAttribPointer ( userData->endPositionLoc, 3, GL_FLOAT,
244 GL_FALSE, PARTICLE_SIZE * sizeof(GLfloat),
245 4 );
246
247 glVertexAttribPointer ( userData->startPositionLoc, 3, GL_FLOAT,
248 GL_FALSE, PARTICLE_SIZE * sizeof(GLfloat),
249 4 * 4 );
250
251
252 glEnableVertexAttribArray ( userData->lifetimeLoc );
253 glEnableVertexAttribArray ( userData->endPositionLoc );
254 glEnableVertexAttribArray ( userData->startPositionLoc );
255 // Blend particles
256 glEnable ( GL_BLEND );
257 glBlendFunc ( GL_SRC_ALPHA, GL_ONE );
258
259 // Bind the texture
260 glActiveTexture ( GL_TEXTURE0 );
261 glBindTexture ( GL_TEXTURE_2D, userData->textureId );
262 //glEnable ( GL_TEXTURE_2D );
263
264 // Set the sampler texture unit to 0
265 glUniform1i ( userData->samplerLoc, 0 );
266
267 Update ( esContext, 133 * 0.001125 );
268
269 glDrawArrays( GL_POINTS, 0, NUM_PARTICLES );
270
271 eglSwapBuffers ( esContext->eglDisplay, esContext->eglSurface );
272 }
273
274 ///
275 // Cleanup
276 //
ShutDown(ESContext * esContext)277 void ShutDown ( ESContext *esContext )
278 {
279 UserData *userData = esContext->userData;
280
281 // Delete texture object
282 glDeleteTextures ( 1, &userData->textureId );
283
284 // Delete program object
285 glDeleteProgram ( userData->programObject );
286 }
287
288
main(int argc,char * argv[])289 int main ( int argc, char *argv[] )
290 {
291 ESContext esContext;
292 UserData userData;
293
294 esInitContext ( &esContext );
295 esContext.userData = &userData;
296
297 esCreateWindow ( &esContext, "ParticleSystem", 320, 240, ES_WINDOW_RGB );
298
299 if ( !Init ( &esContext ) )
300 return 0;
301
302 esRegisterDrawFunc ( &esContext, Draw );
303 // esRegisterUpdateFunc ( &esContext, Update );
304
305 Draw (&esContext);
306 Draw (&esContext);
307 //esMainLoop ( &esContext );
308
309 ShutDown ( &esContext );
310 }
311