Vistas de página en total

jueves, 20 de marzo de 2014

FUNCIÓN LINEA



Las dos funciones más importantes gráficas son: el circulo y la recta. A partir  de ellas podremos generar el resto de funciones.
   En las entradas anteriores he colocado la función básica de putpixel, para dibujar un punto, con la cual se podrán generar el resto de las funciones. En este caso he usado, por comodidad la Int 10h de la Bios., pero si alguien quiere puede hacer un putpixel directamente sobre memoria de pantalla. Esta modificación no influirá en el resto de las funciones ya que si se hace el putpixel de forma equivalente, el resto de las funciones seguirán siendo válidas.

    La recta es una función en principio compleja si la queremos hacer sin usar operaciones matemáticas complejas.
     Actualmente, debido a que los ordenadores son potentes, y se trabaja en alto nivel, a cualquiera que se le proponga hacer una recta mediante pixel, utilizará la ecuación de la recta y a correr. Pero si trabajamos en ensamblador, bien sea el que estamos usando, o sea un microcontrolador, de manera que deseemos trazar una línea en un papel mediante motores paso a paso, resulta problemático usar coma flotante.
     En 1965 Bresenham creó unos algoritmos de aproximación para la recta y los círculos, los cuales son capaces de trazar una recta usando solo operaciones incrementales y  operaciones básicas de  ensamblador como multiplica por 2 y sumar.
     Este es el algoritmo que he utilizado en esta función. Este algoritmo es válido solo si la pendiente es mayor de cero y menor de infinito. Es decir no sirve para rectas horizontales y verticales.
   Por lo tanto estos dos casos son tratados de forma independiente.
   Además hay que tratar el caso de trazar la recta en los dos sentidos, para lo cual lo que realizamos es una comprobación del sentido para poner los incrementos (pasox y pasoy) en +1 o -1 según convenga.
   Además el algoritmo solo sirve para un cuadrante, es decir no es lo mismo si la recta aumenta más deprisa en x que en y que si la recta aumenta más deprisa en y que en x. Por ello hay que verificar si Δx> Δy y tomar un algoritmo diferente.

   Como el algoritmo lo podréis encontrar en internet, pero nunca en ensamblador, he decidido hacer un ejercicio de interpretación muy elegante.
    Os he colocado como comentario a la derecha el código equivalente en “C”. Es decir he puesto el código en ensamblador, traduciéndolo a “C”. Esto servirá a muchos para entender el algoritmo, pero a muchos más, para saber cómo codificar en ensamblador  cada directiva de “C”.
    Esto que he hecho, para mi es super sencillo, porque yo comencé con desensamblar y luego pase a “C”, pero me imagino que para los programadores actuales, acostumbrados a lenguajes de alto nivel, es muy difícil hacerse una idea de cómo traducir el “C” a ensamblador.
    En este caso, yo he tomado el algoritmo en “C” y lo he traducido a ensamblador. Esto se puede hacer con cualquier pseudocódigo, por lo que esta entrada es una forma de enseñar este proceso.
   El conjunto de la librería estará formado por una macro, que deberá ser añadida a las cabeceras GRAPHICS.MAC,  que puse antes, y una función, que deberá ser compilada y añadida a la librería mediante TLIB. Así tendremos lista esta función para el futuro. Será usada como una instrucción más, y no tendremos que volver a compilarla, ni a preocuparnos de ella.
   Si se introduce, como yo hago, dentro de una librería, y siempre usamos esa librería, la función será transparente en  nuestras aplicaciones. Podéis ver cómo hacerlo en la pestaña COMPILAR del blog.
    Con esta función podremos realizar el rectangle y el fillrectangle, que pondré en la siguiente entrada.


    Más infornmación sobre el algoritmo  Aquí



GRAPHICS.MAC
;Dibuja una línea
line macro x0,y0,x1,y1,color
ifndef _line
        extrn _line:near
endif
        mov ax,x0
        push ax
        mov ax,y0
        push ax
        mov ax,x1
        push ax
        mov ax,y1
        push ax
        mov ax,color
        push ax
        call _line
       
 endm  





LINEA.ASM

; Copyright (C) 2013  José Ángel Moneo Fernández

;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.

;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.

;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.




include graphics.mac


.model compact,pascal

        public _line
.data


incE   dw 0
incNE dw 0


deltax dw 0    ;
deltay dw 0

pasox dw 0     ;paso en x
pasoy dw 0     ; paso en y

p dw 0     ;variable p procedimiento breshenham

x0 dw 0    ;parametros pasdados a linea
y0 dw 0    ;usado por todas las rutinas
x1 dw 0
y1 dw 0
color dw 0
.code
       ;algoritmo Bresenham
_line proc uses ax,px0,py0,px1,py1,pcolor
        ;paso de las variables de función a varialbes globales
        ;para uso en todas las rutinas
        mov ax,px0
        mov x0,ax
        mov ax,py0
        mov y0,ax
        mov ax,px1
        mov x1,ax
        mov ax,py1
        mov y1,ax
        mov ax,pcolor
        mov color,ax
       
       ;deltay=abs(yfinal-yinicial)
        mov ax,y1
        sub ax,y0               ; deltay=(y1-y0)
        jns  else_positivo1      ;if (deltay<0)
        neg ax                        ;{abx(deltay)
        mov pasoy,-1                  ;pasoy=-1
        jmp end_positivo1             ;}
