GDI+ Gdip_FillRoundedRectangle() weird artifacts Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
theimmersion
Posts: 181
Joined: 09 Jul 2016, 08:34
Location: Serbia

GDI+ Gdip_FillRoundedRectangle() weird artifacts

28 Mar 2018, 08:42

For some reason, Gdip_FillRoundedRectangle() creates weird artifacts when bevel level goes beyond a certain number.
For instance, width and height of 100x100 with bevel (or roundness) being 34 and up will start showing artifacts.
Im using a slider from 0% to 100%. I really need that but cant find a substitute or workaround nor a reason why it does that.
GIF.gif
GIF.gif (176 KiB) Viewed 6710 times
The code is huge but i tried to take out and edit a bit what i think is the relevant part i hope.

Code: Select all

	pButtonDetectorBrush := Gdip_BrushCreateSolid(0x9100ff00)
	GuiButtonWidth := 100
	GuiButtonHeight := 100
	BevelPercent := 85
	if (GuiButtonWidth > GuiButtonHeight)
		ButtonDetectorBevel := ((GuiButtonHeight/2)/100)*BevelPercent
	else if (GuiButtonWidth < GuiButtonHeight)
		ButtonDetectorBevel := ((GuiButtonWidth/2)/100)*BevelPercent
	else
		ButtonDetectorBevel := ((GuiButtonHeight/2)/100)*BevelPercent
	Gdip_FillRoundedRectangle(G, pButtonDetectorBrush, 0, 0, GuiButtonWidth, GuiButtonHeight, ButtonDetectorBevel)
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: GDI+ Gdip_FillRoundedRectangle() weird artifacts

28 Mar 2018, 09:53

I can confirm the weird behaviour of Gdip_FillRoundedRectangle. But for me, the cut-off point is 50/100. Which makes sense, since otherwise we have twice the bevel is greater than width/height, or, the center point of the quarter-circle to be drawn lies no more inside the quadrant. So maybe its some weird calculation that you do in code not shown, the code posted looks fine to me.
User avatar
theimmersion
Posts: 181
Joined: 09 Jul 2016, 08:34
Location: Serbia

Re: GDI+ Gdip_FillRoundedRectangle() weird artifacts

28 Mar 2018, 09:58

Exactly, i expected those artifacts at 51+ of a 100x100 size but it starts at 34+. Ill snoop around the code see if i goofed something and post my find.
So, you get the proper bevel at 0-50? No artifacts and a perfect circle?

EDIT
Well, i placed a tooltip at bottom and i get the proper numbers as far as im aware. I get 100x100 pixel size with 42 pixel bevel (roundness) when slider is at 84 bevel percent.
:headwall:
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: GDI+ Gdip_FillRoundedRectangle() weird artifacts

28 Mar 2018, 10:23

I tested some more. And I have found weirdness here too: Gdip_FillRoundedRectangle(pGraphic, pBrush, 200, 300, 150, 150, 70)
where 70 is small enough!! Weird indeed, I have no idea why, just confirming for Win10 64x, AHK x64 1.1.28.
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: GDI+ Gdip_FillRoundedRectangle() weird artifacts

28 Mar 2018, 10:27

To answer you question: I did get a perfect circle at first look. 0r so I believed at the time.
Now that I look again and closer, I don't get it at all. the transparency must have confused me. It looks like 4 transparent circles got drawn!!!
User avatar
theimmersion
Posts: 181
Joined: 09 Jul 2016, 08:34
Location: Serbia

Re: GDI+ Gdip_FillRoundedRectangle() weird artifacts

28 Mar 2018, 10:29

Must be something in the function itself and its calculus/matrix or how its called.

Code: Select all

Gdip_FillRoundedRectangle(pGraphics, pBrush, x, y, w, h, r)
{
	Region := Gdip_GetClipRegion(pGraphics)
	Gdip_SetClipRect(pGraphics, x-r, y-r, 2*r, 2*r, 4)
	Gdip_SetClipRect(pGraphics, x+w-r, y-r, 2*r, 2*r, 4)
	Gdip_SetClipRect(pGraphics, x-r, y+h-r, 2*r, 2*r, 4)
	Gdip_SetClipRect(pGraphics, x+w-r, y+h-r, 2*r, 2*r, 4)
	E := Gdip_FillRectangle(pGraphics, pBrush, x, y, w, h)
	Gdip_SetClipRegion(pGraphics, Region, 0)
	Gdip_SetClipRect(pGraphics, x-(2*r), y+r, w+(4*r), h-(2*r), 4)
	Gdip_SetClipRect(pGraphics, x+r, y-(2*r), w-(2*r), h+(4*r), 4)
	Gdip_FillEllipse(pGraphics, pBrush, x, y, 2*r, 2*r)
	Gdip_FillEllipse(pGraphics, pBrush, x+w-(2*r), y, 2*r, 2*r)
	Gdip_FillEllipse(pGraphics, pBrush, x, y+h-(2*r), 2*r, 2*r)
	Gdip_FillEllipse(pGraphics, pBrush, x+w-(2*r), y+h-(2*r), 2*r, 2*r)
	Gdip_SetClipRegion(pGraphics, Region, 0)
	Gdip_DeleteRegion(Region)
	return E
}
I guess something here is up that needs an update? I am in no way good enough to even touch this. xD
Any math genius appreciated here! :crazy:
User avatar
theimmersion
Posts: 181
Joined: 09 Jul 2016, 08:34
Location: Serbia

