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.
399 lines
14 KiB
399 lines
14 KiB
/*==========================================================================;
|
|
*
|
|
* Copyright (C) 1997 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: drawprim.hpp
|
|
* Content: DrawPrimitive common defines
|
|
*
|
|
***************************************************************************/
|
|
|
|
#ifndef _DRAWPRIM_H_
|
|
#define _DRAWPRIM_H_
|
|
|
|
#define MAX_DX6_PRIMCOUNT ((1<<16) - 1)
|
|
#define MAX_DX6_VERTICES MAX_DX6_PRIMCOUNT
|
|
|
|
extern HRESULT DoDrawPrimitive(LPD3DFE_PROCESSVERTICES pv);
|
|
extern HRESULT DoDrawIndexedPrimitive(LPD3DFE_PROCESSVERTICES pv);
|
|
extern HRESULT downloadView(LPDIRECT3DVIEWPORTI);
|
|
extern HRESULT CheckDrawPrimitive(LPDIRECT3DDEVICEI lpDevI);
|
|
extern HRESULT CheckDrawIndexedPrimitive(LPDIRECT3DDEVICEI lpDevI);
|
|
|
|
// 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
|
|
//
|
|
extern HRESULT MapFVFtoTLVertex(LPDIRECT3DDEVICEI lpDevI, LPVOID lpAddress);
|
|
//---------------------------------------------------------------------
|
|
#define FVF_TRANSFORMED(dwFVF) ((dwFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW)
|
|
#define FVF_DRIVERSUPPORTED(lpDevI) (lpDevI->dwDeviceFlags & D3DDEV_FVF)
|
|
#define FVF_TEXCOORD_NUMBER(dwFVF) \
|
|
(((dwFVF) & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT)
|
|
//---------------------------------------------------------------------
|
|
// Input:
|
|
// type - FVF control word
|
|
//
|
|
// Returns D3D_OK, if the control word is valid.
|
|
// DDERR_INVALIDPARAMS otherwise
|
|
//
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "ValidateFVF"
|
|
|
|
__inline HRESULT ValidateFVF(DWORD type)
|
|
{
|
|
DWORD dwTexCoord = FVF_TEXCOORD_NUMBER(type);
|
|
DWORD vertexType = type & D3DFVF_POSITION_MASK;
|
|
// Texture type fields should be 0
|
|
// Reserved field 0 and 2 should be 0
|
|
// Reserved 1 should be set only for LVERTEX
|
|
// Only two vertex position types allowed
|
|
if (type & 0xFFFF0000 ||
|
|
type & (D3DFVF_RESERVED2 | D3DFVF_RESERVED0) ||
|
|
(type & D3DFVF_RESERVED1 && !(type & D3DFVF_LVERTEX)) ||
|
|
!(vertexType == D3DFVF_XYZRHW || vertexType == D3DFVF_XYZ)
|
|
)
|
|
goto error;
|
|
|
|
if (vertexType == D3DFVF_XYZRHW && type & D3DFVF_NORMAL)
|
|
goto error;
|
|
return D3D_OK;
|
|
error:
|
|
D3D_ERR("ValidateFVF() returns DDERR_INVALIDPARAMS");
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
// Computes vertex size in bytes from the vertex ID
|
|
//
|
|
__inline DWORD GetVertexSizeFVF(DWORD fvf)
|
|
{
|
|
DWORD size = 3;
|
|
if (FVF_TRANSFORMED(fvf))
|
|
size++;
|
|
if (fvf & D3DFVF_NORMAL)
|
|
size += 3;
|
|
if (fvf & D3DFVF_RESERVED1)
|
|
size++;
|
|
size += FVF_TEXCOORD_NUMBER(fvf) << 1;
|
|
|
|
if (fvf & D3DFVF_DIFFUSE)
|
|
size++;
|
|
if (fvf & D3DFVF_SPECULAR)
|
|
size++;
|
|
return (size << 2);
|
|
}
|
|
//---------------------------------------------------------------------
|
|
__inline BOOL TextureStageEnabled(LPDIRECT3DDEVICEI lpDevI, DWORD dwStage)
|
|
{
|
|
return (lpDevI->tsstates[dwStage][D3DTSS_COLOROP] != D3DTOP_DISABLE &&
|
|
lpDevI->lpD3DMappedTexI[dwStage] != NULL);
|
|
}
|
|
//---------------------------------------------------------------------
|
|
// Computes nTexCoord and dwTextureIndexToCopy in case when a pre-DX6
|
|
// driver is used.
|
|
__inline void ComputeTCI2CopyLegacy(LPDIRECT3DDEVICEI lpDevI,
|
|
DWORD dwNumInpTexCoord,
|
|
BOOL bVertexTransformed)
|
|
{
|
|
if (lpDevI->dwDeviceFlags & D3DDEV_LEGACYTEXTURE)
|
|
{
|
|
lpDevI->dwTextureIndexToCopy = 0;
|
|
if (dwNumInpTexCoord)
|
|
lpDevI->nTexCoord = 1;
|
|
else
|
|
{
|
|
lpDevI->nTexCoord = 0;
|
|
D3D_WARN(1, "Texture is enabled but vertex has no texture coordinates");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (TextureStageEnabled(lpDevI, 0))
|
|
{
|
|
if (lpDevI->tsstates[0][D3DTSS_TEXCOORDINDEX] >= dwNumInpTexCoord)
|
|
{
|
|
lpDevI->nTexCoord = 0;
|
|
lpDevI->dwTextureIndexToCopy = 0;
|
|
D3D_WARN(1, "Texture index in a texture stage is greater than number of texture coord in vertex");
|
|
}
|
|
else
|
|
{
|
|
lpDevI->dwTextureIndexToCopy = lpDevI->tsstates[0][D3DTSS_TEXCOORDINDEX];
|
|
if (bVertexTransformed)
|
|
{
|
|
// In case of clipping we need to clip as many texture
|
|
// coordinates as set in the texture stage state.
|
|
lpDevI->nTexCoord = min(dwNumInpTexCoord,
|
|
lpDevI->dwTextureIndexToCopy+1);
|
|
}
|
|
else
|
|
{
|
|
// Number of output texture coordinates is 1 because we will
|
|
// build the output buffer in the inner transform & lihgting
|
|
// loop.
|
|
lpDevI->nTexCoord = 1;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lpDevI->nTexCoord = 0;
|
|
lpDevI->dwTextureIndexToCopy = 0;
|
|
}
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------
|
|
// Computes output FVF id, based on input FVF id and device settingd
|
|
// Also computes nTexCoord field
|
|
// Number of texture coordinates is set based on dwVIDIn. ValidateFVF sould
|
|
// make sure that it is not greater than supported by the driver
|
|
// Last settings for dwVIDOut and dwVIDIn are saved to speed up processing
|
|
//
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "ComputeOutputFVF"
|
|
__inline void ComputeOutputFVF(LPDIRECT3DDEVICEI lpDevI)
|
|
{
|
|
if (lpDevI->dwVIDIn == lpDevI->dwFVFLastIn)
|
|
{
|
|
lpDevI->dwVIDOut = lpDevI->dwFVFLastOut;
|
|
lpDevI->dwOutputSize = lpDevI->dwFVFLastOutputSize;
|
|
lpDevI->nTexCoord = lpDevI->dwFVFLastTexCoord;
|
|
return;
|
|
}
|
|
DWORD dwNumInpTexCoord = FVF_TEXCOORD_NUMBER(lpDevI->dwVIDIn);
|
|
// Compute how many texture coordinates to copy
|
|
if (lpDevI->dwMaxTextureIndices == 0)
|
|
lpDevI->nTexCoord = 0;
|
|
else
|
|
if (!(lpDevI->dwDeviceFlags & D3DDEV_FVF))
|
|
{
|
|
ComputeTCI2CopyLegacy(lpDevI, dwNumInpTexCoord, FVF_TRANSFORMED(lpDevI->dwVIDIn));
|
|
}
|
|
else
|
|
{
|
|
if (lpDevI->dwDeviceFlags & D3DDEV_LEGACYTEXTURE)
|
|
lpDevI->nTexCoord = 1;
|
|
else
|
|
{
|
|
// Find the max used index
|
|
if (!(lpDevI->dwFEFlags & D3DFE_TSSINDEX_DIRTY))
|
|
lpDevI->nTexCoord = lpDevI->dwMaxUsedTextureIndex;
|
|
else
|
|
{
|
|
lpDevI->dwMaxUsedTextureIndex = 0;
|
|
for (DWORD i=0; i < lpDevI->dwMaxTextureBlendStages; i++)
|
|
{
|
|
if (lpDevI->tsstates[i][D3DTSS_COLOROP] == D3DTOP_DISABLE)
|
|
break;
|
|
|
|
if (lpDevI->lpD3DMappedTexI[i] != NULL)
|
|
{
|
|
DWORD dwNewMaxTexCoord = lpDevI->tsstates[i][D3DTSS_TEXCOORDINDEX] + 1;
|
|
if (lpDevI->dwMaxUsedTextureIndex < dwNewMaxTexCoord)
|
|
{
|
|
lpDevI->dwMaxUsedTextureIndex = dwNewMaxTexCoord;
|
|
}
|
|
}
|
|
}
|
|
lpDevI->nTexCoord = lpDevI->dwMaxUsedTextureIndex;
|
|
lpDevI->dwFEFlags &= ~D3DFE_TSSINDEX_DIRTY;
|
|
}
|
|
}
|
|
if (lpDevI->nTexCoord > dwNumInpTexCoord)
|
|
{
|
|
lpDevI->nTexCoord = dwNumInpTexCoord;
|
|
D3D_WARN(1, "Texture index in a texture stage is greater than number of texture coord in vertex");
|
|
}
|
|
}
|
|
if (!(lpDevI->dwDeviceFlags & D3DDEV_FVF))
|
|
{
|
|
lpDevI->dwVIDOut = D3DFVF_TLVERTEX;
|
|
lpDevI->dwOutputSize = sizeof(D3DTLVERTEX);
|
|
}
|
|
else
|
|
{
|
|
if (lpDevI->dwDeviceFlags & D3DDEV_DONOTSTRIPELEMENTS)
|
|
{ // In this case diffuse, specular and at least one texture
|
|
// should present
|
|
lpDevI->dwVIDOut = D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR;
|
|
if (lpDevI->nTexCoord == 0)
|
|
lpDevI->dwVIDOut |= 1 << D3DFVF_TEXCOUNT_SHIFT;
|
|
else
|
|
lpDevI->dwVIDOut |= lpDevI->nTexCoord << D3DFVF_TEXCOUNT_SHIFT;
|
|
}
|
|
else
|
|
{
|
|
lpDevI->dwVIDOut = D3DFVF_XYZRHW;
|
|
// If normal present we have to compute specular and duffuse
|
|
// Otherwise set these bits the same as input.
|
|
// Not that normal should not be present for XYZRHW position type
|
|
if (lpDevI->dwVIDIn & D3DFVF_NORMAL)
|
|
lpDevI->dwVIDOut |= D3DFVF_DIFFUSE | D3DFVF_SPECULAR;
|
|
else
|
|
lpDevI->dwVIDOut |= lpDevI->dwVIDIn &
|
|
(D3DFVF_DIFFUSE | D3DFVF_SPECULAR);
|
|
// Always set specular flag if fog is enabled
|
|
if (lpDevI->rstates[D3DRENDERSTATE_FOGENABLE])
|
|
lpDevI->dwVIDOut |= D3DFVF_SPECULAR;
|
|
else
|
|
// Clear specular flag if specular disabled
|
|
if (!lpDevI->rstates[D3DRENDERSTATE_SPECULARENABLE])
|
|
lpDevI->dwVIDOut &= ~D3DFVF_SPECULAR;
|
|
lpDevI->dwVIDOut |= lpDevI->nTexCoord << D3DFVF_TEXCOUNT_SHIFT;
|
|
}
|
|
lpDevI->dwOutputSize = GetVertexSizeFVF(lpDevI->dwVIDOut);
|
|
}
|
|
lpDevI->dwFVFLastIn = lpDevI->dwVIDIn;
|
|
lpDevI->dwFVFLastOut = lpDevI->dwVIDOut;
|
|
lpDevI->dwFVFLastOutputSize = lpDevI->dwOutputSize;
|
|
lpDevI->dwFVFLastTexCoord = lpDevI->nTexCoord;
|
|
return;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CheckDeviceSettings"
|
|
inline HRESULT CheckDeviceSettings(LPDIRECT3DDEVICEI lpDevI)
|
|
{
|
|
LPDIRECT3DVIEWPORTI lpView = lpDevI->lpCurrentViewport;
|
|
#if DBG
|
|
if (!(lpDevI->dwHintFlags & D3DDEVBOOL_HINTFLAGS_INSCENE) && IS_DX5_COMPATIBLE_DEVICE(lpDevI))
|
|
{
|
|
D3D_ERR( "Not in scene" );
|
|
return D3DERR_SCENE_NOT_IN_SCENE;
|
|
}
|
|
|
|
if (!lpView)
|
|
{
|
|
D3D_ERR( "Current viewport not set" );
|
|
return D3DERR_INVALIDCURRENTVIEWPORT;
|
|
}
|
|
|
|
if (!lpView->v_data_is_set)
|
|
{
|
|
D3D_ERR("Viewport data is not set yet");
|
|
return D3DERR_VIEWPORTDATANOTSET;
|
|
}
|
|
|
|
if (lpDevI->dwHintFlags & D3DDEVBOOL_HINTFLAGS_INBEGIN)
|
|
{
|
|
D3D_ERR( "Illegal call between Begin/End" );
|
|
return D3DERR_INBEGIN;
|
|
}
|
|
#endif
|
|
// 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.
|
|
//
|
|
if (lpDevI->v_id != lpView->v_id)
|
|
{
|
|
return downloadView(lpView);
|
|
}
|
|
else
|
|
return D3D_OK;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
// Computes the number of primtives and also updates the stats accordingly
|
|
// Input: lpDevI->primType
|
|
// dwNumVertices
|
|
// Output: lpDevI->dwNumPrimitives
|
|
// lpDevI->D3DStats
|
|
// return value = dwNumPrimitives
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "GetNumPrim"
|
|
|
|
inline DWORD GetNumPrim(LPDIRECT3DDEVICEI lpDevI, DWORD dwNumVertices)
|
|
{
|
|
lpDevI->dwNumPrimitives = 0;
|
|
switch (lpDevI->primType)
|
|
{
|
|
case D3DPT_POINTLIST:
|
|
lpDevI->D3DStats.dwPointsDrawn += lpDevI->dwNumPrimitives = dwNumVertices;
|
|
break;
|
|
case D3DPT_LINELIST:
|
|
lpDevI->D3DStats.dwLinesDrawn += lpDevI->dwNumPrimitives = dwNumVertices >> 1;
|
|
break;
|
|
case D3DPT_LINESTRIP:
|
|
if (dwNumVertices < 2)
|
|
return 0;
|
|
lpDevI->D3DStats.dwLinesDrawn += lpDevI->dwNumPrimitives = dwNumVertices - 1;
|
|
break;
|
|
case D3DPT_TRIANGLEFAN:
|
|
case D3DPT_TRIANGLESTRIP:
|
|
if (dwNumVertices < 3)
|
|
return 0;
|
|
lpDevI->D3DStats.dwTrianglesDrawn += lpDevI->dwNumPrimitives = dwNumVertices - 2;
|
|
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
|
|
}
|
|
lpDevI->D3DStats.dwTrianglesDrawn += lpDevI->dwNumPrimitives = tmp;
|
|
}
|
|
#else
|
|
lpDevI->D3DStats.dwTrianglesDrawn += lpDevI->dwNumPrimitives = dwNumVertices / 3;
|
|
#endif
|
|
break;
|
|
}
|
|
return lpDevI->dwNumPrimitives;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
// Sets front-end flags every time fog state is changed
|
|
//
|
|
inline void SetFogFlags(LPDIRECT3DDEVICEI lpDevI)
|
|
{
|
|
if (lpDevI->lighting.fog_mode != D3DFOG_NONE &&
|
|
lpDevI->rstates[D3DRENDERSTATE_FOGENABLE])
|
|
{
|
|
lpDevI->dwFEFlags |= D3DFE_FOG_DIRTY | D3DFE_FOGENABLED;
|
|
}
|
|
else
|
|
lpDevI->dwFEFlags &= ~D3DFE_FOGENABLED;
|
|
lpDevI->dwFVFLastIn = 0; // Force re-computing of FVF id
|
|
}
|
|
//---------------------------------------------------------------------
|
|
// Validates DrawPrimitive flags
|
|
//
|
|
inline BOOL IsDPFlagsValid(DWORD dwFlags)
|
|
{
|
|
BOOL ret = ((dwFlags & ~(D3DDP_DONOTCLIP | D3DDP_DONOTUPDATEEXTENTS |
|
|
D3DDP_WAIT | D3DDP_DONOTLIGHT)
|
|
) == 0);
|
|
if (!ret)
|
|
{
|
|
D3D_ERR( "Invalid bit set in DrawPrimitive flags" );
|
|
}
|
|
return ret;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
// Allocate memory to hold vertex data, assume all vertices are
|
|
// of same size
|
|
inline HRESULT CheckVertexBatch(LPDIRECT3DDEVICEI lpDevI)
|
|
{
|
|
if (!lpDevI->lpvVertexBatch)
|
|
{
|
|
if (D3DMalloc((void**) &lpDevI->lpvVertexBatch,
|
|
BEGIN_DATA_BLOCK_MEM_SIZE))
|
|
{
|
|
D3D_ERR( "Out of memory" );
|
|
return DDERR_OUTOFMEMORY;
|
|
}
|
|
// Allocate memory to hold index data
|
|
if (D3DMalloc((void**) &lpDevI->lpIndexBatch,
|
|
BEGIN_DATA_BLOCK_SIZE * sizeof(WORD) * 16))
|
|
{
|
|
D3DFree( lpDevI->lpvVertexBatch );
|
|
D3D_ERR( "Out of memory" );
|
|
return DDERR_OUTOFMEMORY;
|
|
}
|
|
}
|
|
return D3D_OK;
|
|
}
|
|
|
|
#endif _DRAWPRIM_H_
|