Category : Printer + Display Graphics
Archive   : EXPLO203.ZIP
Filename : EXPA.ASM

 
Output of file : EXPA.ASM contained in archive : EXPLO203.ZIP

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; expa.asm - support routines for EXPLOD.C. Compile with "masm /mx expa ;".
;
; NOTE:
; Make sure one of DLC or TURBOC is defined below. C compilers other
; than Datalight C and Turbo C will probably require changes to the
; segment naming. This file has been tested with the Arrowsoft Assembler
; 1.00d and MASM 5.0.
;
; (C) 1989 Dennis Lo
; You are free to use and distribute this source code, provided that the
; authors' names remain in the code, and that modified versions are clearly
; distinguished from the original.
;
; 89/06/24 Dennis Lo (V1.0) Initial release.
; 89/07/03 Dennis Lo (V1.1) Added ifdefs for linking with Turbo C.
; 89/07/26 Erik Liljencrantz Added EGA support with autodetection
; Restores previous CRT textmode on exit
; 89/08/22 Dennis Lo (V1.2) Allow frame buffer to be in any segment
; Optimized HGC/CGA frame draw loop
; Restricted EGA colours to only the bright ones
; to get rid of the flickering effect.
; 89/09/03 Erik Liljencrantz Added VGA support with autodetection
; 89/09/23 Dennis Lo Added DOS memory allocation routines
; Cosmetic changes.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;------------------------------------------------------------------
; *** IMPORTANT: Uncomment one of the following ***
;
; uncomment this for Datalight C *******
;DLC equ 1
;
; uncomment this for Turbo C ********
TURBOC equ 1
;
;------------------------------------------------------------------


;;;;;;;;;;;;;;;;;;;;;;;;; SEGMENT NAMES ;;;;;;;;;;;;;;;;;;;;;;;;;
;segment names for Datalight C
ifdef DLC
pgroup group prog
prog segment byte public 'prog'
assume cs:pgroup
prog ends
dgroup group data
data segment word public 'data'
assume ds:dgroup
data ends
endif

;segment names for Turbo C
ifdef TURBOC
name t
_TEXT segment byte public 'CODE'
DGROUP group _DATA,_BSS
assume cs:_TEXT,ds:DGROUP,ss:DGROUP
_TEXT ends
_DATA segment word public 'DATA'
[email protected] label byte
_DATA ends
_BSS segment word public 'BSS'
[email protected] label byte
_BSS ends
endif


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; CONST ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; HGC port addresses
config equ 03bfh
index equ 03b4h
cntrl equ 03b8h
; HGC control codes
scrn_on equ 8
grph equ 2
text equ 20h

par equ 4 ;stack offset of 1st C call parameter
DEADPOINT equ 32767 ;flag for dead point in frame table


;;;;;;;;;;;;;;;;;;;;;;;;;;;;; DATA ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ifdef DLC
data segment word public 'data'
endif
ifdef TURBOC
_DATA segment word public 'DATA'
endif

Vidtype db ? ;video card type
Vidseg dw ? ;video mem segment
Vidsize dw ? ;video mem size
SaveMode DB ? ;Save video text mode
Color db ? ;Current frame colour (for EGA)

; Table of bit values for plotting points
;masktable db 128,64,32,16,8,4,2,1 ;1-pixel wide points
masktable db 192,96,48,24,12,6,3,1 ;2-pixel wide points

; HGC 6845 config tables
hgc_gtable db 35h,2dh,2eh,07h
db 5bh,02h,57h,57h
db 02h,03h,00h,00h
hgc_ttable db 61h,50h,52h,0fh
db 19h,06h,19h,19h
db 02h,0dh,0bh,0ch

; Palette register table for EGA
; Consists of colour values for registers 0-15, plus border colour
palette db 00h,07h,3ah,3bh,3ch,3eh,3fh,07h
db 3ah,3bh,3ch,3eh,07h,3ah,3bh,3ch,00h

ifdef DLC
data ends
endif
ifdef TURBOC
_DATA ends
endif


;;;;;;;;;;;;;;;;;;;;;;;;;;;;; CODE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ifdef DLC
prog segment byte public 'prog'
endif
ifdef TURBOC
_TEXT segment byte public 'CODE'
endif


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Return the number of paragraphs of memory available.
; int num_para = DosMemLeft ();
;
public _DosMemLeft
_DosMemLeft proc near
push bp
mov bp,sp
push es

mov bx,0f000h ;Call DOS malloc with a request for
mov ah,48h ; 960K to make sure it fails
int 21h
jc memleft_cont

xor ax,ax ;Error: DOS malloc() succeeded!
jmp memleft_end ;Return 0

memleft_cont:
mov ax,bx ;Return mem size remaining