Re: GDI+ Gdip_FillRoundedRectangle() weird artifacts

28 Mar 2018, 10:34

Also, Gdip_DrawRoundedRectangle() has the same issues as Gdip_FillRoundedRectangle().
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: GDI+ Gdip_FillRoundedRectangle() weird artifacts

28 Mar 2018, 11:17

Looking at the code, it is not readily obvious, but when I run the following test, I could see that the function can only support a radius up to 1/3 of the width, not 1/2 as we both first thought.
What I did in the script: visualize the clipping rects, to enable that, go in the code and uncomment up to 6 extra drawn rects. (#1..4 are boring, #5 and #6 are interesting). A bit confusing at first but I saw where the support for r>w/3 breaks down, because the circle is sticking out the wrong end of the clipping rect when r>h/3.

Code: Select all

#NoEnv
#SingleInstance, Force
OnExit, Bye
pToken := Gdip_Startup()

    Gui, New, +hwndhGui +E0x80000
    Gui, Show, NoActivate
    hBM := CreateDIBSection(A_ScreenWidth, A_ScreenHeight)
    hDC := CreateCompatibleDC()
    oBM := SelectObject(hDC, hBM)
    pGraphics := Gdip_GraphicsFromHDC(hDC)
    Gosub, Draw
    UpdateLayeredWindow(hGui, hDC, 0, 0, A_ScreenWidth, A_ScreenHeight)

Return

GuiClose:
GuiEscape:
ExitApp

F5:: Reload



;-------------------------------------------------------------------------------
Bye:
;-------------------------------------------------------------------------------
    Gdip_DeleteGraphics(pGraphics)
    SelectObject(hDC, oBM)
    DeleteObject(hBM)
    DeleteDC(hDC)
    Gdip_Shutdown(pToken)

ExitApp



;-------------------------------------------------------------------------------
Draw:
;-------------------------------------------------------------------------------
    pBrush := Gdip_BrushCreateSolid(0x80008000)
    Gdip_Fill_RoundedRectangle(pGraphics, pBrush, 200, 300, 100, 100, 40)
    Gdip_DeleteBrush(pBrush)

Return



Gdip_Fill_RoundedRectangle(pGraphics, pBrush, x, y, w, h, r)
{
	Region := Gdip_GetClipRegion(pGraphics)

	;~ Gdip_FillRectangle(pGraphics, pBrush, x-r, y-r, 2*r, 2*r)
	;~ Gdip_FillRectangle(pGraphics, pBrush, x+w-r, y-r, 2*r, 2*r)
	;~ Gdip_FillRectangle(pGraphics, pBrush, x-r, y+h-r, 2*r, 2*r)
	;~ Gdip_FillRectangle(pGraphics, pBrush, x+w-r, y+h-r, 2*r, 2*r)

	Gdip_SetClipRect(pGraphics, x-r, y-r, 2*r, 2*r, 4)
	Gdip_SetClipRect(pGraphics, x+w-r, y-r, 2*r, 2*r, 4)
	Gdip_SetClipRect(pGraphics, x-r, y+h-r, 2*r, 2*r, 4)
	Gdip_SetClipRect(pGraphics, x+w-r, y+h-r, 2*r, 2*r, 4)
	E := Gdip_FillRectangle(pGraphics, pBrush, x, y, w, h)

	Gdip_SetClipRegion(pGraphics, Region, 0)
	Gdip_DeleteRegion(Region)

	;~ Gdip_FillRectangle(pGraphics, pBrush, x+r, y-(2*r), w-(2*r), h+(4*r))
	;~ Gdip_FillRectangle(pGraphics, pBrush, x-(2*r), y+r, w+(4*r), h-(2*r))

	Gdip_SetClipRect(pGraphics, x-(2*r), y+r, w+(4*r), h-(2*r), 4)
	Gdip_SetClipRect(pGraphics, x+r, y-(2*r), w-(2*r), h+(4*r), 4)

	Gdip_FillEllipse(pGraphics, pBrush, x, y, 2*r, 2*r)
	Gdip_FillEllipse(pGraphics, pBrush, x+w-(2*r), y, 2*r, 2*r)
	Gdip_FillEllipse(pGraphics, pBrush, x, y+h-(2*r), 2*r, 2*r)
	Gdip_FillEllipse(pGraphics, pBrush, x+w-(2*r), y+h-(2*r), 2*r, 2*r)

	Gdip_SetClipRegion(pGraphics, Region, 0)
	Gdip_DeleteRegion(Region)

	return E
}
Thanks for bringing this up. :thumbup:
User avatar
theimmersion
Posts: 181
Joined: 09 Jul 2016, 08:34
Location: Serbia

Re: GDI+ Gdip_FillRoundedRectangle() weird artifacts

28 Mar 2018, 11:54

Can this be changed to support 1/2 radius and the GDI lib updated?
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: GDI+ Gdip_FillRoundedRectangle() weird artifacts

28 Mar 2018, 12:06

Yes, I believe it can be changed.
I'm about to fall asleep now.

Tomorrow, if there is no solution by then, I will have a go at this.
User avatar
theimmersion
Posts: 181
Joined: 09 Jul 2016, 08:34
Location: Serbia

Re: GDI+ Gdip_FillRoundedRectangle() weird artifacts

28 Mar 2018, 12:14

Thanks! Good night. :)
just me
Posts: 9439
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: GDI+ Gdip_FillRoundedRectangle() weird artifacts  Topic is solved

