|
|
/*==========================================================================;
* * Copyright (C) 1997 Microsoft Corporation. All Rights Reserved. * * File: dphal.c * Content: DrawPrimitive implementation for DrawPrimitive HALs * ***************************************************************************/
#include "pch.cpp"
#pragma hdrstop
#include "drawprim.hpp"
#include "clipfunc.h"
#include "d3dfei.h"
extern const DWORD LOWVERTICESNUMBER = 20;
#if DBG
extern DWORD FaceCount; DWORD FaceCount = 0; DWORD StartFace = 0; DWORD EndFace = 10000; #endif
extern void SetDebugRenderState(DWORD value);
#define ALIGN32(x) x = ((DWORD)(x + 31)) & (~31);
//---------------------------------------------------------------------
// Array to map D3DVERTEXTYPE to FVF vertex type
//
DWORD d3dVertexToFVF[4] = { 0, D3DFVF_VERTEX, D3DFVF_LVERTEX, D3DFVF_TLVERTEX }; //---------------------------------------------------------------------
// Handles strides and FVF
//
#undef DPF_MODNAME
#define DPF_MODNAME "D3DFE_updateExtents"
void D3DFE_updateExtents(LPDIRECT3DDEVICEI lpDevI) { int i; D3DVECTOR *v = (D3DVECTOR*)lpDevI->position.lpvData; DWORD stride = lpDevI->position.dwStride; for (i = lpDevI->dwNumVertices; i; i--) { if (v->x < lpDevI->rExtents.x1) lpDevI->rExtents.x1 = v->x; if (v->x > lpDevI->rExtents.x2) lpDevI->rExtents.x2 = v->x; if (v->y < lpDevI->rExtents.y1) lpDevI->rExtents.y1 = v->y; if (v->y > lpDevI->rExtents.y2) lpDevI->rExtents.y2 = v->y; v = (D3DVECTOR*)((char*)v + stride); } } //---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "MapFVFtoTLVertex1"
inline void MapFVFtoTLVertex1(LPDIRECT3DDEVICEI lpDevI, D3DTLVERTEX *pOut, DWORD *pIn) { // Copy position
pOut->sx = *(D3DVALUE*)pIn++; pOut->sy = *(D3DVALUE*)pIn++; pOut->sz = *(D3DVALUE*)pIn++; pOut->rhw = *(D3DVALUE*)pIn++; // Other fields: diffuse, specular, texture
if (lpDevI->dwVIDOut & D3DFVF_DIFFUSE) pOut->color = *pIn++; else { pOut->color = __DEFAULT_DIFFUSE; } if (lpDevI->dwVIDOut & D3DFVF_SPECULAR) pOut->specular = *pIn++; else { pOut->specular= __DEFAULT_SPECULAR; } if (lpDevI->nTexCoord) { pIn = &pIn[lpDevI->dwTextureIndexToCopy << 1]; pOut->tu = *(D3DVALUE*)&pIn[0]; pOut->tv = *(D3DVALUE*)&pIn[1]; } else { pOut->tu = 0; pOut->tv = 0; } } //---------------------------------------------------------------------
// All vertices from lpDevI->lpVout are copied to the output buffer, expanding
// to D3DTLVERTEX.
// The output buffer is lpAddress if it is not NULL, otherwise it is TLVbuf
//
#undef DPF_MODNAME
#define DPF_MODNAME "MapFVFtoTLVertex"
HRESULT MapFVFtoTLVertex(LPDIRECT3DDEVICEI lpDevI, LPVOID lpAddress) { int i; DWORD size = lpDevI->dwNumVertices * sizeof(D3DTLVERTEX); D3DTLVERTEX *pOut; if (lpAddress) pOut = (D3DTLVERTEX*)lpAddress; else { // See if TL buffer has sufficient space
if (size > lpDevI->TLVbuf.GetSize()) { if (lpDevI->TLVbuf.Grow(lpDevI, size) != D3D_OK) { D3D_ERR( "Could not grow TL vertex buffer" ); return DDERR_OUTOFMEMORY; } } pOut = (D3DTLVERTEX*)lpDevI->TLVbuf.GetAddress(); } // Map vertices
DWORD *pIn = (DWORD*)lpDevI->lpvOut; for (i=lpDevI->dwNumVertices; i; i--) { MapFVFtoTLVertex1(lpDevI, pOut, pIn); pOut++; pIn = (DWORD*)((char*)pIn + lpDevI->dwOutputSize); } return D3D_OK; } //---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CheckDrawPrimitive"
HRESULT CheckDrawPrimitive(LPDIRECT3DDEVICEI lpDevI) { D3DFE_PROCESSVERTICES* data = lpDevI; HRESULT ret = CheckDeviceSettings(lpDevI); if (ret != D3D_OK) return ret; if (!data->dwNumVertices) { D3D_ERR( "Invalid dwNumVertices in DrawPrimitive" ); return DDERR_INVALIDPARAMS; }
if(data->position.lpvData==NULL) { D3D_ERR( "Invalid lpvVertices param in DrawPrimitive" ); return DDERR_INVALIDPARAMS; }
switch (data->primType) { case D3DPT_POINTLIST: break; case D3DPT_LINELIST: if (data->dwNumVertices & 1) { D3D_ERR( "DrawPrimitive: bad vertex count" ); return DDERR_INVALIDPARAMS; } break; case D3DPT_LINESTRIP: if (data->dwNumVertices == 1) { D3D_ERR( "DrawPrimitive: bad vertex count" ); return DDERR_INVALIDPARAMS; } break; case D3DPT_TRIANGLEFAN: case D3DPT_TRIANGLESTRIP: if (data->dwNumVertices < 3) { D3D_ERR( "DrawPrimitive: bad vertex count" ); return DDERR_INVALIDPARAMS; } break; case D3DPT_TRIANGLELIST: if ( (data->dwNumVertices % 3) != 0 ) { D3D_ERR( "DrawPrimitive: bad vertex count" ); return DDERR_INVALIDPARAMS; } break; default: D3D_ERR( "Unknown or unsupported primitive type requested of DrawPrimitive" ); return D3DERR_INVALIDPRIMITIVETYPE; }
return D3D_OK; } //---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CheckDrawIndexedPrimitive"
HRESULT CheckDrawIndexedPrimitive(LPDIRECT3DDEVICEI lpDevI) { D3DFE_PROCESSVERTICES *data = lpDevI; DWORD i;
HRESULT ret = CheckDeviceSettings(lpDevI); if (ret != D3D_OK) return ret; if (data->dwNumVertices <= 0 || data->dwNumIndices <= 0) { D3D_ERR( "Invalid dwNumVertices or dwNumIndices in DrawIndexedPrimitive" ); return DDERR_INVALIDPARAMS; }
if (data->dwNumVertices > 65535ul ) { D3D_ERR( "DrawIndexedPrimitive vertex array > 64K" ); return DDERR_INVALIDPARAMS; }
if((data->lpwIndices==NULL) || IsBadReadPtr(data->lpwIndices,data->dwNumIndices*sizeof(WORD))) { D3D_ERR( "Invalid lpwIndices param in DrawIndexedPrimitive" ); return DDERR_INVALIDPARAMS; }
if(data->position.lpvData==NULL) { D3D_ERR( "Invalid lpvVertices param in DrawIndexedPrimitive" ); return DDERR_INVALIDPARAMS; }
switch (data->primType) { case D3DPT_LINELIST: if (data->dwNumIndices & 1) { D3D_ERR( "DrawIndexedPrimitive: bad index count" ); return DDERR_INVALIDPARAMS; } break; case D3DPT_LINESTRIP: if (data->dwNumIndices == 1) { D3D_ERR( "DrawIndexedPrimitive: bad index count" ); return DDERR_INVALIDPARAMS; } break; case D3DPT_TRIANGLEFAN: case D3DPT_TRIANGLESTRIP: if (data->dwNumIndices < 3) { D3D_ERR( "DrawIndexedPrimitive: bad index count" ); return DDERR_INVALIDPARAMS; } break; case D3DPT_TRIANGLELIST: if ( (data->dwNumIndices % 3) != 0 ) { D3D_ERR( "DrawIndexedPrimitive: bad index count" ); return DDERR_INVALIDPARAMS; } break; default: D3D_ERR( "Unknown or unsupported primitive type requested of DrawIndexedPrimitive" ); return D3DERR_INVALIDPRIMITIVETYPE; } for (i=0; i < data->dwNumIndices; i++) { if (data->lpwIndices[i] >= data->dwNumVertices) { D3D_ERR( "Invalid index value in DrawIndexedPrimitive" ); return DDERR_INVALIDPARAMS; } } return D3D_OK; } //---------------------------------------------------------------------
// Draws non-indexed primitives which do not require clipping
//
#undef DPF_MODNAME
#define DPF_MODNAME "DrawPrim"
#define __DRAWPRIMFUNC
#include "dpgen.h"
//---------------------------------------------------------------------
// Draws indexed primitives which do not require clipping
//
#undef DPF_MODNAME
#define DPF_MODNAME "DrawIndexedPrim"
#define __DRAWPRIMFUNC
#define __DRAWPRIMINDEX
#include "dpgen.h"
//---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "FlushStatesDP"
HRESULT CDirect3DDeviceIDP::FlushStates() { HRESULT dwRet=D3D_OK; FlushTextureFromDevice( this ); // delink all texture surfaces
if (this->dwDPOffset>sizeof(D3DHAL_DRAWPRIMCOUNTS)) { if ((dwRet=CheckSurfaces()) != D3D_OK) { this->dwDPOffset = sizeof(D3DHAL_DRAWPRIMCOUNTS); this->lpDPPrimCounts = (LPD3DHAL_DRAWPRIMCOUNTS)this->lpwDPBuffer; memset( (char *)this->lpwDPBuffer,0,sizeof(D3DHAL_DRAWPRIMCOUNTS)); //Clear header also
if (dwRet == DDERR_SURFACELOST) { this->dwFEFlags |= D3DFE_LOSTSURFACES; return D3D_OK; } return dwRet; }
D3DHAL_DRAWPRIMITIVESDATA dpData; DWORD dwDPOffset; if (this->lpDPPrimCounts->wNumVertices) //this->lpDPPrimCounts->wNumVertices==0 means the end
{ //force it if not
memset(((LPBYTE)this->lpwDPBuffer+this->dwDPOffset),0,sizeof(D3DHAL_DRAWPRIMCOUNTS)); } dpData.dwhContext = this->dwhContext; dpData.dwFlags = 0; dpData.lpvData = this->lpwDPBuffer; if (FVF_DRIVERSUPPORTED(this)) dpData.dwFVFControl = this->dwCurrentBatchVID; else { if (this->dwDebugFlags & D3DDEBUG_DISABLEFVF) dpData.dwFVFControl = D3DFVF_TLVERTEX; else dpData.dwFVFControl = 0; //always zero for non-FVF drivers
} dpData.ddrval = 0; dwDPOffset=this->dwDPOffset; //save it in case Flush returns prematurely
#if 0
if (D3DRENDERSTATE_TEXTUREHANDLE==*((DWORD*)this->lpwDPBuffer+2)) DPF(0,"Flushing dwDPOffset=%08lx ddihandle=%08lx",dwDPOffset,*((DWORD*)this->lpwDPBuffer+3)); #endif //0
//we clear this to break re-entering as SW rasterizer needs to lock DDRAWSURFACE
this->dwDPOffset = sizeof(D3DHAL_DRAWPRIMCOUNTS);
// Spin waiting on the driver if wait requested
#if _D3D_FORCEDOUBLE
CD3DForceFPUDouble ForceFPUDouble(this); #endif //_D3D_FORCEDOUBLE
do { #ifndef WIN95
if((dwRet = CheckContextSurface(this)) != D3D_OK) { this->dwDPOffset = dwDPOffset; return (dwRet); } #endif //WIN95
CALL_HAL2ONLY(dwRet, this, DrawPrimitives, &dpData); if (dwRet != DDHAL_DRIVER_HANDLED) { D3D_ERR ( "Driver call for DrawOnePrimitive failed" ); // Need sensible return value in this case,
// currently we return whatever the driver stuck in here.
} } while (dpData.ddrval == DDERR_WASSTILLDRAWING); this->lpDPPrimCounts = (LPD3DHAL_DRAWPRIMCOUNTS)this->lpwDPBuffer; memset( (char *)this->lpwDPBuffer,0,sizeof(D3DHAL_DRAWPRIMCOUNTS)); //Clear header also
dwRet= dpData.ddrval; this->dwCurrentBatchVID = this->dwVIDOut; } return dwRet; } //---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DoDrawPrimitive"
HRESULT DoDrawPrimitive(LPD3DFE_PROCESSVERTICES pv) { HRESULT ret;
if (!CheckIfNeedClipping(pv)) return pv->DrawPrim();
// Preserve primitive type for large begin-end primitives
// Primitive type could be changed by the clipper
D3DPRIMITIVETYPE oldPrimType = pv->primType; switch (pv->primType) { case D3DPT_POINTLIST: ret = ProcessClippedPoints(pv); break; case D3DPT_LINELIST: ret = ProcessClippedLine(pv); break; case D3DPT_LINESTRIP: ret = ProcessClippedLine(pv); break; case D3DPT_TRIANGLELIST: ret = ProcessClippedTriangleList(pv); break; case D3DPT_TRIANGLESTRIP: ret = ProcessClippedTriangleStrip(pv); break; case D3DPT_TRIANGLEFAN: ret = ProcessClippedTriangleFan(pv); break; default: ret = DDERR_GENERIC; break; } ClampExtents(pv); pv->primType = oldPrimType; return ret; } //---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DoDrawIndexedPrimitive"
HRESULT DoDrawIndexedPrimitive(LPD3DFE_PROCESSVERTICES pv) { HRESULT ret;
if (!CheckIfNeedClipping(pv)) return pv->DrawIndexPrim();
// Preserve primitive type for large begin-end primitives
// Primitive type could be changed by the clipper
D3DPRIMITIVETYPE oldPrimType = pv->primType; switch (pv->primType) { case D3DPT_LINELIST: ret = ProcessClippedIndexedLine(pv); break; case D3DPT_LINESTRIP: ret = ProcessClippedIndexedLine(pv); break; case D3DPT_TRIANGLELIST: ret = ProcessClippedIndexedTriangleList(pv); break; case D3DPT_TRIANGLEFAN: ret = ProcessClippedIndexedTriangleFan(pv); break; case D3DPT_TRIANGLESTRIP: ret = ProcessClippedIndexedTriangleStrip(pv); break; default: break; } ClampExtents(pv); pv->primType = oldPrimType; return ret; } //---------------------------------------------------------------------
// ProcessPrimitive processes indexed, non-indexed primitives or
// vertices only as defined by "op"
//
// op = __PROCPRIMOP_NONINDEXEDPRIM by default
//
HRESULT DIRECT3DDEVICEI::ProcessPrimitive(__PROCPRIMOP op) { HRESULT ret=D3D_OK; DWORD vertexPoolSize; // Update vertex stats
this->D3DStats.dwVerticesProcessed += this->dwNumVertices; DWORD dwCurrPrimVertices = this->dwNumVertices;
// Need to call UpdateTextures()
this->dwFEFlags |= D3DFE_NEED_TEXTURE_UPDATE;
// Viewport ID could be different from Device->v_id, because during Execute call
// Device->v_id is changed to whatever viewport is used as a parameter.
// So we have to make sure that we use the right viewport.
//
LPDIRECT3DVIEWPORTI lpView = this->lpCurrentViewport; if (this->v_id != lpView->v_id) { HRESULT ret = downloadView(lpView); if (ret != D3D_OK) return ret; }
// We need to grow TL vertex buffer if
// 1. We have to transform vertices
// 2. We do not have to transform vertices and
// 2.1 Ramp mode is used, because we have to change vertex colors
// 2.2 DP2HAL is used and we have small number of vertices, so we need to
// copy vertices into TL buffer
//
vertexPoolSize = this->dwNumVertices * this->dwOutputSize; if ((!FVF_TRANSFORMED(this->dwVIDIn)) || (this->dwDeviceFlags & D3DDEV_RAMP)) { if (vertexPoolSize > this->TLVbuf.GetSize()) { if (this->TLVbuf.Grow(this, vertexPoolSize) != D3D_OK) { D3D_ERR( "Could not grow TL vertex buffer" ); ret = DDERR_OUTOFMEMORY; return ret; } } if (IS_DP2HAL_DEVICE(this)) { CDirect3DDeviceIDP2 *dev = static_cast<CDirect3DDeviceIDP2*>(this); ret = dev->StartPrimVB(this->TLVbuf.GetVBI(), 0); if (ret != D3D_OK) return ret; } this->lpvOut = this->TLVbuf.GetAddress(); }
// Grow clip flags buffer if we need clipping
//
if (!(this->dwFlags & D3DDP_DONOTCLIP)) { DWORD size = this->dwNumVertices * sizeof(D3DFE_CLIPCODE); if (size > this->HVbuf.GetSize()) { if (this->HVbuf.Grow(size) != D3D_OK) { D3D_ERR( "Could not grow clip buffer" ); ret = DDERR_OUTOFMEMORY; return ret; } } this->lpClipFlags = (D3DFE_CLIPCODE*)this->HVbuf.GetAddress(); }
if (FVF_TRANSFORMED(this->dwVIDIn)) { if (this->dwDeviceFlags & D3DDEV_RAMP) { ConvertColorsToRamp(this, (D3DTLVERTEX*)this->position.lpvData, (D3DTLVERTEX*)(this->lpvOut), this->dwNumVertices); } else { // Pass vertices directly from the user memory
this->dwVIDOut = this->dwVIDIn; this->dwOutputSize = this->position.dwStride; this->lpvOut = this->position.lpvData; vertexPoolSize = this->dwNumVertices * this->dwOutputSize;
if (IS_DP2HAL_DEVICE(this)) { CDirect3DDeviceIDP2 *dev = static_cast<CDirect3DDeviceIDP2*>(this); dev->StartPrimUserMem(this->position.lpvData); if (ret != D3D_OK) return ret; } } if (this->dwFlags & D3DDP_DONOTCLIP) { if (!(this->dwFlags & D3DDP_DONOTUPDATEEXTENTS)) D3DFE_updateExtents(this);
if (op == __PROCPRIMOP_INDEXEDPRIM) { ret = this->DrawIndexPrim(); } else if (op == __PROCPRIMOP_NONINDEXEDPRIM) { ret = this->DrawPrim(); } goto l_exit; } else { // Clear clip union and intersection flags
this->dwClipIntersection = 0; this->dwClipUnion = 0; DWORD clip_intersect; clip_intersect = this->pGeometryFuncs->GenClipFlags(this); D3DFE_UpdateClipStatus(this); if (!clip_intersect) { this->dwFlags |= D3DPV_TLVCLIP; if (op == __PROCPRIMOP_INDEXEDPRIM) { ret = DoDrawIndexedPrimitive(this); } else if (op == __PROCPRIMOP_NONINDEXEDPRIM) { ret = DoDrawPrimitive(this); } goto l_exit; } } } else { // Clear clip union and intersection flags
this->dwClipIntersection = 0; this->dwClipUnion = 0;
// Update Lighting and related flags
if ((ret = DoUpdateState(this)) != D3D_OK) return ret;
// Call PSGP or our implementation
if (op == __PROCPRIMOP_INDEXEDPRIM) ret = this->pGeometryFuncs->ProcessIndexedPrimitive(this); else if (op == __PROCPRIMOP_NONINDEXEDPRIM) ret = this->pGeometryFuncs->ProcessPrimitive(this); else ret = this->pGeometryFuncs->ProcessVertices(this);
D3DFE_UpdateClipStatus(this); } l_exit: if (IS_DP2HAL_DEVICE(this)) { CDirect3DDeviceIDP2 *dev = static_cast<CDirect3DDeviceIDP2*>(this); if (op != __PROCPRIMOP_PROCVERONLY) ret = dev->EndPrim(vertexPoolSize); } return ret; } //---------------------------------------------------------------------
// This function is called when a number of indices in an indexed primitive
// is much less than a number of vertices. In this case we build non-indexed
// primitives.
HRESULT DereferenceIndexedPrim(LPDIRECT3DDEVICEI lpDevI) { HRESULT ret = CheckVertexBatch(lpDevI); if (ret != D3D_OK) return ret;
// Save original vertice and number of primitives
D3DVERTEX *lpvVertices = (D3DVERTEX*)lpDevI->position.lpvData; DWORD dwNumPrimitivesOrg = lpDevI->dwNumPrimitives; WORD *lpwIndices = lpDevI->lpwIndices; // We will dereference here
D3DVERTEX *lpVertex = (D3DVERTEX*)lpDevI->lpvVertexBatch; lpDevI->position.lpvData = lpVertex; lpDevI->lpwIndices = NULL;
switch (lpDevI->primType) { case D3DPT_LINELIST: { for (DWORD j=0; j < dwNumPrimitivesOrg; j += BEGIN_DATA_BLOCK_SIZE/2) { lpDevI->dwNumPrimitives = min(dwNumPrimitivesOrg - j, (BEGIN_DATA_BLOCK_SIZE/2)); lpDevI->dwNumVertices = lpDevI->dwNumPrimitives << 1; D3DVERTEX *lpTmp = lpVertex; for (DWORD i=lpDevI->dwNumVertices; i; i--) { *lpTmp++ = lpvVertices[*lpwIndices++]; } ret = lpDevI->ProcessPrimitive(); if (ret != D3D_OK) return ret; } break; } case D3DPT_LINESTRIP: { for (DWORD j=0; j < dwNumPrimitivesOrg; j+= BEGIN_DATA_BLOCK_SIZE-1) { lpDevI->dwNumPrimitives = min(dwNumPrimitivesOrg-j, (BEGIN_DATA_BLOCK_SIZE-1)); lpDevI->dwNumVertices = lpDevI->dwNumPrimitives + 1; D3DVERTEX *lpTmp = lpVertex; for (DWORD i=lpDevI->dwNumVertices; i; i--) { *lpTmp++ = lpvVertices[*lpwIndices++]; } lpwIndices--; // back off one so the next batch is connected
ret = lpDevI->ProcessPrimitive(); if (ret != D3D_OK) return ret; } break; } case D3DPT_TRIANGLEFAN: { lpVertex[0] = lpvVertices[*lpwIndices++]; for (DWORD j=0; j < dwNumPrimitivesOrg; j+= BEGIN_DATA_BLOCK_SIZE-2) { lpDevI->dwNumPrimitives = min(dwNumPrimitivesOrg - j, (BEGIN_DATA_BLOCK_SIZE-2)); lpDevI->dwNumVertices = lpDevI->dwNumPrimitives + 2; D3DVERTEX *lpTmp = &lpVertex[1]; for (DWORD i=lpDevI->dwNumVertices-1; i; i--) { *lpTmp++ = lpvVertices[*lpwIndices++]; } lpwIndices--; // back off one so the next batch is connected
ret = lpDevI->ProcessPrimitive(); if (ret != D3D_OK) return ret; } break; } case D3DPT_TRIANGLESTRIP: { for (DWORD j=0; j < dwNumPrimitivesOrg; j+= BEGIN_DATA_BLOCK_SIZE-2) { lpDevI->dwNumPrimitives = min(dwNumPrimitivesOrg-j, (BEGIN_DATA_BLOCK_SIZE-2)); lpDevI->dwNumVertices = lpDevI->dwNumPrimitives + 2; D3DVERTEX *lpTmp = lpVertex; for (DWORD i=lpDevI->dwNumVertices; i; i--) { *lpTmp++ = lpvVertices[*lpwIndices++]; } lpwIndices-= 2; // back off so the next batch is connected
ret = lpDevI->ProcessPrimitive(); if (ret != D3D_OK) return ret; } break; } case D3DPT_TRIANGLELIST: { for (DWORD j=0; j < dwNumPrimitivesOrg; j+= BEGIN_DATA_BLOCK_SIZE/3) { lpDevI->dwNumPrimitives = min(dwNumPrimitivesOrg-j, (BEGIN_DATA_BLOCK_SIZE/3)); lpDevI->dwNumVertices = lpDevI->dwNumPrimitives * 3; D3DVERTEX *lpTmp = lpVertex; for (DWORD i=lpDevI->dwNumVertices; i; i--) { *lpTmp++ = lpvVertices[*lpwIndices++]; } ret = lpDevI->ProcessPrimitive(); if (ret != D3D_OK) return ret; } break; } } return D3D_OK; } //---------------------------------------------------------------------
// API calls
//---------------------------------------------------------------------
//---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DrawPrimitiveStrided"
HRESULT D3DAPI DIRECT3DDEVICEI::DrawPrimitiveStrided( D3DPRIMITIVETYPE PrimitiveType, DWORD dwVertexType, LPD3DDRAWPRIMITIVESTRIDEDDATA lpDrawData, DWORD dwNumVertices, DWORD dwFlags) { HRESULT ret = D3D_OK;
CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock.
#if DBG
if (ValidateFVF(dwVertexType) != D3D_OK || !IsDPFlagsValid(dwFlags)) return DDERR_INVALIDPARAMS; Profile(PROF_DRAWPRIMITIVESTRIDED,PrimitiveType,dwVertexType); #endif
//note: this check should be done in retail as well as dbg build
if((dwVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) return D3DERR_INVALIDVERTEXTYPE; this->primType = PrimitiveType; this->dwVIDIn = dwVertexType; this->position = lpDrawData->position; this->normal = lpDrawData->normal; this->diffuse = lpDrawData->diffuse; this->specular = lpDrawData->specular; ComputeOutputFVF(this); for (DWORD i=0; i < this->nTexCoord; i++) this->textures[i] = lpDrawData->textureCoords[i]; this->dwNumVertices = dwNumVertices; this->lpwIndices = NULL; this->dwNumIndices = 0; this->lpClipFlags = (D3DFE_CLIPCODE*)HVbuf.GetAddress(); this->dwFlags = dwFlags | D3DPV_STRIDE; if (this->dwVIDIn & D3DFVF_NORMAL) this->dwFlags |= D3DPV_LIGHTING;
GetNumPrim(this, dwNumVertices); // Calculate dwNumPrimitives and update stats
#if DBG
if (this->dwNumVertices > MAX_DX6_VERTICES) { D3D_ERR("D3D for DX6 cannot handle greater than 64K vertices"); return D3DERR_TOOMANYVERTICES; } ret = CheckDrawPrimitive(this);
if (ret != D3D_OK) { return ret; } #endif
return this->ProcessPrimitive(); } // end of DrawPrimitiveStrided()
//---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DrawIndexedPrimitiveStrided"
HRESULT D3DAPI DIRECT3DDEVICEI::DrawIndexedPrimitiveStrided( D3DPRIMITIVETYPE PrimitiveType, DWORD dwVertexType, LPD3DDRAWPRIMITIVESTRIDEDDATA lpDrawData, DWORD dwNumVertices, LPWORD lpwIndices, DWORD dwNumIndices, DWORD dwFlags) { HRESULT ret = D3D_OK;
CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock.
#if DBG
if (ValidateFVF(dwVertexType) != D3D_OK || !IsDPFlagsValid(dwFlags)) return DDERR_INVALIDPARAMS; Profile(PROF_DRAWINDEXEDPRIMITIVESTRIDED,PrimitiveType,dwVertexType); #endif
//note: this check should be done in retail as well as dbg build
if((dwVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) return D3DERR_INVALIDVERTEXTYPE; this->primType = PrimitiveType; this->dwVIDIn = dwVertexType; this->position = lpDrawData->position; this->normal = lpDrawData->normal; this->diffuse = lpDrawData->diffuse; this->specular = lpDrawData->specular; ComputeOutputFVF(this); for (DWORD i=0; i < this->nTexCoord; i++) this->textures[i] = lpDrawData->textureCoords[i]; this->dwNumVertices = dwNumVertices; this->lpwIndices = lpwIndices; this->dwNumIndices = dwNumIndices; this->lpClipFlags = (D3DFE_CLIPCODE*)HVbuf.GetAddress(); this->dwFlags = dwFlags | D3DPV_STRIDE; if (this->dwVIDIn & D3DFVF_NORMAL) this->dwFlags |= D3DPV_LIGHTING; GetNumPrim(this, dwNumIndices); // Calculate dwNumPrimitives and update stats
#if DBG
if (this->dwNumPrimitives > MAX_DX6_PRIMCOUNT) { D3D_ERR("D3D for DX6 cannot handle greater than 64K sized primitives"); return D3DERR_TOOMANYPRIMITIVES; } ret = CheckDrawIndexedPrimitive(this); if (ret != D3D_OK) { return ret; } if (this->dwNumIndices * INDEX_BATCH_SCALE < this->dwNumVertices && !FVF_TRANSFORMED(this->dwVIDIn)) { D3D_WARN(1, "The number of indices is much less than the number of vertices."); D3D_WARN(1, "This will likely be inefficient. Consider using vertex buffers."); } #endif
return this->ProcessPrimitive(__PROCPRIMOP_INDEXEDPRIM); } // end of DrawIndexedPrimitiveStrided()
//---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DrawPrimitive3"
HRESULT D3DAPI DIRECT3DDEVICEI::DrawPrimitive(D3DPRIMITIVETYPE PrimitiveType, DWORD dwVertexType, LPVOID lpvVertices, DWORD dwNumVertices, DWORD dwFlags) { HRESULT ret = D3D_OK;
CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock.
#if DBG
if (ValidateFVF(dwVertexType) != D3D_OK || !IsDPFlagsValid(dwFlags)) return DDERR_INVALIDPARAMS; Profile(PROF_DRAWPRIMITIVEDEVICE3,PrimitiveType,dwVertexType); #endif
/* This stuff does not change from call to call */ this->lpwIndices = NULL; this->dwNumIndices = 0; this->lpClipFlags = (D3DFE_CLIPCODE*)HVbuf.GetAddress(); /* This stuff is mandatory for the call */ this->primType = PrimitiveType; this->dwVIDIn = dwVertexType; this->position.lpvData = lpvVertices; this->dwNumVertices = dwNumVertices; this->dwFlags = dwFlags; /* This stuff depends upon the vertex type */ this->position.dwStride = GetVertexSizeFVF(this->dwVIDIn); if (this->dwVIDIn & D3DFVF_NORMAL) this->dwFlags |= D3DPV_LIGHTING; ComputeOutputFVF(this); GetNumPrim(this, dwNumVertices); // Calculate dwNumPrimitives and update stats
#if DBG
if (this->dwNumVertices > MAX_DX6_VERTICES) { D3D_ERR("D3D for DX6 cannot handle greater than 64K vertices"); return D3DERR_TOOMANYVERTICES; } ret = CheckDrawPrimitive(this); if (ret != D3D_OK) { return ret; } #endif
return this->ProcessPrimitive(); } //---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "Direct3DDevice::DrawIndexedPrimitive"
HRESULT D3DAPI DIRECT3DDEVICEI::DrawIndexedPrimitive(D3DPRIMITIVETYPE PrimitiveType, DWORD dwVertexType, LPVOID lpvVertices, DWORD dwNumVertices, LPWORD lpwIndices, DWORD dwNumIndices, DWORD dwFlags) { HRESULT ret = D3D_OK;
CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock.
#if DBG
if (ValidateFVF(dwVertexType) != D3D_OK || !IsDPFlagsValid(dwFlags)) return DDERR_INVALIDPARAMS; Profile(PROF_DRAWINDEXEDPRIMITIVEDEVICE3,PrimitiveType,dwVertexType); #endif
// Static part
this->lpClipFlags = (D3DFE_CLIPCODE*)HVbuf.GetAddress(); // Mandatory part
this->primType = PrimitiveType; this->dwVIDIn = dwVertexType; this->dwNumVertices = dwNumVertices; this->lpwIndices = lpwIndices; this->dwNumIndices = dwNumIndices; this->dwFlags = dwFlags; this->position.lpvData = lpvVertices; // Stuff that depends upon dwVIDIn
this->position.dwStride = GetVertexSizeFVF(this->dwVIDIn); if (this->dwVIDIn & D3DFVF_NORMAL) this->dwFlags |= D3DPV_LIGHTING; ComputeOutputFVF(this); GetNumPrim(this, dwNumIndices); // Calculate dwNumPrimitives and update stats
#if DBG
if (this->dwNumPrimitives > MAX_DX6_PRIMCOUNT) { D3D_ERR("D3D for DX6 cannot handle greater than 64K sized primitives"); return D3DERR_TOOMANYPRIMITIVES; } ret = CheckDrawIndexedPrimitive(this); if (ret != D3D_OK) { return ret; } if (this->dwNumIndices * INDEX_BATCH_SCALE < this->dwNumVertices && !FVF_TRANSFORMED(this->dwVIDIn)) { D3D_WARN(1, "The number of indices is much less than the number of vertices."); D3D_WARN(1, "This will likely be inefficient. Consider using vertex buffers."); } #endif
return this->ProcessPrimitive(__PROCPRIMOP_INDEXEDPRIM); } //---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DrawPrimitive"
HRESULT D3DAPI DIRECT3DDEVICEI::DrawPrimitive(D3DPRIMITIVETYPE PrimitiveType, D3DVERTEXTYPE VertexType, LPVOID lpvVertices, DWORD dwNumVertices, DWORD dwFlags) { HRESULT ret = D3D_OK;
CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock.
#if DBG
if (!IsDPFlagsValid(dwFlags)) return DDERR_INVALIDPARAMS;
if((VertexType<=0) || (VertexType>D3DVT_TLVERTEX)) { D3D_ERR("Invalid VertexType"); return D3DERR_INVALIDVERTEXTYPE; } Profile(PROF_DRAWPRIMITIVEDEVICE2,PrimitiveType,VertexType); #endif
/* Static assignments */ this->position.dwStride = sizeof(D3DVERTEX); this->lpwIndices = NULL; this->dwNumIndices = 0; this->lpClipFlags = (D3DFE_CLIPCODE*)HVbuf.GetAddress(); this->nTexCoord = 1; /* Necessary work */ this->primType = PrimitiveType; this->dwNumVertices = dwNumVertices; this->dwFlags = dwFlags; this->position.lpvData = lpvVertices; this->dwVIDIn = d3dVertexToFVF[VertexType]; DWORD dwVertexSize = sizeof(D3DVERTEX); ComputeOutputFVF(this); if (this->dwVIDIn & D3DFVF_NORMAL) this->dwFlags |= D3DPV_LIGHTING;
// AnanKan (6/22/98)
// !! This is a hack for the crippled DP2 driver model which cannot accept
// !! more that 64K vertices. In DX6 interfaces we fail rendering if we
// !! encounter such large primitives for all DDI.
// !! In the legacy (DX5) interfaces,
// !! If the primitive size is greater than MAX_DX6_PRIMCOUNT and
// !! the DDI cannot handle it, then we to break up the primitive into
// !! manageable chunks.
if ((this->dwNumVertices > MAX_DX6_VERTICES) && (IS_DP2HAL_DEVICE(this))) { DWORD dwOrigNumVerts = this->dwNumVertices; WORD wChunkSize = MAX_DX6_VERTICES - 3; // Even and a multiple of 3
BYTE TmpVertex[32], FirstVertex[32]; DWORD dwStepPerChunk;
switch(this->primType) { case D3DPT_POINTLIST: case D3DPT_LINELIST: case D3DPT_TRIANGLELIST: dwStepPerChunk = dwVertexSize*wChunkSize; break; case D3DPT_LINESTRIP: dwStepPerChunk = dwVertexSize*(wChunkSize - 1); break; case D3DPT_TRIANGLEFAN: // Save the first index
memcpy(FirstVertex, this->position.lpvData, dwVertexSize); // Fall through
case D3DPT_TRIANGLESTRIP: dwStepPerChunk = dwVertexSize*(wChunkSize - 2); break; }
int numChunks = (int)(dwOrigNumVerts/(DWORD)wChunkSize); WORD wRemainingVerts = (WORD)(dwOrigNumVerts - wChunkSize*numChunks); this->dwNumVertices = wChunkSize; // Calculate dwNumPrimitives and update stats
GetNumPrim(this, this->dwNumVertices);
// 0th iteration
#if DBG
ret = CheckDrawPrimitive(this); if (ret != D3D_OK) { return ret; } #endif
ret = this->ProcessPrimitive(); if (ret != D3D_OK) { return ret; }
for (int i=1; i<numChunks; i++) { this->position.lpvData = (LPVOID)((LPBYTE)this->position.lpvData + dwStepPerChunk); if (this->primType == D3DPT_TRIANGLEFAN) { // Save the vertex
memcpy(TmpVertex, this->position.lpvData, dwVertexSize); // Copy in the first vertex
memcpy(this->position.lpvData, FirstVertex, dwVertexSize); }
#if DBG
ret = CheckDrawPrimitive(this); if (ret != D3D_OK) { return ret; } #endif
ret = this->ProcessPrimitive();
// Write back the proper vertex in case something has been
// switched
if(this->primType == D3DPT_TRIANGLEFAN) memcpy(this->position.lpvData, TmpVertex, dwVertexSize);
if (ret != D3D_OK) { return ret; } }
// The last time around
if (wRemainingVerts) { this->dwNumVertices = wRemainingVerts; // Calculate dwNumPrimitives and update stats
GetNumPrim(this, this->dwNumVertices); this->position.lpvData = (LPVOID)((LPBYTE)this->position.lpvData + dwStepPerChunk); if (this->primType == D3DPT_TRIANGLEFAN) { memcpy(TmpVertex, this->position.lpvData, dwVertexSize); memcpy(this->position.lpvData, FirstVertex, dwVertexSize); } #if DBG
ret = CheckDrawPrimitive(this); if (ret != D3D_OK) { return ret; } #endif
ret = this->ProcessPrimitive();
// Write back the proper vertex in case something has been
// switched
if(this->primType == D3DPT_TRIANGLEFAN) memcpy(this->position.lpvData, TmpVertex, dwVertexSize);
if (ret != D3D_OK) { return ret; } } } else { // Calculate dwNumPrimitives and update stats
GetNumPrim(this, dwNumVertices); #if DBG
ret = CheckDrawPrimitive(this); if (ret != D3D_OK) { return ret; } #endif
return this->ProcessPrimitive(); }
return D3D_OK; } //---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DrawIndexedPrimitive"
HRESULT D3DAPI DIRECT3DDEVICEI::DrawIndexedPrimitive(D3DPRIMITIVETYPE PrimitiveType, D3DVERTEXTYPE VertexType, LPVOID lpvVertices, DWORD dwNumVertices, LPWORD lpwIndices, DWORD dwNumIndices, DWORD dwFlags) { HRESULT ret = D3D_OK;
CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock.
#if DBG
if (!IsDPFlagsValid(dwFlags)) return DDERR_INVALIDPARAMS; Profile(PROF_DRAWINDEXEDPRIMITIVEDEVICE2,PrimitiveType,VertexType); #endif
this->primType = PrimitiveType; this->dwVIDIn = d3dVertexToFVF[VertexType]; this->position.dwStride = sizeof(D3DVERTEX); this->dwNumVertices = dwNumVertices; this->lpwIndices = lpwIndices; this->dwNumIndices = dwNumIndices; this->lpClipFlags = (D3DFE_CLIPCODE*)HVbuf.GetAddress(); this->dwFlags = dwFlags; this->position.lpvData = lpvVertices; this->nTexCoord = 1; ComputeOutputFVF(this); if (this->dwVIDIn & D3DFVF_NORMAL) this->dwFlags |= D3DPV_LIGHTING; GetNumPrim(this, dwNumIndices); // Calculate dwNumPrimitives and update stats
// AnanKan (6/22/98)
// !! This is a hack for the crippled DP2 driver model which cannot accept
// !! more that 64K primitives (primcount is a WORD). In DX6 interfaces
// !! we fail rendering if we encounter such large primitives.
// !! We do this for all DDI.
// !! In the legacy (DX5) interfaces,
// !! If the primitive size is greater than MAX_DX6_PRIMCOUNT and
// !! the DDI cannot handle it, then we to break up the primitive into
// !! manageable chunks.
if ((this->dwNumPrimitives > MAX_DX6_PRIMCOUNT) && (IS_DP2HAL_DEVICE(this))) { WORD wFirstIndex, wTmpIndex; WORD wChunkSize = MAX_DX6_PRIMCOUNT; int numPrimChunks; DWORD dwResidualPrim; DWORD dwResidualIndices; DWORD dwStepPerChunk; DWORD dwOrigNumPrim = this->dwNumPrimitives; this->dwNumPrimitives = wChunkSize; numPrimChunks = (int)(dwOrigNumPrim/(DWORD)wChunkSize); dwResidualPrim = dwOrigNumPrim - wChunkSize*numPrimChunks;
switch(this->primType) { case D3DPT_POINTLIST: this->dwNumIndices = this->dwNumPrimitives; dwStepPerChunk = this->dwNumIndices; dwResidualIndices = dwResidualPrim; break; case D3DPT_LINELIST: this->dwNumIndices = this->dwNumPrimitives<<1; dwStepPerChunk = this->dwNumIndices; dwResidualIndices = dwResidualPrim << 1; break; case D3DPT_LINESTRIP: this->dwNumIndices = this->dwNumPrimitives + 1; dwStepPerChunk = this->dwNumIndices - 1; dwResidualIndices = dwResidualPrim + 1; break; case D3DPT_TRIANGLEFAN: this->dwNumIndices = this->dwNumPrimitives + 2; dwStepPerChunk = this->dwNumIndices - 2; dwResidualIndices = dwResidualPrim + 2; // Save the first index
wTmpIndex = wFirstIndex = this->lpwIndices[0]; break; case D3DPT_TRIANGLESTRIP: wChunkSize = (MAX_DX6_PRIMCOUNT-1); this->dwNumPrimitives = wChunkSize; this->dwNumIndices = this->dwNumPrimitives + 2; dwStepPerChunk = this->dwNumIndices - 2; numPrimChunks = (int)(dwOrigNumPrim/(DWORD)wChunkSize); dwResidualPrim = dwOrigNumPrim - wChunkSize*numPrimChunks; dwResidualIndices = dwResidualPrim + 2; break; case D3DPT_TRIANGLELIST: this->dwNumIndices = this->dwNumPrimitives * 3; dwStepPerChunk = this->dwNumIndices; dwResidualIndices = dwResidualPrim * 3; break; }
// 0th iteration
#if DBG
ret = CheckDrawIndexedPrimitive(this); if (ret != D3D_OK) { return ret; } #endif
ret = this->ProcessPrimitive(__PROCPRIMOP_INDEXEDPRIM); if (ret != D3D_OK) { return ret; }
// Remaining chunks
for (int i=1; i<numPrimChunks; i++) { this->lpwIndices += dwStepPerChunk;
if (this->primType == D3DPT_TRIANGLEFAN) { // Save the index
wTmpIndex = this->lpwIndices[0]; // Copy in the first vertex
this->lpwIndices[0] = wFirstIndex; }
#if DBG
ret = CheckDrawIndexedPrimitive(this); if (ret != D3D_OK) { return ret; } #endif
ret = this->ProcessPrimitive(__PROCPRIMOP_INDEXEDPRIM);
// Write back the proper index in case something has been
// switched
if(this->primType == D3DPT_TRIANGLEFAN) this->lpwIndices[0] = wTmpIndex;
if (ret != D3D_OK) { return ret; } }
// The last time around
if (dwResidualPrim) { this->dwNumPrimitives = dwResidualPrim; this->dwNumIndices = dwResidualIndices; this->lpwIndices += dwStepPerChunk; if (this->primType == D3DPT_TRIANGLEFAN) { wTmpIndex = this->lpwIndices[0]; this->lpwIndices[0] = wFirstIndex; } #if DBG
ret = CheckDrawIndexedPrimitive(this); if (ret != D3D_OK) { return ret; } #endif
ret = this->ProcessPrimitive(__PROCPRIMOP_INDEXEDPRIM); // Write back the proper index in case something has been
// switched
if(this->primType == D3DPT_TRIANGLEFAN) this->lpwIndices[0] = wTmpIndex; if (ret != D3D_OK) { return ret; } } } else {
#if DBG
ret = CheckDrawIndexedPrimitive(this); if (ret != D3D_OK) { return ret; } #endif
// For an untransformed primitive, if a number of indices is much less
// than number of vertices we rebuild the primitive to reduce number
// of vertices to process.
if (this->dwNumIndices * INDEX_BATCH_SCALE < this->dwNumVertices && !FVF_TRANSFORMED(this->dwVIDIn)) return DereferenceIndexedPrim(this); else return this->ProcessPrimitive(__PROCPRIMOP_INDEXEDPRIM); } return D3D_OK; } //---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDeviceIDP::SetRenderStateI"
HRESULT D3DAPI CDirect3DDeviceIDP::SetRenderStateI(D3DRENDERSTATETYPE dwStateType, DWORD value) { LPD3DHAL_DRAWPRIMCOUNTS lpPC; LPDWORD lpStateChange; HRESULT ret; if (dwStateType > D3DRENDERSTATE_STIPPLEPATTERN31) { D3D_WARN(4,"Trying to send invalid state %d to legacy driver",dwStateType); return D3D_OK; } if (dwStateType > D3DRENDERSTATE_FLUSHBATCH && dwStateType < D3DRENDERSTATE_STIPPLEPATTERN00) { D3D_WARN(4,"Trying to send invalid state %d to legacy driver",dwStateType); return D3D_OK; }
if (D3DRENDERSTATE_FLUSHBATCH == dwStateType) { CLockD3DST lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock (ST only).
ret = FlushStates(); if (ret != D3D_OK) { D3D_ERR("Error trying to render batched commands in SetRenderStateI"); } return ret; }
lpPC = this->lpDPPrimCounts; if (lpPC->wNumVertices) //Do we already have Vertices filled in for this count ?
{ //Yes, then Increment count
lpPC=this->lpDPPrimCounts=(LPD3DHAL_DRAWPRIMCOUNTS)((LPBYTE)this->lpwDPBuffer+this->dwDPOffset); memset( (char *)lpPC,0,sizeof(D3DHAL_DRAWPRIMCOUNTS)); this->dwDPOffset += sizeof(D3DHAL_DRAWPRIMCOUNTS); } if (this->dwDPOffset + 2*sizeof(DWORD) > this->dwDPMaxOffset ) { CLockD3DST lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock (ST only).
ret = FlushStates(); if (ret != D3D_OK) { D3D_ERR("Error trying to render batched commands in SetRenderStateI"); return ret; } } lpStateChange=(LPDWORD)((char *)this->lpwDPBuffer + this->dwDPOffset); *lpStateChange=dwStateType; lpStateChange ++; *lpStateChange=value; this->lpDPPrimCounts->wNumStateChanges ++; this->dwDPOffset += 2*sizeof(DWORD); #if 0
if (dwStateType == D3DRENDERSTATE_TEXTUREHANDLE && this->dwDPOffset== 0x10){ DPF(0,"SRdwDPOffset=%08lx, dwStateType=%08lx value=%08lx ddihandle=%08lx lpStateChange=%08lx lpDPPrimCounts=%08lx", this->dwDPOffset,dwStateType,value,*lpStateChange,lpStateChange,this->lpDPPrimCounts); _asm int 3 } #endif //0
return D3D_OK; } //---------------------------------------------------------------------
DWORD visResults[6][2] = { D3DVIS_INTERSECT_LEFT , D3DVIS_OUTSIDE_LEFT , D3DVIS_INTERSECT_RIGHT , D3DVIS_OUTSIDE_RIGHT , D3DVIS_INTERSECT_TOP , D3DVIS_OUTSIDE_TOP , D3DVIS_INTERSECT_BOTTOM , D3DVIS_OUTSIDE_BOTTOM , D3DVIS_INTERSECT_NEAR , D3DVIS_OUTSIDE_NEAR , D3DVIS_INTERSECT_FAR , D3DVIS_OUTSIDE_FAR }; //---------------------------------------------------------------------
DWORD CheckSphere(LPDIRECT3DDEVICEI lpDevI, LPD3DVECTOR center, D3DVALUE radius) { DWORD result = 0; for (int i=0; i < 6; i++) { // Compute a distance from the center to the plane
D3DVALUE d = lpDevI->transform.frustum[i].x*center->x + lpDevI->transform.frustum[i].y*center->y + lpDevI->transform.frustum[i].z*center->z + lpDevI->transform.frustum[i].w; if (d + radius < 0) result |= visResults[i][1]; // Outside
else if (d - radius < 0.5f) // 0.5 is chosen to offset precision errors
result |= visResults[i][0]; // Intersect
} if (result & (D3DVIS_OUTSIDE_LEFT | D3DVIS_OUTSIDE_RIGHT | D3DVIS_OUTSIDE_TOP | D3DVIS_OUTSIDE_BOTTOM | D3DVIS_OUTSIDE_NEAR | D3DVIS_OUTSIDE_FAR)) { result |= D3DVIS_OUTSIDE_FRUSTUM; } else if (result) result |= D3DVIS_INTERSECT_FRUSTUM;
return result; } //---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DIRECT3DDEVICEI::ComputeSphereVisibility"
HRESULT D3DAPI DIRECT3DDEVICEI::ComputeSphereVisibility(LPD3DVECTOR lpCenters, LPD3DVALUE lpRadii, DWORD dwNumSpheres, DWORD dwFlags, LPDWORD lpdwReturnValues) { CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock.
#if DBG
TRY { if (dwFlags != 0 || dwNumSpheres == 0 || IsBadWritePtr(lpdwReturnValues, dwNumSpheres * sizeof(DWORD)) || IsBadWritePtr(lpRadii, dwNumSpheres * sizeof(D3DVALUE)) || IsBadWritePtr(lpCenters, dwNumSpheres * sizeof(LPD3DVECTOR))) { return DDERR_INVALIDPARAMS; } } EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { D3D_ERR( "Exception encountered validating parameters" ); return DDERR_INVALIDPARAMS; } #endif
this->dwFlags = 0; if (dwFEFlags & D3DFE_TRANSFORM_DIRTY) { updateTransform(this); } if (this->dwFEFlags & D3DFE_FRUSTUMPLANES_DIRTY) { this->dwFlags |= D3DPV_FRUSTUMPLANES_DIRTY; this->dwFEFlags &= ~D3DFE_FRUSTUMPLANES_DIRTY; }
return this->pGeometryFuncs->ComputeSphereVisibility(this, lpCenters, lpRadii, dwNumSpheres, dwFlags, lpdwReturnValues); } //---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "ID3DFE_PVFUNCS::ComputeSphereVisibility"
HRESULT D3DFE_PVFUNCS::ComputeSphereVisibility(LPD3DFE_PROCESSVERTICES pv, LPD3DVECTOR lpCenters, LPD3DVALUE lpRadii, DWORD dwNumSpheres, DWORD dwFlags, LPDWORD lpdwReturnValues) { LPDIRECT3DDEVICEI lpDevI = static_cast<LPDIRECT3DDEVICEI>(pv); HRESULT ret = D3DERR_INVALIDMATRIX;
#define transform lpDevI->transform
if (pv->dwFlags & D3DPV_FRUSTUMPLANES_DIRTY) { transform.dwFlags &= ~D3DTRANS_VALIDFRUSTUM; if (Inverse4x4((D3DMATRIX*)&lpDevI->mCTM, (D3DMATRIX*)&transform.mCTMI)) { D3D_ERR("Cannot invert current (World X View) matrix."); return ret; } // Transform the following clipping volume points to the model space by
// multiplying by inverse CTM
//
// v1 = { 0, 0, 0, 1};
// v2 = { 1, 0, 0, 1};
// v3 = { 1, 1, 0, 1};
// v4 = { 0, 1, 0, 1};
// v5 = { 0, 0, 1, 1};
// v6 = { 1, 0, 1, 1};
// v7 = { 0, 1, 1, 1};
//
// We do it manually to speed up
//
D3DVECTORH v1 = {transform.mCTMI._41, transform.mCTMI._42, transform.mCTMI._43, transform.mCTMI._44}; D3DVECTORH v2 = {transform.mCTMI._11 + transform.mCTMI._41, transform.mCTMI._12 + transform.mCTMI._42, transform.mCTMI._13 + transform.mCTMI._43, transform.mCTMI._14 + transform.mCTMI._44}; D3DVECTORH v3 = {transform.mCTMI._11 + transform.mCTMI._21 + transform.mCTMI._41, transform.mCTMI._12 + transform.mCTMI._22 + transform.mCTMI._42, transform.mCTMI._13 + transform.mCTMI._23 + transform.mCTMI._43, transform.mCTMI._14 + transform.mCTMI._24 + transform.mCTMI._44}; D3DVECTORH v4 = {transform.mCTMI._21 + transform.mCTMI._41, transform.mCTMI._22 + transform.mCTMI._42, transform.mCTMI._23 + transform.mCTMI._43, transform.mCTMI._24 + transform.mCTMI._44}; D3DVECTORH v5 = {transform.mCTMI._31 + transform.mCTMI._41, transform.mCTMI._32 + transform.mCTMI._42, transform.mCTMI._33 + transform.mCTMI._43, transform.mCTMI._34 + transform.mCTMI._44}; D3DVECTORH v6 = {transform.mCTMI._11 + transform.mCTMI._31 + transform.mCTMI._41, transform.mCTMI._12 + transform.mCTMI._32 + transform.mCTMI._42, transform.mCTMI._13 + transform.mCTMI._33 + transform.mCTMI._43, transform.mCTMI._14 + transform.mCTMI._34 + transform.mCTMI._44}; D3DVECTORH v7 = {transform.mCTMI._21 + transform.mCTMI._31 + transform.mCTMI._41, transform.mCTMI._22 + transform.mCTMI._32 + transform.mCTMI._42, transform.mCTMI._23 + transform.mCTMI._33 + transform.mCTMI._43, transform.mCTMI._24 + transform.mCTMI._34 + transform.mCTMI._44};
// Convert vectors from homogeneous to 3D
if (Vector4to3D(&v1)) goto exit; if (Vector4to3D(&v2)) goto exit; if (Vector4to3D(&v3)) goto exit; if (Vector4to3D(&v4)) goto exit; if (Vector4to3D(&v5)) goto exit; if (Vector4to3D(&v6)) goto exit; if (Vector4to3D(&v7)) goto exit; // Build frustum planes
// Left
if (MakePlane((D3DVECTOR*)&v1, (D3DVECTOR*)&v4, (D3DVECTOR*)&v5, &transform.frustum[0])) goto exit; // Right
if (MakePlane((D3DVECTOR*)&v2, (D3DVECTOR*)&v6, (D3DVECTOR*)&v3, &transform.frustum[1])) goto exit; // Top
if (MakePlane((D3DVECTOR*)&v4, (D3DVECTOR*)&v3, (D3DVECTOR*)&v7, &transform.frustum[2])) goto exit; // Bottom
if (MakePlane((D3DVECTOR*)&v1, (D3DVECTOR*)&v5, (D3DVECTOR*)&v2, &transform.frustum[3])) goto exit; // Near
if (MakePlane((D3DVECTOR*)&v1, (D3DVECTOR*)&v2, (D3DVECTOR*)&v3, &transform.frustum[4])) goto exit; // Far
if (MakePlane((D3DVECTOR*)&v6, (D3DVECTOR*)&v5, (D3DVECTOR*)&v7, &transform.frustum[5])) goto exit;
transform.dwFlags |= D3DTRANS_VALIDFRUSTUM; }
if (transform.dwFlags & D3DTRANS_VALIDFRUSTUM) { // Now we can check the spheres against the clipping planes
for (DWORD i=0; i < dwNumSpheres; i++) { lpdwReturnValues[i] = CheckSphere(lpDevI, &lpCenters[i], lpRadii[i]); } return D3D_OK; }
exit: D3D_ERR("Non-orthogonal (world X view) matrix"); return ret; #undef transform
} //---------------------------------------------------------------------
DWORD D3DFE_PVFUNCS::GenClipFlags(D3DFE_PROCESSVERTICES *pv) { return D3DFE_GenClipFlags(pv); } //---------------------------------------------------------------------
DWORD D3DFE_PVFUNCS::TransformVertices(D3DFE_PROCESSVERTICES *pv, DWORD vertexCount, LPD3DTRANSFORMDATAI data) {
if (pv->dwFlags & D3DDP_DONOTCLIP) return D3DFE_TransformUnclippedVp(pv, vertexCount, data); else return D3DFE_TransformClippedVp(pv, vertexCount, data); } //---------------------------------------------------------------------
DWORD ID3DFE_PVFUNCS::GenClipFlags(D3DFE_PROCESSVERTICES *pv) { return GeometryFuncsGuaranteed.GenClipFlags(pv); } //---------------------------------------------------------------------
// Used to implement viewport->TransformVertices
// Returns clip intersection code
DWORD ID3DFE_PVFUNCS::TransformVertices(D3DFE_PROCESSVERTICES *pv, DWORD vertexCount, D3DTRANSFORMDATAI* data) { return GeometryFuncsGuaranteed.TransformVertices(pv, vertexCount, data); }
|