memleft_end:
pop es
pop bp
ret
_DosMemLeft endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Allocate a block of memory
; int segment_addr = DosAlloc (size_in_paragraphs);
; Returns 0 if unsucessful.
;
public _DosAlloc
_DosAlloc proc near
push bp
mov bp,sp
push es

mov bx,par[bp] ;get # paragraphs requested
; add bx,15 ;# paragraphs = (# bytes + 15) / 16
; shr bx,1
; shr bx,1
; shr bx,1
; shr bx,1
mov ah,48h ;call DOS malloc
int 21h
jnc alloc_end
xor ax,ax ;if failure then return 0
alloc_end:
pop es
pop bp
ret
_DosAlloc endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Free a block of memory allocated by DosAlloc
; DosFree (int segment_addr);
; Returns 0 if successful, 1 if not.
;
public _DosFree
_DosFree proc near
push bp
mov bp,sp
push es

mov ax,par[bp] ;get segment address to free at
mov es,ax
mov ah,49h ;call DOS free
int 21h


jc free_end ;if error then return DOS err code
xor ax,ax ;else return 0
free_end:
pop es
pop bp
ret
_DosFree endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Nonblocking keyboard read - returns ASCII char
; int key = ChkKey();
;
public _ChkKey
_ChkKey proc near
push si
push di

mov ah,1
int 16h
jz nokey ;if no key then return
mov ax,0 ;else get the key out of the buffer
int 16h
mov ah,0
jmp chkret
nokey:
mov ax,0
chkret:
pop di
pop si
ret
_ChkKey endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Guess video card type. Returns 'h', 'c', 'e', or 'v'.
; int card = gr_card();
;
public _gr_card
_gr_card proc near
push bp
push si
push di

mov ah,0Fh
int 10h
MOV SaveMode,AL ;Save textmode to restore later...
MOV BL,AL
mov ax,'h' ; Mono, assume HGC
cmp bl,07h ;
je card_done ;
MOV AX,1200h
MOV BX,0FF10h
MOV CX,00FFh
INT 10h
CMP CL,12 ;CL<12
JAE Card_CGA
CMP BH,1 ;BH<=1
JA Card_CGA
CMP BL,3 ;BL<=3
JA Card_CGA
;OK, either EGA or VGA
;Use INT 10/AH=1A00 to determine which one...
MOV AX,1A00h
INT 10h
CMP AL,1Ah ;Returns AL=1Ah if function supported
JNE Card_EGA
CMP BL,08h ;VGA with analog color display
JNE Card_EGA
MOV AX,'v' ;Assume VGA
JMP SHORT Card_Done
Card_EGA:
MOV AX,'e' ;Assume EGA
JMP SHORT Card_Done
Card_CGA:
MOV AX,'c' ;Assume CGA
Card_Done:
pop di
pop si
pop bp
ret
_gr_card endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Set video card type
; gr_setcard (char video_card);
;
public _gr_setcard
_gr_setcard proc near
push bp
mov bp,sp

mov ax,par[bp] ;get video_card parameter
mov Vidtype,al

;Set video mem segment
cmp al,'h'
jne not_herc
mov ax,0b000h ;Hercules
mov cx,8000h ; 32K bytes
jmp s_end
not_herc:
cmp al,'e'
jne not_ega
mov ax,0A000h ;EGA
mov cx,6D60h ; 28000 bytes (but in four planes)
jmp s_end
not_ega:
cmp al,'v'
jne not_vga
mov ax,0A000h ;VGA
mov cx,9600h ; 38400 bytes (but in four planes)
jmp s_end
not_vga:
mov ax,0b800h ;CGA
mov cx,4000h ; 16K bytes
s_end:
mov Vidseg,ax
mov Vidsize,cx

pop bp
ret
_gr_setcard endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Set video card for graphics mode
; gr_gmode();
;
public _gr_gmode
_gr_gmode proc near
push bp
push es
push ds
push si

mov al,Vidtype
cmp al,'h'
jne NotHerc
call hgc_gmode ;HGC
jmp g_end
NotHerc:
cmp al,'e'
jne NotEga
call ega_gmode ;EGA
jmp g_end
NotEga:
cmp al,'v'
jne NotVga
call vga_gmode ;VGA
jmp g_end
NotVga:
call cga_gmode ;CGA
g_end:
pop si
pop ds
pop es
pop bp
ret
_gr_gmode endp


;Set HGC graphics mode, page 0
hgc_gmode:
mov dx,config
mov al,3
out dx,al

mov al,grph
lea si,hgc_gtable
mov bx,0
mov cx,4000h
call hgc_setmd
ret


;Set EGA graphics mode
ega_gmode:
mov ah,00h ;Set 640x350 16-colour mode
mov al,10h ;Probably one of the few changes for VGA
int 10h ;640x480 resolution

mov ax,ds ;set colour palette
mov es,ax
lea dx,palette
mov ax,1002h
int 10h
ret