28 Mar 2018, 13:07

You might want to try this version:

Code: Select all

;#####################################################################################
; Function           Gdip_FillRoundedRectangle
; Description        This function uses a brush to fill a rounded rectangle in the Graphics of a bitmap
;
; pGraphics          Pointer to the Graphics of a bitmap
; pBrush             Pointer to a brush
; x                  x-coordinate of the top left of the rounded rectangle
; y                  y-coordinate of the top left of the rounded rectangle
; w                  width of the rectanlge
; h                  height of the rectangle
; r                  radius of the rounded corners
;
; return             status enumeration. 0 = success
Gdip_FillRoundedRectanglePath(pGraphics, pBrush, X, Y, W, H, R) {
   ; Create a GraphicsPath
   DllCall("Gdiplus.dll\GdipCreatePath", "UInt", 0, "PtrP", pPath)
   ; Create a rounded rectabgle
   D := (R * 2), W -= D, H -= D
   DllCall("Gdiplus.dll\GdipAddPathArc", "Ptr", pPath, "Float", X, "Float", Y, "Float", D, "Float", D, "Float", 180, "Float", 90)
   DllCall("Gdiplus.dll\GdipAddPathArc", "Ptr", pPath, "Float", X + W, "Float", Y, "Float", D, "Float", D, "Float", 270, "Float", 90)
   DllCall("Gdiplus.dll\GdipAddPathArc", "Ptr", pPath, "Float", X + W, "Float", Y + H, "Float", D, "Float", D, "Float", 0, "Float", 90)
   DllCall("Gdiplus.dll\GdipAddPathArc", "Ptr", pPath, "Float", X, "Float", Y + H, "Float", D, "Float", D, "Float", 90, "Float", 90)
   DllCall("Gdiplus.dll\GdipClosePathFigure", "Ptr", pPath)
   ; Fill the path
   RS := DllCall("Gdiplus.dll\GdipFillPath", "Ptr", pGraphics, "Ptr", pBrush, "Ptr", pPath)
   ; Free resources
   DllCall("Gdiplus.dll\GdipDeletePath", "Ptr", pPath)
   Return RS
}
User avatar
theimmersion
Posts: 181
Joined: 09 Jul 2016, 08:34
Location: Serbia

Re: GDI+ Gdip_FillRoundedRectangle() weird artifacts

28 Mar 2018, 13:41

My sister confiscated the laptop. Will try later or tomorrow. Thanks just me. :)
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: GDI+ Gdip_FillRoundedRectangle() weird artifacts

28 Mar 2018, 14:26

Try this:

Code: Select all



