;---------------------------Module-Header------------------------------; ; Module Name: texspan.asm ; ; Include file for "body" of texture routines. ; ; Created: 011/15/1995 ; Author: Otto Berkes [ottob] ; ; Copyright (c) 1995 Microsoft Corporation ;----------------------------------------------------------------------; rMask = ((1 SHL rBits) - 1) SHL rShift gMask = ((1 SHL gBits) - 1) SHL gShift bMask = ((1 SHL bBits) - 1) SHL bShift if REPLACE rRightShiftAdj = 16 - (rShift + rBits) gRightShiftAdj = 16 - (gShift + gBits) bRightShiftAdj = 16 - (bShift + bBits) else rRightShiftAdj = 16 - (rShift) gRightShiftAdj = 16 - (gShift) bRightShiftAdj = 16 - (bShift) endif TMASK_SUBDIV equ [esi].GENGC_tMaskSubDiv TSHIFT_SUBDIV equ [esi].GENGC_tShiftSubDiv if FAST_REPLACE TEXPALETTE equ [esi].GENGC_texImageReplace if (PALETTE_ONLY) TEXIMAGE equ [esi].GENGC_texImage else TEXIMAGE equ [esi].GENGC_texImageReplace endif if PALETTE_ONLY TEX_BPP_LOG2 = 0 elseif (BPP eq 8) TEX_BPP_LOG2 = 0 else TEX_BPP_LOG2 = 1 endif else TEXPALETTE equ [esi].GENGC_texPalette TEXIMAGE equ [esi].GENGC_texImage if PALETTE_ONLY TEX_BPP_LOG2 = 0 else TEX_BPP_LOG2 = 2 endif endif ;; ;; ;; Macros for alpha modulation, and alpha reads ;; ;; ALPHAMODULATE MACRO mov ah, [esi].GENGC_aAccum+2 mov al, [edx+3] and eax, 0ffffh mov ch, _gbMulTable[eax] mov [esi].GENGC_aDisplay, ch ENDM ALPHANOMODULATE MACRO mov ch, [edx+3] mov [esi].GENGC_aDisplay, ch ENDM ;; There are AGIs and other nasties in the alpha-read code. There's ;; not much we can really do, unfortunately... if (BPP eq 8) ALPHAREAD MACRO xor eax, eax mov al, [ebx] mov ebx, [esi].GENGC_pInvTranslateVector mov cl, 0ffh mov al, [ebx+eax] mov ebx, eax and ebx, rMask sub cl, ch shl ebx, gBits + bBits mov bh, cl mov ch, _gbMulTable[ebx] mov ebx, eax mov [esi].GENGC_rDisplay, ch and ebx, gMask shl ebx, bBits mov bh, cl mov ch, _gbMulTable[ebx] mov ebx, eax mov [esi].GENGC_gDisplay, ch and ebx, bMask mov bh, cl mov ch, _gbMulTable[ebx] mov [esi].GENGC_bDisplay, ch ENDM endif if (BPP eq 16) ALPHAREAD MACRO mov ax, [ebx] mov cl, 0ffh mov ebx, eax and ebx, rMask sub cl, ch shr ebx, rShift - (8 - rBits) mov bh, cl mov ch, _gbMulTable[ebx] mov ebx, eax mov [esi].GENGC_rDisplay, ch and ebx, gMask shr ebx, gShift - (8 - gBits) mov bh, cl mov ch, _gbMulTable[ebx] mov ebx, eax mov [esi].GENGC_gDisplay, ch and ebx, bMask shl ebx, (8 - bBits) mov bh, cl mov ch, _gbMulTable[ebx] mov [esi].GENGC_bDisplay, ch ENDM elseif (BPP eq 32) ALPHAREAD MACRO xor eax, eax mov cl, 0ffh mov al, [ebx+2] sub cl, ch mov ah, cl mov al, _gbMulTable[eax] mov [esi].GENGC_rDisplay, al mov al, [ebx+1] mov ah, cl mov al, _gbMulTable[eax] mov [esi].GENGC_gDisplay, al mov al, [ebx] mov ah, cl mov al, _gbMulTable[eax] mov [esi].GENGC_bDisplay, al ENDM endif ;; ;; ;; Macros for advancing a single pixel unit ;; ;; if (BPP eq 8) PIXADVANCE MACRO var inc var ENDM elseif (BPP eq 16) PIXADVANCE MACRO var add var, (BPP / 8) ENDM else PIXADVANCE MACRO var add var, [esi].GENGC_bytesPerPixel ENDM endif if (BPP le 16) PIXADVANCE2 MACRO var1, var2 lea var1, [var2 + (BPP / 8)] ENDM else PIXADVANCE2 MACRO var1, var2 mov var1, var2 add var1, [esi].GENGC_bytesPerPixel ENDM endif ;; ;; ;; Macros for advancing the accumulators if the z-buffer test fails: ;; ;; if FAST_REPLACE ZBUFFER_FAIL_ADVANCE MACRO mov ecx, [esi].GENGC_zAccum ;U mov eax, [esi].GENGC_SPAN_dz ; V mov ebx, [esi].GENGC_pixAccum ;U add edi, 2 ; V add ecx, eax ;U PIXADVANCE ebx ; V sub ebp, 010001h ;U mov [esi].GENGC_zAccum, ecx ; V mov [esi].GENGC_pixAccum, ebx ;U jl doSubDiv ; V test ebp, 08000h ;U je loopTopNoDiv ; V jmp spanExit ENDM elseif REPLACE ZBUFFER_FAIL_ADVANCE MACRO mov ecx, [esi].GENGC_zAccum ;U mov eax, [esi].GENGC_SPAN_dz ; V add edi, 2 ;U add ecx, eax ; V mov eax, [esi].GENGC_ditherAccum ;U mov ebx, [esi].GENGC_pixAccum ; V ror eax, 8 ;U mov [esi].GENGC_zAccum, ecx ; V PIXADVANCE ebx ;U sub ebp, 010001h ; V mov [esi].GENGC_pixAccum, ebx ;U mov [esi].GENGC_ditherAccum, eax ; V jl doSubDiv ;U test ebp, 08000h ; V je loopTopNoDiv ;U jmp spanExit ; V ENDM elseif FLAT_SHADING ZBUFFER_FAIL_ADVANCE MACRO mov ecx, [esi].GENGC_zAccum ;U mov eax, [esi].GENGC_SPAN_dz ; V add edi, 2 ;U add ecx, eax ; V mov ebx, [esi].GENGC_pixAccum ;U mov eax, [esi].GENGC_ditherAccum ; V mov [esi].GENGC_zAccum, ecx ;U PIXADVANCE ebx ; V ror eax, 8 ;U sub ebp, 010001h ; V mov [esi].GENGC_pixAccum, ebx ;U mov [esi].GENGC_ditherAccum, eax ; V jl doSubDiv ;U test ebp, 08000h ; V je loopTopNoDiv ;U jmp spanExit ENDM elseif SMOOTH_SHADING ZBUFFER_FAIL_ADVANCE MACRO mov ecx, [esi].GENGC_zAccum ;U mov eax, [esi].GENGC_SPAN_dz ; V add edi, 2 ;U add ecx, eax ; V mov eax, [esi].GENGC_rAccum ;U mov [esi].GENGC_zAccum, ecx ; V mov ebx, [esi].GENGC_SPAN_dr ;U mov ecx, [esi].GENGC_gAccum ; V add eax, ebx ;U mov edx, [esi].GENGC_SPAN_dg ; V mov [esi].GENGC_rAccum, eax ;U add ecx, edx ; V mov eax, [esi].GENGC_bAccum ;U mov ebx, [esi].GENGC_SPAN_db ; V mov [esi].GENGC_gAccum, ecx ;U add ebx, eax ; V mov eax, [esi].GENGC_ditherAccum ;U mov [esi].GENGC_bAccum, ebx ; V ror eax, 8 ;U if ALPHA mov ecx, [esi].GENGC_aAccum endif mov ebx, [esi].GENGC_pixAccum ;U if ALPHA add ecx, [esi].GENGC_SPAN_da endif PIXADVANCE ebx ;U if ALPHA mov [esi].GENGC_aAccum, ecx endif mov [esi].GENGC_pixAccum, ebx ; V sub ebp, 010001h ;U mov [esi].GENGC_ditherAccum, eax ; V jl doSubDiv ;U test ebp, 08000h ; V je loopTopNoDiv ;U jmp spanExit ; V ENDM endif ;;---------------------------------------------------------------------- ;; ;; This is the start of the texture routine. Kick off the divide, and use ;; the dead time to set up all of the accumulators and other variables. ;; ;;---------------------------------------------------------------------- ZBUFFER_EARLY_OUT = 1 if ZBUFFER push ebx ;U push esi ; V push edi ;U push ebp ; V if ZBUFFER_EARLY_OUT mov edi, [ecx].GENGC_SPAN_zbuf ;U mov esi, [ecx].GENGC_SPAN_z ; V mov edx, [ecx].GENGC_SPAN_length ;U mov ebp, [ecx].GENGC_SPAN_dz ; V @zLoop: mov ebx, esi ;U mov eax, [edi] ; V shr ebx, 16 ;U and eax, 0ffffh ; V cmp ebx, eax ;U if ZCMP_L jl @zFirstWrite ; V else jle @zFirstWrite ; V endif add edi, 2 ;U add esi, ebp ; V dec edx ;U jne @zLoop ; V pop ebp pop edi pop esi pop ebx ret 0 @zFirstWrite: endif ;; ZBUFFER_EARLY_OUT endif ;; ZBUFFER ;; ;; Start the divide: ;; mov eax, [ecx].GENGC_flags fld DWORD PTR [ecx].GENGC_SPAN_qw ;qwAccum fld DWORD PTR [ecx].GENGC_SPAN_qw ;qwAccum qwAccum test eax, GEN_TEXTURE_ORTHO jne @f fdivr __One ;1/qw qwAccum @@: ;; ;; Save the registers that we need to: ;; if ZBUFFER else push ebx ;U push esi ; V push edi ;U push ebp ; V endif mov esi, ecx ;U ;; ;; Set up accumulators: ;; if FAST_REPLACE if ZBUFFER mov eax, [esi].GENGC_SPAN_z ; V endif mov ebx, [esi].GENGC_SPAN_s ;U mov ecx, [esi].GENGC_SPAN_t ; V if ZBUFFER mov [esi].GENGC_zAccum, eax ;U endif mov [esi].GENGC_sAccum, ebx ; V mov [esi].GENGC_tAccum, ecx ;U mov ebx, [esi].GENGC_SPAN_qw ; V mov eax, [esi].GENGC_SPAN_y ;U mov [esi].GENGC_qwAccum, ebx ; V mov edx, [esi].GENGC_SPAN_ppix ;U mov edi, [esi].GENGC_flags ; V mov ebx, [esi].GENGC_SPAN_x ;U test edi, SURFACE_TYPE_DIB ; V jne @f ;U mov edx, [esi].GENGC_ColorsBits ; V jmp short @pixAccumDone @@: if (BPP eq 8) add edx, ebx ;U elseif (BPP eq 16) lea edx, [edx + 2*ebx] else lea edx, [edx + 4*ebx] cmp [esi].GENGC_bpp, 32 je @f sub edx, ebx @@: endif @pixAccumDone: test edi, GEN_TEXTURE_ORTHO ; V mov ebp, [esi].GENGC_SPAN_length ;U je @f ; V else if REPLACE else ;; Handle RGB accumulators if FLAT_SHADING mov eax, [ecx].GENGC_SPAN_r ;U mov ebx, [ecx].GENGC_SPAN_g ; V shr eax, rBits ;U mov ecx, [esi].GENGC_SPAN_b ; V shr ebx, gBits ;U and eax, 0ff00h ; V shr ecx, bBits ;U and ebx, 0ff00h ; V and ecx, 0ff00h ;U mov [esi].GENGC_rAccum, eax ; V mov [esi].GENGC_gAccum, ebx ;U mov [esi].GENGC_bAccum, ecx ; V else mov eax, [ecx].GENGC_SPAN_r ;U mov ebx, [ecx].GENGC_SPAN_g ; V mov ecx, [esi].GENGC_SPAN_b ;U mov [esi].GENGC_rAccum, eax ; V mov [esi].GENGC_gAccum, ebx ;U mov [esi].GENGC_bAccum, ecx ; V endif ;; FLAT_SHADING endif ;; NOT REPLACE if ZBUFFER mov eax, [esi].GENGC_SPAN_z ; V endif mov ebx, [esi].GENGC_SPAN_s ;U mov ecx, [esi].GENGC_SPAN_t ; V if ZBUFFER mov [esi].GENGC_zAccum, eax ;U endif mov [esi].GENGC_sAccum, ebx ; V mov [esi].GENGC_tAccum, ecx ;U mov ebx, [esi].GENGC_SPAN_qw ; V mov eax, [esi].GENGC_SPAN_y ;U mov [esi].GENGC_qwAccum, ebx ; V and eax, 03h ;U mov ecx, [esi].GENGC_SPAN_x ; V lea eax, [eax*4 + offset dither0] ;U lea ecx, [ecx*8] ; V mov edx, [esi].GENGC_SPAN_ppix ;U mov edi, [esi].GENGC_flags ; V mov ebx, [esi].GENGC_SPAN_x ;U test edi, SURFACE_TYPE_DIB ; V jne @f ;U mov edx, [esi].GENGC_ColorsBits ; V jmp short @pixAccumDone @@: if (BPP eq 8) add edx, ebx ;U elseif (BPP eq 16) lea edx, [edx + 2*ebx] else lea edx, [edx + 4*ebx] cmp [esi].GENGC_bpp, 32 je @f sub edx, ebx @@: endif @pixAccumDone: mov eax, [eax] ; V and ecx, 018h ;U test edi, GEN_TEXTURE_ORTHO ; V mov ebp, [esi].GENGC_SPAN_length ;U je @f ; V endif mov edi, [esi].GENGC_sAccum ; V mov ebx, [esi].GENGC_tAccum ;U mov DWORD PTR [esi].GENGC_sResult, edi ; V mov DWORD PTR [esi].GENGC_tResult, ebx ;U mov edi, [esi].GENGC_flags ; V jmp short @stResultDone1 ;U ;; ;; Kick off the next divide: ;; @@: fild DWORD PTR [esi].GENGC_sAccum ; s 1/qw qwAccum fmul ST, ST(1) ; s/qw 1/qw qwAccum fild DWORD PTr [esi].GENGC_tAccum ; t s/qw 1/qw qwAccum fmulp ST(2), ST ; s/qw t/qw qwAccum fistp QWORD PTR [esi].GENGC_sResult ; t/qw qwAccum fistp QWORD PTR [esi].GENGC_tResult ; qwAccum fadd DWORD PTR [esi].GENGC_qwStepX ; qwAccum fld ST(0) ; qwAccum qwAccum fdivr __One ; 1/qw qwAccum @stResultDone1: ror eax, cl ;UV (4) add ebp, 070000h ;U mov [esi].GENGC_ditherAccum, eax ; V dec ebp ;U mov [esi].GENGC_pixAccum, edx ; V mov eax, [esi].GENGC_sAccum ;U mov ebx, [esi].GENGC_tAccum ; V add eax, [esi].GENGC_sStepX ;U add ebx, [esi].GENGC_tStepX ; V mov [esi].GENGC_sAccum, eax ;U mov [esi].GENGC_tAccum, ebx ; V mov eax, [esi].GENGC_sResult ;U mov ebx, [esi].GENGC_tResult ; V mov cl, TSHIFT_SUBDIV ;U sar ebx, cl ;UV (4) and ebx, NOT 7 ;U if ALPHA mov ecx, [esi].GENGC_SPAN_a endif test edi, GEN_TEXTURE_ORTHO ; V mov [esi].GENGC_tResult, ebx ;U if ALPHA mov [esi].GENGC_aAccum, ecx endif je @f mov ecx, [esi].GENGC_sAccum ; V mov edx, [esi].GENGC_tAccum ;U mov DWORD PTR [esi].GENGC_sResultNew, ecx ; V mov DWORD PTR [esi].GENGC_tResultNew, edx ;U jmp short @stResultDone2 ; V @@: ;; We may have to burn some cycles here... fild DWORD PTR [esi].GENGC_sAccum ; s 1/qw qwAccum fmul ST, ST(1) ; s/qw 1/qw qwAccum fild DWORD PTr [esi].GENGC_tAccum ; t s/qw 1/qw qwAccum fmulp ST(2), ST ; s/qw t/qw qwAccum fistp QWORD PTR [esi].GENGC_sResultNew; t/qw qwAccum fistp QWORD PTR [esi].GENGC_tResultNew; qwAccum fadd DWORD PTR [esi].GENGC_qwStepX ; qwAccum @stResultDone2: mov cl, TSHIFT_SUBDIV ;U mov edx, [esi].GENGC_tResultNew ; V sar edx, cl ;UV (4) and edx, NOT 7 ;U mov ecx, [esi].GENGC_sResultNew ; V mov [esi].GENGC_tResultNew, edx ;U sub ecx, eax ; V sar ecx, 3 ;U sub edx, ebx ; V sar edx, 3 ;U mov [esi].GENGC_subDs, ecx ; V mov [esi].GENGC_subDt, edx ;U mov eax, [esi].GENGC_flags ; V mov edi, [esi].GENGC_SPAN_zbuf ;U loopTop: ;; ;; This is the start of the outer loop. We come back here on each ;; subdivision. The key thing is to kick off the next divide: ;; test eax, GEN_TEXTURE_ORTHO ; V jne @f ;U fld ST(0) ; qwAccum qwAccum fadd DWORD PTR [esi].GENGC_qwStepX ; qwAccum+ qwAccum fxch ST(1) ; qwAccum qwAccum+ fdivr __One ; 1/qw qwAccum+ -- let the divide rip! @@: loopTopNoDiv: ;; ;; This is the start of the inner loop. This is where the pixel-level ;; work happens: ;; ;; ;; First, do z-buffering is enabled: ;; if ZBUFFER mov eax, [edi] ;U mov ebx, [esi].GENGC_zAccum ; V shr ebx, 16 ;U and eax, 0ffffh ; V cmp ebx, eax ;U if ZCMP_L jl @zWrite ; V else jle @zWrite ; V endif ZBUFFER_FAIL_ADVANCE @zWrite: mov [edi], bx ;UV endif ;;ZBUFFER ;; ;; Now, get pointer to current texel value in EDX. There are two cases, ;; one if there is a palette-lookup, and one if we index straight into ;; the texture. ;; if PALETTE_ENABLED mov ecx, TEXPALETTE ;U mov eax, TMASK_SUBDIV ; V test ecx, ecx ;U je @noPalette ; V mov edx, [esi].GENGC_tResult ; V mov ebx, [esi].GENGC_sResult ;U and edx, eax ; V mov eax, [esi].GENGC_sMask ;U and ebx, eax ; V shr edx, 6 ;U mov eax, DWORD PTR [esi].GENGC_sResult ; V shr ebx, 16 ;U mov ecx, TEXIMAGE ; V add edx, ecx ;U add eax, [esi].GENGC_subDs ; V mov ecx, DWORD PTR [esi].GENGC_tResult ;U add edx, ebx ; V add ecx, [esi].GENGC_subDt ;U mov DWORD PTR [esi].GENGC_sResult, eax ; V xor eax, eax ;U mov ebx, TEXPALETTE ; V mov DWORD PTR [esi].GENGC_tResult, ecx ;U mov al, [edx] ; V lea edx, [ebx+4*eax] ;U jmp short @paletteDone ; V @noPalette: endif ;;PALETTE_ENABLED mov eax, TMASK_SUBDIV ;U mov edx, [esi].GENGC_tResult ; V mov ebx, [esi].GENGC_sResult ;U and edx, eax ; V shr edx, (6-TEX_BPP_LOG2) ;U mov ecx, [esi].GENGC_sMask ; V and ebx, ecx ;U mov eax, DWORD PTR [esi].GENGC_sResult ; V shr ebx, (16-TEX_BPP_LOG2) ;U mov ecx, [esi].GENGC_subDs ; V add eax, ecx ;U add edx, ebx ; V mov ecx, TEXIMAGE ;U mov ebx, [esi].GENGC_subDt ; V add edx, ecx ;U mov ecx, DWORD PTR [esi].GENGC_tResult ; V add ecx, ebx ;U mov DWORD PTR [esi].GENGC_sResult, eax ; V mov DWORD PTR [esi].GENGC_tResult, ecx ;U if (PALETTE_ONLY) mov al, [edx] ; V and eax, 0ffh ;U mov ebx, TEXPALETTE ; V lea edx, [ebx+4*eax] ;U endif @paletteDone: ;; ;; We are now ready to handle each of the 4 basic modes on a case-by-case ;; basis. We will generally try to adhere to the following register ;; usage: ;; eax - red ;; ebx - green ;; ecx - blue ;; ebx, edx - framebuffer pointers ;; if FAST_REPLACE ;;---------------------------------------------------------------------- ;; ;; ** Replace mode (compressed) ;; ;;---------------------------------------------------------------------- if ALPHA cmp BYTE PTR [edx+3], 0ffh ;U je @noAlpha ; V mov ebx, [esi].GENGC_pixAccum ;U ;; get ready to do read cmp BYTE PTR [edx+3], 0 ; V jne @alphaRead ;U ;; Alpha is 0 in the texture, so just increment all the accumulators if ZBUFFER mov ecx, [esi].GENGC_zAccum ;U add edi, 2 ; V add ecx, [esi].GENGC_SPAN_dz ;U endif PIXADVANCE ebx ;U if ZBUFFER mov [esi].GENGC_zAccum, ecx ;U endif ror eax, 8 ; V sub ebp, 010001h ;U mov [esi].GENGC_pixAccum, ebx ; V mov [esi].GENGC_ditherAccum, eax ;U ;; Finish incrementing all of our accumulators jl doSubDiv ; V test ebp, 08000h ;U je loopTopNoDiv ; V jmp spanExit @alphaRead: ;; ;; Get pixel value and calculate total effect with alpha ;; ;; To make this easy on ourselves, we'll use the uncompressed palette ;; to do the alpha modulation: ALPHANOMODULATE sub edx, [esi].GENGC_texImageReplace add edx, [esi].GENGC_texPalette ALPHAREAD mov al, [edx+2] ;U get texel value mov ah, [esi].GENGC_aDisplay mov bl, [edx+1] ;U mov bh, [esi].GENGC_aDisplay mov cl, [edx] ; V mov ch, [esi].GENGC_aDisplay and eax, 0ffffh and ebx, 0ffffh and ecx, 0ffffh mov ah, _gbMulTable[eax] mov bh, _gbMulTable[ebx] mov ch, _gbMulTable[ecx] add ah, [esi].GENGC_rDisplay add bh, [esi].GENGC_gDisplay add ch, [esi].GENGC_bDisplay if (BPP eq 32) shl eax, -rRightShiftAdj else shr eax, rRightShiftAdj ;U endif mov edx, [esi].GENGC_pixAccum ; V shr ebx, gRightShiftAdj ;U and eax, rMask ; V shr ecx, bRightShiftAdj ;U and ebx, gMask ; V and ecx, bMask ;U or eax, ebx ; V or eax, ecx ;U PIXADVANCE2 ebx, edx ; V if ZBUFFER mov ecx, [esi].GENGC_zAccum ; V add edi, 2 ;U add ecx, [esi].GENGC_SPAN_dz ; V endif mov [esi].GENGC_pixAccum, ebx ;U if ZBUFFER mov [esi].GENGC_zAccum, ecx ;U endif if (BPP eq 8) sub ebp, 010001h ; V mov al, [esi].GENGC_xlatPalette[eax];U ;; AGI without z-buffering mov [edx], al ;U elseif (BPP eq 16) sub ebp, 010001h mov [edx], ax else mov [edx], ax shr eax, 16 sub ebp, 010001h mov [edx+2], al endif ;; Finish the loop: jl doSubDiv ; V test ebp, 08000h ;U je loopTopNoDiv ; V jmp spanExit endif ;;ALPHA @noAlpha: mov ebx, [esi].GENGC_pixAccum ;U if (BPP eq 8) mov al, [edx] ; V get texel value elseif (BPP eq 16) mov ax, [edx] else mov eax, [edx] endif PIXADVANCE2 ecx, ebx ;U if ZBUFFER mov edx, [esi].GENGC_zAccum ; V add edi, 2 ;U add edx, [esi].GENGC_SPAN_dz ; V mov [esi].GENGC_zAccum, edx ;U endif mov [esi].GENGC_pixAccum, ecx ; V if (BPP eq 8) sub ebp, 010001h ;U mov [ebx], al ; V elseif (BPP eq 16) sub ebp, 010001h mov [ebx], ax else mov [ebx], ax shr eax, 16 sub ebp, 010001h mov [ebx+2], al endif ;; Finish incrementing all of our accumulators jl doSubDiv ;U test ebp, 08000h ; V je loopTopNoDiv ;U jmp spanExit elseif REPLACE ;;---------------------------------------------------------------------- ;; ;; ** Replace mode (non-compressed) ;; ;;---------------------------------------------------------------------- if ALPHA cmp BYTE PTR [edx+3], 0ffh ;U je @noAlpha ; V mov ebx, [esi].GENGC_pixAccum ;U ;; get ready to do read cmp BYTE PTR [edx+3], 0 ; V jne @alphaRead ;U ;; Alpha is 0 in the texture, so just increment all the accumulators if ZBUFFER mov ecx, [esi].GENGC_zAccum ;U add edi, 2 ; V add ecx, [esi].GENGC_SPAN_dz ;U endif mov eax, [esi].GENGC_ditherAccum ; V if ZBUFFER mov [esi].GENGC_zAccum, ecx ;U endif PIXADVANCE ebx ;U ror eax, 8 ; V sub ebp, 010001h ;U mov [esi].GENGC_pixAccum, ebx ; V mov [esi].GENGC_ditherAccum, eax ;U ;; Finish incrementing all of our accumulators jl doSubDiv ; V test ebp, 08000h ;U je loopTopNoDiv ; V jmp spanExit @alphaRead: ;; ;; Get pixel value and calculate total effect with alpha ;; ALPHANOMODULATE ALPHAREAD mov al, [edx+2] ;U get texel value mov ah, [esi].GENGC_aDisplay mov bl, [edx+1] ;U mov bh, [esi].GENGC_aDisplay mov cl, [edx] ; V mov ch, [esi].GENGC_aDisplay and eax, 0ffffh and ebx, 0ffffh and ecx, 0ffffh mov ah, _gbMulTable[eax] mov bh, _gbMulTable[ebx] mov ch, _gbMulTable[ecx] add ah, [esi].GENGC_rDisplay add bh, [esi].GENGC_gDisplay add ch, [esi].GENGC_bDisplay if (BPP eq 32) shl eax, -rRightShiftAdj else shr eax, rRightShiftAdj ;U endif mov edx, [esi].GENGC_pixAccum ; V shr ebx, gRightShiftAdj ;U and eax, rMask ; V shr ecx, bRightShiftAdj ;U and ebx, gMask ; V and ecx, bMask ;U or eax, ebx ; V or eax, ecx ;U PIXADVANCE2 ebx, edx ; V if ZBUFFER mov ecx, [esi].GENGC_zAccum ; V add edi, 2 ;U add ecx, [esi].GENGC_SPAN_dz ; V endif mov [esi].GENGC_pixAccum, ebx ;U if ZBUFFER mov [esi].GENGC_zAccum, ecx ;U endif if (BPP eq 8) sub ebp, 010001h ; V mov al, [esi].GENGC_xlatPalette[eax];U ;; AGI without z-buffering mov [edx], al ;U elseif (BPP eq 16) sub ebp, 010001h mov [edx], ax else mov [edx], ax shr eax, 16 sub ebp, 010001h mov [edx+2], al endif ;; Finish the loop: jl doSubDiv ; V test ebp, 08000h ;U je loopTopNoDiv ; V jmp spanExit endif ;;ALPHA @noAlpha: mov ah, [edx+2] ;U get texel value mov bh, [edx+1] ; V if (BPP eq 32) shl eax, -rRightShiftAdj else shr eax, rRightShiftAdj ;U endif mov ch, [edx] ; V shr ebx, gRightShiftAdj ;U and eax, rMask ; V shr ecx, bRightShiftAdj ;U and ebx, gMask ; V or eax, ebx ;U and ecx, bMask ; V mov edx, [esi].GENGC_pixAccum ;U or eax, ecx ; V PIXADVANCE2 ebx, edx ;U if ZBUFFER mov ecx, [esi].GENGC_zAccum ; V add edi, 2 ;U add ecx, [esi].GENGC_SPAN_dz ; V mov [esi].GENGC_zAccum, ecx ;U endif if (BPP eq 8) sub ebp, 010001h ; V mov [esi].GENGC_pixAccum, ebx ;U mov al, [esi].GENGC_xlatPalette[eax]; V mov [edx], al ;U elseif (BPP eq 16) sub ebp, 010001h mov [esi].GENGC_pixAccum, ebx mov [edx], ax else mov [edx], ax shr eax, 16 mov [esi].GENGC_pixAccum, ebx sub ebp, 010001h mov [edx+2], al endif ;; Finish the loop: jl doSubDiv ; V test ebp, 08000h ;U je loopTopNoDiv ; V jmp spanExit elseif FLAT_SHADING ;;---------------------------------------------------------------------- ;; ;; ** Flat shading ;; ;;---------------------------------------------------------------------- if ALPHA mov ebx, [esi].GENGC_pixAccum ;; get ready to do read cmp BYTE PTR [edx+3], 0 jne @alphaRead ;; Alpha is 0 in the texture, so just increment all the accumulators if ZBUFFER mov ecx, [esi].GENGC_zAccum mov eax, [esi].GENGC_SPAN_dz add edi, 2 add ecx, eax endif mov eax, [esi].GENGC_ditherAccum if ZBUFFER mov [esi].GENGC_zAccum, ecx endif ror eax, 8 ;U PIXADVANCE ebx ; V sub ebp, 010001h ;U mov [esi].GENGC_pixAccum, ebx ; V mov [esi].GENGC_ditherAccum, eax ;U ;; Finish incrementing all of our accumulators jl doSubDiv ; V test ebp, 08000h ;U je loopTopNoDiv ; V jmp spanExit @alphaRead: cmp BYTE PTR [edx+3], 0ffh jne @doAlpha cmp BYTE PTR [esi].GENGC_aAccum+2, 0ffh jne @doAlpha ;; Set mix color to 1, 0, 0, 0 mov DWORD PTR [esi].GENGC_rDisplay, 0ff000000h jmp short @doneAlpha ;; ;; Get pixel value and calculate total effect with alpha ;; @doAlpha: ALPHAMODULATE ALPHAREAD @doneAlpha: endif ;;ALPHA mov ebx, [edx] ;U mov ecx, ebx ; V shr ebx, 16 ;U mov edx, ecx ; V shr ecx, 8 ;U mov eax, [esi].GENGC_rAccum ; V and ebx, 0ffh ;U and ecx, 0ffh ; V or ebx, eax ;U mov eax, [esi].GENGC_gAccum ; V and edx, 0ffh ;U or ecx, eax ; V mov eax, [esi].GENGC_bAccum ;U or edx, eax ; V mov ebx, DWORD PTR _gbMulTable[ebx] ;U mov ecx, DWORD PTR _gbMulTable[ecx] ; V mov edx, DWORD PTR _gbMulTable[edx] ;U if ALPHA mov bh, [esi].GENGC_aDisplay mov ch, bh mov dh, bh and ebx, 0ffffh and ecx, 0ffffh and edx, 0ffffh mov bl, _gbMulTable[ebx] mov cl, _gbMulTable[ecx] mov dl, _gbMulTable[edx] add bl, [esi].GENGC_rDisplay add cl, [esi].GENGC_gDisplay add dl, [esi].GENGC_bDisplay endif ;; do the dithering shl ebx, (rBits+8) ;U mov eax, [esi].GENGC_ditherAccum ; V shl ecx, (gBits+8) ;U and eax, 0f800h ; V shl edx, (bBits+8) ;U add ebx, eax ; V add ecx, eax ;U add edx, eax ; V ;; ;; Compose the final pixel: ;; if (BPP eq 32) shl ebx, -rRightShiftAdj else shr ebx, rRightShiftAdj ;U endif mov eax, [esi].GENGC_ditherAccum ; V ror eax, 8 ;U and ebx, rMask ; V shr ecx, gRightShiftAdj ;U mov [esi].GENGC_ditherAccum, eax ; V shr edx, bRightShiftAdj ;U and ecx, gMask ; V or ebx, ecx ;U and edx, bMask ; V or ebx, edx ;U ;; ;; Advance the frame buffer pointer: ;; mov ecx, [esi].GENGC_pixAccum ; V mov edx, ecx ;U if (BPP le 16) add ecx, (BPP / 8) ; V else add ecx, [esi].GENGC_bytesPerPixel ; V endif mov [esi].GENGC_pixAccum, ecx ;U ;; ;; A good time to start incrementing all of our accumulators: ;; if ZBUFFER mov ecx, [esi].GENGC_zAccum ; V mov eax, [esi].GENGC_SPAN_dz ;U add ecx, eax ; V add edi, 2 ;U mov [esi].GENGC_zAccum, ecx ; V endif ;; ;; Write the pixel into the frame buffer ;; if (BPP eq 8) mov al, [esi].GENGC_xlatPalette[ebx]; V sub ebp, 010001h ;U mov [edx], al ; V elseif (BPP eq 16) sub ebp, 010001h mov [edx], bx else mov [edx], bx shr ebx, 16 sub ebp, 010001h mov [edx+2], bl endif ;; Finish incrementing all of our accumulators jl doSubDiv ;U test ebp, 08000h ; V je loopTopNoDiv ;U elseif SMOOTH_SHADING ;;---------------------------------------------------------------------- ;; ;; ** Smooth shading ;; ;;---------------------------------------------------------------------- if ALPHA mov ebx, [esi].GENGC_pixAccum ;; get ready to do read cmp BYTE PTR [edx+3], 0 jne @alphaRead ;; Alpha is 0 in the texture, so just increment all the accumulators if ZBUFFER mov ecx, [esi].GENGC_zAccum mov eax, [esi].GENGC_SPAN_dz add eax, ecx add edi, 2 mov [esi].GENGC_zAccum, eax endif mov eax, [esi].GENGC_rAccum mov ebx, [esi].GENGC_gAccum mov ecx, [esi].GENGC_bAccum add eax, [esi].GENGC_SPAN_dr add ebx, [esi].GENGC_SPAN_dg add ecx, [esi].GENGC_SPAN_db mov [esi].GENGC_rAccum, eax mov [esi].GENGC_gAccum, ebx mov [esi].GENGC_bAccum, ecx mov eax, [esi].GENGC_ditherAccum mov ecx, [esi].GENGC_aAccum ror eax, 8 mov ebx, [esi].GENGC_pixAccum add ecx, [esi].GENGC_SPAN_da PIXADVANCE ebx mov [esi].GENGC_aAccum, ecx mov [esi].GENGC_pixAccum, ebx sub ebp, 010001h mov [esi].GENGC_ditherAccum, eax ;; Finish incrementing all of our accumulators jl doSubDiv ;U test ebp, 08000h ; V je loopTopNoDiv ;U jmp spanExit @alphaRead: cmp BYTE PTR [edx+3], 0ffh jne @doAlpha cmp BYTE PTR [esi].GENGC_aAccum+2, 0ffh jne @doAlpha ;; Set mix color to 1, 0, 0, 0 mov DWORD PTR [esi].GENGC_rDisplay, 0ff000000h jmp short @doneAlpha ;; ;; Get pixel value and calculate total effect with alpha ;; @doAlpha: ALPHAMODULATE ALPHAREAD @doneAlpha: endif ;;ALPHA mov ebx, [esi].GENGC_rAccum ;U mov eax, [edx] ; V shr ebx, rBits ;U and eax, 0ff0000h ; V shr eax, 16 ;U mov ecx, [esi].GENGC_gAccum ; V shr ecx, gBits ;U and ebx, 0ff00h ; V or ebx, eax ;U mov eax, [edx] ; V shr eax, 8 ;U mov edx, [edx] ; V and eax, 0ffh ;U and ecx, 0ff00h ; V or ecx, eax ;U mov eax, [esi].GENGC_bAccum ; V shr eax, bBits ;U and edx, 0ffh ; V and eax, 0ff00h ;U mov ebx, DWORD PTR _gbMulTable[ebx] ; V get multiplied 8-bit R value or edx, eax ;U mov ecx, DWORD PTR _gbMulTable[ecx] ; V get multiplied 8-bit G value mov eax, [esi].GENGC_ditherAccum ;U mov edx, DWORD PTR _gbMulTable[edx] ; V get multiplied 8-bit B value if ALPHA mov bh, [esi].GENGC_aDisplay mov ch, bh mov dh, bh and ebx, 0ffffh and ecx, 0ffffh and edx, 0ffffh mov bl, _gbMulTable[ebx] mov cl, _gbMulTable[ecx] mov dl, _gbMulTable[edx] add bl, [esi].GENGC_rDisplay add cl, [esi].GENGC_gDisplay add dl, [esi].GENGC_bDisplay endif shl ebx, (rBits+8) ;U and eax, 0f800h ; V shl ecx, (gBits+8) ;U add ebx, eax ; V shl edx, (bBits+8) ;U add ecx, eax ; V if (BPP eq 32) shl ebx, -rRightShiftAdj else shr ebx, rRightShiftAdj ;U endif add edx, eax ; V shr ecx, gRightShiftAdj ;U and ebx, rMask ; V shr edx, bRightShiftAdj ;U and ecx, gMask ; V or ebx, ecx ;U and edx, bMask ; V or ebx, edx ;U ;; ;; A good time to start incrementing all of our accumulators ;; if ZBUFFER mov ecx, [esi].GENGC_zAccum ; V mov eax, [esi].GENGC_SPAN_dz ;U add eax, ecx ; V add edi, 2 ;U mov [esi].GENGC_zAccum, eax ; V endif mov eax, [esi].GENGC_rAccum ;U mov ecx, [esi].GENGC_SPAN_dr ; V mov edx, [esi].GENGC_gAccum ;U add eax, ecx ; V mov ecx, [esi].GENGC_SPAN_dg ;U mov [esi].GENGC_rAccum, eax ; V add edx, ecx ;U mov eax, [esi].GENGC_bAccum ; V mov ecx, [esi].GENGC_SPAN_db ;U add eax, ecx ; V mov [esi].GENGC_gAccum, edx ;U mov [esi].GENGC_bAccum, eax ; V mov eax, [esi].GENGC_ditherAccum ;U mov ecx, [esi].GENGC_pixAccum ; V ror eax, 8 ;U mov edx, ecx ; V if (BPP le 16) add ecx, (BPP / 8) ;U else add ecx, [esi].GENGC_bytesPerPixel ;U endif mov [esi].GENGC_ditherAccum, eax ; V mov [esi].GENGC_pixAccum, ecx ;U if ALPHA mov ecx, [esi].GENGC_aAccum add ecx, [esi].GENGC_SPAN_da mov [esi].GENGC_aAccum, ecx endif if (BPP eq 8) mov al, [esi].GENGC_xlatPalette[ebx]; V sub ebp, 010001h ;U mov [edx], al ; V elseif (BPP eq 16) sub ebp, 010001h mov [edx], bx else mov [edx], bx shr ebx, 16 sub ebp, 010001h mov [edx+2], bl endif ;; Finish incrementing all of our accumulators jl doSubDiv ;U test ebp, 08000h ; V je loopTopNoDiv ;U endif ;;SMOOTH_SHADING ;; ;; This is the exit point. We need to pop the unused floating-point ;; registers off the stack, and return: ;; spanExit: fstp ST(0) fstp ST(0) pop ebp pop edi pop esi pop ebx ret 0 ;; ;; This is the subdivision code. After the required number of steps, the ;; routine will jump here to calculate the next set of interpolants based ;; on subdivision: ;; doSubDiv: add ebp, 080000h mov ecx, [esi].GENGC_flags ;; ;; Increment the big S and T steps: ;; mov edx, [esi].GENGC_sAccum test ebp, 08000h jne short spanExit mov ebx, [esi].GENGC_tAccum add edx, [esi].GENGC_sStepX add ebx, [esi].GENGC_tStepX mov [esi].GENGC_sAccum, edx mov [esi].GENGC_tAccum, ebx mov eax, [esi].GENGC_sResultNew mov ebx, [esi].GENGC_tResultNew test ecx, GEN_TEXTURE_ORTHO je @f mov ecx, DWORD PTR [esi].GENGC_tAccum mov DWORD PTR [esi].GENGC_sResultNew, edx mov DWORD PTR [esi].GENGC_tResultNew, ecx jmp short @stResultDone3 ;; ;; Do the floating-point computation for perspective: ;; @@: fild DWORD PTR [esi].GENGC_sAccum ; s 1/qw qwAccum fmul ST, ST(1) ; s/qw 1/qw qwAccum fild DWORD PTr [esi].GENGC_tAccum ; t s/qw 1/qw qwAccum fmulp ST(2), ST ; s/qw t/qw qwAccum fistp QWORD PTR [esi].GENGC_sResultNew; t/qw qwAccum fistp QWORD PTR [esi].GENGC_tResultNew; qwAccum @stResultDone3: ;; ;; Now, calculate the per-pixel deltas: ;; mov cl, TSHIFT_SUBDIV ;U mov edx, [esi].GENGC_tResultNew ; V sar edx, cl ;UV (4) mov ecx, [esi].GENGC_sResultNew ;U and edx, NOT 7 ; V sub ecx, eax ;U mov [esi].GENGC_tResultNew, edx ; V sar ecx, 3 ;U sub edx, ebx ; V sar edx, 3 ;U mov [esi].GENGC_subDs, ecx ; V mov [esi].GENGC_subDt, edx ;U mov [esi].GENGC_sResult, eax ; V mov [esi].GENGC_tResult, ebx ;U mov eax, [esi].GENGC_flags ; V jmp loopTop ;U