home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga ACS 1998 #6
/
amigaacscoverdisc1998-061998.iso
/
games
/
descent
/
source
/
3d
/
draw.asm
< prev
next >
Wrap
Assembly Source File
|
1998-06-08
|
16KB
|
669 lines
;THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
;SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
;END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
;ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
;IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
;SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
;FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
;CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
;AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
;COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
;
; $Source: f:/miner/source/3d/rcs/draw.asm $
; $Revision: 1.30 $
; $Author: matt $
; $Date: 1995/02/15 02:26:52 $
;
; Source for drawing routines
;
; $Log: draw.asm $
; Revision 1.30 1995/02/15 02:26:52 matt
; Put in added handling for odd clipping error
;
; Revision 1.29 1995/02/10 16:41:41 matt
; Put in check for bad points after clip
;
; Revision 1.28 1995/02/09 22:00:52 matt
; Removed dependence on divide overflow handler; we now check for overflow
; before dividing. This fixed problems on some TI chips.
;
; Revision 1.27 1994/11/30 00:59:32 mike
; optimizations.
;
; Revision 1.26 1994/10/03 12:52:04 matt
; Fixed typo
;
; Revision 1.25 1994/10/03 12:49:56 matt
; Took out unused routines & data
;
; Revision 1.24 1994/07/24 23:59:34 matt
; Made 3d no longer deal with point numbers, but only with pointers.
;
; Revision 1.23 1994/05/30 11:36:26 matt
; Added g3_set_special_render() to allow a user to specify functions to
; call for 2d draws.
;
; Revision 1.22 1994/05/19 21:46:13 matt
; Moved texture lighting out of 3d and into the game
;
; Revision 1.21 1994/05/13 17:06:18 matt
; Finished ripping out intersected side lighting code
;
; Revision 1.20 1994/05/13 17:02:58 matt
; Took our special side lighting code
;
; Revision 1.19 1994/04/19 18:45:19 matt
; Now call the clipped disk, which it should have done all along, but
; John had only implemented the unclipped disk, and it clipped anyway.
;
; Revision 1.18 1994/04/19 18:26:42 matt
; Added g3_draw_sphere() function.
;
; Revision 1.17 1994/04/19 17:03:40 matt
; For polygons, call the texture-mapper's flat shader
;
; Revision 1.16 1994/03/18 15:58:37 matt
; Fixed bug that caused light vals to be screwed up
;
; Revision 1.15 1994/03/14 12:37:31 matt
; Made draw routines check for rotated points
;
; Revision 1.14 1994/02/10 18:00:39 matt
; Changed 'if DEBUG_ON' to 'ifndef NDEBUG'
;
; Revision 1.13 1994/02/09 11:48:16 matt
; Changes return codes for drawing functions
;
; Revision 1.12 1994/02/01 13:23:05 matt
; Added use_beam var to turn off beam lighting
;
; Revision 1.11 1994/01/26 20:27:18 mike
; bright light on very near side.
;
; Revision 1.10 1994/01/26 12:49:26 matt
; Made lighting computation a seperate function, g3_compute_lighting_value.
; Note the unwieldy function name, courtesy of Mike.
;
; Revision 1.9 1994/01/25 16:38:02 yuan
; Fixed beam_brightness
;
; Revision 1.8 1994/01/24 11:08:49 matt
; Added beam_brightness variable
;
; Revision 1.7 1994/01/22 18:22:09 matt
; New lighting stuff now done in 3d; g3_draw_tmap() takes lighting parm
;
; Revision 1.6 1993/12/05 23:47:14 matt
; Added function g3_draw_line_ptrs()
;
; Revision 1.5 1993/11/22 10:51:29 matt
; Changed texture map function comments to reflect uvl (not just uv) struct
;
; Revision 1.4 1993/11/17 10:40:02 matt
; Added check for zero-length normal in do_facing_check
;
; Revision 1.3 1993/11/04 18:49:14 matt
; Added system to only rotate points once per frame
;
; Revision 1.2 1993/11/04 12:36:36 mike
; Add support for static lighting value.
;
; Revision 1.1 1993/10/29 22:20:27 matt
; Initial revision
;
;
;
DONT_USE_UPOLY = 1
.386
option oldstructs
.nolist
include types.inc
include psmacros.inc
include gr.inc
include 3d.inc
.list
assume cs:_TEXT, ds:_DATA
_DATA segment dword public USE32 'DATA'
rcsid db "$Id: draw.asm 1.30 1995/02/15 02:26:52 matt Exp $"
align 4
tempv vms_vector <>
n_verts dd ?
n_verts_4 dd ? ; added by mk, 11/29/94, point coding optimization.
bitmap_ptr dd ?
uvl_list_ptr dd ?
tmap_drawer_ptr dd draw_tmap_
flat_drawer_ptr dd gr_upoly_tmap_
line_drawer_ptr dd gr_line_
_DATA ends
_TEXT segment dword public USE32 'CODE'
extn gr_upoly_tmap_
extn draw_tmap_
;specifies new routines to call to draw polygons
;takes eax=ptr to tmap routine, edx=ptr to flat routine, ebx=line rtn
g3_set_special_render:
or eax,eax
jnz got_tmap_ptr
lea eax,cs:draw_tmap_
got_tmap_ptr: mov tmap_drawer_ptr,eax
or edx,edx
jnz got_flat_ptr
lea edx,cs:gr_upoly_tmap_
got_flat_ptr: mov flat_drawer_ptr,edx
or ebx,ebx
jnz got_line_ptr
lea ebx,cs:gr_line_
got_line_ptr: mov line_drawer_ptr,ebx
ret
;alternate entry takes pointers to points. esi,edi = point pointers
g3_draw_line:
;;ifndef NDEBUG
;; mov ax,_Frame_count ;curren frame
;; cmp ax,[esi].p3_frame ;rotated this frame?
;; break_if ne,'Point not rotated in draw_line'
;; cmp ax,[edi].p3_frame ;rotated this frame?
;; break_if ne,'Point not rotated in draw_line'
;;endif
mov al,[esi].p3_codes
mov ah,[edi].p3_codes
;check codes for reject, clip, or no clip
test al,ah ;check codes_and
jnz no_draw_line ;both off same side
or al,ah ;al=codes_or
js must_clip_line ;neg z means must clip
test [esi].p3_flags,PF_PROJECTED
jnz p0_projected
call g3_project_point
p0_projected: test [esi].p3_flags,PF_OVERFLOW
jnz must_clip_line
test [edi].p3_flags,PF_PROJECTED
jnz p1_projected
xchg esi,edi ;get point in esi
call g3_project_point
xchg esi,edi
p1_projected: test [edi].p3_flags,PF_OVERFLOW
jnz must_clip_line
pushm ebx,ecx,edx ;save regs
test al,al ;check codes or
mov eax,[esi].p3_sx
mov edx,[esi].p3_sy
mov ebx,[edi].p3_sx
mov ecx,[edi].p3_sy
jz unclipped_line ;cc set from test above
;call clipping line drawer
;; call gr_line_ ;takes eax,edx,ebx,ecx
push esi
mov esi,line_drawer_ptr
call esi
pop esi
popm ebx,ecx,edx
ret ;return value from gr_line
;we know this one is on screen
unclipped_line: ;;call gr_uline_ ;takes eax,edx,ebx,ecx
;; call gr_line_
push esi
mov esi,line_drawer_ptr
call esi
pop esi
popm ebx,ecx,edx
mov al,1 ;definitely drew
ret
;both points off same side, no do draw
no_draw_line: xor al,al ;not drawn
ret
;jumped here from out of g3_draw_line. esi,edi=points, al=codes_or
must_clip_line: call clip_line ;do the 3d clip
call g3_draw_line ;try draw again
;free up temp points
test [esi].p3_flags,PF_TEMP_POINT
jz not_temp_esi
call free_temp_point
not_temp_esi: test [edi].p3_flags,PF_TEMP_POINT
jz not_temp_edi
xchg esi,edi
call free_temp_point
not_temp_edi:
ret ;ret code set from g3_draw_line
;returns true if a plane is facing the viewer. takes the unrotated surface
;normal of the plane, and a point on it. The normal need not be normalized
;takes esi=vector (unrotated point), edi=normal.
;returns al=true if facing, cc=g if facing
;trashes esi,edi
g3_check_normal_facing:
push edi ;save normal
lea eax,tempv
mov edi,esi
lea esi,View_position
call vm_vec_sub
mov esi,eax ;view vector
pop edi ;normal
call vm_vec_dotprod
or eax,eax ;check sign
setg al ;true if positive
ret
;see if face is visible and draw if it is.
;takes ecx=nv, esi=point list, edi=normal, ebx=point.
;normal can be NULL, which will for compution here (which will be slow).
;returns al=-1 if not facing, else 0
;Trashes ecx,esi,edx,edi
g3_check_and_draw_poly:
call do_facing_check
or al,al
jnz g3_draw_poly
mov al,-1
ret
g3_check_and_draw_tmap:
push ebx
mov ebx,eax
call do_facing_check
pop ebx
or al,al
jnz g3_draw_tmap
mov al,-1
ret
;takes edi=normal or NULL, esi=list of vert nums, ebx=pnt
;returns al=facing?
do_facing_check:
test edi,edi ;normal passed?
jz compute_normal ;..nope
;for debug, check for NULL normal
ifndef NDEBUG
mov eax,[edi].x
or eax,[edi].y
or eax,[edi].z
break_if z,'Zero-length normal in do_facing_check'
endif
;we have the normal. check if facing
push esi
mov esi,ebx
call g3_check_normal_facing ;edi=normal
pop esi
setg al ;set al true if facing
ret
;normal not specified, so must compute
compute_normal:
pushm ebx,ecx,edx,esi
;get three points (rotated) and compute normal
mov eax,[esi] ;get point
mov edi,8[esi] ;get point
mov esi,4[esi] ;get point
lea ebx,tempv
call vm_vec_perp ;get normal
mov edi,eax ;normal in edi
call vm_vec_dotprod ;point in esi
or eax,eax ;check result
popm ebx,ecx,edx,esi
sets al ;al=true if facing
ret
;draw a flat-shaded face. returns true if drew
;takes ecx=nv, esi=list of pointers to points
;returns al=0 if called 2d, 1 if all points off screen
;Trashes ecx,esi,edx
g3_draw_poly:
pushm ebx,edi
lea edi,Vbuf0 ;list of ptrs
xor ebx,ebx ;counter
mov dx,0ff00h ;init codes
codes_loop: mov eax,[esi+ebx*4] ;get point number
mov [edi+ebx*4],eax ;store in ptr array
;;ifndef NDEBUG
;; push ebx
;; mov bx,_Frame_count ;curren frame
;; cmp bx,[eax].p3_frame ;rotated this frame?
;; break_if ne,'Point not rotated in draw_poly'
;; pop ebx
;;endif
and dh,[eax].p3_codes ;update codes_and
or dl,[eax].p3_codes ;update codes_or
inc ebx
cmp ebx,ecx ;done?
jne codes_loop ;..nope
;now dx = codes
test dh,dh ;check codes_and
jnz face_off_screen ;not visible at all
test dl,dl ;how about codes_or
js must_clip_face ;neg z means must clip
jnz must_clip_face
;reentry point for jump back from clipper
draw_poly_reentry:
push edx ;save codes_or
;now make list of 2d coords (& check for overflow)
mov edx,edi ;edx=Vbuf0
xor ebx,ebx
lea edi,Vertex_list
coords_loop: mov esi,[edx+ebx*4] ;esi = point
test [esi].p3_flags,PF_PROJECTED
jnz pnt_projected
call g3_project_point
pnt_projected: test [esi].p3_flags,PF_OVERFLOW
jnz must_clip_face2
mov eax,[esi].p3_sx
mov [edi+ebx*8],eax
mov eax,[esi].p3_sy
mov 4[edi+ebx*8],eax
inc ebx
cmp ebx,ecx
jne coords_loop
mov eax,ecx ;eax=nverts
mov edx,edi ;edx=vertslist
;check for trivial accept
pop ebx ;get codes_or
ife DONT_USE_UPOLY
test bl,bl
jz no_clip_face
endif
;;call gr_poly_ ;takes eax,edx
;;; call gr_upoly_tmap_
push ecx
mov ecx,flat_drawer_ptr
call ecx
pop ecx
popm ebx,edi
xor al,al ;say it drew
ret
;all on screen. call non-clipping version
no_clip_face: ;;call gr_upoly_ ;takes eax,edx
;; call gr_poly_
call gr_upoly_tmap_
popm ebx,edi
xor al,al ;say it drew
ret
;all the way off screen. return
face_off_screen: popm ebx,edi
mov al,1 ;no draw
ret
;we require a 3d clip
must_clip_face2: pop edx ;get codes back
must_clip_face: lea esi,Vbuf0 ;src
lea edi,Vbuf1 ;dest
mov al,dl ;codes in al
call clip_polygon ;count in ecx
mov edi,esi ;new list in edi
;clipped away?
jecxz clipped_away
or dh,dh ;check codes_and
jnz clipped_away
test dl,dl ;check codes or
js clipped_away ;some points still behind eye
push edi ;need edi to free temp pnts
push offset cs:reentry_return
pushm ebx,edi ;match what draw has pushed
jmp draw_poly_reentry
reentry_return:
pop edi
clipped_away:
push eax ;save ret codes
;free temp points
xor ebx,ebx
free_loop: mov esi,[edi+ebx*4] ;get point
test [esi].p3_flags,PF_TEMP_POINT
jz not_temp
call free_temp_point
not_temp: inc ebx
cmp ebx,ecx
jne free_loop
pop eax ;get ret codes back
popm ebx,edi
ret
;draw a texture-mapped face. returns true if drew
;takes ecx=nv, esi=point list, ebx=uvl_list, edx=bitmap
;returns al=0 if called 2d, 1 if all points off screen
;Trashes ecx,esi,edx
g3_draw_tmap:
mov bitmap_ptr,edx ;save
pushm ebx,edi
lea edi,Vbuf0 ;list of ptrs
push ebp ;save ebp
mov ebp,ebx ;ebp=uvl list
mov uvl_list_ptr, ebx
mov n_verts,ecx ;save in memory
shl ecx, 2
;loop to check codes, make list of point ptrs, and copy uvl's into points
mov dh, 0ffh ; init codes (this pipelines nicely)
mov n_verts_4, ecx
xor ebx, ebx
xor dl, dl ; init codes (this pipelines nicely)
t_codes_loop: mov eax,[esi+ebx] ;get point number
mov [edi+ebx],eax ;store in ptr array
and dh,[eax].p3_codes ;update codes_and
or dl,[eax].p3_codes ;update codes_or
mov ecx,[ebp] ;get u
add ebp, 4 ; (this pipelines better ..mk, 11/29/94 ((my 33rd birthday...)))
mov [eax].p3_u,ecx
mov ecx,[ebp] ;get v
add ebp, 4
mov [eax].p3_v,ecx
mov ecx,[ebp] ;get l
add ebp, 4
mov [eax].p3_l,ecx
or [eax].p3_flags,PF_UVS + PF_LVS ;this point's got em
add ebx,4
cmp ebx, n_verts_4
jne t_codes_loop ;..nope
pop ebp ;restore ebp
;now dx = codes
test dh,dh ;check codes_and
jnz t_face_off_screen ;not visible at all
test dl,dl ;how about codes_or
jnz t_must_clip_face ;non-zero means must clip
;reentry point for jump back from clipper
t_draw_poly_reentry:
;make sure all points projected
mov edx,edi ;edx=Vbuf0
xor ebx,ebx
t_proj_loop: mov esi,[edx+ebx*4] ;esi = point
;;ifndef NDEBUG
;; mov ax,_Frame_count ;curren frame
;; cmp ax,[esi].p3_frame ;rotated this frame?
;; break_if ne,'Point not rotated in draw_tmap'
;;endif
test [esi].p3_flags,PF_PROJECTED
jnz t_pnt_projected
call g3_project_point
t_pnt_projected:
test [esi].p3_flags,PF_OVERFLOW
break_if nz,'Should not overflow after clip'
jnz t_face_off_screen
inc ebx
cmp ebx,n_verts
jne t_proj_loop
;now call the texture mapper
mov eax,bitmap_ptr ;eax=bitmap ptr
mov edx,n_verts ;edx=count
mov ebx,edi ;ebx=points
;;; call draw_tmap_
push ecx
mov ecx,tmap_drawer_ptr
call ecx
pop ecx
popm ebx,edi
xor al,al ;say it drew
ret
;all the way off screen. return
t_face_off_screen: popm ebx,edi
mov al,1 ;no draw
ret
;we require a 3d clip
t_must_clip_face: lea esi,Vbuf0 ;src
lea edi,Vbuf1 ;dest
mov al,dl ;codes in al
mov ecx,n_verts
call clip_polygon ;count in ecx
mov n_verts,ecx
mov edi,esi ;new list in edi
;clipped away?
jecxz t_clipped_away
or dh,dh ;check codes_and
jnz t_clipped_away
test dl,dl ;check codes or
js t_clipped_away ;some points still behind eye
push edi ;need edi to free temp pnts
push offset cs:t_reentry_return
pushm ebx,edi ;match what draw has pushed
jmp t_draw_poly_reentry
t_reentry_return:
pop edi
t_clipped_away:
; free temp points
mov ebx, ecx
push eax ;save ret code
dec ebx
shl ebx, 2
t_free_loop: mov esi,[edi+ebx] ;get point
test [esi].p3_flags,PF_TEMP_POINT
jz t_not_temp
call free_temp_point
t_not_temp: sub ebx, 4
jns t_free_loop
pop eax ;get ret code
popm ebx,edi
ret
;draw a sortof-sphere. takes esi=point, ecx=radius
g3_draw_sphere: test [esi].p3_codes,CC_BEHIND
jnz reject_sphere
test [esi].p3_flags,PF_PROJECTED
jnz sphere_p_projected
call g3_project_point
sphere_p_projected:
test [esi].p3_flags,PF_OVERFLOW
jnz reject_sphere
;calc radius. since disk doesn't take width & height, let's just
;say the the radius is the width
pushm eax,ebx,ecx,edx
mov eax,ecx
fixmul Matrix_scale.x
imul Canv_w2
sphere_proj_div: divcheck [esi].z,sphere_div_overflow_handler
idiv [esi].z
mov ebx,eax
mov eax,[esi].p3_sx
mov edx,[esi].p3_sy
call gr_disk_
sphere_div_overflow_handler:
popm eax,ebx,ecx,edx
reject_sphere: ret
_TEXT ends
end