Anti-aliased 2D graphics

Share your advanced PureBasic knowledge/code with the community.
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Anti-aliased 2D graphics

Post 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
Last edited by Dude on Mon Feb 23, 2015 2:29 pm, edited 1 time in total.
User avatar
heartbone
Addict
Addict
Posts: 1058
Joined: Fri Apr 12, 2013 1:55 pm
Location: just outside of Ferguson

Re: Anti-aliased 2D graphics

Post 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.
Keep it BASIC.
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Anti-aliased 2D graphics

Post 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.
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
djes
Addict
Addict
Posts: 1806
Joined: Sat Feb 19, 2005 2:46 pm
Location: Pas-de-Calais, France

Re: Anti-aliased 2D graphics

Post by djes »

luis> Haven't you adapted Bresenham's circle and line algorithms in the past ? I can't find them so far.
Last edited by djes on Mon Feb 23, 2015 2:53 pm, edited 1 time in total.
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Re: Anti-aliased 2D graphics

Post 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! :)
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Anti-aliased 2D graphics

Post 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:
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
djes
Addict
Addict
Posts: 1806
Joined: Sat Feb 19, 2005 2:46 pm
Location: Pas-de-Calais, France

Re: Anti-aliased 2D graphics

Post 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
User avatar
Danilo
Addict
Addict
Posts: 3036
Joined: Sat Apr 26, 2003 8:26 am
Location: Planet Earth

Re: Anti-aliased 2D graphics

Post 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
User avatar
djes
Addict
Addict
Posts: 1806
Joined: Sat Feb 19, 2005 2:46 pm
Location: Pas-de-Calais, France

Re: Anti-aliased 2D graphics

Post 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
User avatar
heartbone
Addict
Addict
Posts: 1058
Joined: Fri Apr 12, 2013 1:55 pm
Location: just outside of Ferguson

Re: Anti-aliased 2D graphics

Post 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.
Keep it BASIC.
User avatar
djes
Addict
Addict
Posts: 1806
Joined: Sat Feb 19, 2005 2:46 pm
Location: Pas-de-Calais, France

Re: Anti-aliased 2D graphics

Post 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...!
Post Reply