Help fix the code

Just starting out? Need help? Post your questions and find answers here.
Everything
Enthusiast
Enthusiast
Posts: 224
Joined: Sat Jul 07, 2018 6:50 pm

Help fix the code

Post by Everything »

For educational purposes, I decided to try to rewrite some PB vector drawing code on a GDI+ Flat API
And there are several problems, first of all it's a very unpopular theme, and I could not find detailed descriptions and nuances of using the interface so most things is intuitively research.
My first attempt ended in a very strange result: (code itself is pretty small, most part is interface declarations)

Code: Select all

; *Minimal working example*
; All error handling removed for better code readability (no errors btw)
; Drawing on the window output again for better code readability (simplify the code, we anyway see the result and that's enough here)

EnableExplicit

;{ GDI+ }

Enumeration ; CompositingMode
  #CompositingModeSourceOver = 0 
  #CompositingModeSourceCopy = 1
EndEnumeration

Enumeration ; QualityMode
  #QualityModeInvalid   = -1
  #QualityModeDefault   =  0
  #QualityModeLow       =  1 
  #QualityModeHigh      =  2  
EndEnumeration

Enumeration ; CompositingQuality
  #CompositingQualityInvalid          = #QualityModeInvalid
  #CompositingQualityDefault          = #QualityModeDefault
  #CompositingQualityHighSpeed        = #QualityModeLow
  #CompositingQualityHighQuality      = #QualityModeHigh
  #CompositingQualityGammaCorrected
  #CompositingQualityAssumeLinear
EndEnumeration

Enumeration ; SmoothingMode
  #SmoothingModeInvalid     = #QualityModeInvalid
  #SmoothingModeDefault     = #QualityModeDefault
  #SmoothingModeHighSpeed   = #QualityModeLow
  #SmoothingModeHighQuality = #QualityModeHigh
  #SmoothingModeNone
  #SmoothingModeAntiAlias
  ;#if (GDIPVER >= 0x0110)
  #SmoothingModeAntiAlias8x4 = #SmoothingModeAntiAlias
  #SmoothingModeAntiAlias8x8
  ;#endif //(GDIPVER >= 0x0110) 
EndEnumeration

Enumeration ; InterpolationMode
  #InterpolationModeInvalid          = #QualityModeInvalid
  #InterpolationModeDefault          = #QualityModeDefault
  #InterpolationModeLowQuality       = #QualityModeLow
  #InterpolationModeHighQuality      = #QualityModeHigh
  #InterpolationModeBilinear
  #InterpolationModeBicubic
  #InterpolationModeNearestNeighbor
  #InterpolationModeHighQualityBilinear
  #InterpolationModeHighQualityBicubic
EndEnumeration

Structure GdiplusStartupInput
    GdiPlusVersion.l
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x64 
    PB_Alignment.b[4]
  CompilerEndIf
    *DebugEventCallback.DebugEventProc
    SuppressBackgroundThread.i
    SuppressExternalCodecs.i
EndStructure

Structure GdiplusStartupOutput
    *NotificationHook.NotificationHookProc
    *NotificationUnhook.NotificationUnhookProc
EndStructure


Structure gdi_internal
  graphics.i
  initialized.b
  gdiplusToken.i
  drawingMode.l
  currentDC.i
  lineCapStart.i
  lineCapEnd.i
  lineCapStartScale.f
  lineCapEndScale.f
  currentPen.i
  currentBrush.i
  currentPenColor.l
  currentPenColor2.l
  currentPenPattern.l
  currentPenSize.f
  currentPenAlignment.i
  currentPenBrushStyle.i
  currentPenStyle.i
  currentPenImage.i
  currentPenImageWrapMode.i
  currentPenLineJoin.l
  currentPenMiterLimit.f
  currentPath.i
  currentFont.i
  currentTextAntialiasingMode.l
  drawTextFlags.l
  transformMatrix.i
EndStructure : Global gdi.gdi_internal

;{ Func list }
Macro GDIFuncList
  GdiplusStartup_.l(*token, *input.GdiplusStartupInput, *output.GdiplusStartupOutput)  As "GdiplusStartup"
  GdiplusShutdown_(token.i) As "GdiplusShutdown"
  GdipCreateFromHDC_.l(*hDC, *graphics) As "GdipCreateFromHDC"
  GdipDeleteGraphics_.l(*graphics) As "GdipDeleteGraphics"
  GdipCreatePath_.l(fillMode.l, *path) As "GdipCreatePath"
  GdipCreateSolidFill_.l(color.l, *brush) As "GdipCreateSolidFill"
  GdipDeleteBrush_.l(*brush) As "GdipDeleteBrush"
  GdipDeletePath_.l(path.i) As "GdipDeletePath"
  GdipFillPath_.l(*graphics, *brush, path.i) As "GdipFillPath"
  GdipAddPathLine_.l(*path, x1.f, y1.f, x2.f, y2.f) As "GdipAddPathLine"
  GdipSetSmoothingMode_.l(*graphics, smoothingMode.l) As "GdipSetSmoothingMode"
  GdipSetCompositingMode_.l(*graphics, compositingMode.l) As "GdipSetCompositingMode"
  GdipSetCompositingQuality_.l(*graphics, compositingQuality.l) As "GdipSetCompositingQuality"
  GdipSetInterpolationMode_.l(*graphics, interpolationMode.l) As "GdipSetInterpolationMode"   
  GdipCreateMatrix_.l(*matrix) As "GdipCreateMatrix"
  GdipDeleteMatrix_.l(matrix.i) As "GdipDeleteMatrix"
  GdipTranslateMatrix_.l(matrix.i, offsetX.f, offsetY.f, order) As "GdipTranslateMatrix"
  GdipSetWorldTransform_.l(*graphics, matrix.i) As "GdipSetWorldTransform" 
  ;GdipStartPathFigure_.l(*path) As "GdipStartPathFigure"
EndMacro  
;}

CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
  Import "x:\gdiplus_x64.lib"
    GDIFuncList
  EndImport   
CompilerElse
  Import "x:\gdiplus_x86.lib"
    GDIFuncList
  EndImport   
CompilerEndIf
;}

Procedure iGdiplusStartup()
  ; Initialize GDI+.
  Protected gdiplusStartupInput.GdiplusStartupInput
  gdiplusStartupInput\GdiplusVersion              = 1 
  gdiplusStartupInput\DebugEventCallback          = #Null
  gdiplusStartupInput\SuppressBackgroundThread    = #False
  gdiplusStartupInput\SuppressExternalCodecs      = #True
  If Not GdiplusStartup_(@gdi\gdiplusToken, @gdiplusStartupInput, #Null) 
    gdi\initialized = #True
  Else
    ProcedureReturn #False
  EndIf
  ProcedureReturn #True 
EndProcedure

Procedure gdi()
  
  Protected *hDC = GetDC_(WindowID(0))
  
  gdi\currentDC = *hDC
  GdipCreateFromHDC_(gdi\currentDC ,@gdi\graphics)
  gdi\drawingMode                 = #PB_2DDrawing_Default
  gdi\lineCapStartScale           = 2.0
  gdi\lineCapEndScale             = 2.0 
  GdipCreateMatrix_(@gdi\transformMatrix) 
  GdipCreatePath_(1, @gdi\currentPath) 
  GdipSetSmoothingMode_     (gdi\graphics, #SmoothingModeAntiAlias) 
  GdipSetCompositingMode_   (gdi\graphics, #CompositingModeSourceOver) 
  GdipSetCompositingQuality_(gdi\graphics, #CompositingQualityGammaCorrected) 
  GdipSetInterpolationMode_ (gdi\graphics, #InterpolationModeHighQualityBicubic)  
  GdipTranslateMatrix_(gdi\transformMatrix , 20, 0, 0)  ;Set Origin 20, 0
  GdipSetWorldTransform_(gdi\graphics, gdi\transformMatrix ) 
  ;GdipStartPathFigure_(gdi\currentPath)
  GdipAddPathLine_(gdi\currentPath, 9.9, 0, 5.5, 4.4) 
  GdipAddPathLine_(gdi\currentPath, 1.1, 0,   0, 1.1) 
  GdipAddPathLine_(gdi\currentPath, 4.4,4.4,  0, 9.9) 
  GdipAddPathLine_(gdi\currentPath, 1.1, 11,  4.4,4.4) 
  GdipAddPathLine_(gdi\currentPath, 9.9, 11,  11, 9.9) 
  GdipAddPathLine_(gdi\currentPath, 6.6,5.5,  11,1.1) 
  GdipCreateSolidFill_($FFFF0000, @gdi\currentBrush)
  GdipFillPath_(gdi\graphics, gdi\currentBrush, gdi\currentPath) 
  GdipDeleteBrush_(gdi\currentBrush) 
  GdipDeleteGraphics_(gdi\graphics)  
  GdipDeleteMatrix_(gdi\transformMatrix)
  GdipDeletePath_(gdi\currentPath)
  
  ReleaseDC_(WindowID(0), *hDC) 
EndProcedure

Procedure PB()  
  If StartVectorDrawing(WindowVectorOutput(0, #PB_Unit_Pixel))
    AddPathSegments("M11,1.1 L9.9,0L5.5,4.4L1.1,0L0,1.1l4.4,4.4L0,9.9L1.1,11l4.4-4.4L9.9,11L11,9.9L6.6,5.5L11,1.1z")
    VectorSourceColor(RGBA(255, 0, 0, 255))
    FillPath()
    StopVectorDrawing()
  EndIf
EndProcedure

If OpenWindow(0, 0, 0, 80, 30, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  If iGdiplusStartup() : gdi() : EndIf  
  PB()
  Repeat
    Define Event = WaitWindowEvent()
  Until Event = #PB_Event_CloseWindow
EndIf
; GdiplusShutdown_(gdi\gdiplusToken)
Image
First icon is PB vector drawing, second one is flat API.

What is wrong with this code and why?

P.S. gdilib (if you don't have one)
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8433
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Help fix the code

Post by netmaestro »

You don't need to supply your own gdiplus libs as PureBasic ships with those included in x86 and x64 versions. This is necessary because the Vector Drawing lib in PB maps gdiplus commands. So:

Code: Select all

Import "gdiplus.lib"
is all the code you need for that.

As to the differences in the quality of the output, I suspect revisiting the number values you are passing to GdipAddPathLine would yield the desired result.
BERESHEIT
infratec
Always Here
Always Here
Posts: 6874
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Help fix the code

Post by infratec »

Code: Select all

Import "gdiplus.lib"
  GdiplusStartup.l(*token, *input.GdiplusStartupInput, *output.GdiplusStartupOutput)
  GdiplusShutdown(token.i)
  GdipCreateFromHDC.l(*hDC, *graphics)
  GdipDeleteGraphics.l(*graphics)
  GdipCreatePath.l(fillMode.l, *path)
  GdipCreateSolidFill.l(color.l, *brush)
  GdipDeleteBrush.l(*brush)
  GdipDeletePath.l(path.i)
  GdipFillPath.l(*graphics, *brush, path.i)
  GdipAddPathLine.l(*path, x1.f, y1.f, x2.f, y2.f)
  GdipSetSmoothingMode.l(*graphics, smoothingMode.l)
  GdipSetCompositingMode.l(*graphics, compositingMode.l)
  GdipSetCompositingQuality.l(*graphics, compositingQuality.l)
  GdipSetInterpolationMode.l(*graphics, interpolationMode.l)
  GdipCreateMatrix.l(*matrix)
  GdipDeleteMatrix.l(matrix.i)
  GdipTranslateMatrix.l(matrix.i, offsetX.f, offsetY.f, order)
  GdipSetWorldTransform.l(*graphics, matrix.i)
  GdipStartPathFigure.l(*path)
  GdipCreatePen1(color.l, width.f, unit.l, *pen)
EndImport
I think you need to create a brush or a pen.
Everything
Enthusiast
Enthusiast
Posts: 224
Joined: Sat Jul 07, 2018 6:50 pm

Re: Help fix the code

Post by Everything »

netmaestro wrote: I suspect revisiting the number values you are passing to GdipAddPathLine would yield the desired result.
Right.
I looked at the values in the debugger (when PB call GdipAddPathLine from AddPathSegments wrapper) and they are different from used one.

AddPathSegments("M11,1.1 L9.9,0 L5.5,4.4 L1.1,0 L0,1.1 l4.4,4.4 L0,9.9 L1.1,11 l4.4-4.4 L9.9,11 L11,9.9 L6.6,5.5 L11,1.1z")

in GdipAddPathLine we can use original values except highlighted
4.4,4.4 becomes 4.4,5.5
4.4,4.4 becomes 5.5,6.6

that's fix the code, unfortunately I don't understand yet how to calc right values...

By the way, I noticed that the letter "L" is lowercase for mismatched values (it's svg path originally) I think it is mean something.
Everything
Enthusiast
Enthusiast
Posts: 224
Joined: Sat Jul 07, 2018 6:50 pm

Re: Help fix the code

Post by Everything »

infratec wrote: I noticed that the letter "L" is lowercase for mismatched values (it's svg path originally) I think it is mean something
I was right

Code: Select all

M  x,y	Move to the absolute coordinates x,y
m  x,y	Move to the right x and down y (or left and up if negative values)
L  x,y	Draw a straight line to the absolute coordinates x,y
l  x,y	Draw a straight line to a point that is relatively right x and down y (or left and up if negative values)
H  x	  Draw a line horizontally to the exact coordinate x
h  x	  Draw a line horizontally relatively to the right x (or to the left if a negative value)
V  y	  Draw a line vertically to the exact coordinate y
v  y	  Draw a line vertically relatively down y (or up if a negative value)
Z  z	  Draw a straight line back to the start of the path
'l' means relative coordinates and 'L' is absolute

now we just need to calc relative coordinates and that will fix the problem
and if we also comment GdipSetCompositingQuality (PB use lower quality by default) we'll get visual match.
Post Reply