/******************************Module*Header*******************************\ * Module Name: mcdutil.c * * Contains various utility routines for the Millenium MCD driver such as * rendering-procedure picking functionality and buffer management. * * Copyright (c) 1996 Microsoft Corporation \**************************************************************************/ #include "precomp.h" #include "mcdhw.h" #include "mcdutil.h" #include "mcdmath.h" #include "stdio.h" static ULONG xlatRop[16] = {bop_BLACKNESS, // GL_CLEAR 0 bop_MASKPEN, // GL_AND S & D bop_MASKPENNOT, // GL_AND_REVERSE S & ~D bop_SRCCOPY, // GL_COPY S bop_MASKNOTPEN, // GL_AND_INVERTED ~S & D bop_NOP, // GL_NOOP D bop_XORPEN, // GL_XOR S ^ D bop_MERGEPEN, // GL_OR S | D bop_NOTMERGEPEN, // GL_NOR ~(S | D) bop_NOTXORPEN, // GL_EQUIV ~(S ^ D) bop_NOT, // GL_INVERT ~D bop_MERGEPENNOT, // GL_OR_REVERSE S | ~D bop_NOTCOPYPEN, // GL_COPY_INVERTED ~S bop_MERGENOTPEN, // GL_OR_INVERTED ~S | D bop_NOTMASKPEN, // GL_NAND ~(S & D) bop_WHITENESS, // GL_SET 1 }; // Function prototypes: VOID FASTCALL HWSetupClipping(DEVRC *pRc, RECTL *pClip); #define MCD_ALLOC_TAG 'dDCM' #if DBG //#define DEVDBG ULONG MCDrvAllocMemSize = 0; UCHAR *MCDDbgAlloc(UINT size) { UCHAR *pRet; if (pRet = (UCHAR *)EngAllocMem(FL_ZERO_MEMORY, size + sizeof(ULONG), MCD_ALLOC_TAG)) { MCDrvAllocMemSize += size; *((ULONG *)pRet) = size; return (pRet + sizeof(ULONG)); } else return (UCHAR *)NULL; } VOID MCDDbgFree(UCHAR *pMem) { if (!pMem) { MCDBG_PRINT("MCDFree: Attempt to free NULL pointer."); return; } pMem -= sizeof(ULONG); MCDrvAllocMemSize -= *((ULONG *)pMem); #ifdef DEVDBG MCDBG_PRINT("MCDFree: %x bytes in use.", MCDrvAllocMemSize); #endif EngFreeMem((VOID *)pMem); } VOID MCDrvDebugPrint(char *pMessage, ...) { va_list ap; va_start(ap, pMessage); EngDebugPrint("[MCD DRIVER] ", pMessage, ap); EngDebugPrint("", "\n", ap); va_end(ap); } #else UCHAR *MCDAlloc(UINT size) { return (UCHAR *)EngAllocMem(FL_ZERO_MEMORY, size, MCD_ALLOC_TAG); } VOID MCDFree(UCHAR *pMem) { EngFreeMem((VOID *)pMem); } #endif /* DBG */ VOID FASTCALL NullRenderPoint(DEVRC *pRc, MCDVERTEX *pv) { } VOID FASTCALL NullRenderLine(DEVRC *pRc, MCDVERTEX *pv1, MCDVERTEX *pv2, BOOL bReset) { } VOID FASTCALL NullRenderTri(DEVRC *pRc, MCDVERTEX *pv1, MCDVERTEX *pv2, MCDVERTEX *pv3) { } MCDCOMMAND * FASTCALL FailPrimDraw(DEVRC *pRc, MCDCOMMAND *pCmd) { HW_WAIT_DRAWING_DONE(pRc); return pCmd; } BOOL PickPointFuncs(DEVRC *pRc) { ULONG enables = pRc->MCDState.enables; pRc->drawPoint = NULL; // assume failure if (enables & (MCD_POINT_SMOOTH_ENABLE)) return FALSE; if ((enables & MCD_FOG_ENABLE) && (!pRc->bCheapFog)) return FALSE; if (pRc->MCDState.pointSize != __MCDONE) return FALSE; // First, get high-level rendering functions: if (pRc->MCDState.drawBuffer != GL_FRONT_AND_BACK) { pRc->renderPoint = __MCDRenderPoint; } else { pRc->renderPoint = __MCDRenderGenPoint; } if ((pRc->bCheapFog) && (pRc->MCDState.shadeModel != GL_SMOOTH)) { pRc->renderPointX = pRc->renderPoint; pRc->renderPoint = __MCDRenderFogPoint; } // Handle any lower-level rendering if needed: pRc->drawPoint = pRc->renderPoint; return TRUE; } BOOL PickLineFuncs(DEVRC *pRc) { ULONG enables = pRc->MCDState.enables; pRc->drawLine = NULL; // assume failure if (enables & (MCD_LINE_SMOOTH_ENABLE | MCD_LINE_STIPPLE_ENABLE)) return FALSE; if ((enables & MCD_FOG_ENABLE) && (!pRc->bCheapFog)) return FALSE; if (pRc->MCDState.lineWidth != __MCDONE) return FALSE; // First, get high-level rendering functions: if (pRc->MCDState.drawBuffer != GL_FRONT_AND_BACK) { if (pRc->MCDState.shadeModel == GL_SMOOTH) pRc->renderLine = __MCDRenderSmoothLine; else pRc->renderLine = __MCDRenderFlatLine; } else { pRc->renderLine = __MCDRenderGenLine; } if ((pRc->bCheapFog) && (pRc->MCDState.shadeModel != GL_SMOOTH)) { pRc->renderLineX = __MCDRenderSmoothLine; pRc->renderLine = __MCDRenderFlatFogLine; } // Handle any lower-level rendering if needed: pRc->drawLine = pRc->renderLine; return TRUE; } BOOL PickTriangleFuncs(DEVRC *pRc) { ULONG enables = pRc->MCDState.enables; if (enables & MCD_POLYGON_STIPPLE_ENABLE) { ULONG *pStipple = (ULONG *)pRc->MCDState.polygonStipple; LONG i; for (pRc->hwStipple = trans_2, i = 0; i < 16; i += 2) { if ((pStipple[i] != 0xaaaaaaaa) || (pStipple[i+1] != 0x55555555)) { pRc->hwStipple = 0; break; } } if (!pRc->hwStipple) { for (pRc->hwStipple = trans_1, i = 0; i < 16; i += 2) { if ((pStipple[i] != 0x55555555) || (pStipple[i+1] != 0xaaaaaaaa)) { pRc->hwStipple = 0; break; } } } if (!pRc->hwStipple) return FALSE; } else pRc->hwStipple = 0; if (enables & (MCD_POLYGON_SMOOTH_ENABLE | MCD_COLOR_LOGIC_OP_ENABLE)) return FALSE; if ((enables & MCD_FOG_ENABLE) && (!pRc->bCheapFog)) return FALSE; // First, get high-level rendering functions. If we're not GL_FILL'ing // both sides of our polygons, use the "generic" function. if (((pRc->MCDState.polygonModeFront == GL_FILL) && (pRc->MCDState.polygonModeBack == GL_FILL)) && (pRc->MCDState.drawBuffer != GL_FRONT_AND_BACK) ) { if ((pRc->MCDState.shadeModel == GL_SMOOTH) || (pRc->bCheapFog)) pRc->renderTri = __MCDRenderSmoothTriangle; else pRc->renderTri = __MCDRenderFlatTriangle; } else { pRc->renderTri = __MCDRenderGenTriangle; // In this case, we must handle the various fill modes. We must // fail triangle drawing if we can't handle the types of primitives // that may have to be drawn. This logic depends on the line and // point pick routines if (((pRc->MCDState.polygonModeFront == GL_POINT) && (!pRc->drawPoint)) || ((pRc->MCDState.polygonModeFront == GL_LINE) && (!pRc->drawLine))) return FALSE; if (pRc->privateEnables & __MCDENABLE_TWOSIDED) { if (((pRc->MCDState.polygonModeBack == GL_POINT) && (!pRc->drawPoint)) || ((pRc->MCDState.polygonModeBack == GL_LINE) && (!pRc->drawLine))) return FALSE; } } if ((pRc->bCheapFog) && (pRc->MCDState.shadeModel != GL_SMOOTH)) { pRc->renderTriX = pRc->renderTri; pRc->renderTri = __MCDRenderFlatFogTriangle; } // Handle lower-level triangle rendering: pRc->drawTri = __MCDFillTriangle; pRc->HWDrawTrap = __HWDrawTrap; pRc->HWSetupDeltas = __HWSetupDeltas; pRc->calcDeltas = __MCDCalcDeltaRGBZ; pRc->adjustLeftEdge = __HWAdjustLeftEdgeRGBZ; pRc->adjustRightEdge = __HWAdjustRightEdge; return TRUE; } VOID __MCDPickRenderingFuncs(DEVRC *pRc, DEVWND *pDevWnd) { BOOL bSupportedZFunc = TRUE; pRc->primFunc[GL_POINTS] = __MCDPrimDrawPoints; pRc->primFunc[GL_LINES] = __MCDPrimDrawLines; pRc->primFunc[GL_LINE_LOOP] = __MCDPrimDrawLineLoop; pRc->primFunc[GL_LINE_STRIP] = __MCDPrimDrawLineStrip; pRc->primFunc[GL_TRIANGLES] = __MCDPrimDrawTriangles; pRc->primFunc[GL_TRIANGLE_STRIP] = __MCDPrimDrawTriangleStrip; pRc->primFunc[GL_TRIANGLE_FAN] = __MCDPrimDrawTriangleFan; pRc->primFunc[GL_QUADS] = __MCDPrimDrawQuads; pRc->primFunc[GL_QUAD_STRIP] = __MCDPrimDrawQuadStrip; pRc->primFunc[GL_POLYGON] = __MCDPrimDrawPolygon; // Set up the privateEnables flags: switch (pRc->MCDState.depthTestFunc) { default: case GL_NEVER: bSupportedZFunc = FALSE; break; case GL_LESS: pRc->hwZFunc = zmode_ZLT; break; case GL_EQUAL: pRc->hwZFunc = zmode_ZE; break; case GL_LEQUAL: pRc->hwZFunc = zmode_ZLTE; break; case GL_GREATER: pRc->hwZFunc = zmode_ZGT; break; case GL_NOTEQUAL: pRc->hwZFunc = zmode_ZNE; break; case GL_GEQUAL: pRc->hwZFunc = zmode_ZGTE; break; case GL_ALWAYS: pRc->hwZFunc = zmode_NOZCMP; break; } if (pRc->MCDState.enables & MCD_COLOR_LOGIC_OP_ENABLE) { pRc->hwRop = xlatRop[pRc->MCDState.logicOpMode & 0xf]; } else pRc->hwRop = bop_SRCCOPY; HW_GET_PLANE_MASK(pRc); pRc->privateEnables = 0; if ((pRc->MCDState.twoSided) && (pRc->MCDState.enables & MCD_LIGHTING_ENABLE)) pRc->privateEnables |= __MCDENABLE_TWOSIDED; if (pDevWnd->bValidZBuffer && (pRc->MCDState.enables & MCD_DEPTH_TEST_ENABLE)) pRc->privateEnables |= __MCDENABLE_Z; if (pRc->MCDState.shadeModel == GL_SMOOTH) pRc->privateEnables |= __MCDENABLE_SMOOTH; // Bail out if we can't support the requested z-buffer function: if (pRc->privateEnables & __MCDENABLE_Z) { if (!bSupportedZFunc) { pRc->allPrimFail = TRUE; return; } if ((pRc->MCDState.depthWritemask) && (pRc->zBufEnabled)) { pRc->hwTrapFunc = pRc->hwLineFunc = atype_ZI; } else { pRc->hwTrapFunc = pRc->hwLineFunc = atype_I; } pRc->hwTrapFunc |= opcode_TRAP | pRc->hwRop | pRc->hwZFunc; pRc->hwLineFunc |= opcode_LINE_OPEN | pRc->hwRop | pRc->hwZFunc; } else { pRc->hwTrapFunc = opcode_TRAP | atype_I | bop_SRCCOPY; pRc->hwLineFunc = opcode_LINE_OPEN | atype_I | bop_SRCCOPY; } pRc->HWSetupClipRect = HWSetupClipping; // Even though we're set up to handle this in the primitive pick // functions, we'll exit early here since we don't actually handle // this in the primitive routines themselves: if (pRc->MCDState.drawBuffer == GL_FRONT_AND_BACK) { pRc->allPrimFail = TRUE; return; } // If we're culling everything or not updating any of our buffers, just // return for all primitives: if (((pRc->MCDState.enables & MCD_CULL_FACE_ENABLE) && (pRc->MCDState.cullFaceMode == GL_FRONT_AND_BACK)) || ((pRc->MCDState.drawBuffer == GL_NONE) && ((!pRc->MCDState.depthWritemask) || (!pDevWnd->bValidZBuffer))) ) { pRc->renderPoint = NullRenderPoint; pRc->renderLine = NullRenderLine; pRc->renderTri = NullRenderTri; pRc->allPrimFail = FALSE; return; } // Build lookup table for face direction switch (pRc->MCDState.frontFace) { case GL_CW: pRc->polygonFace[__MCD_CW] = __MCD_BACKFACE; pRc->polygonFace[__MCD_CCW] = __MCD_FRONTFACE; break; case GL_CCW: pRc->polygonFace[__MCD_CW] = __MCD_FRONTFACE; pRc->polygonFace[__MCD_CCW] = __MCD_BACKFACE; break; } // Build lookup table for face filling modes: pRc->polygonMode[__MCD_FRONTFACE] = pRc->MCDState.polygonModeFront; pRc->polygonMode[__MCD_BACKFACE] = pRc->MCDState.polygonModeBack; if (pRc->MCDState.enables & MCD_CULL_FACE_ENABLE) pRc->cullFlag = (pRc->MCDState.cullFaceMode == GL_FRONT ? __MCD_FRONTFACE : __MCD_BACKFACE); else pRc->cullFlag = __MCD_NOFACE; // Assume that we fail everything: pRc->allPrimFail = TRUE; // Determine if we have "cheap" fog: pRc->bCheapFog = FALSE; if (pRc->MCDState.enables & MCD_FOG_ENABLE) { if (!(pRc->MCDState.textureEnabled) && (pRc->MCDState.fogHint != GL_NICEST)) { pRc->bCheapFog = TRUE; pRc->privateEnables |= __MCDENABLE_SMOOTH; if ((pRc->MCDState.fogColor.r == pRc->MCDState.fogColor.g) && (pRc->MCDState.fogColor.r == pRc->MCDState.fogColor.b)) pRc->privateEnables |= __MCDENABLE_GRAY_FOG; } } if (pRc->MCDState.textureEnabled) return; if (pRc->MCDState.enables & (MCD_ALPHA_TEST_ENABLE | MCD_BLEND_ENABLE | MCD_STENCIL_TEST_ENABLE)) return; // Get rendering functions for points: if (!PickPointFuncs(pRc)) { pRc->primFunc[GL_POINTS] = FailPrimDraw; } else pRc->allPrimFail = FALSE; // Get rendering functions for lines: if (!PickLineFuncs(pRc)) { pRc->primFunc[GL_LINES] = FailPrimDraw; pRc->primFunc[GL_LINE_LOOP] = FailPrimDraw; pRc->primFunc[GL_LINE_STRIP] = FailPrimDraw; } else pRc->allPrimFail = FALSE; // Get rendering functions for triangles: if (!PickTriangleFuncs(pRc)) { pRc->primFunc[GL_TRIANGLES] = FailPrimDraw; pRc->primFunc[GL_TRIANGLE_STRIP] = FailPrimDraw; pRc->primFunc[GL_TRIANGLE_FAN] = FailPrimDraw; pRc->primFunc[GL_QUADS] = FailPrimDraw; pRc->primFunc[GL_QUAD_STRIP] = FailPrimDraw; pRc->primFunc[GL_POLYGON] = FailPrimDraw; } else pRc->allPrimFail = FALSE; } //////////////////////////////////////////////////////////////////////// // Hardware-specific utility functions: //////////////////////////////////////////////////////////////////////// VOID FASTCALL HWSetupClipping(DEVRC *pRc, RECTL *pClip) { PDEV *ppdev = pRc->ppdev; BYTE *pjBase = ppdev->pjBase; CHECK_FIFO_FREE(pjBase, pRc->cFifo, 4); CP_WRITE(pjBase, DWG_CYTOP, ((pClip->top + pRc->hwBufferYBias) * ppdev->cxMemory) + ppdev->ulYDstOrg); CP_WRITE(pjBase, DWG_CXLEFT, pClip->left); CP_WRITE(pjBase, DWG_CXRIGHT, pClip->right - 1); CP_WRITE(pjBase, DWG_CYBOT, ((pClip->bottom + pRc->hwBufferYBias - 1) * ppdev->cxMemory) + ppdev->ulYDstOrg); } //#define DEBUG_OFFSCREEN 1 //#define DEBUG_OFFSSCREEN_PARTIAL 1 #if DEBUG_OFFSCREEN #undef pohAllocate #undef pohFree #define pohAllocate #define pohFree #endif VOID HWUpdateBufferPos(MCDWINDOW *pMCDWnd, SURFOBJ *pso, BOOL bForce) { PDEV *ppdev = (PDEV *)pso->dhpdev; DEVWND *pDevWnd = (DEVWND *)pMCDWnd->pvUser; ULONG height; if (pDevWnd->pohZBuffer && ((ppdev->pohZBuffer != pDevWnd->pohZBuffer) || (bForce))) { LONG offset; LONG offsetAdj; ULONG y; // First, re-adjust the z buffer so that its offset from // the front buffer window rectangle (in z) is a multiple of 512: if (ppdev->pohZBuffer != pDevWnd->pohZBuffer) offset = pDevWnd->zBufferBase - (pMCDWnd->clipBoundsRect.top * pDevWnd->zPitch); else offset = pDevWnd->zBufferBase; if (offset < 0) { offset = -offset; for (y = 0, offsetAdj = 0; (y < pDevWnd->numPadScans) && (offset & 0x1ff); offset -= pDevWnd->zPitch, offsetAdj += pDevWnd->zPitch) ; } else { for (y = 0, offsetAdj = 0; (y < pDevWnd->numPadScans) && (offset & 0x1ff); offset += pDevWnd->zPitch, offsetAdj += pDevWnd->zPitch) ; } ASSERTDD((offset & 0x1ff) == 0, "Z scan not on a 512-byte boundary."); ASSERTDD(y <= pDevWnd->numPadScans, "Z scan adjustment too large"); pDevWnd->zBufferOffset = pDevWnd->zBufferBase + offsetAdj; // Now, re-adjust the back buffer so that its offset (in z) from // the new z buffer offset is also a multiple of 512 bytes. Note // that zBufferOffset is always a multiple of zPitch: if (pDevWnd->pohBackBuffer) { offset = (pDevWnd->backBufferBaseY * pDevWnd->zPitch) - pDevWnd->zBufferOffset; for (y = 0; (y < pDevWnd->numPadScans) && (offset & 0x1ff); y++) offset += pDevWnd->zPitch; ASSERTDD((offset & 0x1ff) == 0, "Scan not on a 512-byte boundary."); ASSERTDD(y <= pDevWnd->numPadScans, "Scan adjustment too large"); pDevWnd->backBufferY = y + pDevWnd->backBufferBaseY; pDevWnd->backBufferOffset = (pDevWnd->backBufferY * ppdev->lDelta); } } height = pMCDWnd->clientRect.bottom - pMCDWnd->clientRect.top; if (height > pDevWnd->allocatedBufferHeight) { #ifdef DEVDBG MCDBG_PRINT("HWUpdateBufferPos: buffers are now an invalid size."); #endif pDevWnd->bValidBackBuffer = FALSE; pDevWnd->bValidZBuffer = FALSE; } } BOOL HWAllocResources(MCDWINDOW *pMCDWnd, SURFOBJ *pso, BOOL zBufferEnabled, BOOL backBufferEnabled) { DEVWND *pDevWnd = (DEVWND *)pMCDWnd->pvUser; PDEV *ppdev = (PDEV *)pso->dhpdev; ULONG w, width, height, fullHeight, zHeight, zFullHeight; BOOL needFullZBuffer, needFullBackBuffer; ULONG bufferExtra; ULONG wPow2; ULONG zPitch; BOOL bFullScreen = FALSE; OH* pohBackBuffer = NULL; OH* pohZBuffer = NULL; #if DEBUG_OFFSCREEN static OH fakeOh[2]; pohBackBuffer = &fakeOh[0]; pohZBuffer = &fakeOh[1]; pohBackBuffer->y = 512; pohZBuffer->y = 256; #endif #ifdef DEVDBG MCDBG_PRINT("HWAllocResources"); #endif #if DEBUG_OFFSCREEN width = ppdev->cxScreen; height = 256; #else width = ppdev->cxScreen; height = min(pMCDWnd->clientRect.bottom - pMCDWnd->clientRect.top, ppdev->cyScreen); #endif // Assume failure: pDevWnd->allocatedBufferHeight = 0; pDevWnd->bValidBackBuffer = FALSE; pDevWnd->bValidZBuffer = FALSE; pDevWnd->pohBackBuffer = NULL; pDevWnd->pohZBuffer = NULL; fullHeight = ppdev->cyScreen; switch (ppdev->iBitmapFormat) { case BMF_8BPP: zPitch = ppdev->lDelta * 2; break; case BMF_16BPP: zPitch = ppdev->lDelta; break; case BMF_24BPP: case BMF_32BPP: zPitch = ppdev->lDelta / 2; break; default: return FALSE; } // We have to be able to keep our buffers 512-byte aligned, so calculate // extra scan lines needed to aligned scan on a 512-byte boundary: for (wPow2 = 1, w = zPitch; (w) && !(w & 1); w >>= 1, wPow2 *= 2) ; bufferExtra = 512 / wPow2; // z buffer granularity is 512 bytes... // Now adjust the number of extra scan lines needed for the pixel format // we're using, since the z and color stride may be different... switch (ppdev->iBitmapFormat) { case BMF_8BPP: zHeight = ((height + bufferExtra) * 2) + 1; zFullHeight = ((fullHeight + bufferExtra) * 2) + 1; break; case BMF_16BPP: zHeight = height + bufferExtra; zFullHeight = fullHeight + bufferExtra; break; case BMF_24BPP: case BMF_32BPP: zHeight = (height + bufferExtra + 1) / 2; zFullHeight = (fullHeight + bufferExtra + 1) / 2; break; default: return FALSE; } pDevWnd->numPadScans = bufferExtra; // Add extra scans for alignment: height += bufferExtra; fullHeight += bufferExtra; if ((backBufferEnabled) && (!ppdev->cDoubleBufferRef)) needFullBackBuffer = TRUE; else needFullBackBuffer = FALSE; if ((zBufferEnabled) && (!ppdev->cZBufferRef)) needFullZBuffer = TRUE; else needFullZBuffer = FALSE; // debugging - force parial window allocation #if DEBUG_OFFSCREEN && DEBUG_OFFSCREEN_PARTIAL pohBackBuffer = NULL; pohZBuffer = NULL; #endif // Before we begin, boot all the discardable stuff from offscreen // memory: bMoveAllDfbsFromOffscreenToDibs(ppdev); // If we need a back buffer, first try to allocate a fullscreen one: if (needFullBackBuffer) { #ifndef DEBUG_OFFSCREEN pohBackBuffer = pohAllocate(ppdev, NULL, width, fullHeight, FLOH_MAKE_PERMANENT); #endif if (pohBackBuffer) { ppdev->pohBackBuffer = pohBackBuffer; ppdev->cDoubleBufferRef = 0; } } // If we need a z buffer, first try to allocate a fullscreen z: if (needFullZBuffer) { #ifndef DEBUG_OFFSCREEN pohZBuffer = pohAllocate(ppdev, NULL, width, zFullHeight, FLOH_MAKE_PERMANENT); #endif if (pohZBuffer) { ppdev->pohZBuffer = pohZBuffer; ppdev->cZBufferRef = 0; } else needFullBackBuffer = FALSE; } // One of our full-screen allocations failed: if ((needFullZBuffer && !pohZBuffer) || (needFullBackBuffer && !pohBackBuffer)) { // Free any resources allocated so far: if (pohZBuffer) { pohFree(ppdev, pohZBuffer); ppdev->pohZBuffer = NULL; ppdev->cZBufferRef = 0; } if (pohBackBuffer) { pohFree(ppdev, pohBackBuffer); ppdev->pohBackBuffer = NULL; ppdev->cDoubleBufferRef = 0; } // Now, try to allocate per-window resources: if (backBufferEnabled) { #ifndef DEBUG_OFFSCREEN pohBackBuffer = pohAllocate(ppdev, NULL, width, height, FLOH_MAKE_PERMANENT); #else pohBackBuffer = &fakeOh[0]; #endif if (!pohBackBuffer) { return FALSE; } } if (zBufferEnabled) { #ifndef DEBUG_OFFSCREEN pohZBuffer = pohAllocate(ppdev, NULL, width, zHeight, FLOH_MAKE_PERMANENT); #else pohZBuffer = &fakeOh[1]; #endif if (!pohZBuffer) { if (pohBackBuffer) pohFree(ppdev, pohBackBuffer); return FALSE; } } #ifdef DEVDBG if (zBufferEnabled) MCDBG_PRINT("HWAllocResources: Allocated window-sized z buffer"); if (backBufferEnabled) MCDBG_PRINT("HWAllocResources: Allocated window-sized back buffer"); #endif } else { // Our full-screen allocations worked, or the resources existed // already: bFullScreen = TRUE; #ifdef DEVDBG if (zBufferEnabled && !ppdev->cZBufferRef) MCDBG_PRINT("HWAllocResources: Allocated full-screen z buffer"); if (backBufferEnabled && !ppdev->cDoubleBufferRef) MCDBG_PRINT("HWAllocResources: Allocated full-screen back buffer"); #endif if (zBufferEnabled) { pohZBuffer = ppdev->pohZBuffer; ppdev->cZBufferRef++; } if (backBufferEnabled) { pohBackBuffer = ppdev->pohBackBuffer; ppdev->cDoubleBufferRef++; } } pDevWnd->pohBackBuffer = pohBackBuffer; pDevWnd->pohZBuffer = pohZBuffer; pDevWnd->frontBufferPitch = ppdev->lDelta; // Calculate back buffer variables: if (backBufferEnabled) { ULONG y; ULONG offset; ASSERTDD(pohBackBuffer->x == 0, "Back buffer should be 0-aligned"); // Set up base position, etc. pDevWnd->backBufferY = pDevWnd->backBufferBaseY = pohBackBuffer->y; pDevWnd->backBufferOffset = pDevWnd->backBufferBase = pohBackBuffer->y * ppdev->lDelta; pDevWnd->backBufferPitch = ppdev->lDelta; pDevWnd->bValidBackBuffer = TRUE; } if (zBufferEnabled) { ULONG y = pohZBuffer->y; ASSERTDD(pohZBuffer->x == 0, "Z buffer should be 0-aligned"); pDevWnd->zBufferBaseY = pohZBuffer->y; // Make sure out z buffer starts on a valid z scan line. The only // case where this may not happen is 8bpp, which is why we add one // the the number if z scan lines allocated above. if (ppdev->iBitmapFormat == BMF_8BPP) pDevWnd->zBufferBase = (pohZBuffer->y & ~1) * ppdev->lDelta; else pDevWnd->zBufferBase = pohZBuffer->y * ppdev->lDelta; pDevWnd->zPitch = zPitch; pDevWnd->bValidZBuffer = TRUE; } if (bFullScreen) pDevWnd->allocatedBufferHeight = ppdev->cyMemory; else pDevWnd->allocatedBufferHeight = min(pMCDWnd->clientRect.bottom - pMCDWnd->clientRect.top, ppdev->cyScreen); // Update position-dependant buffer information: HWUpdateBufferPos(pMCDWnd, pso, TRUE); #ifdef DEVDBG MCDBG_PRINT("HWAllocResources OK"); #endif return TRUE; } VOID HWFreeResources(MCDWINDOW *pMCDWnd, SURFOBJ *pso) { DEVWND *pDevWnd = (DEVWND *)pMCDWnd->pvUser; PDEV *ppdev = (PDEV *)pso->dhpdev; if (pDevWnd->pohZBuffer) { if (ppdev->cZBufferRef) { if (!--ppdev->cZBufferRef) { #ifdef DEVDBG MCDBG_PRINT("MCDrvTrackWindow: Free global z buffer"); #endif pohFree(ppdev, ppdev->pohZBuffer); ppdev->pohZBuffer = NULL; } } else { #ifdef DEVDBG MCDBG_PRINT("MCDrvTrackWindow: Free local z buffer"); #endif pohFree(ppdev, pDevWnd->pohZBuffer); } } if (pDevWnd->pohBackBuffer) { if (ppdev->cDoubleBufferRef) { if (!--ppdev->cDoubleBufferRef) { #ifdef DEVDBG MCDBG_PRINT("MCDrvTrackWindow: Free global color buffer"); #endif pohFree(ppdev, ppdev->pohBackBuffer); ppdev->pohBackBuffer = NULL; } } else { #ifdef DEVDBG MCDBG_PRINT("MCDrvTrackWindow: Free local color buffer"); #endif pohFree(ppdev, pDevWnd->pohBackBuffer); } } } VOID __MCDCalcFogColor(DEVRC *pRc, MCDVERTEX *a, MCDCOLOR *pResult, MCDCOLOR *pColor) { MCDFLOAT oneMinusFog; MCDCOLOR *pFogColor; pFogColor = (MCDCOLOR *)&pRc->MCDState.fogColor; oneMinusFog = (MCDFLOAT)1.0 - a->fog; if (pRc->privateEnables & __MCDENABLE_GRAY_FOG) { MCDFLOAT delta = oneMinusFog * pFogColor->r; pResult->r = a->fog * pColor->r + delta; pResult->g = a->fog * pColor->g + delta; pResult->b = a->fog * pColor->b + delta; } else { pResult->r = (a->fog * pColor->r) + (oneMinusFog * pFogColor->r); pResult->g = (a->fog * pColor->g) + (oneMinusFog * pFogColor->g); pResult->b = (a->fog * pColor->b) + (oneMinusFog * pFogColor->b); } }