; Loading bmp files on a screen with background. Paints the background first
; with background and drawone  procs, then loads the same bmp into 2 locations
; on the screen. All you need to change in order to load your own images, is
; the proc 'loadshape'. The rest you can treat as a 'black box'.

IDEAL
MODEL small
STACK 100h
MAX_BMP_WIDTH = 320
MAX_BMP_HEIGHT = 200

DATASEG
x1                  dw  ?
y1                  dw  ? 
xx                  equ [bp+4]
yy                  equ [bp+6]
;BMP File data
FileHandle	        dw ?
Header 	            db 54 dup(0)
Palette 	        db 400h dup (0)
filename            db 'sample.bmp',0   ;chng
BmpFileErrorMsg    	db 'Error At Opening Bmp File .', 0dh, 0ah,'$'
ErrorFile           db 0
BmpLeft             dw ?
BmpTop              dw ?
BmpColSize          dw ?
BmpRowSize          dw ?
OneBmpLine 	        db MAX_BMP_WIDTH dup (0)  ; One Color line read buffer
ScreenLineMax 	    db MAX_BMP_WIDTH dup (0)  ; One Color line read buffer


bg            equ 10 ;background color
x             dw 160
y             dw 100


CODESEG
;--------------------------------------------------------------------------

proc          background                ; 1 parameter - color
; calls drawone 200 time to draw 200 horizontal lines and cover the screen
              push bp
              mov  bp,sp 
;Save registers state               
              push ax
              push bx
              push cx
              push dx               
              mov  al,[bp+4]            ; color
              mov  bx,200
              mov  cx,0
              mov  dx,0
drlines:              
              call drawone
              inc  dx
              mov  cx,0
              dec  bx
              cmp  bx,0
              jnz  drlines              ;loop on lines, creates the square
;Restore registers
			  pop  dx
			  pop  cx
			  pop  bx
			  pop  ax 
			  pop  bp
			  ret  2
endp          background

;-----------------------------------
proc          drawone 
; receives no parameters, draws one line, 320 pixels long (horizontal)                 
              push bx
              mov  bx,320
oneline:              
              mov  ah,0ch  
              int  10h 
              inc  cx
              dec  bx
              cmp  bx,0
              jnz  oneline
              pop  bx
              ret  
endp          drawone 

;-----------------------------------
proc loadshape
; General proc to load a bmp file (picture) on the screen. Receives 2
; parameters: y coordinate (counted from the top), and x coordinate
; (counted from the left). The size of the bmp is hard-coded, here
; 48x48 (we could receive them also as parms). loadshape places the
; image x pixels to the right of the left screen boarder, and y pixels
; to down from the top of the screen.

	 push bp
	 mov  bp ,sp
	 push ax
	 mov  ax,xx 
	 mov  [BmpLeft],ax
	 mov  ax,yy
	 mov  [BmpTop],ax
	 mov  [BmpColSize], 48
	 mov  [BmpRowSize] ,48
     mov  dx,offset filename	
	 call OpenShowBmp 
	 cmp  [ErrorFile],1
	 jne  continue          
     mov  dx, offset BmpFileErrorMsg  ;reading error
	 mov  ah,9
	 int  21h	
continue:
     pop ax
	 pop bp
     ret 4
endp loadshape


; BMP processing procs (standard)
;-----------------------------------------------------------------
; input :
;	1.BmpLeft offset from left (where to start draw the picture) 
;	2. BmpTop offset from top
;	3. BmpColSize picture width , 
;	4. BmpRowSize bmp height 
;	5. dx offset to file name with zero at the end 
;-------------------------------------
proc OpenShowBmp near
	push cx
	push bx
	call OpenBmpFile
	cmp [ErrorFile],1
	je @@ExitProc
	call ReadBmpHeader
	; from  here assume bx is global param with file handle. 
	call ReadBmpPalette
	call CopyBmpPalette
	call ShowBMP 
	call CloseBmpFile
@@ExitProc:
	pop bx
	pop cx
	ret
endp OpenShowBmp

;--------------------------------------	
; input dx filename to open
proc OpenBmpFile	near						 
	mov ah, 3Dh
	xor al, al
	int 21h
	jc @@ErrorAtOpen
	mov [FileHandle], ax
	jmp @@ExitProc	
