mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
752 lines
20 KiB
C++
752 lines
20 KiB
C++
#include <algorithm>
|
|
|
|
#include <Common/Log.h>
|
|
#include <Config/Config.h>
|
|
#include <D3dDdi/DrawPrimitive.h>
|
|
#include <D3dDdi/Device.h>
|
|
#include <D3dDdi/Resource.h>
|
|
|
|
namespace
|
|
{
|
|
const UINT INDEX_BUFFER_SIZE = D3DMAXNUMPRIMITIVES * 3 * sizeof(UINT16);
|
|
const UINT VERTEX_BUFFER_SIZE = 1024 * 1024;
|
|
|
|
UINT getVertexCount(D3DPRIMITIVETYPE primitiveType, UINT primitiveCount)
|
|
{
|
|
switch (primitiveType)
|
|
{
|
|
case D3DPT_POINTLIST:
|
|
return primitiveCount;
|
|
case D3DPT_LINELIST:
|
|
return primitiveCount * 2;
|
|
case D3DPT_LINESTRIP:
|
|
return primitiveCount + 1;
|
|
case D3DPT_TRIANGLELIST:
|
|
return primitiveCount * 3;
|
|
case D3DPT_TRIANGLESTRIP:
|
|
case D3DPT_TRIANGLEFAN:
|
|
return primitiveCount + 2;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void updateMax(UINT& max, UINT value)
|
|
{
|
|
if (value > max)
|
|
{
|
|
max = value;
|
|
}
|
|
}
|
|
|
|
void updateMin(UINT& min, UINT value)
|
|
{
|
|
if (value < min)
|
|
{
|
|
min = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace D3dDdi
|
|
{
|
|
DrawPrimitive::DrawPrimitive(Device& device)
|
|
: m_device(device)
|
|
, m_origVtable(device.getOrigVtable())
|
|
, m_vertexBuffer(device, VERTEX_BUFFER_SIZE)
|
|
, m_indexBuffer(device, m_vertexBuffer ? INDEX_BUFFER_SIZE : 0)
|
|
, m_streamSource{}
|
|
, m_batched{}
|
|
{
|
|
LOG_ONCE("Dynamic vertex buffers are " << (m_vertexBuffer ? "" : "not ") << "available");
|
|
LOG_ONCE("Dynamic index buffers are " << (m_indexBuffer ? "" : "not ") << "available");
|
|
|
|
if (m_indexBuffer)
|
|
{
|
|
D3DDDIARG_SETINDICES si = {};
|
|
si.hIndexBuffer = m_indexBuffer;
|
|
si.Stride = 2;
|
|
m_origVtable.pfnSetIndices(m_device, &si);
|
|
}
|
|
}
|
|
|
|
void DrawPrimitive::addSysMemVertexBuffer(HANDLE resource, BYTE* vertices)
|
|
{
|
|
m_sysMemVertexBuffers[resource] = vertices;
|
|
}
|
|
|
|
void DrawPrimitive::appendIndexedVertices(const UINT16* indices, UINT count,
|
|
INT baseVertexIndex, UINT minIndex, UINT maxIndex)
|
|
{
|
|
rebaseIndices();
|
|
appendIndexedVerticesWithoutRebase(indices, count, baseVertexIndex, minIndex, maxIndex);
|
|
}
|
|
|
|
void DrawPrimitive::appendIndexedVerticesWithoutRebase(const UINT16* indices, UINT count,
|
|
INT baseVertexIndex, UINT minIndex, UINT maxIndex)
|
|
{
|
|
UINT vertexCount = maxIndex - minIndex + 1;
|
|
if (vertexCount <= count)
|
|
{
|
|
INT delta = getBatchedVertexCount() - minIndex;
|
|
for (UINT i = 0; i < count; ++i)
|
|
{
|
|
m_batched.indices.push_back(static_cast<UINT16>(indices[i] + delta));
|
|
}
|
|
appendVertices(baseVertexIndex + minIndex, vertexCount);
|
|
return;
|
|
}
|
|
|
|
static UINT16 indexMap[D3DMAXNUMVERTICES] = {};
|
|
static BYTE indexCycles[D3DMAXNUMVERTICES] = {};
|
|
static BYTE currentCycle = 0;
|
|
static UINT maxVertexCount = 0;
|
|
|
|
++currentCycle;
|
|
if (0 == currentCycle)
|
|
{
|
|
memset(indexCycles, 0, maxVertexCount);
|
|
maxVertexCount = vertexCount;
|
|
++currentCycle;
|
|
}
|
|
else
|
|
{
|
|
updateMax(maxVertexCount, vertexCount);
|
|
}
|
|
|
|
UINT16 newIndex = static_cast<UINT16>(getBatchedVertexCount());
|
|
for (UINT i = 0; i < count; ++i)
|
|
{
|
|
const UINT16 zeroBasedIndex = static_cast<UINT16>(indices[i] - minIndex);
|
|
if (currentCycle != indexCycles[zeroBasedIndex])
|
|
{
|
|
appendVertices(baseVertexIndex + indices[i], 1);
|
|
indexMap[zeroBasedIndex] = newIndex;
|
|
indexCycles[zeroBasedIndex] = currentCycle;
|
|
m_batched.indices.push_back(newIndex);
|
|
++newIndex;
|
|
}
|
|
else
|
|
{
|
|
m_batched.indices.push_back(indexMap[zeroBasedIndex]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DrawPrimitive::appendIndexRange(UINT base, UINT count)
|
|
{
|
|
rebaseIndices();
|
|
appendIndexRangeWithoutRebase(base, count);
|
|
}
|
|
|
|
void DrawPrimitive::appendIndexRangeWithoutRebase(UINT base, UINT count)
|
|
{
|
|
for (UINT i = base; i < base + count; ++i)
|
|
{
|
|
m_batched.indices.push_back(static_cast<UINT16>(i));
|
|
}
|
|
updateMin(m_batched.minIndex, base);
|
|
updateMax(m_batched.maxIndex, base + count - 1);
|
|
}
|
|
|
|
void DrawPrimitive::appendIndices(const UINT16* indices, UINT count,
|
|
INT baseVertexIndex, UINT minIndex, UINT maxIndex)
|
|
{
|
|
rebaseIndices();
|
|
for (UINT i = 0; i < count; ++i)
|
|
{
|
|
m_batched.indices.push_back(static_cast<UINT16>(baseVertexIndex + indices[i]));
|
|
}
|
|
updateMin(m_batched.minIndex, baseVertexIndex + minIndex);
|
|
updateMax(m_batched.maxIndex, baseVertexIndex + maxIndex);
|
|
}
|
|
|
|
void DrawPrimitive::appendIndicesAndVertices(const UINT16* indices, UINT count,
|
|
INT baseVertexIndex, UINT minIndex, UINT maxIndex)
|
|
{
|
|
if (m_streamSource.vertices)
|
|
{
|
|
if (indices)
|
|
{
|
|
appendIndexedVertices(indices, count, baseVertexIndex, minIndex, maxIndex);
|
|
}
|
|
else
|
|
{
|
|
if (!m_batched.indices.empty())
|
|
{
|
|
appendIndexRange(getBatchedVertexCount(), count);
|
|
}
|
|
appendVertices(baseVertexIndex + minIndex, count);
|
|
}
|
|
}
|
|
else if (indices)
|
|
{
|
|
appendIndices(indices, count, baseVertexIndex, minIndex, maxIndex);
|
|
}
|
|
else
|
|
{
|
|
appendIndexRange(baseVertexIndex, count);
|
|
}
|
|
}
|
|
|
|
void DrawPrimitive::appendLineOrTriangleList(INT baseVertexIndex, UINT primitiveCount, UINT vpp,
|
|
const UINT16* indices, UINT minIndex, UINT maxIndex)
|
|
{
|
|
if (m_streamSource.vertices ||
|
|
indices ||
|
|
!m_batched.indices.empty() ||
|
|
m_batched.baseVertexIndex + static_cast<INT>(m_batched.primitiveCount * vpp) != baseVertexIndex)
|
|
{
|
|
appendIndicesAndVertices(indices, primitiveCount * vpp, baseVertexIndex, minIndex, maxIndex);
|
|
}
|
|
}
|
|
|
|
bool DrawPrimitive::appendPrimitives(D3DPRIMITIVETYPE primitiveType, INT baseVertexIndex, UINT primitiveCount,
|
|
const UINT16* indices, UINT minIndex, UINT maxIndex)
|
|
{
|
|
if (m_batched.primitiveCount + primitiveCount > D3DMAXNUMPRIMITIVES)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
switch (primitiveType)
|
|
{
|
|
case D3DPT_POINTLIST:
|
|
if (D3DPT_POINTLIST != m_batched.primitiveType ||
|
|
!m_streamSource.vertices &&
|
|
m_batched.baseVertexIndex + static_cast<INT>(m_batched.primitiveCount) != baseVertexIndex)
|
|
{
|
|
return false;
|
|
}
|
|
if (m_streamSource.vertices)
|
|
{
|
|
appendVertices(baseVertexIndex, primitiveCount);
|
|
}
|
|
break;
|
|
|
|
case D3DPT_LINESTRIP:
|
|
return false;
|
|
|
|
case D3DPT_LINELIST:
|
|
if (D3DPT_LINELIST != m_batched.primitiveType)
|
|
{
|
|
return false;
|
|
}
|
|
appendLineOrTriangleList(baseVertexIndex, primitiveCount, 2, indices, minIndex, maxIndex);
|
|
break;
|
|
|
|
case D3DPT_TRIANGLELIST:
|
|
if (m_batched.primitiveType < D3DPT_TRIANGLELIST)
|
|
{
|
|
return false;
|
|
}
|
|
convertToTriangleList();
|
|
appendLineOrTriangleList(baseVertexIndex, primitiveCount, 3, indices, minIndex, maxIndex);
|
|
break;
|
|
|
|
case D3DPT_TRIANGLESTRIP:
|
|
if (m_batched.primitiveType < D3DPT_TRIANGLELIST)
|
|
{
|
|
return false;
|
|
}
|
|
appendTriangleStrip(baseVertexIndex, primitiveCount, indices, minIndex, maxIndex);
|
|
break;
|
|
|
|
case D3DPT_TRIANGLEFAN:
|
|
if (m_batched.primitiveType < D3DPT_TRIANGLELIST)
|
|
{
|
|
return false;
|
|
}
|
|
appendTriangleFan(baseVertexIndex, primitiveCount, indices, minIndex, maxIndex);
|
|
break;
|
|
}
|
|
|
|
m_batched.primitiveCount += primitiveCount;
|
|
return true;
|
|
}
|
|
|
|
void DrawPrimitive::appendTriangleFan(INT baseVertexIndex, UINT primitiveCount,
|
|
const UINT16* indices, UINT minIndex, UINT maxIndex)
|
|
{
|
|
convertToTriangleList();
|
|
rebaseIndices();
|
|
appendIndicesAndVertices(indices, primitiveCount + 2, baseVertexIndex, minIndex, maxIndex);
|
|
convertIndexedTriangleFanToList(m_batched.primitiveCount, primitiveCount);
|
|
}
|
|
|
|
void DrawPrimitive::appendTriangleStrip(INT baseVertexIndex, UINT primitiveCount,
|
|
const UINT16* indices, UINT minIndex, UINT maxIndex)
|
|
{
|
|
if (D3DPT_TRIANGLESTRIP != m_batched.primitiveType)
|
|
{
|
|
convertToTriangleList();
|
|
rebaseIndices();
|
|
appendIndicesAndVertices(indices, primitiveCount + 2, baseVertexIndex, minIndex, maxIndex);
|
|
convertIndexedTriangleStripToList(m_batched.primitiveCount, primitiveCount);
|
|
return;
|
|
}
|
|
|
|
if (!m_streamSource.vertices || !m_batched.indices.empty())
|
|
{
|
|
rebaseIndices();
|
|
}
|
|
|
|
for (UINT i = 1 + m_batched.primitiveCount % 2; i != 0; --i)
|
|
{
|
|
repeatLastBatchedVertex();
|
|
m_batched.primitiveCount++;
|
|
}
|
|
|
|
if (m_batched.indices.empty())
|
|
{
|
|
appendVertices(baseVertexIndex, 1);
|
|
}
|
|
else
|
|
{
|
|
if (m_streamSource.vertices)
|
|
{
|
|
m_batched.indices.push_back(static_cast<UINT16>(getBatchedVertexCount()));
|
|
}
|
|
else if (indices)
|
|
{
|
|
m_batched.indices.push_back(static_cast<UINT16>(baseVertexIndex + indices[0]));
|
|
}
|
|
else
|
|
{
|
|
m_batched.indices.push_back(static_cast<UINT16>(baseVertexIndex));
|
|
}
|
|
}
|
|
m_batched.primitiveCount += 3;
|
|
|
|
appendIndicesAndVertices(indices, primitiveCount + 2, baseVertexIndex, minIndex, maxIndex);
|
|
}
|
|
|
|
void DrawPrimitive::appendVertices(UINT base, UINT count)
|
|
{
|
|
auto vertices = m_streamSource.vertices + base * m_streamSource.stride;
|
|
m_batched.vertices.insert(m_batched.vertices.end(), vertices, vertices + count * m_streamSource.stride);
|
|
}
|
|
|
|
void DrawPrimitive::clearBatchedPrimitives()
|
|
{
|
|
m_batched.primitiveCount = 0;
|
|
m_batched.vertices.clear();
|
|
m_batched.indices.clear();
|
|
}
|
|
|
|
void DrawPrimitive::convertIndexedTriangleFanToList(UINT startPrimitive, UINT primitiveCount)
|
|
{
|
|
const UINT totalPrimitiveCount = startPrimitive + primitiveCount;
|
|
m_batched.indices.resize(totalPrimitiveCount * 3);
|
|
|
|
INT startIndexPos = startPrimitive * 3;
|
|
INT oldIndexPos = startIndexPos + primitiveCount - 1;
|
|
INT newIndexPos = (totalPrimitiveCount - 1) * 3;
|
|
const UINT16 startIndex = m_batched.indices[startIndexPos];
|
|
|
|
while (newIndexPos > startIndexPos)
|
|
{
|
|
m_batched.indices[newIndexPos + 2] = startIndex;
|
|
m_batched.indices[newIndexPos + 1] = m_batched.indices[oldIndexPos + 2];
|
|
m_batched.indices[newIndexPos] = m_batched.indices[oldIndexPos + 1];
|
|
newIndexPos -= 3;
|
|
oldIndexPos--;
|
|
}
|
|
|
|
m_batched.indices[newIndexPos] = m_batched.indices[oldIndexPos + 1];
|
|
m_batched.indices[newIndexPos + 1] = m_batched.indices[oldIndexPos + 2];
|
|
m_batched.indices[newIndexPos + 2] = startIndex;
|
|
}
|
|
|
|
void DrawPrimitive::convertIndexedTriangleStripToList(UINT startPrimitive, UINT primitiveCount)
|
|
{
|
|
const UINT totalPrimitiveCount = startPrimitive + primitiveCount;
|
|
m_batched.indices.resize(totalPrimitiveCount * 3);
|
|
|
|
INT oldIndexPos = startPrimitive * 3 + primitiveCount - 2;
|
|
INT newIndexPos = (totalPrimitiveCount - 2) * 3;
|
|
|
|
if (0 != primitiveCount % 2)
|
|
{
|
|
m_batched.indices[newIndexPos + 5] = m_batched.indices[oldIndexPos + 3];
|
|
m_batched.indices[newIndexPos + 4] = m_batched.indices[oldIndexPos + 2];
|
|
m_batched.indices[newIndexPos + 3] = m_batched.indices[oldIndexPos + 1];
|
|
newIndexPos -= 3;
|
|
oldIndexPos--;
|
|
}
|
|
|
|
while (newIndexPos >= oldIndexPos)
|
|
{
|
|
m_batched.indices[newIndexPos + 5] = m_batched.indices[oldIndexPos + 2];
|
|
m_batched.indices[newIndexPos + 4] = m_batched.indices[oldIndexPos + 3];
|
|
m_batched.indices[newIndexPos + 3] = m_batched.indices[oldIndexPos + 1];
|
|
m_batched.indices[newIndexPos + 2] = m_batched.indices[oldIndexPos + 2];
|
|
m_batched.indices[newIndexPos + 1] = m_batched.indices[oldIndexPos + 1];
|
|
m_batched.indices[newIndexPos] = m_batched.indices[oldIndexPos];
|
|
newIndexPos -= 6;
|
|
oldIndexPos -= 2;
|
|
}
|
|
}
|
|
|
|
void DrawPrimitive::convertToTriangleList()
|
|
{
|
|
const bool alreadyIndexed = !m_batched.indices.empty();
|
|
|
|
switch (m_batched.primitiveType)
|
|
{
|
|
case D3DPT_TRIANGLELIST:
|
|
return;
|
|
|
|
case D3DPT_TRIANGLESTRIP:
|
|
if (alreadyIndexed)
|
|
{
|
|
rebaseIndices();
|
|
convertIndexedTriangleStripToList(0, m_batched.primitiveCount);
|
|
}
|
|
else
|
|
{
|
|
const UINT baseVertexIndex = static_cast<UINT>(m_batched.baseVertexIndex);
|
|
UINT i = baseVertexIndex;
|
|
for (; i < baseVertexIndex + m_batched.primitiveCount - 1; i += 2)
|
|
{
|
|
m_batched.indices.push_back(static_cast<UINT16>(i));
|
|
m_batched.indices.push_back(static_cast<UINT16>(i + 1));
|
|
m_batched.indices.push_back(static_cast<UINT16>(i + 2));
|
|
m_batched.indices.push_back(static_cast<UINT16>(i + 1));
|
|
m_batched.indices.push_back(static_cast<UINT16>(i + 3));
|
|
m_batched.indices.push_back(static_cast<UINT16>(i + 2));
|
|
}
|
|
if (i < baseVertexIndex + m_batched.primitiveCount)
|
|
{
|
|
m_batched.indices.push_back(static_cast<UINT16>(i));
|
|
m_batched.indices.push_back(static_cast<UINT16>(i + 1));
|
|
m_batched.indices.push_back(static_cast<UINT16>(i + 2));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case D3DPT_TRIANGLEFAN:
|
|
if (alreadyIndexed)
|
|
{
|
|
rebaseIndices();
|
|
convertIndexedTriangleFanToList(0, m_batched.primitiveCount);
|
|
}
|
|
else
|
|
{
|
|
for (UINT i = m_batched.baseVertexIndex; i < m_batched.baseVertexIndex + m_batched.primitiveCount; ++i)
|
|
{
|
|
m_batched.indices.push_back(static_cast<UINT16>(i + 1));
|
|
m_batched.indices.push_back(static_cast<UINT16>(i + 2));
|
|
m_batched.indices.push_back(static_cast<UINT16>(m_batched.baseVertexIndex));
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
m_batched.primitiveType = D3DPT_TRIANGLELIST;
|
|
if (!alreadyIndexed)
|
|
{
|
|
m_batched.minIndex = m_batched.baseVertexIndex;
|
|
m_batched.maxIndex = m_batched.baseVertexIndex + m_batched.primitiveCount + 1;
|
|
m_batched.baseVertexIndex = 0;
|
|
}
|
|
}
|
|
|
|
HRESULT DrawPrimitive::draw(D3DDDIARG_DRAWPRIMITIVE data, const UINT* flagBuffer)
|
|
{
|
|
m_device.getState().flush();
|
|
|
|
if (0 == m_batched.primitiveCount || flagBuffer ||
|
|
!appendPrimitives(data.PrimitiveType, data.VStart, data.PrimitiveCount, nullptr, 0, 0))
|
|
{
|
|
flushPrimitives();
|
|
auto vertexCount = getVertexCount(data.PrimitiveType, data.PrimitiveCount);
|
|
if (m_streamSource.vertices)
|
|
{
|
|
appendVertices(data.VStart, vertexCount);
|
|
m_batched.baseVertexIndex = 0;
|
|
}
|
|
else
|
|
{
|
|
m_batched.baseVertexIndex = data.VStart;
|
|
m_batched.minIndex = D3DMAXNUMVERTICES;
|
|
m_batched.maxIndex = 0;
|
|
}
|
|
m_batched.primitiveType = data.PrimitiveType;
|
|
m_batched.primitiveCount = data.PrimitiveCount;
|
|
|
|
if (flagBuffer)
|
|
{
|
|
flushPrimitives(flagBuffer);
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT DrawPrimitive::drawIndexed(
|
|
D3DDDIARG_DRAWINDEXEDPRIMITIVE2 data, const UINT16* indices, const UINT* flagBuffer)
|
|
{
|
|
m_device.getState().flush();
|
|
|
|
auto indexCount = getVertexCount(data.PrimitiveType, data.PrimitiveCount);
|
|
auto [min, max] = std::minmax_element(indices, indices + indexCount);
|
|
data.MinIndex = *min;
|
|
data.NumVertices = *max - *min + 1;
|
|
|
|
if (0 == m_batched.primitiveCount || flagBuffer ||
|
|
!appendPrimitives(data.PrimitiveType, data.BaseVertexOffset / static_cast<INT>(m_streamSource.stride),
|
|
data.PrimitiveCount, indices, *min, *max))
|
|
{
|
|
flushPrimitives();
|
|
m_batched.baseVertexIndex = data.BaseVertexOffset / static_cast<INT>(m_streamSource.stride);
|
|
if (m_streamSource.vertices)
|
|
{
|
|
appendIndexedVerticesWithoutRebase(indices, indexCount, m_batched.baseVertexIndex, *min, *max);
|
|
m_batched.baseVertexIndex = 0;
|
|
}
|
|
else
|
|
{
|
|
m_batched.indices.assign(indices, indices + indexCount);
|
|
m_batched.minIndex = *min;
|
|
m_batched.maxIndex = *max;
|
|
}
|
|
m_batched.primitiveType = data.PrimitiveType;
|
|
m_batched.primitiveCount = data.PrimitiveCount;
|
|
|
|
if (flagBuffer)
|
|
{
|
|
flushPrimitives(flagBuffer);
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT DrawPrimitive::flush(const UINT* flagBuffer)
|
|
{
|
|
D3DDDIARG_DRAWPRIMITIVE data = {};
|
|
data.PrimitiveType = m_batched.primitiveType;
|
|
data.VStart = m_batched.baseVertexIndex;
|
|
data.PrimitiveCount = m_batched.primitiveCount;
|
|
|
|
if (m_streamSource.vertices)
|
|
{
|
|
data.VStart = loadVertices(getBatchedVertexCount());
|
|
}
|
|
|
|
clearBatchedPrimitives();
|
|
return m_origVtable.pfnDrawPrimitive(m_device, &data, flagBuffer);
|
|
}
|
|
|
|
HRESULT DrawPrimitive::flushIndexed(const UINT* flagBuffer)
|
|
{
|
|
D3DDDIARG_DRAWINDEXEDPRIMITIVE2 data = {};
|
|
data.PrimitiveType = m_batched.primitiveType;
|
|
data.BaseVertexOffset = m_batched.baseVertexIndex * static_cast<INT>(m_streamSource.stride);
|
|
if (m_streamSource.vertices)
|
|
{
|
|
data.MinIndex = -m_batched.baseVertexIndex;
|
|
data.NumVertices = getBatchedVertexCount();
|
|
}
|
|
else
|
|
{
|
|
data.MinIndex = m_batched.minIndex;
|
|
data.NumVertices = m_batched.maxIndex - m_batched.minIndex + 1;
|
|
}
|
|
data.PrimitiveCount = m_batched.primitiveCount;
|
|
|
|
if (m_streamSource.vertices)
|
|
{
|
|
INT baseVertexIndex = loadVertices(data.NumVertices) - data.MinIndex;
|
|
data.BaseVertexOffset = baseVertexIndex * static_cast<INT>(m_streamSource.stride);
|
|
}
|
|
|
|
INT startIndex = -1;
|
|
if ((!m_streamSource.vertices || m_vertexBuffer) && m_indexBuffer && !flagBuffer)
|
|
{
|
|
startIndex = loadIndices(m_batched.indices.data(), m_batched.indices.size());
|
|
}
|
|
|
|
HRESULT result = S_OK;
|
|
if (startIndex >= 0)
|
|
{
|
|
D3DDDIARG_DRAWINDEXEDPRIMITIVE dp = {};
|
|
dp.PrimitiveType = data.PrimitiveType;
|
|
dp.BaseVertexIndex = data.BaseVertexOffset / static_cast<INT>(m_streamSource.stride);
|
|
dp.MinIndex = data.MinIndex;
|
|
dp.NumVertices = data.NumVertices;
|
|
dp.StartIndex = startIndex;
|
|
dp.PrimitiveCount = data.PrimitiveCount;
|
|
result = m_origVtable.pfnDrawIndexedPrimitive(m_device, &dp);
|
|
}
|
|
else
|
|
{
|
|
result = m_origVtable.pfnDrawIndexedPrimitive2(m_device, &data, 2, m_batched.indices.data(), flagBuffer);
|
|
}
|
|
|
|
clearBatchedPrimitives();
|
|
return result;
|
|
}
|
|
|
|
HRESULT DrawPrimitive::flushPrimitives(const UINT* flagBuffer)
|
|
{
|
|
if (0 == m_batched.primitiveCount)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
LOG_DEBUG << "Flushing " << m_batched.primitiveCount << " primitives of type " << m_batched.primitiveType;
|
|
m_device.prepareForGpuWrite();
|
|
return m_batched.indices.empty() ? flush(flagBuffer) : flushIndexed(flagBuffer);
|
|
}
|
|
|
|
UINT DrawPrimitive::getBatchedVertexCount() const
|
|
{
|
|
return m_batched.vertices.size() / m_streamSource.stride;
|
|
}
|
|
|
|
INT DrawPrimitive::loadIndices(const void* indices, UINT count)
|
|
{
|
|
INT startIndex = m_indexBuffer.load(indices, count);
|
|
if (startIndex >= 0)
|
|
{
|
|
return startIndex;
|
|
}
|
|
|
|
LOG_ONCE("WARN: Dynamic index buffer lock failed");
|
|
m_indexBuffer.resize(0);
|
|
return -1;
|
|
}
|
|
|
|
INT DrawPrimitive::loadVertices(UINT count)
|
|
{
|
|
auto vertices = m_batched.vertices.data();
|
|
if (m_vertexBuffer)
|
|
{
|
|
UINT size = count * m_streamSource.stride;
|
|
if (size > m_vertexBuffer.getSize())
|
|
{
|
|
m_vertexBuffer.resize((size + VERTEX_BUFFER_SIZE - 1) / VERTEX_BUFFER_SIZE * VERTEX_BUFFER_SIZE);
|
|
if (m_vertexBuffer)
|
|
{
|
|
D3DDDIARG_SETSTREAMSOURCE ss = {};
|
|
ss.hVertexBuffer = m_vertexBuffer;
|
|
ss.Stride = m_streamSource.stride;
|
|
m_origVtable.pfnSetStreamSource(m_device, &ss);
|
|
}
|
|
else
|
|
{
|
|
LOG_ONCE("WARN: Dynamic vertex buffer resize failed");
|
|
}
|
|
}
|
|
|
|
if (m_vertexBuffer)
|
|
{
|
|
INT baseVertexIndex = m_vertexBuffer.load(vertices, count);
|
|
if (baseVertexIndex >= 0)
|
|
{
|
|
return baseVertexIndex;
|
|
}
|
|
LOG_ONCE("WARN: Dynamic vertex buffer lock failed");
|
|
}
|
|
|
|
m_vertexBuffer.resize(0);
|
|
m_indexBuffer.resize(0);
|
|
}
|
|
|
|
D3DDDIARG_SETSTREAMSOURCEUM ss = {};
|
|
ss.Stride = m_streamSource.stride;
|
|
m_origVtable.pfnSetStreamSourceUm(m_device, &ss, vertices);
|
|
return 0;
|
|
}
|
|
|
|
void DrawPrimitive::rebaseIndices()
|
|
{
|
|
if (0 != m_batched.baseVertexIndex || m_batched.indices.empty())
|
|
{
|
|
if (m_batched.indices.empty())
|
|
{
|
|
auto vertexCount = getVertexCount(m_batched.primitiveType, m_batched.primitiveCount);
|
|
appendIndexRangeWithoutRebase(m_batched.baseVertexIndex, vertexCount);
|
|
}
|
|
else
|
|
{
|
|
for (auto& index : m_batched.indices)
|
|
{
|
|
index = static_cast<UINT16>(m_batched.baseVertexIndex + index);
|
|
}
|
|
m_batched.minIndex += m_batched.baseVertexIndex;
|
|
m_batched.maxIndex += m_batched.baseVertexIndex;
|
|
}
|
|
m_batched.baseVertexIndex = 0;
|
|
}
|
|
}
|
|
|
|
void DrawPrimitive::repeatLastBatchedVertex()
|
|
{
|
|
if (m_batched.indices.empty())
|
|
{
|
|
m_batched.vertices.reserve(m_batched.vertices.size() + m_streamSource.stride);
|
|
m_batched.vertices.insert(m_batched.vertices.end(),
|
|
m_batched.vertices.end() - m_streamSource.stride, m_batched.vertices.end());
|
|
}
|
|
else
|
|
{
|
|
m_batched.indices.push_back(m_batched.indices.back());
|
|
}
|
|
}
|
|
|
|
void DrawPrimitive::removeSysMemVertexBuffer(HANDLE resource)
|
|
{
|
|
m_sysMemVertexBuffers.erase(resource);
|
|
}
|
|
|
|
HRESULT DrawPrimitive::setStreamSource(const D3DDDIARG_SETSTREAMSOURCE& data)
|
|
{
|
|
auto it = m_sysMemVertexBuffers.find(data.hVertexBuffer);
|
|
if (it != m_sysMemVertexBuffers.end())
|
|
{
|
|
return setSysMemStreamSource(it->second, data.Stride);
|
|
}
|
|
|
|
flushPrimitives();
|
|
HRESULT result = m_origVtable.pfnSetStreamSource(m_device, &data);
|
|
if (SUCCEEDED(result))
|
|
{
|
|
m_streamSource = { nullptr, data.Stride };
|
|
}
|
|
return result;
|
|
}
|
|
|
|
HRESULT DrawPrimitive::setStreamSourceUm(const D3DDDIARG_SETSTREAMSOURCEUM& data, const void* umBuffer)
|
|
{
|
|
return setSysMemStreamSource(static_cast<const BYTE*>(umBuffer), data.Stride);
|
|
}
|
|
|
|
HRESULT DrawPrimitive::setSysMemStreamSource(const BYTE* vertices, UINT stride)
|
|
{
|
|
HRESULT result = S_OK;
|
|
if (!m_streamSource.vertices || stride != m_streamSource.stride)
|
|
{
|
|
flushPrimitives();
|
|
if (m_vertexBuffer)
|
|
{
|
|
D3DDDIARG_SETSTREAMSOURCE ss = {};
|
|
ss.hVertexBuffer = m_vertexBuffer;
|
|
ss.Stride = stride;
|
|
result = m_origVtable.pfnSetStreamSource(m_device, &ss);
|
|
if (SUCCEEDED(result))
|
|
{
|
|
m_vertexBuffer.setStride(stride);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(result))
|
|
{
|
|
m_streamSource = { vertices, stride };
|
|
}
|
|
return result;
|
|
}
|
|
}
|