miércoles, 18 de julio de 2012

Ensamblador 8086 Moviendo imagen BMP

En el post anterior de esta serie mostramos cómo desplegar una imagen bmp. En este post expandiremos el código para mover la imagen alrededor de la pantalla. El siguiente video muestra el objetivo final del programa.

Lo primero que realizamos fue separar las rutinas relacionadas con desplegar la imagen, éstas fueron colocadas en el archivo libgraf.asm con su respectivo archivo libgraf.inc para poder exportar las funciones más importantes a otros módulos (el siguiente post muestra cómo exportar funciones entre módulos). La función principal para desplegar una imagen bmp (mostrar_bmp) ahora recibe los siguientes parámetros: la ruta del archivo y la posición inicial de la esquina superior izquierda de la imagen en la pantalla. De esta forma ya podemos colocar una imagen en cualquier parte de la pantalla y no sólo en la esquina superior izquierda.

La lógica para mover la imagen en la pantalla es muy sencilla (bmp01.asm):

1 Inicializar el modo de video
2 Ciclo hasta que presionemos una tecla:
   2.1 Limpiar pantalla
   2.2 Actualizar la coordenada x en la dirección actual
   2.3 Si hubo una colisión contra el límite izquierdo o derecho
      2.3.1 Ajustar coordenada x
      2.3.2 Invertir dirección en x
   2.4 Realizar pasos 2.2 y 2.3 para y
   2.5 Desplegar imagen

El código que implementa esta lógica se muestra a continuación (bmp01.asm). En el siguiente proyecto de mercurial podrás descargar los 3 archivos necesarios para construir el ejecutable. El proyecto también incluye la imagen bmp usada. Para ensamblar y ligar estos archivos basta con invocar:

ml bmp01.asm libgraf.asm

Como pueden observar en el video, la imagen parpadea notablemente, esto se debe a que estamos escribiendo al área de memoria de gráficos al mismo tiempo que esta área está siendo desplegada en la pantalla. Esto causa que frecuentemente se desplieguen en la pantalla versiones incompletas de la imagen final. En el siguiente post exploraremos una opción para mejorar esto.

.model  small
.stack 128
INCLUDE libgraf.inc
.data
; El nombre del archivo debe terminar en 0
pelotaf         db "pelota.bmp",0
pelotax         dw 100
pelotay         dw 100
pelotad         dw 40
maxx            dw 320
maxy            dw 200
deltax          dw 2
deltay          dw 2

.code
.startup
  mov ax,@data
  mov ds,ax
main proc
  ; Configurar modo grafico VGA con resolucion de 320x200
  call    InitVid
  
  ciclo1:
  call limpiar_pantalla
  ; -------------------------------------------------------
  ; Controlar posicion x de la pelota
  ; -------------------------------------------------------
  testX:
  mov ax, pelotax
  ; avanzar la pelota en la direccion actual
  add ax, deltax
  
  ; validar colision contra limite derecho
  testmaxX:
  mov cx, maxx
  sub cx, pelotad
  cmp cx, ax
  jg testminX
  ; si la pelota esta en el limite derecho
  ; alinearla al limite e invertir la direccion
  mov ax, cx
  mov deltax, -2
  
  ; validar colision contra limite izquierdo
  testminX:
  cmp ax,0
  jg testY
  ; si la pelota esta en el limite izquierdo
  ; alinearla al limite e invertir la direccion
  mov ax,0
  mov deltax, 2
  
  ; -------------------------------------------------------
  ; Controlar posicion y de la pelota
  ; -------------------------------------------------------
  testY:
  mov bx, pelotay
  ; avanzar la pelota en la direccion actual
  add bx, deltay
  
  ; validar colision contra limite inferior
  testmaxY:
  mov cx, maxy
  sub cx, pelotad
  cmp cx, bx
  jg testminY
  ; si la pelota esta en el limite inferior
  ; alinearla al limite e invertir la direccion
  mov bx, cx
  mov deltay, -2
  
  ; validar colision contra limite superior
  testminY:
  cmp bx,0
  jg dibpelota
  ; si la pelota esta en el limite superior
  ; alinearla al limite e invertir la direccion
  mov bx,0
  mov deltay, 2
  
  ; -------------------------------------------------------
  ; Actualizar posicion (x,y) y pintar pelota
  ; -------------------------------------------------------
  dibpelota:
  mov pelotax, ax
  mov pelotay, bx
  mov dx, offset pelotaf
  call mostrar_bmp

  ; Si una tecla es presionada, salimos del ciclo.
  ; Noten que esta interrupcion no espera por una tecla,
  ; solo verifica si fue presionada y si no, continua.
  mov ah,01h
  int 16h
  jnz fin

  jmp ciclo1

  fin:
  ; Regresar a modo texto
  mov ax,0003h
  int 10h
  
  ; Finalizar el programa
  mov ax,4c00h
  int 21h
  ret
main endp
end

2 comentarios:

  1. Hola, no entiendo la parte de ensamblar y ligar ambos archivos, podrías explicarme con que lo hago? O si lo hago con MASM y LINK tambien? Gracias...

    ResponderEliminar
  2. Hola Hack1892, sólo tienes que invocar ml.exe con los archivos .asm. ml.exe ensambla y liga ambos archivos para generar el ejecutable. Saludos.

    ResponderEliminar