;Set VGA graphics mode
vga_gmode:
mov ah,00h ;Set 640x350 16-colour mode
mov al,12h ;Mode 12h: 640x480 in 16 colours
int 10h

mov ax,ds ;set colour palette
mov es,ax
lea dx,palette
mov ax,1002h
int 10h
ret

;Set CGA graphics mode
cga_gmode:
mov ah,00h ;set 320x200 4-colour mode
mov al,04h
int 10h

mov ah,0bh ;set green-red-brown colour palette
mov bx,0100h
int 10h
ret


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Set text mode.
; gr_tmode();
public _gr_tmode
_gr_tmode proc near
push bp
push es
push ds
push si

mov al,Vidtype
cmp al,'h'
jne t_cga
t_hgc: call hgc_tmode
jmp t_end
t_cga: call cga_tmode ;for CGA, EGA, & VGA
t_end:
pop si
pop ds
pop es
pop bp
ret
_gr_tmode endp


;Set HGC text mode
hgc_tmode:
mov dx,config
mov al,0
out dx,al

mov al,text
lea si,hgc_ttable
mov bx,720h
mov cx,2000h
call hgc_setmd
ret


;Set CGA & EGA & VGA text mode
cga_tmode:
mov ah,00h
mov al,SaveMode ;Restore previous textmode
int 10h
ret


;;;;;;;;;;;;;;;;;;;;;;;;; hgc_setmd (Hercules support)
; Set display mode to graphics or text. Local.
; params:
; al = value to be output to 6845 control port
; si = 6845 param table
; cx = # of words to be cleared
; bx = blank value
hgc_setmd proc near
push di
push ds
push es
push ax
push bx
push cx

; change mode but without scrn_on
mov dx,cntrl
out dx,al

; initialize the 6845
mov ax,ds
mov es,ax ;also point es:si to param table

mov dx,index
mov cx,12 ;12 params to be output
xor ah,ah ;starting from reg. 0
parms:
mov al,ah
out dx,al ;output 6845 reg. index

inc dx
lodsb
out dx,al ;output 6845 reg. data

inc ah
dec dx
loop parms

; clear the display buffer
pop cx
mov ax,0b000h
cld

mov es,ax
xor di,di
pop ax
rep stosw

; scrn_on, page 0
mov dx,cntrl
pop ax
add al,scrn_on
out dx,al

pop es
pop ds
pop di
ret
hgc_setmd endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Returns video mem addr of a (x,y) point
; int video_addr = gr_addr (int x, int y);
;
par_x equ par ;in: x
par_y equ 2+par ;in: y

public _gr_addr
_gr_addr proc near
push bp
mov bp,sp
push si
push di

mov bx,par_x[bp]
mov cx,par_y[bp]
call graddr

pop di
pop si
pop bp
ret
_gr_addr endp


;
;Local routine to calculate video address.
;On entry, BX=x, CX=y. Returns addr in AX.
;
graddr proc near
mov al,Vidtype
cmp al,'h'
je hgc_addr
cmp al,'e'
je ega_addr
cmp al,'v'
je vga_addr
jmp cga_addr
graddr endp

;Calc HGC addr = 90 * (y / 4) + 2000h * (y & 3) + x / 8
hgc_addr:
;loc = (y / 4) * 90
mov ax,cx
shr ax,1
shr ax,1

;ax * 90 = ax*2 + ax*8 + ax*16 + ax*64
shl ax,1 ;*2
mov dx,ax
shl ax,1 ;*4
shl ax,1 ;*8
add dx,ax
shl ax,1 ;*16
add dx,ax
shl ax,1 ;*32
shl ax,1 ;*64
add ax,dx
MOV DI,AX ;store sum in DI

;loc += (y & 3) * 2000H
AND CX,3
MOV AX,2000H
MUL CX ;(msb ignored)
ADD DI,AX

;loc += (x / 8)
mov ax,bx
shr ax,1
shr ax,1
shr ax,1
add ax,di
ret


;Calc EGA addr = 80 * y + x / 8
ega_addr:
vga_addr:
MOV AX,cx
SHL AX,1
SHL AX,1
SHL AX,1
SHL AX,1
MOV DX,AX
SHL AX,1
SHL AX,1
ADD DX,AX
MOV AX,bx
SHR AX,1
SHR AX,1
SHR AX,1
ADD AX,DX
RET


;Calc CGA addr = 80 * (y / 4) + 2000h * (y & 3) + x / 8
cga_addr:
;loc = (y / 2) * 80
MOV AX,cx
SHR AX,1

MOV DL,80
MUL DL
MOV DI,AX ;store sum in DI

