Anti-aliased Lines in Screen 13


This SUB draws an anti-aliased line in Screen 13 using a gradient. It is just a QB adaptation of Hugo Elias' pseudo-code, found at http://freespace.virgin.net/hugo.elias/graphics/x_wuline.htm


DECLARE SUB WULine (x1%, y1%, x2%, y2%, basecolor%)
DECLARE FUNCTION invfrac! (xf!)
DECLARE FUNCTION frac! (xf!)

' WULINE.BAS adapted from pseudocode by Na Than :D
' Original code by Hugo Elias,
' http://freespace.virgin.net/hugo.elias/graphics/x_wuline.htm

SCREEN 13

' Set up a correct gradient to test our vu line:
' we need 16 values from ZERO to a pure colour, for example YELLOW.
' We'll start in 16:

OUT &H3C8, 16
FOR i% = 0 TO 15
OUT &H3C9, i% * 4
OUT &H3C9, i% * 4
OUT &H3C9, 0
NEXT i%

' And red, from 32

OUT &H3C8, 32
FOR i% = 0 TO 15
OUT &H3C9, i% * 4
OUT &H3C9, 0
OUT &H3C9, 0
NEXT i%


' Draw a shiny star:

ct% = 0
FOR a! = 0 TO (8 * ATN(1)) STEP (4 * ATN(1)) / 32
IF ct% THEN WULine 160, 100, 160 + 60 * COS(a!), 100 + 60 * SIN(a!), 31
ct% = NOT ct%
WULine 160 + 60 * COS(a!), 100 + 60 * SIN(a!), 160 + 60 * COS(a! + (4 * ATN(1)) / 32), 100 + 60 * SIN(a! + (4 * ATN(1)) / 32), 47
NEXT a!

FUNCTION frac! (xf!)
frac! = xf! - INT(xf!)
END FUNCTION


FUNCTION invfrac! (xf!)
invfrac! = 1 - frac!(xf!)
END FUNCTION

SUB WULine (x1%, y1%, x2%, y2%, basecolor%)
' This function uses basecolor% so basecolor%-15 is BLACK and there is
' a gradient to basecolor%-15 to basecolor%.

' Stop if vertical/horizontal line:
IF x1% = x2% OR y1% = y2% THEN LINE (x1%, y1%)-(x2%, y2%), basecolor%: EXIT SUB

pixelbase% = basecolor% - 15
maxpixelvalue% = 15

' Width and Height of the line
xd% = (x2% - x1%)
yd% = (y2% - y1%)

' Now we must check whether the line is horizontal or vertical

IF ABS(xd%) > ABS(yd%) THEN

' Horizontal line (more horizontal than vertical)

IF x1% > x2% THEN ' if line is back to front then swap it round
SWAP x1%, x2%
SWAP y1%, y2%
xd% = (x2% - x1%)
yd% = (y2% - y1%)
END IF

grad! = yd% / xd% ' gradient of the line

' End Point 1

xend! = INT(x1% + .5) ' find nearest integer X-coordinate
yend! = y1% + grad! * (xend! - x1%) ' and corresponding Y value

xgap! = invfrac!(x1% + .5) ' distance i

ix1% = INT(xend!) ' calc screen coordinates
iy1% = INT(yend!)

brightness1! = invfrac!(yend!) * xgap! ' calc the intensity of the other
brightness2! = frac!(yend!) * xgap! ' end point pixel pair.

c1% = pixelbase% + brightness1! * maxpixelvalue%
c2% = pixelbase% + brightness2! * maxpixelvalue%

PSET (ix1%, iy1%), c1%
PSET (ix1%, iy1% + 1), c2%

yf! = yend! + grad! ' calc first Y-intersection for main loop

' End Point 2

xend! = INT(x2% + .5)
yend! = y2% + grad! * (xend! - x2%)

xgap! = invfrac!(x2% - .5)

ix2% = INT(xend!)
iy2% = INT(yend!)

brightness1! = invfrac!(yend!) * xgap!
brightness2! = frac!(yend!) * xgap!

c1% = pixelbase% + brightness1! * maxpixelvalue%
c2% = pixelbase% + brightness2! * maxpixelvalue%

PSET (ix2%, iy2%), c1%
PSET (ix2%, iy2% + 1), c2%

' MAIN LOOP

FOR x% = (ix1% + 1) TO (ix2% - 1)

brightness1! = invfrac!(yf!)
brightness2! = frac!(yf!)

c1% = pixelbase% + brightness1! * maxpixelvalue%
c2% = pixelbase% + brightness2! * maxpixelvalue%

PSET (x%, INT(yf!)), c1%
PSET (x%, INT(yf!) + 1), c2%

yf! = yf! + grad! ' Update coordinate (bresenham style)

NEXT x%

ELSE

' Vertical line (more vertical than horizontal)
' NOTE that it is the same code, but with x and y swapped:

IF y1% > y2% THEN ' if line is back to front then swap it round
SWAP y1%, y2%
SWAP x1%, x2%
yd% = (y2% - y1%)
xd% = (x2% - x1%)
END IF

grad! = xd% / yd% ' gradient of the line ***

' End Point 1

yend! = INT(y1% + .5) ' find nearest integer X-coordinate
xend! = x1% + grad! * (yend! - y1%) ' and corresponding Y value

ygap! = invfrac!(y1% + .5) ' distance i

iy1% = INT(yend!) ' calc screen coordinates
ix1% = INT(xend!)

brightness1! = invfrac!(xend!) * ygap! ' calc the intensity of the other
brightness2! = frac!(xend!) * ygap! ' end point pixel pair.

c1% = pixelbase% + brightness1! * maxpixelvalue%
c2% = pixelbase% + brightness2! * maxpixelvalue%

PSET (ix1%, iy1%), c1%
PSET (ix1% + 1, iy1%), c2%

xf! = xend! + grad! ' calc first Y-intersection for main loop

' End Point 2

yend! = INT(y2% + .5)
xend! = x2% + grad! * (yend! - y2%)

ygap! = invfrac!(y2% - .5)

iy2% = INT(yend!)
ix2% = INT(xend!)

brightness1! = invfrac!(xend!) * ygap!
brightness2! = frac!(xend!) * ygap!

c1% = pixelbase% + brightness1! * maxpixelvalue%
c2% = pixelbase% + brightness2! * maxpixelvalue%

PSET (ix2%, iy2%), c1%
PSET (ix2% + 1, iy2%), c2%

' MAIN LOOP

FOR y% = (iy1% + 1) TO (iy2% - 1)

brightness1! = invfrac!(xf!)
brightness2! = frac!(xf!)

c1% = pixelbase% + brightness1! * maxpixelvalue%
c2% = pixelbase% + brightness2! * maxpixelvalue%

PSET (INT(xf!), y%), c1%
PSET (INT(xf!) + 1, y%), c2%

xf! = xf! + grad! ' Update coodinate (bresenham style)

NEXT y%
END IF
END SUB


The code above is not very optimized, and uses the DDA approach which is slower than the Bresenham algorithm. Also, the antialiased lines don't blend with the background. In order to do that, translucency should have to be added, thus needing a blending map or a special palette, or a RGB mode. I will post a complete version (which blends with the background) anytime sooner or later. Cheers.


AntiAliasedLinesInScreenThirteen - page last edited 2004-02-10 12:35:11 by 172.167.146.22 (home) (edit)
Blast WIKI - by RoboticBoy - edited and tweaked for our evil purposes by Hexadecimal Disaster