1111
1212#include " StdInc.h"
1313#include " CAdditionalVertexStreamManager.h"
14+ #include < limits>
1415
1516CAdditionalVertexStreamManager* CAdditionalVertexStreamManager::ms_Singleton = nullptr ;
1617
1718namespace
1819{
1920 // Helper functions for this file only
2021
21- // Convert size of PT stream to sizeof of N stream
22- uint ConvertPTSize (uint SizePT) { return SizePT * 12 / 20 ; }
22+ uint ConvertPTOffset (uint OffsetPT)
23+ {
24+ return (OffsetPT / 20 ) * 12 ;
25+ }
26+
27+ // Convert size of PT stream to sizeof of N stream (rounded up to the next vertex)
28+ uint ConvertPTSize (uint SizePT)
29+ {
30+ uint64_t padded = static_cast <uint64_t >(SizePT) + 19ull ;
31+ uint64_t result = (padded / 20ull ) * 12ull ;
32+ if (result > std::numeric_limits<uint>::max ())
33+ return std::numeric_limits<uint>::max ();
34+ return static_cast <uint>(result);
35+ }
36+
37+ struct STriKey
38+ {
39+ uint32_t v0;
40+ uint32_t v1;
41+ uint32_t v2;
42+
43+ bool operator <(const STriKey& rhs) const
44+ {
45+ if (v0 != rhs.v0 )
46+ return v0 < rhs.v0 ;
47+ if (v1 != rhs.v1 )
48+ return v1 < rhs.v1 ;
49+ return v2 < rhs.v2 ;
50+ }
51+ };
2352
24- // Get 64 bit key for a triangle by using the ordered vertex indices
25- long long getTriKey (WORD a, WORD b, WORD c)
53+ // Get ordered key for a triangle by using the sorted vertex indices
54+ STriKey GetTriKey ( uint32_t a, uint32_t b, uint32_t c)
2655 {
27- WORD tmp;
56+ uint32_t tmp;
2857 if (b < a)
2958 {
3059 tmp = b;
@@ -43,7 +72,8 @@ namespace
4372 b = a;
4473 a = tmp;
4574 }
46- return (((long long )a) << 32 ) | (((long long )b) << 16 ) | ((long long )c);
75+ STriKey key = {a, b, c};
76+ return key;
4777 }
4878} // namespace
4979
@@ -145,14 +175,14 @@ bool CAdditionalVertexStreamManager::MaybeSetAdditionalVertexStream(D3DPRIMITIVE
145175 state.args .primCount = primCount;
146176
147177 // Cache info about state streams etc
148- UpdateCurrentStateInfo (state);
178+ if (!UpdateCurrentStateInfo (state))
179+ return false ;
149180
150181 // For now, this only works if the original has 3 decl elements (0:D, 1:P, 1:T) and stream 1 has a stride of 20
151182 if (!CheckCanDoThis (state))
152183 return false ;
153184
154- SetAdditionalVertexStream (state);
155- return true ;
185+ return SetAdditionalVertexStream (state);
156186}
157187
158188// /////////////////////////////////////////////////////////////
@@ -162,7 +192,7 @@ bool CAdditionalVertexStreamManager::MaybeSetAdditionalVertexStream(D3DPRIMITIVE
162192//
163193//
164194// /////////////////////////////////////////////////////////////
165- void CAdditionalVertexStreamManager::SetAdditionalVertexStream (SCurrentStateInfo& state)
195+ bool CAdditionalVertexStreamManager::SetAdditionalVertexStream (SCurrentStateInfo& state)
166196{
167197 HRESULT hr;
168198
@@ -171,40 +201,81 @@ void CAdditionalVertexStreamManager::SetAdditionalVertexStream(SCurrentStateInfo
171201 if (!pAdditionalInfo)
172202 pAdditionalInfo = CreateAdditionalStreamInfo (state);
173203
204+ if (!pAdditionalInfo)
205+ return false ;
206+
174207 uint StridePT = 20 ;
175208 uint StrideN = 12 ;
176209
177- // Calc area we are going to use
178- uint viMinBased = state.args .MinVertexIndex + state.args .BaseVertexIndex ;
179- uint viMaxBased = state.args .MinVertexIndex + state.args .NumVertices + state.args .BaseVertexIndex ;
210+ const INT baseVertexIndex = state.args .BaseVertexIndex ;
180211
181- uint ReadOffsetStart = viMinBased * StridePT + state.stream1 .OffsetInBytes ;
182- uint ReadOffsetSize = (viMaxBased - viMinBased) * StridePT;
212+ const int64_t maxUint = static_cast <int64_t >(std::numeric_limits<uint>::max ());
213+ const int64_t viMinBasedSigned = static_cast <int64_t >(state.args .MinVertexIndex ) + static_cast <int64_t >(baseVertexIndex);
214+ if (viMinBasedSigned < 0 || viMinBasedSigned > maxUint)
215+ return false ;
216+
217+ const int64_t viMaxBasedSigned = viMinBasedSigned + static_cast <int64_t >(state.args .NumVertices );
218+ if (viMaxBasedSigned < viMinBasedSigned || viMaxBasedSigned > maxUint)
219+ return false ;
183220
184- uint OffsetInBytesN = ConvertPTSize (state.stream1 .OffsetInBytes );
185- uint WriteOffsetStart = viMinBased * StrideN + OffsetInBytesN;
186- uint WriteOffsetSize = (viMaxBased - viMinBased) * StrideN;
221+ uint viMinBased = static_cast <uint>(viMinBasedSigned);
222+ uint viMaxBased = static_cast <uint>(viMaxBasedSigned);
223+ uint vertexSpan = viMaxBased - viMinBased;
224+
225+ uint64_t readOffsetStart64 = static_cast <uint64_t >(viMinBased) * StridePT + state.stream1 .OffsetInBytes ;
226+ if (readOffsetStart64 > std::numeric_limits<uint>::max ())
227+ return false ;
228+ uint ReadOffsetStart = static_cast <uint>(readOffsetStart64);
187229
188- assert (WriteOffsetStart == ConvertPTSize (ReadOffsetStart));
230+ uint64_t readOffsetSize64 = static_cast <uint64_t >(vertexSpan) * StridePT;
231+ if (readOffsetSize64 > std::numeric_limits<uint>::max ())
232+ return false ;
233+ uint ReadOffsetSize = static_cast <uint>(readOffsetSize64);
234+
235+ uint OffsetInBytesN = ConvertPTOffset (state.stream1 .OffsetInBytes );
236+ uint64_t writeOffsetStart64 = static_cast <uint64_t >(viMinBased) * StrideN + OffsetInBytesN;
237+ if (writeOffsetStart64 > std::numeric_limits<uint>::max ())
238+ return false ;
239+ uint WriteOffsetStart = static_cast <uint>(writeOffsetStart64);
240+
241+ uint64_t writeOffsetSize64 = static_cast <uint64_t >(vertexSpan) * StrideN;
242+ if (writeOffsetSize64 > std::numeric_limits<uint>::max ())
243+ return false ;
244+ uint WriteOffsetSize = static_cast <uint>(writeOffsetSize64);
245+
246+ assert (WriteOffsetStart == ConvertPTOffset (ReadOffsetStart));
189247 assert (WriteOffsetSize == ConvertPTSize (ReadOffsetSize));
190248
191249 // See if area VB area needs updating
192250 if (!pAdditionalInfo->ConvertedRanges .IsRangeSet (WriteOffsetStart, WriteOffsetSize))
193251 {
194- // Update VB area
195- UpdateAdditionalStreamContent (state, pAdditionalInfo, ReadOffsetStart, ReadOffsetSize, WriteOffsetStart, WriteOffsetSize);
252+ if (!UpdateAdditionalStreamContent (state, pAdditionalInfo, ReadOffsetStart, ReadOffsetSize, WriteOffsetStart, WriteOffsetSize))
253+ return false ;
254+
196255 pAdditionalInfo->ConvertedRanges .SetRange (WriteOffsetStart, WriteOffsetSize);
197256 }
198257
199- // Save old declaration
200- hr = m_pDevice->GetVertexDeclaration (&m_pOldVertexDeclaration);
258+ IDirect3DVertexDeclaration9* pPreviousDecl = nullptr ;
259+ if (FAILED (m_pDevice->GetVertexDeclaration (&pPreviousDecl)))
260+ return false ;
201261
202- // Set declaration
203- hr = g_pProxyDevice->SetVertexDeclaration (pAdditionalInfo->pVertexDeclaration );
262+ if (FAILED (g_pProxyDevice->SetVertexDeclaration (pAdditionalInfo->pVertexDeclaration )))
263+ {
264+ SAFE_RELEASE (pPreviousDecl);
265+ return false ;
266+ }
204267
205- // Set additional stream
206- uint OffsetInBytes = ConvertPTSize (state.stream1 .OffsetInBytes );
207- hr = m_pDevice->SetStreamSource (2 , pAdditionalInfo->pStreamData , OffsetInBytes, pAdditionalInfo->Stride );
268+ uint OffsetInBytes = ConvertPTOffset (state.stream1 .OffsetInBytes );
269+ if (FAILED (m_pDevice->SetStreamSource (2 , pAdditionalInfo->pStreamData , OffsetInBytes, pAdditionalInfo->Stride )))
270+ {
271+ g_pProxyDevice->SetVertexDeclaration (pPreviousDecl);
272+ SAFE_RELEASE (pPreviousDecl);
273+ return false ;
274+ }
275+
276+ SAFE_RELEASE (m_pOldVertexDeclaration);
277+ m_pOldVertexDeclaration = pPreviousDecl;
278+ return true ;
208279}
209280
210281// /////////////////////////////////////////////////////////////
@@ -249,6 +320,38 @@ bool CAdditionalVertexStreamManager::UpdateAdditionalStreamContent(SCurrentState
249320 uint NumVerts = ReadSize / StridePT;
250321 assert (NumVerts == WriteSize / StrideN);
251322
323+ if (ReadSize == 0 || WriteSize == 0 )
324+ return false ;
325+
326+ if ((ReadSize % StridePT) != 0 )
327+ return false ;
328+
329+ if ((WriteSize % StrideN) != 0 )
330+ return false ;
331+
332+ if (WriteSize != NumVerts * StrideN)
333+ return false ;
334+
335+ if (NumVerts == 0 )
336+ return false ;
337+
338+ const UINT bufferSizePT = state.decl .VertexBufferDesc1 .Size ;
339+ if (ReadOffsetStart > bufferSizePT)
340+ return false ;
341+
342+ if (ReadSize > bufferSizePT - ReadOffsetStart)
343+ return false ;
344+
345+ D3DVERTEXBUFFER_DESC destDesc;
346+ if (FAILED (pStreamDataN->GetDesc (&destDesc)))
347+ return false ;
348+
349+ if (WriteOffsetStart > destDesc.Size )
350+ return false ;
351+
352+ if (WriteSize > destDesc.Size - WriteOffsetStart)
353+ return false ;
354+
252355 // Get the source vertex bytes
253356 std::vector<uchar> sourceArray;
254357 sourceArray.resize (ReadSize);
@@ -269,47 +372,73 @@ bool CAdditionalVertexStreamManager::UpdateAdditionalStreamContent(SCurrentState
269372 // Compute dest bytes
270373 {
271374 // Get index buffer
272- if (FAILED (m_pDevice->GetIndices (&state.pIndexData )))
375+ if (FAILED (m_pDevice->GetIndices (&state.pIndexData )) || !state. pIndexData )
273376 return false ;
274377
275378 // Get index buffer desc
276379 D3DINDEXBUFFER_DESC IndexBufferDesc;
277380 state.pIndexData ->GetDesc (&IndexBufferDesc);
278381
382+ uint indexStride = 0 ;
383+ if (IndexBufferDesc.Format == D3DFMT_INDEX16)
384+ indexStride = sizeof (WORD);
385+ else if (IndexBufferDesc.Format == D3DFMT_INDEX32)
386+ indexStride = sizeof (DWORD);
387+ else
388+ return false ;
389+
279390 uint numIndices = state.args .primCount + 2 ;
280391 uint step = 1 ;
281392 if (state.args .PrimitiveType == D3DPT_TRIANGLELIST)
282393 {
283394 numIndices = state.args .primCount * 3 ;
284395 step = 3 ;
285396 }
286- assert (IndexBufferDesc.Size >= (numIndices + state.args .startIndex ) * 2 );
287397
288- // Get index buffer data
289- std::vector<uchar> indexArray;
290- indexArray.resize (ReadSize);
291- uchar* pIndexArrayBytes = &indexArray[0 ];
398+ size_t startByte = static_cast <size_t >(state.args .startIndex ) * indexStride;
399+ size_t requiredBytes = static_cast <size_t >(numIndices) * indexStride;
400+ if (startByte > IndexBufferDesc.Size )
401+ return false ;
402+
403+ if (requiredBytes > IndexBufferDesc.Size - startByte)
404+ return false ;
405+
406+ std::vector<uint32_t > indices (numIndices);
292407 {
293408 void * pIndexBytes = nullptr ;
294- if (FAILED (state.pIndexData ->Lock (state.args .startIndex * 2 , numIndices * 2 , &pIndexBytes, D3DLOCK_NOSYSLOCK | D3DLOCK_READONLY)))
409+ if (FAILED (state.pIndexData ->Lock (static_cast <UINT>(startByte), static_cast <UINT>(requiredBytes), &pIndexBytes,
410+ D3DLOCK_NOSYSLOCK | D3DLOCK_READONLY)))
295411 return false ;
296- memcpy (pIndexArrayBytes, pIndexBytes, numIndices * 2 );
412+
413+ if (indexStride == sizeof (WORD))
414+ {
415+ const WORD* pSrc = static_cast <const WORD*>(pIndexBytes);
416+ for (uint i = 0 ; i < numIndices; ++i)
417+ indices[i] = pSrc[i];
418+ }
419+ else
420+ {
421+ const DWORD* pSrc = static_cast <const DWORD*>(pIndexBytes);
422+ for (uint i = 0 ; i < numIndices; ++i)
423+ indices[i] = pSrc[i];
424+ }
425+
297426 state.pIndexData ->Unlock ();
298427 }
299428
300429 // Calc normals
301430 std::vector<CVector> NormalList;
302431 NormalList.insert (NormalList.end (), NumVerts, CVector ());
303432
304- std::map<long long , CVector> doneTrisMap;
433+ std::map<STriKey , CVector> doneTrisMap;
305434
306435 // For each triangle
307436 for (uint i = 0 ; i < numIndices - 2 ; i += step)
308437 {
309438 // Get triangle vertex indici
310- WORD v0 = ((WORD*)pIndexArrayBytes) [i];
311- WORD v1 = ((WORD*)pIndexArrayBytes) [i + 1 ];
312- WORD v2 = ((WORD*)pIndexArrayBytes) [i + 2 ];
439+ uint32_t v0 = indices [i];
440+ uint32_t v1 = indices [i + 1 ];
441+ uint32_t v2 = indices [i + 2 ];
313442
314443 if (v0 >= NumVerts || v1 >= NumVerts || v2 >= NumVerts)
315444 continue ; // vert index out of range
@@ -318,9 +447,9 @@ bool CAdditionalVertexStreamManager::UpdateAdditionalStreamContent(SCurrentState
318447 continue ; // degenerate tri
319448
320449 // Get vertex positions from original stream
321- CVector* pPos0 = ( CVector*) (pSourceArrayBytes + v0 * 20 );
322- CVector* pPos1 = ( CVector*) (pSourceArrayBytes + v1 * 20 );
323- CVector* pPos2 = ( CVector*) (pSourceArrayBytes + v2 * 20 );
450+ CVector* pPos0 = reinterpret_cast < CVector*> (pSourceArrayBytes + v0 * StridePT );
451+ CVector* pPos1 = reinterpret_cast < CVector*> (pSourceArrayBytes + v1 * StridePT );
452+ CVector* pPos2 = reinterpret_cast < CVector*> (pSourceArrayBytes + v2 * StridePT );
324453
325454 // Calculate the normal
326455 CVector Dir1 = *pPos2 - *pPos1;
@@ -335,7 +464,7 @@ bool CAdditionalVertexStreamManager::UpdateAdditionalStreamContent(SCurrentState
335464 Normal = -Normal;
336465
337466 // Try to improve results by ignoring duplicated triangles
338- long long key = getTriKey (v0, v1, v2);
467+ STriKey key = GetTriKey (v0, v1, v2);
339468 if (CVector* pDoneTriPrevNormal = MapFind (doneTrisMap, key))
340469 {
341470 // Already done this tri - Keep prev tri if it has a better 'up' rating
@@ -365,7 +494,7 @@ bool CAdditionalVertexStreamManager::UpdateAdditionalStreamContent(SCurrentState
365494 Normal = CVector (0 , 0 , 1 );
366495
367496 // Set
368- CVector* pNormal = ( CVector*) (pDestArrayBytes + i * 12 );
497+ CVector* pNormal = reinterpret_cast < CVector*> (pDestArrayBytes + i * StrideN );
369498 *pNormal = Normal;
370499 }
371500 }
@@ -504,7 +633,7 @@ SAdditionalStreamInfo* CAdditionalVertexStreamManager::CreateAdditionalStreamInf
504633
505634 // Create new stream
506635 info.Stride = sizeof (float ) * 3 ;
507- UINT Size2 = ConvertPTSize (state.decl .VertexBufferDesc1 .Size );
636+ UINT Size2 = ConvertPTSize (state.decl .VertexBufferDesc1 .Size );
508637 if (FAILED (m_pDevice->CreateVertexBuffer (Size2, D3DUSAGE_WRITEONLY, 0 , D3DPOOL_MANAGED, &info.pStreamData , nullptr )))
509638 {
510639 SAFE_RELEASE (info.pVertexDeclaration );
@@ -549,7 +678,26 @@ void CAdditionalVertexStreamManager::OnVertexBufferRangeInvalidated(IDirect3DVer
549678 SAdditionalStreamInfo* pAdditionalInfo = GetAdditionalStreamInfo (pStreamData1);
550679 if (pAdditionalInfo)
551680 {
552- pAdditionalInfo->ConvertedRanges .UnsetRange (Offset, Size);
681+ if (Size == 0 )
682+ {
683+ pAdditionalInfo->ConvertedRanges = CRanges ();
684+ return ;
685+ }
686+
687+ uint convertedOffset = ConvertPTOffset (Offset);
688+
689+ uint verticesTouched = Size / 20 ;
690+ if ((Size % 20 ) != 0 )
691+ ++verticesTouched;
692+
693+ if (verticesTouched == 0 )
694+ verticesTouched = 1 ;
695+
696+ uint64_t convertedSize64 = static_cast <uint64_t >(verticesTouched) * static_cast <uint64_t >(pAdditionalInfo->Stride );
697+ uint convertedSize = convertedSize64 > std::numeric_limits<uint>::max () ? std::numeric_limits<uint>::max ()
698+ : static_cast <uint>(convertedSize64);
699+
700+ pAdditionalInfo->ConvertedRanges .UnsetRange (convertedOffset, convertedSize);
553701 }
554702}
555703
0 commit comments