Vistas de página en total

domingo, 30 de marzo de 2014

EJEMPLO TRAZADO DE CIRCULOS

  Este programa es un ejemplo de ejecución de la librería gráfica de circulos.
   Lo más complejo de esta rutina es calcular el radio de la circunferencia a partir de dos puntos seleccionados en pantallas.
   Para ello, utilizo el teorema de pitágoras, y apoyándome en las funciones matemáticas puestas anteriormente calculo el radio.   Esto lo programé ya en la función puesta anterirometne dist_pixel.

   En este caso para que quede3 más elegante, el programa incrementa el color por cada circulo.

                       

     Se puede bajar el ejemplo compilado en el enlace





EJ_CIRCL.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 main.mac
include stdio.mac
include mouse.mac
include graphics.mac
include math.mac

.model compact,pascal
.stack 200

.data
x0 dw 100
y0 dw 100
x1 dw 90
y1 dw 90
radio dw 0,0

color dw 1

.code

principal proc far
        main
        modovideo 12h   ;inicia graficos
        resmouse         ;reinicia ratón
        mouse on         ; activa rarón
    
punto1:
        getmouse        ;espera  EST+ SIN PULSAR
        cmp ax,0
        jne punto1
pulsar1:      
        getmouse         ;verifica espera pulsación raton
        cmp ax,2      ;salir?
        jne sig1
        jmp fuera
sig1:      
        cmp ax,1      ;boton izquierdo?
        jne pulsar1
        getmousex
        mov x0,ax
        getmousey
        mov y0,ax
punto2:
        getmouse        ;espera soltar
        cmp ax,0
        jne punto2
pulsar2:     
        getmouse         ;verifica espera pulsación raton
        cmp ax,2      ;salir?
        jNe sg1
        JMP FUERA
SG1:      
        cmp ax,1      ;boton izquierdo?
        jne pulsar2
        getmousex
        mov x1,ax
        getmousey
        mov y1,ax
        dist_pixel x0,y0,x1,y1
     
        mov radio,ax

        mouse off
        mov ax,color        ;incremeta color en cada circulo
        inc ax
        and ax,0fh
        mov color,ax
      
        circle x0,y0,radio,color
        mouse on
      
        jmp punto1
fuera:
        modovideo t80col
        resmouse
        mouse off
        exit  0
principal endp

end

viernes, 28 de marzo de 2014

DISTANCIA ENTRE DOS PIXEL

    Para poder realizar el ejemplo con circulos, necesito poder pasar a la función circle el radio, tomandolo de la posición dadapor el ratón. Es decir el primer punto que elija con el ratón será el origen del circulo y el  segundo punto será un extremo que definirá el radio.
   Por lo tanto necxesitamos una funcion que nos permita calcular la distancia desde el primer punto al segundo, dado que esa distancia será el radio.
  
   Como esta acción es muy interesante para otras aplicaciones, nos conviene generar una rutina y no aplicar el algoritmo directamente al programa de ejemplo. Aunque lleve un poco más de trabajo valdrá la pena.





A añadir a GRAPHICS.MAC

;definición de la llamada a Dist_pixel
;se le pasan las coordenadas de dos puntos y devuelve en ax la distancia
Dist_pixel macro x0,y0,x1,y1
ifndef _dist_pixel
     extern _dist_pixel
endif
        mov ax,x0
        push ax
        mov ax,y0
        push ax
        mov ax,x1
        push ax
        mov ax,y1
        push ax       call _dist_pixel
endm



DPIXEL.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 math.mac

;mide la distancia entre dos pixel
;se le pasa las coordenadas de los dos puntos y nos devuenve en ax la distancia en pixel
    public _dist_pixel
