When a computer video system is required to draw a line, it has to 'light up' the appropriate pixels. However these lie on a 2D matrix of positions, so while horizontal and vertical may be easily drawn, at other angles it has to step along and/or up to give the best representation.
Liberty BASIC is pretty good at calling underlying Windows routines, so as users we do not see this going on- a line will magically appear using the fastest method and best approximation.
Horizontal or vertical- easy!
-
But at angles we have best to take a pattern of alongs and ups.
It may help to use fractional tones so the eye is better fooled into seeing a smooth line- anti-aliasing. This leads rto Bresenham's method.
LB has a set of turtle commands, which make simple drawing very easy. However there are a number of drawbacks for accurate representation and convenience. There is no access to the current ( x, y) of the drawing pen, and its position is stored rounded off to an integer, so rounding errors add up. Thus doing 20 'go's of 1 behaves as expected, but not 20 'go's of 0.3 or 1.3. And the geometric figures like squares or stars may not exactly join, so if you apply a fill it leaks out. And while you can alter a line width or color as a whole, you can't change it along a line- say fading the color or narrowing the width, or creating dot/dash effects.
The introductory animation shows that by implementing your own Bresenham routine you can examine each pixel which the algorithm wishes to draw and inhibit it for a chosen background color. So an invisible logo, written in a near-black colour, is slowly revealed...
nomainwin
WindowWidth =530
WindowHeight =550
graphicbox #w.gb, 10, 10, 500, 500
global hdc
open "Bresenham" for graphics_nsb as #w
#w "trapclose quit"
h = hwnd( #w.gb)
calldll #user32, "GetDC", h as ulong, hdc as ulong
#w.gb "goto 100 270 ; down ; fill 1 0 0 ; color 0 0 0 ; backcolor 1 0 0"
#w.gb "font Times_Roman bold italic 90": #w.gb "\ LB" +chr$( 13) +"rules!"
#w.gb "color 255 255 0 ; rule "; _R2_COPYPEN
for jf =1 to 2000
x1 =-100 +int( 700 *rnd( 1))
y1 = 0 +int( 500 *rnd( 1))
x2 =-100 +int( 700 *rnd( 1))
y2 = 0 +int( 500 *rnd( 1))
call bresenham x1, y1, x2, y2
next jf
#w.gb "getbmp scr 0 0 500 500"
'bmpsave "scr", "bresenhamInverse.bmp"
wait
sub quit h$
close #h$
calldll #user32, "ReleaseDC", hw as ulong, hdc as ulong 'release the DC
end
end sub
sub bresenham x1, y1, x2, y2 ' Inputs are x1, y1, x2, y2: destroys value of x1, y1
dx = abs( x2 - x1): sx = -1: if x1 < x2 then sx = 1
dy = abs( y2 - y1): sy = -1: if y1 < y2 then sy = 1
er = 0 -dy: if dx > dy then er = dx
er = int( er / 2)
[more] g = getPixel( x1, y1) ' can only write on longcolor 1 or own colour...
'if ( g = 1) or ( g = bg) then #w.gb "set "; x1; " "; y1
'if y1 >250 then #w.gb "color red" else #w.gb "color blue"
p =int( ( y1 +100) /600 *255)
c$ =str$( p) +" " +str$( int( ( x1 +100) /700 *255)) +" " +str$( 255 -p)
#w.gb "color " +c$
if ( g <> 1) then #w.gb "set "; x1; " "; y1
scan
if ( ( x1 = x2) and ( y1 = y2)) then exit sub
'if ( ( x2 > 490) or ( x2 < 10) or ( y2 > 490) or ( y2 < 10)) then exit sub ' should not happen!
e2 = er
if ( e2 > 0 -dx) then er = ( er - dy): x1 = ( x1 + sx)
if ( e2 < dy) then er = ( er + dx): y1 = ( y1 + sy)
goto [more]
end sub
function getPixel( x, y)
calldll #gdi32, "GetPixel", hdc as ulong, x as long, y as long, pixcol as ulong
getPixel =pixcol
end function
'function MakeRGB$( cc)
' blu =int( cc /256 /256)
' grn =int( ( cc -blu *256 *256) / 256)
' red =int( cc -blu *256 *256 -grn *256)
' MakeRGB$ =str$( red) +" " +str$( grn) +" " +str$( blu)
'end function