spriteblast.c revision 32001f49
132001f49Smrg
232001f49Smrg/* Copyright (c) Mark J. Kilgard, 1997.  */
332001f49Smrg
432001f49Smrg/* This program is freely distributable without licensing fees
532001f49Smrg   and is provided without guarantee or warrantee expressed or
632001f49Smrg   implied. This program is -not- in the public domain. */
732001f49Smrg
832001f49Smrg/* This example demonstrates how to render particle effects
932001f49Smrg   with OpenGL.  A cloud of pinkish/orange particles explodes with the
1032001f49Smrg   particles bouncing off the ground.  When the EXT_point_parameters
1132001f49Smrg   is present , the particle size is attenuated based on eye distance. */
1232001f49Smrg
1332001f49Smrg
1432001f49Smrg/* Modified by Brian Paul to test GL_ARB_point_sprite */
1532001f49Smrg
1632001f49Smrg
1732001f49Smrg#include <assert.h>
1832001f49Smrg#include <stdio.h>
1932001f49Smrg#include <stdlib.h>
2032001f49Smrg#include <string.h>
2132001f49Smrg#include <math.h>       /* for cos(), sin(), and sqrt() */
2232001f49Smrg#ifdef _WIN32
2332001f49Smrg#include <windows.h>
2432001f49Smrg#endif
2532001f49Smrg#include <GL/glew.h>
2632001f49Smrg#include "glut_wrap.h"
2732001f49Smrg
2832001f49Smrg/* Some <math.h> files do not define M_PI... */
2932001f49Smrg#ifndef M_PI
3032001f49Smrg#define M_PI 3.14159265
3132001f49Smrg#endif
3232001f49Smrg
3332001f49Smrg#if 0  /* For debugging. */
3432001f49Smrg#undef GL_EXT_point_parameters
3532001f49Smrg#endif
3632001f49Smrg
3732001f49Smrgstatic GLfloat angle = -150;   /* in degrees */
3832001f49Smrgstatic int spin = 0;
3932001f49Smrgstatic int moving, begin;
4032001f49Smrgstatic float theTime;
4132001f49Smrgstatic int repeat = 1;
4232001f49Smrgstatic int blend = 1;
4332001f49Smrgstatic int useMipmaps = 1;
4432001f49Smrgstatic int linearFiltering = 1;
4532001f49Smrg
4632001f49Smrgstatic GLuint Tex0, Tex1;
4732001f49Smrg
4832001f49Smrgstatic GLfloat constant[3] = { .2,  0.0,     0.0 };
4932001f49Smrgstatic GLfloat linear[3]   = { .0,   .1,     0.0 };
5032001f49Smrgstatic GLfloat theQuad[3]  = { .005, 0.05, 1/600.0 };
5132001f49Smrg
5232001f49Smrg#define MAX_POINTS 2000
5332001f49Smrg
5432001f49Smrgstatic int numPoints = 200;
5532001f49Smrg
5632001f49Smrgstatic GLfloat pointList[MAX_POINTS][3];
5732001f49Smrgstatic GLfloat pointTime[MAX_POINTS];
5832001f49Smrgstatic GLfloat pointVelocity[MAX_POINTS][2];
5932001f49Smrgstatic GLfloat pointDirection[MAX_POINTS][2];
6032001f49Smrgstatic int colorList[MAX_POINTS];
6132001f49Smrgstatic int animate = 1, motion = 0, org = 0, sprite = 1, smooth = 1;
6232001f49Smrg
6332001f49Smrgstatic GLfloat colorSet[][4] = {
6432001f49Smrg  /* Shades of red. */
6532001f49Smrg  { 0.7, 0.2, 0.4, 0.5 },
6632001f49Smrg  { 0.8, 0.0, 0.7, 0.5 },
6732001f49Smrg  { 1.0, 0.0, 0.0, 0.5 },
6832001f49Smrg  { 0.9, 0.3, 0.6, 0.5 },
6932001f49Smrg  { 1.0, 0.4, 0.0, 0.5 },
7032001f49Smrg  { 1.0, 0.0, 0.5, 0.5 },
7132001f49Smrg};
7232001f49Smrg
7332001f49Smrg#define NUM_COLORS (sizeof(colorSet)/sizeof(colorSet[0]))
7432001f49Smrg
7532001f49Smrg#define DEAD (NUM_COLORS+1)
7632001f49Smrg
7732001f49Smrg
7832001f49Smrg/* GL */
7932001f49Smrgstatic GLint spritePattern[16][16] = {
8032001f49Smrg   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
8132001f49Smrg   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
8232001f49Smrg   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
8332001f49Smrg   { 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0 },
8432001f49Smrg   { 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0 },
8532001f49Smrg   { 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0 },
8632001f49Smrg   { 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0 },
8732001f49Smrg   { 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0 },
8832001f49Smrg   { 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0 },
8932001f49Smrg   { 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0 },
9032001f49Smrg   { 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0 },
9132001f49Smrg   { 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0 },
9232001f49Smrg   { 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0 },
9332001f49Smrg   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
9432001f49Smrg   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
9532001f49Smrg   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
9632001f49Smrg};
9732001f49Smrg
9832001f49Smrg
9932001f49Smrg/** Fragment shader which inverts the texture's color */
10032001f49Smrgstatic const char *FragShaderText =
10132001f49Smrg   "uniform sampler2D tex; \n"
10232001f49Smrg   "void main(void) \n"
10332001f49Smrg   "{ \n"
10432001f49Smrg   "   gl_FragColor = vec4(1.0) - texture2D(tex, gl_TexCoord[0].xy); \n"
10532001f49Smrg   "} \n";
10632001f49Smrg
10732001f49Smrgstatic GLuint FragShader, ShaderProg;
10832001f49Smrgstatic GLboolean UseFragShader = GL_FALSE;
10932001f49Smrgstatic GLboolean HaveShaders = GL_FALSE;
11032001f49Smrg
11132001f49Smrgstatic void
11232001f49SmrgmakeFragShader(void)
11332001f49Smrg{
11432001f49Smrg   GLint stat;
11532001f49Smrg
11632001f49Smrg   HaveShaders = GLEW_VERSION_2_0;
11732001f49Smrg   if (!HaveShaders)
11832001f49Smrg      return;
11932001f49Smrg
12032001f49Smrg   FragShader = glCreateShader(GL_FRAGMENT_SHADER);
12132001f49Smrg   glShaderSource(FragShader, 1, (const GLchar **) &FragShaderText, NULL);
12232001f49Smrg   glCompileShader(FragShader);
12332001f49Smrg
12432001f49Smrg   ShaderProg = glCreateProgram();
12532001f49Smrg   glAttachShader(ShaderProg, FragShader);
12632001f49Smrg   glLinkProgram(ShaderProg);
12732001f49Smrg
12832001f49Smrg   glGetProgramiv(ShaderProg, GL_LINK_STATUS, &stat);
12932001f49Smrg   assert(stat);
13032001f49Smrg}
13132001f49Smrg
13232001f49Smrg
13332001f49Smrg
13432001f49Smrg
13532001f49Smrg#if 0  /* drand48 might be better on Unix machines */
13632001f49Smrg#define RANDOM_RANGE(lo, hi) ((lo) + (hi - lo) * drand48())
13732001f49Smrg#else
13832001f49Smrgstatic float float_rand(void) { return rand() / (float) RAND_MAX; }
13932001f49Smrg#define RANDOM_RANGE(lo, hi) ((lo) + (hi - lo) * float_rand())
14032001f49Smrg#endif
14132001f49Smrg
14232001f49Smrg#define MEAN_VELOCITY 3.0
14332001f49Smrg#define GRAVITY 2.0
14432001f49Smrg
14532001f49Smrg/* Modeling units of ground extent in each X and Z direction. */
14632001f49Smrg#define EDGE 12
14732001f49Smrg
14832001f49Smrgstatic void
14932001f49SmrgmakePointList(void)
15032001f49Smrg{
15132001f49Smrg  float angle, velocity, direction;
15232001f49Smrg  int i;
15332001f49Smrg
15432001f49Smrg  motion = 1;
15532001f49Smrg  for (i=0; i<numPoints; i++) {
15632001f49Smrg    pointList[i][0] = 0.0;
15732001f49Smrg    pointList[i][1] = 0.0;
15832001f49Smrg    pointList[i][2] = 0.0;
15932001f49Smrg    pointTime[i] = 0.0;
16032001f49Smrg    angle = (RANDOM_RANGE(60.0, 70.0)) * M_PI/180.0;
16132001f49Smrg    direction = RANDOM_RANGE(0.0, 360.0) * M_PI/180.0;
16232001f49Smrg    pointDirection[i][0] = cos(direction);
16332001f49Smrg    pointDirection[i][1] = sin(direction);
16432001f49Smrg    velocity = MEAN_VELOCITY + RANDOM_RANGE(-0.8, 1.0);
16532001f49Smrg    pointVelocity[i][0] = velocity * cos(angle);
16632001f49Smrg    pointVelocity[i][1] = velocity * sin(angle);
16732001f49Smrg    colorList[i] = rand() % NUM_COLORS;
16832001f49Smrg  }
16932001f49Smrg  theTime = 0.0;
17032001f49Smrg}
17132001f49Smrg
17232001f49Smrgstatic void
17332001f49SmrgupdatePointList(void)
17432001f49Smrg{
17532001f49Smrg  float distance;
17632001f49Smrg  int i;
17732001f49Smrg
17832001f49Smrg  static double t0 = -1.;
17932001f49Smrg  double dt, t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
18032001f49Smrg  if (t0 < 0.0)
18132001f49Smrg    t0 = t;
18232001f49Smrg  dt = t - t0;
18332001f49Smrg  t0 = t;
18432001f49Smrg
18532001f49Smrg  motion = 0;
18632001f49Smrg  for (i=0; i<numPoints; i++) {
18732001f49Smrg    distance = pointVelocity[i][0] * theTime;
18832001f49Smrg
18932001f49Smrg    /* X and Z */
19032001f49Smrg    pointList[i][0] = pointDirection[i][0] * distance;
19132001f49Smrg    pointList[i][2] = pointDirection[i][1] * distance;
19232001f49Smrg
19332001f49Smrg    /* Z */
19432001f49Smrg    pointList[i][1] =
19532001f49Smrg      (pointVelocity[i][1] - 0.5 * GRAVITY * pointTime[i])*pointTime[i];
19632001f49Smrg
19732001f49Smrg    /* If we hit the ground, bounce the point upward again. */
19832001f49Smrg    if (pointList[i][1] <= 0.0) {
19932001f49Smrg      if (distance > EDGE) {
20032001f49Smrg        /* Particle has hit ground past the distance duration of
20132001f49Smrg          the particles.  Mark particle as dead. */
20232001f49Smrg       colorList[i] = NUM_COLORS;  /* Not moving. */
20332001f49Smrg       continue;
20432001f49Smrg      }
20532001f49Smrg
20632001f49Smrg      pointVelocity[i][1] *= 0.8;  /* 80% of previous up velocity. */
20732001f49Smrg      pointTime[i] = 0.0;  /* Reset the particles sense of up time. */
20832001f49Smrg    }
20932001f49Smrg    motion = 1;
21032001f49Smrg    pointTime[i] += dt;
21132001f49Smrg  }
21232001f49Smrg  theTime += dt;
21332001f49Smrg  if (!motion && !spin) {
21432001f49Smrg    if (repeat) {
21532001f49Smrg      makePointList();
21632001f49Smrg    } else {
21732001f49Smrg      glutIdleFunc(NULL);
21832001f49Smrg    }
21932001f49Smrg  }
22032001f49Smrg}
22132001f49Smrg
22232001f49Smrgstatic void
22332001f49Smrgidle(void)
22432001f49Smrg{
22532001f49Smrg  updatePointList();
22632001f49Smrg  if (spin) {
22732001f49Smrg    angle += 0.3;
22832001f49Smrg  }
22932001f49Smrg  glutPostRedisplay();
23032001f49Smrg}
23132001f49Smrg
23232001f49Smrgstatic void
23332001f49Smrgvisible(int vis)
23432001f49Smrg{
23532001f49Smrg  if (vis == GLUT_VISIBLE) {
23632001f49Smrg    if (animate && (motion || spin)) {
23732001f49Smrg      glutIdleFunc(idle);
23832001f49Smrg    }
23932001f49Smrg  } else {
24032001f49Smrg    glutIdleFunc(NULL);
24132001f49Smrg  }
24232001f49Smrg}
24332001f49Smrg
24432001f49Smrgstatic void
24532001f49Smrgredraw(void)
24632001f49Smrg{
24732001f49Smrg  int i;
24832001f49Smrg
24932001f49Smrg  glDepthMask(GL_TRUE);
25032001f49Smrg  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
25132001f49Smrg
25232001f49Smrg  if (HaveShaders)
25332001f49Smrg     glUseProgram(0);
25432001f49Smrg
25532001f49Smrg  glPushMatrix();
25632001f49Smrg  glRotatef(15.0, 1.0, 0.0, 0.0);
25732001f49Smrg  glRotatef(angle, 0.0, 1.0, 0.0);
25832001f49Smrg
25932001f49Smrg
26032001f49Smrg  /* Draw the floor. */
26132001f49Smrg  glColor3f(0.1, 0.5, 1.0);
26232001f49Smrg  glBegin(GL_QUADS);
26332001f49Smrg    glTexCoord2f(0.0, 0.0);
26432001f49Smrg    glVertex3f(-EDGE, -0.05, -EDGE);
26532001f49Smrg    glTexCoord2f(20.0, 0.0);
26632001f49Smrg    glVertex3f(EDGE, -0.05, -EDGE);
26732001f49Smrg    glTexCoord2f(20.0, 20.0);
26832001f49Smrg    glVertex3f(EDGE, -0.05, EDGE);
26932001f49Smrg    glTexCoord2f(0.0, 20.0);
27032001f49Smrg    glVertex3f(-EDGE, -0.05, EDGE);
27132001f49Smrg  glEnd();
27232001f49Smrg
27332001f49Smrg  /* Allow particles to blend with each other. */
27432001f49Smrg  glDepthMask(GL_FALSE);
27532001f49Smrg
27632001f49Smrg  if (blend)
27732001f49Smrg     glEnable(GL_BLEND);
27832001f49Smrg
27932001f49Smrg  if (sprite) {
28032001f49Smrg     glActiveTexture(GL_TEXTURE0);
28132001f49Smrg     glEnable(GL_TEXTURE_2D);
28232001f49Smrg     if (0) {
28332001f49Smrg        /* debug/test code */
28432001f49Smrg        glActiveTexture(GL_TEXTURE1);
28532001f49Smrg        glEnable(GL_TEXTURE_2D);
28632001f49Smrg     }
28732001f49Smrg
28832001f49Smrg#ifdef GL_ARB_point_sprite
28932001f49Smrg     glEnable(GL_POINT_SPRITE_ARB);
29032001f49Smrg#endif
29132001f49Smrg     if (UseFragShader) {
29232001f49Smrg        glUseProgram(ShaderProg);
29332001f49Smrg     }
29432001f49Smrg  }
29532001f49Smrg
29632001f49Smrg  glColor3f(1,1,1);
29732001f49Smrg  glBegin(GL_POINTS);
29832001f49Smrg    for (i=0; i<numPoints; i++) {
29932001f49Smrg      /* Draw alive particles. */
30032001f49Smrg      if (colorList[i] != DEAD) {
30132001f49Smrg        if (!sprite)
30232001f49Smrg           glColor4fv(colorSet[colorList[i]]);
30332001f49Smrg        glVertex3fv(pointList[i]);
30432001f49Smrg      }
30532001f49Smrg    }
30632001f49Smrg  glEnd();
30732001f49Smrg
30832001f49Smrg  glActiveTexture(GL_TEXTURE0);
30932001f49Smrg  glDisable(GL_TEXTURE_2D);
31032001f49Smrg  glActiveTexture(GL_TEXTURE1);
31132001f49Smrg  glDisable(GL_TEXTURE_2D);
31232001f49Smrg
31332001f49Smrg#ifdef GL_ARB_point_sprite
31432001f49Smrg  glDisable(GL_POINT_SPRITE_ARB);
31532001f49Smrg#endif
31632001f49Smrg  glDisable(GL_BLEND);
31732001f49Smrg
31832001f49Smrg  glPopMatrix();
31932001f49Smrg
32032001f49Smrg  glutSwapBuffers();
32132001f49Smrg}
32232001f49Smrg
32332001f49Smrg/* ARGSUSED2 */
32432001f49Smrgstatic void
32532001f49Smrgmouse(int button, int state, int x, int y)
32632001f49Smrg{
32732001f49Smrg  /* Scene can be spun around Y axis using left
32832001f49Smrg     mouse button movement. */
32932001f49Smrg  if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
33032001f49Smrg    moving = 1;
33132001f49Smrg    begin = x;
33232001f49Smrg  }
33332001f49Smrg  if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
33432001f49Smrg    moving = 0;
33532001f49Smrg  }
33632001f49Smrg}
33732001f49Smrg
33832001f49Smrg/* ARGSUSED1 */
33932001f49Smrgstatic void
34032001f49SmrgmouseMotion(int x, int y)
34132001f49Smrg{
34232001f49Smrg  if (moving) {
34332001f49Smrg    angle = angle + (x - begin);
34432001f49Smrg    begin = x;
34532001f49Smrg    glutPostRedisplay();
34632001f49Smrg  }
34732001f49Smrg}
34832001f49Smrg
34932001f49Smrgstatic void
35032001f49Smrgmenu(int option)
35132001f49Smrg{
35232001f49Smrg  switch (option) {
35332001f49Smrg  case 0:
35432001f49Smrg    makePointList();
35532001f49Smrg    break;
35632001f49Smrg#ifdef GL_ARB_point_parameters
35732001f49Smrg  case 1:
35832001f49Smrg    glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, constant);
35932001f49Smrg    break;
36032001f49Smrg  case 2:
36132001f49Smrg    glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, linear);
36232001f49Smrg    break;
36332001f49Smrg  case 3:
36432001f49Smrg    glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, theQuad);
36532001f49Smrg    break;
36632001f49Smrg#endif
36732001f49Smrg  case 4:
36832001f49Smrg    blend = 1;
36932001f49Smrg    break;
37032001f49Smrg  case 5:
37132001f49Smrg    blend = 0;
37232001f49Smrg    break;
37332001f49Smrg#ifdef GL_ARB_point_parameters
37432001f49Smrg  case 6:
37532001f49Smrg    glPointParameterfARB(GL_POINT_FADE_THRESHOLD_SIZE_ARB, 1.0);
37632001f49Smrg    break;
37732001f49Smrg  case 7:
37832001f49Smrg    glPointParameterfARB(GL_POINT_FADE_THRESHOLD_SIZE_ARB, 10.0);
37932001f49Smrg    break;
38032001f49Smrg#endif
38132001f49Smrg  case 8:
38232001f49Smrg    glEnable(GL_POINT_SMOOTH);
38332001f49Smrg    smooth = 1;
38432001f49Smrg    break;
38532001f49Smrg  case 9:
38632001f49Smrg    glDisable(GL_POINT_SMOOTH);
38732001f49Smrg    smooth = 0;
38832001f49Smrg    break;
38932001f49Smrg  case 10:
39032001f49Smrg    glPointSize(16.0);
39132001f49Smrg    break;
39232001f49Smrg  case 11:
39332001f49Smrg    glPointSize(32.0);
39432001f49Smrg    break;
39532001f49Smrg  case 12:
39632001f49Smrg    glPointSize(64.0);
39732001f49Smrg    break;
39832001f49Smrg  case 13:
39932001f49Smrg    spin = 1 - spin;
40032001f49Smrg    if (animate && (spin || motion)) {
40132001f49Smrg      glutIdleFunc(idle);
40232001f49Smrg    } else {
40332001f49Smrg      glutIdleFunc(NULL);
40432001f49Smrg    }
40532001f49Smrg    break;
40632001f49Smrg  case 14:
40732001f49Smrg    numPoints = 200;
40832001f49Smrg    break;
40932001f49Smrg  case 15:
41032001f49Smrg    numPoints = 500;
41132001f49Smrg    break;
41232001f49Smrg  case 16:
41332001f49Smrg    numPoints = 1000;
41432001f49Smrg    break;
41532001f49Smrg  case 17:
41632001f49Smrg    numPoints = 2000;
41732001f49Smrg    break;
41832001f49Smrg  case 666:
41932001f49Smrg    exit(0);
42032001f49Smrg  }
42132001f49Smrg  glutPostRedisplay();
42232001f49Smrg}
42332001f49Smrg
42432001f49Smrg/* ARGSUSED1 */
42532001f49Smrgstatic void
42632001f49Smrgkey(unsigned char c, int x, int y)
42732001f49Smrg{
42832001f49Smrg  switch (c) {
42932001f49Smrg  case 13:
43032001f49Smrg    animate = 1 - animate;  /* toggle. */
43132001f49Smrg    if (animate && (motion || spin)) {
43232001f49Smrg      glutIdleFunc(idle);
43332001f49Smrg    } else {
43432001f49Smrg      glutIdleFunc(NULL);
43532001f49Smrg    }
43632001f49Smrg    break;
43732001f49Smrg  case ' ':
43832001f49Smrg    animate = 1;
43932001f49Smrg    makePointList();
44032001f49Smrg    glutIdleFunc(idle);
44132001f49Smrg    break;
44232001f49Smrg  case 'o':
44332001f49Smrg  case 'O':
44432001f49Smrg    org ^= 1;
44532001f49Smrg#ifdef GL_VERSION_2_0
44632001f49Smrg#ifdef GL_ARB_point_parameters
44732001f49Smrg    glPointParameteri(GL_POINT_SPRITE_COORD_ORIGIN,
44832001f49Smrg                      org ? GL_LOWER_LEFT : GL_UPPER_LEFT);
44932001f49Smrg#endif
45032001f49Smrg#endif
45132001f49Smrg    glutPostRedisplay();
45232001f49Smrg    break;
45332001f49Smrg  case 't':
45432001f49Smrg  case 'T':
45532001f49Smrg    sprite ^= 1;
45632001f49Smrg    glutPostRedisplay();
45732001f49Smrg    break;
45832001f49Smrg  case 's':
45932001f49Smrg  case 'S':
46032001f49Smrg    (smooth ^= 1) ? glEnable(GL_POINT_SMOOTH) : glDisable(GL_POINT_SMOOTH);
46132001f49Smrg    glutPostRedisplay();
46232001f49Smrg    break;
46332001f49Smrg  case 'f':
46432001f49Smrg  case 'F':
46532001f49Smrg    if (HaveShaders) {
46632001f49Smrg       UseFragShader = !UseFragShader;
46732001f49Smrg       glutPostRedisplay();
46832001f49Smrg    }
46932001f49Smrg    break;
47032001f49Smrg  case '0':
47132001f49Smrg    glPointSize(1.0);
47232001f49Smrg    glutPostRedisplay();
47332001f49Smrg    break;
47432001f49Smrg  case '1':
47532001f49Smrg    glPointSize(16.0);
47632001f49Smrg    glutPostRedisplay();
47732001f49Smrg    break;
47832001f49Smrg  case '2':
47932001f49Smrg    glPointSize(32.0);
48032001f49Smrg    glutPostRedisplay();
48132001f49Smrg    break;
48232001f49Smrg  case '3':
48332001f49Smrg    glPointSize(64.0);
48432001f49Smrg    glutPostRedisplay();
48532001f49Smrg    break;
48632001f49Smrg  case '4':
48732001f49Smrg    glPointSize(128.0);
48832001f49Smrg    glutPostRedisplay();
48932001f49Smrg    break;
49032001f49Smrg  case 27:
49132001f49Smrg    exit(0);
49232001f49Smrg  }
49332001f49Smrg}
49432001f49Smrg
49532001f49Smrg
49632001f49Smrg
49732001f49Smrgstatic void
49832001f49SmrgmakeSpriteTextures(void)
49932001f49Smrg{
50032001f49Smrg   GLubyte texture[16][16][4];
50132001f49Smrg   int i, j;
50232001f49Smrg
50332001f49Smrg   if (!glutExtensionSupported("GL_ARB_point_sprite")) {
50432001f49Smrg      printf("Sorry, this demo requires GL_ARB_point_sprite.\n");
50532001f49Smrg      exit(0);
50632001f49Smrg   }
50732001f49Smrg   if (!glutExtensionSupported("GL_ARB_point_parameters")) {
50832001f49Smrg      printf("Sorry, this demo requires GL_ARB_point_parameters.\n");
50932001f49Smrg      exit(0);
51032001f49Smrg   }
51132001f49Smrg
51232001f49Smrg   /* "GL" */
51332001f49Smrg   for (i = 0; i < 16; i++) {
51432001f49Smrg      for (j = 0; j < 16; j++) {
51532001f49Smrg         if (spritePattern[i][j]) {
51632001f49Smrg            texture[i][j][0] = 255;
51732001f49Smrg            texture[i][j][1] = 255;
51832001f49Smrg            texture[i][j][2] = 255;
51932001f49Smrg            texture[i][j][3] = 255;
52032001f49Smrg         }
52132001f49Smrg         else {
52232001f49Smrg            texture[i][j][0] = 255;
52332001f49Smrg            texture[i][j][1] = 0;
52432001f49Smrg            texture[i][j][2] = 0;
52532001f49Smrg            texture[i][j][3] = 0;
52632001f49Smrg         }
52732001f49Smrg      }
52832001f49Smrg   }
52932001f49Smrg
53032001f49Smrg   /* texture 0 */
53132001f49Smrg   glActiveTexture(GL_TEXTURE0);
53232001f49Smrg   glGenTextures(1, &Tex0);
53332001f49Smrg   glBindTexture(GL_TEXTURE_2D, Tex0);
53432001f49Smrg   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE,
53532001f49Smrg                texture);
53632001f49Smrg   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
53732001f49Smrg   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
53832001f49Smrg
53932001f49Smrg   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
54032001f49Smrg#ifdef GL_ARB_point_sprite
54132001f49Smrg   glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
54232001f49Smrg#endif
54332001f49Smrg
54432001f49Smrg   /* left=yellow, right=green */
54532001f49Smrg   memset(texture, 0, sizeof(texture));
54632001f49Smrg   for (i = 0; i < 16; i++) {
54732001f49Smrg      for (j = 0; j < 16; j++) {
54832001f49Smrg         if (j < 8) {
54932001f49Smrg            texture[i][j][0] = 255;
55032001f49Smrg            texture[i][j][1] = 255;
55132001f49Smrg            texture[i][j][2] = 0;
55232001f49Smrg            texture[i][j][3] = 255;
55332001f49Smrg         }
55432001f49Smrg         else {
55532001f49Smrg            texture[i][j][0] = 0;
55632001f49Smrg            texture[i][j][1] = 255;
55732001f49Smrg            texture[i][j][2] = 0;
55832001f49Smrg            texture[i][j][3] = 255;
55932001f49Smrg         }
56032001f49Smrg      }
56132001f49Smrg   }
56232001f49Smrg
56332001f49Smrg   /* texture 1 */
56432001f49Smrg   glActiveTexture(GL_TEXTURE1);
56532001f49Smrg   glGenTextures(1, &Tex1);
56632001f49Smrg   glBindTexture(GL_TEXTURE_2D, Tex1);
56732001f49Smrg   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE,
56832001f49Smrg                texture);
56932001f49Smrg   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
57032001f49Smrg   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
57132001f49Smrg   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
57232001f49Smrg#ifdef GL_ARB_point_sprite
57332001f49Smrg   glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
57432001f49Smrg#endif
57532001f49Smrg
57632001f49Smrg   glActiveTexture(GL_TEXTURE0);
57732001f49Smrg}
57832001f49Smrg
57932001f49Smrg
58032001f49Smrgstatic void
58132001f49Smrgreshape(int width, int height)
58232001f49Smrg{
58332001f49Smrg  GLfloat h = (GLfloat) height / (GLfloat) width;
58432001f49Smrg
58532001f49Smrg  glViewport(0, 0, (GLint) width, (GLint) height);
58632001f49Smrg
58732001f49Smrg#if 0 /* debug/test code */
58832001f49Smrg  glMatrixMode(GL_TEXTURE);
58932001f49Smrg  glLoadIdentity();
59032001f49Smrg  glRotatef(45, 0, 0, 1);
59132001f49Smrg#endif
59232001f49Smrg
59332001f49Smrg  glMatrixMode(GL_PROJECTION);
59432001f49Smrg  glLoadIdentity();
59532001f49Smrg  glFrustum(-1.0, 1.0, -h, h, 2.0, 30.0);
59632001f49Smrg  glMatrixMode(GL_MODELVIEW);
59732001f49Smrg  glLoadIdentity();
59832001f49Smrg  glTranslatef(0.0, 0.0, -10.0);
59932001f49Smrg}
60032001f49Smrg
60132001f49Smrgint
60232001f49Smrgmain(int argc, char **argv)
60332001f49Smrg{
60432001f49Smrg  int i;
60532001f49Smrg
60632001f49Smrg  glutInitWindowSize(600,300);
60732001f49Smrg  glutInit(&argc, argv);
60832001f49Smrg  glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
60932001f49Smrg
61032001f49Smrg  for (i=1; i<argc; i++) {
61132001f49Smrg    if(!strcmp("-noms", argv[i])) {
61232001f49Smrg      glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
61332001f49Smrg      printf("forcing no multisampling\n");
61432001f49Smrg    } else if(!strcmp("-nomipmaps", argv[i])) {
61532001f49Smrg      useMipmaps = 0;
61632001f49Smrg    } else if(!strcmp("-nearest", argv[i])) {
61732001f49Smrg      linearFiltering = 0;
61832001f49Smrg    }
61932001f49Smrg  }
62032001f49Smrg  glutCreateWindow("sprite blast");
62132001f49Smrg  glewInit();
62232001f49Smrg  glutReshapeFunc(reshape);
62332001f49Smrg  glutDisplayFunc(redraw);
62432001f49Smrg  glutMouseFunc(mouse);
62532001f49Smrg  glutMotionFunc(mouseMotion);
62632001f49Smrg  glutVisibilityFunc(visible);
62732001f49Smrg  glutKeyboardFunc(key);
62832001f49Smrg  glutCreateMenu(menu);
62932001f49Smrg  glutAddMenuEntry("Reset time", 0);
63032001f49Smrg  glutAddMenuEntry("Constant", 1);
63132001f49Smrg  glutAddMenuEntry("Linear", 2);
63232001f49Smrg  glutAddMenuEntry("Quadratic", 3);
63332001f49Smrg  glutAddMenuEntry("Blend on", 4);
63432001f49Smrg  glutAddMenuEntry("Blend off", 5);
63532001f49Smrg  glutAddMenuEntry("Threshold 1", 6);
63632001f49Smrg  glutAddMenuEntry("Threshold 10", 7);
63732001f49Smrg  glutAddMenuEntry("Point smooth on", 8);
63832001f49Smrg  glutAddMenuEntry("Point smooth off", 9);
63932001f49Smrg  glutAddMenuEntry("Point size 16", 10);
64032001f49Smrg  glutAddMenuEntry("Point size 32", 11);
64132001f49Smrg  glutAddMenuEntry("Point size 64", 12);
64232001f49Smrg  glutAddMenuEntry("Toggle spin", 13);
64332001f49Smrg  glutAddMenuEntry("200 points ", 14);
64432001f49Smrg  glutAddMenuEntry("500 points ", 15);
64532001f49Smrg  glutAddMenuEntry("1000 points ", 16);
64632001f49Smrg  glutAddMenuEntry("2000 points ", 17);
64732001f49Smrg  glutAddMenuEntry("Quit", 666);
64832001f49Smrg  glutAttachMenu(GLUT_RIGHT_BUTTON);
64932001f49Smrg
65032001f49Smrg  makePointList();
65132001f49Smrg  makeSpriteTextures();
65232001f49Smrg  makeFragShader();
65332001f49Smrg
65432001f49Smrg  glShadeModel(GL_FLAT);
65532001f49Smrg  glEnable(GL_DEPTH_TEST);
65632001f49Smrg  glEnable(GL_POINT_SMOOTH);
65732001f49Smrg  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
65832001f49Smrg  glPointSize(32.0);
65932001f49Smrg#ifdef GL_ARB_point_parameters
66032001f49Smrg  glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, theQuad);
66132001f49Smrg#endif
66232001f49Smrg
66332001f49Smrg  glutMainLoop();
66432001f49Smrg  return 0;             /* ANSI C requires main to return int. */
66532001f49Smrg}
666