objarni's picture

Reading pixels from front buffer, example code?

Is there anyone that has done GL.ReadPixels() with OpenTK?

Preferrably I'd like to avoid unsafe sections.

Here's what I've got so far:

float[] rgb = new float[3];
GL.ReadPixels(0,0,1,1, PixelFormat.Rgb, PixelType.Float, ???);

.. where ??? means I don't know what to type ;)

(this is for alpha-blended texture testing .. I want to read out the pixel Red,Green,Blue values written by OpenGL to the colorbuffer!)


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture

Hey, doesn't this work?

float[] rgb = new float[3];
GL.ReadPixels(0,0,1,1, PixelFormat.Rgb, PixelType.Float, rgb);

Contrast with the GrabScreenshot method of the GLControl:

Bitmap bmp = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);
BitmapData data = bmp.LockBits(this.ClientRectangle, ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
 
GL.ReadPixels(0, 0, this.ClientSize.Width, this.ClientSize.Height, PixelFormat.Bgr, PixelType.UnsignedByte, data.Scan0);
 
bmp.UnlockBits(data);
bmp.RotateFlip(RotateFlipType.RotateNoneFlipY);
objarni's picture

I'm not by my dev.comp. now but - was there not only two overloads, one of which is IntPtr and the other *object, neither of which is float[]?

martinsm's picture

float[] is object. In .NET every class ir derived from special common "object" class.

hshutao's picture

i want to draw polygon with hole and pattern it with bitmap. how to do? thanks.
hshutao.

objarni's picture

@martinsm

Yes every class derives object.

But *object is something else - it's a pointer to an object.

the Fiddler's picture

The CLR does not allow pointers to managed objects (i.e. object*), because managed types may be relocated by the GC. OpenTK pins the arguments of object overloads, in order to obtain a pointer and pass that down to unmanaged code (obviously this is slow and, even worse, generates garbage).

These pins are only valid for the duration of the call, so take care if you are using client storage (e.g. old-style vertex arrays) or async methods. Fortunately most OpenGL and OpenAL methods, like BufferData or TexImage*, are blocking and finish before the pin is released.

The IntPtr overloads are there if you with to take control of this process: they are harder to use, but may be faster if you know what you are doing. For example, you may wish to allocate unmanaged memory with Marshal.AllocHGlobal to avoid long-term pinning (which impacts the GC heavily).

To cut a long story short, the proposed code should work fine, as long as:

  1. You don't access anything you shouldn't (i.e. pass float[3] and write 4 floats).
  2. You pass valuetypes or arrays of valuetypes.

In any other case results are undefined (and will probably, but not always, cause an AccessViolationException).

martinsm's picture
objarni wrote:

But *object is something else - it's a pointer to an object.

Oh, I though that asterix was a typo, because pointer would be object* from C++ point of view ;)

objarni's picture

@martinsm - Yes it was a typo - it is object* in C# too, I'm just not used to them at all ;)

@Fiddler - Thanks for your elaborative answer! Is this "object*"-argument-behaviour (that you can actually pass in arrays if the correct type, and OpenTK will sort out the rest) documented somewhere easily accessible (onsite)?

I consider the IntPtr-method even more advanced, maybe the IntelliSense should tell the OpenTK user to use object* if he does not know of HAlloc/Marshalling etc. My rule of thumb regarding these things - the basic way ("Red book way") should be easy to use, the advanced will always be advanced, nothing we can do about that.

the Fiddler's picture

These IntPtr overloads are more advanced, indeed. The good thing is that there is no obvious way to (mis-)use them, so they are relatively safe in the hands of a newbie. This leaves the object overload, which pretty much works as per "the Red book way".

I agree this should be in the handbook. However, even without documentation, I think the intent of the object overloads is pretty clear: you can pass anything.

Even the dangers I outlined are a) more or less self-evident and b) relatively unlikely to occur. Self-evident because you (should) know you may not access unallocated memory. Unlikely to occur because OpenGL works with floats, ints and combinations of these types (e.g. Vector3[]). If you try to pass a GraphicsContext to GL.TexImage2D, well, you'll get what you deserve.

If you have any ideas on how to make these overloads easier or safer to use, I'd like to hear them (other than documentation that is).

objarni's picture

Thanks for all help, it is working now.. And I don't know where I found the "object*"-idea .. It is just an object as last parameter to GL.ReadPixels()! Sorry for the confusion.

If you have any ideas on how to make these overloads easier or safer to use, I'd like to hear them (other than documentation that is).

Why wouldn't you want to document how OpenTK works..? I could do it if you like, no prob.

About making them simpler:

1. The name of the last parameter should be "array" in the object case, instead of "pixels". It tells the user what is expected.

2. Is it possible to make IntelliSense put the object overload as number 1 of 2 in the list, instead of 2 of 2? The first choice should be the simpler alternative.

3. An alternative to (2) would be to rename the IntPtr-overload something like GL.ReadPixelsRaw to indicate that this is a more "raw" or "lowlevel" method.

4. Another approach would be to provide different overloads for different types of array elements:

GL.ReadPixelsAsFloats(mousex, mousey, 1, 1, PixelFormat.Rgb, floatarray);
GL.ReadPixelsAsBytes(mousex, mousey, 1, 1, PixelFormat.Rgb, bytearray);
GL.ReadPixelsAsInts(mousex, mousey, 1, 1, PixelFormat.Rgb, intarray);

These could just call the more general GL.ReadPixels-method internally.