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