model compact,pascal
.data
radio dw 0,0
ix dw 0,0    ;valor absoluto incremento x
iy dw 0,0     ; valort absoluto incremento de y
ix2  dw 0,0  ; cuadrado del incremento x
iy2  dw 0,0  ;cuadrado del incremento y
.code
_dist_pixel proc uses ,x0,y0,x1,y1

        mov ax,y1
        sub ax,y0        ;(y1-y0)
        abs ax         
        mov iy,ax        ;dy=abs(y1-y0)
        pot iy,2,iy2     ;dy2=dy^2
        mov ax,x1
        sub  ax,x0      ;(x1-x0)2
        abs ax         
        mov ix,ax        ;dx=abs(x1-x0)
        pot ix,2,ix2     ;dx2=dx^2
      
        suma ix2,iy2,radio     ;(y1-y0)^2+(x1-x0)^2  
      
        sqr radio
        ret
_dist_pixel endp

end

miércoles, 26 de marzo de 2014

CIRCLE

   Siguiendo las funciones gráficas, la siguinete depues de la línea en impritancia es el circulo.
Al igual que he hecho con la línea utilizaré el algoritmo de Bresenham.

 
  El pseudocódigo del algoritmo es:
 
*Se capturan el radio r y el centro de la circunferencia (xc, yc).
 *Se obtiene el primer punto de la circunferencia centrada en origen (xc, yc) como (0, r).
 *Se cacula el valor inicial del parametro de decisión como p0=5/4 - r.
 Para k=0 hasta x>=y incrementa k
    Si pk < 0 
       *Siguiente punto de la circunferencia con centro (0,0) es (xk+1, yk).
       *pk+1=pk+2xk+1+1.
    Sino
        *Siguiente punto de la circunferencia con centro (0,0) es (xk+1, yk-1).
       *pk+1=pk+2xk+1+1-2yk+1.
    //Donde 2xk+1=2xk+2  y  2yk+1=2yk-2
 
 *Se determinan los puntos de simetría para los otros siete octantes.
 *Se mueve cada posición del pixel calculada (x,y) a la trayectoria circular centrada en (xc, yc) 
   y trazamos los valores de las coordenadas: x=x+xc y y=y+yc.
 Fin Para

   Fuente wikipedia.

     Aquí teneis la implementación del algoritmo en ensamblador, comentado en C, para que sirva de entreanmiento a la hora de codificar en lenguaje ensamblador otros algoritmos.




CIRCLE.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 _circle
.data

e dw 0     ;variable p procedimiento breshenham


.code
       ;algoritmo Bresenham
_circle proc uses ax bx dx si di,x0,y0,radio,color
        mov bx,0     ;x=0
        mov dx,radio      ;y=radio
        mov cx,dx   ;e=radio
        neg cx       ;e=-radio
        add cx,1    ; e=1-radio

      
while:        ;while (x<y)
        cmp bx,dx
        jb sig
        jmp fin
sig:
        call _dibuja8   ;dibuja en los 8 octantes
        inc bx       ;x=x+1
        cmp cx,0    ;if (e>0)
        jl else_if
        dec dx       ;y=y+1
        mov ax,bx
        sub ax,dx   ;x-y
        shl ax,1    ;(x-y)*2
        add ax,1  ;1*(x-y)+1
        add cx,ax    ;e=e+ 2*(x-y)+1
        jmp fin_if
else_if:
        mov ax,bx
        shl ax,1
        add ax,1         
        add cx,ax   ;e=e+2*x+1
fin_if:
     
        jmp while      
fin:
        ret
_circle endp 

