1/*
2 * Test mipmap generation and lod bias.
3 *
4 * Brian Paul
5 * 17 March 2008
6 */
7
8
9#include <assert.h>
10#include <stdlib.h>
11#include <stdio.h>
12#include <math.h>
13#include <GL/glew.h>
14#include "glut_wrap.h"
15
16#include "readtex.h"
17
18#define TEXTURE_FILE DEMOS_DATA_DIR "arch.rgb"
19
20#define LEVELS 8
21#define SIZE (1<<LEVELS)
22static int TexWidth = SIZE, TexHeight = SIZE;
23static int WinWidth = 1044, WinHeight = 900;
24static GLfloat Bias = 0.0;
25static GLboolean ScaleQuads = GL_FALSE;
26static GLboolean Linear = GL_FALSE;
27static GLint Win = 0;
28static GLint RenderTextureLevel = 0;
29static GLuint TexObj;
30
31
32
33static void
34CheckError(int line)
35{
36   GLenum err = glGetError();
37   if (err) {
38      printf("GL Error 0x%x at line %d\n", (int) err, line);
39   }
40}
41
42
43
44static void
45PrintString(const char *s)
46{
47   while (*s) {
48      glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int) *s);
49      s++;
50   }
51}
52
53
54
55
56static void
57MipGenTexture( void )
58{
59   /* test auto mipmap generation */
60   GLint width, height, i;
61   GLenum format;
62   GLubyte *image = LoadRGBImage(TEXTURE_FILE, &width, &height, &format);
63   if (!image) {
64      printf("Error: could not load texture image %s\n", TEXTURE_FILE);
65      exit(1);
66   }
67   /* resize to TexWidth x TexHeight */
68   if (width != TexWidth || height != TexHeight) {
69      GLubyte *newImage = malloc(TexWidth * TexHeight * 4);
70
71      fprintf(stderr, "rescale %d %d to %d %d\n", width, height,
72              TexWidth, TexHeight);
73      fflush(stderr);
74
75      gluScaleImage(format, width, height, GL_UNSIGNED_BYTE, image,
76                    TexWidth, TexHeight, GL_UNSIGNED_BYTE, newImage);
77      free(image);
78      image = newImage;
79   }
80   printf("Using GL_SGIS_generate_mipmap\n");
81   glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
82   glTexImage2D(GL_TEXTURE_2D, 0, format, TexWidth, TexHeight, 0,
83                format, GL_UNSIGNED_BYTE, image);
84   free(image);
85
86   /* make sure mipmap was really generated correctly */
87   width = TexWidth;
88   height = TexHeight;
89   for (i = 0; i < 9; i++) {
90      GLint w, h;
91      glGetTexLevelParameteriv(GL_TEXTURE_2D, i, GL_TEXTURE_WIDTH, &w);
92      glGetTexLevelParameteriv(GL_TEXTURE_2D, i, GL_TEXTURE_HEIGHT, &h);
93      printf("Level %d size: %d x %d\n", i, w, h);
94      assert(w == width);
95      assert(h == height);
96      width /= 2;
97      height /= 2;
98   }
99
100
101   glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_FALSE);
102}
103
104
105
106static void
107ResetTextureLevel( int i )
108{
109   GLubyte tex2d[SIZE*SIZE][4];
110
111   {
112      GLint Width = TexWidth / (1 << i);
113      GLint Height = TexHeight / (1 << i);
114      GLint s, t;
115
116      for (s = 0; s < Width; s++) {
117         for (t = 0; t < Height; t++) {
118            tex2d[t*Width+s][0] = ((s / 16) % 2) ? 0 : 255;
119            tex2d[t*Width+s][1] = ((t / 16) % 2) ? 0 : 255;
120            tex2d[t*Width+s][2] = 128;
121            tex2d[t*Width+s][3] = 255;
122         }
123      }
124
125      glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
126
127      glTexImage2D(GL_TEXTURE_2D, i, GL_RGB, Width, Height, 0,
128                   GL_RGBA, GL_UNSIGNED_BYTE, tex2d);
129   }
130}
131
132
133static void
134ResetTexture( void )
135{
136#if 0
137   /* This doesn't work so well as the arch texture is 512x512.
138    */
139   LoadRGBMipmaps(TEXTURE_FILE, GL_RGB);
140#else
141   {
142      int i;
143
144      for (i = 0; i <= LEVELS; i++)
145      {
146         ResetTextureLevel(i);
147      }
148   }
149#endif
150}
151
152
153
154
155
156
157
158static void
159RenderTexture( void )
160{
161   GLenum status;
162   GLuint MyFB;
163
164   fprintf(stderr, "RenderTextureLevel %d\n", RenderTextureLevel);
165   fflush(stderr);
166
167   /* gen framebuffer id, delete it, do some assertions, just for testing */
168   glGenFramebuffersEXT(1, &MyFB);
169   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, MyFB);
170   assert(glIsFramebufferEXT(MyFB));
171
172   CheckError(__LINE__);
173
174   /* Render color to texture */
175   glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
176                             GL_COLOR_ATTACHMENT0_EXT,
177                             GL_TEXTURE_2D, TexObj,
178                             RenderTextureLevel);
179
180
181
182   CheckError(__LINE__);
183
184
185   glMatrixMode(GL_PROJECTION);
186   glLoadIdentity();
187   glOrtho(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
188   glMatrixMode(GL_MODELVIEW);
189   glLoadIdentity();
190   glTranslatef(0.0, 0.0, -15.0);
191
192   status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
193   if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
194      printf("Framebuffer incomplete!!!\n");
195   }
196
197   glViewport(0, 0,
198              TexWidth / (1 << RenderTextureLevel),
199              TexHeight / (1 << RenderTextureLevel));
200
201   glClearColor(0.5, 0.5, 1.0, 0.0);
202   glClear(GL_COLOR_BUFFER_BIT);
203
204   CheckError(__LINE__);
205
206   glBegin(GL_POLYGON);
207   glColor3f(1, 0, 0);
208   glVertex2f(-1, -1);
209   glColor3f(0, 1, 0);
210   glVertex2f(1, -1);
211   glColor3f(0, 0, 1);
212   glVertex2f(0, 1);
213   glEnd();
214
215
216   /* Bind normal framebuffer */
217   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
218   CheckError(__LINE__);
219
220   glDeleteFramebuffersEXT(1, &MyFB);
221   CheckError(__LINE__);
222
223   glClearColor(0, 0, 0, 0);
224}
225
226static void
227Display(void)
228{
229   int x, y, bias;
230   char str[100];
231   int texWidth = TexWidth, texHeight = TexHeight;
232
233   glViewport(0, 0, WinHeight, WinHeight);
234
235   glClear(GL_COLOR_BUFFER_BIT);
236
237   glMatrixMode(GL_PROJECTION);
238   glLoadIdentity();
239   glOrtho(0, WinWidth, 0, WinHeight, -1, 1);
240   glMatrixMode(GL_MODELVIEW);
241   glLoadIdentity();
242
243   glColor3f(1,1,1);
244
245   if (Linear) {
246      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
247      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
248   }
249   else {
250      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
251      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
252   }
253
254   y = WinHeight - 300;
255   x = 4;
256
257   for (bias = -1; bias < 11; bias++) {
258
259      if (ScaleQuads) {
260         if (bias > 0) {
261            if (texWidth == 1 && texHeight == 1)
262               break;
263            texWidth = TexWidth >> bias;
264            texHeight = TexHeight >> bias;
265            if (texWidth < 1)
266               texWidth = 1;
267            if (texHeight < 1)
268               texHeight = 1;
269         }
270         glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0.0);
271      }
272      else {
273         glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, bias);
274      }
275
276      glRasterPos2f(x, y + TexHeight + 5);
277      if (ScaleQuads)
278         sprintf(str, "Texture Level %d: %d x %d",
279                 (bias < 0 ? 0 : bias),
280                 texWidth, texHeight);
281      else
282         sprintf(str, "Texture LOD Bias = %d", bias);
283      PrintString(str);
284
285      glPushMatrix();
286      glTranslatef(x, y, 0);
287
288      glEnable(GL_TEXTURE_2D);
289
290      glBegin(GL_POLYGON);
291      glTexCoord2f(0, 0);  glVertex2f(0, 0);
292      glTexCoord2f(1, 0);  glVertex2f(texWidth, 0);
293      glTexCoord2f(1, 1);  glVertex2f(texWidth, texHeight);
294      glTexCoord2f(0, 1);  glVertex2f(0, texHeight);
295      glEnd();
296
297      glPopMatrix();
298
299      glDisable(GL_TEXTURE_2D);
300
301      x += TexWidth + 4;
302      if (x >= WinWidth) {
303         x = 4;
304         y -= 300;
305      }
306   }
307
308   glutSwapBuffers();
309}
310
311
312static void
313Reshape(int width, int height)
314{
315   WinWidth = width;
316   WinHeight = height;
317}
318
319
320static void
321Key(unsigned char key, int x, int y)
322{
323   (void) x;
324   (void) y;
325   switch (key) {
326      case 'b':
327         Bias -= 10;
328         break;
329      case 'B':
330         Bias += 10;
331         break;
332      case 'l':
333         Linear = !Linear;
334         break;
335      case 'v':
336         RenderTextureLevel++;
337         break;
338      case 'V':
339         RenderTextureLevel--;
340         break;
341      case 'r':
342         RenderTexture();
343         break;
344      case 'X':
345         ResetTexture();
346         break;
347      case 'x':
348         ResetTextureLevel(RenderTextureLevel);
349         break;
350      case '0':
351      case '1':
352      case '2':
353      case '3':
354      case '4':
355      case '5':
356      case '6':
357      case '7':
358      case '8':
359      case '9':
360         Bias = 100.0 * (key - '0');
361         break;
362      case 's':
363         ScaleQuads = !ScaleQuads;
364         break;
365      case ' ':
366         MipGenTexture();
367         Bias = 0;
368         Linear = 0;
369         RenderTextureLevel = 0;
370         ScaleQuads = 0;
371         break;
372
373      case 27:
374         glutDestroyWindow(Win);
375         exit(0);
376         break;
377   }
378   glutPostRedisplay();
379}
380
381
382static void
383Init(void)
384{
385   GLfloat maxBias;
386
387   if (!glutExtensionSupported("GL_EXT_texture_lod_bias")) {
388      printf("Sorry, GL_EXT_texture_lod_bias not supported by this renderer.\n");
389      exit(1);
390   }
391
392   if (!glutExtensionSupported("GL_SGIS_generate_mipmap")) {
393      printf("Sorry, GL_SGIS_generate_mipmap not supported by this renderer.\n");
394      exit(1);
395   }
396
397   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
398
399   glGenTextures(1, &TexObj);
400   glBindTexture(GL_TEXTURE_2D, TexObj);
401
402   if (1)
403      MipGenTexture();
404   else
405      ResetTexture();
406
407   /* mipmapping required for this extension */
408   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
409
410   glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS_EXT, &maxBias);
411
412   printf("GL_RENDERER: %s\n", (char*) glGetString(GL_RENDERER));
413   printf("LOD bias range: [%g, %g]\n", -maxBias, maxBias);
414
415   printf("Press 's' to toggle quad scaling\n");
416}
417
418
419int
420main(int argc, char *argv[])
421{
422   glutInit(&argc, argv);
423   glutInitWindowPosition(0, 0);
424   glutInitWindowSize(WinWidth, WinHeight);
425   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
426   Win = glutCreateWindow(argv[0]);
427   glewInit();
428   glutReshapeFunc(Reshape);
429   glutKeyboardFunc(Key);
430   glutDisplayFunc(Display);
431   Init();
432   glutMainLoop();
433   return 0;
434}
435