@@ -2042,9 +2042,9 @@ public static async Task<TTModel> LoadExternalModel(string externalPath, ModelIm
2042
2042
/// <param name="ogMdl"></param>
2043
2043
/// <param name="loggingFunction"></param>
2044
2044
/// <returns></returns>
2045
- public static async Task < byte [ ] > MakeCompressedMdlFile ( TTModel ttModel , XivMdl ogMdl , Action < bool , string > loggingFunction = null )
2045
+ public static async Task < byte [ ] > MakeCompressedMdlFile ( TTModel ttModel , XivMdl ogMdl , Action < bool , string > loggingFunction = null , bool upgradePrecision = true )
2046
2046
{
2047
- var mdl = MakeUncompressedMdlFile ( ttModel , ogMdl , loggingFunction ) ;
2047
+ var mdl = MakeUncompressedMdlFile ( ttModel , ogMdl , loggingFunction , upgradePrecision ) ;
2048
2048
var compressed = await CompressMdlFile ( mdl ) ;
2049
2049
return compressed ;
2050
2050
}
@@ -2371,17 +2371,24 @@ public static async Task<byte[]> MakeUncompressedMdlFile(TTModel model, string t
2371
2371
return MakeUncompressedMdlFile ( model , xivMdl , loggingFunction ) ;
2372
2372
2373
2373
}
2374
+
2375
+ // I do not know where in FFXIV's model pipeline this limit comes from,
2376
+ // but vertex buffers larger than 2^23 will overflow and wrap around in game.
2377
+ public const int _MaxVertexBufferSize = 8388608 ;
2378
+
2379
+
2374
2380
/// <summary>
2375
2381
/// Creates a new Uncompressed MDL file from the given information.
2376
2382
/// OGMdl is used to fill in gaps in data types we do not know about.
2377
2383
/// TODO: It should be possible at this point to adjust this function to accomodate [null] ogMDLs.
2378
2384
/// </summary>
2379
2385
/// <param name="ttModel">The ttModel to import</param>
2380
2386
/// <param name="ogMdl">The currently modified Mdl file.</param>
2381
- public static byte [ ] MakeUncompressedMdlFile ( TTModel ttModel , XivMdl ogMdl , Action < bool , string > loggingFunction = null )
2387
+ public static byte [ ] MakeUncompressedMdlFile ( TTModel ttModel , XivMdl ogMdl , Action < bool , string > loggingFunction = null , bool upgradePrecision = true )
2382
2388
{
2383
2389
var mdlVersion = ttModel . MdlVersion > 0 ? ttModel . MdlVersion : ogMdl . MdlVersion ;
2384
2390
2391
+
2385
2392
// Debug Code
2386
2393
/*
2387
2394
var root = XivCache.GetFilePathRoot(ogMdl.MdlPath);
@@ -2393,10 +2400,6 @@ public static byte[] MakeUncompressedMdlFile(TTModel ttModel, XivMdl ogMdl, Acti
2393
2400
2394
2401
byte _LoDCount = 1 ;
2395
2402
2396
- // Pipe some user var down here and we could ship this toggle.
2397
- // Not really much reason to ever use lower precision other than file size/perf though.
2398
- bool _UpgradePrecision = true ;
2399
-
2400
2403
// Distance used for model LoD settings. 0 is infinite.
2401
2404
float _ModelLoDDistance = 0.0f ;
2402
2405
@@ -2411,6 +2414,33 @@ public static byte[] MakeUncompressedMdlFile(TTModel ttModel, XivMdl ogMdl, Acti
2411
2414
2412
2415
try
2413
2416
{
2417
+ var usageInfo = ttModel . GetUsageInfo ( ) ;
2418
+
2419
+ var vertexSize = 48 ;
2420
+ if ( usageInfo . NeedsEightWeights )
2421
+ {
2422
+ vertexSize += 8 ;
2423
+ }
2424
+ if ( usageInfo . UsesUv2 )
2425
+ {
2426
+ vertexSize += 8 ;
2427
+ }
2428
+ if ( usageInfo . UsesVColor2 )
2429
+ {
2430
+ vertexSize += 4 ;
2431
+ }
2432
+ var shapeVertCount = ttModel . MeshGroups . Sum ( m => m . Parts . Sum ( p => p . ShapeParts . Sum ( s => s . Value . Vertices . Count ) ) ) ;
2433
+ var totalVertexCount = shapeVertCount + ttModel . VertexCount ;
2434
+ var estimatedVertexBufferSize = ( vertexSize * totalVertexCount ) ;
2435
+
2436
+ if ( estimatedVertexBufferSize >= _MaxVertexBufferSize )
2437
+ {
2438
+ upgradePrecision = false ;
2439
+ }
2440
+
2441
+
2442
+
2443
+
2414
2444
ttModel . OrderMeshGroupsForImport ( ) ;
2415
2445
var rawShapeData = ttModel . GetRawShapeParts ( ) ;
2416
2446
@@ -2492,8 +2522,7 @@ public static byte[] MakeUncompressedMdlFile(TTModel ttModel, XivMdl ogMdl, Acti
2492
2522
source . OrderBy ( x => ( x . DataBlock * - 1000 ) + x . DataOffset ) ;
2493
2523
vertexStreamCounts . Add ( source . Max ( x => x . DataBlock ) + 1 ) ;
2494
2524
2495
- // If we're upgrading precision on a v6 mdl, might as well add all the bells and whistles.
2496
- if ( mdlVersion >= 6 && _UpgradePrecision )
2525
+ if ( upgradePrecision )
2497
2526
{
2498
2527
// Add precomputed tangent data.
2499
2528
var tangentCount = source . Count ( x => x . DataUsage == VertexUsageType . Tangent ) ;
@@ -2508,9 +2537,14 @@ public static byte[] MakeUncompressedMdlFile(TTModel ttModel, XivMdl ogMdl, Acti
2508
2537
DataType = VertexDataType . Ubyte4n ,
2509
2538
DataUsage = VertexUsageType . Tangent
2510
2539
} ) ;
2511
-
2512
2540
}
2513
-
2541
+ } else
2542
+ {
2543
+ source . RemoveAll ( x => x . DataUsage == VertexUsageType . Tangent ) ;
2544
+ }
2545
+
2546
+ if ( usageInfo . UsesVColor2 )
2547
+ {
2514
2548
// Add 2nd color channel for faux-wind simulation.
2515
2549
var colorCounts = source . Count ( x => x . DataUsage == VertexUsageType . Color ) ;
2516
2550
var colorIdx = source . FindIndex ( x => x . DataUsage == VertexUsageType . Color ) ;
@@ -2524,6 +2558,41 @@ public static byte[] MakeUncompressedMdlFile(TTModel ttModel, XivMdl ogMdl, Acti
2524
2558
DataUsage = VertexUsageType . Color
2525
2559
} ) ;
2526
2560
}
2561
+ } else
2562
+ {
2563
+ source . RemoveAll ( x => x . DataUsage == VertexUsageType . Color && x . Count == 1 ) ;
2564
+ }
2565
+
2566
+ if ( ttModel . HasWeights )
2567
+ {
2568
+ // Ensure we have bone vertex structs if we need them.
2569
+ var bone = source . FirstOrDefault ( x => x . DataUsage == VertexUsageType . BoneWeight ) ;
2570
+ if ( bone == null )
2571
+ {
2572
+ source . Add ( new VertexDataStruct ( )
2573
+ {
2574
+ DataBlock = 0 ,
2575
+ DataOffset = 0 ,
2576
+ DataType = VertexDataType . Ubyte4 ,
2577
+ DataUsage = VertexUsageType . BoneWeight
2578
+ } ) ;
2579
+ }
2580
+ bone = source . FirstOrDefault ( x => x . DataUsage == VertexUsageType . BoneIndex ) ;
2581
+ if ( bone == null )
2582
+ {
2583
+ source . Add ( new VertexDataStruct ( )
2584
+ {
2585
+ DataBlock = 0 ,
2586
+ DataOffset = 0 ,
2587
+ DataType = VertexDataType . Ubyte4 ,
2588
+ DataUsage = VertexUsageType . BoneIndex
2589
+ } ) ;
2590
+ }
2591
+ } else
2592
+ {
2593
+ // Remove bone vertex structs if they're not used.
2594
+ source . RemoveAll ( x => x . DataUsage == VertexUsageType . BoneWeight ) ;
2595
+ source . RemoveAll ( x => x . DataUsage == VertexUsageType . BoneIndex ) ;
2527
2596
}
2528
2597
2529
2598
foreach ( var vds in source )
@@ -2542,7 +2611,7 @@ public static byte[] MakeUncompressedMdlFile(TTModel ttModel, XivMdl ogMdl, Acti
2542
2611
// Perform precision updates if requested, and adjustments for MDL version.
2543
2612
if ( dataUsage == VertexUsageType . Position )
2544
2613
{
2545
- if ( _UpgradePrecision )
2614
+ if ( upgradePrecision )
2546
2615
{
2547
2616
dataType = VertexDataType . Float3 ;
2548
2617
}
@@ -2554,7 +2623,7 @@ public static byte[] MakeUncompressedMdlFile(TTModel ttModel, XivMdl ogMdl, Acti
2554
2623
2555
2624
if ( dataUsage == VertexUsageType . BoneWeight )
2556
2625
{
2557
- if ( mdlVersion >= 6 && _UpgradePrecision )
2626
+ if ( usageInfo . NeedsEightWeights )
2558
2627
{
2559
2628
dataType = VertexDataType . UByte8 ;
2560
2629
}
@@ -2566,7 +2635,7 @@ public static byte[] MakeUncompressedMdlFile(TTModel ttModel, XivMdl ogMdl, Acti
2566
2635
2567
2636
if ( dataUsage == VertexUsageType . BoneIndex )
2568
2637
{
2569
- if ( mdlVersion >= 6 && _UpgradePrecision )
2638
+ if ( usageInfo . NeedsEightWeights )
2570
2639
{
2571
2640
dataType = VertexDataType . UByte8 ;
2572
2641
}
@@ -2578,7 +2647,7 @@ public static byte[] MakeUncompressedMdlFile(TTModel ttModel, XivMdl ogMdl, Acti
2578
2647
2579
2648
if ( dataUsage == VertexUsageType . Normal )
2580
2649
{
2581
- if ( _UpgradePrecision )
2650
+ if ( upgradePrecision )
2582
2651
{
2583
2652
dataType = VertexDataType . Float3 ;
2584
2653
}
@@ -2590,26 +2659,25 @@ public static byte[] MakeUncompressedMdlFile(TTModel ttModel, XivMdl ogMdl, Acti
2590
2659
2591
2660
if ( dataUsage == VertexUsageType . TextureCoordinate )
2592
2661
{
2593
- if ( _UpgradePrecision )
2662
+ if ( upgradePrecision )
2594
2663
{
2595
- if ( dataType == VertexDataType . Half2 )
2664
+ if ( usageInfo . UsesUv2 )
2596
2665
{
2597
- dataType = VertexDataType . Float2 ;
2666
+ dataType = VertexDataType . Float4 ;
2598
2667
}
2599
- else if ( dataType == VertexDataType . Half4 )
2668
+ else
2600
2669
{
2601
- dataType = VertexDataType . Float4 ;
2670
+ dataType = VertexDataType . Float2 ;
2602
2671
}
2603
2672
}
2604
2673
else
2605
2674
{
2606
- if ( dataType == VertexDataType . Float2 )
2607
- {
2608
- dataType = VertexDataType . Half2 ;
2609
- }
2610
- else if ( dataType == VertexDataType . Float4 )
2675
+ if ( usageInfo . UsesUv2 )
2611
2676
{
2612
2677
dataType = VertexDataType . Half4 ;
2678
+ } else
2679
+ {
2680
+ dataType = VertexDataType . Half2 ;
2613
2681
}
2614
2682
}
2615
2683
}
@@ -2711,6 +2779,12 @@ public static byte[] MakeUncompressedMdlFile(TTModel ttModel, XivMdl ogMdl, Acti
2711
2779
2712
2780
Dat . Pad ( indexDataBlock , 16 ) ;
2713
2781
}
2782
+
2783
+ if ( vertexDataBlock . Count > _MaxVertexBufferSize )
2784
+ {
2785
+ throw new InvalidDataException ( $ "Total Vertex buffer data size is too large, even after compression attempts:\n Total Size: { vertexDataBlock . Count } \n Max Size: { _MaxVertexBufferSize } \n \n Please reduce the total number of Vertices in the model:\n Vertices (After Unwelding): { totalVertexCount } ") ;
2786
+ }
2787
+
2714
2788
#endregion
2715
2789
2716
2790
// Path Data
0 commit comments