| OLD | NEW |
| (Empty) |
| 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 // | |
| 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_UNSIGNE
D_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 // | |
| 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_lif
etime" ); | |
| 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_tex
ture" ); | |
| 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 // | |
| 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, ¢erPos[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 // | |
| 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 // | |
| 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 | |
| 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, "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 } | |
| OLD | NEW |