132001f49Smrg/*
232001f49Smrg * Test mipmap generation and lod bias.
332001f49Smrg *
432001f49Smrg * Brian Paul
532001f49Smrg * 17 March 2008
632001f49Smrg */
732001f49Smrg
832001f49Smrg
932001f49Smrg#include <assert.h>
1032001f49Smrg#include <stdlib.h>
1132001f49Smrg#include <stdio.h>
1232001f49Smrg#include <math.h>
1332001f49Smrg#include <GL/glew.h>
1432001f49Smrg#include "glut_wrap.h"
1532001f49Smrg
1632001f49Smrg#include "readtex.h"
1732001f49Smrg
1832001f49Smrg#define TEXTURE_FILE DEMOS_DATA_DIR "arch.rgb"
1932001f49Smrg
2032001f49Smrg#define LEVELS 8
2132001f49Smrg#define SIZE (1<<LEVELS)
2232001f49Smrgstatic int TexWidth = SIZE, TexHeight = SIZE;
2332001f49Smrgstatic int WinWidth = 1044, WinHeight = 900;
2432001f49Smrgstatic GLfloat Bias = 0.0;
2532001f49Smrgstatic GLboolean ScaleQuads = GL_FALSE;
2632001f49Smrgstatic GLboolean Linear = GL_FALSE;
2732001f49Smrgstatic GLint Win = 0;
2832001f49Smrgstatic GLint RenderTextureLevel = 0;
2932001f49Smrgstatic GLuint TexObj;
3032001f49Smrg
3132001f49Smrg
3232001f49Smrg
3332001f49Smrgstatic void
3432001f49SmrgCheckError(int line)
3532001f49Smrg{
3632001f49Smrg   GLenum err = glGetError();
3732001f49Smrg   if (err) {
3832001f49Smrg      printf("GL Error 0x%x at line %d\n", (int) err, line);
3932001f49Smrg   }
4032001f49Smrg}
4132001f49Smrg
4232001f49Smrg
4332001f49Smrg
4432001f49Smrgstatic void
4532001f49SmrgPrintString(const char *s)
4632001f49Smrg{
4732001f49Smrg   while (*s) {
4832001f49Smrg      glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int) *s);
4932001f49Smrg      s++;
5032001f49Smrg   }
5132001f49Smrg}
5232001f49Smrg
5332001f49Smrg
5432001f49Smrg
5532001f49Smrg
5632001f49Smrgstatic void
5732001f49SmrgMipGenTexture( void )
5832001f49Smrg{
5932001f49Smrg   /* test auto mipmap generation */
6032001f49Smrg   GLint width, height, i;
6132001f49Smrg   GLenum format;
6232001f49Smrg   GLubyte *image = LoadRGBImage(TEXTURE_FILE, &width, &height, &format);
6332001f49Smrg   if (!image) {
6432001f49Smrg      printf("Error: could not load texture image %s\n", TEXTURE_FILE);
6532001f49Smrg      exit(1);
6632001f49Smrg   }
6732001f49Smrg   /* resize to TexWidth x TexHeight */
6832001f49Smrg   if (width != TexWidth || height != TexHeight) {
6932001f49Smrg      GLubyte *newImage = malloc(TexWidth * TexHeight * 4);
7032001f49Smrg
7132001f49Smrg      fprintf(stderr, "rescale %d %d to %d %d\n", width, height,
7232001f49Smrg              TexWidth, TexHeight);
7332001f49Smrg      fflush(stderr);
7432001f49Smrg
7532001f49Smrg      gluScaleImage(format, width, height, GL_UNSIGNED_BYTE, image,
7632001f49Smrg                    TexWidth, TexHeight, GL_UNSIGNED_BYTE, newImage);
7732001f49Smrg      free(image);
7832001f49Smrg      image = newImage;
7932001f49Smrg   }
8032001f49Smrg   printf("Using GL_SGIS_generate_mipmap\n");
8132001f49Smrg   glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
8232001f49Smrg   glTexImage2D(GL_TEXTURE_2D, 0, format, TexWidth, TexHeight, 0,
8332001f49Smrg                format, GL_UNSIGNED_BYTE, image);
8432001f49Smrg   free(image);
8532001f49Smrg
8632001f49Smrg   /* make sure mipmap was really generated correctly */
8732001f49Smrg   width = TexWidth;
8832001f49Smrg   height = TexHeight;
8932001f49Smrg   for (i = 0; i < 9; i++) {
9032001f49Smrg      GLint w, h;
9132001f49Smrg      glGetTexLevelParameteriv(GL_TEXTURE_2D, i, GL_TEXTURE_WIDTH, &w);
9232001f49Smrg      glGetTexLevelParameteriv(GL_TEXTURE_2D, i, GL_TEXTURE_HEIGHT, &h);
9332001f49Smrg      printf("Level %d size: %d x %d\n", i, w, h);
9432001f49Smrg      assert(w == width);
9532001f49Smrg      assert(h == height);
9632001f49Smrg      width /= 2;
9732001f49Smrg      height /= 2;
9832001f49Smrg   }
9932001f49Smrg
10032001f49Smrg
10132001f49Smrg   glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_FALSE);
10232001f49Smrg}
10332001f49Smrg
10432001f49Smrg
10532001f49Smrg
10632001f49Smrgstatic void
10732001f49SmrgResetTextureLevel( int i )
10832001f49Smrg{
10932001f49Smrg   GLubyte tex2d[SIZE*SIZE][4];
11032001f49Smrg
11132001f49Smrg   {
11232001f49Smrg      GLint Width = TexWidth / (1 << i);
11332001f49Smrg      GLint Height = TexHeight / (1 << i);
11432001f49Smrg      GLint s, t;
11532001f49Smrg
11632001f49Smrg      for (s = 0; s < Width; s++) {
11732001f49Smrg         for (t = 0; t < Height; t++) {
11832001f49Smrg            tex2d[t*Width+s][0] = ((s / 16) % 2) ? 0 : 255;
11932001f49Smrg            tex2d[t*Width+s][1] = ((t / 16) % 2) ? 0 : 255;
12032001f49Smrg            tex2d[t*Width+s][2] = 128;
12132001f49Smrg            tex2d[t*Width+s][3] = 255;
12232001f49Smrg         }
12332001f49Smrg      }
12432001f49Smrg
12532001f49Smrg      glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
12632001f49Smrg
12732001f49Smrg      glTexImage2D(GL_TEXTURE_2D, i, GL_RGB, Width, Height, 0,
12832001f49Smrg                   GL_RGBA, GL_UNSIGNED_BYTE, tex2d);
12932001f49Smrg   }
13032001f49Smrg}
13132001f49Smrg
13232001f49Smrg
13332001f49Smrgstatic void
13432001f49SmrgResetTexture( void )
13532001f49Smrg{
13632001f49Smrg#if 0
13732001f49Smrg   /* This doesn't work so well as the arch texture is 512x512.
13832001f49Smrg    */
13932001f49Smrg   LoadRGBMipmaps(TEXTURE_FILE, GL_RGB);
14032001f49Smrg#else
14132001f49Smrg   {
14232001f49Smrg      int i;
14332001f49Smrg
14432001f49Smrg      for (i = 0; i <= LEVELS; i++)
14532001f49Smrg      {
14632001f49Smrg         ResetTextureLevel(i);
14732001f49Smrg      }
14832001f49Smrg   }
14932001f49Smrg#endif
15032001f49Smrg}
15132001f49Smrg
15232001f49Smrg
15332001f49Smrg
15432001f49Smrg
15532001f49Smrg
15632001f49Smrg
15732001f49Smrg
15832001f49Smrgstatic void
15932001f49SmrgRenderTexture( void )
16032001f49Smrg{
16132001f49Smrg   GLenum status;
16232001f49Smrg   GLuint MyFB;
16332001f49Smrg
16432001f49Smrg   fprintf(stderr, "RenderTextureLevel %d\n", RenderTextureLevel);
16532001f49Smrg   fflush(stderr);
16632001f49Smrg
16732001f49Smrg   /* gen framebuffer id, delete it, do some assertions, just for testing */
16832001f49Smrg   glGenFramebuffersEXT(1, &MyFB);
16932001f49Smrg   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, MyFB);
17032001f49Smrg   assert(glIsFramebufferEXT(MyFB));
17132001f49Smrg
17232001f49Smrg   CheckError(__LINE__);
17332001f49Smrg
17432001f49Smrg   /* Render color to texture */
17532001f49Smrg   glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
17632001f49Smrg                             GL_COLOR_ATTACHMENT0_EXT,
17732001f49Smrg                             GL_TEXTURE_2D, TexObj,
17832001f49Smrg                             RenderTextureLevel);
17932001f49Smrg
18032001f49Smrg
18132001f49Smrg
18232001f49Smrg   CheckError(__LINE__);
18332001f49Smrg
18432001f49Smrg
18532001f49Smrg   glMatrixMode(GL_PROJECTION);
18632001f49Smrg   glLoadIdentity();
18732001f49Smrg   glOrtho(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
18832001f49Smrg   glMatrixMode(GL_MODELVIEW);
18932001f49Smrg   glLoadIdentity();
19032001f49Smrg   glTranslatef(0.0, 0.0, -15.0);
19132001f49Smrg
19232001f49Smrg   status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
19332001f49Smrg   if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
19432001f49Smrg      printf("Framebuffer incomplete!!!\n");
19532001f49Smrg   }
19632001f49Smrg
19732001f49Smrg   glViewport(0, 0,
19832001f49Smrg              TexWidth / (1 << RenderTextureLevel),
19932001f49Smrg              TexHeight / (1 << RenderTextureLevel));
20032001f49Smrg
20132001f49Smrg   glClearColor(0.5, 0.5, 1.0, 0.0);
20232001f49Smrg   glClear(GL_COLOR_BUFFER_BIT);
20332001f49Smrg
20432001f49Smrg   CheckError(__LINE__);
20532001f49Smrg
20632001f49Smrg   glBegin(GL_POLYGON);
20732001f49Smrg   glColor3f(1, 0, 0);
20832001f49Smrg   glVertex2f(-1, -1);
20932001f49Smrg   glColor3f(0, 1, 0);
21032001f49Smrg   glVertex2f(1, -1);
21132001f49Smrg   glColor3f(0, 0, 1);
21232001f49Smrg   glVertex2f(0, 1);
21332001f49Smrg   glEnd();
21432001f49Smrg
21532001f49Smrg
21632001f49Smrg   /* Bind normal framebuffer */
21732001f49Smrg   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
21832001f49Smrg   CheckError(__LINE__);
21932001f49Smrg
22032001f49Smrg   glDeleteFramebuffersEXT(1, &MyFB);
22132001f49Smrg   CheckError(__LINE__);
22232001f49Smrg
22332001f49Smrg   glClearColor(0, 0, 0, 0);
22432001f49Smrg}
22532001f49Smrg
22632001f49Smrgstatic void
22732001f49SmrgDisplay(void)
22832001f49Smrg{
22932001f49Smrg   int x, y, bias;
23032001f49Smrg   char str[100];
23132001f49Smrg   int texWidth = TexWidth, texHeight = TexHeight;
23232001f49Smrg
23332001f49Smrg   glViewport(0, 0, WinHeight, WinHeight);
23432001f49Smrg
23532001f49Smrg   glClear(GL_COLOR_BUFFER_BIT);
23632001f49Smrg
23732001f49Smrg   glMatrixMode(GL_PROJECTION);
23832001f49Smrg   glLoadIdentity();
23932001f49Smrg   glOrtho(0, WinWidth, 0, WinHeight, -1, 1);
24032001f49Smrg   glMatrixMode(GL_MODELVIEW);
24132001f49Smrg   glLoadIdentity();
24232001f49Smrg
24332001f49Smrg   glColor3f(1,1,1);
24432001f49Smrg
24532001f49Smrg   if (Linear) {
24632001f49Smrg      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
24732001f49Smrg      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
24832001f49Smrg   }
24932001f49Smrg   else {
25032001f49Smrg      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
25132001f49Smrg      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
25232001f49Smrg   }
25332001f49Smrg
25432001f49Smrg   y = WinHeight - 300;
25532001f49Smrg   x = 4;
25632001f49Smrg
25732001f49Smrg   for (bias = -1; bias < 11; bias++) {
25832001f49Smrg
25932001f49Smrg      if (ScaleQuads) {
26032001f49Smrg         if (bias > 0) {
26132001f49Smrg            if (texWidth == 1 && texHeight == 1)
26232001f49Smrg               break;
26332001f49Smrg            texWidth = TexWidth >> bias;
26432001f49Smrg            texHeight = TexHeight >> bias;
26532001f49Smrg            if (texWidth < 1)
26632001f49Smrg               texWidth = 1;
26732001f49Smrg            if (texHeight < 1)
26832001f49Smrg               texHeight = 1;
26932001f49Smrg         }
27032001f49Smrg         glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0.0);
27132001f49Smrg      }
27232001f49Smrg      else {
27332001f49Smrg         glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, bias);
27432001f49Smrg      }
27532001f49Smrg
27632001f49Smrg      glRasterPos2f(x, y + TexHeight + 5);
27732001f49Smrg      if (ScaleQuads)
27832001f49Smrg         sprintf(str, "Texture Level %d: %d x %d",
27932001f49Smrg                 (bias < 0 ? 0 : bias),
28032001f49Smrg                 texWidth, texHeight);
28132001f49Smrg      else
28232001f49Smrg         sprintf(str, "Texture LOD Bias = %d", bias);
28332001f49Smrg      PrintString(str);
28432001f49Smrg
28532001f49Smrg      glPushMatrix();
28632001f49Smrg      glTranslatef(x, y, 0);
28732001f49Smrg
28832001f49Smrg      glEnable(GL_TEXTURE_2D);
28932001f49Smrg
29032001f49Smrg      glBegin(GL_POLYGON);
29132001f49Smrg      glTexCoord2f(0, 0);  glVertex2f(0, 0);
29232001f49Smrg      glTexCoord2f(1, 0);  glVertex2f(texWidth, 0);
29332001f49Smrg      glTexCoord2f(1, 1);  glVertex2f(texWidth, texHeight);
29432001f49Smrg      glTexCoord2f(0, 1);  glVertex2f(0, texHeight);
29532001f49Smrg      glEnd();
29632001f49Smrg
29732001f49Smrg      glPopMatrix();
29832001f49Smrg
29932001f49Smrg      glDisable(GL_TEXTURE_2D);
30032001f49Smrg
30132001f49Smrg      x += TexWidth + 4;
30232001f49Smrg      if (x >= WinWidth) {
30332001f49Smrg         x = 4;
30432001f49Smrg         y -= 300;
30532001f49Smrg      }
30632001f49Smrg   }
30732001f49Smrg
30832001f49Smrg   glutSwapBuffers();
30932001f49Smrg}
31032001f49Smrg
31132001f49Smrg
31232001f49Smrgstatic void
31332001f49SmrgReshape(int width, int height)
31432001f49Smrg{
31532001f49Smrg   WinWidth = width;
31632001f49Smrg   WinHeight = height;
31732001f49Smrg}
31832001f49Smrg
31932001f49Smrg
32032001f49Smrgstatic void
32132001f49SmrgKey(unsigned char key, int x, int y)
32232001f49Smrg{
32332001f49Smrg   (void) x;
32432001f49Smrg   (void) y;
32532001f49Smrg   switch (key) {
32632001f49Smrg      case 'b':
32732001f49Smrg         Bias -= 10;
32832001f49Smrg         break;
32932001f49Smrg      case 'B':
33032001f49Smrg         Bias += 10;
33132001f49Smrg         break;
33232001f49Smrg      case 'l':
33332001f49Smrg         Linear = !Linear;
33432001f49Smrg         break;
33532001f49Smrg      case 'v':
33632001f49Smrg         RenderTextureLevel++;
33732001f49Smrg         break;
33832001f49Smrg      case 'V':
33932001f49Smrg         RenderTextureLevel--;
34032001f49Smrg         break;
34132001f49Smrg      case 'r':
34232001f49Smrg         RenderTexture();
34332001f49Smrg         break;
34432001f49Smrg      case 'X':
34532001f49Smrg         ResetTexture();
34632001f49Smrg         break;
34732001f49Smrg      case 'x':
34832001f49Smrg         ResetTextureLevel(RenderTextureLevel);
34932001f49Smrg         break;
35032001f49Smrg      case '0':
35132001f49Smrg      case '1':
35232001f49Smrg      case '2':
35332001f49Smrg      case '3':
35432001f49Smrg      case '4':
35532001f49Smrg      case '5':
35632001f49Smrg      case '6':
35732001f49Smrg      case '7':
35832001f49Smrg      case '8':
35932001f49Smrg      case '9':
36032001f49Smrg         Bias = 100.0 * (key - '0');
36132001f49Smrg         break;
36232001f49Smrg      case 's':
36332001f49Smrg         ScaleQuads = !ScaleQuads;
36432001f49Smrg         break;
36532001f49Smrg      case ' ':
36632001f49Smrg         MipGenTexture();
36732001f49Smrg         Bias = 0;
36832001f49Smrg         Linear = 0;
36932001f49Smrg         RenderTextureLevel = 0;
37032001f49Smrg         ScaleQuads = 0;
37132001f49Smrg         break;
37232001f49Smrg
37332001f49Smrg      case 27:
37432001f49Smrg         glutDestroyWindow(Win);
37532001f49Smrg         exit(0);
37632001f49Smrg         break;
37732001f49Smrg   }
37832001f49Smrg   glutPostRedisplay();
37932001f49Smrg}
38032001f49Smrg
38132001f49Smrg
38232001f49Smrgstatic void
38332001f49SmrgInit(void)
38432001f49Smrg{
38532001f49Smrg   GLfloat maxBias;
38632001f49Smrg
38732001f49Smrg   if (!glutExtensionSupported("GL_EXT_texture_lod_bias")) {
38832001f49Smrg      printf("Sorry, GL_EXT_texture_lod_bias not supported by this renderer.\n");
38932001f49Smrg      exit(1);
39032001f49Smrg   }
39132001f49Smrg
39232001f49Smrg   if (!glutExtensionSupported("GL_SGIS_generate_mipmap")) {
39332001f49Smrg      printf("Sorry, GL_SGIS_generate_mipmap not supported by this renderer.\n");
39432001f49Smrg      exit(1);
39532001f49Smrg   }
39632001f49Smrg
39732001f49Smrg   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
39832001f49Smrg
39932001f49Smrg   glGenTextures(1, &TexObj);
40032001f49Smrg   glBindTexture(GL_TEXTURE_2D, TexObj);
40132001f49Smrg
40232001f49Smrg   if (1)
40332001f49Smrg      MipGenTexture();
40432001f49Smrg   else
40532001f49Smrg      ResetTexture();
40632001f49Smrg
40732001f49Smrg   /* mipmapping required for this extension */
40832001f49Smrg   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
40932001f49Smrg
41032001f49Smrg   glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS_EXT, &maxBias);
41132001f49Smrg
41232001f49Smrg   printf("GL_RENDERER: %s\n", (char*) glGetString(GL_RENDERER));
41332001f49Smrg   printf("LOD bias range: [%g, %g]\n", -maxBias, maxBias);
41432001f49Smrg
41532001f49Smrg   printf("Press 's' to toggle quad scaling\n");
41632001f49Smrg}
41732001f49Smrg
41832001f49Smrg
41932001f49Smrgint
42032001f49Smrgmain(int argc, char *argv[])
42132001f49Smrg{
42232001f49Smrg   glutInit(&argc, argv);
42332001f49Smrg   glutInitWindowPosition(0, 0);
42432001f49Smrg   glutInitWindowSize(WinWidth, WinHeight);
42532001f49Smrg   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
42632001f49Smrg   Win = glutCreateWindow(argv[0]);
42732001f49Smrg   glewInit();
42832001f49Smrg   glutReshapeFunc(Reshape);
42932001f49Smrg   glutKeyboardFunc(Key);
43032001f49Smrg   glutDisplayFunc(Display);
43132001f49Smrg   Init();
43232001f49Smrg   glutMainLoop();
43332001f49Smrg   return 0;
43432001f49Smrg}
435