132001f49Smrg/*
232001f49Smrg * (C) Copyright IBM Corporation 2005
332001f49Smrg * All Rights Reserved.
432001f49Smrg *
532001f49Smrg * Permission is hereby granted, free of charge, to any person obtaining a
632001f49Smrg * copy of this software and associated documentation files (the "Software"),
732001f49Smrg * to deal in the Software without restriction, including without limitation
832001f49Smrg * on the rights to use, copy, modify, merge, publish, distribute, sub
932001f49Smrg * license, and/or sell copies of the Software, and to permit persons to whom
1032001f49Smrg * the Software is furnished to do so, subject to the following conditions:
1132001f49Smrg *
1232001f49Smrg * The above copyright notice and this permission notice (including the next
1332001f49Smrg * paragraph) shall be included in all copies or substantial portions of the
1432001f49Smrg * Software.
1532001f49Smrg *
1632001f49Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1732001f49Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1832001f49Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
1932001f49Smrg * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
2032001f49Smrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
2132001f49Smrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
2232001f49Smrg * USE OR OTHER DEALINGS IN THE SOFTWARE.
2332001f49Smrg */
2432001f49Smrg
2532001f49Smrg
2632001f49Smrg#include <stdio.h>
2732001f49Smrg#include <stdlib.h>
2832001f49Smrg#include <string.h>
2932001f49Smrg#include <math.h>
3032001f49Smrg#include <GL/glew.h>
3132001f49Smrg#include "glut_wrap.h"
3232001f49Smrg
3332001f49Smrgconst GLenum filter_modes[] = {
3432001f49Smrg     GL_NEAREST,
3532001f49Smrg     GL_LINEAR,
3632001f49Smrg     GL_NEAREST_MIPMAP_NEAREST,
3732001f49Smrg     GL_NEAREST_MIPMAP_LINEAR,
3832001f49Smrg     GL_LINEAR_MIPMAP_NEAREST,
3932001f49Smrg     GL_LINEAR_MIPMAP_LINEAR,
4032001f49Smrg};
4132001f49Smrg
4232001f49Smrgstatic GLenum min_filter = GL_LINEAR_MIPMAP_LINEAR;
4332001f49Smrgstatic GLenum mag_filter = GL_LINEAR;
4432001f49Smrg
4532001f49Smrgstatic unsigned segments = 64;
4632001f49Smrgstatic GLfloat * position_data = NULL;
4732001f49Smrgstatic GLfloat * texcoord_data = NULL;
4832001f49Smrgstatic GLfloat max_anisotropy = 0.0;
4932001f49Smrgstatic GLfloat anisotropy = 1.0;
5032001f49Smrg
5132001f49Smrgstatic void generate_tunnel( unsigned num_segs, GLfloat ** pos_data,
5232001f49Smrg    GLfloat ** tex_data );
5332001f49Smrgstatic void generate_textures( unsigned mode );
5432001f49Smrg
5532001f49Smrg#define min(a,b)  ( (a) < (b) ) ? (a) : (b)
5632001f49Smrg#define max(a,b)  ( (a) > (b) ) ? (a) : (b)
5732001f49Smrg
5832001f49Smrg
5932001f49Smrgstatic void Display( void )
6032001f49Smrg{
6132001f49Smrg   glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter );
6232001f49Smrg   glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter );
6332001f49Smrg
6432001f49Smrg   if ( max_anisotropy > 0.0 ) {
6532001f49Smrg      glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
6632001f49Smrg		       anisotropy );
6732001f49Smrg   }
6832001f49Smrg
6932001f49Smrg   glClear( GL_COLOR_BUFFER_BIT );
7032001f49Smrg   glLoadIdentity();
7132001f49Smrg   glTranslatef( 0.0f, 0.0f, -19.0f );
7232001f49Smrg
7332001f49Smrg   glVertexPointer( 4, GL_FLOAT, 0, position_data );
7432001f49Smrg   glTexCoordPointer( 2, GL_FLOAT, 0, texcoord_data );
7532001f49Smrg   glEnableClientState( GL_VERTEX_ARRAY );
7632001f49Smrg   glEnableClientState( GL_TEXTURE_COORD_ARRAY );
7732001f49Smrg   glDrawArrays( GL_QUADS, 0, 4 * segments );
7832001f49Smrg   glutSwapBuffers();
7932001f49Smrg}
8032001f49Smrg
8132001f49Smrg
8232001f49Smrgstatic void Reshape( int width, int height )
8332001f49Smrg{
8432001f49Smrg   glViewport(0, 0, width, height);
8532001f49Smrg   glMatrixMode(GL_PROJECTION);
8632001f49Smrg   glLoadIdentity();
8732001f49Smrg   gluPerspective(45.0f, (GLfloat)(width)/(GLfloat)(height), 0.1f, 100.0f);
8832001f49Smrg   glMatrixMode(GL_MODELVIEW);
8932001f49Smrg   glLoadIdentity();
9032001f49Smrg}
9132001f49Smrg
9232001f49Smrg
9332001f49Smrgstatic void Key( unsigned char key, int x, int y )
9432001f49Smrg{
9532001f49Smrg   GLfloat new_anisotropy = anisotropy;
9632001f49Smrg
9732001f49Smrg   (void) x;
9832001f49Smrg   (void) y;
9932001f49Smrg
10032001f49Smrg
10132001f49Smrg   switch( key ) {
10232001f49Smrg   case 'a': {
10332001f49Smrg      new_anisotropy = anisotropy - 1.0;
10432001f49Smrg      break;
10532001f49Smrg   }
10632001f49Smrg
10732001f49Smrg   case 'A': {
10832001f49Smrg      new_anisotropy = anisotropy + 1.0;
10932001f49Smrg      break;
11032001f49Smrg   }
11132001f49Smrg
11232001f49Smrg   case 's': {
11332001f49Smrg      segments--;
11432001f49Smrg      if ( segments < 3 ) {
11532001f49Smrg	 segments = 3;
11632001f49Smrg      }
11732001f49Smrg      generate_tunnel( segments, & position_data, & texcoord_data );
11832001f49Smrg      break;
11932001f49Smrg   }
12032001f49Smrg
12132001f49Smrg   case 'S': {
12232001f49Smrg      segments++;
12332001f49Smrg      if ( segments > 128 ) {
12432001f49Smrg	 segments = 128;
12532001f49Smrg      }
12632001f49Smrg      generate_tunnel( segments, & position_data, & texcoord_data );
12732001f49Smrg      break;
12832001f49Smrg   }
12932001f49Smrg   case 'q':
13032001f49Smrg   case 'Q':
13132001f49Smrg   case 27:
13232001f49Smrg      exit(0);
13332001f49Smrg      break;
13432001f49Smrg   }
13532001f49Smrg
13632001f49Smrg   new_anisotropy = max( new_anisotropy, 1.0 );
13732001f49Smrg   new_anisotropy = min( new_anisotropy, max_anisotropy );
13832001f49Smrg   if ( new_anisotropy != anisotropy ) {
13932001f49Smrg      anisotropy = new_anisotropy;
14032001f49Smrg      printf( "Texture anisotropy: %f%s\n", anisotropy,
14132001f49Smrg	      (anisotropy == 1.0) ? " (disabled)" : "" );
14232001f49Smrg   }
14332001f49Smrg
14432001f49Smrg   glutPostRedisplay();
14532001f49Smrg}
14632001f49Smrg
14732001f49Smrg
14832001f49Smrgstatic void SpecialKey( int key, int x, int y )
14932001f49Smrg{
15032001f49Smrg   (void) x;
15132001f49Smrg   (void) y;
15232001f49Smrg   (void) key;
15332001f49Smrg   glutPostRedisplay();
15432001f49Smrg}
15532001f49Smrg
15632001f49Smrg
15732001f49Smrgstatic void menu_handler( int selection )
15832001f49Smrg{
15932001f49Smrg   switch( selection >> 3 ) {
16032001f49Smrg   case 0:
16132001f49Smrg      glBindTexture( GL_TEXTURE_2D, selection );
16232001f49Smrg      break;
16332001f49Smrg
16432001f49Smrg   case 1:
16532001f49Smrg      min_filter = filter_modes[ selection & 7 ];
16632001f49Smrg      break;
16732001f49Smrg
16832001f49Smrg   case 2:
16932001f49Smrg      mag_filter = filter_modes[ selection & 7 ];
17032001f49Smrg      break;
17132001f49Smrg   }
17232001f49Smrg
17332001f49Smrg   glutPostRedisplay();
17432001f49Smrg}
17532001f49Smrg
17632001f49Smrg
17732001f49Smrgstatic void Init( void )
17832001f49Smrg{
17932001f49Smrg   glDisable(GL_CULL_FACE);
18032001f49Smrg   glEnable(GL_TEXTURE_2D);
18132001f49Smrg   glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
18232001f49Smrg   glShadeModel(GL_SMOOTH);
18332001f49Smrg   glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
18432001f49Smrg
18532001f49Smrg   generate_tunnel( segments, & position_data, & texcoord_data );
18632001f49Smrg
18732001f49Smrg   glBindTexture( GL_TEXTURE_2D, 1 );
18832001f49Smrg   generate_textures(1);
18932001f49Smrg
19032001f49Smrg   glBindTexture( GL_TEXTURE_2D, 2 );
19132001f49Smrg   generate_textures(2);
19232001f49Smrg
19332001f49Smrg   glBindTexture( GL_TEXTURE_2D, 3 );
19432001f49Smrg   generate_textures(3);
19532001f49Smrg
19632001f49Smrg   if ( glutExtensionSupported( "GL_EXT_texture_filter_anisotropic" ) ) {
19732001f49Smrg      glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, & max_anisotropy );
19832001f49Smrg   }
19932001f49Smrg
20032001f49Smrg   printf("Maximum texture anisotropy: %f\n", max_anisotropy );
20132001f49Smrg
20232001f49Smrg   /* Create the menus. */
20332001f49Smrg
20432001f49Smrg   glutCreateMenu( menu_handler );
20532001f49Smrg   glutAddMenuEntry( "Min filter: GL_NEAREST",                 8 + 0 );
20632001f49Smrg   glutAddMenuEntry( "Min filter: GL_LINEAR",                  8 + 1 );
20732001f49Smrg   glutAddMenuEntry( "Min filter: GL_NEAREST_MIMMAP_NEAREST",  8 + 2 );
20832001f49Smrg   glutAddMenuEntry( "Min filter: GL_NEAREST_MIMMAP_LINEAR",   8 + 3 );
20932001f49Smrg   glutAddMenuEntry( "Min filter: GL_LINEAR_MIMMAP_NEAREST",   8 + 4 );
21032001f49Smrg   glutAddMenuEntry( "Min filter: GL_LINEAR_MIMMAP_LINEAR",    8 + 5 );
21132001f49Smrg   glutAddMenuEntry( "Mag filter: GL_NEAREST",                16 + 0 );
21232001f49Smrg   glutAddMenuEntry( "Mag filter: GL_LINEAR",                 16 + 1 );
21332001f49Smrg   glutAddMenuEntry( "Texture: regular mipmaps",                   1 );
21432001f49Smrg   glutAddMenuEntry( "Texture: blended mipmaps",                   2 );
21532001f49Smrg   glutAddMenuEntry( "Texture: color mipmaps",                     3 );
21632001f49Smrg   glutAttachMenu( GLUT_RIGHT_BUTTON );
21732001f49Smrg}
21832001f49Smrg
21932001f49Smrg
22032001f49Smrgstatic void generate_tunnel( unsigned num_segs, GLfloat ** pos_data,
22132001f49Smrg			     GLfloat ** tex_data )
22232001f49Smrg{
22332001f49Smrg   const GLfloat far_distance = 20.0f;
22432001f49Smrg   const GLfloat near_distance = -90.0f;
22532001f49Smrg   const GLfloat far_tex = 30.0f;
22632001f49Smrg   const GLfloat near_tex = 0.0f;
22732001f49Smrg   const GLfloat angle_step = (2 * M_PI) / num_segs;
22832001f49Smrg   const GLfloat tex_coord_step = 2.0 / num_segs;
22932001f49Smrg   GLfloat angle = 0.0f;
23032001f49Smrg   GLfloat tex_coord = 0.0f;
23132001f49Smrg   unsigned i;
23232001f49Smrg   GLfloat * position;
23332001f49Smrg   GLfloat * texture;
23432001f49Smrg
23532001f49Smrg
23632001f49Smrg   position = realloc( *pos_data, sizeof( GLfloat ) * num_segs * 4 * 4 );
23732001f49Smrg   texture = realloc( *tex_data, sizeof( GLfloat ) * num_segs * 4 * 2 );
23832001f49Smrg
23932001f49Smrg   *pos_data = position;
24032001f49Smrg   *tex_data = texture;
24132001f49Smrg
24232001f49Smrg   for ( i = 0 ; i < num_segs ; i++ ) {
24332001f49Smrg      position[0] = 2.5 * sinf( angle );
24432001f49Smrg      position[1] = 2.5 * cosf( angle );
24532001f49Smrg      position[2] = (i & 1) ? far_distance : near_distance;
24632001f49Smrg      position[3] = 1.0f;
24732001f49Smrg
24832001f49Smrg      position[4] = position[0];
24932001f49Smrg      position[5] = position[1];
25032001f49Smrg      position[6] = (i & 1) ? near_distance : far_distance;
25132001f49Smrg      position[7] = 1.0f;
25232001f49Smrg
25332001f49Smrg      position += 8;
25432001f49Smrg
25532001f49Smrg      texture[0] = tex_coord;
25632001f49Smrg      texture[1] = (i & 1) ? far_tex : near_tex;
25732001f49Smrg      texture += 2;
25832001f49Smrg
25932001f49Smrg      texture[0] = tex_coord;
26032001f49Smrg      texture[1] = (i & 1) ? near_tex : far_tex;
26132001f49Smrg      texture += 2;
26232001f49Smrg
26332001f49Smrg      angle += angle_step;
26432001f49Smrg      tex_coord += tex_coord_step;
26532001f49Smrg
26632001f49Smrg      position[0] = 2.5 * sinf( angle );
26732001f49Smrg      position[1] = 2.5 * cosf( angle );
26832001f49Smrg      position[2] = (i & 1) ? near_distance : far_distance;
26932001f49Smrg      position[3] = 1.0f;
27032001f49Smrg
27132001f49Smrg      position[4] = position[0];
27232001f49Smrg      position[5] = position[1];
27332001f49Smrg      position[6] = (i & 1) ? far_distance : near_distance;
27432001f49Smrg      position[7] = 1.0f;
27532001f49Smrg
27632001f49Smrg      position += 8;
27732001f49Smrg
27832001f49Smrg      texture[0] = tex_coord;
27932001f49Smrg      texture[1] = (i & 1) ? near_tex : far_tex;
28032001f49Smrg      texture += 2;
28132001f49Smrg
28232001f49Smrg      texture[0] = tex_coord;
28332001f49Smrg      texture[1] = (i & 1) ? far_tex : near_tex;
28432001f49Smrg      texture += 2;
28532001f49Smrg   }
28632001f49Smrg}
28732001f49Smrg
28832001f49Smrg
28932001f49Smrgstatic void generate_textures( unsigned mode )
29032001f49Smrg{
29132001f49Smrg#define LEVEL_COLORS 6
29232001f49Smrg   const GLfloat colors[LEVEL_COLORS][3] = {
29332001f49Smrg	{ 1.0, 0.0, 0.0 },  /* 32 x 32 */
29432001f49Smrg	{ 0.0, 1.0, 0.0 },  /* 16 x 16 */
29532001f49Smrg	{ 0.0, 0.0, 1.0 },  /*  8 x  8 */
29632001f49Smrg	{ 1.0, 0.0, 1.0 },  /*  4 x  4 */
29732001f49Smrg	{ 1.0, 1.0, 1.0 },  /*  2 x  2 */
29832001f49Smrg	{ 1.0, 1.0, 0.0 }   /*  1 x  1 */
29932001f49Smrg   };
30032001f49Smrg   const unsigned checkers_per_level = 2;
30132001f49Smrg   GLfloat * tex;
30232001f49Smrg   unsigned level;
30332001f49Smrg   unsigned size;
30432001f49Smrg   GLint max_size;
30532001f49Smrg
30632001f49Smrg
30732001f49Smrg   glGetIntegerv( GL_MAX_TEXTURE_SIZE, & max_size );
30832001f49Smrg   if ( max_size > 512 ) {
30932001f49Smrg      max_size = 512;
31032001f49Smrg   }
31132001f49Smrg
31232001f49Smrg   tex = malloc( sizeof( GLfloat ) * 3 * max_size * max_size );
31332001f49Smrg
31432001f49Smrg   level = 0;
31532001f49Smrg   for ( size = max_size ; size > 0 ; size >>= 1 ) {
31632001f49Smrg      unsigned divisor = size / checkers_per_level;
31732001f49Smrg      unsigned i;
31832001f49Smrg      unsigned j;
31932001f49Smrg      GLfloat checkers[2][3];
32032001f49Smrg
32132001f49Smrg
32232001f49Smrg      if ((level == 0) || (mode == 1)) {
32332001f49Smrg	 checkers[0][0] = 1.0;
32432001f49Smrg	 checkers[0][1] = 1.0;
32532001f49Smrg	 checkers[0][2] = 1.0;
32632001f49Smrg	 checkers[1][0] = 0.0;
32732001f49Smrg	 checkers[1][1] = 0.0;
32832001f49Smrg	 checkers[1][2] = 0.0;
32932001f49Smrg      }
33032001f49Smrg      else if (mode == 2) {
33132001f49Smrg	 checkers[0][0] = colors[level % LEVEL_COLORS][0];
33232001f49Smrg	 checkers[0][1] = colors[level % LEVEL_COLORS][1];
33332001f49Smrg	 checkers[0][2] = colors[level % LEVEL_COLORS][2];
33432001f49Smrg	 checkers[1][0] = colors[level % LEVEL_COLORS][0] * 0.5;
33532001f49Smrg	 checkers[1][1] = colors[level % LEVEL_COLORS][1] * 0.5;
33632001f49Smrg	 checkers[1][2] = colors[level % LEVEL_COLORS][2] * 0.5;
33732001f49Smrg      }
33832001f49Smrg      else {
33932001f49Smrg	 checkers[0][0] = colors[level % LEVEL_COLORS][0];
34032001f49Smrg	 checkers[0][1] = colors[level % LEVEL_COLORS][1];
34132001f49Smrg	 checkers[0][2] = colors[level % LEVEL_COLORS][2];
34232001f49Smrg	 checkers[1][0] = colors[level % LEVEL_COLORS][0];
34332001f49Smrg	 checkers[1][1] = colors[level % LEVEL_COLORS][1];
34432001f49Smrg	 checkers[1][2] = colors[level % LEVEL_COLORS][2];
34532001f49Smrg      }
34632001f49Smrg
34732001f49Smrg      if ( divisor == 0 ) {
34832001f49Smrg	 divisor = 1;
34932001f49Smrg
35032001f49Smrg	 checkers[0][0] = (checkers[0][0] + checkers[1][0]) / 2;
35132001f49Smrg	 checkers[0][1] = (checkers[0][0] + checkers[1][0]) / 2;
35232001f49Smrg	 checkers[0][2] = (checkers[0][0] + checkers[1][0]) / 2;
35332001f49Smrg	 checkers[1][0] = checkers[0][0];
35432001f49Smrg	 checkers[1][1] = checkers[0][1];
35532001f49Smrg	 checkers[1][2] = checkers[0][2];
35632001f49Smrg      }
35732001f49Smrg
35832001f49Smrg
35932001f49Smrg      for ( i = 0 ; i < size ; i++ ) {
36032001f49Smrg	 for ( j = 0 ; j < size ; j++ ) {
36132001f49Smrg	    const unsigned idx = ((i ^ j) / divisor) & 1;
36232001f49Smrg
36332001f49Smrg	    tex[ ((i * size) + j) * 3 + 0] = checkers[ idx ][0];
36432001f49Smrg	    tex[ ((i * size) + j) * 3 + 1] = checkers[ idx ][1];
36532001f49Smrg	    tex[ ((i * size) + j) * 3 + 2] = checkers[ idx ][2];
36632001f49Smrg	 }
36732001f49Smrg      }
36832001f49Smrg
36932001f49Smrg      glTexImage2D( GL_TEXTURE_2D, level, GL_RGB, size, size, 0,
37032001f49Smrg		    GL_RGB, GL_FLOAT, tex );
37132001f49Smrg      level++;
37232001f49Smrg   }
37332001f49Smrg
37432001f49Smrg   free( tex );
37532001f49Smrg}
37632001f49Smrg
37732001f49Smrg
37832001f49Smrgint main( int argc, char ** argv )
37932001f49Smrg{
38032001f49Smrg   glutInit( &argc, argv );
38132001f49Smrg   glutInitWindowPosition( 0, 0 );
38232001f49Smrg   glutInitWindowSize( 800, 600 );
38332001f49Smrg   glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
38432001f49Smrg   glutCreateWindow( "Texture Filter Test" );
38532001f49Smrg   glewInit();
38632001f49Smrg   glutReshapeFunc( Reshape );
38732001f49Smrg   glutKeyboardFunc( Key );
38832001f49Smrg   glutSpecialFunc( SpecialKey );
38932001f49Smrg   glutDisplayFunc( Display );
39032001f49Smrg
39132001f49Smrg   Init();
39232001f49Smrg
39332001f49Smrg   printf("\nUse the right-button menu to select the texture and filter mode.\n");
39432001f49Smrg   printf("Use 'A' and 'a' to increase and decrease the aniotropy.\n");
39532001f49Smrg   printf("Use 'S' and 's' to increase and decrease the number of cylinder segments.\n");
39632001f49Smrg   printf("Use 'q' to exit.\n\n");
39732001f49Smrg
39832001f49Smrg   glutMainLoop();
39932001f49Smrg   return 0;
40032001f49Smrg}
401