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.
 
 
 
 
 
 

1182 lines
40 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"
#ifndef WIN95
#include <ntgdistr.h>
#endif
#define ALIGN32(x) x = ((DWORD)(x + 31)) & (~31);
//---------------------------------------------------------------------
// 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);
}
}
#if DBG
//---------------------------------------------------------------------
#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;
}
if (lpDevI->dwNumVertices > MAX_DX6_VERTICES)
{
D3D_ERR("D3D for DX6 cannot handle greater than 64K vertices");
return D3DERR_TOOMANYVERTICES;
}
return D3D_OK;
}
//---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CheckDrawIndexedPrimitive"
HRESULT
CheckDrawIndexedPrimitive(LPDIRECT3DDEVICEI lpDevI, DWORD dwStartVertex)
{
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;
}
}
if (lpDevI->dwNumPrimitives > MAX_DX6_PRIMCOUNT)
{
D3D_ERR("D3D for DX6 cannot handle greater than 64K sized primitives");
return D3DERR_TOOMANYPRIMITIVES;
}
if (lpDevI->dwNumIndices * INDEX_BATCH_SCALE < lpDevI->dwNumVertices &&
!FVF_TRANSFORMED(lpDevI->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.");
}
return D3D_OK;
}
#endif // DBG
//---------------------------------------------------------------------
#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:
D3D_ERR( "Unknown primitive type in DrawPrimitive" );
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;
}
//---------------------------------------------------------------------
// 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;
try
{
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->position = lpDrawData->position;
this->normal = lpDrawData->normal;
this->diffuse = lpDrawData->diffuse;
this->specular = lpDrawData->specular;
this->dwNumVertices = dwNumVertices;
this->dwFlags = dwFlags;
if (this->dwVIDIn != dwVertexType || !(this->dwDeviceFlags & D3DDEV_STRIDE))
{
this->dwDeviceFlags |= D3DDEV_STRIDE;
this->dwVIDIn = dwVertexType;
ret = this->SetupFVFData(NULL);
if (ret != D3D_OK)
return ret;
}
for (DWORD i=0; i < this->nTexCoord; i++)
this->textures[i] = lpDrawData->textureCoords[i];
GetNumPrim(this, dwNumVertices); // Calculate dwNumPrimitives and update stats
#if DBG
ret = CheckDrawPrimitive(this);
if (ret != D3D_OK)
{
return ret;
}
#endif
return this->ProcessPrimitive();
}
catch (HRESULT ret)
{
return ret;
}
} // 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;
try
{
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->position = lpDrawData->position;
this->normal = lpDrawData->normal;
this->diffuse = lpDrawData->diffuse;
this->specular = lpDrawData->specular;
this->dwNumVertices = dwNumVertices;
this->lpwIndices = lpwIndices;
this->dwNumIndices = dwNumIndices;
this->dwFlags = dwFlags;
if (this->dwVIDIn != dwVertexType || !(this->dwDeviceFlags & D3DDEV_STRIDE))
{
this->dwDeviceFlags |= D3DDEV_STRIDE;
this->dwVIDIn = dwVertexType;
ret = this->SetupFVFData(NULL);
if (ret != D3D_OK)
return ret;
}
for (DWORD i=0; i < this->nTexCoord; i++)
this->textures[i] = lpDrawData->textureCoords[i];
GetNumPrim(this, dwNumIndices); // Calculate dwNumPrimitives and update stats
#if DBG
ret = CheckDrawIndexedPrimitive(this);
if (ret != D3D_OK)
{
return ret;
}
#endif
return this->ProcessPrimitive(__PROCPRIMOP_INDEXEDPRIM);
}
catch (HRESULT ret)
{
return ret;
}
} // 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;
try
{
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 is mandatory for the call */
this->primType = PrimitiveType;
this->position.lpvData = lpvVertices;
this->dwNumVertices = dwNumVertices;
this->dwFlags = dwFlags;
/* This stuff depends upon the vertex type */
if (this->dwVIDIn != dwVertexType || this->dwDeviceFlags & D3DDEV_STRIDE)
{
this->dwDeviceFlags &= ~D3DDEV_STRIDE;
this->dwVIDIn = dwVertexType;
ret = SetupFVFData(&this->position.dwStride);
if (ret != D3D_OK)
{
return ret;
}
}
GetNumPrim(this, dwNumVertices); // Calculate dwNumPrimitives and update stats
#if DBG
ret = CheckDrawPrimitive(this);
if (ret != D3D_OK)
{
return ret;
}
#endif
return this->ProcessPrimitive();
}
catch (HRESULT ret)
{
return ret;
}
}
//---------------------------------------------------------------------
#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;
try
{
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
// Mandatory part
this->primType = PrimitiveType;
this->dwNumVertices = dwNumVertices;
this->lpwIndices = lpwIndices;
this->dwNumIndices = dwNumIndices;
this->dwFlags = dwFlags;
this->position.lpvData = lpvVertices;
// Stuff that depends upon dwVIDIn
if (this->dwVIDIn != dwVertexType || this->dwDeviceFlags & D3DDEV_STRIDE)
{
this->dwDeviceFlags &= ~D3DDEV_STRIDE;
this->dwVIDIn = dwVertexType;
ret = SetupFVFData(&this->position.dwStride);
if (ret != D3D_OK)
{
return ret;
}
}
GetNumPrim(this, dwNumIndices); // Calculate dwNumPrimitives and update stats
#if DBG
ret = CheckDrawIndexedPrimitive(this);
if (ret != D3D_OK)
{
return ret;
}
#endif
return this->ProcessPrimitive(__PROCPRIMOP_INDEXEDPRIM);
}
catch (HRESULT ret)
{
return ret;
}
}
#ifdef VTABLE_HACK
//----------------------------------------------------------------------
// Dedicated DrawPrimitive Implementation for TL vertex case
// Assumptions:
// No clipping
// No extents update
// Single threaded app
// No state change since last call
// no FVF change since last call
//
//---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DrawPrimitiveTL"
HRESULT D3DAPI
CDirect3DDeviceIDP2::DrawPrimitiveTL(D3DPRIMITIVETYPE PrimitiveType,
DWORD dwVertexType,
LPVOID lpvVertices,
DWORD dwNumVertices,
DWORD dwFlags)
{
HRESULT ret;
#if DBG
if (ValidateFVF(dwVertexType) != D3D_OK || !IsDPFlagsValid(dwFlags))
return DDERR_INVALIDPARAMS;
Profile(PROF_DRAWPRIMITIVEDEVICE3,PrimitiveType,dwVertexType);
#endif
/* Make sure we can use the fast path */
if (this->dwVIDIn != dwVertexType ||
this->dwDeviceFlags & D3DDEV_STRIDE ||
dwNumVertices >= LOWVERTICESNUMBER)
{
VtblDrawPrimitiveDefault();
return DrawPrimitive(PrimitiveType, dwVertexType, lpvVertices, dwNumVertices, dwFlags);
}
/* This stuff is mandatory for the call */
this->primType = PrimitiveType;
this->dwFlags = dwFlags;
this->dwNumVertices = dwNumVertices;
GetNumPrim(this, dwNumVertices); // Calculate dwNumPrimitives
#if DBG
this->position.lpvData = lpvVertices;
ret = CheckDrawPrimitive(this);
if (ret != D3D_OK)
{
return ret;
}
#endif
DWORD vertexPoolSize = dwNumVertices * this->dwOutputSize;
if (vertexPoolSize > this->TLVbuf_GetSize())
{
// try
// {
if (this->TLVbuf_Grow(vertexPoolSize, true) != D3D_OK)
{
D3D_ERR( "Could not grow TL vertex buffer" );
return DDERR_OUTOFMEMORY;
}
/* }
catch (HRESULT ret)
{
return ret;
}
*/ }
this->dwVertexBase = this->dwDP2VertexCount;
DDASSERT(this->dwVertexBase < MAX_DX6_VERTICES);
this->dwDP2VertexCount = this->dwVertexBase + dwNumVertices;
memcpy(this->TLVbuf_GetAddress(), lpvVertices, vertexPoolSize);
// try
// {
ret = this->DrawPrim();
/* }
catch (HRESULT ret)
{
return ret;
}
*/
this->TLVbuf_Base() += vertexPoolSize;
DDASSERT(TLVbuf_base <= TLVbuf_size);
DDASSERT(TLVbuf_base == this->dwDP2VertexCount * this->dwOutputSize);
return ret;
}
//----------------------------------------------------------------------
// Dedicated DrawIndexedPrimitive Implementation for TL vertex case
// Assumptions:
// No clipping
// No extents update
// Single threaded app
// No state change since last call
// no FVF change since last call
//
//---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DrawIndexedPrimitiveTL"
HRESULT D3DAPI
CDirect3DDeviceIDP2::DrawIndexedPrimitiveTL(D3DPRIMITIVETYPE PrimitiveType,
DWORD dwVertexType,
LPVOID lpvVertices, DWORD dwNumVertices,
LPWORD lpwIndices, DWORD dwNumIndices,
DWORD dwFlags)
{
HRESULT ret;
#if DBG
if (ValidateFVF(dwVertexType) != D3D_OK || !IsDPFlagsValid(dwFlags))
return DDERR_INVALIDPARAMS;
Profile(PROF_DRAWINDEXEDPRIMITIVEDEVICE3,PrimitiveType,dwVertexType);
#endif
/* Make sure we can use the fast path */
if (this->dwVIDIn != dwVertexType ||
this->dwDeviceFlags & D3DDEV_STRIDE ||
dwNumVertices >= LOWVERTICESNUMBER)
{
VtblDrawIndexedPrimitiveDefault();
return DrawIndexedPrimitive(PrimitiveType, dwVertexType, lpvVertices,
dwNumVertices, lpwIndices, dwNumIndices, dwFlags);
}
/* This stuff is mandatory for the call */
this->primType = PrimitiveType;
this->dwFlags = dwFlags;
this->lpwIndices = lpwIndices;
this->dwNumIndices = dwNumIndices;
this->dwNumVertices = dwNumVertices;
GetNumPrim(this, dwNumIndices); // Calculate dwNumPrimitives
#if DBG
this->position.lpvData = lpvVertices;
ret = CheckDrawIndexedPrimitive(this);
if (ret != D3D_OK)
{
return ret;
}
#endif
DWORD vertexPoolSize = dwNumVertices * this->dwOutputSize;
if (vertexPoolSize > this->TLVbuf_GetSize())
{
// try
// {
if (this->TLVbuf_Grow(vertexPoolSize, true) != D3D_OK)
{
D3D_ERR( "Could not grow TL vertex buffer" );
return DDERR_OUTOFMEMORY;
}
/* }
catch (HRESULT ret)
{
return ret;
}
*/ }
this->dwVertexBase = this->dwDP2VertexCount;
DDASSERT(this->dwVertexBase < MAX_DX6_VERTICES);
this->dwDP2VertexCount = this->dwVertexBase + dwNumVertices;
memcpy(this->TLVbuf_GetAddress(), lpvVertices, vertexPoolSize);
// try
// {
ret = this->DrawIndexPrim();
/* }
catch (HRESULT ret)
{
return ret;
}
*/
this->TLVbuf_Base() += vertexPoolSize;
DDASSERT(TLVbuf_base <= TLVbuf_size);
DDASSERT(TLVbuf_base == this->dwDP2VertexCount * this->dwOutputSize);
return ret;
}
//----------------------------------------------------------------------
// Dedicated DrawPrimitive Implementation for non-TL vertex case
// Assumptions:
// Single threaded app
// No state change since last call
// no FVF change since last call
//
//---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DrawPrimitiveFE"
HRESULT D3DAPI
CDirect3DDeviceIDP2::DrawPrimitiveFE(D3DPRIMITIVETYPE PrimitiveType,
DWORD dwVertexType,
LPVOID lpvVertices,
DWORD dwNumVertices,
DWORD dwFlags)
{
HRESULT ret;
#if DBG
if (ValidateFVF(dwVertexType) != D3D_OK || !IsDPFlagsValid(dwFlags))
return DDERR_INVALIDPARAMS;
Profile(PROF_DRAWPRIMITIVEDEVICE3,PrimitiveType,dwVertexType);
#endif
/* Make sure we can use the fast path */
if (this->dwVIDIn != dwVertexType ||
this->dwDeviceFlags & D3DDEV_STRIDE ||
this->dwFEFlags & D3DFE_FRONTEND_DIRTY)
{
VtblDrawPrimitiveDefault();
return DrawPrimitive(PrimitiveType, dwVertexType, lpvVertices, dwNumVertices, dwFlags);
}
/* This stuff is mandatory for the call */
this->primType = PrimitiveType;
this->dwFlags = this->dwLastFlags | dwFlags;
this->dwNumVertices = dwNumVertices;
this->position.lpvData = lpvVertices;
#if DBG
GetNumPrim(this, dwNumVertices); // Calculate dwNumPrimitives
ret = CheckDrawPrimitive(this);
if (ret != D3D_OK)
{
return ret;
}
#endif
this->dwVertexPoolSize = dwNumVertices * this->dwOutputSize;
if (this->dwVertexPoolSize > this->TLVbuf_GetSize())
{
// try
// {
if (this->TLVbuf_Grow(this->dwVertexPoolSize, true) != D3D_OK)
{
D3D_ERR( "Could not grow TL vertex buffer" );
return DDERR_OUTOFMEMORY;
}
// }
// catch (HRESULT ret)
// {
// return ret;
// }
}
if (dwNumVertices * sizeof(D3DFE_CLIPCODE) > this->HVbuf.GetSize())
{
if (this->HVbuf.Grow(dwNumVertices * sizeof(D3DFE_CLIPCODE)) != D3D_OK)
{
D3D_ERR( "Could not grow clip buffer" );
ret = DDERR_OUTOFMEMORY;
return ret;
}
this->lpClipFlags = (D3DFE_CLIPCODE*)this->HVbuf.GetAddress();
}
this->dwVertexBase = this->dwDP2VertexCount;
DDASSERT(this->dwVertexBase < MAX_DX6_VERTICES);
this->dwDP2VertexCount = this->dwVertexBase + dwNumVertices;
this->lpvOut = this->TLVbuf_GetAddress();
// try
// {
switch (this->primType)
{
case D3DPT_POINTLIST:
this->dwNumPrimitives = dwNumVertices;
ret = this->pGeometryFuncs->ProcessPrimitive(this);
break;
case D3DPT_LINELIST:
this->dwNumPrimitives = dwNumVertices >> 1;
ret = this->pGeometryFuncs->ProcessPrimitive(this);
break;
case D3DPT_LINESTRIP:
this->dwNumPrimitives = dwNumVertices - 1;
ret = this->pGeometryFuncs->ProcessPrimitive(this);
break;
case D3DPT_TRIANGLEFAN:
this->dwNumPrimitives = dwNumVertices - 2;
ret = this->pGeometryFuncs->ProcessTriangleFan(this);
break;
case D3DPT_TRIANGLESTRIP:
this->dwNumPrimitives = dwNumVertices - 2;
ret = this->pGeometryFuncs->ProcessTriangleStrip(this);
break;
case D3DPT_TRIANGLELIST:
#ifdef _X86_
{
DWORD tmp;
__asm
{
mov eax, 0x55555555 // fractional part of 1.0/3.0
mul dwNumVertices
add eax, 0x80000000 // Rounding
adc edx, 0
mov tmp, edx
}
this->dwNumPrimitives = tmp;
}
#else
this->dwNumPrimitives = dwNumVertices / 3;
#endif
ret = this->pGeometryFuncs->ProcessTriangleList(this);
break;
}
/* }
catch (HRESULT ret)
{
return ret;
}*/
D3DFE_UpdateClipStatus(this);
this->TLVbuf_Base() += this->dwVertexPoolSize;
DDASSERT(TLVbuf_base <= TLVbuf_size);
DDASSERT(TLVbuf_base == this->dwDP2VertexCount * this->dwOutputSize);
return ret;
}
//----------------------------------------------------------------------
// Dedicated DrawIndexedPrimitive Implementation for non-TL vertex case
// Assumptions:
// Single threaded app
// No state change since last call
// no FVF change since last call
//
//---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DrawIndexedPrimitiveFE"
HRESULT D3DAPI
CDirect3DDeviceIDP2::DrawIndexedPrimitiveFE(D3DPRIMITIVETYPE PrimitiveType,
DWORD dwVertexType,
LPVOID lpvVertices, DWORD dwNumVertices,
LPWORD lpwIndices, DWORD dwNumIndices,
DWORD dwFlags)
{
HRESULT ret;
#if DBG
if (ValidateFVF(dwVertexType) != D3D_OK || !IsDPFlagsValid(dwFlags))
return DDERR_INVALIDPARAMS;
Profile(PROF_DRAWINDEXEDPRIMITIVEDEVICE3,PrimitiveType,dwVertexType);
#endif
/* Make sure we can use the fast path */
if (this->dwVIDIn != dwVertexType ||
this->dwDeviceFlags & D3DDEV_STRIDE ||
this->dwFEFlags & D3DFE_FRONTEND_DIRTY)
{
VtblDrawIndexedPrimitiveDefault();
return DrawIndexedPrimitive(PrimitiveType, dwVertexType, lpvVertices,
dwNumVertices, lpwIndices, dwNumIndices, dwFlags);
}
/* This stuff is mandatory for the call */
this->primType = PrimitiveType;
this->dwFlags = this->dwLastFlags | dwFlags;
this->lpwIndices = lpwIndices;
this->dwNumIndices = dwNumIndices;
this->dwNumVertices = dwNumVertices;
this->position.lpvData = lpvVertices;
GetNumPrim(this, dwNumIndices); // Calculate dwNumPrimitives
#if DBG
ret = CheckDrawIndexedPrimitive(this);
if (ret != D3D_OK)
{
return ret;
}
#endif
this->dwVertexPoolSize = dwNumVertices * this->dwOutputSize;
if (this->dwVertexPoolSize > this->TLVbuf_GetSize())
{
// try
// {
if (this->TLVbuf_Grow(this->dwVertexPoolSize,
(this->dwDeviceFlags & D3DDEV_DONOTCLIP)!=0) != D3D_OK)
{
D3D_ERR( "Could not grow TL vertex buffer" );
return DDERR_OUTOFMEMORY;
}
// }
// catch (HRESULT ret)
// {
// return ret;
// }
}
if (dwNumVertices * sizeof(D3DFE_CLIPCODE) > this->HVbuf.GetSize())
{
if (this->HVbuf.Grow(dwNumVertices * sizeof(D3DFE_CLIPCODE)) != D3D_OK)
{
D3D_ERR( "Could not grow clip buffer" );
ret = DDERR_OUTOFMEMORY;
return ret;
}
this->lpClipFlags = (D3DFE_CLIPCODE*)this->HVbuf.GetAddress();
}
this->dwVertexBase = this->dwDP2VertexCount;
DDASSERT(this->dwVertexBase < MAX_DX6_VERTICES);
this->dwDP2VertexCount = this->dwVertexBase + dwNumVertices;
this->lpvOut = this->TLVbuf_GetAddress();
// try
// {
ret = this->pGeometryFuncs->ProcessIndexedPrimitive(this);
/* }
catch (HRESULT ret)
{
return ret;
}*/
D3DFE_UpdateClipStatus(this);
this->TLVbuf_Base() += this->dwVertexPoolSize;
DDASSERT(TLVbuf_base <= TLVbuf_size);
DDASSERT(TLVbuf_base == this->dwDP2VertexCount * this->dwOutputSize);
return ret;
}
#endif
//---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DIRECT3DDEVICEI::ComputeSphereVisibility"
HRESULT D3DAPI
DIRECT3DDEVICEI::ComputeSphereVisibility(LPD3DVECTOR lpCenters,
LPD3DVALUE lpRadii,
DWORD dwNumSpheres,
DWORD dwFlags,
LPDWORD lpdwReturnValues)
{
try
{
CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock.
#if DBG
if (dwFlags != 0 || dwNumSpheres == 0 ||
IsBadWritePtr(lpdwReturnValues, dwNumSpheres * sizeof(DWORD)) ||
IsBadWritePtr(lpRadii, dwNumSpheres * sizeof(D3DVALUE)) ||
IsBadWritePtr(lpCenters, dwNumSpheres * sizeof(LPD3DVECTOR)))
{
return DDERR_INVALIDPARAMS;
}
#endif
this->dwFlags = 0;
if (this->dwFEFlags & (D3DFE_TRANSFORM_DIRTY | D3DFE_CLIPPLANES_DIRTY))
{
DoUpdateState(this);
}
return this->pGeometryFuncs->ComputeSphereVisibility(this,
lpCenters,
lpRadii,
dwNumSpheres,
dwFlags,
lpdwReturnValues);
}
catch (HRESULT ret)
{
return ret;
}
}
//---------------------------------------------------------------------
#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);
CD3DFPstate D3DFPstate; // Sets optimal FPU state for D3D.
for (DWORD i=0; i < dwNumSpheres; i++)
{
const D3DVALUE x = lpCenters[i].x;
const D3DVALUE y = lpCenters[i].y;
const D3DVALUE z = lpCenters[i].z;
const D3DVALUE r = lpRadii[i];
const D3DVALUE xmin = x-r;
const D3DVALUE ymin = y-r;
const D3DVALUE zmin = z-r;
const D3DVALUE xmax = x+r;
const D3DVALUE ymax = y+r;
const D3DVALUE zmax = z+r;
D3DVECTOR v[8] =
{
{xmin, ymin, zmin},
{xmax, ymin, zmin},
{xmin, ymax, zmin},
{xmax, ymax, zmin},
{xmin, ymin, zmax},
{xmax, ymin, zmax},
{xmin, ymax, zmax},
{xmax, ymax, zmax}
};
DWORD dwClipUnion =0;
DWORD dwClipIntersection = ~0;
lpDevI->CheckClipStatus((D3DVALUE*)v, sizeof(D3DVECTOR), 8,
&dwClipUnion, &dwClipIntersection);
lpdwReturnValues[i] = dwClipUnion + (dwClipIntersection << 12);
}
return D3D_OK;
}
/*
//---------------------------------------------------------------------
#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 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)
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;
}
*/