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, &centerPos[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