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