;dibuja el punto en cada octante, referido a la coordenada origen del circulo
_dibuja8 proc
        mov si,bx          
        add si,x0           ;xc=x+x0
        mov di,dx          
        add di,y0           ;yc=y+y0
        putpixel si,di,color    ;pixel(x+x0,y+y0)
        mov si,dx          
        add si,x0           ;xc=y+x0
        mov di,bx          
        add di,y0           ;yc=x+y0
        putpixel si,di,color    ;pixel(y+x0,x+y0)
        mov si,bx             
        neg si
        add si,x0            ;xc=-x+x0
        mov di,dx          
        add di,y0           ;yc=y+y0
        putpixel si,di,color          ;pixel(-x+x0,y+y0)
        mov si,dx          
        add si,x0           ;xc=y+x0
        mov di,bx             
        neg di
        add di,y0               ;yc=-x+y0
        putpixel si,di,color           ;pixel(y+x0,-x+y0)
        mov si,bx             
        neg si
        add si,x0               ;xc=-x+x0
        mov di,dx 
        neg di              
        add di,y0               ;yc=-y+y0
        putpixel si,di,color          ;pixel(-x+x0,-y+y0)
        mov si,dx 
        neg si              
        add si,x0               ;yc=-y+x0
        mov di,bx             
        neg di
        add di,y0               ;xc=-x+y0
        putpixel si,di,color           ;pixel(-y+x0,-x+y0)
        mov si,bx          
        add si,x0           ;xc=x+x0
        mov di,dx 
        neg di              
        add di,y0               ;yc=-y+y0
        putpixel si,di,color          ;pixel(x+x0,-y+y0)
        mov si,dx 
        neg si              
        add si,x0               ;yc=-y+x0
        mov di,bx          
        add di,y0           ;yc=x+y0
        putpixel si,di,color           ;pixel(-y+x0,x+y0)
        ret
_dibuja8 endp       

end

lunes, 24 de marzo de 2014

ACTUALIZACIÓN LIBRERÍA MATH

   Debido a que ahora vamos a necesitar alguna de las funciones matemáticas publicadas al comienzo del blog, y a que ya nos encontramos programando sobre TASM2.0, voy a refrescar estas librerías, pasando al nuevo fromato de código y comentándolas un poco más.

     Estas librerías son necesarias para realizar el progra,a de ejemplo de circulo que pondré más adelante. Para poder determinar el centro y radio de un circulo a partir de dos pintos elegidos por el ratón en pantalla.
    no pongo todas. Solo las que usaré para realizar un ejemplo como el de dibujos de líneas con el ratón, pero de circulos.
  En este caso, como se trata de refrescar algo que ya he puesto, pondré en unas sola entrada la definición de la cabecera y de cada una de las librerías.

; 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/>.


Cabecera matemática

MATH.MAC
@b = 2
@o = 8
@d = 10
@h = 16

;valor absoluto del dato 16bits
abs macro dato
local positivo
        add dato,0       
        jns  positivo1    
        neg dato
endm

;suma datos 32bits
suma macro ope1,ope2,res
ifndef _suma
       extrn _suma:near
endif
        lea ax,ope1
        push ax
        lea ax,ope2
        push ax
        lea ax,res
        push ax
        call _suma

     endm
    
;resta datos 32bits    
resta macro ope1,ope2,res
ifndef _resta
       extrn _resta:near
endif
        lea ax,ope1
        push ax
        lea ax,ope2
        push ax
        lea ax,res
        push ax
        call _resta

     endm


;multiplica dato 32 bits
mult macro ope1,ope2,res
ifndef _mult
       extrn _mult:near
endif
        lea ax,ope1
        push ax
        lea ax,ope2
        push ax
        lea ax,res
        push ax
        call _mult

     endm
    
    
;divide dato 32 bits    
divi macro ope1,ope2,res
ifndef _divi
       extrn _divi:near
endif
        lea ax,ope1
        push ax
        lea ax,ope2
        push ax
        lea ax,res
        push ax
        call _divi

     endm
    
    
;sqr devuelve en ax el resultado de la raiz de 32 bits
sqr macro oper
ifndef _sqr
        extrn _sqr:near
endif
        lea ax,oper
        push ax
        call _sqr

      endm

;factorial numeros de 32bits
;fac calcula el factorial del int fuente y lo devuelve en destino
fac macro fuente,destino
ifndef _fac
       extrn _fac:near
endif
        lea ax,fuente
        push ax
        lea ax,destino
        push ax
        call _fac

  endm
 
