1/*
2 * Simple test of multiple textures
3 */
4
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <math.h>
9#include <GL/glew.h>
10#include "glut_wrap.h"
11#include "readtex.h"
12
13#define TEST_CLAMP 0
14#define TEST_MIPMAPS 0
15#define TEST_GEN_COMPRESSED_MIPMAPS 0
16
17#define MAX_TEXTURES 8
18
19
20static int Win;
21static GLfloat Xrot = 0, Yrot = 0, Zrot = 0;
22static GLboolean Anim = GL_TRUE;
23static GLboolean Blend = GL_FALSE;
24static GLuint Filter = 0;
25static GLboolean Clamp = GL_FALSE;
26static GLfloat Scale = 1.0;
27
28static GLuint NumTextures;
29static GLuint Textures[MAX_TEXTURES];
30static float TexRot[MAX_TEXTURES][3];
31static float TexPos[MAX_TEXTURES][3];
32static float TexAspect[MAX_TEXTURES];
33
34static const char *DefaultFiles[] = {
35   DEMOS_DATA_DIR "arch.rgb",
36   DEMOS_DATA_DIR "reflect.rgb",
37   DEMOS_DATA_DIR "tree2.rgba",
38   DEMOS_DATA_DIR "tile.rgb"
39};
40
41
42#define NUM_FILTERS 6
43static
44struct filter {
45   GLenum min, mag;
46   const char *name;
47} FilterModes[NUM_FILTERS] = {
48   { GL_NEAREST, GL_NEAREST, "Nearest,Nearest" },
49   { GL_LINEAR, GL_LINEAR, "Linear,Linear" },
50   { GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST, "NearestMipmapNearest,Nearest" },
51   { GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR, "NearestMipmapNearest,Linear" },
52   { GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR, "LinearMipmapNearest,Linear" },
53   { GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, "LinearMipmapLinear,Linear" }
54};
55
56
57
58
59static void
60Idle(void)
61{
62   Xrot = glutGet(GLUT_ELAPSED_TIME) * 0.02;
63   Yrot = glutGet(GLUT_ELAPSED_TIME) * 0.04;
64   /* Zrot += 2.0; */
65   glutPostRedisplay();
66}
67
68
69static void
70DrawTextures(void)
71{
72   GLuint i;
73
74   for (i = 0; i < NumTextures; i++) {
75      GLfloat ar = TexAspect[i];
76
77      glPushMatrix();
78      glTranslatef(TexPos[i][0], TexPos[i][1], TexPos[i][2]);
79      glRotatef(TexRot[i][0], 1, 0, 0);
80      glRotatef(TexRot[i][1], 0, 1, 0);
81      glRotatef(TexRot[i][2], 0, 0, 1);
82
83      glBindTexture(GL_TEXTURE_2D, Textures[i]);
84      glBegin(GL_POLYGON);
85#if TEST_CLAMP
86      glTexCoord2f( -0.5, -0.5 );   glVertex2f( -ar, -1.0 );
87      glTexCoord2f(  1.5, -0.5 );   glVertex2f(  ar, -1.0 );
88      glTexCoord2f(  1.5,  1.5 );   glVertex2f(  ar,  1.0 );
89      glTexCoord2f( -0.5,  1.5 );   glVertex2f( -ar,  1.0 );
90#else
91      glTexCoord2f( 0.0, 0.0 );   glVertex2f( -ar, -1.0 );
92      glTexCoord2f( 1.0, 0.0 );   glVertex2f(  ar, -1.0 );
93      glTexCoord2f( 1.0, 1.0 );   glVertex2f(  ar,  1.0 );
94      glTexCoord2f( 0.0, 1.0 );   glVertex2f( -ar,  1.0 );
95#endif
96      glEnd();
97
98      glPopMatrix();
99   }
100}
101
102static void
103Draw(void)
104{
105   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
106
107   if (Blend) {
108      glEnable(GL_BLEND);
109      glDisable(GL_DEPTH_TEST);
110   }
111   else {
112      glDisable(GL_BLEND);
113      glEnable(GL_DEPTH_TEST);
114   }
115
116   glPushMatrix();
117   glRotatef(Xrot, 1, 0, 0);
118   glRotatef(Yrot, 0, 1, 0);
119   glRotatef(Zrot, 0, 0, 1);
120   glScalef(Scale, Scale, Scale);
121
122   DrawTextures();
123
124   glPopMatrix();
125
126   glutSwapBuffers();
127}
128
129
130static void
131Reshape(int width, int height)
132{
133   glViewport(0, 0, width, height);
134   glMatrixMode(GL_PROJECTION);
135   glLoadIdentity();
136   glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 50.0);
137   glMatrixMode(GL_MODELVIEW);
138   glLoadIdentity();
139   glTranslatef(0.0, 0.0, -10.0);
140}
141
142
143static GLfloat
144RandFloat(float min, float max)
145{
146   float x = (float) (rand() % 1000) * 0.001;
147   x = x * (max - min) + min;
148   return x;
149}
150
151
152static void
153Randomize(void)
154{
155   GLfloat k = 1.0;
156   GLuint i;
157
158   srand(glutGet(GLUT_ELAPSED_TIME));
159
160   for (i = 0; i < NumTextures; i++) {
161      TexRot[i][0] = RandFloat(0.0, 360);
162      TexRot[i][1] = RandFloat(0.0, 360);
163      TexRot[i][2] = RandFloat(0.0, 360);
164      TexPos[i][0] = RandFloat(-k, k);
165      TexPos[i][1] = RandFloat(-k, k);
166      TexPos[i][2] = RandFloat(-k, k);
167   }
168}
169
170
171static void
172SetTexParams(void)
173{
174   GLuint i;
175   for (i = 0; i < NumTextures; i++) {
176      glBindTexture(GL_TEXTURE_2D, Textures[i]);
177      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
178                      FilterModes[Filter].min);
179      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
180                      FilterModes[Filter].mag);
181
182      if (Clamp) {
183         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
184         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
185      }
186      else {
187         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
188         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
189      }
190   }
191}
192
193
194static void
195PrintState(void)
196{
197   printf("Blend=%s Filter=%s\n",
198          Blend ? "Y" : "n",
199          FilterModes[Filter].name);
200}
201
202
203static void
204Key(unsigned char key, int x, int y)
205{
206   const GLfloat step = 3.0;
207   (void) x;
208   (void) y;
209   switch (key) {
210   case 'a':
211   case ' ':
212      Anim = !Anim;
213      if (Anim)
214         glutIdleFunc(Idle);
215      else
216         glutIdleFunc(NULL);
217      break;
218   case 'b':
219      Blend = !Blend;
220      break;
221   case 's':
222      Scale /= 1.1;
223      break;
224   case 'S':
225      Scale *= 1.1;
226      break;
227   case 'f':
228      Filter = (Filter + 1) % NUM_FILTERS;
229      SetTexParams();
230      break;
231   case 'r':
232      Randomize();
233      break;
234#if TEST_CLAMP
235   case 'c':
236      Clamp = !Clamp;
237      SetTexParams();
238      break;
239#endif
240   case 'z':
241      Zrot -= step;
242      break;
243   case 'Z':
244      Zrot += step;
245      break;
246   case 27:
247      glutDestroyWindow(Win);
248      exit(0);
249      break;
250   }
251
252   PrintState();
253
254   glutPostRedisplay();
255}
256
257
258static void
259SpecialKey(int key, int x, int y)
260{
261   const GLfloat step = 3.0;
262   (void) x;
263   (void) y;
264   switch (key) {
265      case GLUT_KEY_UP:
266         Xrot -= step;
267         break;
268      case GLUT_KEY_DOWN:
269         Xrot += step;
270         break;
271      case GLUT_KEY_LEFT:
272         Yrot -= step;
273         break;
274      case GLUT_KEY_RIGHT:
275         Yrot += step;
276         break;
277   }
278   glutPostRedisplay();
279}
280
281
282static void
283LoadTextures(GLuint n, const char *files[])
284{
285   GLuint i;
286
287   NumTextures = n < MAX_TEXTURES ? n : MAX_TEXTURES;
288
289   glGenTextures(n, Textures);
290
291   SetTexParams();
292
293   for (i = 0; i < n; i++) {
294      GLint w, h;
295      glBindTexture(GL_TEXTURE_2D, Textures[i]);
296#if TEST_MIPMAPS
297      {
298         static const GLubyte color[9][4] = {
299            {255, 0, 0},
300            {0, 255, 0},
301            {0, 0, 255},
302            {0, 255, 255},
303            {255, 0, 255},
304            {255, 255, 0},
305            {255, 128, 255},
306            {128, 128, 128},
307            {64, 64, 64}
308         };
309
310         GLubyte image[256*256*4];
311         int i, level;
312         w = h = 256;
313         for (level = 0; level <= 8; level++) {
314            for (i = 0; i < w * h; i++) {
315               image[i*4+0] = color[level][0];
316               image[i*4+1] = color[level][1];
317               image[i*4+2] = color[level][2];
318               image[i*4+3] = color[level][3];
319            }
320            printf("Load level %d: %d x %d\n", level, w>>level, h>>level);
321            glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, w>>level, h>>level, 0,
322                         GL_RGBA, GL_UNSIGNED_BYTE, image);
323         }
324      }
325#elif TEST_GEN_COMPRESSED_MIPMAPS
326      {
327         GLenum intFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
328         int f;
329         GLenum format;
330         GLubyte *img = LoadRGBImage(files[i], &w, &h, &format);
331         GLboolean write_compressed = GL_FALSE;
332         GLboolean read_compressed = GL_FALSE;
333
334         glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
335         glTexImage2D(GL_TEXTURE_2D, 0, intFormat, w, h, 0,
336                      format, GL_UNSIGNED_BYTE, img);
337         glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);
338         free(img);
339
340         glGetTexLevelParameteriv(GL_TEXTURE_2D, i,
341                                  GL_TEXTURE_INTERNAL_FORMAT, &f);
342         printf("actual internal format 0x%x\n", f);
343
344         if (write_compressed) {
345            GLint i, sz, w, h;
346            int num_levels = 8;
347            for (i = 0; i < num_levels; i++) {
348               char name[20], *buf;
349               FILE *f;
350               glGetTexLevelParameteriv(GL_TEXTURE_2D, i, GL_TEXTURE_WIDTH, &w);
351               glGetTexLevelParameteriv(GL_TEXTURE_2D, i, GL_TEXTURE_HEIGHT, &h);
352               glGetTexLevelParameteriv(GL_TEXTURE_2D, i,
353                                        GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &sz);
354               printf("Writing level %d: %d x %d  bytes: %d\n", i, w, h, sz);
355               buf = malloc(sz);
356               glGetCompressedTexImageARB(GL_TEXTURE_2D, i, buf);
357               sprintf(name, "comp%d", i);
358               f = fopen(name, "w");
359               fwrite(buf, 1, sz, f);
360               fclose(f);
361               free(buf);
362            }
363         }
364
365         if (read_compressed) {
366            GLint i, sz, w, h;
367            int num_levels = 8;
368            for (i = 01; i < num_levels; i++) {
369               char name[20], *buf;
370               FILE *f;
371               glGetTexLevelParameteriv(GL_TEXTURE_2D, i, GL_TEXTURE_WIDTH, &w);
372               glGetTexLevelParameteriv(GL_TEXTURE_2D, i, GL_TEXTURE_HEIGHT, &h);
373               glGetTexLevelParameteriv(GL_TEXTURE_2D, i,
374                                        GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &sz);
375               buf = malloc(sz);
376               sprintf(name, "comp%d", i);
377               printf("Reading level %d: %d x %d  bytes: %d from %s\n",
378                      i, w, h, sz, name);
379               f = fopen(name, "r");
380               fread(buf, 1, sz, f);
381               fclose(f);
382               glCompressedTexImage2DARB(GL_TEXTURE_2D, i, intFormat,
383                                         w, h, 0, sz, buf);
384               free(buf);
385            }
386         }
387      }
388#else
389      if (!LoadRGBMipmaps2(files[i], GL_TEXTURE_2D, GL_RGB, &w, &h)) {
390         printf("Error: couldn't load %s\n", files[i]);
391         exit(1);
392      }
393#endif
394      TexAspect[i] = (float) w / (float) h;
395      printf("Loaded %s\n", files[i]);
396   }
397}
398
399
400static void
401Init(int argc, const char *argv[])
402{
403   if (argc == 1)
404      LoadTextures(4, DefaultFiles);
405   else
406      LoadTextures(argc - 1, argv + 1);
407
408   Randomize();
409
410   glEnable(GL_TEXTURE_2D);
411
412   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
413   glColor4f(1, 1, 1, 0.5);
414
415#if 0
416   /* setup lighting, etc */
417   glEnable(GL_LIGHTING);
418   glEnable(GL_LIGHT0);
419#endif
420}
421
422
423static void
424Usage(void)
425{
426   printf("Usage:\n");
427   printf("  textures [file.rgb] ...\n");
428   printf("Keys:\n");
429   printf("  a - toggle animation\n");
430   printf("  b - toggle blending\n");
431   printf("  f - change texture filter mode\n");
432   printf("  r - randomize\n");
433   printf("  ESC - exit\n");
434}
435
436
437int
438main(int argc, char *argv[])
439{
440   glutInitWindowSize(700, 700);
441   glutInit(&argc, argv);
442   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
443   Win = glutCreateWindow(argv[0]);
444   glewInit();
445   glutReshapeFunc(Reshape);
446   glutKeyboardFunc(Key);
447   glutSpecialFunc(SpecialKey);
448   glutDisplayFunc(Draw);
449   if (Anim)
450      glutIdleFunc(Idle);
451   Init(argc, (const char **) argv);
452   Usage();
453   PrintState();
454   glutMainLoop();
455   return 0;
456}
457