Adds more owners.
[chromium-blink-merge.git] / third_party / gles2_book / Chapter_13 / ParticleSystem / ParticleSystem.c
blobc6be9cf40d39211e849df2e906f35082e964e7f4
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 //
11 // ParticleSystem.c
13 // This is an example that demonstrates rendering a particle system
14 // using a vertex shader and point sprites.
16 #include <stdlib.h>
17 #include <math.h>
18 #include "esUtil.h"
20 #define NUM_PARTICLES 1000
21 #define PARTICLE_SIZE 7
23 typedef struct
25 // Handle to a program object
26 GLuint programObject;
28 // Attribute locations
29 GLint lifetimeLoc;
30 GLint startPositionLoc;
31 GLint endPositionLoc;
33 // Uniform location
34 GLint timeLoc;
35 GLint colorLoc;
36 GLint centerPositionLoc;
37 GLint samplerLoc;
39 // Texture handle
40 GLuint textureId;
42 // Particle vertex data
43 float particleData[ NUM_PARTICLES * PARTICLE_SIZE ];
45 // Current time
46 float time;
48 } UserData;
50 ///
51 // Load texture from disk
53 GLuint LoadTexture ( char *fileName )
55 int width,
56 height;
57 char *buffer = esLoadTGA ( fileName, &width, &height );
58 GLuint texId;
60 if ( buffer == NULL )
62 esLogMessage ( "Error loading (%s) image.\n", fileName );
63 return 0;
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 );
75 free ( buffer );
77 return texId;
81 ///
82 // Initialize the shader and program object
84 int Init ( ESContext *esContext )
86 UserData *userData = esContext->userData;
87 int i;
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 "}";
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";
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
142 srand ( 0 );
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 )
168 return FALSE;
171 return TRUE;
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 )
185 float centerPos[3];
186 float color[4];
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, &centerPos[0] );
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;
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;
217 // Set the viewport
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 );
243 // Blend particles
244 glEnable ( GL_BLEND );
245 glBlendFunc ( GL_SRC_ALPHA, GL_ONE );
247 // Bind the texture
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 );
261 // Cleanup
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[] )
277 ESContext esContext;
278 UserData userData;
280 esInitContext ( &esContext );
281 esContext.userData = &userData;
283 esCreateWindow ( &esContext, "ParticleSystem", 640, 480, ES_WINDOW_RGB );
285 if ( !Init ( &esContext ) )
286 return 0;
288 esRegisterDrawFunc ( &esContext, Draw );
289 esRegisterUpdateFunc ( &esContext, Update );
291 esMainLoop ( &esContext );
293 ShutDown ( &esContext );