;potencia numeros de 32bits
;fuente es un puntero de una variable de 16 bits
;potencia es una variable de 16 bits
;destino es un puntero a una variable de 32 bits
;pot calcula x a la n siendo x=fuente,n=potenc y devuelve el resultado en destino
pot macro fuente,potenc,destino
ifndef _pot
       extrn _pot:near
endif
        lea ax,fuente
        push ax
        mov ax,potenc
        push ax
        lea ax,destino
        push ax
        call _pot

  endm
 
;exp numeros de 32bits 
exp macro potenc,destino
ifndef _exp
       extrn _exp:near
endif
        lea ax,potenc
        push ax
        mov ax,destino
        push ax
        call _exp

  endm

;compara numeros de 32bits
cmpi macro destino,fuente
local fin

     push ax
     mov ax,fuente+2
     cmp destino+2,ax
     jne fin
     mov ax,fuente
     cmp destino,ax
 fin:
     pop ax
     endm






Librerías Matemáticas

POT.ASM

; eleva un úmero de 16 bits a otro número dando el resultado en un número de 32 bits
;op1 puntero a varialbe de 16 bits
;op2 numero de 16 bits
;res puntero a variable de 16 bits
model compact,pascal

.code
      public _pot
_pot proc uses bx di cx,op1,op2,res
      extrn _mult:near

 mov cx,op2
        mov bx,op1
        mov di,res
        mov word ptr [di],1
        mov word ptr [di+2],0
 otro:
        cmp cx,0
        jz fin
        push bx
        push bx
        push di
        call _mult
        dec cx
        jmp otro
   fin:
               ret
_pot endp

end


MULT.ASM
;multiplica dos numeros de 32 bits  y el resultado lo lleva a otro de 16 bits
;op1 puntero a nuemro de 32 bits
;op2 puntero a nuemro de 32 bits
;res puntero a número de 32 bits
; multiplica en formato de 32 bits, pero el resultado debe de ser como máximo de 32 bits
;multiplica número sin signo.
.model compact,pascal

.code    
       public _mult
_mult proc uses bx dx cx si di,op1,op2,res
        mov si,op1
        mov bx,op2
        mov di,res
        mov ax,[bx+2]
        push ax
        mov ax,[si]
        push ax
        mov ax,[si]
        mov cx,[bx]
        mul cx
        mov [di],ax
        push dx
        mov ax,[si+2]
        mul cx
        pop dx
        add ax,dx
        mov [di+2],ax
        pop ax
        pop cx
        mul cx
        add [di+2],ax

        ret
_mult endp

end




SUMA.ASM
; codigo
;suma dos números de 32 bits
;sum1 puntero a variable de 32 bits
;sum2 puntero a varialbe de 32 bits
;res puntero a variable de 32 bits
.model compact,pascal
.code
        public _suma
_suma proc uses bx si di,sum1,sum2,res

        mov si,sum1
        mov bx,sum2
        mov di,res
        mov ax,[si]
        add ax,[bx]
        mov [di],ax
        mov ax,[si+2]
        adc ax,[bx+2]
        mov [di+2],ax

        ret
_suma endp

end



SQR.ASM

INCLUDE MATH.MAC
; raiz cuadrada. devuelve en ax el resultado
;Calcula la raiz de un número de 32 bis
; p1 puntero a variable de 32 bits
;El valor de una raíz cuadrada lo vamos a ir a aproximando de está forma:
; Para una raiz N, y teniendo una aproximación APROX, mi siguiente aproximación va a ser igual a:
;APROX = APROX - (APROX ^2 - N) / (2 * APROX)
;Este proceso lo repetimos hasta que la aproximación no cambie, o cuando los cambios de ésta sean mínimos (depende de que tan precisa quieres la raíz)
;SOLO PODREMOS CALCULAR RAICES DE NUMEROS HASTA 4.294.836.225, YA QUE EL RESULTADO DE LA RAIZ LO DEVOLVEREMOS EN AX

model compact,pascal
.data 
APROX DW 0,0
AAPROX DW 0,0
APROX2 DW 0,0
APROX3 DW 0,0
APROX4 DW 0,0
N DW 0,0

