1 /**
2  * Display trilinear mipmap filtering quality.
3  * We look down a long tunnel shape which has a mipmapped texture
4  * applied to it.  Ideally, the transition from one mipmap level to
5  * another should be nice and regular/circular.
6  * This sort of test is frequently seen in online articles about GPU
7  * texture filtering.
8  *
9  * Brian Paul
10  * 13 Oct 2010
11  */
12 
13 
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <GL/glew.h>
17 #include "glut_wrap.h"
18 
19 
20 static GLfloat LodBias = 0.0;
21 static GLboolean NearestFilter = GL_FALSE;
22 static GLfloat Zpos = -10.0, Zrot = 0.0;
23 static GLuint TexObj;
24 static GLboolean HaveAniso;
25 static GLfloat AnisoMax = 1.0, MaxAnisoMax = 8.0;
26 
27 #define TEX_SIZE 1024
28 
29 
30 /** Make a solid-colored texture image */
31 static void
MakeImage(int level,int width,int height,const GLubyte color[4])32 MakeImage(int level, int width, int height, const GLubyte color[4])
33 {
34    const int makeStripes = 0;
35    GLubyte img[TEX_SIZE * TEX_SIZE * 3];
36    int i, j;
37    for (i = 0; i < height; i++) {
38       for (j = 0; j < width; j++) {
39          int k = (i * width + j) * 3;
40          int p = (i / 8) & makeStripes;
41          if (p == 0) {
42             img[k + 0] = color[0];
43             img[k + 1] = color[1];
44             img[k + 2] = color[2];
45          }
46          else {
47             img[k + 0] = 0;
48             img[k + 1] = 0;
49             img[k + 2] = 0;
50          }
51       }
52    }
53 
54    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
55    glTexImage2D(GL_TEXTURE_2D, level, GL_RGB, width, height, 0,
56                 GL_RGB, GL_UNSIGNED_BYTE, img);
57 }
58 
59 
60 /** Make a mipmap in which each level is a different, solid color */
61 static void
MakeMipmap(void)62 MakeMipmap(void)
63 {
64    static const GLubyte colors[12][3] = {
65       {255, 0, 0},
66       {0, 255, 0},
67       {0, 0, 255},
68       {0, 255, 255},
69       {255, 0, 255},
70       {255, 255, 0},
71       {255, 0, 0},
72       {0, 255, 0},
73       {0, 0, 255},
74       {0, 255, 255},
75       {255, 0, 255},
76       {255, 255, 0},
77    };
78    int i, sz = TEX_SIZE;
79 
80    for (i = 0; sz > 0; i++) {
81       MakeImage(i, sz, sz, colors[i]);
82       printf("Level %d size: %d x %d\n", i, sz, sz);
83       sz /= 2;
84    }
85 }
86 
87 
88 static void
Init(void)89 Init(void)
90 {
91    glClearColor(.5, .5, .5, .5);
92 
93    glGenTextures(1, &TexObj);
94    glBindTexture(GL_TEXTURE_2D, TexObj);
95    MakeMipmap();
96 
97    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
98    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
99    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
100 
101    printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
102    printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
103 
104    HaveAniso = glutExtensionSupported("GL_EXT_texture_filter_anisotropic");
105    if (HaveAniso) {
106       glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &MaxAnisoMax);
107       printf("GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = %f\n", MaxAnisoMax);
108    }
109 }
110 
111 
112 static void
DrawTunnel(void)113 DrawTunnel(void)
114 {
115    const float radius = 10.0, height = 500.0;
116    const int slices = 24, stacks = 52;
117    const float bias = 0.995;
118    GLUquadric *q = gluNewQuadric();
119 
120    glPushMatrix();
121       glRotatef(180, 1, 0, 0);
122       glEnable(GL_TEXTURE_2D);
123       gluQuadricTexture(q, GL_TRUE);
124       gluCylinder(q, radius, radius, height, slices, stacks);
125 
126       glDisable(GL_TEXTURE_2D);
127       glColor3f(0, 0, 0);
128       gluQuadricDrawStyle(q, GLU_LINE);
129       gluCylinder(q, bias*radius, bias*radius, height/4, slices, stacks/4);
130    glPopMatrix();
131 
132    gluDeleteQuadric(q);
133 }
134 
135 
136 static void
PrintString(const char * s)137 PrintString(const char *s)
138 {
139    while (*s) {
140       glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int) *s);
141       s++;
142    }
143 }
144 
145 
146 static void
Display(void)147 Display(void)
148 {
149    char str[100];
150 
151    glBindTexture(GL_TEXTURE_2D, TexObj);
152 
153    if (NearestFilter) {
154       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
155       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
156                       GL_NEAREST_MIPMAP_NEAREST);
157    }
158    else {
159       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
160       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
161                       GL_LINEAR_MIPMAP_LINEAR);
162    }
163 
164    if (HaveAniso) {
165       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, AnisoMax);
166    }
167 
168    glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, LodBias);
169 
170    glClear(GL_COLOR_BUFFER_BIT);
171 
172    glPushMatrix();
173       glTranslatef(0.0, 0.0, Zpos);
174       glRotatef(Zrot, 0, 0, 1);
175       DrawTunnel();
176    glPopMatrix();
177 
178    glColor3f(1, 1, 1);
179    glWindowPos2i(10, 10);
180    if (HaveAniso)
181       sprintf(str, "LOD bias (b/B): %.3f  MaxAnisotropy: %.3f", LodBias, AnisoMax);
182    else
183       sprintf(str, "LOD bias (b/B): %.3f", LodBias);
184    PrintString(str);
185 
186    glutSwapBuffers();
187 }
188 
189 
190 static void
Reshape(int w,int h)191 Reshape(int w, int h)
192 {
193    glViewport(0, 0, w, h);
194    glMatrixMode(GL_PROJECTION);
195    glLoadIdentity();
196    gluPerspective(80.0, 1.0 * (GLfloat) w / (GLfloat) h, 1.0, 3000.0);
197    glMatrixMode(GL_MODELVIEW);
198    glLoadIdentity();
199 }
200 
201 
202 static void
Key(unsigned char k,int x,int y)203 Key(unsigned char k, int x, int y)
204 {
205    (void) x;
206    (void) y;
207    switch (k) {
208    case 'a':
209       AnisoMax -= 0.25;
210       if (AnisoMax <= 1.0)
211          AnisoMax = 1.0;
212       break;
213    case 'A':
214       AnisoMax += 0.25;
215       if (AnisoMax > MaxAnisoMax)
216          AnisoMax = MaxAnisoMax;
217       break;
218    case 'b':
219       LodBias -= 0.125;
220       break;
221    case 'B':
222       LodBias += 0.125;
223       break;
224    case 'f':
225       NearestFilter = !NearestFilter;
226       break;
227    case 'r':
228       Zrot--;
229       break;
230    case 'R':
231       Zrot++;
232       break;
233    case 'z':
234       Zpos--;
235       break;
236    case 'Z':
237       Zpos++;
238       break;
239    case 27:
240       exit(0);
241       break;
242    default:
243       return;
244    }
245    glutPostRedisplay();
246 }
247 
248 
249 static void
Usage(void)250 Usage(void)
251 {
252    printf("Keys:\n");
253    printf("  b/B    decrease/increase GL_TEXTURE_LOD_BIAS\n");
254    printf("  f      toggle nearest/linear filtering\n");
255    printf("  r/R    rotate tunnel\n");
256 }
257 
258 
259 int
main(int argc,char ** argv)260 main(int argc, char **argv)
261 {
262    glutInitWindowSize(600, 600);
263    glutInit(&argc, argv);
264    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
265    glutCreateWindow(argv[0]);
266    glewInit();
267    glutReshapeFunc(Reshape);
268    glutDisplayFunc(Display);
269    glutKeyboardFunc(Key);
270    Init();
271    Usage();
272    glutMainLoop();
273    return 0;
274 }
275