Lesson 4: Starfield Particle Engine OpenGL
We introduce a simple particle engine. A particle engine can be used for many purposes in 3d graphics such as fire, explosions, lasers, stars and many other fun things! ![]()
To make a particle engine, we need to have a particle set. The set consists of N elements where each elements represents a star. A star itself can be defined by a set of variables including vertex position, size, colour, speed and others. Stars could be defined in a class or struct, but we keep things very basic in this tutorial.
First we define a set of stars:
int NR_STARS = 1024; float starx[1024],stary[1024],starz[1024];
In this example, every star is actually a flat square with a transparent texture. To make textures transparent we need to enable blending.
void drawStar() {
glBegin(GL_QUADS);
glTexCoord2f( 0.0f, 1.0f ); glVertex3f( -1.0f, -1.0f, 1.0f );
glTexCoord2f( 1.0f, 1.0f ); glVertex3f( 1.0f, -1.0f, 1.0f );
glTexCoord2f( 1.0f, 0.0f ); glVertex3f( 1.0f, 1.0f, 1.0f );
glTexCoord2f( 0.0f, 0.0f ); glVertex3f( -1.0f, 1.0f, 1.0f );
glEnd( );
}
And turn on blending, as mentioned ![]()
// turn on alpha blending for transparency glEnable(GL_BLEND); // Turn Blending On glDisable(GL_DEPTH_TEST); // Turn Depth Testing Off glBlendFunc(GL_SRC_ALPHA,GL_ONE);
Finally we need to draw and update the star position.
We have put them in one loop to increase speed:
int i = 0;
for (i = 0; i
Full code:
/*
* OpenGL Textured Cube
* https://talkera.org.cp-in-1.webhostbox.net/opengl/
* http://openglsamples.sf.net
*
* Compilation trough:
* gcc cube2.c -lglut -lGL -lGLU -lSDL -lSDL_image
*
* Note lSDL_image is added for PNG support!
*
*/
#include
#include
#include
#include
#include "SDL/SDL.h"
#include
/* screen width, height, and bit depth */
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
#define SCREEN_BPP 16
/* Setup useful booleans */
#define TRUE 1
#define FALSE 0
/* This is our SDL surface */
SDL_Surface *surface;
/* Used for rotating the cube */
GLfloat rotationXaxis;
GLfloat rotationYaxis;
GLfloat rotationZaxis;
/* Storage For Textures */
GLuint texture[3];
/* Release resources and quit */
void Quit( int returnCode ) {
SDL_Quit( );
exit( returnCode );
}
int NR_STARS = 1024;
float starx[1024],stary[1024],starz[1024];
/* Loads in a bitmap as a GL texture */
int LoadGLTextures( ) {
int Status = FALSE;
/* Create storage space for the texture */
SDL_Surface *TextureImage[1];
/* Load The Bitmap into Memory */
if ((TextureImage[0] = IMG_Load("data/fire2.jpg"))) {
Status = TRUE;
glGenTextures( 1, &texture[0] );
glBindTexture( GL_TEXTURE_2D, texture[0] );
glTexImage2D( GL_TEXTURE_2D, 0, 3, TextureImage[0]->w,
TextureImage[0]->h, 0, GL_RGB,
GL_UNSIGNED_BYTE, TextureImage[0]->pixels );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
}
/* Free up some memory */
if ( TextureImage[0] )
SDL_FreeSurface( TextureImage[0] );
// second texture
/* Load The Bitmap into Memory */
if ((TextureImage[0] = IMG_Load("data/fire.jpg"))) {
Status = TRUE;
glGenTextures( 1, &texture[1] );
glBindTexture( GL_TEXTURE_2D, texture[1] );
glTexImage2D( GL_TEXTURE_2D, 0, 3, TextureImage[0]->w,
TextureImage[0]->h, 0, GL_RGB,
GL_UNSIGNED_BYTE, TextureImage[0]->pixels );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
}
/* Free up some memory */
if ( TextureImage[0] )
SDL_FreeSurface( TextureImage[0] );
return Status;
}
/* function to reset our viewport after a window resize */
int resizeWindow( int width, int height ) {
/* Height / width ration */
GLfloat ratio;
/* Protect against a divide by zero */
if ( height == 0 )
height = 1;
ratio = ( GLfloat )width / ( GLfloat )height;
/* Setup our viewport. */
glViewport( 0, 0, ( GLint )width, ( GLint )height );
/*
* change to the projection matrix and set
* our viewing volume.
*/
glMatrixMode( GL_PROJECTION );
glLoadIdentity( );
/* Set our perspective */
gluPerspective( 45.0f, ratio, 0.1f, 100.0f );
/* Make sure we're chaning the model view and not the projection */
glMatrixMode( GL_MODELVIEW );
/* Reset The View */
glLoadIdentity( );
return( TRUE );
}
/* function to handle key press events */
void handleKeyPress( SDL_keysym *keysym )
{
switch ( keysym->sym )
{
case SDLK_ESCAPE:
/* ESC key was pressed */
Quit( 0 );
break;
case SDLK_F1:
/* F1 key was pressed
* this toggles fullscreen mode
*/
SDL_WM_ToggleFullScreen( surface );
break;
default:
break;
}
return;
}
/* OpenGL initialization function */
int initGL( GLvoid )
{
/* Load in the texture */
if ( !LoadGLTextures( ) )
return FALSE;
/* Enable Texture Mapping ( NEW ) */
glEnable( GL_TEXTURE_2D );
/* Enable smooth shading */
glShadeModel( GL_SMOOTH );
/* Set the background black */
glClearColor( 0.0f, 0.0f, 0.0f, 0.5f );
/* Depth buffer setup */
glClearDepth( 1.0f );
/* Enables Depth Testing */
glEnable( GL_DEPTH_TEST );
/* The Type Of Depth Test To Do */
glDepthFunc( GL_LEQUAL );
/* Really Nice Perspective Calculations */
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
return( TRUE );
}
void initStars() {
int i = 0;
for (i = 0; i hw_available )
videoFlags |= SDL_HWSURFACE;
else
videoFlags |= SDL_SWSURFACE;
/* This checks if hardware blits can be done */
if ( videoInfo->blit_hw )
videoFlags |= SDL_HWACCEL;
/* Sets up OpenGL double buffering */
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
/* get a SDL surface */
surface = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP,
videoFlags );
/* Verify there is a surface */
if ( !surface )
{
fprintf( stderr, "Video mode set failed: %s\n", SDL_GetError( ) );
Quit( 1 );
}
/* initialize OpenGL */
initGL( );
initStars();
/* resize the initial window */
resizeWindow( SCREEN_WIDTH, SCREEN_HEIGHT );
/* wait for events */
while ( !done )
{
/* handle the events in the queue */
while ( SDL_PollEvent( &event ) )
{
switch( event.type )
{
case SDL_ACTIVEEVENT:
if ( event.active.gain == 0 )
isActive = FALSE;
else
isActive = TRUE;
break;
case SDL_VIDEORESIZE:
/* handle resize event */
surface = SDL_SetVideoMode( event.resize.w,
event.resize.h,
16, videoFlags );
if ( !surface )
{
fprintf( stderr, "Could not get a surface after resize: %s\n", SDL_GetError( ) );
Quit( 1 );
}
resizeWindow( event.resize.w, event.resize.h );
break;
case SDL_KEYDOWN:
/* handle key presses */
handleKeyPress( &event.key.keysym );
break;
case SDL_QUIT:
/* handle quit requests */
done = TRUE;
break;
default:
break;
}
}
/* draw the scene */
if ( isActive )
drawGLScene( );
}
/* clean ourselves up and exit */
Quit( 0 );
/* Should never get here */
return( 0 );
}
We have used this texture: