1/* 2 * Compressed texture demo. Written by Daniel Borca. 3 * This program is in the public domain. 4 */ 5 6#include <stdio.h> 7#include <stdlib.h> 8#include <math.h> 9#include <string.h> 10#include <GL/glew.h> 11#include "glut_wrap.h" 12 13#include "readtex.c" /* I know, this is a hack. */ 14#define TEXTURE_FILE DEMOS_DATA_DIR "tree2.rgba" 15 16 17static float Rot = 0.0; 18static GLboolean Anim = 1; 19 20typedef struct { 21 GLubyte *data; 22 GLuint size; 23 GLenum format; 24 GLuint w, h; 25 26 GLenum TC; 27 28 GLubyte *cData; 29 GLuint cSize; 30 GLenum cFormat; 31} TEXTURE; 32 33static TEXTURE *Tx, t1, t2, t3; 34static GLboolean fxt1, dxtc, s3tc; 35 36 37static const char *TextureName (GLenum TC) 38{ 39 switch (TC) { 40 case GL_RGB: 41 return "RGB"; 42 case GL_RGBA: 43 return "RGBA"; 44 case GL_COMPRESSED_RGB: 45 return "COMPRESSED_RGB"; 46 case GL_COMPRESSED_RGBA: 47 return "COMPRESSED_RGBA"; 48 case GL_COMPRESSED_RGB_FXT1_3DFX: 49 return "GL_COMPRESSED_RGB_FXT1_3DFX"; 50 case GL_COMPRESSED_RGBA_FXT1_3DFX: 51 return "GL_COMPRESSED_RGBA_FXT1_3DFX"; 52 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: 53 return "GL_COMPRESSED_RGB_S3TC_DXT1_EXT"; 54 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: 55 return "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT"; 56 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: 57 return "GL_COMPRESSED_RGBA_S3TC_DXT3_EXT"; 58 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: 59 return "GL_COMPRESSED_RGBA_S3TC_DXT5_EXT"; 60 case GL_RGB_S3TC: 61 return "GL_RGB_S3TC"; 62 case GL_RGB4_S3TC: 63 return "GL_RGB4_S3TC"; 64 case GL_RGBA_S3TC: 65 return "GL_RGBA_S3TC"; 66 case GL_RGBA4_S3TC: 67 return "GL_RGBA4_S3TC"; 68 case 0: 69 return "Invalid format"; 70 default: 71 return "Unknown format"; 72 } 73} 74 75 76static void 77PrintString(const char *s) 78{ 79 while (*s) { 80 glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int) *s); 81 s++; 82 } 83} 84 85 86static void Idle( void ) 87{ 88 float t = glutGet(GLUT_ELAPSED_TIME) * 0.001; /* in seconds */ 89 Rot = t * 360 / 4; /* 1 rotation per 4 seconds */ 90 glutPostRedisplay(); 91} 92 93 94static void Display( void ) 95{ 96 /* draw background gradient */ 97 glDisable(GL_TEXTURE_2D); 98 glBegin(GL_POLYGON); 99 glColor3f(1.0, 0.0, 0.2); glVertex2f(-1.5, -1.0); 100 glColor3f(1.0, 0.0, 0.2); glVertex2f( 1.5, -1.0); 101 glColor3f(0.0, 0.0, 1.0); glVertex2f( 1.5, 1.0); 102 glColor3f(0.0, 0.0, 1.0); glVertex2f(-1.5, 1.0); 103 glEnd(); 104 105 glPushMatrix(); 106 glRotatef(Rot, 0, 0, 1); 107 108 glEnable(GL_TEXTURE_2D); 109 glEnable(GL_BLEND); 110 111 glBegin(GL_POLYGON); 112 glTexCoord2f(0, 1); glVertex2f(-1, -0.5); 113 glTexCoord2f(1, 1); glVertex2f( 1, -0.5); 114 glTexCoord2f(1, 0); glVertex2f( 1, 0.5); 115 glTexCoord2f(0, 0); glVertex2f(-1, 0.5); 116 glEnd(); 117 118 glPopMatrix(); 119 120 glDisable(GL_TEXTURE_2D); 121 122 /* info */ 123 glDisable(GL_BLEND); 124 glColor4f(1, 1, 1, 1); 125 126 glRasterPos3f(-1.2, -0.7, 0); 127 PrintString("Selected: "); 128 PrintString(TextureName(Tx->TC)); 129 if (Tx->cData) { 130 char tmp[64]; 131 glRasterPos3f(-1.2, -0.8, 0); 132 PrintString("Internal: "); 133 PrintString(TextureName(Tx->cFormat)); 134 glRasterPos3f(-1.2, -0.9, 0); 135 PrintString("Size : "); 136 sprintf(tmp, "%d (%d%% of %d)", Tx->cSize, Tx->cSize * 100 / Tx->size, Tx->size); 137 PrintString(tmp); 138 } 139 140 glutSwapBuffers(); 141} 142 143 144static void Reshape( int width, int height ) 145{ 146 glViewport( 0, 0, width, height ); 147 glMatrixMode( GL_PROJECTION ); 148 glLoadIdentity(); 149 glOrtho( -1.5, 1.5, -1.0, 1.0, -1.0, 1.0 ); 150 glMatrixMode( GL_MODELVIEW ); 151 glLoadIdentity(); 152} 153 154 155static void ReInit( GLenum TC, TEXTURE *Tx ) 156{ 157 GLint rv, v; 158 159 if ((Tx->TC == TC) && (Tx->cData != NULL)) { 160 glCompressedTexImage2DARB(GL_TEXTURE_2D, /* target */ 161 0, /* level */ 162 Tx->cFormat, /* real format */ 163 Tx->w, /* original width */ 164 Tx->h, /* original height */ 165 0, /* border */ 166 Tx->cSize, /* compressed size*/ 167 Tx->cData); /* compressed data*/ 168 } else { 169 glTexImage2D(GL_TEXTURE_2D, /* target */ 170 0, /* level */ 171 TC, /* internal format */ 172 Tx->w, Tx->h, /* width, height */ 173 0, /* border */ 174 Tx->format, /* texture format */ 175 GL_UNSIGNED_BYTE, /* texture type */ 176 Tx->data); /* the texture */ 177 178 179 v = 0; 180 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, 181 GL_TEXTURE_INTERNAL_FORMAT, &v); 182 printf("Requested internal format = 0x%x, actual = 0x%x\n", TC, v); 183 184 if (0) { 185 GLint r, g, b, a, l, i; 186 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_RED_SIZE, &r); 187 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_GREEN_SIZE, &g); 188 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BLUE_SIZE, &b); 189 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_ALPHA_SIZE, &a); 190 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_LUMINANCE_SIZE, &l); 191 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTENSITY_SIZE, &i); 192 printf("Compressed Bits per R: %d G: %d B: %d A: %d L: %d I: %d\n", 193 r, g, b, a, l, i); 194 } 195 196 /* okay, now cache the compressed texture */ 197 Tx->TC = TC; 198 if (Tx->cData != NULL) { 199 free(Tx->cData); 200 Tx->cData = NULL; 201 } 202 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_ARB, &rv); 203 if (rv) { 204 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, (GLint *)&Tx->cFormat); 205 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB, (GLint *)&Tx->cSize); 206 if ((Tx->cData = malloc(Tx->cSize)) != NULL) { 207 glGetCompressedTexImageARB(GL_TEXTURE_2D, 0, Tx->cData); 208 } 209 } 210 } 211} 212 213 214static void Init( void ) 215{ 216 /* HEIGHT * WIDTH + 1 (for trailing '\0') */ 217 static char pattern[8 * 32 + 1] = {"\ 218 \ 219 MMM EEEE SSS AAA \ 220 M M M E S S A A \ 221 M M M EEEE SS A A \ 222 M M M E SS AAAAA \ 223 M M E S S A A \ 224 M M EEEE SSS A A \ 225 " 226 }; 227 228 GLuint i, j; 229 230 GLubyte (*texture1)[8 * 32][4]; 231 GLubyte (*texture2)[256][256][4]; 232 233 t1.w = 32; 234 t1.h = 8; 235 t1.size = t1.w * t1.h * 4; 236 t1.data = malloc(t1.size); 237 t1.format = GL_RGBA; 238 t1.TC = GL_RGBA; 239 240 texture1 = (GLubyte (*)[8 * 32][4])t1.data; 241 for (i = 0; i < sizeof(pattern) - 1; i++) { 242 switch (pattern[i]) { 243 default: 244 case ' ': 245 (*texture1)[i][0] = 255; 246 (*texture1)[i][1] = 255; 247 (*texture1)[i][2] = 255; 248 (*texture1)[i][3] = 64; 249 break; 250 case 'M': 251 (*texture1)[i][0] = 255; 252 (*texture1)[i][1] = 0; 253 (*texture1)[i][2] = 0; 254 (*texture1)[i][3] = 255; 255 break; 256 case 'E': 257 (*texture1)[i][0] = 0; 258 (*texture1)[i][1] = 255; 259 (*texture1)[i][2] = 0; 260 (*texture1)[i][3] = 255; 261 break; 262 case 'S': 263 (*texture1)[i][0] = 0; 264 (*texture1)[i][1] = 0; 265 (*texture1)[i][2] = 255; 266 (*texture1)[i][3] = 255; 267 break; 268 case 'A': 269 (*texture1)[i][0] = 255; 270 (*texture1)[i][1] = 255; 271 (*texture1)[i][2] = 0; 272 (*texture1)[i][3] = 255; 273 break; 274 } 275 } 276 277 t2.w = 256; 278 t2.h = 256; 279 t2.size = t2.w * t2.h * 4; 280 t2.data = malloc(t2.size); 281 t2.format = GL_RGBA; 282 t2.TC = GL_RGBA; 283 284 texture2 = (GLubyte (*)[256][256][4])t2.data; 285 for (j = 0; j < t2.h; j++) { 286 for (i = 0; i < t2.w; i++) { 287 (*texture2)[j][i][0] = sqrt(i * j * 255 * 255 / (t2.w * t2.h)); 288 (*texture2)[j][i][1] = 0; 289 (*texture2)[j][i][2] = 0; 290 (*texture2)[j][i][3] = 255; 291 } 292 } 293 294 t3.data = LoadRGBImage(TEXTURE_FILE, (GLint *)&t3.w, (GLint *)&t3.h, &t3.format); 295 t3.size = t3.w * t3.h * ((t3.format == GL_RGB) ? 3 : 4); 296 t3.TC = GL_RGBA; 297 298 ReInit(GL_RGBA, Tx = &t1); 299 300 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 301 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 302 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 303 glEnable(GL_TEXTURE_2D); 304 305 glEnable(GL_BLEND); 306 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 307} 308 309 310static void Key( unsigned char key, int x, int y ) 311{ 312 (void) x; 313 (void) y; 314 switch (key) { 315 case 27: 316 exit(0); 317 break; 318 case ' ': 319 Anim = !Anim; 320 if (Anim) 321 glutIdleFunc( Idle ); 322 else 323 glutIdleFunc( NULL ); 324 break; 325 case 't': 326 if (Tx == &t1) { 327 Tx = &t2; 328 } else if (Tx == &t2) { 329 Tx = &t3; 330 } else { 331 Tx = &t1; 332 } 333 ReInit(Tx->TC, Tx); 334 break; 335 case '9': 336 ReInit(GL_RGB, Tx); 337 break; 338 case '0': 339 ReInit(GL_RGBA, Tx); 340 break; 341 case '1': 342 ReInit(GL_COMPRESSED_RGB, Tx); 343 break; 344 case '2': 345 ReInit(GL_COMPRESSED_RGBA, Tx); 346 break; 347 case '3': 348 if (fxt1) ReInit(GL_COMPRESSED_RGB_FXT1_3DFX, Tx); 349 break; 350 case '4': 351 if (fxt1) ReInit(GL_COMPRESSED_RGBA_FXT1_3DFX, Tx); 352 break; 353 case '5': 354 if (dxtc) ReInit(GL_COMPRESSED_RGB_S3TC_DXT1_EXT, Tx); 355 break; 356 case '6': 357 if (dxtc) ReInit(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, Tx); 358 break; 359 case '7': 360 if (dxtc) ReInit(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, Tx); 361 break; 362 case '8': 363 if (dxtc) ReInit(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, Tx); 364 break; 365 case 'a': 366 if (s3tc) ReInit(GL_RGB_S3TC, Tx); 367 break; 368 case 's': 369 if (s3tc) ReInit(GL_RGB4_S3TC, Tx); 370 break; 371 case 'd': 372 if (s3tc) ReInit(GL_RGBA_S3TC, Tx); 373 break; 374 case 'f': 375 if (s3tc) ReInit(GL_RGBA4_S3TC, Tx); 376 break; 377 } 378 glutPostRedisplay(); 379} 380 381 382int main( int argc, char *argv[] ) 383{ 384 float gl_version; 385 GLint num_formats; 386 GLint i; 387 GLint formats[64]; 388 389 390 glutInit( &argc, argv ); 391 glutInitWindowPosition( 0, 0 ); 392 glutInitWindowSize( 400, 300 ); 393 394 glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE ); 395 396 if (glutCreateWindow(argv[0]) <= 0) { 397 printf("Couldn't create window\n"); 398 exit(0); 399 } 400 401 glewInit(); 402 gl_version = atof( (const char *) glGetString( GL_VERSION ) ); 403 if ( (gl_version < 1.3) 404 && !glutExtensionSupported("GL_ARB_texture_compression") ) { 405 printf("Sorry, GL_ARB_texture_compression not supported\n"); 406 exit(0); 407 } 408 if (glutExtensionSupported("GL_3DFX_texture_compression_FXT1")) { 409 fxt1 = GL_TRUE; 410 } 411 if (glutExtensionSupported("GL_EXT_texture_compression_s3tc")) { 412 dxtc = GL_TRUE; 413 } 414 if (glutExtensionSupported("GL_S3_s3tc")) { 415 s3tc = GL_TRUE; 416 } 417 418 glGetIntegerv( GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB, & num_formats ); 419 420 (void) memset( formats, 0, sizeof( formats ) ); 421 glGetIntegerv( GL_COMPRESSED_TEXTURE_FORMATS_ARB, formats ); 422 423 printf( "The following texture formats are supported:\n" ); 424 for ( i = 0 ; i < num_formats ; i++ ) { 425 printf( "\t%s\n", TextureName( formats[i] ) ); 426 } 427 428 Init(); 429 430 glutReshapeFunc( Reshape ); 431 glutKeyboardFunc( Key ); 432 glutDisplayFunc( Display ); 433 if (Anim) 434 glutIdleFunc( Idle ); 435 436 glutMainLoop(); 437 return 0; 438} 439