mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
295 lines
9.1 KiB
C
295 lines
9.1 KiB
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, ¢erPos[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 );
|
|
}
|