1/* 2 * (C) Copyright IBM Corporation 2005 3 * All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * on the rights to use, copy, modify, merge, publish, distribute, sub 9 * license, and/or sell copies of the Software, and to permit persons to whom 10 * the Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 19 * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 22 * USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 26#include <stdio.h> 27#include <stdlib.h> 28#include <string.h> 29#include <math.h> 30#include <GL/glew.h> 31#include "glut_wrap.h" 32 33const GLenum filter_modes[] = { 34 GL_NEAREST, 35 GL_LINEAR, 36 GL_NEAREST_MIPMAP_NEAREST, 37 GL_NEAREST_MIPMAP_LINEAR, 38 GL_LINEAR_MIPMAP_NEAREST, 39 GL_LINEAR_MIPMAP_LINEAR, 40}; 41 42static GLenum min_filter = GL_LINEAR_MIPMAP_LINEAR; 43static GLenum mag_filter = GL_LINEAR; 44 45static unsigned segments = 64; 46static GLfloat * position_data = NULL; 47static GLfloat * texcoord_data = NULL; 48static GLfloat max_anisotropy = 0.0; 49static GLfloat anisotropy = 1.0; 50 51static void generate_tunnel( unsigned num_segs, GLfloat ** pos_data, 52 GLfloat ** tex_data ); 53static void generate_textures( unsigned mode ); 54 55#define min(a,b) ( (a) < (b) ) ? (a) : (b) 56#define max(a,b) ( (a) > (b) ) ? (a) : (b) 57 58 59static void Display( void ) 60{ 61 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter ); 62 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter ); 63 64 if ( max_anisotropy > 0.0 ) { 65 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 66 anisotropy ); 67 } 68 69 glClear( GL_COLOR_BUFFER_BIT ); 70 glLoadIdentity(); 71 glTranslatef( 0.0f, 0.0f, -19.0f ); 72 73 glVertexPointer( 4, GL_FLOAT, 0, position_data ); 74 glTexCoordPointer( 2, GL_FLOAT, 0, texcoord_data ); 75 glEnableClientState( GL_VERTEX_ARRAY ); 76 glEnableClientState( GL_TEXTURE_COORD_ARRAY ); 77 glDrawArrays( GL_QUADS, 0, 4 * segments ); 78 glutSwapBuffers(); 79} 80 81 82static void Reshape( int width, int height ) 83{ 84 glViewport(0, 0, width, height); 85 glMatrixMode(GL_PROJECTION); 86 glLoadIdentity(); 87 gluPerspective(45.0f, (GLfloat)(width)/(GLfloat)(height), 0.1f, 100.0f); 88 glMatrixMode(GL_MODELVIEW); 89 glLoadIdentity(); 90} 91 92 93static void Key( unsigned char key, int x, int y ) 94{ 95 GLfloat new_anisotropy = anisotropy; 96 97 (void) x; 98 (void) y; 99 100 101 switch( key ) { 102 case 'a': { 103 new_anisotropy = anisotropy - 1.0; 104 break; 105 } 106 107 case 'A': { 108 new_anisotropy = anisotropy + 1.0; 109 break; 110 } 111 112 case 's': { 113 segments--; 114 if ( segments < 3 ) { 115 segments = 3; 116 } 117 generate_tunnel( segments, & position_data, & texcoord_data ); 118 break; 119 } 120 121 case 'S': { 122 segments++; 123 if ( segments > 128 ) { 124 segments = 128; 125 } 126 generate_tunnel( segments, & position_data, & texcoord_data ); 127 break; 128 } 129 case 'q': 130 case 'Q': 131 case 27: 132 exit(0); 133 break; 134 } 135 136 new_anisotropy = max( new_anisotropy, 1.0 ); 137 new_anisotropy = min( new_anisotropy, max_anisotropy ); 138 if ( new_anisotropy != anisotropy ) { 139 anisotropy = new_anisotropy; 140 printf( "Texture anisotropy: %f%s\n", anisotropy, 141 (anisotropy == 1.0) ? " (disabled)" : "" ); 142 } 143 144 glutPostRedisplay(); 145} 146 147 148static void SpecialKey( int key, int x, int y ) 149{ 150 (void) x; 151 (void) y; 152 (void) key; 153 glutPostRedisplay(); 154} 155 156 157static void menu_handler( int selection ) 158{ 159 switch( selection >> 3 ) { 160 case 0: 161 glBindTexture( GL_TEXTURE_2D, selection ); 162 break; 163 164 case 1: 165 min_filter = filter_modes[ selection & 7 ]; 166 break; 167 168 case 2: 169 mag_filter = filter_modes[ selection & 7 ]; 170 break; 171 } 172 173 glutPostRedisplay(); 174} 175 176 177static void Init( void ) 178{ 179 glDisable(GL_CULL_FACE); 180 glEnable(GL_TEXTURE_2D); 181 glClearColor(0.0f, 0.0f, 0.4f, 0.0f); 182 glShadeModel(GL_SMOOTH); 183 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); 184 185 generate_tunnel( segments, & position_data, & texcoord_data ); 186 187 glBindTexture( GL_TEXTURE_2D, 1 ); 188 generate_textures(1); 189 190 glBindTexture( GL_TEXTURE_2D, 2 ); 191 generate_textures(2); 192 193 glBindTexture( GL_TEXTURE_2D, 3 ); 194 generate_textures(3); 195 196 if ( glutExtensionSupported( "GL_EXT_texture_filter_anisotropic" ) ) { 197 glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, & max_anisotropy ); 198 } 199 200 printf("Maximum texture anisotropy: %f\n", max_anisotropy ); 201 202 /* Create the menus. */ 203 204 glutCreateMenu( menu_handler ); 205 glutAddMenuEntry( "Min filter: GL_NEAREST", 8 + 0 ); 206 glutAddMenuEntry( "Min filter: GL_LINEAR", 8 + 1 ); 207 glutAddMenuEntry( "Min filter: GL_NEAREST_MIMMAP_NEAREST", 8 + 2 ); 208 glutAddMenuEntry( "Min filter: GL_NEAREST_MIMMAP_LINEAR", 8 + 3 ); 209 glutAddMenuEntry( "Min filter: GL_LINEAR_MIMMAP_NEAREST", 8 + 4 ); 210 glutAddMenuEntry( "Min filter: GL_LINEAR_MIMMAP_LINEAR", 8 + 5 ); 211 glutAddMenuEntry( "Mag filter: GL_NEAREST", 16 + 0 ); 212 glutAddMenuEntry( "Mag filter: GL_LINEAR", 16 + 1 ); 213 glutAddMenuEntry( "Texture: regular mipmaps", 1 ); 214 glutAddMenuEntry( "Texture: blended mipmaps", 2 ); 215 glutAddMenuEntry( "Texture: color mipmaps", 3 ); 216 glutAttachMenu( GLUT_RIGHT_BUTTON ); 217} 218 219 220static void generate_tunnel( unsigned num_segs, GLfloat ** pos_data, 221 GLfloat ** tex_data ) 222{ 223 const GLfloat far_distance = 20.0f; 224 const GLfloat near_distance = -90.0f; 225 const GLfloat far_tex = 30.0f; 226 const GLfloat near_tex = 0.0f; 227 const GLfloat angle_step = (2 * M_PI) / num_segs; 228 const GLfloat tex_coord_step = 2.0 / num_segs; 229 GLfloat angle = 0.0f; 230 GLfloat tex_coord = 0.0f; 231 unsigned i; 232 GLfloat * position; 233 GLfloat * texture; 234 235 236 position = realloc( *pos_data, sizeof( GLfloat ) * num_segs * 4 * 4 ); 237 texture = realloc( *tex_data, sizeof( GLfloat ) * num_segs * 4 * 2 ); 238 239 *pos_data = position; 240 *tex_data = texture; 241 242 for ( i = 0 ; i < num_segs ; i++ ) { 243 position[0] = 2.5 * sinf( angle ); 244 position[1] = 2.5 * cosf( angle ); 245 position[2] = (i & 1) ? far_distance : near_distance; 246 position[3] = 1.0f; 247 248 position[4] = position[0]; 249 position[5] = position[1]; 250 position[6] = (i & 1) ? near_distance : far_distance; 251 position[7] = 1.0f; 252 253 position += 8; 254 255 texture[0] = tex_coord; 256 texture[1] = (i & 1) ? far_tex : near_tex; 257 texture += 2; 258 259 texture[0] = tex_coord; 260 texture[1] = (i & 1) ? near_tex : far_tex; 261 texture += 2; 262 263 angle += angle_step; 264 tex_coord += tex_coord_step; 265 266 position[0] = 2.5 * sinf( angle ); 267 position[1] = 2.5 * cosf( angle ); 268 position[2] = (i & 1) ? near_distance : far_distance; 269 position[3] = 1.0f; 270 271 position[4] = position[0]; 272 position[5] = position[1]; 273 position[6] = (i & 1) ? far_distance : near_distance; 274 position[7] = 1.0f; 275 276 position += 8; 277 278 texture[0] = tex_coord; 279 texture[1] = (i & 1) ? near_tex : far_tex; 280 texture += 2; 281 282 texture[0] = tex_coord; 283 texture[1] = (i & 1) ? far_tex : near_tex; 284 texture += 2; 285 } 286} 287 288 289static void generate_textures( unsigned mode ) 290{ 291#define LEVEL_COLORS 6 292 const GLfloat colors[LEVEL_COLORS][3] = { 293 { 1.0, 0.0, 0.0 }, /* 32 x 32 */ 294 { 0.0, 1.0, 0.0 }, /* 16 x 16 */ 295 { 0.0, 0.0, 1.0 }, /* 8 x 8 */ 296 { 1.0, 0.0, 1.0 }, /* 4 x 4 */ 297 { 1.0, 1.0, 1.0 }, /* 2 x 2 */ 298 { 1.0, 1.0, 0.0 } /* 1 x 1 */ 299 }; 300 const unsigned checkers_per_level = 2; 301 GLfloat * tex; 302 unsigned level; 303 unsigned size; 304 GLint max_size; 305 306 307 glGetIntegerv( GL_MAX_TEXTURE_SIZE, & max_size ); 308 if ( max_size > 512 ) { 309 max_size = 512; 310 } 311 312 tex = malloc( sizeof( GLfloat ) * 3 * max_size * max_size ); 313 314 level = 0; 315 for ( size = max_size ; size > 0 ; size >>= 1 ) { 316 unsigned divisor = size / checkers_per_level; 317 unsigned i; 318 unsigned j; 319 GLfloat checkers[2][3]; 320 321 322 if ((level == 0) || (mode == 1)) { 323 checkers[0][0] = 1.0; 324 checkers[0][1] = 1.0; 325 checkers[0][2] = 1.0; 326 checkers[1][0] = 0.0; 327 checkers[1][1] = 0.0; 328 checkers[1][2] = 0.0; 329 } 330 else if (mode == 2) { 331 checkers[0][0] = colors[level % LEVEL_COLORS][0]; 332 checkers[0][1] = colors[level % LEVEL_COLORS][1]; 333 checkers[0][2] = colors[level % LEVEL_COLORS][2]; 334 checkers[1][0] = colors[level % LEVEL_COLORS][0] * 0.5; 335 checkers[1][1] = colors[level % LEVEL_COLORS][1] * 0.5; 336 checkers[1][2] = colors[level % LEVEL_COLORS][2] * 0.5; 337 } 338 else { 339 checkers[0][0] = colors[level % LEVEL_COLORS][0]; 340 checkers[0][1] = colors[level % LEVEL_COLORS][1]; 341 checkers[0][2] = colors[level % LEVEL_COLORS][2]; 342 checkers[1][0] = colors[level % LEVEL_COLORS][0]; 343 checkers[1][1] = colors[level % LEVEL_COLORS][1]; 344 checkers[1][2] = colors[level % LEVEL_COLORS][2]; 345 } 346 347 if ( divisor == 0 ) { 348 divisor = 1; 349 350 checkers[0][0] = (checkers[0][0] + checkers[1][0]) / 2; 351 checkers[0][1] = (checkers[0][0] + checkers[1][0]) / 2; 352 checkers[0][2] = (checkers[0][0] + checkers[1][0]) / 2; 353 checkers[1][0] = checkers[0][0]; 354 checkers[1][1] = checkers[0][1]; 355 checkers[1][2] = checkers[0][2]; 356 } 357 358 359 for ( i = 0 ; i < size ; i++ ) { 360 for ( j = 0 ; j < size ; j++ ) { 361 const unsigned idx = ((i ^ j) / divisor) & 1; 362 363 tex[ ((i * size) + j) * 3 + 0] = checkers[ idx ][0]; 364 tex[ ((i * size) + j) * 3 + 1] = checkers[ idx ][1]; 365 tex[ ((i * size) + j) * 3 + 2] = checkers[ idx ][2]; 366 } 367 } 368 369 glTexImage2D( GL_TEXTURE_2D, level, GL_RGB, size, size, 0, 370 GL_RGB, GL_FLOAT, tex ); 371 level++; 372 } 373 374 free( tex ); 375} 376 377 378int main( int argc, char ** argv ) 379{ 380 glutInit( &argc, argv ); 381 glutInitWindowPosition( 0, 0 ); 382 glutInitWindowSize( 800, 600 ); 383 glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE ); 384 glutCreateWindow( "Texture Filter Test" ); 385 glewInit(); 386 glutReshapeFunc( Reshape ); 387 glutKeyboardFunc( Key ); 388 glutSpecialFunc( SpecialKey ); 389 glutDisplayFunc( Display ); 390 391 Init(); 392 393 printf("\nUse the right-button menu to select the texture and filter mode.\n"); 394 printf("Use 'A' and 'a' to increase and decrease the aniotropy.\n"); 395 printf("Use 'S' and 's' to increase and decrease the number of cylinder segments.\n"); 396 printf("Use 'q' to exit.\n\n"); 397 398 glutMainLoop(); 399 return 0; 400} 401