2 * GL_ARB_texture_cube_map demo
8 * Copyright (C) 2000 Brian Paul All Rights Reserved.
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
24 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 * This is a pretty minimalistic demo for now. Eventually, use some
31 * interesting cube map textures and 3D objects.
32 * For now, we use 6 checkerboard "walls" and a sphere (good for
33 * verification purposes).
47 static GLfloat Xrot
= 0, Yrot
= 0;
48 static GLfloat EyeDist
= 10;
49 static GLboolean use_vertex_arrays
= GL_FALSE
;
50 static GLboolean anim
= GL_TRUE
;
51 static GLboolean NoClear
= GL_FALSE
;
52 static GLint FrameParity
= 0;
53 static GLenum FilterIndex
= 0;
54 static GLint ClampIndex
= 0;
61 { GL_CLAMP_TO_EDGE
, "GL_CLAMP_TO_EDGE" },
62 { GL_CLAMP_TO_BORDER
, "GL_CLAMP_TO_BORDER" },
63 { GL_CLAMP
, "GL_CLAMP" },
64 { GL_REPEAT
, "GL_REPEAT" }
67 #define NUM_CLAMP_MODES (sizeof(ClampModes) / sizeof(ClampModes[0]))
71 GLenum mag_mode
, min_mode
;
74 { GL_NEAREST
, GL_NEAREST
, "GL_NEAREST, GL_NEAREST" },
75 { GL_NEAREST
, GL_LINEAR
, "GL_NEAREST, GL_LINEAR" },
76 { GL_NEAREST
, GL_NEAREST_MIPMAP_NEAREST
, "GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST" },
77 { GL_NEAREST
, GL_NEAREST_MIPMAP_LINEAR
, "GL_NEAREST, GL_NEAREST_MIPMAP_LINEAR" },
78 { GL_NEAREST
, GL_LINEAR_MIPMAP_NEAREST
, "GL_NEAREST, GL_LINEAR_MIPMAP_NEAREST" },
79 { GL_NEAREST
, GL_LINEAR_MIPMAP_LINEAR
, "GL_NEAREST, GL_LINEAR_MIPMAP_LINEAR" },
81 { GL_LINEAR
, GL_NEAREST
, "GL_LINEAR, GL_NEAREST" },
82 { GL_LINEAR
, GL_LINEAR
, "GL_LINEAR, GL_LINEAR" },
83 { GL_LINEAR
, GL_NEAREST_MIPMAP_NEAREST
, "GL_LINEAR, GL_NEAREST_MIPMAP_NEAREST" },
84 { GL_LINEAR
, GL_NEAREST_MIPMAP_LINEAR
, "GL_LINEAR, GL_NEAREST_MIPMAP_LINEAR" },
85 { GL_LINEAR
, GL_LINEAR_MIPMAP_NEAREST
, "GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST" },
86 { GL_LINEAR
, GL_LINEAR_MIPMAP_LINEAR
, "GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR" }
89 #define NUM_FILTER_MODES (sizeof(FilterModes) / sizeof(FilterModes[0]))
94 #define br 20.0 /* box radius */
96 static const GLfloat tex_coords
[] = {
134 static const GLfloat vtx_coords
[] = {
172 static void draw_skybox( void )
174 if ( use_vertex_arrays
) {
175 glTexCoordPointer( 3, GL_FLOAT
, 0, tex_coords
);
176 glVertexPointer( 3, GL_FLOAT
, 0, vtx_coords
);
178 glEnableClientState( GL_TEXTURE_COORD_ARRAY
);
179 glEnableClientState( GL_VERTEX_ARRAY
);
181 glDrawArrays( GL_QUADS
, 0, 24 );
183 glDisableClientState( GL_TEXTURE_COORD_ARRAY
);
184 glDisableClientState( GL_VERTEX_ARRAY
);
190 for ( i
= 0 ; i
< 24 ; i
++ ) {
191 glTexCoord3fv( & tex_coords
[ i
* 3 ] );
192 glVertex3fv ( & vtx_coords
[ i
* 3 ] );
199 static void draw( void )
204 /* This demonstrates how we can avoid calling glClear.
205 * This method only works if every pixel in the window is painted for
207 * We can simply skip clearing of the color buffer in this case.
208 * For the depth buffer, we alternately use a different subrange of
209 * the depth buffer for each frame. For the odd frame use the range
210 * [0, 0.5] with GL_LESS. For the even frames, use the range [1, 0.5]
213 FrameParity
= 1 - FrameParity
;
215 glDepthRange(0.0, 0.5);
216 glDepthFunc(GL_LESS
);
219 glDepthRange(1.0, 0.5);
220 glDepthFunc(GL_GREATER
);
224 /* ordinary clearing */
225 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
228 glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB
, GL_TEXTURE_MIN_FILTER
,
229 FilterModes
[FilterIndex
].min_mode
);
230 glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB
, GL_TEXTURE_MAG_FILTER
,
231 FilterModes
[FilterIndex
].mag_mode
);
233 wrap
= ClampModes
[ClampIndex
].mode
;
234 glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB
, GL_TEXTURE_WRAP_S
, wrap
);
235 glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB
, GL_TEXTURE_WRAP_T
, wrap
);
236 glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB
, GL_TEXTURE_WRAP_R
, wrap
);
238 glPushMatrix(); /*MODELVIEW*/
239 glTranslatef( 0.0, 0.0, -EyeDist
);
242 glDisable(GL_TEXTURE_GEN_S
);
243 glDisable(GL_TEXTURE_GEN_T
);
244 glDisable(GL_TEXTURE_GEN_R
);
246 glMatrixMode(GL_MODELVIEW
);
248 glRotatef(Xrot
, 1, 0, 0);
249 glRotatef(Yrot
, 0, 1, 0);
254 glMatrixMode(GL_TEXTURE
);
256 glRotatef(-Yrot
, 0, 1, 0);
257 glRotatef(-Xrot
, 1, 0, 0);
259 glEnable(GL_TEXTURE_GEN_S
);
260 glEnable(GL_TEXTURE_GEN_T
);
261 glEnable(GL_TEXTURE_GEN_R
);
262 glutSolidSphere(2.0, 20, 20);
264 glLoadIdentity(); /* texture */
266 glMatrixMode(GL_MODELVIEW
);
273 static void idle(void)
275 GLfloat t
= 0.05 * glutGet(GLUT_ELAPSED_TIME
);
281 static void set_mode(GLuint mode
)
284 glTexGeni(GL_S
, GL_TEXTURE_GEN_MODE
, GL_REFLECTION_MAP_ARB
);
285 glTexGeni(GL_T
, GL_TEXTURE_GEN_MODE
, GL_REFLECTION_MAP_ARB
);
286 glTexGeni(GL_R
, GL_TEXTURE_GEN_MODE
, GL_REFLECTION_MAP_ARB
);
287 printf("GL_REFLECTION_MAP_ARB mode\n");
289 else if (mode
== 1) {
290 glTexGeni(GL_S
, GL_TEXTURE_GEN_MODE
, GL_NORMAL_MAP_ARB
);
291 glTexGeni(GL_T
, GL_TEXTURE_GEN_MODE
, GL_NORMAL_MAP_ARB
);
292 glTexGeni(GL_R
, GL_TEXTURE_GEN_MODE
, GL_NORMAL_MAP_ARB
);
293 printf("GL_NORMAL_MAP_ARB mode\n");
298 static void key(unsigned char k
, int x
, int y
)
300 static GLuint mode
= 0;
312 FilterIndex
= (FilterIndex
+ 1) % NUM_FILTER_MODES
;
313 printf("Tex filter: %s\n", FilterModes
[FilterIndex
].name
);
316 ClampIndex
= (ClampIndex
+ 1) % NUM_CLAMP_MODES
;
317 printf("Tex wrap mode: %s\n", ClampModes
[ClampIndex
].name
);
324 use_vertex_arrays
= ! use_vertex_arrays
;
325 printf( "Vertex arrays are %sabled\n",
326 (use_vertex_arrays
) ? "en" : "dis" );
345 static void specialkey(int key
, int x
, int y
)
368 /* new window size or exposure */
369 static void reshape(int width
, int height
)
371 GLfloat ar
= (float) width
/ (float) height
;
372 glViewport(0, 0, (GLint
)width
, (GLint
)height
);
373 glMatrixMode(GL_PROJECTION
);
375 glFrustum( -2.0*ar
, 2.0*ar
, -2.0, 2.0, 4.0, 100.0 );
376 glMatrixMode(GL_MODELVIEW
);
381 static void init_checkers( void )
383 #define CUBE_TEX_SIZE 64
384 GLubyte image
[CUBE_TEX_SIZE
][CUBE_TEX_SIZE
][4];
385 static const GLubyte colors
[6][3] = {
386 { 255, 0, 0 }, /* face 0 - red */
387 { 0, 255, 255 }, /* face 1 - cyan */
388 { 0, 255, 0 }, /* face 2 - green */
389 { 255, 0, 255 }, /* face 3 - purple */
390 { 0, 0, 255 }, /* face 4 - blue */
391 { 255, 255, 0 } /* face 5 - yellow */
393 static const GLenum targets
[6] = {
394 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB
,
395 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB
,
396 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB
,
397 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB
,
398 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB
,
399 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
404 glPixelStorei(GL_UNPACK_ALIGNMENT
, 1);
406 /* make colored checkerboard cube faces */
407 for (f
= 0; f
< 6; f
++) {
408 for (i
= 0; i
< CUBE_TEX_SIZE
; i
++) {
409 for (j
= 0; j
< CUBE_TEX_SIZE
; j
++) {
410 if ((i
/4 + j
/4) & 1) {
411 image
[i
][j
][0] = colors
[f
][2];
412 image
[i
][j
][1] = colors
[f
][1];
413 image
[i
][j
][2] = colors
[f
][0];
414 image
[i
][j
][3] = 255;
417 image
[i
][j
][0] = 255;
418 image
[i
][j
][1] = 255;
419 image
[i
][j
][2] = 255;
420 image
[i
][j
][3] = 255;
425 glTexImage2D(targets
[f
], 0, GL_RGBA8
, CUBE_TEX_SIZE
, CUBE_TEX_SIZE
, 0,
426 GL_BGRA
, GL_UNSIGNED_BYTE
, image
);
429 glGenerateMipmapEXT(GL_TEXTURE_CUBE_MAP_ARB
);
433 static void load(GLenum target
, const char *filename
,
434 GLboolean flipTB
, GLboolean flipLR
)
438 GLubyte
*img
= LoadRGBImage( filename
, &w
, &h
, &format
);
440 printf("Error: couldn't load texture image %s\n", filename
);
443 assert(format
== GL_RGB
);
445 /* <sigh> the way the texture cube mapping works, we have to flip
446 * images to make things look right.
449 const int stride
= 3 * w
;
450 GLubyte temp
[3*1024];
452 for (i
= 0; i
< h
/ 2; i
++) {
453 memcpy(temp
, img
+ i
* stride
, stride
);
454 memcpy(img
+ i
* stride
, img
+ (h
- i
- 1) * stride
, stride
);
455 memcpy(img
+ (h
- i
- 1) * stride
, temp
, stride
);
459 const int stride
= 3 * w
;
463 for (i
= 0; i
< h
; i
++) {
464 row
= img
+ i
* stride
;
465 for (j
= 0; j
< w
/ 2; j
++) {
467 temp
[0] = row
[j
*3+0];
468 temp
[1] = row
[j
*3+1];
469 temp
[2] = row
[j
*3+2];
470 row
[j
*3+0] = row
[k
*3+0];
471 row
[j
*3+1] = row
[k
*3+1];
472 row
[j
*3+2] = row
[k
*3+2];
473 row
[k
*3+0] = temp
[0];
474 row
[k
*3+1] = temp
[1];
475 row
[k
*3+2] = temp
[2];
480 gluBuild2DMipmaps(target
, GL_RGB
, w
, h
, format
, GL_UNSIGNED_BYTE
, img
);
485 static void load_envmaps(void)
487 load(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB
, "right.rgb", GL_TRUE
, GL_FALSE
);
488 load(GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB
, "left.rgb", GL_TRUE
, GL_FALSE
);
489 load(GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB
, "top.rgb", GL_FALSE
, GL_TRUE
);
490 load(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB
, "bottom.rgb", GL_FALSE
, GL_TRUE
);
491 load(GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB
, "front.rgb", GL_TRUE
, GL_FALSE
);
492 load(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
, "back.rgb", GL_TRUE
, GL_FALSE
);
496 static void init( GLboolean useImageFiles
)
498 /* check for extensions */
500 char *exten
= (char *) glGetString(GL_EXTENSIONS
);
501 if (!strstr(exten
, "GL_ARB_texture_cube_map")) {
502 printf("Sorry, this demo requires GL_ARB_texture_cube_map\n");
506 /* Needed for glGenerateMipmapEXT
508 if (!strstr(exten
, "GL_EXT_framebuffer_object")) {
509 printf("Sorry, this demo requires GL_EXT_framebuffer_object\n");
513 printf("GL_RENDERER: %s\n", (char *) glGetString(GL_RENDERER
));
522 glEnable(GL_TEXTURE_CUBE_MAP_ARB
);
523 glEnable(GL_DEPTH_TEST
);
525 glClearColor(.3, .3, .3, 0);
526 glColor3f( 1.0, 1.0, 1.0 );
532 static void usage(void)
535 printf(" SPACE - toggle animation\n");
536 printf(" CURSOR KEYS - rotation\n");
537 printf(" c - toggle texture clamp/wrap mode\n");
538 printf(" f - toggle texture filter mode\n");
539 printf(" m - toggle texgen reflection mode\n");
540 printf(" z/Z - change viewing distance\n");
544 static void parse_args(int argc
, char *argv
[])
549 for (i
= 1; i
< argc
; i
++) {
550 if (strcmp(argv
[i
], "-i") == 0)
552 else if (strcmp(argv
[i
], "--noclear") == 0)
555 fprintf(stderr
, "Bad option: %s\n", argv
[i
]);
562 int main( int argc
, char *argv
[] )
564 glutInit(&argc
, argv
);
565 glutInitWindowPosition(0, 0);
566 glutInitWindowSize(600, 500);
567 glutInitDisplayMode( GLUT_RGB
| GLUT_DEPTH
| GLUT_DOUBLE
);
568 glutCreateWindow("Texture Cube Mapping");
570 glutReshapeFunc( reshape
);
571 glutKeyboardFunc( key
);
572 glutSpecialFunc( specialkey
);
573 glutDisplayFunc( draw
);
576 parse_args(argc
, argv
);