The MASM Forum

General => The Workshop => Topic started by: jj2007 on January 08, 2016, 07:16:13 AM

Title: Problem with GdiPlus and GdipCreateCustomLineCap
Post by: jj2007 on January 08, 2016, 07:16:13 AM
I am using
invoke GdipCreateCustomLineCap, 0, gdiPath, LineCapFlat, 0, addr custCap
invoke GdipSetCustomLineCapStrokeCaps, custCap, LineCapTriangle, LineCapRound

in the WM_CREATE handler, then, in the WM_PAINT handler:
      invGdip GdipSetPenEndCap, pPen, LineCapArrowAnchor
      invGdip GdipDrawLineI, gdiDC, pPen, 20, 100, 400, 180
     
      invGdip GdipSetPenCustomEndCap, pPen, custCap      ; PB example (http://www.powerbasic.com/support/pbforums/showthread.php?t=49981)
      invGdip GdipDrawLineI, gdiDC, pPen, 20, 120, 400, 200


The first one works fine, the custom cap doesn't - it just draws the start point but no line and no end point. All GdiPlus calls return S_OK. The PB example uses cloning, but 1. I see no reason why and 2. same result :(

Any ideas? Full code attached, as plain Masm32.
Title: Re: Problem with GdiPlus and GdipCreateCustomLineCap
Post by: guga on January 08, 2016, 08:14:48 AM
Maybe this can help ?

http://www.jose.it-berater.org/smfforum/index.php?topic=1980.0
Title: Re: Problem with GdiPlus and GdipCreateCustomLineCap
Post by: qWord on January 08, 2016, 08:28:26 AM
PointF != POINT
Title: Re: Problem with GdiPlus and GdipCreateCustomLineCap
Post by: jj2007 on January 08, 2016, 11:37:40 AM
Quote from: guga on January 08, 2016, 08:14:48 AM
Maybe this can help ?

http://www.jose.it-berater.org/smfforum/index.php?topic=1980.0

Thanks, Gustavo - José Roca is indeed my main source of inspiration, when it comes to Gdi+ ;)

