@n.allan: No you aren't banging up the wrong tree at all! The key thing here is that you need to create an HDC which is tied to a offscreen bitmap which you can get the pointer to the actually memory for the pixels. The engine has to do this on Windows to get the mask to render text, and to copy rendered controls into the Window.
Now, offscreen buffers in windows work by creating a 'bitmap object', then creating a 'compatible DC' for the bitmap, and then binding the bitmap to the DC. In pseudo-C:
Code: Select all
// Create a 'DIB Section' these are GDI bitmaps to which you can access the backing store directly.
// To to this you initialize a 'BITMAPINFO' structure, and use that to generate an HBITMAP, and
// a pointer to the pixels in memory.
HBITMAP t_rgb_bitmap;
void *t_rgb_data;
BITMAPINFO t_bitmapinfo;
memset(&t_bitmapinfo, 0, sizeof(BITMAPINFO));
t_bitmapinfo . bmiHeader . biSize = sizeof(BITMAPINFOHEADER);
t_bitmapinfo . bmiHeader . biCompression = BI_RGB;
t_bitmapinfo . bmiHeader . biWidth = p_bounds . width;
t_bitmapinfo . bmiHeader . biHeight = -p_bounds . height;
t_bitmapinfo . bmiHeader . biPlanes = 1;
t_bitmapinfo . bmiHeader . biBitCount = 32;
t_rgb_bitmap = CreateDIBSection(p_gdicontext, &t_bitmapinfo, DIB_RGB_COLORS, &t_rgb_data, NULL, 0);
// Create an offscreen DC
HDC t_offscreen_dc;
t_offscreen_dc = CreateCompatibleDC(NULL);
// Bind the bitmap into the DC
HDIOBJ t_old_bitmap;
t_old_bitmap = SelectObject(t_offscreen_dc, t_rgb_bitmap);
// Now paint into the bitmap
DrawCad(t_cad_image, t_offscreen_dc, &t_cad_rect);
// Unbind the bitmap from the DC
SelectObject(t_offscreen_dc, t_old_bitmap);
// At this point you have a GDI bitmap (t_rgb_bitmap) and a pointer to its backing store t_rgb_data
For getting this to work in LCB, I suggest you put a function like the following into your support dll (it could be done in pure LCB, but is a little fiddly at the moment!):
Code: Select all
bool Win32CreateOffscreenBitmap(int width, int height, HBITMAP *r_bitmap, void *r_bits)
{
HBITMAP t_rgb_bitmap;
t_rgb_bitmap = NULL;
void *t_rgb_data;
t_rgb_data = NULL;
BITMAPINFO t_bitmapinfo;
memset(&t_bitmapinfo, 0, sizeof(BITMAPINFO));
t_bitmapinfo . bmiHeader . biSize = sizeof(BITMAPINFOHEADER);
t_bitmapinfo . bmiHeader . biCompression = BI_RGB;
t_bitmapinfo . bmiHeader . biWidth = p_bounds . width;
t_bitmapinfo . bmiHeader . biHeight = -p_bounds . height;
t_bitmapinfo . bmiHeader . biPlanes = 1;
t_bitmapinfo . bmiHeader . biBitCount = 32;
t_rgb_bitmap = CreateDIBSection(p_gdicontext, &t_bitmapinfo, DIB_RGB_COLORS, &t_rgb_data, NULL, 0);
if (t_rgb_bitmap == NULL)
return false;
*r_bitmap = t_rgb_bitmap;
*r_bits = t_rgb_data;
}
So, with this, you should be able to do something along these lines (the foreign handler bind declarations need to be filled in, and there's no error checking):
Code: Select all
foreign handler Win32CreateOffscreenBitmap(in pWidth as CInt, in pHeight as CInt, out rBitmap as Pointer, our rBits as Pointer) returns bool binds to ...
foreign handler CreateCompatibleDC(in pTarget as optional Pointer) returns Pointer binds to ...
foreign handler SelectObject(in pObject as optional Pointer) returns optional Pointer binds to ...
foreign handler DeleteDC(in pTarget as Pointer) returns nothing binds to ...
foreign handler DeleteObject(in pTarget as Pointer) returns nothing binds to ...
foreign handler MCDataCreate(in pBits as Pointer, in pSize as CUInt, out rData as Data) binds to "<builtin>"
handler RenderCADAsImage(...) returns Image
variable tBitmap as Pointer
variable tBits as Pointer
Win32CreateOffscreenBitmap(<width>, <height>, tBitmap, tBits)
variable tDC as Pointer
put CreateCompatibleDC(nothing) into tDC
variable tOldObject
put SelectObject(tDC, tBitmap) into tOldObject
DrawCAD(<cad object>, tDC, <rect>)
SelectObject(tDC, tOldObject)
DeleteDC(tDC)
variable tImageData as Data
MCDataCreateWithBytes(tBits, <width> * <height> * 4, tImageData)
-- At this point we've copied the data, so don't need the bitmap anymore.
DeleteObject(tBitmap)
-- Create the image
variable tImage as Image
put image of size [ <width>, <height> ] with pixels tImageData into tImage
return tImage
end handler
The RenderCADAsImage() has some places to be filled in (i.e. the CAD object, and width and height), but it should return a Canvas Image object which you can then use to render things in the normal way.
This is slightly inefficient at the moment as the bitmap data is copied a couple of times. However, we should be able to add something to the canvas at some point which allows you to 'lock' a rect of it and return a pointer to the bits, or as a appropriate system object for binding into a DC.