@@ -8,7 +8,7 @@ namespace Sandbox;
88
99public partial class TerrainStorage
1010{
11- public override int ResourceVersion => 1 ;
11+ public override int ResourceVersion => 2 ;
1212
1313 [ Expose , JsonUpgrader ( typeof ( TerrainStorage ) , 1 ) ]
1414 static void Upgrader_v1 ( JsonObject obj )
@@ -48,6 +48,69 @@ static void Upgrader_v1( JsonObject obj )
4848 obj . Remove ( "RootObject" ) ;
4949 }
5050
51+ [ Expose , JsonUpgrader ( typeof ( TerrainStorage ) , 2 ) ]
52+ static void Upgrader_v2 ( JsonObject obj )
53+ {
54+ if ( obj [ "Maps" ] is not JsonObject maps )
55+ return ;
56+
57+ if ( maps . ContainsKey ( "indexedsplatmap" ) )
58+ return ;
59+
60+ if ( maps [ "splatmap" ] is not JsonValue splatmapValue )
61+ return ;
62+
63+ // We need to convert our old splatmat(RGBA) into an indexed control map which contains much more information
64+ // that is all packed together. We also merge our hole map into a single bit of our new indexed map.
65+ var splatmapBase64 = splatmapValue . Deserialize < string > ( ) ;
66+ var splatmapData = TerrainMaps . Decompress < Color32 > ( Convert . FromBase64String ( splatmapBase64 ) ) ;
67+
68+ // Cache holes map, so we can pack it
69+ byte [ ] holesData = null ;
70+ if ( maps [ "holesmap" ] is JsonValue holesValue )
71+ {
72+ var holesBase64 = holesValue . Deserialize < string > ( ) ;
73+ holesData = TerrainMaps . Decompress < byte > ( Convert . FromBase64String ( holesBase64 ) ) . ToArray ( ) ;
74+ }
75+
76+ var compactData = new CompactTerrainMaterial [ splatmapData . Length ] ;
77+
78+ // Take the top two most contributing materials, and pack them with base material + overlay with the weight
79+ for ( int i = 0 ; i < splatmapData . Length ; i ++ )
80+ {
81+ var legacy = splatmapData [ i ] ;
82+ bool isHole = holesData != null && holesData [ i ] != 0 ;
83+
84+ // Find the two materials with highest weights
85+ var topTwo = new [ ] { ( legacy . r , 0 ) , ( legacy . g , 1 ) , ( legacy . b , 2 ) , ( legacy . a , 3 ) }
86+ . OrderByDescending ( x => x . Item1 )
87+ . Take ( 2 )
88+ . ToArray ( ) ;
89+
90+ // Calculate blend factor between base and overlay
91+ byte blendFactor = 0 ;
92+ int totalWeight = topTwo [ 0 ] . Item1 + topTwo [ 1 ] . Item1 ;
93+ if ( totalWeight > 0 )
94+ {
95+ blendFactor = ( byte ) ( ( topTwo [ 1 ] . Item1 * 255 ) / totalWeight ) ;
96+ }
97+
98+ compactData [ i ] = new CompactTerrainMaterial (
99+ baseTextureId : ( byte ) topTwo [ 0 ] . Item2 ,
100+ overlayTextureId : ( byte ) topTwo [ 1 ] . Item2 ,
101+ blendFactor : blendFactor ,
102+ isHole : isHole
103+ ) ;
104+ }
105+
106+ // Add compact format to maps
107+ var compactBase64 = Convert . ToBase64String ( TerrainMaps . Compress < CompactTerrainMaterial > ( compactData ) ) ;
108+ maps [ "splatmap" ] = compactBase64 ;
109+
110+ // Remove legacy holesmap
111+ maps . Remove ( "holesmap" ) ;
112+ }
113+
51114 static Span < ushort > ResampleHeightmap ( Span < ushort > original , int originalSize , int newSize )
52115 {
53116 // Create SKBitmap with the original data copied in
0 commit comments