Edit

kc3-lang/angle/samples/gles2_book/ParticleSystem/ParticleSystem.c

Branch :

  • Show log

    Commit

  • Author : alokp@chromium.org
    Date : 2010-04-07 19:57:20
    Hash : 0270ef14
    Message : Changed the default character set to be UNICODE, the same as chromium. Changes to fix compile errors and warnings. Review URL: http://codereview.appspot.com/816046 git-svn-id: https://angleproject.googlecode.com/svn/trunk@103 736b8ea6-26fd-11df-bfd4-992fa37f6226

  • samples/gles2_book/ParticleSystem/ParticleSystem.c
  • //
    // Book:      OpenGL(R) ES 2.0 Programming Guide
    // Authors:   Aaftab Munshi, Dan Ginsburg, Dave Shreiner
    // ISBN-10:   0321502795
    // ISBN-13:   9780321502797
    // Publisher: Addison-Wesley Professional
    // URLs:      http://safari.informit.com/9780321563835
    //            http://www.opengles-book.com
    //
    
    // ParticleSystem.c
    //
    //    This is an example that demonstrates rendering a particle system
    //    using a vertex shader and point sprites.
    //
    #include <stdlib.h>
    #include <math.h>
    #include "esUtil.h"
    
    #define NUM_PARTICLES	1000
    #define PARTICLE_SIZE   7
    
    typedef struct
    {
       // Handle to a program object
       GLuint programObject;
    
       // Attribute locations
       GLint  lifetimeLoc;
       GLint  startPositionLoc;
       GLint  endPositionLoc;
       
       // Uniform location
       GLint timeLoc;
       GLint colorLoc;
       GLint centerPositionLoc;
       GLint samplerLoc;
    
       // Texture handle
       GLuint textureId;
    
       // Particle vertex data
       float particleData[ NUM_PARTICLES * PARTICLE_SIZE ];
    
       // Current time
       float time;
    
    } UserData;
    
    ///
    // Load texture from disk
    //
    GLuint LoadTexture ( char *fileName )
    {
       int width,
           height;
       char *buffer = esLoadTGA ( fileName, &width, &height );
       GLuint texId;
    
       if ( buffer == NULL )
       {
          esLogMessage ( "Error loading (%s) image.\n", fileName );
          return 0;
       }
    
       glGenTextures ( 1, &texId );
       glBindTexture ( GL_TEXTURE_2D, texId );
    
       glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer );
       glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
       glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
       glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
       glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
    
       free ( buffer );
    
       return texId;
    }
    
    
    ///
    // Initialize the shader and program object
    //
    int Init ( ESContext *esContext )
    {
       UserData *userData = esContext->userData;
       int i;
       
       GLbyte vShaderStr[] =
          "uniform float u_time;		                           \n"
          "uniform vec3 u_centerPosition;                       \n"
          "attribute float a_lifetime;                          \n"
          "attribute vec3 a_startPosition;                      \n"
          "attribute vec3 a_endPosition;                        \n"
          "varying float v_lifetime;                            \n"
          "void main()                                          \n"
          "{                                                    \n"
          "  if ( u_time <= a_lifetime )                        \n"
          "  {                                                  \n"
          "    gl_Position.xyz = a_startPosition +              \n"
          "                      (u_time * a_endPosition);      \n"
          "    gl_Position.xyz += u_centerPosition;             \n"
          "    gl_Position.w = 1.0;                             \n"
          "  }                                                  \n"
          "  else                                               \n"
          "     gl_Position = vec4( -1000, -1000, 0, 0 );       \n"
          "  v_lifetime = 1.0 - ( u_time / a_lifetime );        \n"
          "  v_lifetime = clamp ( v_lifetime, 0.0, 1.0 );       \n"
          "  gl_PointSize = ( v_lifetime * v_lifetime ) * 40.0; \n"
          "}";
          
       GLbyte fShaderStr[] =  
          "precision mediump float;                             \n"
          "uniform vec4 u_color;		                           \n"
          "varying float v_lifetime;                            \n"
          "uniform sampler2D s_texture;                         \n"
          "void main()                                          \n"
          "{                                                    \n"
          "  vec4 texColor;                                     \n"
          "  texColor = texture2D( s_texture, gl_PointCoord );  \n"
          "  gl_FragColor = vec4( u_color ) * texColor;         \n"
          "  gl_FragColor.a *= v_lifetime;                      \n"
          "}                                                    \n";
    
       // Load the shaders and get a linked program object
       userData->programObject = esLoadProgram ( vShaderStr, fShaderStr );
    
       // Get the attribute locations
       userData->lifetimeLoc = glGetAttribLocation ( userData->programObject, "a_lifetime" );
       userData->startPositionLoc = glGetAttribLocation ( userData->programObject, "a_startPosition" );
       userData->endPositionLoc = glGetAttribLocation ( userData->programObject, "a_endPosition" );
       
       // Get the uniform locations
       userData->timeLoc = glGetUniformLocation ( userData->programObject, "u_time" );
       userData->centerPositionLoc = glGetUniformLocation ( userData->programObject, "u_centerPosition" );
       userData->colorLoc = glGetUniformLocation ( userData->programObject, "u_color" );
       userData->samplerLoc = glGetUniformLocation ( userData->programObject, "s_texture" );
    
       glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f );
    
       // Fill in particle data array
       srand ( 0 );
       for ( i = 0; i < NUM_PARTICLES; i++ )
       {
          float *particleData = &userData->particleData[i * PARTICLE_SIZE];
       
          // Lifetime of particle
          (*particleData++) = ( (float)(rand() % 10000) / 10000.0f );
    
          // End position of particle
          (*particleData++) = ( (float)(rand() % 10000) / 5000.0f ) - 1.0f;
          (*particleData++) = ( (float)(rand() % 10000) / 5000.0f ) - 1.0f;
          (*particleData++) = ( (float)(rand() % 10000) / 5000.0f ) - 1.0f;
    
          // Start position of particle
          (*particleData++) = ( (float)(rand() % 10000) / 40000.0f ) - 0.125f;
          (*particleData++) = ( (float)(rand() % 10000) / 40000.0f ) - 0.125f;
          (*particleData++) = ( (float)(rand() % 10000) / 40000.0f ) - 0.125f;
    
       }
    
       // Initialize time to cause reset on first update
       userData->time = 1.0f;
    
       userData->textureId = LoadTexture ( "smoke.tga" );
       if ( userData->textureId <= 0 )
       {
          return FALSE;
       }
       
       return TRUE;
    }
    
    ///
    //  Update time-based variables
    //
    void Update ( ESContext *esContext, float deltaTime )
    {
       UserData *userData = esContext->userData;
      
       userData->time += deltaTime;
    
       if ( userData->time >= 1.0f )
       {
          float centerPos[3];
          float color[4];
    
          userData->time = 0.0f;
    
          // Pick a new start location and color
          centerPos[0] = ( (float)(rand() % 10000) / 10000.0f ) - 0.5f;
          centerPos[1] = ( (float)(rand() % 10000) / 10000.0f ) - 0.5f;
          centerPos[2] = ( (float)(rand() % 10000) / 10000.0f ) - 0.5f;
          
          glUniform3fv ( userData->centerPositionLoc, 1, &centerPos[0] );
    
          // Random color
          color[0] = ( (float)(rand() % 10000) / 20000.0f ) + 0.5f;
          color[1] = ( (float)(rand() % 10000) / 20000.0f ) + 0.5f;
          color[2] = ( (float)(rand() % 10000) / 20000.0f ) + 0.5f;
          color[3] = 0.5;
    
          glUniform4fv ( userData->colorLoc, 1, &color[0] );
       }
    
       // Load uniform time variable
       glUniform1f ( userData->timeLoc, userData->time );
    }
    
    ///
    // Draw a triangle using the shader pair created in Init()
    //
    void Draw ( ESContext *esContext )
    {
       UserData *userData = esContext->userData;
          
       // Set the viewport
       glViewport ( 0, 0, esContext->width, esContext->height );
       
       // Clear the color buffer
       glClear ( GL_COLOR_BUFFER_BIT );
    
       // Use the program object
       glUseProgram ( userData->programObject );
    
       // Load the vertex attributes
       glVertexAttribPointer ( userData->lifetimeLoc, 1, GL_FLOAT, 
                               GL_FALSE, PARTICLE_SIZE * sizeof(GLfloat), 
                               userData->particleData );
       
       glVertexAttribPointer ( userData->endPositionLoc, 3, GL_FLOAT,
                               GL_FALSE, PARTICLE_SIZE * sizeof(GLfloat),
                               &userData->particleData[1] );
    
       glVertexAttribPointer ( userData->startPositionLoc, 3, GL_FLOAT,
                               GL_FALSE, PARTICLE_SIZE * sizeof(GLfloat),
                               &userData->particleData[4] );
    
       
       glEnableVertexAttribArray ( userData->lifetimeLoc );
       glEnableVertexAttribArray ( userData->endPositionLoc );
       glEnableVertexAttribArray ( userData->startPositionLoc );
       // Blend particles
       glEnable ( GL_BLEND );
       glBlendFunc ( GL_SRC_ALPHA, GL_ONE );
    
       // Bind the texture
       glActiveTexture ( GL_TEXTURE0 );
       glBindTexture ( GL_TEXTURE_2D, userData->textureId );
       glEnable ( GL_TEXTURE_2D );
    
       // Set the sampler texture unit to 0
       glUniform1i ( userData->samplerLoc, 0 );
    
       glDrawArrays( GL_POINTS, 0, NUM_PARTICLES );
       
       eglSwapBuffers ( esContext->eglDisplay, esContext->eglSurface );
    }
    
    ///
    // Cleanup
    //
    void ShutDown ( ESContext *esContext )
    {
       UserData *userData = esContext->userData;
    
       // Delete texture object
       glDeleteTextures ( 1, &userData->textureId );
    
       // Delete program object
       glDeleteProgram ( userData->programObject );
    }
    
    
    int main ( int argc, char *argv[] )
    {
       ESContext esContext;
       UserData  userData;
    
       esInitContext ( &esContext );
       esContext.userData = &userData;
    
       esCreateWindow ( &esContext, TEXT("ParticleSystem"), 640, 480, ES_WINDOW_RGB );
       
       if ( !Init ( &esContext ) )
          return 0;
    
       esRegisterDrawFunc ( &esContext, Draw );
       esRegisterUpdateFunc ( &esContext, Update );
       
       esMainLoop ( &esContext );
    
       ShutDown ( &esContext );
    }