PDA

View Full Version : glReadPixels Weirdness



Jan
03-20-2006, 10:17 AM
Hi there

I have some code to take a screenshot. I use glReadPixels to get the data.

However, i use that piece of code for over 2 years now and used several drivers, etc. and since the first day there is one weird thing about it:

The data is randomly flipped about the horizontal or vertical axis!

Sometimes i need to flip the screenshot around the x-axis, sometimes around the y-axis, sometimes i need to rotate the image 180°. It seems to be completely non-deterministic. I don't change ANYTHING of the code, it seems to be decided at program-startup, how the driver flips the data around.

I use an ATI Radeon 9700.

So, i assume it is some setting, which i don't set, which affects how the data is transfered. Any ideas?

Thanks,
Jan.

jide
03-20-2006, 02:43 PM
Strange. Did you ensure all the ReadPixels have been fully processed before doing anything else ? (like calling glFinish).

Jan
03-20-2006, 05:10 PM
Hm, i put a glFinish right before and after glReadPixels and now it seems to always work as expected. Although i can't say for sure now, because this "bug" has a will of his own.

I will test it further and if it comes up again, i'll tell you. However, it seems as if this solved it.

Thanks,
Jan.

Ther
03-22-2006, 01:19 AM
this is my source for reading one pixel of the screen, but i am read the whole screen for it.

Maybe you can use it:
//---------------------------------

int Thervl :: getColorAt ( int x , int y ) {

//--------------------------------


int size = ( mwin ->getWidth () ) * ( mwin ->getHeight () );


glReadPixels (0,0,mwin ->getWidth (),mwin ->getHeight (),GL_RED,GL_UNSIGNED_BYTE,pixels);


return( int ) ( pixels [x + mwin ->getWidth () * ( mwin ->getHeight () - y )] );

return 0;

}

RigidBody
03-22-2006, 02:24 AM
congratulations for living for 2 years with the pain ;-)

can you show some code?

Jan
03-22-2006, 06:18 AM
I only "lived with the pain" because it didn't bother me very much :)
I simply had to rotate/flip some screenshots. And now i wanted to sort things out.

But well, if you want my code for taking a screenshot, here it is:


unsigned int uiViewPort[4];
glGetIntegerv (GL_VIEWPORT, (GLint*) uiViewPort);

uiViewPort[2] = GetResolutionX ();
uiViewPort[3] = GetResolutionY ();

int Width = uiViewPort[2];
int Height = uiViewPort[3];

unsigned char* Data = new unsigned char[Width * Height * 3];

glFinish (); // new!
glReadPixels (0, 0, Width, Height, GL_RGB, GL_UNSIGNED_BYTE, (void*) Data);
glFinish (); // also new!

FILESYSTEM* Fs = gp_FileSystem;
FILEDATA* File;

char path[256];
strcpy (path, Fs->GetProgramPath ().c_str ());

char filename[256] = "$SCREENSHOTS$/Screenshot0.tga";

int i = 1;
while (Fs->DoesFileExist (filename))
{
sprintf (filename, "$SCREENSHOTS$/Screenshot%d.tga", i);
i++;
}

gp_LogSystem->Log ("Saving Screenshot to: \"%s\".
\n", filename);

File = Fs->Open (filename, WRITE, 4096);

TGAHeader Header;
fastmemcpy (&Header, uTGAcompare, sizeof (TGAHeader));
Fs->Write (File, &Header, sizeof (TGAHeader));

TGA tga;
tga.header[1] = Width / 256;
tga.header[0] = Width % 256;
tga.header[3] = Height / 256;
tga.header[2] = Height % 256;
tga.header[4] = 24;

Fs->Write (File, &tga.header, sizeof (tga.header));

for (int y=0; y<Height; y++)
{
for (int x=0; x<Width; x++)
{
Fs->Write (File, &amp;Data[y*Width*3+x*3 + 2], sizeof (char));
Fs->Write (File, &amp;Data[y*Width*3+x*3 + 1], sizeof (char));
Fs->Write (File, &amp;Data[y*Width*3+x*3 + 0], sizeof (char));
}
}

Fs->Close (File);
delete[] Data;Have fun with it :D

Jan.

RigidBody
03-22-2006, 07:20 AM
pretty complicated :p

the beginning looks a bit strange: first, you use glGetInteger to get the viewport size. then you modify the viewport variable with GetResolution*, although it already contains the viewport size.

btw, it's not necessary to create the file byte by byte if you use GL_BGR in glReadPixels, like in the following example


void ScreenToTGA(int W, int H) {
FILE *out = fopen("screenshot.tga", "w");
short TGAhead[] = {0, 2, 0, 0, 0, 0, W, H, 24};
char pixel_data[3*W*H];

fwrite(&amp;TGAhead, sizeof(TGAhead), 1, out);
glReadBuffer(GL_FRONT);
glReadPixels(0, 0, W, H, GL_BGR, GL_UNSIGNED_BYTE, pixel_data);
fwrite(pixel_data, 3*W*H, 1, out);
fclose(out); }

Jan
03-22-2006, 08:50 AM
Uh, got me there! :D
Seems i first did it this way and then, after i had some new and shiny code, changed it to another way, but forgot to remove the redundancy.

Well, i admit, your code is shorter. And nicer. But mine got more love in it! :p

But maybe i use yours from now on.

I wish i had the time to do all the programming i like, right now :(
If you are so good, would you also like to write my medicine test for me?

Bye,
Jan.

RigidBody
03-22-2006, 09:08 AM
i'm not a doctor, but i think the correct answer to every question is: "take 2 aspirin and call me tomorrow"

:D