132001f49Smrg
232001f49Smrg/*
332001f49Smrg * glReadPixels and glCopyPixels test
432001f49Smrg *
532001f49Smrg * Brian Paul   March 1, 2000  This file is in the public domain.
632001f49Smrg */
732001f49Smrg
832001f49Smrg#include <assert.h>
932001f49Smrg#include <stdio.h>
1032001f49Smrg#include <stdlib.h>
1132001f49Smrg#include <math.h>
1232001f49Smrg#include <string.h>
1332001f49Smrg#include "glut_wrap.h"
1432001f49Smrg
1532001f49Smrg#include "readtex.h"
1632001f49Smrg
1732001f49Smrg#define IMAGE_FILE DEMOS_DATA_DIR "girl.rgb"
1832001f49Smrg
1932001f49Smrgstatic int ImgWidth, ImgHeight;
2032001f49Smrgstatic int WinWidth, WinHeight;
2132001f49Smrgstatic GLenum ImgFormat;
2232001f49Smrgstatic GLubyte *Image = NULL;
2332001f49Smrg
2432001f49Smrgstatic int APosX, APosY;  /* simple drawpixels */
2532001f49Smrgstatic int BPosX, BPosY;  /* read/draw pixels */
2632001f49Smrgstatic int CPosX, CPosY;  /* copypixels */
2732001f49Smrg
2832001f49Smrgstatic GLboolean DrawFront = GL_FALSE;
2932001f49Smrgstatic GLboolean ScaleAndBias = GL_FALSE;
3032001f49Smrgstatic GLboolean Benchmark = GL_FALSE;
3132001f49Smrgstatic GLboolean Triangle = GL_FALSE;
3232001f49Smrgstatic GLubyte *TempImage = NULL;
3332001f49Smrg
3432001f49Smrg#define COMBO 1
3532001f49Smrg#if COMBO == 0
3632001f49Smrg#define ReadFormat ImgFormat
3732001f49Smrg#define ReadType GL_UNSIGNED_BYTE
3832001f49Smrg#elif COMBO == 1
3932001f49Smrgstatic GLenum ReadFormat = GL_RGBA;
4032001f49Smrgstatic GLenum ReadType = GL_UNSIGNED_BYTE;
4132001f49Smrg#elif COMBO == 2
4232001f49Smrgstatic GLenum ReadFormat = GL_RGB;
4332001f49Smrgstatic GLenum ReadType = GL_UNSIGNED_BYTE;
4432001f49Smrg#elif COMBO == 3
4532001f49Smrgstatic GLenum ReadFormat = GL_RGB;
4632001f49Smrgstatic GLenum ReadType = GL_UNSIGNED_SHORT_5_6_5;
4732001f49Smrg#elif COMBO == 4
4832001f49Smrgstatic GLenum ReadFormat = GL_RGBA;
4932001f49Smrgstatic GLenum ReadType = GL_UNSIGNED_SHORT_1_5_5_5_REV;
5032001f49Smrg#elif COMBO == 5
5132001f49Smrgstatic GLenum ReadFormat = GL_BGRA;
5232001f49Smrgstatic GLenum ReadType = GL_UNSIGNED_SHORT_5_5_5_1;
5332001f49Smrg#elif COMBO == 6
5432001f49Smrgstatic GLenum ReadFormat = GL_BGRA;
5532001f49Smrgstatic GLenum ReadType = GL_UNSIGNED_SHORT_4_4_4_4_REV;
5632001f49Smrg#elif COMBO == 7
5732001f49Smrgstatic GLenum ReadFormat = GL_RGBA;
5832001f49Smrgstatic GLenum ReadType = GL_HALF_FLOAT_ARB;
5932001f49Smrg#undef GL_OES_read_format
6032001f49Smrg#endif
6132001f49Smrg
6232001f49Smrg
6332001f49Smrgstatic void
6432001f49SmrgReset( void )
6532001f49Smrg{
6632001f49Smrg   APosX = 5;     APosY = 20;
6732001f49Smrg   BPosX = APosX + ImgWidth + 5;   BPosY = 20;
6832001f49Smrg   CPosX = BPosX + ImgWidth + 5;   CPosY = 20;
6932001f49Smrg}
7032001f49Smrg
7132001f49Smrg
7232001f49Smrgstatic void
7332001f49SmrgPrintString(const char *s)
7432001f49Smrg{
7532001f49Smrg   while (*s) {
7632001f49Smrg      glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int) *s);
7732001f49Smrg      s++;
7832001f49Smrg   }
7932001f49Smrg}
8032001f49Smrg
8132001f49Smrg
8232001f49Smrgstatic void
8332001f49SmrgSetupPixelTransfer(GLboolean invert)
8432001f49Smrg{
8532001f49Smrg   if (invert) {
8632001f49Smrg      glPixelTransferf(GL_RED_SCALE, -1.0);
8732001f49Smrg      glPixelTransferf(GL_RED_BIAS, 1.0);
8832001f49Smrg      glPixelTransferf(GL_GREEN_SCALE, -1.0);
8932001f49Smrg      glPixelTransferf(GL_GREEN_BIAS, 1.0);
9032001f49Smrg      glPixelTransferf(GL_BLUE_SCALE, -1.0);
9132001f49Smrg      glPixelTransferf(GL_BLUE_BIAS, 1.0);
9232001f49Smrg   }
9332001f49Smrg   else {
9432001f49Smrg      glPixelTransferf(GL_RED_SCALE, 1.0);
9532001f49Smrg      glPixelTransferf(GL_RED_BIAS, 0.0);
9632001f49Smrg      glPixelTransferf(GL_GREEN_SCALE, 1.0);
9732001f49Smrg      glPixelTransferf(GL_GREEN_BIAS, 0.0);
9832001f49Smrg      glPixelTransferf(GL_BLUE_SCALE, 1.0);
9932001f49Smrg      glPixelTransferf(GL_BLUE_BIAS, 0.0);
10032001f49Smrg   }
10132001f49Smrg}
10232001f49Smrg
10332001f49Smrg
10432001f49Smrg/**
10532001f49Smrg * Exercise Pixel Pack parameters by reading the image in four pieces.
10632001f49Smrg */
10732001f49Smrgstatic void
10832001f49SmrgComplexReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
10932001f49Smrg                  GLenum format, GLenum type, GLvoid *pixels)
11032001f49Smrg{
11132001f49Smrg   const GLsizei width0 = width / 2;
11232001f49Smrg   const GLsizei width1 = width - width0;
11332001f49Smrg   const GLsizei height0 = height / 2;
11432001f49Smrg   const GLsizei height1 = height - height0;
11532001f49Smrg
11632001f49Smrg   glPixelStorei(GL_PACK_ROW_LENGTH, width);
11732001f49Smrg
11832001f49Smrg   /* lower-left quadrant */
11932001f49Smrg   glReadPixels(x, y, width0, height0, format, type, pixels);
12032001f49Smrg
12132001f49Smrg   /* lower-right quadrant */
12232001f49Smrg   glPixelStorei(GL_PACK_SKIP_PIXELS, width0);
12332001f49Smrg   glReadPixels(x + width0, y, width1, height0, format, type, pixels);
12432001f49Smrg
12532001f49Smrg   /* upper-left quadrant */
12632001f49Smrg   glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
12732001f49Smrg   glPixelStorei(GL_PACK_SKIP_ROWS, height0);
12832001f49Smrg   glReadPixels(x, y + height0, width0, height1, format, type, pixels);
12932001f49Smrg
13032001f49Smrg   /* upper-right quadrant */
13132001f49Smrg   glPixelStorei(GL_PACK_SKIP_PIXELS, width0);
13232001f49Smrg   glPixelStorei(GL_PACK_SKIP_ROWS, height0);
13332001f49Smrg   glReadPixels(x + width0, y + height0, width1, height1, format, type, pixels);
13432001f49Smrg
13532001f49Smrg   /* restore defaults */
13632001f49Smrg   glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
13732001f49Smrg   glPixelStorei(GL_PACK_SKIP_ROWS, 0);
13832001f49Smrg   glPixelStorei(GL_PACK_ROW_LENGTH, ImgWidth);
13932001f49Smrg}
14032001f49Smrg
14132001f49Smrg
14232001f49Smrg
14332001f49Smrgstatic void
14432001f49SmrgDisplay( void )
14532001f49Smrg{
14632001f49Smrg   glClearColor(.3, .3, .3, 1);
14732001f49Smrg   glClear( GL_COLOR_BUFFER_BIT );
14832001f49Smrg
14932001f49Smrg   glRasterPos2i(5, ImgHeight+25);
15032001f49Smrg   PrintString("f = toggle front/back  s = toggle scale/bias  b = benchmark");
15132001f49Smrg
15232001f49Smrg   /* draw original image */
15332001f49Smrg   glRasterPos2i(APosX, 5);
15432001f49Smrg   PrintString("Original");
15532001f49Smrg   if (!Triangle) {
15632001f49Smrg      glRasterPos2i(APosX, APosY);
15732001f49Smrg      glEnable(GL_DITHER);
15832001f49Smrg      SetupPixelTransfer(GL_FALSE);
15932001f49Smrg      glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
16032001f49Smrg      glDrawPixels(ImgWidth, ImgHeight, ImgFormat, GL_UNSIGNED_BYTE, Image);
16132001f49Smrg   }
16232001f49Smrg   else {
16332001f49Smrg      float z = 0;
16432001f49Smrg
16532001f49Smrg      glViewport(APosX, APosY, ImgWidth, ImgHeight);
16632001f49Smrg      glMatrixMode( GL_PROJECTION );
16732001f49Smrg      glLoadIdentity();
16832001f49Smrg      glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
16932001f49Smrg      glDisable(GL_CULL_FACE);
17032001f49Smrg
17132001f49Smrg      /* Red should never be seen
17232001f49Smrg       */
17332001f49Smrg      glBegin(GL_POLYGON);
17432001f49Smrg      glColor3f(1,0,0);
17532001f49Smrg      glVertex3f(-2, -2, z);
17632001f49Smrg      glVertex3f(-2, 2, z);
17732001f49Smrg      glVertex3f(2, 2, z);
17832001f49Smrg      glVertex3f(2, -2, z);
17932001f49Smrg      glEnd();
18032001f49Smrg
18132001f49Smrg      /* Blue background
18232001f49Smrg       */
18332001f49Smrg      glBegin(GL_POLYGON);
18432001f49Smrg      glColor3f(.5,.5,1);
18532001f49Smrg      glVertex3f(-1, -1, z);
18632001f49Smrg      glVertex3f(-1, 1, z);
18732001f49Smrg      glVertex3f(1, 1, z);
18832001f49Smrg      glVertex3f(1, -1, z);
18932001f49Smrg      glEnd();
19032001f49Smrg
19132001f49Smrg      /* Triangle
19232001f49Smrg       */
19332001f49Smrg      glBegin(GL_TRIANGLES);
19432001f49Smrg      glColor3f(.8,0,0);
19532001f49Smrg      glVertex3f(-0.9, -0.9, z);
19632001f49Smrg      glColor3f(0,.9,0);
19732001f49Smrg      glVertex3f( 0.9, -0.9, z);
19832001f49Smrg      glColor3f(0,0,.7);
19932001f49Smrg      glVertex3f( 0.0,  0.9, z);
20032001f49Smrg      glEnd();
20132001f49Smrg
20232001f49Smrg      glColor3f(1,1,1);
20332001f49Smrg
20432001f49Smrg      glViewport( 0, 0, WinWidth, WinHeight );
20532001f49Smrg      glMatrixMode( GL_PROJECTION );
20632001f49Smrg      glLoadIdentity();
20732001f49Smrg      glOrtho( 0.0, WinWidth, 0.0, WinHeight, -1.0, 1.0 );
20832001f49Smrg   }
20932001f49Smrg
21032001f49Smrg   /* might try alignment=4 here for testing */
21132001f49Smrg   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
21232001f49Smrg   glPixelStorei(GL_PACK_ALIGNMENT, 1);
21332001f49Smrg
21432001f49Smrg   /* do readpixels, drawpixels */
21532001f49Smrg   glRasterPos2i(BPosX, 5);
21632001f49Smrg   PrintString("Read/DrawPixels");
21732001f49Smrg   SetupPixelTransfer(ScaleAndBias);
21832001f49Smrg   if (Benchmark) {
21932001f49Smrg      GLint reads = 0;
22032001f49Smrg      GLint endTime;
22132001f49Smrg      GLint startTime = glutGet(GLUT_ELAPSED_TIME);
22232001f49Smrg      GLdouble seconds, mpixels, mpixelsPerSecond;
22332001f49Smrg      printf("Benchmarking...\n");
22432001f49Smrg      do {
22532001f49Smrg         glReadPixels(APosX, APosY, ImgWidth, ImgHeight,
22632001f49Smrg                      ReadFormat, ReadType, TempImage);
22732001f49Smrg         reads++;
22832001f49Smrg         endTime = glutGet(GLUT_ELAPSED_TIME);
22932001f49Smrg      } while (endTime - startTime < 4000);   /* 4 seconds */
23032001f49Smrg      seconds = (double) (endTime - startTime) / 1000.0;
23132001f49Smrg      mpixels = reads * (ImgWidth * ImgHeight / (1000.0 * 1000.0));
23232001f49Smrg      mpixelsPerSecond = mpixels / seconds;
23332001f49Smrg      printf("Result:  %d reads in %f seconds = %f Mpixels/sec\n",
23432001f49Smrg             reads, seconds, mpixelsPerSecond);
23532001f49Smrg      Benchmark = GL_FALSE;
23632001f49Smrg   }
23732001f49Smrg   else {
23832001f49Smrg      /* clear the temporary image to white (helpful for debugging */
23932001f49Smrg      memset(TempImage, 255, ImgWidth * ImgHeight * 4);
24032001f49Smrg#if 1
24132001f49Smrg      glReadPixels(APosX, APosY, ImgWidth, ImgHeight,
24232001f49Smrg                   ReadFormat, ReadType, TempImage);
24332001f49Smrg      (void) ComplexReadPixels;
24432001f49Smrg#else
24532001f49Smrg      /* you might use this when debugging */
24632001f49Smrg      ComplexReadPixels(APosX, APosY, ImgWidth, ImgHeight,
24732001f49Smrg                        ReadFormat, ReadType, TempImage);
24832001f49Smrg#endif
24932001f49Smrg   }
25032001f49Smrg   glRasterPos2i(BPosX, BPosY);
25132001f49Smrg   glDisable(GL_DITHER);
25232001f49Smrg   SetupPixelTransfer(GL_FALSE);
25332001f49Smrg   glDrawPixels(ImgWidth, ImgHeight, ReadFormat, ReadType, TempImage);
25432001f49Smrg
25532001f49Smrg   /* do copypixels */
25632001f49Smrg   glRasterPos2i(CPosX, 5);
25732001f49Smrg   PrintString("CopyPixels");
25832001f49Smrg   glRasterPos2i(CPosX, CPosY);
25932001f49Smrg   glDisable(GL_DITHER);
26032001f49Smrg   SetupPixelTransfer(ScaleAndBias);
26132001f49Smrg   glCopyPixels(APosX, APosY, ImgWidth, ImgHeight, GL_COLOR);
26232001f49Smrg
26332001f49Smrg   if (!DrawFront)
26432001f49Smrg      glutSwapBuffers();
26532001f49Smrg   else
26632001f49Smrg      glFinish();
26732001f49Smrg}
26832001f49Smrg
26932001f49Smrg
27032001f49Smrgstatic void
27132001f49SmrgReshape( int width, int height )
27232001f49Smrg{
27332001f49Smrg   WinWidth = width;
27432001f49Smrg   WinHeight = height;
27532001f49Smrg
27632001f49Smrg   glViewport( 0, 0, width, height );
27732001f49Smrg   glMatrixMode( GL_PROJECTION );
27832001f49Smrg   glLoadIdentity();
27932001f49Smrg   glOrtho( 0.0, width, 0.0, height, -1.0, 1.0 );
28032001f49Smrg   glMatrixMode( GL_MODELVIEW );
28132001f49Smrg   glLoadIdentity();
28232001f49Smrg}
28332001f49Smrg
28432001f49Smrg
28532001f49Smrgstatic void
28632001f49SmrgKey( unsigned char key, int x, int y )
28732001f49Smrg{
28832001f49Smrg   (void) x;
28932001f49Smrg   (void) y;
29032001f49Smrg   switch (key) {
29132001f49Smrg      case 'b':
29232001f49Smrg         Benchmark = GL_TRUE;
29332001f49Smrg         break;
29432001f49Smrg      case 't':
29532001f49Smrg         Triangle = !Triangle;
29632001f49Smrg         break;
29732001f49Smrg      case 's':
29832001f49Smrg         ScaleAndBias = !ScaleAndBias;
29932001f49Smrg         break;
30032001f49Smrg      case 'f':
30132001f49Smrg         DrawFront = !DrawFront;
30232001f49Smrg         if (DrawFront) {
30332001f49Smrg            glDrawBuffer(GL_FRONT);
30432001f49Smrg            glReadBuffer(GL_FRONT);
30532001f49Smrg         }
30632001f49Smrg         else {
30732001f49Smrg            glDrawBuffer(GL_BACK);
30832001f49Smrg            glReadBuffer(GL_BACK);
30932001f49Smrg         }
31032001f49Smrg         printf("glDrawBuffer(%s)\n", DrawFront ? "GL_FRONT" : "GL_BACK");
31132001f49Smrg         break;
31232001f49Smrg      case 27:
31332001f49Smrg         exit(0);
31432001f49Smrg         break;
31532001f49Smrg   }
31632001f49Smrg   glutPostRedisplay();
31732001f49Smrg}
31832001f49Smrg
31932001f49Smrg
32032001f49Smrgstatic void
32132001f49SmrgInit( GLboolean ciMode )
32232001f49Smrg{
32332001f49Smrg   GLboolean have_read_format = GL_FALSE;
32432001f49Smrg
32532001f49Smrg   printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
32632001f49Smrg   printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
32732001f49Smrg
32832001f49Smrg   Image = LoadRGBImage( IMAGE_FILE, &ImgWidth, &ImgHeight, &ImgFormat );
32932001f49Smrg   if (!Image) {
33032001f49Smrg      printf("Couldn't read %s\n", IMAGE_FILE);
33132001f49Smrg      exit(0);
33232001f49Smrg   }
33332001f49Smrg
33432001f49Smrg   if (ciMode) {
33532001f49Smrg      /* Convert RGB image to grayscale */
33632001f49Smrg      GLubyte *indexImage = (GLubyte *) malloc( ImgWidth * ImgHeight );
33732001f49Smrg      GLint i;
33832001f49Smrg      for (i=0; i<ImgWidth*ImgHeight; i++) {
33932001f49Smrg         int gray = Image[i*3] + Image[i*3+1] + Image[i*3+2];
34032001f49Smrg         indexImage[i] = gray / 3;
34132001f49Smrg      }
34232001f49Smrg      free(Image);
34332001f49Smrg      Image = indexImage;
34432001f49Smrg      ImgFormat = GL_COLOR_INDEX;
34532001f49Smrg
34632001f49Smrg      for (i=0;i<255;i++) {
34732001f49Smrg         float g = i / 255.0;
34832001f49Smrg         glutSetColor(i, g, g, g);
34932001f49Smrg      }
35032001f49Smrg   }
35132001f49Smrg
35232001f49Smrg#ifdef GL_OES_read_format
35332001f49Smrg   if ( glutExtensionSupported( "GL_OES_read_format" ) ) {
35432001f49Smrg      glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES,   (GLint *) &ReadType);
35532001f49Smrg      glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES, (GLint *) &ReadFormat);
35632001f49Smrg
35732001f49Smrg      have_read_format = GL_TRUE;
35832001f49Smrg   }
35932001f49Smrg#endif
36032001f49Smrg
36132001f49Smrg   printf( "GL_OES_read_format %ssupported.  "
36232001f49Smrg	   "Using type / format = 0x%04x / 0x%04x\n",
36332001f49Smrg	   (have_read_format) ? "" : "not ",
36432001f49Smrg	   ReadType, ReadFormat );
36532001f49Smrg
36632001f49Smrg   printf("Loaded %d by %d image\n", ImgWidth, ImgHeight );
36732001f49Smrg
36832001f49Smrg   glPixelStorei(GL_UNPACK_ROW_LENGTH, ImgWidth);
36932001f49Smrg   glPixelStorei(GL_PACK_ROW_LENGTH, ImgWidth);
37032001f49Smrg
37132001f49Smrg   Reset();
37232001f49Smrg
37332001f49Smrg   /* allocate large TempImage to store and image data type, plus an
37432001f49Smrg    * extra 1KB in case we're tinkering with pack alignment.
37532001f49Smrg    */
37632001f49Smrg   TempImage = (GLubyte *) malloc(ImgWidth * ImgHeight * 4 * 4
37732001f49Smrg                                  + 1000);
37832001f49Smrg   assert(TempImage);
37932001f49Smrg}
38032001f49Smrg
38132001f49Smrg
38232001f49Smrgint
38332001f49Smrgmain( int argc, char *argv[] )
38432001f49Smrg{
38532001f49Smrg   GLboolean ciMode = GL_FALSE;
38632001f49Smrg   glutInitWindowSize( 750, 250 );
38732001f49Smrg   glutInit( &argc, argv );
38832001f49Smrg   if (argc > 1 && strcmp(argv[1], "-ci")==0) {
38932001f49Smrg      ciMode = GL_TRUE;
39032001f49Smrg   }
39132001f49Smrg   if (ciMode)
39232001f49Smrg      glutInitDisplayMode( GLUT_INDEX | GLUT_DOUBLE );
39332001f49Smrg   else
39432001f49Smrg      glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
39532001f49Smrg   glutCreateWindow(argv[0]);
39632001f49Smrg   Init(ciMode);
39732001f49Smrg   glutReshapeFunc( Reshape );
39832001f49Smrg   glutKeyboardFunc( Key );
39932001f49Smrg   glutDisplayFunc( Display );
40032001f49Smrg   glutMainLoop();
40132001f49Smrg   return 0;
40232001f49Smrg}
403