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