1 2/* 3 * test handling of many texture maps 4 * Also tests texture priority and residency. 5 * 6 * Brian Paul 7 * August 2, 2000 8 */ 9 10 11#include <assert.h> 12#include <stdio.h> 13#include <stdlib.h> 14#include <string.h> 15#include <math.h> 16#include <GL/glew.h> 17#include "glut_wrap.h" 18 19 20static GLint NumTextures = 20; 21static GLuint *TextureID = NULL; 22static GLint *TextureWidth = NULL, *TextureHeight = NULL; 23static GLboolean *TextureResidency = NULL; 24static GLint TexWidth = 128, TexHeight = 128; 25static GLfloat Zrot = 0; 26static GLboolean Anim = GL_TRUE; 27static GLint WinWidth = 500, WinHeight = 400; 28static GLboolean MipMap = GL_FALSE; 29static GLboolean LinearFilter = GL_FALSE; 30static GLboolean RandomSize = GL_FALSE; 31static GLint Rows, Columns; 32static GLint LowPriorityCount = 0; 33static GLint Win; 34 35 36static void Idle( void ) 37{ 38 Zrot += 1.0; 39 glutPostRedisplay(); 40} 41 42 43static void Display( void ) 44{ 45 GLfloat spacing = WinWidth / Columns; 46 GLfloat size = spacing * 0.4; 47 GLint i; 48 49 /* test residency */ 50 if (0) 51 { 52 GLboolean b; 53 GLint i, resident; 54 b = glAreTexturesResident(NumTextures, TextureID, TextureResidency); 55 if (b) { 56 printf("all resident\n"); 57 } 58 else { 59 resident = 0; 60 for (i = 0; i < NumTextures; i++) { 61 if (TextureResidency[i]) { 62 resident++; 63 } 64 } 65 printf("%d of %d texture resident\n", resident, NumTextures); 66 } 67 } 68 69 /* render the textured quads */ 70 glClear( GL_COLOR_BUFFER_BIT ); 71 for (i = 0; i < NumTextures; i++) { 72 GLint row = i / Columns; 73 GLint col = i % Columns; 74 GLfloat x = col * spacing + spacing * 0.5; 75 GLfloat y = row * spacing + spacing * 0.5; 76 77 GLfloat maxDim = (TextureWidth[i] > TextureHeight[i]) 78 ? TextureWidth[i] : TextureHeight[i]; 79 GLfloat w = TextureWidth[i] / maxDim; 80 GLfloat h = TextureHeight[i] / maxDim; 81 82 glPushMatrix(); 83 glTranslatef(x, y, 0.0); 84 glRotatef(Zrot, 0, 0, 1); 85 glScalef(size, size, 1); 86 87 glBindTexture(GL_TEXTURE_2D, TextureID[i]); 88 glBegin(GL_POLYGON); 89#if 0 90 glTexCoord2f(0, 0); glVertex2f(-1, -1); 91 glTexCoord2f(1, 0); glVertex2f( 1, -1); 92 glTexCoord2f(1, 1); glVertex2f( 1, 1); 93 glTexCoord2f(0, 1); glVertex2f(-1, 1); 94#else 95 glTexCoord2f(0, 0); glVertex2f(-w, -h); 96 glTexCoord2f(1, 0); glVertex2f( w, -h); 97 glTexCoord2f(1, 1); glVertex2f( w, h); 98 glTexCoord2f(0, 1); glVertex2f(-w, h); 99#endif 100 glEnd(); 101 glPopMatrix(); 102 } 103 104 glutSwapBuffers(); 105} 106 107 108static void Reshape( int width, int height ) 109{ 110 WinWidth = width; 111 WinHeight = height; 112 glViewport( 0, 0, width, height ); 113 glMatrixMode( GL_PROJECTION ); 114 glLoadIdentity(); 115 glOrtho(0, width, 0, height, -1, 1); 116 glMatrixMode( GL_MODELVIEW ); 117 glLoadIdentity(); 118} 119 120 121/* 122 * Return a random int in [min, max]. 123 */ 124static int RandomInt(int min, int max) 125{ 126 int i = rand(); 127 int j = i % (max - min + 1); 128 return min + j; 129} 130 131 132static void DeleteTextures(void) 133{ 134 glDeleteTextures(NumTextures, TextureID); 135 free(TextureID); 136 TextureID = NULL; 137} 138 139 140 141static void Init( void ) 142{ 143 GLint i; 144 145 if (RandomSize) { 146 printf("Creating %d %s random-size textures, ", NumTextures, 147 MipMap ? "Mipmapped" : "non-Mipmapped"); 148 } 149 else { 150 printf("Creating %d %s %d x %d textures, ", NumTextures, 151 MipMap ? "Mipmapped" : "non-Mipmapped", 152 TexWidth, TexHeight); 153 } 154 155 if (LinearFilter) { 156 printf("bilinear filtering\n"); 157 } 158 else { 159 printf("nearest filtering\n"); 160 } 161 162 163 /* compute number of rows and columns of rects */ 164 { 165 GLfloat area = (GLfloat) (WinWidth * WinHeight) / (GLfloat) NumTextures; 166 GLfloat edgeLen = sqrt(area); 167 168 Columns = WinWidth / edgeLen; 169 Rows = (NumTextures + Columns - 1) / Columns; 170 printf("Rows: %d Cols: %d\n", Rows, Columns); 171 } 172 173 174 if (!TextureID) { 175 TextureID = (GLuint *) malloc(sizeof(GLuint) * NumTextures); 176 assert(TextureID); 177 glGenTextures(NumTextures, TextureID); 178 } 179 180 if (!TextureResidency) { 181 TextureResidency = (GLboolean *) malloc(sizeof(GLboolean) * NumTextures); 182 assert(TextureResidency); 183 } 184 185 if (!TextureWidth) { 186 TextureWidth = (GLint *) malloc(sizeof(GLint) * NumTextures); 187 assert(TextureWidth); 188 } 189 if (!TextureHeight) { 190 TextureHeight = (GLint *) malloc(sizeof(GLint) * NumTextures); 191 assert(TextureHeight); 192 } 193 194 for (i = 0; i < NumTextures; i++) { 195 GLubyte color[4]; 196 GLubyte *texImage; 197 GLint j, row, col; 198 199 row = i / Columns; 200 col = i % Columns; 201 202 glBindTexture(GL_TEXTURE_2D, TextureID[i]); 203 204 if (i < LowPriorityCount) 205 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, 0.5F); 206 207 if (RandomSize) { 208#if 0 209 int k = (glutGet(GLUT_ELAPSED_TIME) % 7) + 2; 210 TexWidth = 1 << k; 211 TexHeight = 1 << k; 212#else 213 TexWidth = 1 << RandomInt(2, 7); 214 TexHeight = 1 << RandomInt(2, 7); 215 printf("Random size of %3d: %d x %d\n", i, TexWidth, TexHeight); 216#endif 217 } 218 219 TextureWidth[i] = TexWidth; 220 TextureHeight[i] = TexHeight; 221 222 texImage = (GLubyte*) malloc(4 * TexWidth * TexHeight * sizeof(GLubyte)); 223 assert(texImage); 224 225 /* determine texture color */ 226 color[0] = (GLint) (255.0 * ((float) col / (Columns - 1))); 227 color[1] = 127; 228 color[2] = (GLint) (255.0 * ((float) row / (Rows - 1))); 229 color[3] = 255; 230 231 /* fill in solid-colored teximage */ 232 for (j = 0; j < TexWidth * TexHeight; j++) { 233 texImage[j*4+0] = color[0]; 234 texImage[j*4+1] = color[1]; 235 texImage[j*4+2] = color[2]; 236 texImage[j*4+3] = color[3]; 237 } 238 239 if (MipMap) { 240 GLint level = 0; 241 GLint w = TexWidth, h = TexHeight; 242 while (1) { 243 glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, w, h, 0, 244 GL_RGBA, GL_UNSIGNED_BYTE, texImage); 245 if (w == 1 && h == 1) 246 break; 247 if (w > 1) 248 w /= 2; 249 if (h > 1) 250 h /= 2; 251 level++; 252 /*printf("%d: %d x %d\n", level, w, h);*/ 253 } 254 if (LinearFilter) { 255 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 256 GL_LINEAR_MIPMAP_LINEAR); 257 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 258 } 259 else { 260 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 261 GL_NEAREST_MIPMAP_NEAREST); 262 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 263 } 264 } 265 else { 266 /* Set corners to white */ 267 int k = 0; 268 texImage[k+0] = texImage[k+1] = texImage[k+2] = texImage[k+3] = 255; 269 k = (TexWidth - 1) * 4; 270 texImage[k+0] = texImage[k+1] = texImage[k+2] = texImage[k+3] = 255; 271 k = (TexWidth * TexHeight - TexWidth) * 4; 272 texImage[k+0] = texImage[k+1] = texImage[k+2] = texImage[k+3] = 255; 273 k = (TexWidth * TexHeight - 1) * 4; 274 texImage[k+0] = texImage[k+1] = texImage[k+2] = texImage[k+3] = 255; 275 276 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TexWidth, TexHeight, 0, 277 GL_RGBA, GL_UNSIGNED_BYTE, texImage); 278 if (LinearFilter) { 279 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 280 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 281 } 282 else { 283 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 284 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 285 } 286 } 287 288 free(texImage); 289 } 290 291 glEnable(GL_TEXTURE_2D); 292} 293 294 295static void Key( unsigned char key, int x, int y ) 296{ 297 const GLfloat step = 3.0; 298 (void) x; 299 (void) y; 300 switch (key) { 301 case 'a': 302 Anim = !Anim; 303 if (Anim) 304 glutIdleFunc(Idle); 305 else 306 glutIdleFunc(NULL); 307 break; 308 case 's': 309 Idle(); 310 break; 311 case 'z': 312 Zrot -= step; 313 break; 314 case 'Z': 315 Zrot += step; 316 break; 317 case ' ': 318 DeleteTextures(); 319 Init(); 320 break; 321 case 27: 322 DeleteTextures(); 323 glutDestroyWindow(Win); 324 exit(0); 325 break; 326 } 327 glutPostRedisplay(); 328} 329 330 331int main( int argc, char *argv[] ) 332{ 333 GLint i; 334 335 glutInit( &argc, argv ); 336 glutInitWindowPosition( 0, 0 ); 337 glutInitWindowSize( WinWidth, WinHeight ); 338 glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE ); 339 Win = glutCreateWindow(argv[0]); 340 glewInit(); 341 glutReshapeFunc( Reshape ); 342 glutKeyboardFunc( Key ); 343 glutDisplayFunc( Display ); 344 if (Anim) 345 glutIdleFunc(Idle); 346 347 for (i = 1; i < argc; i++) { 348 if (strcmp(argv[i], "-n") == 0) { 349 NumTextures = atoi(argv[i+1]); 350 if (NumTextures <= 0) { 351 printf("Error, bad number of textures\n"); 352 return 1; 353 } 354 i++; 355 } 356 else if (strcmp(argv[i], "-mipmap") == 0) { 357 MipMap = GL_TRUE; 358 } 359 else if (strcmp(argv[i], "-linear") == 0) { 360 LinearFilter = GL_TRUE; 361 } 362 else if (strcmp(argv[i], "-size") == 0) { 363 TexWidth = atoi(argv[i+1]); 364 TexHeight = atoi(argv[i+2]); 365 assert(TexWidth >= 1); 366 assert(TexHeight >= 1); 367 i += 2; 368 } 369 else if (strcmp(argv[i], "-randomsize") == 0) { 370 RandomSize = GL_TRUE; 371 } 372 else if (strcmp(argv[i], "-lowpri") == 0) { 373 LowPriorityCount = atoi(argv[i+1]); 374 i++; 375 } 376 else { 377 printf("Usage:\n"); 378 printf(" manytex [options]\n"); 379 printf("Options:\n"); 380 printf(" -n <number of texture objects>\n"); 381 printf(" -size <width> <height> - specify texture size\n"); 382 printf(" -randomsize - use random size textures\n"); 383 printf(" -mipmap - generate mipmaps\n"); 384 printf(" -linear - use linear filtering instead of nearest\n"); 385 printf(" -lowpri <n> - Set lower priority on <n> textures\n"); 386 return 0; 387 } 388 } 389 390 Init(); 391 392 glutMainLoop(); 393 394 return 0; 395} 396