diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index 4007b216b..50f3d63ba 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -9006,6 +9006,10 @@ xbox::void_xt WINAPI xbox::EMUPATCH(D3DDevice_InsertCallback) unsigned int MaxRectPatchVertexCount = 0; std::map g_RectPatchInfoCache; std::map g_TriPatchInfoCache; +// global flag true: using DrawRectPatch. false: converting patches to triangle stripes. +bool g_bUseDrawPatch = false; +INDEX16 IndexedPatchVertex[0x250]; +static inline int GetIndex(int x, int y, int stride) { return x + y * stride; } // ****************************************************************** // * patch: D3DDevice_DrawRectPatch // ****************************************************************** @@ -9025,7 +9029,6 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(D3DDevice_DrawRectPatch) CxbxUpdateNativeD3DResources(); //setup DrawContext in order to call VertexBufferConverter.Apply() to setup stream source and vertex buffer CxbxDrawContext DrawContext = {}; - DrawContext.XboxPrimitiveType = xbox::X_D3DPRIMITIVETYPE::X_D3DPT_QUADLIST; D3DRECTPATCH_INFO tmpRectPatchInfo; if (pRectPatchInfo != nullptr) { g_RectPatchInfoCache.insert(std::pair(Handle, *pRectPatchInfo)); @@ -9036,14 +9039,106 @@ xbox::hresult_xt WINAPI xbox::EMUPATCH(D3DDevice_DrawRectPatch) tmpRectPatchInfo = it->second; pRectPatchInfo = &tmpRectPatchInfo; } - DrawContext.dwVertexCount = (pRectPatchInfo->StartVertexOffsetHeight + pRectPatchInfo->Height) * pRectPatchInfo->Stride; - //keep max. vertex count so we can use same vertex count in DrawContext which will result in using the same vertex buffer cache. - if (MaxRectPatchVertexCount < DrawContext.dwVertexCount)MaxRectPatchVertexCount = DrawContext.dwVertexCount; - DrawContext.dwVertexCount = MaxRectPatchVertexCount; - VertexBufferConverter.Apply(&DrawContext); - HRESULT hRet = g_pD3DDevice->DrawRectPatch(Handle, pNumSegs, pRectPatchInfo); - DEBUG_D3DRESULT(hRet, "g_pD3DDevice->DrawRectPatch"); - return hRet; + + DrawContext.XboxPrimitiveType = xbox::X_D3DPRIMITIVETYPE::X_D3DPT_TRIANGLESTRIP; + /* + + illustration of a 4X3 RectPatch + StartVertexOffsetWidth :2 + |<----->| + V0 V1 V2 V3 V4 --- + -------------- | StartVertexOffsetHeight:1 + V5 V6 | V7 V8 V9 | --- --- + /|\ + V10 V11 |V12 V13 V14 | | + | Height:4 + V15 V16 |V17 V18 V19 | | + \|/ + V20 V21 |V22 V23 V24 | --- + -------------- + |<----->| Width:3 + + |<-------------->| Stride:5 + + start vertex index V7 = StartVertexOffsetWidth + StartVertexOffsetHeight * Stride; 2 + 1*5 =7 + + for any given vertex in position x, y, assuming origin is on top left corner, x positive to right, y positive to down. + the index of given vertex is x + y * Stride + + give vertex V7, (x,y)=(2,1), index = 2 + 1* 5 =7 + + vertex index in upper row is index(V7) - Stride = 7 - 5 = 2 + vertex index in lower rwo is index(V7) + stride = 7 + 5 = 12 + vertex index in right is index(V7) + 1 = 8 + vertex index in left is index(V7) - 1 = 6 + + we're going to create a index buffer to conver the 4X3 RectPatch into 3 triangle strips. + + V5 V6 V7 V8 V9 + |\ |\ | + | \ | \ | + | \| \| + V10 V11 V12 V13 V14 + |\ |\ | + | \ | \ | + | \| \| + V15 V16 V17 V18 V19 + |\ |\ | + | \ | \ | + | \| \| + V20 V21 V22 V23 V24 + + test case: Patch sample uses 4X4 RectPatch + test case: True Crime Streets of LA ? + + */ + + // g_bUseDrawPatch is global flag which we can dynamically switch between using DrawRectPatch or converting patches to triangle stripes. + if(!g_bUseDrawPatch){ + int index = 0; + int stride = pRectPatchInfo->Stride; + int originY = pRectPatchInfo->StartVertexOffsetHeight; + int originX = pRectPatchInfo->StartVertexOffsetWidth; + int y; + int StartVertexIndex= pRectPatchInfo->StartVertexOffsetHeight * pRectPatchInfo->Stride + pRectPatchInfo->StartVertexOffsetWidth; + for ( int deltaY = 1; deltaY < (pRectPatchInfo->Height); deltaY++) { + y = originY + deltaY; + int x; + for (int deltaX = 0; deltaX < (pRectPatchInfo->Width); deltaX++) { + x = originX + deltaX; + /* + (x,y-1)(x+1,y-1) + V5 V6 V7 V8 V9 + |\ |\ | + | \ | \ | + | \ | \ | + | \| \| + V10 V11 V12 V13 V14 + (x,y) (x+1,y) + 1st loop: V12,V7, + 2nd loop: V13,V8, + 3rd loop: V14,V9 + */ + IndexedPatchVertex[index++] = GetIndex( x, y, stride); + IndexedPatchVertex[index++] = GetIndex( x, y-1, stride); + } + } + DrawContext.dwVertexCount = index; + DrawContext.pXboxIndexData = IndexedPatchVertex; + DrawContext.dwStartVertex = 0; + CxbxDrawIndexed(DrawContext); + return S_OK; + } + else{ + DrawContext.dwVertexCount = (pRectPatchInfo->StartVertexOffsetHeight + pRectPatchInfo->Height) * pRectPatchInfo->Stride; + //keep max. vertex count so we can use same vertex count in DrawContext which will result in using the same vertex buffer cache. + if (MaxRectPatchVertexCount < DrawContext.dwVertexCount)MaxRectPatchVertexCount = DrawContext.dwVertexCount; + DrawContext.dwVertexCount = MaxRectPatchVertexCount; + VertexBufferConverter.Apply(&DrawContext); + HRESULT hRet = g_pD3DDevice->DrawRectPatch(Handle, pNumSegs, pRectPatchInfo); + DEBUG_D3DRESULT(hRet, "g_pD3DDevice->DrawRectPatch"); + return hRet; + } } // ******************************************************************