Category : Assembly Language Source Code
Archive   : DEFEND.ZIP
Filename : ESPRITE.ASM

 
Output of file : ESPRITE.ASM contained in archive : DEFEND.ZIP
;**************************
;* esprite.asm *
;* ega sprite manager *
;**************************

include ega.equ

ega segment at 0a000h
ega ends

;****************
;* data segment *
;****************
data segment word public 'data'

scrnright dw scrn_right
rightbyte dw scrn_right/4

scrnleft dw scrn_left
leftbyte dw scrn_left/4

scrntop dw scrn_top
scrnbottom dw scrn_bot

;*****************************************************
;* erase table *
;* each entry in the table has the following format *
;* word 0 = screen offset of sprite *
;* 1 = adjusted height of sprite (in rows) *
;* 2 = adjusted row width of sprite (in bytes) *
;*****************************************************
erase_tbl dw max_sprites*3 dup(0000)
erase_tbl2 dw max_sprites*3 dup(0000)

erase_ptr dw erase_tbl ;current position in erase table
erase_ptr2 dw erase_tbl2 ;current position in erase table2
public erase_tbl,erase_tbl2

;*********************************************
;* macro to generate 1 entry on sprite table *
;* with a label reflecting it's position on *
;* the table (sprite1, sprite2...etc) *
;*********************************************
testx macro name2,type2,y
&name2&y type2 1 dup(<>)
endm

;***********************************
;* macro to generate sprite tables *
;***********************************
expand macro namex,typex,count
x = 1
rept count
testx &namex,&typex,%x
x = x+1
endm
endm

;***********************************************************
;* The sprite INFO TABLE has the following format: *
;* word 0 = x position on screen *
;* 1 = y position on screen *
;* 2 = pointer offset value (sprite data) *
;* 3 = pointer segment value (sprite data) *
;* *
;* Words 0 - 3 are repeated for each sprite. *
;* a value of 'off' in word 0 of any sprite makes that *
;* sprite inactive. *
;* A sprite may be partially off the screen. A sprite that *
;* is completely off of the screen is treated the same as *
;* a sprite with 'off' in word 0. *
;***********************************************************
;***********************************************************
;* The sprite DATA TABLES have the following format: *
;*-------------------header--------------------------------*
;* bytes 0-1 = sprite height (in rows) *
;* 2-3 = sprite width (in screen bytes) *
;* 4-5 = total data count (in bytes, of one shift of *
;* the sprite) *
;*--------------------data---------------------------------*
;* 6 = pixel mask value for data byte 0 *
;* 7 = color plane 3 data for byte 0 *
;* 8 = '' '' 2 '' '' '' '' *
;* 9 = '' '' 1 '' '' '' '' *
;* 10 = '' '' 0 '' '' '' '' *
;* *
;* bytes 6-10 are repeated for each element of the sprite. *
;* 1 sprite element = 8 pixels. *
;***********************************************************

;*********************
;* sprite info table *
;*********************
spr_table label byte
expand sprite, sprite_def, max_sprites
last_sprite equ $-sprite_size

;**********************************************
;* work area for sprites partially off screen *
;**********************************************
adj_rows dw 0000h ;adjusted row count (current sprite)
act_bytes dw 0000h ;actual byte count (current sprite)
adj_bytes dw 0000h ;adjusted byte count (current sprite)

data ends

code segment word public 'code'
assume cs:code

extrn work_page:word, erase_page:word
extrn scan_table:word

extrn flip_page:near
extrn wait_vbi:near

;***************************************
;* Clear out sprite & erase tables *
;* and initialize screen limits. *
;* This defines the clipping region *
;* for the Sprite manager. *
;* entry: *
;* di = top limit (0-199) *
;* bx = bottom limit (0-199) *
;* cx = left limit (0-160) *
;* dx = right limit (0-160) *
;* exit: *
;* no returned values or flags. *
;* *
;* NOTE: *
;* The clipping region allows a sprite *
;* display area that is smaller than *
;* the actual screen size. *
;***************************************
initspr proc near
public initspr

push ax
push cx
push dx
push si

push ds

mov ax,data
mov ds,ax

assume ds:data, es:nothing

mov [scrnleft],cx ;left clip - x boundry
sar cx,1
sar cx,1
mov [leftbyte],cx ;left clip - byte boundry

mov [scrnright],dx ;right clip - x boundry
sar dx,1
sar dx,1
mov [rightbyte],dx ;right clip - byte boundry

mov [scrnbottom],bx ;bottom clip
mov [scrntop],di ;top clip

;*** init sprite info table ***

