;-----------------------------------------------------------------------------
;
; This file contains the alpha test functions.
;
; Copyright (C) Microsoft Corporation, 1997.
;
;
;-----------------------------------------------------------------------------
INCLUDE iammx.inc
INCLUDE offs_acp.inc


include(`m4hdr.mh')dnl
include(`cvars.mh')dnl

.586
.model flat
.code

EXTERN  g_uDitherValue:MMWORD

; Alpha Test compare macro
;#define ACMP(p, g, b)  \
;((((((INT32)(g) - (INT32)(b)) & (p)->iAAndMask) - (p)->iANeg) >= 0) ^ (p)->iAXorMask)

define(`d_LabelCounter', 0)dnl
dnl
dnl d_DoZWrite
dnl
dnl Inserts conditional Z Defered write code
dnl $1 the function type, $2 is the format of the Z buffer.
dnl
define(`d_DoZWrite', `
ifelse(`$1', `NoZWrite', `', `
ifelse(`$2', `16', `
        ; *((UINT16*)pS->pZ) = (UINT16)pCtx->SI.uZDeferred;
        mov   esi, XpS(pZ)
        movzx edx, word ptr XpCtxSI(uZDeferred)
        mov   word ptr [esi], dx
', `
        ;*((UINT32*)pS->pZ) = pCtx->SI.uZDeferred;
        mov   esi, XpS(pZ)
        mov   edx, dword ptr XpCtxSI(uZDeferred)
        mov   dword ptr [esi], edx
')dnl if 16
')dnl if NoZWrite
')dnl d_DoZWrite define
dnl d_DoAlphaDitherTest
dnl
dnl
dnl d_DoEnd
dnl
dnl $1 is NoStencil or Stencil
dnl
define(`d_DoEnd', `ifelse($1, `NoStencil', `
    ; pCtx->pfnAlphaTestPassEnd(pCtx, pP, pS);
    jmp     dword ptr XpCtx(pfnAlphaTestPassEnd)
', `
    ; if (pCtx->SI.bStencilPass)
    ; {
    ;     pCtx->pfnAlphaTestPassEnd(pCtx, pP, pS);
    ; }
    ; else
    ; {
    ;     // in the C code this does a return, since this is the
    ;     // last bead before write
    ;     // pCtx->pfnAlphaTestFailEnd(pCtx, pP, pS);
    ; }
    cmp word ptr XpCtxSI(bStencilPass), 0
    je  NoWrite   ; All cases can jump to same label since all just routine to span loop.
    jmp dword ptr XpCtx(pfnAlphaTestPassEnd)
')')dnl
dnl
dnl Inserts conditional AlphaDither Test code
dnl $1 the function type
dnl $2 is the ZWrite type
dnl $3 is the format of the Z buffer
dnl $4 is whether this function do a conditional return based on stencil
dnl
define(`d_DoAlphaDitherTest', `ifelse(`$1', `NoAlphaDither', `', `

define(`d_LabelCounter', eval(d_LabelCounter+1))dnl

    ;INT32 Alpha;
    xor     eax, eax    ; Prevent partial register stall. Since alpha will be one byte.

    ;UINT16 uDither = g_uDitherTable[pCtx->SI.uDitherOffset];
    mov     edx, DWORD PTR g_uDitherValue   ; Only need one byte for comparison.
    shr     edx, 3  ; The dither values are shifted to make color dithering easier.
                    ; Just shift them back down.

    ;if (pCtx->cActTex != 0)
    ;{
    cmp dword ptr XpCtx(cActTex), 0
    je  NoTexture`'d_LabelCounter`'

        ;Alpha = RGBA_GETALPHA(pCtx->SI.TexCol[0]);
        mov     al, byte ptr XpCtxSI(TexCol+3)
        jmp     DoneTexture`'d_LabelCounter`'
    ;}
    ;else
    ;{
NoTexture`'d_LabelCounter`':
        ;Alpha = pS->uA >> COLOR_SHIFT;
        mov     al, byte ptr XpS(uA+1)
    ;}
DoneTexture`'d_LabelCounter`':

    ;if ((Alpha & 0xff) > uDither)
    ;{
    cmp     al, dl
    jbe     DitherAlpha`'d_LabelCounter`'

        d_DoZWrite($2, $3)
        d_DoEnd($4)
    ;}
DitherAlpha`'d_LabelCounter`':
')')dnl

define(`d_AlphaHdr', `
;void MMX_AlphaTest_$1_$2_$3_$4_$5(PD3DI_RASTCTX pCtx, PD3DI_RASTPRIM pP, PD3DI_RASTSPAN pS)
;{
  PUBLIC _MMX_AlphaTest_$1_$2_$3_$4_$5
_MMX_AlphaTest_$1_$2_$3_$4_$5:

ifelse(`$1', `NoAlpha',
    `d_DoAlphaDitherTest(`$2', `$3', `$4', `$5')', `
    ;if (ACMP(pCtx, pCtx->SI.uBA, pCtx->iARef))
    ;{
    movzx edx, word ptr XpCtxSI(uBA)
    sub   edx, dword ptr XpCtx(iARef)
    and   edx, XpCtx(iAAndMask)
    sub   edx, XpCtx(iANeg)
    sar   edx, 31
    xor   edx, XpCtx(iAXorMask)
    test  edx, edx
    jz    NoWrite   ; All cases can jump to same label since all just routine to span loop.

ifelse($2, `NoAlphaDither', `
        d_DoZWrite(`$3', `$4')
        d_DoEnd($5)
', `
        d_DoAlphaDitherTest(`$2', `$3', `$4', `$5')
')
    ;}
    ;else
    ;{
        ;// in the C code this does a return, since this is the
        ;// last bead before write
        ;// pCtx->pfnAlphaTestFailEnd(pCtx, pP, pS);
        ; ASM code has everything jump to same label since it all goes to the same place.
    ;}')
dnl
    ; If Alpha Test passes, but alpha dither fails, we still need to call
    ; AlphaTestFailEnd or code continues to run into next routine.
    jmp     dword ptr XpCtx(pfnAlphaTestFailEnd)
;}')
dnl

NoWrite:
    jmp     dword ptr XpCtx(pfnAlphaTestFailEnd)


d_RepStr(`d_RepStr(`d_RepStr(`d_RepStr(`d_RepStr(`d_AlphaHdr(AA, BB, CC, DD, EE)',
         `AA', `NoAlpha', `Alpha')',
         `BB', `NoAlphaDither', `AlphaDither')',
         `CC', `NoZWrite', `ZWrite')',
         `DD', `16', `32')',
         `EE', `NoStencil', `Stencil')

END