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