Using OpenGL to draw directly to a .NET Bitmap

2019-07-18 11:45发布

问题:

I'd like to use OpenGL to draw directly to a .NET System::Drawing::Bitmap (C++/CLI). It seems like it should work like this:

char buf[48];
ZeroMemory( &buf, sizeof(buf));
System::Drawing::Bitmap bmp(
    4,
    4,
    12,
    Imaging::PixelFormat::Format24bppRgb,
    (System::IntPtr)buf);
Graphics^ g = Graphics::FromImage(%bmp);
HDC local_hdc = (HDC)((void*)g->GetHdc());
HGLRC local_hrc = wglCreateContext( local_hdc );
if(!wglMakeCurrent( local_hdc, local_hrc ))
    ShowError();

//Draw something with OpenGL ...

g->ReleaseHdc((IntPtr)((void*)local_hdc));

//Do something with the bitmap ...

But wglMakeCurrent fails with "The pixel format is invalid".

"Of course!" I think. "I just need to set the pixel format of the bitmap in such a way that OpenGL can render to it!"

Sadly, if I use the above Bitmap constructor, I'm limited to an enum of canned pixelformats, rather than a struct holding a bunch of attributes that I can OR together. And I don't think it's possible to set the pixel format after the fact.

Anyway, this way of doing things would be prettier than using a bunch of Win32 calls to make a Device-Independent Bitmap, but the canned pixel formats seem to omit any sort of GL-enabled anything, and I just fail. Can you succeed?

回答1:

You probably don't want to draw directly into your buffer anyway, you'd lose all hardware acceleration which is the advantage of OpenGL to begin with. Instead:

  • Set up an OpenGL context as usual, using video RAM.
  • Draw into it, fully accelerated.
  • Create a Bitmap.
  • Call Bitmap::LockBits to get the pointer to the raw pixel memory.
  • Use glCopyImage to read the results from video RAM into the Bitmap.

The PixelFormat passed to LockBits and glCopyImage in the last two steps need to match of course.