• Welcome to Dark Bit Factory & Gravity.
 

Drawing a Line

Started by Phoenix, August 13, 2006

Previous topic - Next topic

0 Members and 0 Guests are viewing this topic.

Phoenix

Hi!

I'm trying to write an ASM macro which draws a line, but it seems like I'm just drowning myself in useless lines - it's harder than I thought. You must calculate the angle of the line, distance, and where to put the pixels. If you have a little code snippet then feel free to share ;), because I could use some help here.

Thanks,
Martin

Phoenix

Ohh, I think I got it. I'm just going to finish it...

Phoenix

Hmm... I followed this tutorial, and made it to ASM, but it doesn't work. It only draws a dot at the end point, and not a line from source->destination. Here's my code:
; Draws a line bewtween the source x/y and destination x/y parameters
macro DrawLine sx, sy, dx, dy
{
        local deltax ; Width
        local deltay ; Height
        local x      ; Current drawing point's x coordinate
        local y      ; Current drawing point's y coordinate
        local f      ; Frequency decides when to change the y coordinate

        ; Set up the frequency
        mov al, 2        ; Set up the al register for multiplication
        mov ah, [deltay] ; Change the ah register to the value of deltay
        mul ah           ; Multiply by 2
        sub ah, [deltax] ; Subtract the value of deltax

        jmp draw
        ; Define locals
        deltax db dx - sx
        deltay db dy - sy
        x db sx
        y db sy
        f db 0

        draw:
        mov [f], ah ; Set the frequency

        mov ah, 0Ch ; Put pixels
        ; Repeat through the line pixel by pixel
        repeat deltax
               ; Put pixel
               mov dh, [x] ; X-axis
               mov ch, [y] ; Y-axis
               mov al, 255 ; Color (White)
               int 10h     ; Perform

               ; Update coords
               if f < 0
                  mov bl, [deltay] ; Stick deltay into bl
                  mov al, 2        ; Change the multiplication factor
                  mul bl           ; Multiply bl (deltay) with 2
                  add f, bl        ; Add it to the frequncy
               else
                  mov bl, [deltay] ; Stick deltay into bl
                  sub bl, [deltax] ; Subtract deltax from bl (deltay)
                  mov al, 2        ; Change the multiplication factor
                  mul bl           ; Multiply es (deltay) with 2
                  add [f], bl      ; Add it to the frequency
                  inc [y]          ; Increase the y variable
               end if

               inc [x] ; Increase the x variable
        end repeat


}


edit: Shockwave, can you change the codeboxes so that they use a font like courier new, the current font messes up my indentation

Rbz

Can you provide the full source, with screen initializations etc ?
Challenge Trophies Won:

Phoenix


org 100h
mov ax, 13h
int 10h

; * * * * * * * * * * * * * * * * * * * ;
; Macros                                ;
; * * * * * * * * * * * * * * * * * * * ;
; Draws a line bewtween the source x/y and destination x/y parameters
macro DrawLine sx, sy, dx, dy
{
        local deltax ; Width
        local deltay ; Height
        local x      ; Current drawing point's x coordinate
        local y      ; Current drawing point's y coordinate
        local f      ; Frequency decides when to change the y coordinate

        ; Set up the frequency
        mov al, 2        ; Set up the al register for multiplication
        mov ah, [deltay] ; Change the ah register to the value of deltay
        mul ah           ; Multiply by 2
        sub ah, [deltax] ; Subtract the value of deltax

        jmp draw
        ; Define locals
        deltax db dx - sx
        deltay db dy - sy
        x db sx
        y db sy
        f db 0

        draw:
        mov [f], ah ; Set the frequency

        mov ah, 0Ch ; Put pixels
        ; Repeat through the line pixel by pixel
        repeat deltax
               ; Put pixel
               mov dh, [x] ; X-axis
               mov ch, [y] ; Y-axis
               mov al, 255 ; Color (White)
               int 10h     ; Perform

               ; Update coords
               if f < 0
                  mov bl, [deltay] ; Stick deltay into bl
                  mov al, 2        ; Change the multiplication factor
                  mul bl           ; Multiply bl (deltay) with 2
                  add f, bl        ; Add it to the frequncy
               else
                  mov bl, [deltay] ; Stick deltay into bl
                  sub bl, [deltax] ; Subtract deltax from bl (deltay)
                  mov al, 2        ; Change the multiplication factor
                  mul bl           ; Multiply es (deltay) with 2
                  add [f], bl      ; Add it to the frequency
                  inc [y]          ; Increase the y variable
               end if

               inc [x] ; Increase the x variable
        end repeat


}

; * * * * * * * * * * * * * * * * * * * ;
; Main                                  ;
; * * * * * * * * * * * * * * * * * * * ;
DrawLine 100,100,200,200
mov ah, 01
int 21h
int 20h

Jim

This is crazy :o code for drawing a line!  It looks like Bresenham's line algorithm, but it's done badly.  One problem is, every time you write 'drawline' in your code it's going to splat in this whole routine into your file, and it can only ever draw that one line form those two endpoints! :o
I found this article http://www.gamedev.net/reference/articles/article767.asp which goes through Bresenham's line drawing algorithm with some explanation, and plenty of code to look at.  I supect there are better links.  Google 'Bresenham' for line drawing code.

Jim
Challenge Trophies Won:

Phoenix