.code
      public _sqr
_sqr proc uses bx CX si,p1

        mov bx,p1   ;SE RECOGE EL PUNTERO A LA VARIBLE
        mov si,offset N     ; SE ASIGNA SI AL PUNTERO A LA VARIALBE N
        mov ax,[bx]       ;COPIAMOS EL DATO PASADO 
        mov [si],ax        ;N=P1
        mov ax,[bx+2]
        mov [si+2],ax
        MOV CX,2          ;MULTIPLICADOR 2
        ;COMIENZA LA ITARACIÓN
        mov AX,1       ;APROX=1
    sig:        
        MOV APROX,AX
        MUL CX       ;2*APROX
        MOV AAPROX,AX
        MOV AAPROX+2,DX
        POT APROX,2,APROX2         ;APROX^2
        RESTA APROX2,N,APROX3
        DIVI  APROX3,AAPROX,APROX4
        MOV AX, APROX
        SUB AX, APROX4
        CMP AX, APROX
        jne sig
  

        ret
_sqr endp

end



DIVI.ASM
;; solo divide por numeros menores de ffffh
title dividir
include main.mac

.model  compact,pascal
.data 
aux dw 0,0
.code
      public _divi
_divi proc uses bx dx cx si di,dividendo,divisor,resultado

        mov si,dividendo
        mov di,resultado
        mov bx,divisor
        mov word ptr [di+2],0
        mov word ptr [di],0
        xor dx,dx
        cmp word ptr [bx+2],0
        jz normal
        mov ax,[si+2]
        cmp ax,[bx+2]
        jb fin
        mov cx,[bx+2]
        div cx
        mov [di],ax
comprueba:
        mul word ptr [bx]
        mov aux,ax
        mov aux+2,dx
        mov ax,[di]
        mul word ptr [bx+2]
        add aux+2,ax
        mov ax,aux+2
        cmp ax,[si+2]
        ja no_cabe
        jne fin
        mov ax,aux
        cmp ax,[si]
        jbe fin
no_cabe:
        dec word ptr [di]
        mov ax,[di]
        jmp comprueba


  normal:
        mov cx,[bx]
        mov ax,[si+2]
        div cx
        mov [di+2],ax
        mov ax,[si]
        div cx
        mov [di],ax
   fin:

        ret
_divi endp





RESTA.ASM
; codigo
    public _resta
model compact,pascal

.code
_resta proc uses bx si di,min,subs,res

        mov si,min
        mov bx,subs
        mov di,res
        mov ax,[si]
        sub ax,[bx]
        mov [di],ax
        mov ax,[si+2]
        sbb ax,[bx+2]
        mov [di+2],ax

        ret
_resta endp


end


sábado, 22 de marzo de 2014

EJEMPLO TRAZADO LINEAS

   Para ir verificando que las funciones. Este es un pequeño programa que lee dos pulsaciones consecutivas del ratón, y toma las coordenadas de cada una de ellas, para trazar una recta que vaya desde el primer punto hasta el segundo.
    De esta forma podremos probar todas las posibilidades de la función recta, colocando en todas las posiciones y casos las rectas.
    Como solo es un ejemplo, no importa el color, y como en el resto de los ejemplos imprimo siemopre en color azul.


   El ejecutable podeis cargarlo directamente en  Ej_linea.exe 
   Recordad que está en gráficos de dos y necesitais en Windows7 hace falta un emulador de DOS como el DOSBOX, para ejecutarlo.


 EJ_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 main.mac
include stdio.mac
include mouse.mac
include graphics.mac

.model compact,pascal
.stack 200

.data
x0 dw 0
y0 dw 0
x1 dw 0
y1 dw 0

color dw 1

.code

principal proc far
        main
        modovideo 12h   ;inicia graficos
        resmouse         ;reinicia ratón
        mouse on         ; activa rarón
    
punto1:
        getmouse        ;espera  ESTÉ SIN PULSAR
        cmp ax,0
        jne punto1