mov si,offset sprite1
mov cx,max_sprites
mov ax,off
mov dx,sprite_size
init_spr_lp:
mov [si].x_pos,ax ;turn off sprite
add si,dx
loop init_spr_lp

;*** init sprite erase tables ***

mov [erase_ptr],offset erase_tbl
mov [erase_ptr2],offset erase_tbl2

pop ds

pop si
pop dx
pop cx
pop ax
ret
initspr endp

;***************************************
;* update sprites and flip screen page *
;* entry: *
;* sprite1 - spritex *
;* *
;* exit: *
;* assume all registers altered *
;* except cs, ss, ds, es, sp *
;***************************************
sprite_update proc near
public sprite_update

push ds
push es

mov ax,data
mov ds,ax

assume ds:data, es:nothing

;*** this sets up for drawing sprites ***

mov dx,graphics_reg ;set mode 0
mov ax,0000h + graph_mode
out dx,ax

mov al,graph_bit_mask ;select bit mask
out dx,al

mov dx,sequence_reg ;select map mask
mov al,seq_map_mask
out dx,al

mov si,offset last_sprite ;draw in reverse order

;*** top of sprite draw loop ***

spr_drw_lp1:
cmp [si].x_pos,off ;sprite active ?
jne spr_drw0 ;jump if yes
spr_drw_nxt2:
jmp spr_drw_nxt
spr_drw0:
mov cx,[si].x_pos ;new x position
mov dx,[si].y_pos ;new y position

cmp cx,scrnright ;too far right ?
jge spr_drw_nxt2 ;jump if yes

cmp dx,[scrnbottom] ;too far down ?
jge spr_drw_nxt2 ;jump if yes

push ds
push es
push si

les si,dword ptr [si].ptr_off ;-> sprite data header

push cx
and cx,3 ;first shift ?
jz spr_drw_skp0 ;jump if yes
spr_drw_lp0:
mov ax,es:[si+4] ;total size of 1 shift
add ax,6 ;-> data start

add si,ax ;next shift
loop spr_drw_lp0
spr_drw_skp0:
pop cx
mov bp,es:[si] ;y size (rows)
mov ax,es:[si+2] ;x size (bytes)
mov [adj_bytes],ax ;screen data size
mov bx,ax
shl ax,1 ;* 2
shl ax,1 ;* 4
add ax,bx ;* 5
mov [act_bytes],ax ;actual data size
add si,6

;**** process x positions ****

cmp cx,scrnleft ;start off screen ?
jge spr_drw_skp1 ;jump if no

sub cx,scrnleft ;x positions too far left
sar cx,1 ;get bytes
sar cx,1

add [adj_bytes],cx ;adjust bytes out
jle spr_drw_skip2 ;jump if too far off

neg cx ;get data position offset
add si,cx ;si = si + (cx * 5)
shl cx,1
shl cx,1
add si,cx

mov cx,scrnleft ;start display at left edge
spr_drw_skp1:
sar cx,1 ;x byte offset
sar cx,1
mov ax,cx
add ax,[adj_bytes]
sub ax,rightbyte ;end off screen ?
jle spr_drw_skp1a ;jump if no

sub [adj_bytes],ax ;adjust bytes out

;**** process y positions ****

spr_drw_skp1a:
cmp dx,[scrntop] ;start off screen ?
jge spr_drw_skp2 ;jump if no

sub dx,[scrntop] ;find how far off top

add bp,dx ;adjust row count
jg spr_drw_skp1b ;jump if not all the way off
spr_drw_skip2:
jmp spr_drw_skip
spr_drw_skp1b:
neg dx
mov ax,[act_bytes]
spr_xx_lp:
add si,ax ;adjust data pointer
dec dx
jnz spr_xx_lp

mov dx,[scrntop]
spr_drw_skp2:
mov ax,dx ;y pos
add ax,bp ;get end row
sub ax,[scrnbottom] ;end off screen ?
jb spr_drw_skp2a ;jump if no

sub bp,ax ;adjust row count
spr_drw_skp2a:
mov di,dx ;y pos
shl di,1 ;* 2
mov di, cs:[di+scan_table] ;get screen row address

add di,cx ;add in byte offset
mov bx,[erase_ptr2] ;set up erase stack
mov [bx],di
add di, cs:[work_page] ;draw to work page
mov [bx+2],bp
mov cx,[adj_bytes] ;bytes/row for draw
mov [bx+4],cx

add bx,6
mov [erase_ptr2],bx
mov bx,[act_bytes] ;row offset for draw

mov ax,es ;sprite data segment
mov ds,ax
mov ax,ega ;screen segment
mov es,ax

assume ds:nothing,es:ega

