2 // Book: OpenGL(R) ES 2.0 Programming Guide
3 // Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
5 // ISBN-13: 9780321502797
6 // Publisher: Addison-Wesley Professional
7 // URLs: http://safari.informit.com/9780321563835
8 // http://www.opengles-book.com
13 // This is an example that demonstrates rendering a particle system
14 // using a vertex shader and point sprites.
20 #define NUM_PARTICLES 1000
21 #define PARTICLE_SIZE 7
25 // Handle to a program object
28 // Attribute locations
30 GLint startPositionLoc
;
36 GLint centerPositionLoc
;
42 // Particle vertex data
43 float particleData
[ NUM_PARTICLES
* PARTICLE_SIZE
];
51 // Load texture from disk
53 GLuint
LoadTexture ( char *fileName
)
57 char *buffer
= esLoadTGA ( fileName
, &width
, &height
);
62 esLogMessage ( "Error loading (%s) image.\n", fileName
);
66 glGenTextures ( 1, &texId
);
67 glBindTexture ( GL_TEXTURE_2D
, texId
);
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
);
82 // Initialize the shader and program object
84 int Init ( ESContext
*esContext
)
86 UserData
*userData
= esContext
->userData
;
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"
98 " if ( u_time <= a_lifetime ) \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"
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"
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"
120 " texColor = texture2D( s_texture, gl_PointCoord ); \n"
121 " gl_FragColor = vec4( u_color ) * texColor; \n"
122 " gl_FragColor.a *= v_lifetime; \n"
125 // Load the shaders and get a linked program object
126 userData
->programObject
= esLoadProgram ( vShaderStr
, fShaderStr
);
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" );
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" );
139 glClearColor ( 0.0f
, 0.0f
, 0.0f
, 0.0f
);
141 // Fill in particle data array
143 for ( i
= 0; i
< NUM_PARTICLES
; i
++ )
145 float *particleData
= &userData
->particleData
[i
* PARTICLE_SIZE
];
147 // Lifetime of particle
148 (*particleData
++) = ( (float)(rand() % 10000) / 10000.0f
);
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
;
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
;
162 // Initialize time to cause reset on first update
163 userData
->time
= 1.0f
;
165 userData
->textureId
= LoadTexture ( "smoke.tga" );
166 if ( userData
->textureId
<= 0 )
175 // Update time-based variables
177 void Update ( ESContext
*esContext
, float deltaTime
)
179 UserData
*userData
= esContext
->userData
;
181 userData
->time
+= deltaTime
;
183 if ( userData
->time
>= 1.0f
)
188 userData
->time
= 0.0f
;
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
;
195 glUniform3fv ( userData
->centerPositionLoc
, 1, ¢erPos
[0] );
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
;
203 glUniform4fv ( userData
->colorLoc
, 1, &color
[0] );
206 // Load uniform time variable
207 glUniform1f ( userData
->timeLoc
, userData
->time
);
211 // Draw a triangle using the shader pair created in Init()
213 void Draw ( ESContext
*esContext
)
215 UserData
*userData
= esContext
->userData
;
218 glViewport ( 0, 0, esContext
->width
, esContext
->height
);
220 // Clear the color buffer
221 glClear ( GL_COLOR_BUFFER_BIT
);
223 // Use the program object
224 glUseProgram ( userData
->programObject
);
226 // Load the vertex attributes
227 glVertexAttribPointer ( userData
->lifetimeLoc
, 1, GL_FLOAT
,
228 GL_FALSE
, PARTICLE_SIZE
* sizeof(GLfloat
),
229 userData
->particleData
);
231 glVertexAttribPointer ( userData
->endPositionLoc
, 3, GL_FLOAT
,
232 GL_FALSE
, PARTICLE_SIZE
* sizeof(GLfloat
),
233 &userData
->particleData
[1] );
235 glVertexAttribPointer ( userData
->startPositionLoc
, 3, GL_FLOAT
,
236 GL_FALSE
, PARTICLE_SIZE
* sizeof(GLfloat
),
237 &userData
->particleData
[4] );
240 glEnableVertexAttribArray ( userData
->lifetimeLoc
);
241 glEnableVertexAttribArray ( userData
->endPositionLoc
);
242 glEnableVertexAttribArray ( userData
->startPositionLoc
);
244 glEnable ( GL_BLEND
);
245 glBlendFunc ( GL_SRC_ALPHA
, GL_ONE
);
248 glActiveTexture ( GL_TEXTURE0
);
249 glBindTexture ( GL_TEXTURE_2D
, userData
->textureId
);
250 glEnable ( GL_TEXTURE_2D
);
252 // Set the sampler texture unit to 0
253 glUniform1i ( userData
->samplerLoc
, 0 );
255 glDrawArrays( GL_POINTS
, 0, NUM_PARTICLES
);
257 eglSwapBuffers ( esContext
->eglDisplay
, esContext
->eglSurface
);
263 void ShutDown ( ESContext
*esContext
)
265 UserData
*userData
= esContext
->userData
;
267 // Delete texture object
268 glDeleteTextures ( 1, &userData
->textureId
);
270 // Delete program object
271 glDeleteProgram ( userData
->programObject
);
275 int main ( int argc
, char *argv
[] )
280 esInitContext ( &esContext
);
281 esContext
.userData
= &userData
;
283 esCreateWindow ( &esContext
, "ParticleSystem", 640, 480, ES_WINDOW_RGB
);
285 if ( !Init ( &esContext
) )
288 esRegisterDrawFunc ( &esContext
, Draw
);
289 esRegisterUpdateFunc ( &esContext
, Update
);
291 esMainLoop ( &esContext
);
293 ShutDown ( &esContext
);