pulsar1:      
        getmouse         ;verifica espera pulsación raton
        cmp ax,2      ;salir?
        jne sig1
        jmp fuera
sig1:      
        cmp ax,1      ;boton izquierdo?
        jne pulsar1
        getmousex
        mov x0,ax
        getmousey
        mov y0,ax
punto2:
        getmouse        ;espera soltar
        cmp ax,0
        jne punto2
pulsar2:     
        getmouse         ;verifica espera pulsación raton
        cmp ax,2      ;salir?
        je fuera
        cmp ax,1      ;boton izquierdo?
        jne pulsar2
        getmousex
        mov x1,ax
        getmousey
        mov y1,ax
             
      
        mouse off

      
        line x0,y0,x1,y1,color
        mouse on
        jmp punto1
fuera:
        modovideo t80col
        resmouse
        mouse off
        exit  0
principal endp

end





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

martes, 18 de marzo de 2014

PAINT BASICO

     Este programa es el comienzo de una serie de programas asociados a librerías más avanzadas de gráficos. Como ya teníamos la función putpixel hay que darle salida. por lo tanto usando la estrucutrac del pograma anterior, este programa coloca pixel en la posiciñon del ratón cuando el botón izquierdo de este está pulsado. esto lo que permite es realizar un Paint muy simple.

      Para mejorarlo deberemos crear la funicón line, ya que de esta manera no se verán los trazos discontinuos. Ese será el siguiente módulo de la librería graphics.
     En la siguiente entrada presentaré las funciones line, circle, y rectangle, fillrectangle, y fillcircle, con las que podremos dibujar las entidades más básicas de dibujo.
 
 
    Programa ejecutable  Ej_Pixel.exe


EJ_PAINT1.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 main.mac
include stdio.mac
include mouse.mac
include graphics.mac

.model compact,pascal
.stack 200

.data
letra db 0

color dw 1

.code

principal proc far
        main
        modovideo 12h   ;inicia graficos
        resmouse         ;reinicia ratón
        mouse on         ; activa rarón
        mov cx,0
ciclo: 
      
        getmouse         ;verifica espera pulsación raton
        cmp ax,2      ;salir?
        je fuera
        cmp ax,1      ;boton izquierdo?
        jne ciclo
        getmousex
        mov cx,ax
        getmousey
        mov dx,ax
        mouse off
        putpixel cx,dx,color
        mouse on
        jmp ciclo
fuera:
        modovideo t80col
        resmouse
        mouse off 
        exit  0
principal endp

end





domingo, 16 de marzo de 2014

EJEMPLO IMPRESIÓN. PAINT CON CARACTERES GRÁFICOS

  Como primer ejemplo del modo gráfico, voy a presentar un pequeño programa que tomando la posición del ratón como posición de impresion imprimirá la letra que estemos pusando en el teclado en pantalla. Esto solo lo hará si pulsamos el botón izquierdo del ratón.
   Se saldrá del programa pulsando el botón drecho del rarón.
   El resultado del programa es un paint que dibuja en la pantalla los trazos del ratón, pero con el caracter que tengamos pulsado en ese momento.



   Podeis descargar el programa ya compilado en  EJ_GRAF1.EXE 



EJ_GRAPH1.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 main.mac
include stdio.mac
include mouse.mac
include graphics.mac

.model compact,pascal
.stack 200      ;define el tamaño de pila

.data
letra db 0            ; almacenamiento de la letra actual a imprimir

color dw 1       ; color del texto

.code

principal proc far
        main                      ;inicializa programa
        modovideo 12h    ;inicia graficos
        resmouse            ;reinicia ratón
        mouse on             ; activa rarón
                   
ciclo: 
        kbhit                           ;comprueba si si pulsa el teclado
        jz sigue                                              
        getch letra                ; si se pulsó lee el bufer de teclado y lo guarda en letra