;loc += (y & 1) * 2000H
MOV AX,2000H
AND CX,1
jz ca_noadd
ADD DI,AX
ca_noadd:
;loc += (x / 8)
MOV AX,bx
shr ax,1
shr ax,1
shr ax,1
ADD ax,di
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Returns video mem addr of a (x,y) point
; int video_addr = gr_addr (int x, int y);
;
public _gr_value
_gr_value proc near
push bp
mov bp,sp
mov bx,par_x[bp]
call grvalue
pop bp
ret
_gr_value endp

;
; Local: returns the byte value of a (x,y) point in AL
; Input: BX=x
; Output: AL = 2 << [7 - (x & 7)]
;
grvalue proc near
and bx,7
mov al,masktable[bx]
ret
grvalue endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; gr_store_pt (x, y, dest_seg, dest_ofs, centre_addr)
;
dest_seg equ par+4
dest_ofs equ par+6
cent_addr equ par+8

public _gr_store_pt
_gr_store_pt proc near
push bp
mov bp,sp
push es
push si
push di

mov bx,par_x[bp] ;get addr
cmp bx,DEADPOINT
je store_dead
mov cx,par_y[bp]
call graddr
sub ax,cent_addr[bp]
mov dx,ax

mov bx,par_x[bp] ;get value
call grvalue
mov cl,al
store_pt:
mov bx,dest_ofs[bp] ;get dest addr
mov ax,dest_seg[bp]
mov es,ax
mov es:[bx],dx ;store addr in dest
mov es:[bx+2],cl ;store value in dest

pop di
pop si
pop es
pop bp
ret
_gr_store_pt endp

store_dead: mov dx,bx
jmp store_pt

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Plot one frame of 3-byte (offset, value) point records.
; gr_frplot (num_points, frame_seg, frame_offset, centre_addr, draw_or_erase)
;
fpar_nump equ par ;No. of points per frame
fpar_frm_seg equ par+2 ;frame segment
fpar_frm_ofs equ par+4 ;frame offset
fpar_centre equ par+6 ;video addr of explosion's centre
fpar_mode equ par+8 ;for EGA: 0 means erase, 1 means draw

public _gr_frplot
_gr_frplot proc near
push bp
mov bp,sp
push ds
push es
push si
push di

mov cx,fpar_nump[bp]
mov si,fpar_frm_ofs[bp]
mov dx,fpar_centre[bp]
mov di,3
cmp VidType,'e'
je fr_ega
cmp VidType,'v'
je fr_vga

;Plot frame on HGC or CGA
fr_cga_hgc:
mov ax,Vidseg ;get video segment
mov es,ax
mov ax,fpar_frm_seg[bp] ;get frame table segment
mov ds,ax
frloop:
mov bx,[si] ;get point offset
add bx,dx ;add centre to offset
mov al,[si+2] ;get point's byte value
xor es:[bx],al
frnext:
add si,di
loop frloop
fr_end:
pop di
pop si
pop es
pop ds
pop bp
ret

;Plot frame on EGA
fr_vga:
fr_ega:
MOV BL,fpar_mode[BP]
MOV AX,00F02H
push dx
MOV DX,03C4H ;3C4
OUT DX,AX ;Map Mask = enable write in all planes
MOV DX,03CEH
MOV AX,0FF01H
OUT DX,AX
MOV AX,00005H
OUT DX,AX ;Mode register
CMP BL,0
JE fr_Clear
MOV AX,01803H
OUT DX,AX ;Select XOR of data

INC Color ;Increment colorcounter
MOV AH,Color

;Alternative coloring of the explosion...
; MOV AX,40h ;Get color from timer...!
; MOV ES,AX ;
; MOV AH,ES:[06Ch] ;

;Alternative explosion colouring using "random" numbers from ROM
; inc Colour
; mov ax,0f000h
; mov es,ax
; mov bl,Color
; xor bh,bh
; mov ah,es:[bx]
; or ah,ah
; and ah,15
; jne notblack
; inc ah
;notblack:
;here ah should contain colour byte
JMP SHORT fr_cont
fr_Clear:
MOV AX,00003H
OUT DX,AX ;Select unmodified data
XOR AH,AH
fr_cont:
XOR AL,AL
OUT DX,AX
MOV AL,08
OUT DX,AL ; Select register 8 again
INC DX

mov ax,Vidseg ;get video segment
mov es,ax
mov ax,fpar_frm_seg[bp] ;get frame table segment
mov ds,ax
pop bp ;get centre addr pushed earlier
egaloop:
mov bx,[si] ;get point offset
cmp bx,DEADPOINT ;check if point is dead
je eganext
add bx,BP ;add centre to offset
mov al,[si+2] ;get point's byte value
OUT DX,AL
XCHG AL,ES:[BX]
eganext:
add si,di
loop egaloop
JMP fr_end

_gr_frplot endp


ifdef DLC
prog ends
endif
ifdef TURBOC
_TEXT ends
endif
end