Page 1 of 1

Anti-aliased 2D graphics

Posted: Mon Feb 23, 2015 10:59 am
by Dude
To quickly anti-alias all 2D drawing, all you really need to do for satisfactory results is double the size of everything created, then shrink it back to 100% size afterwards.

To that end, it seems to me that wrapping the 2D drawing commands in macros to double everything is the easiest way, and this means the drawing speed is always exactly the same as the normal 2D drawing commands; except for the final single step of shrinking it to 100%. So for general image displays (think charts as opposed to games), the speed is perfectly acceptable.

Here's some wrapping to show what I mean. As you can see, the AA commands are anti-aliased versions of the normal 2D commands, so they're easy to drop right in when AA is needed. You just have to finish all drawing of the AA image with the Finish_AA() command, which always goes after the StopDrawing() command.

Anyway, it's what I'm using and I like it, so I hope it helps/inspires others. :)

Image

Code: Select all

Macro CreateImage_AA(img,w,h,depth=24,color=0)
  CreateImage(img,w*2,h*2,depth,color)
EndMacro

Macro Circle_AA(x,y,radius,color=#PB_Default)
  Circle(x*2,y*2,radius*2,color)
EndMacro

Macro LineXY_AA(x1,y1,x2,y2,color=#PB_Default)
  LineXY(x1*2,y1*2,x2*2,y2*2,color)
EndMacro

Macro Finish_AA(img)
  ResizeImage(img,ImageWidth(img)/2,ImageHeight(img)/2)
EndMacro

OpenWindow(0,0,0,680,280,"Anti-Alias Macros",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)

; Normal 2D circle with line.
CreateImage(1,320,240,32,#White)
StartDrawing(ImageOutput(1))
  DrawingMode(#PB_2DDrawing_Outlined)
  Circle(160,120,100,#Blue)
  LineXY(0,0,320,240,#Red)
StopDrawing()

; Anti-aliased 2D circle with line.
CreateImage_AA(2,320,240,32,#White)
StartDrawing(ImageOutput(2))
  DrawingMode(#PB_2DDrawing_Outlined)
  Circle_AA(160,120,100,#Blue)
  LineXY_AA(0,0,320,240,#Red)
StopDrawing()
Finish_AA(2) ; Required when AA drawing is done.

ImageGadget(1,10,10,320,240,ImageID(1))
ImageGadget(2,350,10,320,240,ImageID(2))

Repeat : Until WaitWindowEvent()=#PB_Event_CloseWindow

Re: Anti-aliased 2D graphics

Posted: Mon Feb 23, 2015 1:43 pm
by heartbone
Your algorithm's results would look even better if you doubled the thickness of the line and circle before shrinking.
I think it might also look better if you did a shrink that was not an even power of two.
e.g., transform a 1680x1260 or 1592x1194 drawing into 800x600 resolution.

Re: Anti-aliased 2D graphics

Posted: Mon Feb 23, 2015 2:18 pm
by luis
with the Finish_AA() command, which always goes just before the StopDrawing() command.
Finish_AA() expands to ResizeImage(), and I believe this should be outside the StartDrawing()/StopDrawing() block.

You can use the commands from the drawing library inside it, but ResizeImage() it's not one of them.
It's to be used on a finished, stable image, the locked one is a sort of work in progress under the control of the PB drawing library.

The default value for the mode of operation of ResizeImage() is #PB_Image_Smooth, which probably requires more steps and maybe does a copy of the locked bitmap or something else which in some way luckily bypass the problem.

Try using #PB_Image_Raw, which is more simple and maybe works directly on the locked bitmap.
The test program doesn't work anymore, at least on Windows. Move it outside of the StartDrawing()/StopDrawing() block and works again.

What's bad is that even by testing the return value of ResizeImage() you get a "success" in any case, so the poor command it's not aware of what's happening (even if I understand it's something unexpected for it).

In short, it works in your case but just because you are lucky, should be outside of the block.

Re: Anti-aliased 2D graphics

Posted: Mon Feb 23, 2015 2:28 pm
by djes
luis> Haven't you adapted Bresenham's circle and line algorithms in the past ? I can't find them so far.

Re: Anti-aliased 2D graphics

Posted: Mon Feb 23, 2015 2:31 pm
by Dude
luis wrote:Finish_AA() expands to ResizeImage(), and I believe this should be outside the StartDrawing()/StopDrawing() block.
You're right, Luis. I've edited my post to put it after StopDrawing(). Thanks for the heads-up! :)

Re: Anti-aliased 2D graphics

Posted: Mon Feb 23, 2015 2:32 pm
by luis
@djes
No, it wasn't me :P

Maybe this ? http://www.purebasic.fr/english/viewtop ... 12&t=15855


@Dude
No prob, thanks for the tip :wink:

Re: Anti-aliased 2D graphics

Posted: Mon Feb 23, 2015 3:13 pm
by djes
luis wrote:@djes
No, it wasn't me :P

Maybe this ? http://www.purebasic.fr/english/viewtop ... 12&t=15855
No.... Strange ! And I can't get my hand on a nice website with all the AA drawing routines in pseudo-code (chrome's bookmarks are sh***)... Anyway, here's one, among a lot on the web : http://rosettacode.org/wiki/Xiaolin_Wu% ... #PureBasic

Edit : I got it : A simple implementation to plot lines, circles, ellipses and Bézier curves

Re: Anti-aliased 2D graphics

Posted: Mon Feb 23, 2015 8:07 pm
by Danilo
With AA:
- Draw anti-aliazed line, circle, ellipse, triangle by Le Soldat Inconnum - Feb 10, 2009

Bresenham without AA:
- Bresenham Algorithms by hagibaba - Jul 09, 2005
- Filled and outlined Box, Circle, Ellipse (because PB/Linux didn't have it at this time) by Danilo - Feb 04, 2005

Re: Anti-aliased 2D graphics

Posted: Fri Feb 27, 2015 5:09 pm
by djes
Here's the purebasic version of the Alois Zingl's antialiased line routine. Someone could test ? I think there's a problem with transparency.

Code: Select all

;
; ------------------------------------------------------------
;
;   PureBasic - Antialiased line Drawing example file
;
;    (c) 2005 - Background code by Fantaisie Software
;        2015 - LineAA by djes
;
; ------------------------------------------------------------
;

Procedure LineAA(x0.i, y0.i, x1.i, y1.i, color.i)
  ; /* draw an anti-aliased line on background */
  ; adapted by djes upon Alois Zingl's work - http://members.chello.at/~easyfilter/bresenham.html
  Define.i dx = Abs(x1 - x0), sx : If x0 < x1 : sx = 1 : Else : sx = -1 : EndIf
  Define.i dy = Abs(y1 - y0), sy : If y0 < y1 : sy = 1 : Else : sy = -1 : EndIf
  Define.i x2, e2, err = dx - dy; /* error value e_xy */
  Define.i ed : If dx + dy = 0 : ed = 0 : Else : ed = Sqr(dx*dx + dy*dy) : EndIf
  Define.i r = Red(color), g = Green(color), b=Blue(color), a=Alpha(color), c
  Define.i blend
  While #True ; pixel loop
    blend = 255*Abs(err - dx+dy)/ed : c = Point(x0,y0)
    Plot(x0, y0, RGBA((blend*Red(c) + (255-blend)*r) / 255, (blend*Green(c) + (255-blend)*g) / 255, (blend*Blue(c) + (255-blend)*b) / 255, (blend*Alpha(c) + (255-blend)*a) / 255))
    e2 = err : x2 = x0;
    If (2*e2 >= -dx)  ;{ /* x Step */
      If (x0 = x1) : Break : EndIf
      If (e2+dy < ed) 
        blend = 255*(e2+dy)/ed : c = Point(x0,y0+sy)
        Plot(x0, y0+sy, RGBA((blend*Red(c) + (255-blend)*r) / 255, (blend*Green(c) + (255-blend)*g) / 255, (blend*Blue(c) + (255-blend)*b) / 255, (blend*Alpha(c) + (255-blend)*a) / 255))
      EndIf
      err - dy : x0 + sx;
    EndIf
    If (2*e2 <= dy) ;{ /* y Step */
      If (y0 = y1) : Break : EndIf
      If (dx-e2 < ed)
        blend = 255*(dx-e2)/ed : c = Point(x2+sx,y0)
        Plot(x2+sx,y0, RGBA((blend*Red(c) + (255-blend)*r) / 255, (blend*Green(c) + (255-blend)*g) / 255, (blend*Blue(c) + (255-blend)*b) / 255, (blend*Alpha(c) + (255-blend)*a) / 255))
      EndIf
      err + dx : y0 + sy
    EndIf
  Wend
EndProcedure

If OpenWindow(0, 100, 200, 300, 200, "AA Line Drawing Test")
  
  ; Create an offscreen image, with a green circle in it.
  ; It will be displayed later
  ;
  If CreateImage(0, 300, 200, 32)
    If StartDrawing(ImageOutput(0))
      Circle(100,100,50, RGB(0,0,255))  ; a nice blue circle...
      
      Box(150,20,20,20, RGB(0,255,0))  ; and a green box
      
      FrontColor(RGB(255,0,0)) ; Finally, red lines..
      For k=0 To 20
        LineAA(10,10+k*8,150, 0, RGBA(255,255,0,0))
        LineXY(290,10+k*8,150, 0)
      Next
      
      DrawingMode(#PB_2DDrawing_Transparent)
      BackColor(RGB(0,155,155)) ; Change the text back and front colour
      FrontColor(RGB(255,255,255)) 
      DrawText(10,50,"Hello, this is a test")
      
      StopDrawing()
    EndIf
  EndIf
  
  ; Create a gadget to display our nice image
  ;  
  ImageGadget(0, 0, 0, 0, 0, ImageID(0))
  
  ;
  ; This is the 'event loop'. All the user actions are processed here.
  ; It's very easy to understand: when an action occurs, the Event
  ; isn't 0 and we just have to see what have happened...
  ;
  
  Repeat
    Event = WaitWindowEvent() 
  Until Event = #PB_Event_CloseWindow  ; If the user has pressed on the window close button
  
EndIf

End   ; All the opened windows are closed automatically by PureBasic

Re: Anti-aliased 2D graphics

Posted: Fri Feb 27, 2015 8:10 pm
by heartbone
djes wrote:Here's the purebasic version of the Alois Zingl's antialiased line routine. Someone could test ? I think there's a problem with transparency.
The only elements that appear to have a transparent characteristic are the yellow lines which have a distinct moiré pattern distortion induced by the algorithm.

Ignoring for now my advice about avoiding an integer power of two scale factor,
Dude wrote:To quickly anti-alias all 2D drawing, all you really need to do for satisfactory results is double the size of everything created, then shrink it back to 100% size afterwards.

Image
as long as one actually doubles the size of everything created so there will be no unsatisfactory color shifts like those present in the image, the method as described seems to be the easiest way to accomplish the AA effect.

Re: Anti-aliased 2D graphics

Posted: Fri Feb 27, 2015 10:25 pm
by djes
Actually, doubling the size is satisfactory only for small images. I can't imagine doing this kind of thing on a 300dpi A0 poster...!