windows-nt/Source/XPSP1/NT/multimedia/directx/dxg/d3d8/fe/drawprim.cpp
2020-09-26 16:20:57 +08:00

209 lines
7.5 KiB
C++

/*==========================================================================;
*
* 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"
//-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DHal::ProcessVertices"
HRESULT D3DAPI
CD3DHal::ProcessVertices(UINT SrcStartIndex, UINT DestIndex, UINT VertexCount,
IDirect3DVertexBuffer8 *DestBuffer,
DWORD dwFlags)
{
API_ENTER(this); // Takes D3D Lock if necessary
HRESULT hr = D3D_OK;
CVertexBuffer* pVB = static_cast<CVertexBuffer*>(DestBuffer);
const D3DBUFFER_DESC* pDesc = pVB->GetBufferDesc();
UINT vbVertexSize = pVB->GetVertexSize();
UINT vbNumVertices = pVB->GetNumVertices();
#if DBG
if (pVB->Device() != this)
{
D3D_ERR("VertexBuffer not created with this device. ProcessVertices failed.");
return D3DERR_INVALIDCALL;
}
if (m_dwCurrentShaderHandle == 0)
{
D3D_ERR("Current vertex shader is not set. ProcessVertices failed.");
return D3DERR_INVALIDCALL;
}
if (D3DVSD_ISLEGACY(m_dwCurrentShaderHandle) &&
FVF_TRANSFORMED(m_dwCurrentShaderHandle))
{
D3D_ERR("Invalid vertex shader for ProcessVertices. ProcessVertices failed.");
return D3DERR_INVALIDCALL;
}
if (!(m_dwRuntimeFlags & D3DRT_RSSOFTWAREPROCESSING))
{
D3D_ERR("D3D Device should be in software mode for ProcessVertices. ProcessVertices failed.");
return D3DERR_INVALIDCALL;
}
if (dwFlags & ~D3DPV_DONOTCOPYDATA)
{
D3D_ERR( "Invalid dwFlags set. ProcessVertices failed." );
return D3DERR_INVALIDCALL;
}
if (pDesc->Usage & D3DUSAGE_DONOTCLIP &&
!(m_pv->dwDeviceFlags & D3DDEV_DONOTCLIP))
{
D3D_ERR("Vertex buffer has D3D_DONOTCLIP usage, but clipping is enabled. ProcessVertices failed.");
return D3DERR_INVALIDCALL;
}
if (pVB->GetFVF() == 0)
{
D3D_ERR("Destination buffer has no FVF associated with it. ProcessVertices failed.");
return D3DERR_INVALIDCALL;
}
if ((pVB->GetFVF() & D3DFVF_POSITION_MASK) != D3DFVF_XYZRHW)
{
D3D_ERR("Destination vertex buffer should have D3DFVF_XYZRHW position. ProcessVertices failed.");
return D3DERR_INVALIDCALL;
}
if (VertexCount + DestIndex > vbNumVertices)
{
D3D_ERR("Destination vertex buffer has not enough space. ProcessVertices failed.");
return D3DERR_INVALIDCALL;
}
#endif
try
{
DWORD vbFVF = pVB->GetFVF();
m_pv->dwNumVertices = VertexCount;
m_pv->dwFlags = D3DPV_VBCALL;
#if DBG
ValidateDraw2(D3DPT_TRIANGLELIST, SrcStartIndex, 1, VertexCount, FALSE);
#endif
// Internal flags and output vertex offsets could be different for
// ProcessVertices
ForceFVFRecompute();
(this->*m_pfnPrepareToDraw)(SrcStartIndex);
if (!(m_pv->dwDeviceFlags & D3DDEV_DONOTCLIP))
{
if (pVB->GetClipCodes() == NULL)
{
pVB->AllocateClipCodes();
}
m_pv->lpClipFlags = pVB->GetClipCodes();
#if DBG
if (m_pv->lpClipFlags == NULL)
{
D3D_THROW_FAIL("Failed to allocate clip code for the dest VB");
}
#endif
m_pv->lpClipFlags += DestIndex;
}
// Check number of texture coordinates and texture formats in the
// destination VB are the same as in the computed FVF
DWORD dwComputedTexFormats = m_pv->dwVIDOut & 0xFFFF0000;
DWORD dwNumTexCoordVB = FVF_TEXCOORD_NUMBER(vbFVF);
if (m_pv->nOutTexCoord > dwNumTexCoordVB ||
((vbFVF & dwComputedTexFormats) != dwComputedTexFormats))
{
D3D_ERR("Number of output texture coordinates and their format should be");
D3D_ERR("the same in the destination vertex buffer and as computed for current D3D settings.");
D3D_ERR("Computed output FVF is 0x%08X", m_pv->dwVIDOut);
D3D_THROW_FAIL("");
}
// Check if the computed output FVF is a subset of the VB's FVF.
// Number of texture coordinates should be cleared.
DWORD dwComputedFVF = m_pv->dwVIDOut & 0x000000FF;
// Specularand diffuse colors could be omitted, as well as psize
dwComputedFVF &= ~(D3DFVF_PSIZE | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_FOG);
if((dwComputedFVF & vbFVF) != dwComputedFVF)
{
D3D_ERR("Dest vertex buffer's FVF should be a superset of the FVF, computed for");
D3D_ERR("the current D3D settings");
D3D_ERR("Computed output FVF is 0x%08X", m_pv->dwVIDOut);
D3D_THROW_FAIL("");
}
BYTE* p;
hr = pVB->Lock(0, pDesc->Size, &p, D3DLOCK_NOSYSLOCK);
if (FAILED(hr))
{
D3D_THROW_FAIL("Cannot lock destination buffer");
}
if (this->dwFEFlags & D3DFE_FRONTEND_DIRTY)
DoUpdateState(this);
// Replace output FVF and vertex size
m_pv->dwOutputSize = vbVertexSize;
m_pv->dwVIDOut = vbFVF;
m_pv->lpvOut = p + DestIndex * vbVertexSize;
// Vertex shaders don't write to the output unless shader writes to it
// explicitely. So we do not bother setting any flags
if (dwFlags & D3DPV_DONOTCOPYDATA)
{
if (m_pv->dwDeviceFlags & D3DDEV_VERTEXSHADERS)
{
m_pv->dwFlags |= D3DPV_DONOTCOPYDIFFUSE |
D3DPV_DONOTCOPYSPECULAR |
D3DPV_DONOTCOPYTEXTURE;
}
else
{
m_pv->dwFlags |= D3DPV_DONOTCOPYDIFFUSE |
D3DPV_DONOTCOPYSPECULAR |
D3DPV_DONOTCOPYTEXTURE;
// If D3DIM generates colors or texture, we should clear
// DONOTCOPY bits
if (m_pv->dwFlags & D3DPV_LIGHTING)
{
m_pv->dwFlags &= ~D3DPV_DONOTCOPYDIFFUSE;
if (m_pv->dwDeviceFlags & D3DDEV_SPECULARENABLE)
m_pv->dwFlags &= ~D3DPV_DONOTCOPYSPECULAR;
}
if (m_pv->dwFlags & D3DPV_FOG)
m_pv->dwFlags &= ~D3DPV_DONOTCOPYSPECULAR;
// If front-end is asked to do something with texture
// coordinates we disable DONOTCOPYTEXTURE
if (__TEXTURETRANSFORMENABLED(m_pv) ||
m_pv->dwFlags2 & __FLAGS2_TEXGEN)
{
m_pv->dwFlags &= ~D3DPV_DONOTCOPYTEXTURE;
}
}
}
// Compute flags based on the vertex buffer FVF
UpdateFlagsForOutputFVF(m_pv);
// Update output vertex offsets for the new FVF
ComputeOutputVertexOffsets(m_pv);
m_pv->pGeometryFuncs->ProcessVertices(m_pv);
if (!(m_pv->dwDeviceFlags & D3DDEV_DONOTCLIP))
UpdateClipStatus(this);
// When ProcessVertices is used, user must re-program texture
// stage indices and wrap modes himself
m_pv->dwDeviceFlags &= ~D3DDEV_REMAPTEXTUREINDICES;
}
catch(HRESULT ret)
{
D3D_ERR("ProcessVertices failed.");
hr = ret;
}
ForceFVFRecompute();
pVB->Unlock();
return hr;
}