/*
 * 'Texture leak' test
 *
 * Allocates and uses an additional texture of the maximum supported size for
 * each frame. This tests the system's ability to cope with using increasing
 * amounts of texture memory.
 *
 * Michel Dänzer  July 2009  This program is in the public domain.
 */


#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>
#include <GL/glew.h>
#include <GL/glut.h>


GLint size;
GLvoid *image;
static GLuint numTexObj;
static GLuint *texObj;


static void Idle( void )
{
   glutPostRedisplay();
}


static void DrawObject(void)
{
   static const GLfloat tex_coords[] = {  0.0,  0.0,  1.0,  1.0,  0.0 };
   static const GLfloat vtx_coords[] = { -1.0, -1.0,  1.0,  1.0, -1.0 };
   GLint i, j;

   glEnable(GL_TEXTURE_2D);

   for (i = 0; i < numTexObj; i++) {
      glBindTexture(GL_TEXTURE_2D, texObj[i]);
      glBegin(GL_QUADS);
      for (j = 0; j < 4; j++ ) {
         glTexCoord2f(tex_coords[j], tex_coords[j+1]);
         glVertex2f( vtx_coords[j], vtx_coords[j+1] );
      }
      glEnd();
   }
}


static void Display( void )
{
   struct timeval start, end;

   texObj = realloc(texObj, ++numTexObj * sizeof(*texObj));

   /* allocate a texture object */
   glGenTextures(1, texObj + (numTexObj - 1));

   glBindTexture(GL_TEXTURE_2D, texObj[numTexObj - 1]);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   memset(image, (16 * numTexObj) & 0xff, 4 * size * size);
   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0,
                GL_RGBA, GL_UNSIGNED_BYTE, image);

   gettimeofday(&start, NULL);

   glClear( GL_COLOR_BUFFER_BIT );

   glPushMatrix();
      glScalef(5.0, 5.0, 5.0);
      DrawObject();
   glPopMatrix();

   glutSwapBuffers();

   glFinish();
   gettimeofday(&end, NULL);
   printf("Rendering frame took %lu ms using %u MB of textures\n",
	  end.tv_sec * 1000 + end.tv_usec / 1000 - start.tv_sec * 1000 -
	  start.tv_usec / 1000, numTexObj * 4 * size / 1024 * size / 1024);

   sleep(1);
}


static void Reshape( int width, int height )
{
   glViewport( 0, 0, width, height );
   glMatrixMode( GL_PROJECTION );
   glLoadIdentity();
   glOrtho( -6.0, 6.0, -6.0, 6.0, 10.0, 100.0 );
   glMatrixMode( GL_MODELVIEW );
   glLoadIdentity();
   glTranslatef( 0.0, 0.0, -70.0 );
}


static void Init( int argc, char *argv[] )
{
   glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size);
   printf("%d x %d max texture size\n", size, size);

   image = malloc(4 * size * size);
   if (!image) {
      fprintf(stderr, "Failed to allocate %u bytes of memory\n", 4 * size * size);
      exit(1);
   }

   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

   glShadeModel(GL_FLAT);
   glClearColor(0.3, 0.3, 0.4, 1.0);

   Idle();
}


int main( int argc, char *argv[] )
{
   glutInit( &argc, argv );
   glutInitWindowSize( 300, 300 );
   glutInitWindowPosition( 0, 0 );
   glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
   glutCreateWindow(argv[0] );
   glewInit();

   Init( argc, argv );

   glutReshapeFunc( Reshape );
   glutDisplayFunc( Display );
   glutIdleFunc(Idle);

   glutMainLoop();
   return 0;
}