else_positivo1:                  ;else
        mov pasoy,1                    ;pasoy=1
end_positivo1:
        mov deltay,ax           ; deltay=abs(y1-y0)
       
        ;deltax=abs(xfinal-xinicial)
        mov ax,x1
        sub ax,x0                ; deltax=(x1-x0)
        jns  elsepositivo2       ;if (deltax>0)
        neg ax                       ;{abx(deltax)
        mov pasox,-1                 ;pasox=-1
        jmp end_positivo2            ;}
elsepositivo2:                    ;else
        mov pasox,1                   ;pasox=1
end_positivo2:

        mov deltax,ax             ; deltax=abs(x1-x0)
        cmp ax,0                  ;if(deltax==0)
        jne no_vertical                  ;{
        call _linea_vertical      ;linea_vertical
        jmp fin_linea                        ;}
no_vertical:

        mov ax,deltay
        cmp ax,0                        ;if(deltay==0)
        jne no_horizontal                   ;{
        call _linea_Horizontal      ;linea_horizontal
        jmp fin_linea                      ;}
no_horizontal:
        
  ;resto de lineas mediante algoritmo Bresenham
        mov ax,deltax
        cmp ax,deltay                    ;if(deltax>deltay)
        jna alg2
        call _algoritmo1    ; algoritmo1
        jmp fin_linea
alg2:                                   ;else
        call _algoritmo2     ;algoritmo2
fin_linea:
        ret
_line endp

_linea_vertical proc uses ax bx cx dx
        mov bx,x0         ; x=x0
        mov dx,y0         ; y=y0
        mov cx,y1         ; yend=y1

while_vert:     
        cmp dx,cx               ;while (y!=yend)
        je fin_vert                  ;{
        putpixel bx,dx,color   ;pixel x,y
        add dx,pasoy                 ;y+=pasoy
        jmp while_vert
       
fin_vert:
        ret
_linea_vertical endp

_linea_horizontal proc uses ax bx cx dx
        mov bx,x0         ; x=x0
        mov dx,y0         ; y=y0
        mov cx,x1         ; xend=x1
      
while_hor:     
        cmp bx,cx               ;while (x!=xend)
        je fin_hor                  ;{
        putpixel bx,dx,color   ;pixel x,y
        add bx,pasox                 ;x+=pasox
        jmp while_hor
       
fin_hor:
        ret
_linea_horizontal endp


 ;si deltax>deltay
_algoritmo1 proc uses ax bx cx dx
        ;p=2*deltay-deltax
        mov ax,deltay         
        shl ax,1     
        mov incE,ax                 ;incE=2*deltay        
        sub ax,deltax          
        mov p,ax                    ;p=2*deltay-deltax 
         
        ;incNE=2*(deltay-deltax)
        mov ax, deltay
        sub ax,deltax
        shl ax,1
        mov incNE,ax                 ;incNE=2*(deltay-deltax)
         

        mov bx,x0         ; x=x0
        mov dx,y0         ; y=y0
        mov cx,x1         ; xend=x1

while1:     
        cmp bx,cx               ;while (x!=xend)
        je fin1                  ;{
        putpixel bx,dx,color   ;pixel x,y
        add bx,pasox                 ;x+=pasox
       
        mov ax,p
        cmp ax,0              ; if(p<0)
        jns else_if1
        add ax,incE
        mov p,ax              ;p+=incE
        jmp short end_if1
else_if1:                     ;else
        add ax,incNE
        mov p,ax             ;p+=incNE
        add dx,pasoy                ;y+=pasoy
end_if1:        
        jmp while1            ;}        
fin1:       
        ret
_algoritmo1 endp

;si deltay>deltax
 _algoritmo2 proc uses ax bx cx dx
        ;p=2*deltax-deltay
        mov ax,deltax         
        shl ax,1   
        mov incE,ax                 ;incE=2*deltay           
        sub ax,deltay          
        mov p,ax                    ;p=2*deltax-deltay 
        
        ;incNE=2*(deltax-deltay)
        mov ax, deltax
        sub ax,deltay
        shl ax,1
        mov incNE,ax                 ;incNE=2*(deltax-deltay)
         

        mov bx,x0         ; x=x0
        mov dx,y0         ; y=y0
        mov cx,y1         ; yend=y1
while2:         
        cmp dx,cx               ;while (y!=yend)
        je fin2                  ;{
        putpixel bx,dx,color   ;pixel x,y
        add dx,pasoy                ;y+=pasoy
       
        mov ax,p
        cmp ax,0              ; if(p<0)
        jns else_if2
        add ax,incE
        mov p,ax              ;p+=incE
        jmp short end_if2
else_if2:                     ;else
        add ax,incNE
        mov p,ax             ;p+=incNE
        add bx,pasox              ;x+=pasox 
end_if2:        
        jmp while2            ;}        
fin2:       
        ret
_algoritmo2 endp
end

No hay comentarios:

Publicar un comentario

Si tienes algún comentario, duda o sugerencia, o si quieres aportar algún código creado a partir de las librerías expuestas aquí, por favor, indícamelo.