132001f49Smrg/*
232001f49Smrg * GL_ARB_texture_cube_map demo
332001f49Smrg *
432001f49Smrg * Brian Paul
532001f49Smrg * May 2000
632001f49Smrg *
732001f49Smrg *
832001f49Smrg * Copyright (C) 2000  Brian Paul   All Rights Reserved.
932001f49Smrg *
1032001f49Smrg * Permission is hereby granted, free of charge, to any person obtaining a
1132001f49Smrg * copy of this software and associated documentation files (the "Software"),
1232001f49Smrg * to deal in the Software without restriction, including without limitation
1332001f49Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1432001f49Smrg * and/or sell copies of the Software, and to permit persons to whom the
1532001f49Smrg * Software is furnished to do so, subject to the following conditions:
1632001f49Smrg *
1732001f49Smrg * The above copyright notice and this permission notice shall be included
1832001f49Smrg * in all copies or substantial portions of the Software.
1932001f49Smrg *
2032001f49Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
2132001f49Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2232001f49Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
2332001f49Smrg * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
2432001f49Smrg * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2532001f49Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2632001f49Smrg */
2732001f49Smrg
2832001f49Smrg
2932001f49Smrg/*
3032001f49Smrg * This is a pretty minimalistic demo for now.  Eventually, use some
3132001f49Smrg * interesting cube map textures and 3D objects.
3232001f49Smrg * For now, we use 6 checkerboard "walls" and a sphere (good for
3332001f49Smrg * verification purposes).
3432001f49Smrg */
3532001f49Smrg
3632001f49Smrg
3732001f49Smrg#include <assert.h>
3832001f49Smrg#include <math.h>
3932001f49Smrg#include <stdio.h>
4032001f49Smrg#include <stdlib.h>
4132001f49Smrg#include <string.h>
4232001f49Smrg#include <GL/glew.h>
4332001f49Smrg#include "glut_wrap.h"
4432001f49Smrg#include "readtex.h"
4532001f49Smrg
4632001f49Smrg#ifndef GL_TEXTURE_CUBE_MAP_SEAMLESS
4732001f49Smrg#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F
4832001f49Smrg#endif
4932001f49Smrg
5032001f49Smrgstatic GLfloat Xrot = 0, Yrot = 0;
5132001f49Smrgstatic GLfloat EyeDist = 10;
5232001f49Smrgstatic GLboolean use_vertex_arrays = GL_FALSE;
5332001f49Smrgstatic GLboolean anim = GL_TRUE;
5432001f49Smrgstatic GLboolean NoClear = GL_FALSE;
5532001f49Smrgstatic GLint FrameParity = 0;
5632001f49Smrgstatic GLenum FilterIndex = 0;
5732001f49Smrgstatic GLint ClampIndex = 0;
5832001f49Smrgstatic GLboolean supportFBO = GL_FALSE;
5932001f49Smrgstatic GLboolean supportSeamless = GL_FALSE;
6032001f49Smrgstatic GLboolean seamless = GL_FALSE;
6132001f49Smrgstatic GLuint TexObj = 0;
6232001f49Smrgstatic GLint T0 = 0;
6332001f49Smrgstatic GLint Frames = 0;
6432001f49Smrg
6532001f49Smrg
6632001f49Smrgstatic struct {
6732001f49Smrg   GLenum mode;
6832001f49Smrg   const char *name;
6932001f49Smrg} ClampModes[] = {
7032001f49Smrg   { GL_CLAMP_TO_EDGE, "GL_CLAMP_TO_EDGE" },
7132001f49Smrg   { GL_CLAMP_TO_BORDER, "GL_CLAMP_TO_BORDER" },
7232001f49Smrg   { GL_CLAMP, "GL_CLAMP" },
7332001f49Smrg   { GL_REPEAT, "GL_REPEAT" }
7432001f49Smrg};
7532001f49Smrg
7632001f49Smrg#define NUM_CLAMP_MODES (sizeof(ClampModes) / sizeof(ClampModes[0]))
7732001f49Smrg
7832001f49Smrg
7932001f49Smrgstatic struct {
8032001f49Smrg   GLenum mag_mode, min_mode;
8132001f49Smrg   const char *name;
8232001f49Smrg} FilterModes[] = {
8332001f49Smrg   { GL_NEAREST, GL_NEAREST, "GL_NEAREST, GL_NEAREST" },
8432001f49Smrg   { GL_NEAREST, GL_LINEAR, "GL_NEAREST, GL_LINEAR" },
8532001f49Smrg   { GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST, "GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST" },
8632001f49Smrg   { GL_NEAREST, GL_NEAREST_MIPMAP_LINEAR, "GL_NEAREST, GL_NEAREST_MIPMAP_LINEAR" },
8732001f49Smrg   { GL_NEAREST, GL_LINEAR_MIPMAP_NEAREST, "GL_NEAREST, GL_LINEAR_MIPMAP_NEAREST" },
8832001f49Smrg   { GL_NEAREST, GL_LINEAR_MIPMAP_LINEAR, "GL_NEAREST, GL_LINEAR_MIPMAP_LINEAR" },
8932001f49Smrg
9032001f49Smrg   { GL_LINEAR, GL_NEAREST, "GL_LINEAR, GL_NEAREST" },
9132001f49Smrg   { GL_LINEAR, GL_LINEAR, "GL_LINEAR, GL_LINEAR" },
9232001f49Smrg   { GL_LINEAR, GL_NEAREST_MIPMAP_NEAREST, "GL_LINEAR, GL_NEAREST_MIPMAP_NEAREST" },
9332001f49Smrg   { GL_LINEAR, GL_NEAREST_MIPMAP_LINEAR, "GL_LINEAR, GL_NEAREST_MIPMAP_LINEAR" },
9432001f49Smrg   { GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, "GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST" },
9532001f49Smrg   { GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, "GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR" }
9632001f49Smrg};
9732001f49Smrg
9832001f49Smrg#define NUM_FILTER_MODES (sizeof(FilterModes) / sizeof(FilterModes[0]))
9932001f49Smrg
10032001f49Smrg
10132001f49Smrg
10232001f49Smrg/* The effects of GL_ARB_seamless_cube_map don't show up unless eps1 is 1.0.
10332001f49Smrg */
10432001f49Smrg#define eps1 1.0 /*0.99*/
10532001f49Smrg#define br   20.0  /* box radius */
10632001f49Smrg
10732001f49Smrgstatic const GLfloat tex_coords[] = {
10832001f49Smrg   /* +X side */
10932001f49Smrg   1.0, -eps1, -eps1,
11032001f49Smrg   1.0, -eps1,  eps1,
11132001f49Smrg   1.0,  eps1,  eps1,
11232001f49Smrg   1.0,  eps1, -eps1,
11332001f49Smrg
11432001f49Smrg   /* -X side */
11532001f49Smrg   -1.0,  eps1, -eps1,
11632001f49Smrg   -1.0,  eps1,  eps1,
11732001f49Smrg   -1.0, -eps1,  eps1,
11832001f49Smrg   -1.0, -eps1, -eps1,
11932001f49Smrg
12032001f49Smrg   /* +Y side */
12132001f49Smrg   -eps1, 1.0, -eps1,
12232001f49Smrg   -eps1, 1.0,  eps1,
12332001f49Smrg    eps1, 1.0,  eps1,
12432001f49Smrg    eps1, 1.0, -eps1,
12532001f49Smrg
12632001f49Smrg   /* -Y side */
12732001f49Smrg   -eps1, -1.0, -eps1,
12832001f49Smrg   -eps1, -1.0,  eps1,
12932001f49Smrg    eps1, -1.0,  eps1,
13032001f49Smrg    eps1, -1.0, -eps1,
13132001f49Smrg
13232001f49Smrg   /* +Z side */
13332001f49Smrg    eps1, -eps1, 1.0,
13432001f49Smrg   -eps1, -eps1, 1.0,
13532001f49Smrg   -eps1,  eps1, 1.0,
13632001f49Smrg    eps1,  eps1, 1.0,
13732001f49Smrg
13832001f49Smrg   /* -Z side */
13932001f49Smrg    eps1,  eps1, -1.0,
14032001f49Smrg   -eps1,  eps1, -1.0,
14132001f49Smrg   -eps1, -eps1, -1.0,
14232001f49Smrg    eps1, -eps1, -1.0,
14332001f49Smrg};
14432001f49Smrg
14532001f49Smrgstatic const GLfloat vtx_coords[] = {
14632001f49Smrg   /* +X side */
14732001f49Smrg   br, -br, -br,
14832001f49Smrg   br, -br,  br,
14932001f49Smrg   br,  br,  br,
15032001f49Smrg   br,  br, -br,
15132001f49Smrg
15232001f49Smrg   /* -X side */
15332001f49Smrg   -br,  br, -br,
15432001f49Smrg   -br,  br,  br,
15532001f49Smrg   -br, -br,  br,
15632001f49Smrg   -br, -br, -br,
15732001f49Smrg
15832001f49Smrg   /* +Y side */
15932001f49Smrg   -br,  br, -br,
16032001f49Smrg   -br,  br,  br,
16132001f49Smrg    br,  br,  br,
16232001f49Smrg    br,  br, -br,
16332001f49Smrg
16432001f49Smrg   /* -Y side */
16532001f49Smrg   -br, -br, -br,
16632001f49Smrg   -br, -br,  br,
16732001f49Smrg    br, -br,  br,
16832001f49Smrg    br, -br, -br,
16932001f49Smrg
17032001f49Smrg   /* +Z side */
17132001f49Smrg    br, -br, br,
17232001f49Smrg   -br, -br, br,
17332001f49Smrg   -br,  br, br,
17432001f49Smrg    br,  br, br,
17532001f49Smrg
17632001f49Smrg   /* -Z side */
17732001f49Smrg    br,  br, -br,
17832001f49Smrg   -br,  br, -br,
17932001f49Smrg   -br, -br, -br,
18032001f49Smrg    br, -br, -br,
18132001f49Smrg};
18232001f49Smrg
18332001f49Smrgstatic void draw_skybox( void )
18432001f49Smrg{
18532001f49Smrg   if ( use_vertex_arrays ) {
18632001f49Smrg      glTexCoordPointer( 3, GL_FLOAT, 0, tex_coords );
18732001f49Smrg      glVertexPointer(   3, GL_FLOAT, 0, vtx_coords );
18832001f49Smrg
18932001f49Smrg      glEnableClientState( GL_TEXTURE_COORD_ARRAY );
19032001f49Smrg      glEnableClientState( GL_VERTEX_ARRAY );
19132001f49Smrg
19232001f49Smrg      glDrawArrays( GL_QUADS, 0, 24 );
19332001f49Smrg
19432001f49Smrg      glDisableClientState( GL_TEXTURE_COORD_ARRAY );
19532001f49Smrg      glDisableClientState( GL_VERTEX_ARRAY );
19632001f49Smrg   }
19732001f49Smrg   else {
19832001f49Smrg      unsigned   i;
19932001f49Smrg
20032001f49Smrg      glBegin(GL_QUADS);
20132001f49Smrg      for ( i = 0 ; i < 24 ; i++ ) {
20232001f49Smrg	 glTexCoord3fv( & tex_coords[ i * 3 ] );
20332001f49Smrg	 glVertex3fv  ( & vtx_coords[ i * 3 ] );
20432001f49Smrg      }
20532001f49Smrg      glEnd();
20632001f49Smrg   }
20732001f49Smrg}
20832001f49Smrg
20932001f49Smrg
21032001f49Smrgstatic void draw( void )
21132001f49Smrg{
21232001f49Smrg   GLenum wrap;
21332001f49Smrg
21432001f49Smrg   if (NoClear) {
21532001f49Smrg      /* This demonstrates how we can avoid calling glClear.
21632001f49Smrg       * This method only works if every pixel in the window is painted for
21732001f49Smrg       * every frame.
21832001f49Smrg       * We can simply skip clearing of the color buffer in this case.
21932001f49Smrg       * For the depth buffer, we alternately use a different subrange of
22032001f49Smrg       * the depth buffer for each frame.  For the odd frame use the range
22132001f49Smrg       * [0, 0.5] with GL_LESS.  For the even frames, use the range [1, 0.5]
22232001f49Smrg       * with GL_GREATER.
22332001f49Smrg       */
22432001f49Smrg      FrameParity = 1 - FrameParity;
22532001f49Smrg      if (FrameParity) {
22632001f49Smrg         glDepthRange(0.0, 0.5);
22732001f49Smrg         glDepthFunc(GL_LESS);
22832001f49Smrg      }
22932001f49Smrg      else {
23032001f49Smrg         glDepthRange(1.0, 0.5);
23132001f49Smrg         glDepthFunc(GL_GREATER);
23232001f49Smrg      }
23332001f49Smrg   }
23432001f49Smrg   else {
23532001f49Smrg      /* ordinary clearing */
23632001f49Smrg      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
23732001f49Smrg   }
23832001f49Smrg
23932001f49Smrg   glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER,
24032001f49Smrg                   FilterModes[FilterIndex].min_mode);
24132001f49Smrg   glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER,
24232001f49Smrg                   FilterModes[FilterIndex].mag_mode);
24332001f49Smrg
24432001f49Smrg   if (supportSeamless) {
24532001f49Smrg      if (seamless) {
24632001f49Smrg	 glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
24732001f49Smrg      } else {
24832001f49Smrg	 glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
24932001f49Smrg      }
25032001f49Smrg   }
25132001f49Smrg   wrap = ClampModes[ClampIndex].mode;
25232001f49Smrg   glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, wrap);
25332001f49Smrg   glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, wrap);
25432001f49Smrg   glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_R, wrap);
25532001f49Smrg
25632001f49Smrg   glPushMatrix(); /*MODELVIEW*/
25732001f49Smrg      glTranslatef( 0.0, 0.0, -EyeDist );
25832001f49Smrg
25932001f49Smrg      /* skybox */
26032001f49Smrg      glDisable(GL_TEXTURE_GEN_S);
26132001f49Smrg      glDisable(GL_TEXTURE_GEN_T);
26232001f49Smrg      glDisable(GL_TEXTURE_GEN_R);
26332001f49Smrg
26432001f49Smrg      glMatrixMode(GL_MODELVIEW);
26532001f49Smrg      glPushMatrix();
26632001f49Smrg         glRotatef(Xrot, 1, 0, 0);
26732001f49Smrg         glRotatef(Yrot, 0, 1, 0);
26832001f49Smrg         draw_skybox();
26932001f49Smrg      glPopMatrix();
27032001f49Smrg
27132001f49Smrg      /* sphere */
27232001f49Smrg      glMatrixMode(GL_TEXTURE);
27332001f49Smrg      glLoadIdentity();
27432001f49Smrg      glRotatef(-Yrot, 0, 1, 0);
27532001f49Smrg      glRotatef(-Xrot, 1, 0, 0);
27632001f49Smrg
27732001f49Smrg      glEnable(GL_TEXTURE_GEN_S);
27832001f49Smrg      glEnable(GL_TEXTURE_GEN_T);
27932001f49Smrg      glEnable(GL_TEXTURE_GEN_R);
28032001f49Smrg      glutSolidSphere(2.0, 20, 20);
28132001f49Smrg
28232001f49Smrg      glLoadIdentity(); /* texture */
28332001f49Smrg
28432001f49Smrg      glMatrixMode(GL_MODELVIEW);
28532001f49Smrg   glPopMatrix();
28632001f49Smrg
28732001f49Smrg   glutSwapBuffers();
28832001f49Smrg
28932001f49Smrg   Frames++;
29032001f49Smrg
29132001f49Smrg   {
29232001f49Smrg      GLint t = glutGet(GLUT_ELAPSED_TIME);
29332001f49Smrg      if (t - T0 >= 5000) {
29432001f49Smrg	 GLfloat seconds = (t - T0) / 1000.0;
29532001f49Smrg	 GLfloat fps = Frames / seconds;
29632001f49Smrg	 printf("%d frames in %6.3f seconds = %6.3f FPS\n", Frames, seconds, fps);
29732001f49Smrg	 fflush(stdout);
29832001f49Smrg	 T0 = t;
29932001f49Smrg	 Frames = 0;
30032001f49Smrg      }
30132001f49Smrg   }
30232001f49Smrg}
30332001f49Smrg
30432001f49Smrg
30532001f49Smrgstatic void idle(void)
30632001f49Smrg{
30732001f49Smrg   GLfloat t = 0.05 * glutGet(GLUT_ELAPSED_TIME);
30832001f49Smrg   Yrot = t;
30932001f49Smrg   glutPostRedisplay();
31032001f49Smrg}
31132001f49Smrg
31232001f49Smrg
31332001f49Smrgstatic void set_mode(GLuint mode)
31432001f49Smrg{
31532001f49Smrg   if (mode == 0) {
31632001f49Smrg      glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB);
31732001f49Smrg      glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB);
31832001f49Smrg      glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB);
31932001f49Smrg      printf("GL_REFLECTION_MAP_ARB mode\n");
32032001f49Smrg   }
32132001f49Smrg   else if (mode == 1) {
32232001f49Smrg      glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_ARB);
32332001f49Smrg      glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_ARB);
32432001f49Smrg      glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_ARB);
32532001f49Smrg      printf("GL_NORMAL_MAP_ARB mode\n");
32632001f49Smrg   }
32732001f49Smrg}
32832001f49Smrg
32932001f49Smrg
33032001f49Smrgstatic void key(unsigned char k, int x, int y)
33132001f49Smrg{
33232001f49Smrg   static GLuint mode = 0;
33332001f49Smrg   (void) x;
33432001f49Smrg   (void) y;
33532001f49Smrg   switch (k) {
33632001f49Smrg      case ' ':
33732001f49Smrg         anim = !anim;
33832001f49Smrg         if (anim)
33932001f49Smrg            glutIdleFunc(idle);
34032001f49Smrg         else
34132001f49Smrg            glutIdleFunc(NULL);
34232001f49Smrg         break;
34332001f49Smrg      case 'f':
34432001f49Smrg         FilterIndex = (FilterIndex + 1) % NUM_FILTER_MODES;
34532001f49Smrg         printf("Tex filter: %s\n", FilterModes[FilterIndex].name);
34632001f49Smrg         break;
34732001f49Smrg      case 'c':
34832001f49Smrg         ClampIndex = (ClampIndex + 1) % NUM_CLAMP_MODES;
34932001f49Smrg         printf("Tex wrap mode: %s\n", ClampModes[ClampIndex].name);
35032001f49Smrg         break;
35132001f49Smrg      case 'm':
35232001f49Smrg         mode = !mode;
35332001f49Smrg         set_mode(mode);
35432001f49Smrg         break;
35532001f49Smrg      case 's':
35632001f49Smrg	 seamless = ! seamless;
35732001f49Smrg	 printf("Seamless cube map filtering is %sabled\n",
35832001f49Smrg		(seamless) ? "en" : "dis" );
35932001f49Smrg	 break;
36032001f49Smrg      case 'v':
36132001f49Smrg         use_vertex_arrays = ! use_vertex_arrays;
36232001f49Smrg         printf( "Vertex arrays are %sabled\n",
36332001f49Smrg		 (use_vertex_arrays) ? "en" : "dis" );
36432001f49Smrg         break;
36532001f49Smrg      case 'z':
36632001f49Smrg         EyeDist -= 0.5;
36732001f49Smrg         if (EyeDist < 6.0)
36832001f49Smrg            EyeDist = 6.0;
36932001f49Smrg         break;
37032001f49Smrg      case 'Z':
37132001f49Smrg         EyeDist += 0.5;
37232001f49Smrg         if (EyeDist > 90.0)
37332001f49Smrg            EyeDist = 90;
37432001f49Smrg         break;
37532001f49Smrg      case 27:
37632001f49Smrg         exit(0);
37732001f49Smrg   }
37832001f49Smrg   fflush(stdout);
37932001f49Smrg   glutPostRedisplay();
38032001f49Smrg}
38132001f49Smrg
38232001f49Smrg
38332001f49Smrgstatic void specialkey(int key, int x, int y)
38432001f49Smrg{
38532001f49Smrg   GLfloat step = 5;
38632001f49Smrg   (void) x;
38732001f49Smrg   (void) y;
38832001f49Smrg   switch (key) {
38932001f49Smrg      case GLUT_KEY_UP:
39032001f49Smrg         Xrot += step;
39132001f49Smrg         break;
39232001f49Smrg      case GLUT_KEY_DOWN:
39332001f49Smrg         Xrot -= step;
39432001f49Smrg         break;
39532001f49Smrg      case GLUT_KEY_LEFT:
39632001f49Smrg         Yrot -= step;
39732001f49Smrg         break;
39832001f49Smrg      case GLUT_KEY_RIGHT:
39932001f49Smrg         Yrot += step;
40032001f49Smrg         break;
40132001f49Smrg   }
40232001f49Smrg   glutPostRedisplay();
40332001f49Smrg}
40432001f49Smrg
40532001f49Smrg
40632001f49Smrg/* new window size or exposure */
40732001f49Smrgstatic void reshape(int width, int height)
40832001f49Smrg{
40932001f49Smrg   GLfloat ar = (float) width / (float) height;
41032001f49Smrg   glViewport(0, 0, (GLint)width, (GLint)height);
41132001f49Smrg   glMatrixMode(GL_PROJECTION);
41232001f49Smrg   glLoadIdentity();
41332001f49Smrg   glFrustum( -2.0*ar, 2.0*ar, -2.0, 2.0, 4.0, 100.0 );
41432001f49Smrg   glMatrixMode(GL_MODELVIEW);
41532001f49Smrg   glLoadIdentity();
41632001f49Smrg}
41732001f49Smrg
41832001f49Smrg
41932001f49Smrgstatic void init_checkers( void )
42032001f49Smrg{
42132001f49Smrg#define CUBE_TEX_SIZE 64
42232001f49Smrg   GLubyte image[CUBE_TEX_SIZE][CUBE_TEX_SIZE][4];
42332001f49Smrg   static const GLubyte colors[6][3] = {
42432001f49Smrg      { 255,   0,   0 },	/* face 0 - red */
42532001f49Smrg      {   0, 255, 255 },	/* face 1 - cyan */
42632001f49Smrg      {   0, 255,   0 },	/* face 2 - green */
42732001f49Smrg      { 255,   0, 255 },	/* face 3 - purple */
42832001f49Smrg      {   0,   0, 255 },	/* face 4 - blue */
42932001f49Smrg      { 255, 255,   0 }		/* face 5 - yellow */
43032001f49Smrg   };
43132001f49Smrg   static const GLenum targets[6] = {
43232001f49Smrg      GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
43332001f49Smrg      GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
43432001f49Smrg      GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
43532001f49Smrg      GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
43632001f49Smrg      GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
43732001f49Smrg      GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
43832001f49Smrg   };
43932001f49Smrg
44032001f49Smrg   GLint i, j, f;
44132001f49Smrg
44232001f49Smrg   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
44332001f49Smrg
44432001f49Smrg   if (!supportFBO)
44532001f49Smrg      glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
44632001f49Smrg
44732001f49Smrg
44832001f49Smrg   /* make colored checkerboard cube faces */
44932001f49Smrg   for (f = 0; f < 6; f++) {
45032001f49Smrg      for (i = 0; i < CUBE_TEX_SIZE; i++) {
45132001f49Smrg         for (j = 0; j < CUBE_TEX_SIZE; j++) {
45232001f49Smrg            if ((i/4 + j/4) & 1) {
45332001f49Smrg               image[i][j][0] = colors[f][2];
45432001f49Smrg               image[i][j][1] = colors[f][1];
45532001f49Smrg               image[i][j][2] = colors[f][0];
45632001f49Smrg               image[i][j][3] = 255;
45732001f49Smrg            }
45832001f49Smrg            else {
45932001f49Smrg               image[i][j][0] = 255;
46032001f49Smrg               image[i][j][1] = 255;
46132001f49Smrg               image[i][j][2] = 255;
46232001f49Smrg               image[i][j][3] = 255;
46332001f49Smrg            }
46432001f49Smrg         }
46532001f49Smrg      }
46632001f49Smrg
46732001f49Smrg      glTexImage2D(targets[f], 0, GL_RGBA8, CUBE_TEX_SIZE, CUBE_TEX_SIZE, 0,
46832001f49Smrg                   GL_BGRA, GL_UNSIGNED_BYTE, image);
46932001f49Smrg   }
47032001f49Smrg
47132001f49Smrg   if (supportFBO)
47232001f49Smrg      glGenerateMipmapEXT(GL_TEXTURE_CUBE_MAP_ARB);
47332001f49Smrg}
47432001f49Smrg
47532001f49Smrg
47632001f49Smrgstatic void load(GLenum target, const char *filename,
47732001f49Smrg                 GLboolean flipTB, GLboolean flipLR)
47832001f49Smrg{
47932001f49Smrg   GLint w, h;
48032001f49Smrg   GLenum format;
48132001f49Smrg   GLubyte *img = LoadRGBImage( filename, &w, &h, &format );
48232001f49Smrg   if (!img) {
48332001f49Smrg      printf("Error: couldn't load texture image %s\n", filename);
48432001f49Smrg      exit(1);
48532001f49Smrg   }
48632001f49Smrg   assert(format == GL_RGB);
48732001f49Smrg
48832001f49Smrg   /* <sigh> the way the texture cube mapping works, we have to flip
48932001f49Smrg    * images to make things look right.
49032001f49Smrg    */
49132001f49Smrg   if (flipTB) {
49232001f49Smrg      const int stride = 3 * w;
49332001f49Smrg      GLubyte temp[3*1024];
49432001f49Smrg      int i;
49532001f49Smrg      for (i = 0; i < h / 2; i++) {
49632001f49Smrg         memcpy(temp, img + i * stride, stride);
49732001f49Smrg         memcpy(img + i * stride, img + (h - i - 1) * stride, stride);
49832001f49Smrg         memcpy(img + (h - i - 1) * stride, temp, stride);
49932001f49Smrg      }
50032001f49Smrg   }
50132001f49Smrg   if (flipLR) {
50232001f49Smrg      const int stride = 3 * w;
50332001f49Smrg      GLubyte temp[3];
50432001f49Smrg      GLubyte *row;
50532001f49Smrg      int i, j;
50632001f49Smrg      for (i = 0; i < h; i++) {
50732001f49Smrg         row = img + i * stride;
50832001f49Smrg         for (j = 0; j < w / 2; j++) {
50932001f49Smrg            int k = w - j - 1;
51032001f49Smrg            temp[0] = row[j*3+0];
51132001f49Smrg            temp[1] = row[j*3+1];
51232001f49Smrg            temp[2] = row[j*3+2];
51332001f49Smrg            row[j*3+0] = row[k*3+0];
51432001f49Smrg            row[j*3+1] = row[k*3+1];
51532001f49Smrg            row[j*3+2] = row[k*3+2];
51632001f49Smrg            row[k*3+0] = temp[0];
51732001f49Smrg            row[k*3+1] = temp[1];
51832001f49Smrg            row[k*3+2] = temp[2];
51932001f49Smrg         }
52032001f49Smrg      }
52132001f49Smrg   }
52232001f49Smrg
52332001f49Smrg   gluBuild2DMipmaps(target, GL_RGB, w, h, format, GL_UNSIGNED_BYTE, img);
52432001f49Smrg   free(img);
52532001f49Smrg}
52632001f49Smrg
52732001f49Smrg
52832001f49Smrgstatic void load_envmaps(void)
52932001f49Smrg{
53032001f49Smrg   load(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, "right.rgb", GL_TRUE, GL_FALSE);
53132001f49Smrg   load(GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, "left.rgb", GL_TRUE, GL_FALSE);
53232001f49Smrg   load(GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, "top.rgb", GL_FALSE, GL_TRUE);
53332001f49Smrg   load(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, "bottom.rgb", GL_FALSE, GL_TRUE);
53432001f49Smrg   load(GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, "front.rgb", GL_TRUE, GL_FALSE);
53532001f49Smrg   load(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB, "back.rgb", GL_TRUE, GL_FALSE);
53632001f49Smrg}
53732001f49Smrg
53832001f49Smrg
53932001f49Smrgstatic void init( GLboolean useImageFiles )
54032001f49Smrg{
54132001f49Smrg   /* check for extensions */
54232001f49Smrg   if (!GLEW_ARB_texture_cube_map) {
54332001f49Smrg      printf("Sorry, this demo requires GL_ARB_texture_cube_map\n");
54432001f49Smrg      exit(0);
54532001f49Smrg   }
54632001f49Smrg
54732001f49Smrg   /* Needed for glGenerateMipmapEXT / auto mipmapping
54832001f49Smrg    */
54932001f49Smrg   supportFBO = GLEW_EXT_framebuffer_object;
55032001f49Smrg
55132001f49Smrg   if (!supportFBO && !GLEW_SGIS_generate_mipmap) {
55232001f49Smrg      printf("Sorry, this demo requires GL_EXT_framebuffer_object or "
55332001f49Smrg	     "GL_SGIS_generate_mipmap\n");
55432001f49Smrg      exit(0);
55532001f49Smrg   }
55632001f49Smrg
55732001f49Smrg   /* GLEW doesn't know about this extension yet, so use the old GLUT function
55832001f49Smrg    * to check for availability.
55932001f49Smrg    */
56032001f49Smrg   supportSeamless = glutExtensionSupported("GL_ARB_seamless_cube_map");
56132001f49Smrg
56232001f49Smrg   printf("GL_RENDERER: %s\n", (char *) glGetString(GL_RENDERER));
56332001f49Smrg
56432001f49Smrg
56532001f49Smrg   glGenTextures(1, &TexObj);
56632001f49Smrg   glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, TexObj);
56732001f49Smrg
56832001f49Smrg   if (useImageFiles) {
56932001f49Smrg      load_envmaps();
57032001f49Smrg   }
57132001f49Smrg   else {
57232001f49Smrg      init_checkers();
57332001f49Smrg   }
57432001f49Smrg
57532001f49Smrg   glEnable(GL_TEXTURE_CUBE_MAP_ARB);
57632001f49Smrg   glEnable(GL_DEPTH_TEST);
57732001f49Smrg
57832001f49Smrg   glClearColor(.3, .3, .3, 0);
57932001f49Smrg   glColor3f( 1.0, 1.0, 1.0 );
58032001f49Smrg
58132001f49Smrg   set_mode(0);
58232001f49Smrg}
58332001f49Smrg
58432001f49Smrg
58532001f49Smrgstatic void usage(void)
58632001f49Smrg{
58732001f49Smrg   printf("keys:\n");
58832001f49Smrg   printf("  SPACE - toggle animation\n");
58932001f49Smrg   printf("  CURSOR KEYS - rotation\n");
59032001f49Smrg   printf("  c - toggle texture clamp/wrap mode\n");
59132001f49Smrg   printf("  f - toggle texture filter mode\n");
59232001f49Smrg   printf("  m - toggle texgen reflection mode\n");
59332001f49Smrg   printf("  z/Z - change viewing distance\n");
59432001f49Smrg   fflush(stdout);
59532001f49Smrg}
59632001f49Smrg
59732001f49Smrg
59832001f49Smrgstatic void parse_args(int argc, char *argv[])
59932001f49Smrg{
60032001f49Smrg   int initFlag = 0;
60132001f49Smrg   int i;
60232001f49Smrg
60332001f49Smrg   for (i = 1; i < argc; i++) {
60432001f49Smrg      if (strcmp(argv[i], "-i") == 0)
60532001f49Smrg         initFlag = 1;
60632001f49Smrg      else if (strcmp(argv[i], "--noclear") == 0)
60732001f49Smrg         NoClear = GL_TRUE;
60832001f49Smrg      else {
60932001f49Smrg         fprintf(stderr, "Bad option: %s\n", argv[i]);
61032001f49Smrg         exit(1);
61132001f49Smrg      }
61232001f49Smrg   }
61332001f49Smrg   init (initFlag);
61432001f49Smrg}
61532001f49Smrg
61632001f49Smrgint main( int argc, char *argv[] )
61732001f49Smrg{
61832001f49Smrg   glutInitWindowSize(600, 500);
61932001f49Smrg   glutInit(&argc, argv);
62032001f49Smrg   glutInitDisplayMode( GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE );
62132001f49Smrg   glutCreateWindow("Texture Cube Mapping");
62232001f49Smrg   glewInit();
62332001f49Smrg   glutReshapeFunc( reshape );
62432001f49Smrg   glutKeyboardFunc( key );
62532001f49Smrg   glutSpecialFunc( specialkey );
62632001f49Smrg   glutDisplayFunc( draw );
62732001f49Smrg   if (anim)
62832001f49Smrg      glutIdleFunc(idle);
62932001f49Smrg   parse_args(argc, argv);
63032001f49Smrg   usage();
63132001f49Smrg   glutMainLoop();
63232001f49Smrg   return 0;
63332001f49Smrg}
634