But the real problem (pun intended) was on another José Roca page (http://www.jose.it-berater.org/smfforum/index.php?topic=1835.0) in the C++ example:
   //Create a Path, and add two lines to it.
   Point points[3] = {Point(-15, -15), Point(0, 0), Point(15, -15)};


Looks like an array of integers, but...

Quote from: qWord on January 08, 2016, 08:28:26 AM
PointF != POINT

Thanks, qWord :t
Title: Re: Problem with GdiPlus and GdipCreateCustomLineCap
Post by: mabdelouahab on January 08, 2016, 05:58:35 PM

.DATA
_ccPts REAL4 -15.0 , -15.0
REAL4 0.0 , 0.0
REAL4 15.0 , -15.0
Title: Re: Problem with GdiPlus and GdipCreateCustomLineCap
Post by: jj2007 on January 08, 2016, 07:04:25 PM
Thanks, mabdelouahab. It works fine now:

invGdip GdipAddPathPolygon, gdiPath, addr ccPts, (sizeof ccPts)/PointF
(invGdip is a macro that works like invoke but checks ret values in debug mode, and displays a text error if eax!=S_OK)

Now I am fighting with:
wm_create:
invGdip GdipCreateSolidFill, RgbCol(255, 0, 255, 255), addr pSolidBrush
...
wm_paint:
  invGdip GdipFillPath, gdiDC, pSolidBrush, custCap
  invGdip GdipSetPenCustomEndCap, pPen, custCap


Works fine to fill a rectangle in the WM_PAINT handler, but I would like to fill the endcap triangle; and that doesn't work, invGdip barks GdipFillPath: ObjectBusy :(
Title: Re: Problem with GdiPlus and GdipCreateCustomLineCap
Post by: qWord on January 09, 2016, 12:36:58 AM
First make sure that the path passed to CustomLineCap-Constructor is closed (GdipClosePathFigure(s)).
To get filled shapes, pass the path as first constructor argument and set the stroke-path to zero.
For custom arrows there is also the special class AdjustableArrowCap, which is derived from CustomLineCap.

Tip: take a look into the Gdiplus headers coming with the windows SDK. The class definitions shows how to use the flat API, e.g. which parameters are optional.
Title: Re: Problem with GdiPlus and GdipCreateCustomLineCap
Post by: jj2007 on January 09, 2016, 01:16:29 AM
Quote from: qWord on January 09, 2016, 12:36:58 AM
First make sure that the path passed to CustomLineCap-Constructor is closed (GdipClosePathFigure(s)).
To get filled shapes, pass the path as first constructor argument and set the stroke-path to zero.
For custom arrows there is also the special class AdjustableArrowCap, which is derived from CustomLineCap.

Thanks, qWord. I had already discovered AdjustableArrowCap, and it works fine, see lower array below:
invGdip GdipCreateAdjustableArrowCap, FP4(6.0), FP4(5.0), TRUE, addr custCapFilled
Re path as first constructor argument, that gives me "not implemented" for some reason (very unlikely, so the reason is elsewhere). With GdipAddPathPolygon, it works but the result looks odd, see second image below.
Title: Re: Problem with GdiPlus and GdipCreateCustomLineCap
Post by: qWord on January 09, 2016, 02:46:30 AM
I currently can't find any documentation how the cap-coordinates are handled, but a quick test shows that everything above the x-axes is clipped away. The line comes from -Infinity along the y-axes and ends in the origin (0,0). With the function GdipSetCustomLineCapBaseInset you can set the line end to whatever negative y-coordinate to make room for the cap. Otherwise, as in your case, the line and the cap interferes.

Code ("jwasm") Select
mov ccPts[0*PointF].x, -15.0
mov ccPts[0*PointF].y, -15.0
mov ccPts[1*PointF].x, 0
mov ccPts[1*PointF].y, 0
mov ccPts[2*PointF].x, 15.0
mov ccPts[2*PointF].y, -15.0

invoke GdipCreatePath, FillModeAlternate, addr gdiPath
invoke GdipAddPathLine2, gdiPath, addr ccPts, 3
invoke GdipClosePathFigure,gdiPath

invoke GdipCreateCustomLineCap, 0, gdiPath, LineCapFlat, 0, addr custCap
invoke GdipCreateCustomLineCap, gdiPath, 0, LineCapFlat, 0, addr custCap0

invoke GdipCreatePen1, 0ffffff00h, FP4(5.0), UnitWorld, addr pPen

; make room for cap
invoke GdipSetCustomLineCapBaseInset,custCap, FP4(15.0)
invoke GdipSetCustomLineCapBaseInset,custCap0, FP4(15.0)

; fill
invoke GdipSetPenCustomStartCap,pPen, custCap0
invoke GdipSetPenCustomEndCap, pPen, custCap0
invoke GdipDrawLineI, gdiDC, pPen, 20, 120, 400, 200

invoke GdipSetPenColor,pPen,0ffff0000h

; outline
invoke GdipSetPenCustomStartCap,pPen, custCap
invoke GdipSetPenCustomEndCap, pPen, custCap
invoke GdipDrawLineI, gdiDC, pPen, 20, 120, 400, 200
Title: Re: Problem with GdiPlus and GdipCreateCustomLineCap
Post by: jj2007 on January 09, 2016, 04:16:00 AM
Thanks, qWord :t
Title: Re: Problem with GdiPlus and GdipCreateCustomLineCap
Post by: guga on January 10, 2016, 09:43:49 AM
I remember seeing a wrapper for GDIPlus in plain C that seems to be documented. I´ll look in my files and see if i can find it for you guys.
Title: Re: Problem with GdiPlus and GdipCreateCustomLineCap
Post by: guga on January 10, 2016, 11:16:21 AM
Found it

https://github.com/mono/libgdiplus

https://github.com/mono/libgdiplus/blob/master/src/customlinecap.c

Indeed, they some parameters are pointer to floats


static GpStatus gdip_custom_linecap_setup (GpGraphics *graphics, GpCustomLineCap *cap);
static GpStatus gdip_custom_linecap_clone_cap (GpCustomLineCap *cap, GpCustomLineCap **clonedCap);
static GpStatus gdip_custom_linecap_destroy (GpCustomLineCap *cap);
static GpStatus gdip_custom_linecap_draw (GpGraphics *graphics, GpPen *pen, GpCustomLineCap *cap, float x, float y, float otherend_x, float otherend_y);

GpStatus
GdipGetCustomLineCapBaseInset (GpCustomLineCap *customCap, float *inset)
{
if (!customCap || !inset)
return InvalidParameter;

*(inset) = customCap->base_inset;

return Ok;
}