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