;-------------------------------------------------------------------------------
Gdip_FillRoundedRectangle2(pGraphics, pBrush, x, y, w, h, r) {
;-------------------------------------------------------------------------------
	Gdip_SetClipRect(pGraphics, x, y, r, r, 4)
	Gdip_SetClipRect(pGraphics, x+w-r, y, r, r, 4)
	Gdip_SetClipRect(pGraphics, x, y+h-r, r, r, 4)
	Gdip_SetClipRect(pGraphics, x+w-r, y+h-r, r, r, 4)
	Gdip_FillRectangle(pGraphics, pBrush, x, y, w, h)
    Gdip_ResetClip(pGraphics)
	Gdip_SetClipRect(pGraphics, x, y+r, 2*r, r, 4)
	Gdip_SetClipRect(pGraphics, x+r, y, r, r, 4)
	Gdip_FillEllipse(pGraphics, pBrush, x, y, 2*r, 2*r)
    Gdip_ResetClip(pGraphics)
	Gdip_SetClipRect(pGraphics, x+w-2*r, y+r, 2*r, r, 4)
	Gdip_SetClipRect(pGraphics, x+w-2*r, y, r, r, 4)
	Gdip_FillEllipse(pGraphics, pBrush, x+w-(2*r), y, 2*r, 2*r)
    Gdip_ResetClip(pGraphics)
	Gdip_SetClipRect(pGraphics, x, y+h-2*r, 2*r, r, 4)
	Gdip_SetClipRect(pGraphics, x+r, y+h-r, r, r, 4)
	Gdip_FillEllipse(pGraphics, pBrush, x, y+h-2*r, 2*r, 2*r)
    Gdip_ResetClip(pGraphics)
	Gdip_SetClipRect(pGraphics, x+w-(2*r), y+h-2*r, 2*r, r, 4)
	Gdip_SetClipRect(pGraphics, x+w-(2*r), y+h-r, r, r, 4)
	Gdip_FillEllipse(pGraphics, pBrush, x+w-(2*r), y+h-(2*r), 2*r, 2*r)
    Gdip_ResetClip(pGraphics)
}
Never mind, I'll check out just me's code. Thx :thumbup:
User avatar
theimmersion
Posts: 181
Joined: 09 Jul 2016, 08:34
Location: Serbia

Re: GDI+ Gdip_FillRoundedRectangle() weird artifacts

29 Mar 2018, 06:40

Well, just me's code works wonderfully. wolf_II, your function kinda also works nicely but creates some different artifacts as well.
It creates one pixel lines on either bottom-[left/right] depending on the W vs H vs R values.
GIF.gif
GIF.gif (19.48 KiB) Viewed 6603 times
But except that, the outer rim is perfect. So ill go with just me's solution.

@just me, is this your personal edited function?
So i can add to the function comment its from you to keep track of things.

Thank you both for continuous help!
just me
Posts: 9439
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: GDI+ Gdip_FillRoundedRectangle() weird artifacts

29 Mar 2018, 08:27

Hi theimmerson,

I created the function from the code of my Class_Imagebutton. I found a code snippet using this method anywhere in the web and implemented it in the class some time ago.

License: The Unlicense. ;)

Do what you want to do.
User avatar
theimmersion
Posts: 181
Joined: 09 Jul 2016, 08:34
Location: Serbia

Re: GDI+ Gdip_FillRoundedRectangle() weird artifacts

29 Mar 2018, 09:03

Btw, do you by any chance have a proper Gdip_DrawRoundedRectangle() function as well? It has the same exact issues. Im using it to create a black line around an image and the outer border in case some image has same colors like the border. xD
GIF.gif
GIF.gif (259.53 KiB) Viewed 6588 times
As you can see, the border (grey) using your function works perfectly.
just me
Posts: 9439
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: GDI+ Gdip_FillRoundedRectangle() weird artifacts

29 Mar 2018, 09:18

You might try this untested function:

Code: Select all

Gdip_DrawRoundedRectanglePath(pGraphics, pPen, X, Y, W, H, R) {
   ; Create a GraphicsPath
   DllCall("Gdiplus.dll\GdipCreatePath", "UInt", 0, "PtrP", pPath)
   ; Create a rounded rectabgle
   D := (R * 2), W -= D, H -= D
   DllCall("Gdiplus.dll\GdipAddPathArc", "Ptr", pPath, "Float", X, "Float", Y, "Float", D, "Float", D, "Float", 180, "Float", 90)
   DllCall("Gdiplus.dll\GdipAddPathArc", "Ptr", pPath, "Float", X + W, "Float", Y, "Float", D, "Float", D, "Float", 270, "Float", 90)
   DllCall("Gdiplus.dll\GdipAddPathArc", "Ptr", pPath, "Float", X + W, "Float", Y + H, "Float", D, "Float", D, "Float", 0, "Float", 90)
   DllCall("Gdiplus.dll\GdipAddPathArc", "Ptr", pPath, "Float", X, "Float", Y + H, "Float", D, "Float", D, "Float", 90, "Float", 90)
   DllCall("Gdiplus.dll\GdipClosePathFigure", "Ptr", pPath)
   ; Draw the path
   RS := DllCall("Gdiplus.dll\GdipDrawPath", "Ptr", pGraphics, "Ptr", pPen, "Ptr", pPath)
   ; Free resources
   DllCall("Gdiplus.dll\GdipDeletePath", "Ptr", pPath)
   Return RS
}

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Google [Bot], QrJuicy and 75 guests