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 20static GLfloat LodBias = 0.0; 21static GLboolean NearestFilter = GL_FALSE; 22static GLfloat Zpos = -10.0, Zrot = 0.0; 23static GLuint TexObj; 24static GLboolean HaveAniso; 25static GLfloat AnisoMax = 1.0, MaxAnisoMax = 8.0; 26 27#define TEX_SIZE 1024 28 29 30/** Make a solid-colored texture image */ 31static void 32MakeImage(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 */ 61static void 62MakeMipmap(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 88static void 89Init(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 112static void 113DrawTunnel(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 136static void 137PrintString(const char *s) 138{ 139 while (*s) { 140 glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int) *s); 141 s++; 142 } 143} 144 145 146static void 147Display(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 190static void 191Reshape(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 202static void 203Key(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 249static void 250Usage(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 259int 260main(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