/* * test handling of many texture maps * Also tests texture priority and residency. * * Brian Paul * August 2, 2000 */ #include <assert.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <GL/glut.h> static GLint NumTextures = 20; static GLuint *TextureID = NULL; static GLint *TextureWidth = NULL, *TextureHeight = NULL; static GLboolean *TextureResidency = NULL; static GLint TexWidth = 128, TexHeight = 128; static GLfloat Zrot = 0; static GLboolean Anim = GL_TRUE; static GLint WinWidth = 500, WinHeight = 400; static GLboolean MipMap = GL_FALSE; static GLboolean LinearFilter = GL_FALSE; static GLboolean RandomSize = GL_FALSE; static GLint Rows, Columns; static GLint LowPriorityCount = 0; static void Idle( void ) { Zrot += 1.0; glutPostRedisplay(); } static void Display( void ) { GLfloat spacing = WinWidth / Columns; GLfloat size = spacing * 0.4; GLint i; /* test residency */ if (0) { GLboolean b; GLint i, resident; b = glAreTexturesResident(NumTextures, TextureID, TextureResidency); if (b) { printf("all resident\n"); } else { resident = 0; for (i = 0; i < NumTextures; i++) { if (TextureResidency[i]) { resident++; } } printf("%d of %d texture resident\n", resident, NumTextures); } } /* render the textured quads */ glClear( GL_COLOR_BUFFER_BIT ); for (i = 0; i < NumTextures; i++) { GLint row = i / Columns; GLint col = i % Columns; GLfloat x = col * spacing + spacing * 0.5; GLfloat y = row * spacing + spacing * 0.5; GLfloat maxDim = (TextureWidth[i] > TextureHeight[i]) ? TextureWidth[i] : TextureHeight[i]; GLfloat w = TextureWidth[i] / maxDim; GLfloat h = TextureHeight[i] / maxDim; glPushMatrix(); glTranslatef(x, y, 0.0); glRotatef(Zrot, 0, 0, 1); glScalef(size, size, 1); glBindTexture(GL_TEXTURE_2D, TextureID[i]); glBegin(GL_POLYGON); #if 0 glTexCoord2f(0, 0); glVertex2f(-1, -1); glTexCoord2f(1, 0); glVertex2f( 1, -1); glTexCoord2f(1, 1); glVertex2f( 1, 1); glTexCoord2f(0, 1); glVertex2f(-1, 1); #else glTexCoord2f(0, 0); glVertex2f(-w, -h); glTexCoord2f(1, 0); glVertex2f( w, -h); glTexCoord2f(1, 1); glVertex2f( w, h); glTexCoord2f(0, 1); glVertex2f(-w, h); #endif glEnd(); glPopMatrix(); } glutSwapBuffers(); } static void Reshape( int width, int height ) { WinWidth = width; WinHeight = height; glViewport( 0, 0, width, height ); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glOrtho(0, width, 0, height, -1, 1); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); } /* * Return a random int in [min, max]. */ static int RandomInt(int min, int max) { int i = rand(); int j = i % (max - min + 1); return min + j; } static void Init( void ) { GLint i; if (RandomSize) { printf("Creating %d %s random-size textures, ", NumTextures, MipMap ? "Mipmapped" : "non-Mipmapped"); } else { printf("Creating %d %s %d x %d textures, ", NumTextures, MipMap ? "Mipmapped" : "non-Mipmapped", TexWidth, TexHeight); } if (LinearFilter) { printf("bilinear filtering\n"); } else { printf("nearest filtering\n"); } /* compute number of rows and columns of rects */ { GLfloat area = (GLfloat) (WinWidth * WinHeight) / (GLfloat) NumTextures; GLfloat edgeLen = sqrt(area); Columns = WinWidth / edgeLen; Rows = (NumTextures + Columns - 1) / Columns; printf("Rows: %d Cols: %d\n", Rows, Columns); } if (!TextureID) { TextureID = (GLuint *) malloc(sizeof(GLuint) * NumTextures); assert(TextureID); glGenTextures(NumTextures, TextureID); } if (!TextureResidency) { TextureResidency = (GLboolean *) malloc(sizeof(GLboolean) * NumTextures); assert(TextureResidency); } if (!TextureWidth) { TextureWidth = (GLint *) malloc(sizeof(GLint) * NumTextures); assert(TextureWidth); } if (!TextureHeight) { TextureHeight = (GLint *) malloc(sizeof(GLint) * NumTextures); assert(TextureHeight); } for (i = 0; i < NumTextures; i++) { GLubyte color[4]; GLubyte *texImage; GLint j, row, col; row = i / Columns; col = i % Columns; glBindTexture(GL_TEXTURE_2D, TextureID[i]); if (i < LowPriorityCount) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, 0.5F); if (RandomSize) { #if 0 int k = (glutGet(GLUT_ELAPSED_TIME) % 7) + 2; TexWidth = 1 << k; TexHeight = 1 << k; #else TexWidth = 1 << RandomInt(2, 7); TexHeight = 1 << RandomInt(2, 7); printf("Random size of %3d: %d x %d\n", i, TexWidth, TexHeight); #endif } TextureWidth[i] = TexWidth; TextureHeight[i] = TexHeight; texImage = (GLubyte*) malloc(4 * TexWidth * TexHeight * sizeof(GLubyte)); assert(texImage); /* determine texture color */ color[0] = (GLint) (255.0 * ((float) col / (Columns - 1))); color[1] = 127; color[2] = (GLint) (255.0 * ((float) row / (Rows - 1))); color[3] = 255; /* fill in solid-colored teximage */ for (j = 0; j < TexWidth * TexHeight; j++) { texImage[j*4+0] = color[0]; texImage[j*4+1] = color[1]; texImage[j*4+2] = color[2]; texImage[j*4+3] = color[3]; } if (MipMap) { GLint level = 0; GLint w = TexWidth, h = TexHeight; while (1) { glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, texImage); if (w == 1 && h == 1) break; if (w > 1) w /= 2; if (h > 1) h /= 2; level++; /*printf("%d: %d x %d\n", level, w, h);*/ } if (LinearFilter) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); } } else { /* Set corners to white */ int k = 0; texImage[k+0] = texImage[k+1] = texImage[k+2] = texImage[k+3] = 255; k = (TexWidth - 1) * 4; texImage[k+0] = texImage[k+1] = texImage[k+2] = texImage[k+3] = 255; k = (TexWidth * TexHeight - TexWidth) * 4; texImage[k+0] = texImage[k+1] = texImage[k+2] = texImage[k+3] = 255; k = (TexWidth * TexHeight - 1) * 4; texImage[k+0] = texImage[k+1] = texImage[k+2] = texImage[k+3] = 255; glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TexWidth, TexHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, texImage); if (LinearFilter) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); } } free(texImage); } glEnable(GL_TEXTURE_2D); } static void Key( unsigned char key, int x, int y ) { const GLfloat step = 3.0; (void) x; (void) y; switch (key) { case 'a': Anim = !Anim; if (Anim) glutIdleFunc(Idle); else glutIdleFunc(NULL); break; case 's': Idle(); break; case 'z': Zrot -= step; break; case 'Z': Zrot += step; break; case ' ': Init(); break; case 27: exit(0); break; } glutPostRedisplay(); } int main( int argc, char *argv[] ) { GLint i; glutInit( &argc, argv ); glutInitWindowPosition( 0, 0 ); glutInitWindowSize( WinWidth, WinHeight ); glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE ); glutCreateWindow(argv[0]); glutReshapeFunc( Reshape ); glutKeyboardFunc( Key ); glutDisplayFunc( Display ); if (Anim) glutIdleFunc(Idle); for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-n") == 0) { NumTextures = atoi(argv[i+1]); if (NumTextures <= 0) { printf("Error, bad number of textures\n"); return 1; } i++; } else if (strcmp(argv[i], "-mipmap") == 0) { MipMap = GL_TRUE; } else if (strcmp(argv[i], "-linear") == 0) { LinearFilter = GL_TRUE; } else if (strcmp(argv[i], "-size") == 0) { TexWidth = atoi(argv[i+1]); TexHeight = atoi(argv[i+2]); assert(TexWidth >= 1); assert(TexHeight >= 1); i += 2; } else if (strcmp(argv[i], "-randomsize") == 0) { RandomSize = GL_TRUE; } else if (strcmp(argv[i], "-lowpri") == 0) { LowPriorityCount = atoi(argv[i+1]); i++; } else { printf("Usage:\n"); printf(" manytex [options]\n"); printf("Options:\n"); printf(" -n <number of texture objects>\n"); printf(" -size <width> <height> - specify texture size\n"); printf(" -randomsize - use random size textures\n"); printf(" -mipmap - generate mipmaps\n"); printf(" -linear - use linear filtering instead of nearest\n"); printf(" -lowpri <n> - Set lower priority on <n> textures\n"); return 0; } } Init(); glutMainLoop(); return 0; }