//---------------------------------------------------------------------------- // // line.cpp // // Line processing. // // Copyright (C) Microsoft Corporation, 1997. // //---------------------------------------------------------------------------- #include "pch.cpp" #pragma hdrstop DBG_DECLARE_FILE(); //---------------------------------------------------------------------------- // // LinePatternStateMachine // // Runs the line pattern state machine and returns TRUE if the pixel is to be // drawn, false otherwise. // //---------------------------------------------------------------------------- static inline BOOL LinePatternStateMachine(WORD wRepeatFactor, WORD wLinePattern, WORD& wRepeati, WORD& wPatterni) { if (wRepeatFactor == 0) { return TRUE; } WORD wBit = (wLinePattern >> wPatterni) & 1; if (++wRepeati >= wRepeatFactor) { wRepeati = 0; wPatterni = (wPatterni+1) & 0xf; } return (BOOL)wBit; } #define CLAMP_COLOR(fVal, uVal) \ if (FLOAT_LTZ(fVal)) \ { \ uVal = 0; \ } \ else \ { \ if (uVal > 0xffff) \ { \ uVal = 0xffff; \ } \ } \ #define CLAMP_Z(fVal, uVal) \ if (FLOAT_LTZ(fVal)) \ { \ uVal = 0; \ } \ //---------------------------------------------------------------------------- // // ClampPixel // // Clamp color, specular and z(if any) of a pixel. Right now, it's done for // first and last pixel of a line only. // //---------------------------------------------------------------------------- inline void ClampPixel(PATTRSET pAttrs, PD3DI_RASTSPAN pSpan) { CLAMP_COLOR(pAttrs->fB, pSpan->uB); CLAMP_COLOR(pAttrs->fG, pSpan->uG); CLAMP_COLOR(pAttrs->fR, pSpan->uR); CLAMP_COLOR(pAttrs->fA, pSpan->uA); CLAMP_COLOR(pAttrs->fBS, pSpan->uBS); CLAMP_COLOR(pAttrs->fGS, pSpan->uGS); CLAMP_COLOR(pAttrs->fRS, pSpan->uRS); CLAMP_Z(pAttrs->fZ, pSpan->uZ); } //---------------------------------------------------------------------------- // // WalkLinePattern // // Walks a line and generates the pixels touched according to the pattern. // If wRepeatFactor >= 1, we are patterning, otherwise, we are not // //---------------------------------------------------------------------------- HRESULT WalkLinePattern(PSETUPCTX pStpCtx, WORD wRepeatFactor, WORD wLinePattern) { HRESULT hr; UINT uSpansAvail; PD3DI_RASTSPAN pSpan; WORD wRepeati = 0; WORD wPatterni = 0; BOOL bFirst = TRUE; RSASSERT(pStpCtx->cLinePix > 0); hr = D3D_OK; uSpansAvail = 0; RSASSERT((pStpCtx->uFlags & PRIMSF_LOD_USED) == 0); #ifdef PWL_FOG pStpCtx->uPwlFlags = PWL_NO_NEXT_FOG; #endif for (;;) { if (pStpCtx->iX >= pStpCtx->pCtx->Clip.left && pStpCtx->iX < pStpCtx->pCtx->Clip.right && pStpCtx->iY >= pStpCtx->pCtx->Clip.top && pStpCtx->iY < pStpCtx->pCtx->Clip.bottom) { if (LinePatternStateMachine(wRepeatFactor, wLinePattern, wRepeati, wPatterni)) { if (uSpansAvail == 0) { uSpansAvail = pStpCtx->cLinePix; hr = ALLOC_SPANS(pStpCtx, &uSpansAvail, &pSpan); if (hr != D3D_OK) { // uSpansAvail is set to zero on failure. goto EH_Exit; } } else { pSpan++; } uSpansAvail--; pStpCtx->pPrim->uSpans++; pSpan->uPix = 1; pSpan->uX = (UINT16)pStpCtx->iX; pSpan->uY = (UINT16)pStpCtx->iY; pStpCtx->pfnFillSpanAttrs(&pStpCtx->Attr, pSpan, pStpCtx, 1); // Clamp first/last pixel if (bFirst || pStpCtx->cLinePix == 1) { bFirst = FALSE; ClampPixel(&pStpCtx->Attr, pSpan); } } } if (--pStpCtx->cLinePix == 0) { break; } #ifdef VERBOSE_LINES RSDPF((" %4d,%4d: %10d %11d => ", pStpCtx->iX, pStpCtx->iY, pStpCtx->iLineFrac, pStpCtx->iLineFrac + pStpCtx->iDLineFrac)); #endif pStpCtx->iLineFrac += pStpCtx->iDLineFrac; if (pStpCtx->iLineFrac < 0) { pStpCtx->iLineFrac &= 0x7fffffff; pStpCtx->iX += pStpCtx->iDXCY; pStpCtx->iY += pStpCtx->iDYCY; pStpCtx->DAttrDMajor.ipSurface = pStpCtx->DAttrCY.ipSurface; pStpCtx->DAttrDMajor.ipZ = pStpCtx->DAttrCY.ipZ; } else { pStpCtx->iX += pStpCtx->iDXNC; pStpCtx->iY += pStpCtx->iDYNC; pStpCtx->DAttrDMajor.ipSurface = pStpCtx->DAttrNC.ipSurface; pStpCtx->DAttrDMajor.ipZ = pStpCtx->DAttrNC.ipZ; } #ifdef VERBOSE_LINES RSDPFM((DBG_MASK_FORCE | DBG_MASK_NO_PREFIX, "%4d,%4d: %10d\n", pStpCtx->iX, pStpCtx->iY, pStpCtx->iLineFrac)); #endif pStpCtx->pfnAddAttrs(&pStpCtx->Attr, &pStpCtx->DAttrDMajor, pStpCtx); } EH_Exit: if (uSpansAvail > 0) { FREE_SPANS(pStpCtx, uSpansAvail); } return hr; } //---------------------------------------------------------------------------- // // PrimProcessor::Line // // Provides a line for processing. // //---------------------------------------------------------------------------- HRESULT PrimProcessor::Line(LPD3DTLVERTEX pV0, LPD3DTLVERTEX pV1, LPD3DTLVERTEX pFlatVtx) { HRESULT hr; hr = D3D_OK; #if DBG hr = ValidateVertex(pV0); if (hr != D3D_OK) { return hr; } hr = ValidateVertex(pV1); if (hr != D3D_OK) { return hr; } #endif // Clear per-line flags. m_StpCtx.uFlags &= ~(PRIMF_ALL | LNF_ALL); RSDPFM((RSM_FLAGS, "m_uPpFlags: 0x%08X, m_StpCtx.uFlags: 0x%08X\n", m_uPpFlags, m_StpCtx.uFlags)); RSDPFM((RSM_LINES, "Line\n")); RSDPFM((RSM_LINES, " V0 (%f,%f,%f)\n", pV0->dvSX, pV0->dvSY, pV0->dvSZ)); RSDPFM((RSM_LINES, " V1 (%f,%f,%f)\n", pV1->dvSX, pV1->dvSY, pV1->dvSZ)); // Remember flat color controlling vertex for setup. m_StpCtx.pFlatVtx = pFlatVtx; if (LineSetup(pV0, pV1)) { // Compute initial buffer pointers for the scanline. m_StpCtx.Attr.pSurface = m_StpCtx.pCtx->pSurfaceBits + m_StpCtx.iX * m_StpCtx.pCtx->iSurfaceStep + m_StpCtx.iY * m_StpCtx.pCtx->iSurfaceStride; if (m_StpCtx.uFlags & PRIMSF_Z_USED) { m_StpCtx.Attr.pZ = m_StpCtx.pCtx->pZBits + m_StpCtx.iX * m_StpCtx.pCtx->iZStep + m_StpCtx.iY * m_StpCtx.pCtx->iZStride; } // Line walking only generates single-pixel spans so // the prim deltas are unused. Therefore, line spans // are simply added to whatever primitive happens to // be sitting in the buffer. hr = AppendPrim(); if (hr != D3D_OK) { return hr; } union { D3DLINEPATTERN LPat; DWORD dwLPat; } LinePat; LinePat.dwLPat = m_StpCtx.pCtx->pdwRenderState[D3DRENDERSTATE_LINEPATTERN]; hr = WalkLinePattern(&m_StpCtx, LinePat.LPat.wRepeatFactor, LinePat.LPat.wLinePattern); } return hr; }