1357 lines
25 KiB
NASM
1357 lines
25 KiB
NASM
;; Copyright (c) 1992,1993-1995 Argonaut Technologies Limited. All rights reserved.
|
|
;;
|
|
;; $Id: ti8_pfz.asm 1.6 1995/05/25 13:25:15 sam Exp $
|
|
;; $Locker: $
|
|
;;
|
|
;; 8 bit Indexed mode
|
|
;;
|
|
;; Triangle scan convertion and rendering
|
|
;;
|
|
;; Perfect scan, fractional vertices, Z buffered
|
|
;;
|
|
.386p
|
|
.model flat,c
|
|
|
|
include zb.inc
|
|
include 586_macs.inc
|
|
|
|
GRAD_IDIV equ 0
|
|
GRAD_IMUL equ 0
|
|
GRAD_FMUL equ 1
|
|
|
|
X equ 0
|
|
Y equ 1
|
|
Z equ 2
|
|
|
|
;Z_MASK equ 0ffff0000h
|
|
|
|
FRAMEBUFFER_FAR equ 0
|
|
|
|
;; Various macros for generating the triangle renderers
|
|
;;
|
|
|
|
; Setup of a fractional, perfect pixel triangle
|
|
;
|
|
TRIANGLE_SETUP_PF macro
|
|
|
|
; Get Y components of vertices
|
|
;
|
|
mov eax,[esi].temp_vertex.v[4]
|
|
mov ebx,[edi].temp_vertex.v[4]
|
|
mov ecx,[ebp].temp_vertex.v[4]
|
|
|
|
; Sort pointers and values in order of y value
|
|
;
|
|
cmp eax,ebx
|
|
jg short sort_3
|
|
cmp ebx,ecx
|
|
jle short sort_done
|
|
; abc
|
|
cmp eax,ecx
|
|
jg short sort_2
|
|
; acb
|
|
SWAP ebx,ecx
|
|
SWAP edi,ebp
|
|
jmp short sort_done
|
|
sort_2:
|
|
; cab
|
|
SWAP ebx,ecx
|
|
SWAP edi,ebp
|
|
SWAP eax,ebx
|
|
SWAP esi,edi
|
|
jmp short sort_done
|
|
sort_3:
|
|
cmp ecx,ebx
|
|
jg short sort_4
|
|
; cba
|
|
SWAP eax,ecx
|
|
SWAP esi,ebp
|
|
jmp short sort_done
|
|
|
|
sort_4: cmp eax,ecx
|
|
jg short sort_5
|
|
; bac
|
|
SWAP eax,ebx
|
|
SWAP esi,edi
|
|
jmp short sort_done
|
|
sort_5:
|
|
; bca
|
|
SWAP eax,ebx
|
|
SWAP esi,edi
|
|
SWAP ebx,ecx
|
|
SWAP edi,ebp
|
|
sort_done:
|
|
|
|
; Work out top.count and bot.count - the heights of each part
|
|
; of the triangle
|
|
;
|
|
sar eax,16
|
|
sar ebx,16
|
|
sar ecx,16
|
|
sub ecx,ebx
|
|
sub ebx,eax
|
|
mov zb.bot.count,ecx
|
|
mov zb.top.count,ebx
|
|
|
|
or ebx,ecx ; Check for zero height polys
|
|
je quit
|
|
|
|
; Work out deltas and gradients along edges
|
|
;
|
|
; top short edge
|
|
;
|
|
mov edx,[edi].temp_vertex.v[0] ; zb.top.x
|
|
sub edx,[esi].temp_vertex.v[0]
|
|
mov zb.top.x,edx
|
|
|
|
mov ebx,[edi].temp_vertex.v[4] ; zb.top.y
|
|
sub ebx,[esi].temp_vertex.v[4]
|
|
mov zb.top.y,ebx
|
|
|
|
cmp zb.top.count,0
|
|
je short no_top
|
|
|
|
FIX_DIV ; zb.top.grad = zb.top.x/zb.top.y
|
|
idiv ebx
|
|
mov zb.top.grad,eax
|
|
mov word ptr zb.top.d_f+2,ax
|
|
sar eax,16
|
|
add eax,zb.row_width
|
|
mov zb.top.d_i,eax
|
|
no_top:
|
|
; bottom short edge
|
|
;
|
|
xor eax,eax
|
|
mov edx,[ebp].temp_vertex.v[0] ; zb.bot.x
|
|
sub edx,[edi].temp_vertex.v[0]
|
|
mov zb.bot.x,edx
|
|
|
|
mov ebx,[ebp].temp_vertex.v[4] ; zb.bot.y
|
|
sub ebx,[edi].temp_vertex.v[4]
|
|
mov zb.bot.y,ebx
|
|
|
|
cmp zb.bot.count,0
|
|
je short no_bottom
|
|
|
|
FIX_DIV ; zb.bot.grad = zb.bot.x/zb.bot.y
|
|
idiv ebx
|
|
mov zb.bot.grad,eax
|
|
mov word ptr zb.bot.d_f+2,ax
|
|
sar eax,16
|
|
add eax,zb.row_width
|
|
mov zb.bot.d_i,eax
|
|
|
|
no_bottom:
|
|
; long edge
|
|
;
|
|
mov edx,[ebp].temp_vertex.v[0] ; zb.main.x
|
|
sub edx,[esi].temp_vertex.v[0]
|
|
mov zb.main.x,edx
|
|
|
|
mov ebx,[ebp].temp_vertex.v[4] ; zb.main.y
|
|
sub ebx,[esi].temp_vertex.v[4]
|
|
mov zb.main.y,ebx
|
|
|
|
FIX_DIV ; zb.main.grad = zb.main.x/zb.main.y
|
|
idiv ebx
|
|
mov zb.main.grad,eax
|
|
mov word ptr zb.main.d_f+2,ax
|
|
sar eax,16
|
|
add eax,zb.row_width
|
|
mov zb.main.d_i,eax
|
|
|
|
; Work out divisor for use in parameter gradient calcs.
|
|
;
|
|
if GRAD_IDIV
|
|
mov eax,zb.main.x
|
|
imul zb.top.y
|
|
mov ebx,eax
|
|
mov ecx,edx
|
|
|
|
mov eax,zb.top.x
|
|
imul zb.main.y
|
|
sub eax,ebx
|
|
sbb edx,ecx
|
|
FIX_MUL
|
|
mov g_divisor,eax ; bottom of gradient calc.
|
|
endif
|
|
if GRAD_IMUL
|
|
mov eax,zb.main.x
|
|
imul zb.top.y
|
|
mov ebx,eax
|
|
mov ecx,edx
|
|
|
|
mov eax,zb.top.x
|
|
imul zb.main.y
|
|
sub eax,ebx
|
|
sbb edx,ecx
|
|
FIX_MUL
|
|
test eax,eax
|
|
|
|
jz gd_is_zero
|
|
mov ebx,eax
|
|
xor edx,edx
|
|
mov eax,40000000h
|
|
idiv ebx
|
|
add eax,eax
|
|
add eax,eax
|
|
gd_is_zero:
|
|
mov g_divisor,eax ; bottom of gradient calc.
|
|
endif
|
|
if GRAD_FMUL
|
|
mov eax,zb.main.x
|
|
imul zb.top.y
|
|
mov ebx,eax
|
|
mov ecx,edx
|
|
|
|
mov eax,zb.top.x
|
|
imul zb.main.y
|
|
sub eax,ebx
|
|
sbb edx,ecx
|
|
|
|
mov g_d_temp,eax
|
|
mov g_d_temph,edx
|
|
|
|
fild qword ptr g_d_temp
|
|
fld fixed_one
|
|
fdivrp st(1),st
|
|
fstp g_divisor
|
|
endif
|
|
; Initialise bottom x to intersection with middle scanline
|
|
;
|
|
xor ecx,ecx
|
|
sub cx,word ptr [edi].temp_vertex.v[4] ; pdy = 1.0-fraction(p1y)
|
|
|
|
mov eax,zb.bot.grad ; x_b = p1x+pdy*zb.bot.grad
|
|
imul ecx
|
|
FIX_MUL
|
|
add eax,[edi].temp_vertex.v[0]
|
|
mov word ptr zb.bot.f+2,ax
|
|
sar eax,16
|
|
mov zb.bot.i,eax
|
|
|
|
; Initialise top x to intersection with first scanline
|
|
;
|
|
; From here on, only vertex 0 is needed
|
|
;
|
|
; Find x & y offset from vertex 0 to first pixel for use in param. initialisation
|
|
;
|
|
xor ecx,ecx
|
|
sub cx,word ptr [esi].temp_vertex.v[4] ; pdy = 1.0-fraction(p0y)
|
|
mov p0_offset_y,ecx
|
|
|
|
mov eax,zb.main.grad ; x = p0x+pdy*zb.main.grad
|
|
imul ecx
|
|
FIX_MUL
|
|
add eax,[esi].temp_vertex.v[0]
|
|
mov zb.main.f+2,eax
|
|
|
|
xor ax,ax
|
|
mov word ptr zb.main.i+2,ax ; XXX
|
|
|
|
add eax,010000h
|
|
sub eax,[esi].temp_vertex.v[0] ; pdx = integer(x)+1.0-p0x
|
|
mov p0_offset_x,eax
|
|
|
|
mov eax,zb.top.grad ; x_t = p0x+pdy*zb.top.grad
|
|
imul ecx
|
|
FIX_MUL
|
|
add eax,[esi].temp_vertex.v[0]
|
|
mov word ptr zb.top.f+2,ax
|
|
sar eax,16
|
|
mov zb.top.i,eax
|
|
|
|
; Convert integer parts of X variables to pixel offsets
|
|
;
|
|
mov ebx,zb.row_width
|
|
mov ecx,dword ptr zb.colour_buffer
|
|
xor eax,eax
|
|
mov ax,word ptr [esi].temp_vertex.v[4]+2
|
|
imul ebx
|
|
add zb.main.i,eax
|
|
add eax,ecx
|
|
add zb.top.i,eax
|
|
|
|
xor eax,eax
|
|
mov ax,word ptr [edi].temp_vertex.v[4]+2
|
|
imul ebx
|
|
add eax,ecx
|
|
add zb.bot.i,eax
|
|
endm
|
|
|
|
; Per-parameter initialisation of perfect scan, fractionl vertex triangle
|
|
;
|
|
TRIANGLE_PARAM_PF macro vparam,param
|
|
|
|
|
|
if GRAD_IDIV
|
|
; d_p_x = (d_p_1.zb.main.y - d_p_2.zb.top.y)/g_denom
|
|
;
|
|
mov eax,[ebp].temp_vertex.vparam ; d_p_2
|
|
sub eax,[esi].temp_vertex.vparam
|
|
push eax
|
|
imul zb.top.y
|
|
mov ebx,eax
|
|
mov ecx,edx
|
|
mov eax,[edi].temp_vertex.vparam ; d_p_1
|
|
sub eax,[esi].temp_vertex.vparam
|
|
push eax
|
|
imul zb.main.y
|
|
sub eax,ebx
|
|
sbb edx,ecx
|
|
|
|
idiv g_divisor
|
|
mov param.grad_x,eax
|
|
|
|
; d_p_y = (d_p_2.zb.top.x - d_p_1.zb.main.x)/g_denom
|
|
;
|
|
pop eax ; d_p_1
|
|
imul zb.main.x
|
|
mov ebx,eax
|
|
mov ecx,edx
|
|
pop eax ; d_p_2
|
|
imul zb.top.x
|
|
sub eax,ebx
|
|
sbb edx,ecx
|
|
|
|
idiv g_divisor
|
|
mov param.grad_y,eax
|
|
endif
|
|
if GRAD_IMUL
|
|
; d_p_x = (d_p_1.zb.main.y - d_p_2.zb.top.y)/g_denom
|
|
;
|
|
mov eax,[ebp].temp_vertex.vparam ; d_p_2
|
|
sub eax,[esi].temp_vertex.vparam
|
|
push eax
|
|
imul zb.top.y
|
|
mov ebx,eax
|
|
mov ecx,edx
|
|
mov eax,[edi].temp_vertex.vparam ; d_p_1
|
|
sub eax,[esi].temp_vertex.vparam
|
|
push eax
|
|
imul zb.main.y
|
|
sub eax,ebx
|
|
sbb edx,ecx
|
|
|
|
FIX_MUL
|
|
imul g_divisor
|
|
FIX_MUL
|
|
mov param.grad_x,eax
|
|
|
|
; d_p_y = (d_p_2.zb.top.x - d_p_1.zb.main.x)/g_denom
|
|
;
|
|
pop eax ; d_p_1
|
|
imul zb.main.x
|
|
mov ebx,eax
|
|
mov ecx,edx
|
|
pop eax ; d_p_2
|
|
imul zb.top.x
|
|
sub eax,ebx
|
|
sbb edx,ecx
|
|
|
|
FIX_MUL
|
|
imul g_divisor
|
|
FIX_MUL
|
|
mov param.grad_y,eax
|
|
endif
|
|
if GRAD_FMUL
|
|
; d_p_x = (d_p_1.zb.main.y - d_p_2.zb.top.y)/g_denom
|
|
;
|
|
mov eax,[ebp].temp_vertex.vparam ; d_p_2
|
|
sub eax,[esi].temp_vertex.vparam
|
|
push eax
|
|
imul zb.top.y
|
|
mov ebx,eax
|
|
mov ecx,edx
|
|
mov eax,[edi].temp_vertex.vparam ; d_p_1
|
|
sub eax,[esi].temp_vertex.vparam
|
|
push eax
|
|
imul zb.main.y
|
|
sub eax,ebx
|
|
sbb edx,ecx
|
|
|
|
mov g_d_temp,eax
|
|
mov g_d_temph,edx
|
|
|
|
fild qword ptr g_d_temp
|
|
|
|
fmul g_divisor
|
|
fistp param.grad_x
|
|
|
|
; d_p_y = (d_p_2.zb.top.x - d_p_1.zb.main.x)/g_denom
|
|
;
|
|
pop eax ; d_p_1
|
|
imul zb.main.x
|
|
mov ebx,eax
|
|
mov ecx,edx
|
|
pop eax ; d_p_2
|
|
imul zb.top.x
|
|
sub eax,ebx
|
|
sbb edx,ecx
|
|
|
|
mov g_d_temp,eax
|
|
mov g_d_temph,edx
|
|
|
|
fild qword ptr g_d_temp
|
|
|
|
fmul g_divisor
|
|
fistp param.grad_y
|
|
endif
|
|
|
|
; Initialise parameter to starting pixel centre
|
|
;
|
|
mov eax,param.grad_y ; p = p0x+pdy*d_p_y+pdx*d_p_x
|
|
imul p0_offset_y
|
|
mov ecx,eax
|
|
mov ebx,edx
|
|
mov eax,param.grad_x
|
|
imul p0_offset_x
|
|
add eax,ecx
|
|
adc edx,ebx
|
|
FIX_MUL
|
|
add eax,[esi].temp_vertex.vparam
|
|
mov param.current,eax
|
|
|
|
; Work out parameter increments per scanline
|
|
;
|
|
movsx eax,word ptr zb.main.grad+2
|
|
imul param.grad_x
|
|
add eax,param.grad_y
|
|
mov param.d_nocarry,eax
|
|
add eax,param.grad_x
|
|
mov param.d_carry,eax
|
|
endm
|
|
|
|
; Invoke the trapezoid macro for the appropriate renderer
|
|
;
|
|
TRIANGLE_RENDER macro trapezoid_mac
|
|
|
|
; See which side has long edge
|
|
;
|
|
if GRAD_IDIV
|
|
cmp g_divisor,0
|
|
jl reversed
|
|
endif
|
|
if GRAD_IMUL
|
|
cmp g_divisor,0
|
|
jl reversed
|
|
endif
|
|
if GRAD_FMUL
|
|
cmp dword ptr g_divisor+4,0
|
|
jl reversed
|
|
endif
|
|
|
|
; Scan convert top half of triangle - if any - forwards
|
|
;
|
|
% trapezoid_mac top,1
|
|
|
|
; Scan convert bottom half of triangle - if any - forwards
|
|
;
|
|
% trapezoid_mac bot,1
|
|
quit: ret
|
|
|
|
reversed:
|
|
; Scan convert top half of triangle - if any - backwards
|
|
;
|
|
% trapezoid_mac top,0
|
|
|
|
; Scan convert bottom half of triangle - if any - backwards
|
|
;
|
|
% trapezoid_mac bot,0
|
|
ret
|
|
|
|
endm
|
|
|
|
.data
|
|
db '$Id: ti8_pfz.asm 1.6 1995/05/25 13:25:15 sam Exp $',0
|
|
align 4
|
|
|
|
p0_offset_x dd 0 ; Offset of start pixel centre from vertex 0
|
|
p0_offset_y dd 0
|
|
|
|
temp_i dd 0
|
|
temp_u dd 0
|
|
temp_v dd 0
|
|
|
|
if GRAD_IMUL
|
|
g_divisor dd 0 ; Bottom of param. gradient calc.
|
|
endif
|
|
|
|
if GRAD_IDIV
|
|
g_divisor dd 0 ; Bottom of param. gradient calc.
|
|
endif
|
|
|
|
if GRAD_FMUL
|
|
g_divisor real8 0.0 ; Bottom of param. gradient calc.
|
|
fixed_one real4 65536.0
|
|
g_d_temp dd 0
|
|
g_d_temph dd 0
|
|
endif
|
|
.code
|
|
|
|
; Trapezoid loop for flat shaded z buffered faces
|
|
;
|
|
; Arguments control:
|
|
; whether loop uses 'top' or 'bottom' variables
|
|
; which direction scanline are rendered from the long edge
|
|
;
|
|
TRAPEZOID_PFZ2 macro half,forward
|
|
local scan_loop,pixel_loop,pixel_behind,no_pixels
|
|
local start_carried,done_trapezoid
|
|
|
|
cmp zb.half.count,0
|
|
je done_trapezoid
|
|
|
|
mov ecx,zb.half.i
|
|
|
|
; Prepare for next iteration of loop
|
|
;
|
|
scan_loop:
|
|
push esi
|
|
push edx
|
|
|
|
mov edi,zb.depth_buffer
|
|
lea edi,[edi+esi*2]
|
|
add esi,dword ptr zb.colour_buffer
|
|
|
|
; Render same colour pixels along scanline (forwards or backwards)
|
|
;
|
|
; bl: colour
|
|
; ecx: address of end of scanline
|
|
; edx: z (16.16)
|
|
; ebp: z delta (16.16)
|
|
; esi: frame buffer ptr
|
|
; edi: z buffer ptr
|
|
;
|
|
if forward
|
|
cmp esi,ecx
|
|
jae short no_pixels
|
|
pixel_loop:
|
|
mov eax,edx
|
|
shr eax,16
|
|
cmp ax,[edi] ; if (z > *zptr)
|
|
jae short pixel_behind
|
|
mov [edi],ax ; *zptr = z
|
|
|
|
if FRAMEBUFFER_FAR
|
|
mov es:[esi],bl ; *ptr = colour
|
|
else
|
|
mov [esi],bl ; *ptr = colour
|
|
endif
|
|
pixel_behind:
|
|
add edx,ebp ; z += d_z_z
|
|
add edi,2 ; z_ptr++
|
|
inc esi ; ptr++
|
|
cmp esi,ecx
|
|
jb short pixel_loop
|
|
else
|
|
cmp esi,ecx
|
|
jbe short no_pixels
|
|
pixel_loop:
|
|
sub edx,ebp ; z += d_z_z
|
|
sub edi,2 ; z_ptr++
|
|
dec esi ; ptr++
|
|
|
|
mov eax,edx
|
|
shr eax,16
|
|
cmp ax,[edi] ; if (z > *zptr)
|
|
jae short pixel_behind
|
|
|
|
mov [edi],ax ; *zptr = z
|
|
|
|
if FRAMEBUFFER_FAR
|
|
mov es:[esi],bl ; *ptr = colour
|
|
else
|
|
mov [esi],bl ; *ptr = colour
|
|
endif
|
|
|
|
pixel_behind:
|
|
cmp esi,ecx
|
|
ja short pixel_loop
|
|
endif
|
|
no_pixels:
|
|
|
|
; Updates for next scanline:
|
|
;
|
|
pop edx
|
|
pop esi
|
|
mov edi,zb.half.d_f
|
|
mov eax,zb.main.d_f ; x+= zb.main.grad (fraction)
|
|
add zb.main.f,eax
|
|
jc start_carried
|
|
|
|
add esi,zb.main.d_i ; fb_offset+=delta+CARRY
|
|
add edx,zb.pz.d_nocarry
|
|
|
|
add zb.half.f,edi ; x_end += zb.main.grad_end (fraction)
|
|
adc ecx,zb.half.d_i ; endptr += integer(dx_end)+CARRY
|
|
|
|
dec zb.half.count
|
|
jne short scan_loop
|
|
jmp short done_trapezoid
|
|
|
|
start_carried: adc esi,zb.main.d_i ; fb_offset+=delta+CARRY
|
|
add edx,zb.pz.d_carry
|
|
|
|
add zb.half.f,edi ; x_end += zb.main.grad_end (fraction)
|
|
adc ecx,zb.half.d_i ; endptr += integer(dx_end)+CARRY
|
|
|
|
dec zb.half.count
|
|
jne scan_loop
|
|
done_trapezoid:
|
|
endm
|
|
|
|
; void TriangleRenderPFZ2(struct br_vertex *pvertex_0,
|
|
; struct br_vertex *pvertex_1,
|
|
; struct br_vertex *pvertex_2);
|
|
;
|
|
; C stub directly to triangle renderer
|
|
;
|
|
TriangleRenderPFZ2 proc uses eax ebx ecx edx esi edi,
|
|
pvertex_0 : ptr word,
|
|
pvertex_1 : ptr word,
|
|
pvertex_2 : ptr word
|
|
|
|
; Get pointers to vertex structures and colour
|
|
;
|
|
; eax = colour
|
|
; esi = vertex 0
|
|
; edi = vertex 1
|
|
; ebp = vertex 2
|
|
;
|
|
push ebp
|
|
if FRAMEBUFFER_FAR
|
|
push es
|
|
endif
|
|
mov esi,pvertex_0
|
|
mov edi,pvertex_1
|
|
mov ebp,pvertex_2
|
|
call RawTriangle_PFZ2
|
|
if FRAMEBUFFER_FAR
|
|
pop es
|
|
endif
|
|
pop ebp
|
|
ret
|
|
TriangleRenderPFZ2 endp
|
|
|
|
; Triangle_PFZ2
|
|
;
|
|
; Render a triangle into frame buffer
|
|
;
|
|
; Flat colour
|
|
; Z buffer
|
|
; Fractional vertices
|
|
; Perfect point sampling
|
|
;
|
|
; esi = vertex 0 pointer
|
|
; edi = vertex 1 pointer
|
|
; ebp = vertex 2 pointer
|
|
;
|
|
RawTriangle_PFZ2 proc
|
|
|
|
TRIANGLE_SETUP_PF
|
|
TRIANGLE_PARAM_PF v[Z*4],zb.pz
|
|
|
|
; Load up registers for first time around inner loop
|
|
;
|
|
mov esi,zb.main.i
|
|
mov edx,zb.pz.current
|
|
mov ebp,zb.pz.grad_x
|
|
mov bl,byte ptr zb.pi.current+2
|
|
if FRAMEBUFFER_FAR
|
|
mov es,word ptr zb.colour_buffer+4
|
|
endif
|
|
|
|
TRIANGLE_RENDER TRAPEZOID_PFZ2
|
|
|
|
RawTriangle_PFZ2 endp
|
|
|
|
; void TriangleRenderPFZ2I(struct br_vertex *pvertex_0,
|
|
; struct br_vertex *pvertex_1,
|
|
; struct br_vertex *pvertex_2);
|
|
;
|
|
; C stub directly to triangle renderer
|
|
;
|
|
TriangleRenderPFZ2I proc uses eax ebx ecx edx esi edi,
|
|
pvertex_0 : ptr word,
|
|
pvertex_1 : ptr word,
|
|
pvertex_2 : ptr word
|
|
|
|
; Get pointers to vertex structures and colour
|
|
;
|
|
; eax = colour
|
|
; esi = vertex 0
|
|
; edi = vertex 1
|
|
; ebp = vertex 2
|
|
;
|
|
push ebp
|
|
if FRAMEBUFFER_FAR
|
|
push es
|
|
endif
|
|
mov esi,pvertex_0
|
|
mov edi,pvertex_1
|
|
mov ebp,pvertex_2
|
|
call RawTriangle_PFZ2I
|
|
if FRAMEBUFFER_FAR
|
|
pop es
|
|
endif
|
|
pop ebp
|
|
ret
|
|
TriangleRenderPFZ2I endp
|
|
|
|
; Trapezoid loop for gouraud shaded z buffered faces
|
|
;
|
|
; Arguments control:
|
|
; whether loop uses 'top' or 'bottom' variables
|
|
; which direction scanline are rendered from the long edge
|
|
;
|
|
TRAPEZOID_PFZ2I macro half,forward
|
|
local scan_loop,pixel_loop,pixel_behind,no_pixels
|
|
local start_carried,done_trapezoid
|
|
|
|
cmp zb.half.count,0
|
|
je done_trapezoid
|
|
|
|
mov ecx,zb.half.i
|
|
|
|
; Prepare for next iteration of loop
|
|
;
|
|
scan_loop:
|
|
push esi
|
|
push edx
|
|
|
|
mov edi,zb.depth_buffer
|
|
lea edi,[edi+esi*2]
|
|
add esi,dword ptr zb.colour_buffer
|
|
mov eax,zb.pi.current
|
|
|
|
; Render same colour pixels along scanline (forwards or backwards)
|
|
;
|
|
; bl: colour
|
|
; ecx: address of end of scanline
|
|
; edx: z (16.16)
|
|
; ebp: z delta (16.16)
|
|
; esi: frame buffer ptr
|
|
; edi: z buffer ptr
|
|
;
|
|
if forward
|
|
cmp esi,ecx
|
|
jae short no_pixels
|
|
pixel_loop:
|
|
mov ebx,edx
|
|
shr ebx,16
|
|
cmp bx,[edi] ; if (z > *zptr)
|
|
jae short pixel_behind
|
|
|
|
ifndef Z_MASK
|
|
mov [edi],bx ; *zptr = z
|
|
else
|
|
mov ebx,edx
|
|
and ebx,Z_MASK
|
|
mov [edi],ebx
|
|
endif
|
|
|
|
mov ebx,eax
|
|
shr ebx,16
|
|
if FRAMEBUFFER_FAR
|
|
mov es:[esi],bl ; *ptr = colour
|
|
else
|
|
mov [esi],bl ; *ptr = colour
|
|
endif
|
|
pixel_behind:
|
|
add edx,ebp ; z += d_z_z
|
|
add eax,zb.pi.grad_x
|
|
add edi,2 ; z_ptr++
|
|
inc esi ; ptr++
|
|
cmp esi,ecx
|
|
jb short pixel_loop
|
|
else
|
|
cmp esi,ecx
|
|
jbe short no_pixels
|
|
pixel_loop:
|
|
sub edx,ebp ; z += d_z_z
|
|
sub eax,zb.pi.grad_x
|
|
sub edi,2 ; z_ptr++
|
|
dec esi ; ptr++
|
|
|
|
mov ebx,edx
|
|
shr ebx,16
|
|
cmp bx,[edi] ; if (z > *zptr)
|
|
jae short pixel_behind
|
|
|
|
ifndef Z_MASK
|
|
mov [edi],bx ; *zptr = z
|
|
else
|
|
mov ebx,edx
|
|
and ebx,Z_MASK
|
|
mov [edi],ebx
|
|
endif
|
|
mov ebx,eax
|
|
shr ebx,16
|
|
if FRAMEBUFFER_FAR
|
|
mov es:[esi],bl ; *ptr = colour
|
|
else
|
|
mov [esi],bl ; *ptr = colour
|
|
endif
|
|
pixel_behind:
|
|
cmp esi,ecx
|
|
ja short pixel_loop
|
|
endif
|
|
no_pixels:
|
|
|
|
; Updates for next scanline:
|
|
;
|
|
pop edx
|
|
pop esi
|
|
mov edi,zb.half.d_f
|
|
mov eax,zb.main.d_f ; x+= zb.main.grad (fraction)
|
|
add zb.main.f,eax
|
|
jc start_carried
|
|
|
|
add esi,zb.main.d_i ; fb_offset+=delta+CARRY
|
|
add edx,zb.pz.d_nocarry
|
|
mov eax,zb.pi.d_nocarry
|
|
add zb.pi.current,eax
|
|
|
|
add zb.half.f,edi ; x_end += zb.main.grad_end (fraction)
|
|
adc ecx,zb.half.d_i ; endptr += integer(dx_end)+CARRY
|
|
|
|
dec zb.half.count
|
|
jne short scan_loop
|
|
jmp short done_trapezoid
|
|
|
|
start_carried: adc esi,zb.main.d_i ; fb_offset+=delta+CARRY
|
|
add edx,zb.pz.d_carry
|
|
mov eax,zb.pi.d_carry
|
|
add zb.pi.current,eax
|
|
|
|
add zb.half.f,edi ; x_end += zb.main.grad_end (fraction)
|
|
adc ecx,zb.half.d_i ; endptr += integer(dx_end)+CARRY
|
|
|
|
dec zb.half.count
|
|
jne scan_loop
|
|
done_trapezoid:
|
|
endm
|
|
|
|
|
|
; RawTriangle_PFZ2I
|
|
;
|
|
; Render a triangle into frame buffer
|
|
;
|
|
; Linear interpolated colour index
|
|
; Linear interpolated Z value
|
|
; Fractional vertices
|
|
; Perfect point sampling
|
|
;
|
|
; esi = vertex 0 pointer
|
|
; edi = vertex 1 pointer
|
|
; ebp = vertex 2 pointer
|
|
;
|
|
RawTriangle_PFZ2I proc
|
|
|
|
TRIANGLE_SETUP_PF
|
|
TRIANGLE_PARAM_PF v[Z*4],zb.pz
|
|
TRIANGLE_PARAM_PF comp[C_I*4],zb.pi
|
|
|
|
; Load up registers for first time around inner loop
|
|
;
|
|
mov esi,zb.main.i
|
|
mov edx,zb.pz.current
|
|
mov ebp,zb.pz.grad_x
|
|
if FRAMEBUFFER_FAR
|
|
mov es,word ptr zb.colour_buffer+4
|
|
endif
|
|
TRIANGLE_RENDER TRAPEZOID_PFZ2I
|
|
|
|
RawTriangle_PFZ2I endp
|
|
|
|
|
|
TriangleRenderPFZ2T proc uses eax ebx ecx edx esi edi,
|
|
pvertex_0 : ptr word,
|
|
pvertex_1 : ptr word,
|
|
pvertex_2 : ptr word
|
|
|
|
; Get pointers to vertex structures and colour
|
|
;
|
|
; eax = colour
|
|
; esi = vertex 0
|
|
; edi = vertex 1
|
|
; ebp = vertex 2
|
|
;
|
|
push ebp
|
|
if FRAMEBUFFER_FAR
|
|
push es
|
|
endif
|
|
mov esi,pvertex_0
|
|
mov edi,pvertex_1
|
|
mov ebp,pvertex_2
|
|
call RawTriangle_PFZ2T
|
|
if FRAMEBUFFER_FAR
|
|
pop es
|
|
endif
|
|
pop ebp
|
|
ret
|
|
TriangleRenderPFZ2T endp
|
|
|
|
; Trapezoid loop for linear texture mapped z buffered faces
|
|
;
|
|
; Arguments control:
|
|
; whether loop uses 'top' or 'bottom' variables
|
|
; which direction scanline are rendered from the long edge
|
|
;
|
|
TRAPEZOID_PFZ2T macro half,forward
|
|
local scan_loop,pixel_loop,pixel_behind,no_pixels
|
|
local start_carried,done_trapezoid
|
|
|
|
cmp zb.half.count,0
|
|
je done_trapezoid
|
|
|
|
mov ecx,zb.half.i
|
|
|
|
; Prepare for next iteration of loop
|
|
;
|
|
scan_loop:
|
|
push esi
|
|
push edx
|
|
|
|
mov edi,zb.depth_buffer
|
|
lea edi,[edi+esi*2]
|
|
add esi,dword ptr zb.colour_buffer
|
|
|
|
mov eax,zb.pu.current
|
|
mov ebx,zb.pv.current
|
|
mov temp_u,eax
|
|
mov temp_v,ebx
|
|
|
|
; Render same colour pixels along scanline (forwards or backwards)
|
|
;
|
|
; bl: colour
|
|
; ecx: address of end of scanline
|
|
; edx: z (16.16)
|
|
; ebp: z delta (16.16)
|
|
; esi: frame buffer ptr
|
|
; edi: z buffer ptr
|
|
;
|
|
if forward
|
|
cmp esi,ecx
|
|
jae no_pixels
|
|
pixel_loop:
|
|
mov ebx,edx
|
|
shr ebx,16
|
|
cmp bx,[edi] ; if (z > *zptr)
|
|
jae short pixel_behind
|
|
mov [edi],bx ; *zptr = z
|
|
|
|
;; Per pixel fetch colour
|
|
;;
|
|
xor ebx,ebx
|
|
mov bl,byte ptr temp_u+3
|
|
mov bh,byte ptr temp_v+3
|
|
add ebx,zb.texture_buffer
|
|
mov bl,[ebx]
|
|
|
|
if FRAMEBUFFER_FAR
|
|
mov es:[esi],bl ; *ptr = colour
|
|
else
|
|
mov [esi],bl ; *ptr = colour
|
|
endif
|
|
pixel_behind:
|
|
add edx,ebp ; z += d_z_z
|
|
|
|
;; Per pixel update - forwards
|
|
;;
|
|
mov eax,temp_u
|
|
mov ebx,temp_v
|
|
add eax,zb.pu.grad_x
|
|
add ebx,zb.pv.grad_x
|
|
mov temp_u,eax
|
|
mov temp_v,ebx
|
|
|
|
add edi,2 ; z_ptr++
|
|
inc esi ; ptr++
|
|
cmp esi,ecx
|
|
jb pixel_loop
|
|
else
|
|
cmp esi,ecx
|
|
jbe no_pixels
|
|
pixel_loop:
|
|
sub edx,ebp ; z += d_z_z
|
|
|
|
;; Per pixel update - backwards
|
|
;;
|
|
mov eax,temp_u
|
|
mov ebx,temp_v
|
|
sub eax,zb.pu.grad_x
|
|
sub ebx,zb.pv.grad_x
|
|
mov temp_u,eax
|
|
mov temp_v,ebx
|
|
|
|
sub edi,2 ; z_ptr++
|
|
dec esi ; ptr++
|
|
|
|
mov ebx,edx
|
|
shr ebx,16
|
|
cmp bx,[edi] ; if (z > *zptr)
|
|
jae short pixel_behind
|
|
mov [edi],bx ; *zptr = z
|
|
|
|
;; Per pixel fetch colour
|
|
;;
|
|
xor ebx,ebx
|
|
mov bl,byte ptr temp_u+3
|
|
mov bh,byte ptr temp_v+3
|
|
add ebx,zb.texture_buffer
|
|
mov bl,[ebx]
|
|
|
|
if FRAMEBUFFER_FAR
|
|
mov es:[esi],bl ; *ptr = colour
|
|
else
|
|
mov [esi],bl ; *ptr = colour
|
|
endif
|
|
pixel_behind:
|
|
cmp esi,ecx
|
|
ja pixel_loop
|
|
endif
|
|
no_pixels:
|
|
|
|
; Updates for next scanline:
|
|
;
|
|
pop edx
|
|
pop esi
|
|
mov edi,zb.half.d_f
|
|
mov eax,zb.main.d_f ; x+= zb.main.grad (fraction)
|
|
add zb.main.f,eax
|
|
jc start_carried
|
|
|
|
add esi,zb.main.d_i ; fb_offset+=delta+CARRY
|
|
add edx,zb.pz.d_nocarry
|
|
|
|
if 1
|
|
;; Per scanline parameter update - no carry
|
|
;;
|
|
mov eax,zb.pu.current
|
|
mov ebx,zb.pv.current
|
|
add eax,zb.pu.d_nocarry
|
|
add ebx,zb.pv.d_nocarry
|
|
mov zb.pu.current,eax
|
|
mov zb.pv.current,ebx
|
|
endif
|
|
|
|
add zb.half.f,edi ; x_end += zb.main.grad_end (fraction)
|
|
adc ecx,zb.half.d_i ; endptr += integer(dx_end)+CARRY
|
|
|
|
dec zb.half.count
|
|
jne scan_loop
|
|
jmp done_trapezoid
|
|
|
|
start_carried: adc esi,zb.main.d_i ; fb_offset+=delta+CARRY
|
|
add edx,zb.pz.d_carry
|
|
|
|
if 1
|
|
;; Per scanline parameter update - carry
|
|
;;
|
|
mov eax,zb.pu.current
|
|
mov ebx,zb.pv.current
|
|
add eax,zb.pu.d_carry
|
|
add ebx,zb.pv.d_carry
|
|
mov zb.pu.current,eax
|
|
mov zb.pv.current,ebx
|
|
endif
|
|
|
|
add zb.half.f,edi ; x_end += zb.main.grad_end (fraction)
|
|
adc ecx,zb.half.d_i ; endptr += integer(dx_end)+CARRY
|
|
|
|
dec zb.half.count
|
|
jne scan_loop
|
|
done_trapezoid:
|
|
endm
|
|
|
|
|
|
; RawTriangle_PFZ2T
|
|
;
|
|
; Render a triangle into frame buffer
|
|
;
|
|
; Linear interpolated colour texture
|
|
; Linear interpolated Z value
|
|
; Fractional vertices
|
|
; Perfect point sampling
|
|
;
|
|
; esi = vertex 0 pointer
|
|
; edi = vertex 1 pointer
|
|
; ebp = vertex 2 pointer
|
|
;
|
|
RawTriangle_PFZ2T proc
|
|
|
|
TRIANGLE_SETUP_PF
|
|
TRIANGLE_PARAM_PF v[Z*4],zb.pz
|
|
TRIANGLE_PARAM_PF comp[C_U*4],zb.pu
|
|
TRIANGLE_PARAM_PF comp[C_V*4],zb.pv
|
|
|
|
; Load up registers for first time around inner loop
|
|
;
|
|
mov esi,zb.main.i
|
|
mov edx,zb.pz.current
|
|
mov ebp,zb.pz.grad_x
|
|
|
|
if FRAMEBUFFER_FAR
|
|
mov es,word ptr zb.colour_buffer+4
|
|
endif
|
|
TRIANGLE_RENDER TRAPEZOID_PFZ2T
|
|
|
|
RawTriangle_PFZ2T endp
|
|
|
|
TriangleRenderPFZ2TI proc uses eax ebx ecx edx esi edi,
|
|
pvertex_0 : ptr word,
|
|
pvertex_1 : ptr word,
|
|
pvertex_2 : ptr word
|
|
|
|
; Get pointers to vertex structures and colour
|
|
;
|
|
; eax = colour
|
|
; esi = vertex 0
|
|
; edi = vertex 1
|
|
; ebp = vertex 2
|
|
;
|
|
push ebp
|
|
if FRAMEBUFFER_FAR
|
|
push es
|
|
endif
|
|
mov esi,pvertex_0
|
|
mov edi,pvertex_1
|
|
mov ebp,pvertex_2
|
|
call RawTriangle_PFZ2TI
|
|
if FRAMEBUFFER_FAR
|
|
pop es
|
|
endif
|
|
pop ebp
|
|
ret
|
|
TriangleRenderPFZ2TI endp
|
|
|
|
; Trapezoid loop for linear texture mapped z buffered faces
|
|
;
|
|
; Arguments control:
|
|
; whether loop uses 'top' or 'bottom' variables
|
|
; which direction scanline are rendered from the long edge
|
|
;
|
|
TRAPEZOID_PFZ2TI macro half,forward
|
|
local scan_loop,pixel_loop,pixel_behind,no_pixels
|
|
local start_carried,done_trapezoid
|
|
|
|
cmp zb.half.count,0
|
|
je done_trapezoid
|
|
|
|
mov ecx,zb.half.i
|
|
|
|
; Prepare for next iteration of loop
|
|
;
|
|
scan_loop:
|
|
push esi
|
|
push edx
|
|
|
|
mov edi,zb.depth_buffer
|
|
lea edi,[edi+esi*2]
|
|
add esi,dword ptr zb.colour_buffer
|
|
|
|
mov eax,zb.pu.current
|
|
mov ebx,zb.pv.current
|
|
mov ebp,zb.pi.current
|
|
mov temp_u,eax
|
|
mov temp_v,ebx
|
|
mov temp_i,ebp
|
|
|
|
; Render same colour pixels along scanline (forwards or backwards)
|
|
;
|
|
; bl: colour
|
|
; ecx: address of end of scanline
|
|
; edx: z (16.16)
|
|
; ebp: z delta (16.16)
|
|
; esi: frame buffer ptr
|
|
; edi: z buffer ptr
|
|
;
|
|
if forward
|
|
cmp esi,ecx
|
|
jae no_pixels
|
|
pixel_loop:
|
|
mov ebx,edx
|
|
shr ebx,16
|
|
cmp bx,[edi] ; if (z > *zptr)
|
|
jae short pixel_behind
|
|
mov [edi],bx ; *zptr = z
|
|
|
|
;; Per pixel fetch colour
|
|
;;
|
|
xor eax,eax
|
|
xor ebx,ebx
|
|
mov bl,byte ptr temp_u+3
|
|
mov bh,byte ptr temp_v+3
|
|
add ebx,zb.texture_buffer
|
|
mov al,[ebx]
|
|
mov ah,byte ptr temp_i+2
|
|
add eax,zb.shade_table
|
|
mov al,[eax]
|
|
|
|
if FRAMEBUFFER_FAR
|
|
mov es:[esi],al ; *ptr = colour
|
|
else
|
|
mov [esi],al ; *ptr = colour
|
|
endif
|
|
pixel_behind:
|
|
add edx,zb.pz.grad_x ; z += d_z_z
|
|
|
|
;; Per pixel update - forwards
|
|
;;
|
|
mov ebp,temp_i
|
|
mov eax,temp_u
|
|
mov ebx,temp_v
|
|
add ebp,zb.pi.grad_x
|
|
add eax,zb.pu.grad_x
|
|
add ebx,zb.pv.grad_x
|
|
mov temp_i,ebp
|
|
mov temp_u,eax
|
|
mov temp_v,ebx
|
|
|
|
add edi,2 ; z_ptr++
|
|
inc esi ; ptr++
|
|
cmp esi,ecx
|
|
jb pixel_loop
|
|
else
|
|
cmp esi,ecx
|
|
jbe no_pixels
|
|
pixel_loop:
|
|
sub edx,zb.pz.grad_x ; z += d_z_z
|
|
|
|
;; Per pixel update - backwards
|
|
;;
|
|
mov ebp,temp_i
|
|
mov eax,temp_u
|
|
mov ebx,temp_v
|
|
sub ebp,zb.pi.grad_x
|
|
sub eax,zb.pu.grad_x
|
|
sub ebx,zb.pv.grad_x
|
|
mov temp_i,ebp
|
|
mov temp_u,eax
|
|
mov temp_v,ebx
|
|
|
|
sub edi,2 ; z_ptr++
|
|
dec esi ; ptr++
|
|
|
|
mov ebx,edx
|
|
shr ebx,16
|
|
cmp bx,[edi] ; if (z > *zptr)
|
|
jae short pixel_behind
|
|
mov [edi],bx ; *zptr = z
|
|
|
|
;; Per pixel fetch colour
|
|
;;
|
|
xor eax,eax
|
|
xor ebx,ebx
|
|
mov bl,byte ptr temp_u+3
|
|
mov bh,byte ptr temp_v+3
|
|
add ebx,zb.texture_buffer
|
|
mov al,[ebx]
|
|
mov ah,byte ptr temp_i+2
|
|
add eax,zb.shade_table
|
|
mov al,[eax]
|
|
|
|
if FRAMEBUFFER_FAR
|
|
mov es:[esi],al ; *ptr = colour
|
|
else
|
|
mov [esi],al ; *ptr = colour
|
|
endif
|
|
pixel_behind:
|
|
cmp esi,ecx
|
|
ja pixel_loop
|
|
endif
|
|
no_pixels:
|
|
|
|
; Updates for next scanline:
|
|
;
|
|
pop edx
|
|
pop esi
|
|
mov edi,zb.half.d_f
|
|
mov eax,zb.main.d_f ; x+= zb.main.grad (fraction)
|
|
add zb.main.f,eax
|
|
jc start_carried
|
|
|
|
add esi,zb.main.d_i ; fb_offset+=delta+CARRY
|
|
add edx,zb.pz.d_nocarry
|
|
|
|
;; Per scanline parameter update - no carry
|
|
;;
|
|
mov ebp,zb.pi.current
|
|
mov eax,zb.pu.current
|
|
mov ebx,zb.pv.current
|
|
add ebp,zb.pi.d_nocarry
|
|
add eax,zb.pu.d_nocarry
|
|
add ebx,zb.pv.d_nocarry
|
|
mov zb.pi.current,ebp
|
|
mov zb.pu.current,eax
|
|
mov zb.pv.current,ebx
|
|
|
|
add zb.half.f,edi ; x_end += zb.main.grad_end (fraction)
|
|
adc ecx,zb.half.d_i ; endptr += integer(dx_end)+CARRY
|
|
|
|
dec zb.half.count
|
|
jne scan_loop
|
|
jmp done_trapezoid
|
|
|
|
start_carried: adc esi,zb.main.d_i ; fb_offset+=delta+CARRY
|
|
add edx,zb.pz.d_carry
|
|
|
|
;; Per scanline parameter update - carry
|
|
;;
|
|
mov ebp,zb.pi.current
|
|
mov eax,zb.pu.current
|
|
mov ebx,zb.pv.current
|
|
add ebp,zb.pi.d_carry
|
|
add eax,zb.pu.d_carry
|
|
add ebx,zb.pv.d_carry
|
|
mov zb.pi.current,ebp
|
|
mov zb.pu.current,eax
|
|
mov zb.pv.current,ebx
|
|
|
|
add zb.half.f,edi ; x_end += zb.main.grad_end (fraction)
|
|
adc ecx,zb.half.d_i ; endptr += integer(dx_end)+CARRY
|
|
|
|
dec zb.half.count
|
|
jne scan_loop
|
|
done_trapezoid:
|
|
endm
|
|
|
|
|
|
; RawTriangle_PFZ2TI
|
|
;
|
|
; Render a triangle into frame buffer
|
|
;
|
|
; Linear interpolated colour texture
|
|
; Linear interpolated shade index
|
|
; Linear interpolated Z value
|
|
; Fractional vertices
|
|
; Perfect point sampling
|
|
;
|
|
; esi = vertex 0 pointer
|
|
; edi = vertex 1 pointer
|
|
; ebp = vertex 2 pointer
|
|
;
|
|
RawTriangle_PFZ2TI proc
|
|
|
|
TRIANGLE_SETUP_PF
|
|
TRIANGLE_PARAM_PF v[Z*4],zb.pz
|
|
TRIANGLE_PARAM_PF comp[C_I*4],zb.pi
|
|
TRIANGLE_PARAM_PF comp[C_U*4],zb.pu
|
|
TRIANGLE_PARAM_PF comp[C_V*4],zb.pv
|
|
|
|
; Load up registers for first time around inner loop
|
|
;
|
|
mov esi,zb.main.i
|
|
mov edx,zb.pz.current
|
|
if FRAMEBUFFER_FAR
|
|
mov es,word ptr zb.colour_buffer+4
|
|
endif
|
|
TRIANGLE_RENDER TRAPEZOID_PFZ2TI
|
|
|
|
RawTriangle_PFZ2TI endp
|
|
|
|
|
|
end
|
|
|