;**** put sprite on work screen ****

draw_sprite_lp1:
push bx ;data increment
push di ;screen pointer
push si ;data pointer
push cx ;bytes/row count
draw_sprite_lp2:
lodsb ;get pixel mask
or al,al ;any pixels on ?
jnz ds_sk1 ;jump if yes

add si,4 ;skip this element
jmp short no_bits
ds_sk1:
mov dx,graphics_reg+1 ;setup bit mask
out dx,al

mov dx,sequence_reg+1
mov bl,8 ;start on color plane 3
draw_sprite_lp3:
mov al,bl
out dx,al ;select plane
mov al,es:[di] ;load latches
lodsb ;get data
mov es:[di],al ;write color plane data
shr bl,1 ;next plane
jnz draw_sprite_lp3
no_bits:
inc di ;next column out (byte)
loop draw_sprite_lp2

pop cx
pop si
pop di
pop bx

add di,true_width ;next row (screen)
add si,bx ;next row (data)
dec bp
jnz draw_sprite_lp1
spr_drw_skip:
pop si
pop es
pop ds

assume ds:data

spr_drw_nxt:
sub si,sprite_size ;next sprite
cmp si,offset sprite1 ;end of table ?
jb spr_drw_xit ;jump if yes

jmp spr_drw_lp1 ;play it again sam
spr_drw_xit:
call flip_page
call erase_sprites
sprite_exit:
pop es
pop ds
ret
sprite_update endp

;***********************************
;* erase sprites *
;* entry: *
;* erase_tbl has list of sprites *
;* to erase *
;* format of table is as follows *
;* word 0 = screen position *
;* 1 = row count *
;* 2 = byte count/row *
;***********************************
erase_sprites proc near
public erase_sprites

push ds
push es

mov ax,ega
mov es,ax
mov ax,data
mov ds,ax

assume es:ega,ds:data

mov dx,graphics_reg ;set mode 1
mov ax,0100h + graph_mode
out dx,ax

mov ax,0ff00h + graph_bit_mask
out dx,al

mov dx,sequence_reg ;enable all planes
mov ax,0f00h + seq_map_mask
out dx,ax

mov bx,[erase_ptr] ;get table position
erase_lp1:
sub bx,6
cmp bx,offset erase_tbl ;done ?
jb erase_xit ;jump if yes

mov si,[bx] ;screen offset
mov dx,[bx+2] ;row count
mov cx,[bx+4] ;byte count
mov bp,true_width
sub bp,cx

mov di,si
add di, cs:[work_page] ;-> destination
add si, cs:[erase_page] ;-> erase screen

push ds
mov ax,es
mov ds,ax
assume ds:ega

erase_lp2:
push cx
rep movsb ;do it a word at a time
pop cx

add di,bp ;next row
add si,bp ; ditto
dec dl
jnz erase_lp2

pop ds
assume ds:data

jmp short erase_lp1
erase_xit:

mov dx,graphics_reg ;set mode 0
mov ax,0000h + graph_mode
out dx,ax

mov ax,data
mov ds,ax
mov es,ax
assume ds:data,es:data

;** move erase data ***

mov si,offset erase_tbl2
mov di,offset erase_tbl
mov cx,max_sprites*3
rep movsw

mov ax,[erase_ptr2]
sub ax,max_sprites*6
mov [erase_ptr],ax
mov [erase_ptr2],offset erase_tbl2

pop es
pop ds
ret
erase_sprites endp

;***********************************
;* set sprite parameters *
;* entry: *
;* cx = X position *
;* dx = Y position *
;* bl = sprite # (0 - max) *
;***********************************
set_spr proc near
public set_spr

cmp bl,max_sprites ;invalid sprite # ?
jae set_spr_xit ;jump if yes

push ds
mov ax,data
mov ds,ax
assume ds:data, es:nothing

sub bh,bh
shl bx,1 ;* 2
shl bx,1 ;* 4
shl bx,1 ;* 8

mov spr_table[bx].x_pos, cx
mov spr_table[bx].y_pos, dx
mov spr_table[bx].ptr_off,di
mov spr_table[bx].ptr_seg,es
pop ds
set_spr_xit:
ret
set_spr endp

if debug

;*************************
;* bl = register number *
;* bh = color number *
;*************************
change_color proc near
public change_color

assume ds:data,es:data

mov dx,3dah
in al,dx

mov dx,3c0h
mov ax,bx
or al,20h
out dx,ax

ret
change_color endp

endif

code ends
end


  3 Responses to “Category : Assembly Language Source Code
Archive   : DEFEND.ZIP
Filename : ESPRITE.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/