Hehe, that's the article I followed. But I've never done any line algorithms before, so it's not a surprise that it's done badly. But do you mean that I should shrink it? Maybe I could remove all those local variables & definitions and place them at the bottom of the code instead?

Jim

I got a bit ahead of myself, you want it to work before doing anything I've posted below.
But the problem is, I don't know which assembler you're using that will actually assemble that code. :-\

To fix that, make it a function, so it doesn't duplicate the code for each line you want to draw.  So you pass it the end points in
ax,bx,cx,dx.  Get rid of all the macro stuff, end, repeat, if, local.  Make it look more like the very last routine in the tutorial link I posted.

Try moving x,y,deltax,deltay and f into registers.

Also notice that

shl bx,1

is the same as

mov al,2
mul bl

That should clarify things a bit.  This works in the same way that adding a 0 to a decimal number multiplies by 10, adding a 0 to a binary number multiplies by 2.

Jim
Challenge Trophies Won:

Jim

I think I've found the original problem

        mov ah, 0Ch ; Put pixels
        ; Repeat through the line pixel by pixel
        repeat deltax
               ; Put pixel
               mov dh, [x] ; X-axis
               mov ch, [y] ; Y-axis
               mov al, 255 ; Color (White)
               int 10h     ; Perform


int 10h function 0Ch is described here http://www.ctyme.com/intr/rb-0104.htm

It's expecting cx and dx for the pixel positions.  You're filling in ch and dh, so everything is 256x too big.

Try making it

xor dx,dx
xor cx,cx
mov dl,[x]
mov cl,[y]


Does that make any difference?

Jim
Challenge Trophies Won:

relsoft

Ints to plot pixels is bad

Try a direct memory access starting from 0a00h
Challenge Trophies Won:

Agent Smith

I think you mean 0a000h

Phoenix

I'm using FASM, and I'm only an ASM novice, so I don't know what you mean by using direct memory access starting from 0a000h. Anyway, I'm rewriting it now, but what's wrong with macros, ifs, and repeats?

Agent Smith

#12
?

Rbz

@Phonix, try something like that to draw a pixel on screen (compile with fasm), and use function to create your line draw as Jim suggested.



;
;   --------------
;   Kryton Advetro
;   --------------
;
;                by Rbraz ^ Gravity
;                April 2006
;

org 100h

;-------------VGA mode X - 320x200x256k
mov al,13h
int 10h
push 0a000h   ; Vga memory
pop es        ;

;-------------Load Palette
  mov  cl,63
  mov  bl,126
.pal:
  mov  dx,3c8h
  mov  al,bl  ;[ col ]
  dec  bl
  out  dx,al
  inc  dx
  mov  al,0   ;[ r ]
  out  dx,al
  mov  al,0   ;[ g ]
  out  dx,al
  mov  al,cl  ;[ b ]
  out  dx,al
  loop .pal

;-------------Write our text
  mov  ah,02h
  mov  bh,00h
  mov  dx,0308h
  int  10h
  mov  ah,9
  mov  dx,text
  int  21h

Main:

;-------------Wait for vertical retrace
mov dx,03DAh
.wait_for_retrace:
in al,dx
test al,8
jz .wait_for_retrace

;-------------Blur Screen
mov di,16000
mov cx,8000
.blur:
mov eax,[es:di]
cmp eax,40404040h
jle .noblur
sub eax,01010101h
.noblur:
stosd
loop .blur

;-------------Sine wave function
fld   [angle]
fadd  [one]
fst   [angle]
fdiv  [twopi]
fsin
fmul  [mult]
fadd  [ center ]
fistp [y]

.draw:

mov ax,word [y] ; ax = y
mov bx,[x]      ; bx = x

;-------------WritePixelFast :)
; vgamemory[x + (y*320)] = color ; bx=x, ax=y, cl=color
imul ax,320
add ax,bx
mov di,ax
mov byte [es:di],126   ; color

;-------------Increments x pos
inc [x]
cmp [x],320
je .lp1
jmp .draw
.lp1:
mov [x],0
; mov [angle],0


;-------------Loop (While not key hit)
mov ah,01
int 16h
jz Main

;-------------Return to text mode
mov al,03h
int 10h

;-------------Exit to DOS
mov ax,4c00h
int 21h

;-------------Some variables
angle   dd 0.0
one     dd 0.25
mult    dd 20.0
center  dd 100.0
y       dd 0.0
x       dw 0
twopi   dd 6.2830
text db 'Kryton >> Coming up soon!',24h
Challenge Trophies Won:

Jim

QuoteI'm using FASM, and I'm only an ASM novice, so I don't know what you mean by using direct memory access starting from 0a000h.
Segment a000h is where the screen memory starts.  In the mode you're using, there is 64Kb there, 320bytes wide, 200bytes high.
To write a pixel, you can poke into that memory.

;com file
org 100h

;screen mode 13h
mov ax,013h
int 10h

;point ds segment register at screen
mov ax,0a000h
mov ds,ax

;colour 255
mov al,255

;pixel address (320*y+x)
mov si,320*100+160

;write pixel
mov [si],al

;wait for a key
wait:
mov ah,01
int 016h
jz wait

;text mode
mov ax,03h
int 10h

;exit to dos (actually, ret is fine for .com programs)
mov ax,4c00h
int 21h


Fiddle around with the value in si (0-63999) to move the pixel and the colour in al (0-255)

Jim
Challenge Trophies Won:

Phoenix

Thanks for your help, I'll try it later...