Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1662 lines
58 KiB

/*==========================================================================;
*
* 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);
}