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