@@ErrorAtOpen:
	mov [ErrorFile],1
@@ExitProc:	
	ret
endp OpenBmpFile
;--------------------------------------
proc CloseBmpFile near
	mov ah,3Eh
	mov bx, [FileHandle]
	int 21h
	ret
endp CloseBmpFile
;--------------------------------------

; Read 54 bytes the Header
proc ReadBmpHeader	near					
	push cx
	push dx
	
	mov ah,3fh
	mov bx, [FileHandle]
	mov cx,54
	mov dx,offset Header
	int 21h
	
	pop dx
	pop cx
	ret
endp ReadBmpHeader
;--------------------------------------

proc ReadBmpPalette near ; Read BMP file color palette, 256 colors * 4 bytes (400h)
						 ; 4 bytes for each color BGR + null)			
	push cx
	push dx
	
	mov ah,3fh
	mov cx,400h
	mov dx,offset Palette
	int 21h
	
	pop dx
	pop cx
	
	ret
endp ReadBmpPalette
;--------------------------------------

; Will move out to screen memory the colors
; video ports are 3C8h for number of first color
; and 3C9h for all rest
proc CopyBmpPalette		near					
										
	push cx
	push dx
	mov si,offset Palette
	mov cx,256
	mov dx,3C8h
	mov al,0  ; black first							
	out dx,al ;3C8h
	inc dx	  ;3C9h
CopyNextColor:
	mov al,[si+2] 		; Red				
	shr al,2 			; divide by 4 Max (cos max is 63 and we have here max 255 ) (loosing color resolution).				
	out dx,al 						
	mov al,[si+1] 		; Green.				
	shr al,2            
	out dx,al 							
	mov al,[si] 		; Blue.				
	shr al,2            
	out dx,al 							
	add si,4 			; Point to next color.  (4 bytes for each color BGR + null)				
								
	loop CopyNextColor
	pop dx
	pop cx
	ret
endp CopyBmpPalette
;--------------------------------------

proc ShowBMP 
; BMP graphics are saved upside-down.
; Read the graphic line by line (BmpRowSize lines in VGA format),
; displaying the lines from bottom to top.
	push cx
	
	mov ax, 0A000h
	mov es, ax
	
	mov cx,[BmpRowSize]
	
	mov ax,[BmpColSize] ; row size must dived by 4 so if it less we must calculate the extra padding bytes
	xor dx,dx
	mov si,4
	div si
	mov bp,dx
	
	mov dx,[BmpLeft]
	
@@NextLine:
	push cx
	push dx
	
	mov di,cx  ; Current Row at the small bmp (each time -1)
	add di,[BmpTop] ; add the Y on entire screen
	
 
	; next 5 lines  di will be  = cx*320 + dx , point to the correct screen line
	mov cx,di
	shl cx,6
	shl di,8
	add di,cx
	add di,dx
	
	; small Read one line
	mov ah,3fh
	mov cx,[BmpColSize]  
	add cx,bp  ; extra  bytes to each row must be divided by 4
	mov dx,offset ScreenLineMax
	int 21h
	; Copy one line into video memory
	cld ; Clear direction flag, for movsb
	mov cx,[BmpColSize]  
	mov si,offset ScreenLineMax
	rep movsb ; Copy line to the screen
	
	pop dx
	pop cx
	 
	loop @@NextLine
	
	pop cx
	ret
endp ShowBMP 
;--------------------------------------

;----- MAIN ------

start:
	      mov ax, @data
	      mov ds, ax
; Graphics mode 
	      mov ax, 13h
	      int 10h
	      
	      push bg                    ;paint the background
          call background 
	      
	      push  40    ;y             ; load a .bmp with x,y as top left corner
	      push  60    ;x
	      call loadshape
	      
	      push  100    ;y             ; load a .bmp with x,y as top left corner
	      push  200    ;x
	      call loadshape
	      
;Init mouse
          mov  ax,0h
          int  33h
;Show mouse                           ;graphics mouse, just for fun.
          mov  ax,1h
          int  33h 	      
	      
	      ; wait for key press        ;Allows a key press to end the program.
	      mov  ah, 1
	      int 21h
	      mov ah, 0
	      mov al, 2
	      int 10h	
exit:
	      mov ax, 4c00h
	      int 21h
END start	      