sigue:             
        getmouse         ;verifica espera pulsaci¾n raton

        cmp ax,2      ;salir?
        je fuera
        cmp ax,1      ;boton izquierdo?
        jne ciclo
        getmousex
        shr ax,3   ;convierte a posición caracter
        mov cl,al
        getmousey
        shr ax,4    ;convierte a posición caracter
        mov ch,al
        gotoxy  cl,ch
        mouse off
        putcharG letra  
        mouse on
        jmp ciclo
fuera:
        modovideo t80col          ;repone la pantalla texto
        resmouse                       ;resetea el rarón
        mouse off                     ;desactiva el ratón
        exit  0                          ;sale al sistema con código 0
principal endp

end









viernes, 14 de marzo de 2014

FUNCIONES GRÁFICAS BASICAS

   Algunas de las funciones introducidas en la macro GRAPHICS.MAC serán funciones implementadas mediante rutinas en la librería, bien porque son muy utilizadas y queremos ahorrar algunos bytes frente a las llamadas inline, o bién porque pensamos poder mejorarlas posterioremente sin tener que retocar la llamada.
    Como siempre mi filosofía es crear funciones con el mismo nombre que las macros, pero usando el caracter "_" delante.
    Como ya se ha visto, a mi no me gusta la función "invoke" del ensamblador, ya que impide una visión clara de la secuencia del programa  al llenar de palabras "invoke" el programa. Para entender un programa actual, hay que ir saltandose esta palabra, para llegar a leer el comando.
    Por ello, aunque lleve un poco más de trabajo, yo soy partidario de crear una definición de función, al igual que se haría en "C" en las cabeceres ".h". Esta definición hará la llamada a la función equivalente y nos permitirá trabajar directamente con el nombre de la función y sus parámetros, eliminando el molesto "invoke", que no es mas que un "call".

    Aquí, hoy solo crearé las funciones putpixel y gotoxyG. Como desde hace tiempo, me estoy apoyando en la directiva "use "y "argum". Así no tengo que salvaguardar con push y pop de los registros usados y no tengo que acceder a los parámetros mediante la indexación a través del puntero de pila. Esto desvirtua el verdadero ensamblador, pues hay líneas generadas por el compilador que no están aquí, pero mejora la lectrua del programa.Debemos tener en cuenta, por lo tanto que los programas no contienen todo el código ensamblador.
     Quien quiera conocer como ensambla estas directivas el compilador puede ir a las primeras entradas del blog, donde programo sin usarlas.
    
    Como la pantalla es gráfica, aquí aparece una diferencia, entre las coordenadas de las dos operaciones.
    En putpixel, las coordenadas son las de pantalla 640x480, pero en la función de texto (servicio 2, Int 10), las coordenadas debe de ser las del cursor, que se reducen por 8 en x y por 4 en y. Para no tener que hacer reconversiones en cada caso, las dos funciones trabajan con coordenadas gráficas. La función gotoxyG hace por lo tanto la tansformación de coordenadas gráficas a coordenadas de texto.

     A partir de ahora y progresivamente iré ampliando esta libería con el resto de las funciones gráficas, colocando un ejemplo ejecuable por cada nueva función, hasta poder realizar un pequeño juego gráfico, integramente hecho en ensamblador, al igual que he ido haciendo con los programas en pantallas de texto.

GRAPHICS.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/>.



    public _gotoxyG
    public _putpixel
.286   
.model compact,pascal
.code
proc _putpixel uses ax cx dx bx,x,y,color:byte
        mov cx, x
        mov dx, y                      ; (CX,DX) = (x,y)
        xor bh, bh                       ; p gina 0
        mov al, color                  ; AL = Color del pixel      
        mov ah, 0Ch                    ; AH = 0x0C (WritePixel)
        int  10h 
        ret
_putpixel endp

end
;coloca el cursor en la posición indicada  en una pnatalla gráfica
proc _gotoxyG uses ax dx cx bx,x,y
        mov bh,0
        mov ax,x
        shr ax,3
        mov dl,al
        mov ax,y
        shr ax,4
        mov dh,al
        mov ah,02h
        int 10h
        ret
_gotoxyG endp