====== Bresenham's line algorithm ======
Here is a C program using the allegro library that I pout up and ported to 6502 assembler. This implementation was designed by Janusz Ganczarski.
#include "allegro.h"
void init();
void deinit();
void B_Line (int x1, int y1, int x2, int y2);
void PutPixel (int x,int y);
int main() {
init();
B_Line (1, 1, 50, 10);
while (!key[KEY_ESC]) {
/* put your code here */
}
deinit();
return 0;
}
END_OF_MAIN()
void init() {
int depth, res;
allegro_init();
depth = desktop_color_depth();
if (depth == 0) depth = 32;
set_color_depth(depth);
res = set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);
if (res != 0) {
allegro_message(allegro_error);
exit(-1);
}
install_timer();
install_keyboard();
install_mouse();
/* add other initializations here */
}
void deinit() {
clear_keybuf();
/* add other deinitializations here */
}
void PutPixel (int x,int y)
{
putpixel(screen,x,y,makecol(255,255,255));
}
//---------------------------------------------------------------------------
// rysowanie linii algorytmem Bresenhama
//---------------------------------------------------------------------------
void B_Line (int x1, int y1, int x2, int y2)
{
// zmienne pomocnicze
int d,dx,dy,ai,bi,xi,yi;
// dy - "dlugosc" y
// dx - "dlugosc" X
// xi , yi - kierunek rysowania w osi x , y
//
// ustalenie kierunku rysowania oraz kroków zmiennych
if (x1 < x2)
{
xi = 1;
dx = x2 - x1;
}
else
{
xi = -1;
dx = x1 - x2;
}
// ustalenie kierunku rysowania oraz kroków zmiennych
if (y1 < y2)
{
yi = 1;
dy = y2 - y1;
}
else
{
yi = -1;
dy = y1 - y2;
}
// pierwszy piksel
PutPixel (x1,y1);
// oś wiodąca OX
if (dx > dy)
{
ai = (dy - dx) * 2;
bi = dy * 2;
d = bi - dx;
// warunek != zamiast < umożliwia rysowanie "pod górkę"
while (x1 != x2)
{
// przejście NE
if (d > 0)
{
y1 += yi;
d += ai;
}
// przejście E
else
d += bi;
x1 += xi;
PutPixel (x1,y1);
}
}
// oś wiodąca OY
else
{
ai = (dx - dy) * 2;
bi = dx * 2;
d = bi - dy;
// warunek != zamiast < umożliwia rysowanie "pod górkę"
while (y1 != y2)
{
// przejście NE
if (d > 0)
{
x1 += xi;
d += ai;
}
// przejście E
else
d += bi;
y1 += yi;
PutPixel (x1,y1);
}
}
}
6502 code was written using 6502sim and debugged here too , it's not optimized in any way and entire code uses only accumulator - it was written to represent that C program's B_Line function completely and needs further optimization to be really useful. it also uses 8bit variables only so lenght of line is limited too , and so on. 'debug' call should be exchanged with proper putpixel routine, in simulator 'debug' routine is used to watch how coords of pixels are chagning with line being drawn. after all this code is good for beginners I hope :)
; defines for 6502 simulator debugging
io_area = $e000
io_cls = io_area + 0 ; clear terminal window
io_putc = io_area + 1 ; put char
io_putr = io_area + 2 ; put raw char (doesn't interpret CR/LF)
io_puth = io_area + 3 ; put as hex number
io_getc = io_area + 4 ; get char
*= $c000
LDA #10
STA l_x1
lda #4
STA l_y1
LDA #0
STA l_x2
lda #0
STA l_y2
jmp do_line
*= $c100
do_line
; // zmienne pomocnicze
;// int d,dx,dy,ai,bi,xi,yi;
;U2 = two's compliment
;ZU = normal binary
;var name type desc
l_dx = $10 ; ZU - "dlugosc" x (rozpietosc na osi)
l_dy = l_dx + 1 ; ZU - "dlugosc" y
l_xi = l_dx + 2 ; U2 xi,yi - kierunek rysowania w osi x , y
l_yi = l_dx + 3 ; U2
l_ai = l_dx + 4 ; U2 step
l_bi = l_dx + 5 ; U2 step
l_d = l_dx + 6 ; U2 'error'
;points
l_x1 = l_dx + 7 ; ZU poczatek linii
l_y1 = l_dx + 8 ; ZU
l_x2 = l_dx + 9 ; ZU koniec linii
l_y2 = l_dx +10 ; ZU
; // ustalenie kierunku rysowania oraz kroków zmiennych
;// deciding what direction to draw + steps
; if (x1 < x2)
;if
x1mx2 LDA l_x1
CMP l_x2
BCC x1mx2_
jmp x1wx2
x1mx2_
;then [x1x2]
x1wx2 lda #255 ; -1 U2
STA l_xi ; xi = -1;
LDA l_x1
SEC
SBC l_x2
STA l_dx ; dx = x1 - x2
;// ustalenie kierunku rysowania oraz kroków zmiennych
;// deciding what direction to draw + steps
;if (y1 < y2)
y1my2 ; [y1y2]
y1wy2
lda #255 ; -1 U2
STA l_yi ; yi = -1;
LDA l_y1
SEC
SBC l_y2
STA l_dy ; dy = y1 - x2
skok1
;;;;;
; postaw pierwszy pixel
; put first pixel
; putpix(x1,y1);
jsr debug
; spr ktora os jest wiodaca
; check 'primary axis' (longer distance)
; if (dx>dy) // (dydx)
;// oś wiodąca OX
wiod_ox
;ai
LDA l_dy
SEC
SBC l_dx
CLC
ROL ;a
STA l_ai ; ai = (dy-dx)*2
;bi
LDA l_dy
CLC
ROL ;a
STA l_bi ; bi = dy * 2
;d
LDA l_bi
SEC
SBC l_dx
STA l_d ; d = bi - dx
whx1rx2 ;// while (x1 != x2)
LDA l_x1
CMP l_x2
BEQ l_end
; if (d > 0)
LDA l_d
CMP #0
beq _a
BPL _else
_a ; <0
; przejscie E
LDA l_d
CLC
ADC l_bi
sta l_d ; d += bi;
jmp _reszta
;else [d>0]
_else
; // przejście NE
LDA l_y1
CLC
ADC l_yi
sta l_y1 ;y1 += yi;
LDA l_d
CLC
ADC l_ai
sta l_d ; d += ai;
;end else
_reszta
LDA l_x1
CLC
ADC l_xi
sta l_x1 ; x1 += xi;
;;// putpix(x1,y1);
jsr debug
jmp whx1rx2 ; (petla while)
jmp l_end
;// os wiodaca OY (dy > dx)
wiod_oy
;ai
LDA l_dx
SEC
SBC l_dy
CLC
ROL ;a
STA l_ai ; ai = (dx-dy)*2
;bi
LDA l_dx
CLC
ROL ;a
STA l_bi ; bi = dx * 2
;d
LDA l_bi
SEC
SBC l_dy
STA l_d ; d = bi - dy
why1ry2 ;// while (y1 != y2)
LDA l_y1
CMP l_y2
BEQ l_end
; if (d > 0)
; then
LDA l_d
CMP #0
BEQ _b
BPL _elsey
_b ; <0
LDA l_d
CLC
ADC l_bi
sta l_d ; d += bi;
jmp _resztay
;else [d>0]
; // przejście NE
_elsey ; >0
LDA l_x1
CLC
ADC l_xi
sta l_x1 ;x1 += xi;
LDA l_d
CLC
ADC l_ai
sta l_d ; d += ai;
;end else
_resztay
LDA l_y1
CLC
ADC l_yi
sta l_y1 ; y1 += yi;
;;// putpix(x1,y1);
jsr debug
jmp why1ry2
; koniec
l_end
RTS
; PUTPIXEL should be called instead of this debug stuff for 6502sim
debug ;rts
LDY #10
STy io_putc
LDy #13
STy io_putc
LDY l_x1
STy io_puth
LDy #' '
STy io_putc
LDy l_y1
STy io_puth
rts