11
11
12
12
#include " StdInc.h"
13
13
#include " CAdditionalVertexStreamManager.h"
14
+ #include < limits>
14
15
15
16
CAdditionalVertexStreamManager* CAdditionalVertexStreamManager::ms_Singleton = nullptr ;
16
17
17
18
namespace
18
19
{
19
20
// Helper functions for this file only
20
21
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
+ };
23
52
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)
26
55
{
27
- WORD tmp;
56
+ uint32_t tmp;
28
57
if (b < a)
29
58
{
30
59
tmp = b;
@@ -43,7 +72,8 @@ namespace
43
72
b = a;
44
73
a = tmp;
45
74
}
46
- return (((long long )a) << 32 ) | (((long long )b) << 16 ) | ((long long )c);
75
+ STriKey key = {a, b, c};
76
+ return key;
47
77
}
48
78
} // namespace
49
79
@@ -145,14 +175,14 @@ bool CAdditionalVertexStreamManager::MaybeSetAdditionalVertexStream(D3DPRIMITIVE
145
175
state.args .primCount = primCount;
146
176
147
177
// Cache info about state streams etc
148
- UpdateCurrentStateInfo (state);
178
+ if (!UpdateCurrentStateInfo (state))
179
+ return false ;
149
180
150
181
// 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
151
182
if (!CheckCanDoThis (state))
152
183
return false ;
153
184
154
- SetAdditionalVertexStream (state);
155
- return true ;
185
+ return SetAdditionalVertexStream (state);
156
186
}
157
187
158
188
// /////////////////////////////////////////////////////////////
@@ -162,7 +192,7 @@ bool CAdditionalVertexStreamManager::MaybeSetAdditionalVertexStream(D3DPRIMITIVE
162
192
//
163
193
//
164
194
// /////////////////////////////////////////////////////////////
165
- void CAdditionalVertexStreamManager::SetAdditionalVertexStream (SCurrentStateInfo& state)
195
+ bool CAdditionalVertexStreamManager::SetAdditionalVertexStream (SCurrentStateInfo& state)
166
196
{
167
197
HRESULT hr;
168
198
@@ -171,40 +201,81 @@ void CAdditionalVertexStreamManager::SetAdditionalVertexStream(SCurrentStateInfo
171
201
if (!pAdditionalInfo)
172
202
pAdditionalInfo = CreateAdditionalStreamInfo (state);
173
203
204
+ if (!pAdditionalInfo)
205
+ return false ;
206
+
174
207
uint StridePT = 20 ;
175
208
uint StrideN = 12 ;
176
209
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 ;
180
211
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 ;
183
220
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);
187
229
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));
189
247
assert (WriteOffsetSize == ConvertPTSize (ReadOffsetSize));
190
248
191
249
// See if area VB area needs updating
192
250
if (!pAdditionalInfo->ConvertedRanges .IsRangeSet (WriteOffsetStart, WriteOffsetSize))
193
251
{
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
+
196
255
pAdditionalInfo->ConvertedRanges .SetRange (WriteOffsetStart, WriteOffsetSize);
197
256
}
198
257
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 ;
201
261
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
+ }
204
267
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 ;
208
279
}
209
280
210
281
// /////////////////////////////////////////////////////////////
@@ -249,6 +320,38 @@ bool CAdditionalVertexStreamManager::UpdateAdditionalStreamContent(SCurrentState
249
320
uint NumVerts = ReadSize / StridePT;
250
321
assert (NumVerts == WriteSize / StrideN);
251
322
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
+
252
355
// Get the source vertex bytes
253
356
std::vector<uchar> sourceArray;
254
357
sourceArray.resize (ReadSize);
@@ -269,47 +372,73 @@ bool CAdditionalVertexStreamManager::UpdateAdditionalStreamContent(SCurrentState
269
372
// Compute dest bytes
270
373
{
271
374
// Get index buffer
272
- if (FAILED (m_pDevice->GetIndices (&state.pIndexData )))
375
+ if (FAILED (m_pDevice->GetIndices (&state.pIndexData )) || !state. pIndexData )
273
376
return false ;
274
377
275
378
// Get index buffer desc
276
379
D3DINDEXBUFFER_DESC IndexBufferDesc;
277
380
state.pIndexData ->GetDesc (&IndexBufferDesc);
278
381
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
+
279
390
uint numIndices = state.args .primCount + 2 ;
280
391
uint step = 1 ;
281
392
if (state.args .PrimitiveType == D3DPT_TRIANGLELIST)
282
393
{
283
394
numIndices = state.args .primCount * 3 ;
284
395
step = 3 ;
285
396
}
286
- assert (IndexBufferDesc.Size >= (numIndices + state.args .startIndex ) * 2 );
287
397
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);
292
407
{
293
408
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)))
295
411
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
+
297
426
state.pIndexData ->Unlock ();
298
427
}
299
428
300
429
// Calc normals
301
430
std::vector<CVector> NormalList;
302
431
NormalList.insert (NormalList.end (), NumVerts, CVector ());
303
432
304
- std::map<long long , CVector> doneTrisMap;
433
+ std::map<STriKey , CVector> doneTrisMap;
305
434
306
435
// For each triangle
307
436
for (uint i = 0 ; i < numIndices - 2 ; i += step)
308
437
{
309
438
// 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 ];
313
442
314
443
if (v0 >= NumVerts || v1 >= NumVerts || v2 >= NumVerts)
315
444
continue ; // vert index out of range
@@ -318,9 +447,9 @@ bool CAdditionalVertexStreamManager::UpdateAdditionalStreamContent(SCurrentState
318
447
continue ; // degenerate tri
319
448
320
449
// 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 );
324
453
325
454
// Calculate the normal
326
455
CVector Dir1 = *pPos2 - *pPos1;
@@ -335,7 +464,7 @@ bool CAdditionalVertexStreamManager::UpdateAdditionalStreamContent(SCurrentState
335
464
Normal = -Normal;
336
465
337
466
// Try to improve results by ignoring duplicated triangles
338
- long long key = getTriKey (v0, v1, v2);
467
+ STriKey key = GetTriKey (v0, v1, v2);
339
468
if (CVector* pDoneTriPrevNormal = MapFind (doneTrisMap, key))
340
469
{
341
470
// Already done this tri - Keep prev tri if it has a better 'up' rating
@@ -365,7 +494,7 @@ bool CAdditionalVertexStreamManager::UpdateAdditionalStreamContent(SCurrentState
365
494
Normal = CVector (0 , 0 , 1 );
366
495
367
496
// Set
368
- CVector* pNormal = ( CVector*) (pDestArrayBytes + i * 12 );
497
+ CVector* pNormal = reinterpret_cast < CVector*> (pDestArrayBytes + i * StrideN );
369
498
*pNormal = Normal;
370
499
}
371
500
}
@@ -504,7 +633,7 @@ SAdditionalStreamInfo* CAdditionalVertexStreamManager::CreateAdditionalStreamInf
504
633
505
634
// Create new stream
506
635
info.Stride = sizeof (float ) * 3 ;
507
- UINT Size2 = ConvertPTSize (state.decl .VertexBufferDesc1 .Size );
636
+ UINT Size2 = ConvertPTSize (state.decl .VertexBufferDesc1 .Size );
508
637
if (FAILED (m_pDevice->CreateVertexBuffer (Size2, D3DUSAGE_WRITEONLY, 0 , D3DPOOL_MANAGED, &info.pStreamData , nullptr )))
509
638
{
510
639
SAFE_RELEASE (info.pVertexDeclaration );
@@ -549,6 +678,25 @@ void CAdditionalVertexStreamManager::OnVertexBufferRangeInvalidated(IDirect3DVer
549
678
SAdditionalStreamInfo* pAdditionalInfo = GetAdditionalStreamInfo (pStreamData1);
550
679
if (pAdditionalInfo)
551
680
{
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);
553
701
}
554
702
}
0 commit comments