Widget Canvas "ID" for foreign handlers
Widget Canvas "ID" for foreign handlers
BTW I'm sorry to keep banging on about foreign handlers....but
I remember a while back that Kevin showed a video of a widget rendering pdfs using foreign handlers.
Is there an ID or context ID for each widget canvas you can pass to a foreign handler to "paint" on?
I am currently trialling a library to render dxf/dwg cad files. It's working after a fashion. I currently pass the windowid of the stack, get a device context for it and paint the dxf drawing. This paints the drawing directly to the client area of the window. Now, this is fine until we have other controls on the screen. Any other controls are wiped out by the foreign paint command. The drawing also dissapears occaisionally but that's a whole other problem.
If we could paint to the canvas of a widget it would help a lot with layering issues and I could paint the cad drawing during the OnPaint() handler as it is supposed to be done.
I remember a while back that Kevin showed a video of a widget rendering pdfs using foreign handlers.
Is there an ID or context ID for each widget canvas you can pass to a foreign handler to "paint" on?
I am currently trialling a library to render dxf/dwg cad files. It's working after a fashion. I currently pass the windowid of the stack, get a device context for it and paint the dxf drawing. This paints the drawing directly to the client area of the window. Now, this is fine until we have other controls on the screen. Any other controls are wiped out by the foreign paint command. The drawing also dissapears occaisionally but that's a whole other problem.
If we could paint to the canvas of a widget it would help a lot with layering issues and I could paint the cad drawing during the OnPaint() handler as it is supposed to be done.
Re: Widget Canvas "ID" for foreign handlers
@n.allan: Unfortunately things are a little more complicated then that.
LiveCode does not paint directly into the window on any platform. This is because the underlying graphics capabilities of every platform is significantly less than LiveCode needs. Instead, libgraphics does all the heavy lifting of rasterizing into an offscreen buffer, which then gets composited into the window.
The PDF example Kevin demonstrated used the CoreGraphics calls to paint into a buffer then composited that into LiveCode's canvas.
Do you have a link to the library you are trying to use so I can take a look at its API - there are a couple of options here and knowing what the API can do will help me suggest a reasonable approach.
LiveCode does not paint directly into the window on any platform. This is because the underlying graphics capabilities of every platform is significantly less than LiveCode needs. Instead, libgraphics does all the heavy lifting of rasterizing into an offscreen buffer, which then gets composited into the window.
The PDF example Kevin demonstrated used the CoreGraphics calls to paint into a buffer then composited that into LiveCode's canvas.
Do you have a link to the library you are trying to use so I can take a look at its API - there are a couple of options here and knowing what the API can do will help me suggest a reasonable approach.
Re: Widget Canvas "ID" for foreign handlers
I rather think I'm barkng up the wrong tree here then. The dll is closed source. I do have the api help file if it's any use but there is only one function which paint the dwg file to the device context. Looking at the c++ samples etc...It looks like this should be called in the windows ON_PAINT handler. but since we don't have access to that I had to hack my way through. There is nothing else in the api to render to a context.
Here is the main function in the api:-
The HOBJECT parameter is created by the dll internally when you load a drawing. I can get it no problem with a foreign handler.
The LPRECT parameter is created by a seperate dll I created in code::blocks in order for LCB to handle structs. The LPRECT members are set using foreign handlers to my own dll. Again no probs here.
The HDC parameter is created by calling GetDC( the windowid of this stack ) using a foreign handler to the Windows API.
My hopes were that I could create a compatible HDC for a widget and pass that along with the rect of the widget in order for the dll to paint to it.
I went back the books again and found imagePixmapID and pixmapID. Hoping I could render to an image box but it looks like they are no longer supported. They always return 0.
Here is the main function in the api:-
Code: Select all
The DrawCAD function draws the CADImage object on the specified device context.
Syntax:
int DrawCAD (
HANDLE hObject,
HDC hDC,
LPRECT lprc
);
Parameters:
hObject
Identifies the CADImage object handle.
hDC
Identifies the device context.
lprc
Points to the RECT structure that contains logical coordinates of the drawing rectangle.
The LPRECT parameter is created by a seperate dll I created in code::blocks in order for LCB to handle structs. The LPRECT members are set using foreign handlers to my own dll. Again no probs here.
The HDC parameter is created by calling GetDC( the windowid of this stack ) using a foreign handler to the Windows API.
My hopes were that I could create a compatible HDC for a widget and pass that along with the rect of the widget in order for the dll to paint to it.
I went back the books again and found imagePixmapID and pixmapID. Hoping I could render to an image box but it looks like they are no longer supported. They always return 0.
Re: Widget Canvas "ID" for foreign handlers
OK I just had a look through libgraphics src on git, There is a whole mess of stuff in context.cpp that looks interesting ( but over my head unfortunately ).
I see references to skBitmap objects and context creation. I'm hoping there is some way to create a compatible device context to pass to this CAD library (or any library for that matter )
Do we have access to these skBitmap objects in LCB?
I see references to skBitmap objects and context creation. I'm hoping there is some way to create a compatible device context to pass to this CAD library (or any library for that matter )
Do we have access to these skBitmap objects in LCB?
Re: Widget Canvas "ID" for foreign handlers
@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:
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!):
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):
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.
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
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;
}
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
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.
Re: Widget Canvas "ID" for foreign handlers
Muahhaha <attempts evil laugh>
I am definately getting something coming up in the widget. It's garbled so I might need to play with the ARGB order of the HBITMAP or it maybe a "rect" issue but still an awesome start!
@LCMark you have mad skils! I pretty much copied and pasted, fixed a couple compiler errors, tweaks and boom! What a genius you are!
I certainly was not expecting all that code and thanks yet again.
I did see a similar implementation to this in some of the Google chrome forums. It looks like they use skia for all the rendering too.
I am definately getting something coming up in the widget. It's garbled so I might need to play with the ARGB order of the HBITMAP or it maybe a "rect" issue but still an awesome start!
@LCMark you have mad skils! I pretty much copied and pasted, fixed a couple compiler errors, tweaks and boom! What a genius you are!
I certainly was not expecting all that code and thanks yet again.
I did see a similar implementation to this in some of the Google chrome forums. It looks like they use skia for all the rendering too.
Re: Widget Canvas "ID" for foreign handlers
I'm having trouble with this foreign handler from libfoundation:
Is this correct? Every time I call it it, livecode just quits. I looked up the source for MCDataCreateWithBytes on git but I am not really sure what the parameters are supposed to be.
What is the based type base type of MCDataRef& is. Is it a void* ?
I am passing the following parameters:
pBits is a void* from mark's c function above, pSize is the height * width of image *4, rData is a variable tImageData as Data
Code: Select all
foreign handler MCDataCreateWithBytes(in pBits as Pointer, in pSize as CUint, out rData as Data) returns CBool binds to "<builtin>"
What is the based type base type of MCDataRef& is. Is it a void* ?
I am passing the following parameters:
pBits is a void* from mark's c function above, pSize is the height * width of image *4, rData is a variable tImageData as Data
Re: Widget Canvas "ID" for foreign handlers
@n.allan: Could you paste the code you are using the MCDataCreateWithBytes function with so I can see the context?
The handler declaration looks correct... The only thing that would cause it to crash (I think) is if the pBits parameter did not point to pSize bytes of data. MCDataRef's are pointers, and 'out' parameters map to MCDataRef& (i.e. a reference) in C++.
The handler declaration looks correct... The only thing that would cause it to crash (I think) is if the pBits parameter did not point to pSize bytes of data. MCDataRef's are pointers, and 'out' parameters map to MCDataRef& (i.e. a reference) in C++.
Re: Widget Canvas "ID" for foreign handlers
I could have sworn I replied to this thread?
My "version control" is non existent and as a result I have lost the code for the MCCreateDataWithBytes function along with the c dll I was using at the time.
Anyway I have been away for a while and on return I noticed the new browser widget has a "native layer" handler.
Does native layer return the HWND of the widget (on windows obviously) Could we now grab the DC of this and draw to it?
My "version control" is non existent and as a result I have lost the code for the MCCreateDataWithBytes function along with the c dll I was using at the time.
Anyway I have been away for a while and on return I noticed the new browser widget has a "native layer" handler.
Does native layer return the HWND of the widget (on windows obviously) Could we now grab the DC of this and draw to it?