;/ ============================ ;/ = DrawEx - Module.pbi = ;/ ============================ ;/ ;/ [ PB V5.7x / 64Bit / All OS / DPI ] ;/ ;/ 2DDrawing with antialiasing effect ;/ ;/ © 2019 Thorsten1867 (06/2019) ;/ ; Last Update: ;{ ===== MIT License ===== ; ; Copyright (c) 2019 Thorsten Hoeppner ; ; Permission is hereby granted, free of charge, to any person obtaining a copy ; of this software and associated documentation files (the "Software"), to deal ; in the Software without restriction, including without limitation the rights ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ; copies of the Software, and to permit persons to whom the Software is ; furnished to do so, subject to the following conditions: ; ; The above copyright notice and this permission notice shall be included in all ; copies or substantial portions of the Software. ; ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ; SOFTWARE. ;} ;{ _____ DrawEx - Commands _____ ; Draw::AlphaColor() - similar to RGBA() ; Draw::aBox() - similar to Box() ; Draw::aCircle() - similar to Circle() ; Draw::aCircleArc() - draws a arc of a circle ; Draw::aCircleSector() - draws a circle sector ; Draw::aLine() - similar to Line() ; Draw::aLineXY() - similar to LineXY() ; Draw::MixColor() - mixes 2 colours in a mixing ratio of 1% - 99% ;} DeclareModule Draw #DPI = 1 ;- =========================================================================== ;- DeclareModule ;- =========================================================================== Declare.q AlphaColor(Color.i, Alpha.i) Declare aBox(X.i, Y.i, Width.i, Height.i, Color.i, Flags.i=#False) Declare aCircle(X.i, Y.i, Radius.i, Color.i, Flags.i=#False) Declare aCircleArc(X.i, Y.i, Radius.i, startAngle.i, endAngle.i, Color.i, Flags.i=#False) Declare aCircleSector(X.i, Y.i, Radius.i, startAngle.i, endAngle.i, Color.i, FillColor.i=#PB_Default, Flags.i=#False) Declare aLine(X.i, Y.i, Width.i, Height.i, Color.i, Flags.i=#False) Declare aLineXY(X1.i, Y1.i, X2.i, Y2.i, Color.i, Flags.i=#False) Declare.i MixColor(Color1.i, Color2.i, Factor.i=50) EndDeclareModule Module Draw EnableExplicit ;- ============================================================================ ;- Module - Internal ;- ============================================================================ Procedure.f dpiX(Num.i) ProcedureReturn DesktopScaledX(Num) EndProcedure Procedure.f dpiY(Num.i) ProcedureReturn DesktopScaledY(Num) EndProcedure Procedure.i BlendColor_(Color1.i, Color2.i, Factor.i=50) Define.i Red1, Green1, Blue1, Red2, Green2, Blue2 Define.f Blend = Factor / 100 Red1 = Red(Color1): Green1 = Green(Color1): Blue1 = Blue(Color1) Red2 = Red(Color2): Green2 = Green(Color2): Blue2 = Blue(Color2) ProcedureReturn RGB((Red1 * Blend) + (Red2 * (1 - Blend)), (Green1 * Blend) + (Green2 * (1 - Blend)), (Blue1 * Blend) + (Blue2 * (1 - Blend))) EndProcedure Procedure.q AlphaColor_(Color.i, Alpha.i) ProcedureReturn RGBA(Red(Color), Green(Color), Blue(Color), Alpha) EndProcedure Procedure.f Frac(Float.f) ProcedureReturn Float - Int(Float) EndProcedure Procedure.f GetAngle_(X.i, Y.i, cX.i=0, cY.i=0) Define.i aX, aY Define.f Angle aX = X - cX aY = Y - cY Angle = ATan2(aX, aY) If Angle >= 0 ProcedureReturn Angle Else ProcedureReturn Angle + (2 * #PI) EndIf EndProcedure Procedure.f GetAngleDegree_(X.i, Y.i, cX.i=0, cY.i=0) Define.i aX, aY Define.f Angle aX = X - cX aY = Y - cY Angle = ATan2(aX, aY) If Angle >= 0 ProcedureReturn Degree(Angle) Else ProcedureReturn 360 + Degree(Angle) EndIf EndProcedure Procedure SectorBackground_(X.i, Y.i, Radius.f, sAngle.f, eAngle.f, Color.i, Gradient.i=#PB_Default) Define.i a, pX, pY, fX, fY DrawingMode(#PB_2DDrawing_Default) pX = Radius * Cos(sAngle) : pY = Radius * Sin(sAngle) LineXY(X, Y, pX + X, pY + Y, Color) pX = Radius * Cos(eAngle) : pY = Radius * Sin(eAngle) LineXY(X, Y, X + pX, Y + pY, Color) For a = sAngle * Radius To eAngle * Radius pX = Cos(a / Radius) * Radius + X pY = Sin(a / Radius) * Radius + Y Plot(pX, pY, Color) Next DrawingMode(#PB_2DDrawing_Gradient) fX = Cos((eAngle + sAngle) / 2) * (Radius / 2) + X fY = Sin((eAngle + sAngle) / 2) * (Radius / 2) + Y If Gradient = #PB_Default : Gradient = BlendColor_(Color, Point(fX, fY), 60) : EndIf CircularGradient(X, Y, Radius) FrontColor(Color) BackColor(Gradient) FillArea(fX, fY, Color) DrawingMode(#PB_2DDrawing_Default) EndProcedure Procedure CircleArc_(X.i, Y.i, Radius.i, startAngle.i, endAngle.i, Color.i) Define.i a, sX, Color1, Color2 Define.f sY, lX, lY, C1, C2, Angle, sAngle, eAngle sAngle = Radian(startAngle) eAngle = Radian(endAngle) DrawingMode(#PB_2DDrawing_AlphaBlend) For sX = -Radius * 0.7071 To -1 sY = Sqr(Radius * Radius - sX * sX) C2 = Frac(sY + 0.5) C1 = 1 - C2 Color1 = AlphaColor_(Color, C1 * 255) Color2 = AlphaColor_(Color, C2 * 255) Angle = GetAngleDegree_(sX, sY) If startAngle < 135 And endAngle > 90 Plot(X + sX, Y + sY, Color1) Plot(X + sX, Y + sY + 1, Color2) EndIf Angle = GetAngleDegree_(sX, -sY) If startAngle <= Angle And endAngle >= Angle Plot(X + sX, Y - sY, Color1) Plot(X + sX, Y - sY - 1, Color2) EndIf Angle = GetAngleDegree_(-sX, sY) If startAngle <= Angle And endAngle >= Angle Plot(X - sX, Y + sY, Color1) Plot(X - sX, Y + sY + 1, Color2) EndIf Angle = GetAngleDegree_(-sX, -sY) If startAngle <= Angle And endAngle >= Angle Plot(X - sX, Y - sY, Color1) Plot(X - sX, Y - sY - 1, Color2) EndIf Angle = GetAngleDegree_(sY, sX) If startAngle <= Angle And endAngle >= Angle Plot(X + sY, Y + sX, Color1) Plot(X + sY + 1, Y + sX, Color2) EndIf Angle = GetAngleDegree_(-sY, sX) If startAngle <= Angle And endAngle >= Angle Plot(X - sY, Y + sX, Color1) Plot(X - sY - 1, Y + sX, Color2) EndIf Angle = GetAngleDegree_(sY, -sX) If startAngle <= Angle And endAngle >= Angle Plot(X + sY, Y - sX, Color1) Plot(X + sY + 1, Y - sX, Color2) EndIf Angle = GetAngleDegree_(-sY, -sX) If startAngle <= Angle And endAngle >= Angle Plot(X - sY, Y - sX, Color1) Plot(X - sY - 1, Y - sX, Color2) EndIf Next C2 = Frac(Radius + 0.5) C1 = 1 - C2 If startAngle <= 90 And endAngle >= 90 Plot(X, Y + Radius, Color1) Plot(X, Y + Radius + 1, Color2) EndIf If startAngle <= 180 And endAngle >= 180 Plot(X - Radius, Y, Color1) Plot(X - Radius - 1, Y, Color2) EndIf If startAngle <= 270 And endAngle >= 270 Plot(X, Y - Radius, Color1) Plot(X, Y - Radius - 1, Color2) EndIf If startAngle <= 0 And endAngle >= 0 Plot(X + Radius, Y, Color1) Plot(X + Radius + 1, Y, Color2) EndIf DrawingMode(#PB_2DDrawing_Default) EndProcedure Procedure LineXY_(X1.i, Y1.i, X2.i, Y2.i, Color.i) Define.i X, Down, Color1, Color2 Define.f Y, Incline, C1, C2, deltaX, deltaY If Abs(Y2 - Y1) > Abs(X2 - X1) : Down = #True : EndIf If Down Swap X1, Y1 Swap X2, Y2 EndIf If X1 > X2 Swap X1, X2 Swap Y1, Y2 EndIf deltaX = X2 - X1 deltaY = Abs(Y2 - Y1) If deltaX <> 0 : Incline = deltaY / deltaX + 0.0010001 : EndIf If Y1 >= Y2 : Incline * -1 : EndIf Y = Y1 DrawingMode(#PB_2DDrawing_AlphaBlend) For X = X1 To X2 C2 = Frac(Y + 0.5) C1 = (1 - C2) Color1 = AlphaColor_(Color, C1 * 255) Color2 = AlphaColor_(Color, C2 * 255) If Down Plot(Y, X, Color1) Plot(Y + 1, X, Color2) Else Plot(X, Y, Color1) Plot(X, Y + 1, Color2) EndIf Y + Incline Next DrawingMode(#PB_2DDrawing_Default) EndProcedure ;- ========================================================================== ;- Module - Declared Procedures ;- ========================================================================== Procedure.q AlphaColor(Color.i, Alpha.i) ProcedureReturn AlphaColor(Color.i, Alpha.i) EndProcedure Procedure.i MixColor(Color1.i, Color2.i, Factor.i=50) ProcedureReturn BlendColor_(Color1, Color2, Factor) EndProcedure Procedure aBox(X.i, Y.i, Width.i, Height.i, Color.i, Flags.i=#False) If Flags & #DPI X = dpix(X) Y = dpix(Y) Width = dpix(Width) Height = dpix(Height) EndIf If Width And Height LineXY_(X, Y, X + Width, Y, Color) LineXY_(X, Y, X, Y + Height, Color) LineXY_(X + Width, Y, X + Width, Y + Height, Color) LineXY_(X, Y, X + Width, Y, Color) LineXY_(X, Y + Height, X + Width, Y + Height, Color) EndIf EndProcedure Procedure aLine(X.i, Y.i, Width.i, Height.i, Color.i, Flags.i=#False) If Flags & #DPI X = dpix(X) Y = dpix(Y) Width = dpix(Width) Height = dpix(Height) EndIf If Width And Height If Width > 1 LineXY_(X, Y, X + Width, Y, Color) Else LineXY_(X, Y, X, Y + Height, Color) EndIf EndIf EndProcedure Procedure aLineXY(X1.i, Y1.i, X2.i, Y2.i, Color.i, Flags.i=#False) If Flags & #DPI X1 = dpix(X1) Y1 = dpix(Y1) X2 = dpix(X2) Y2 = dpix(Y2) EndIf LineXY_(X1, Y1, X2, Y2, Color) EndProcedure Procedure aCircle(X.i, Y.i, Radius.i, Color.i, Flags.i=#False) Define.i a, sX, Color1, Color2 Define.f sY, C1.f, C2.f If Radius > 0 If Flags & #DPI X = dpix(X) Y = dpix(Y) Radius = dpiX(Radius) EndIf DrawingMode(#PB_2DDrawing_AlphaBlend) For sX = -Radius * 0.7071 To -1 sY = Sqr(Radius * Radius - sX * sX) C2 = Frac(sY + 0.5) C1 = 1 - C2 Color1 = AlphaColor_(Color, C1 * 255) Color2 = AlphaColor_(Color, C2 * 255) Plot(X + sX, Y + sY, Color1) Plot(X - sX, Y + sY, Color1) Plot(X + sX, Y - sY, Color1) Plot(X - sX, Y - sY, Color1) Plot(X + sY, Y + sX, Color1) Plot(X - sY, Y + sX, Color1) Plot(X + sY, Y - sX, Color1) Plot(X - sY, Y - sX, Color1) Plot(X + sX, Y + sY + 1, Color2) Plot(X - sX, Y + sY + 1, Color2) Plot(X + sX, Y - sY - 1, Color2) Plot(X - sX, Y - sY - 1, Color2) Plot(X + sY + 1, Y + sX, Color2) Plot(X - sY - 1, Y + sX, Color2) Plot(X + sY + 1, Y - sX, Color2) Plot(X - sY - 1, Y - sX, Color2) Next C2 = Frac(Radius + 0.5) C1 = 1 - C2 Plot(X, Y + Radius, Color1) Plot(X, Y - Radius, Color1) Plot(X + Radius, Y, Color1) Plot(X - Radius, Y, Color1) Plot(X, Y + Radius + 1, Color2) Plot(X, Y - Radius - 1, Color2) Plot(X + Radius + 1, Y, Color2) Plot(X - Radius - 1, Y, Color2) DrawingMode(#PB_2DDrawing_Default) EndIf EndProcedure Procedure aCircleArc(X.i, Y.i, Radius.i, startAngle.i, endAngle.i, Color.i, Flags.i=#False) If Radius > 0 If Flags & #DPI X = dpix(X) Y = dpix(Y) Radius = dpiX(Radius) EndIf CircleArc_(X, Y, Radius, startAngle, endAngle, Color) EndIf EndProcedure Procedure aCircleSector(X.i, Y.i, Radius.i, startAngle.i, endAngle.i, Color.i, FillColor.i=#PB_Default, Flags.i=#False) Define.f lX, lY, sAngle, eAngle If Radius > 0 If Flags & #DPI X = dpix(X) Y = dpix(Y) Radius = dpiX(Radius) EndIf sAngle = Radian(startAngle) eAngle = Radian(endAngle) SectorBackground_(X, Y, Radius, sAngle, eAngle, FillColor) CircleArc_(X, Y, Radius, startAngle, endAngle, Color) lX = Radius * Cos(eAngle) : lY = Radius * Sin(eAngle) aLineXY(X, Y, lX + X, lY + Y, Color) lX = Radius * Cos(sAngle) : lY = Radius * Sin(sAngle) aLineXY(X, Y, lX + X, lY + Y, Color) EndIf EndProcedure EndModule ;- ======== Module - Example ======== CompilerIf #PB_Compiler_IsMainFile #Window = 0 #Gadget = 1 If OpenWindow(#Window, 0, 0, 200, 200, "2DDrawing Beispiel", #PB_Window_SystemMenu|#PB_Window_Tool|#PB_Window_ScreenCentered) CanvasGadget(#Gadget, 10, 10, 180, 180) If StartDrawing(CanvasOutput(#Gadget)) Draw::aLineXY(90, 90, 90 + 80 * Cos(Radian(230)), 90 + 80 * Sin(Radian(230)), $228B22, Draw::#DPI) Draw::aCircleSector(90, 90, 70, 40, 90, $800000, $00D7FF, Draw::#DPI) Draw::aCircle(90, 90, 80, $800000, Draw::#DPI) Draw::aCircleArc(90, 90, 70, 250, 340, $008CFF, Draw::#DPI) Draw::aLine(10, 90, 160, 1, $8515C7, Draw::#DPI) Draw::aBox(5, 5, 170, 170, $CD0000, Draw::#DPI) StopDrawing() EndIf Repeat Event = WaitWindowEvent() Until Event = #PB_Event_CloseWindow EndIf CompilerEndIf ; IDE Options = PureBasic 5.70 LTS (Windows - x86) ; CursorPosition = 47 ; Folding = OAAw ; EnableXP ; DPIAware