2017-01-20 08:36:52 -05:00
# include "STDInclude.hpp"
2017-01-19 16:23:59 -05:00
2017-03-18 10:19:31 -04:00
# define IW4X_MAT_VERSION "1"
2017-01-19 16:23:59 -05:00
namespace Assets
{
2018-12-17 08:29:18 -05:00
void IMaterial : : load ( Game : : XAssetHeader * header , const std : : string & name , Components : : ZoneBuilder : : Zone * builder )
2017-01-19 16:23:59 -05:00
{
if ( ! header - > data ) this - > loadJson ( header , name , builder ) ; // Check if we want to override materials
if ( ! header - > data ) this - > loadNative ( header , name , builder ) ; // Check if there is a native one
if ( ! header - > data ) this - > loadBinary ( header , name , builder ) ; // Check if we need to import a new one into the game
}
2018-12-17 08:29:18 -05:00
void IMaterial : : loadBinary ( Game : : XAssetHeader * header , const std : : string & name , Components : : ZoneBuilder : : Zone * builder )
2017-01-19 16:23:59 -05:00
{
2017-05-30 04:03:12 -04:00
static const char * techsetSuffix [ ] =
{
" _lin " ,
" _add_lin " ,
" _replace " ,
" _eyeoffset " ,
" _blend " ,
" _blend_nofog " ,
" _add " ,
" _nofog " ,
" _nocast " ,
2017-06-02 16:18:14 -04:00
" _add_lin_nofog " ,
2017-05-30 04:03:12 -04:00
} ;
2021-04-04 06:06:24 -04:00
std : : map < std : : string , std : : string > techSetCorrespondance = {
{ " effect_zfeather_outdoor " , " effect_zfeather_blend " } ,
{ " effect " , " effect_blend " } ,
2021-04-05 17:18:59 -04:00
{ " effect_nofog " , " effect_blend_nofog " } ,
{ " wc_unlit_add " , " wc_unlit_add_lin " } ,
{ " wc_unlit_multiply " , " wc_unlit_multiply_lin " } ,
{ " wc_unlit_falloff_add " , " wc_unlit_falloff_add_lin_ua " } ,
{ " mc_unlit_replace " , " mc_unlit_replace_lin " } ,
{ " mc_unlit_nofog " , " mc_unlit_blend_nofog_ua " } ,
{ " wc_unlit " , " wc_unlit_add " } ,
{ " wc_unlit_multiply_lin " , " wc_unlit_multiply_lin " } ,
{ " wc_unlit_blend " , " wc_unlit_blend_lin " } ,
{ " mc_unlit " , " mc_unlit_replace_lin " } /*,
{ " " , " " } ,
{ " " , " " } ,
{ " " , " " } ,
{ " " , " " } ,
{ " " , " " } ,
{ " " , " " } , */
2021-04-04 06:06:24 -04:00
} ;
2017-01-19 16:23:59 -05:00
Components : : FileSystem : : File materialFile ( Utils : : String : : VA ( " materials/%s.iw4xMaterial " , name . data ( ) ) ) ;
if ( ! materialFile . exists ( ) ) return ;
Utils : : Stream : : Reader reader ( builder - > getAllocator ( ) , materialFile . getBuffer ( ) ) ;
2017-03-18 10:19:31 -04:00
char * magic = reader . readArray < char > ( 7 ) ;
if ( std : : memcmp ( magic , " IW4xMat " , 7 ) )
2017-01-19 16:23:59 -05:00
{
Components : : Logger : : Error ( 0 , " Reading material '%s' failed, header is invalid! " , name . data ( ) ) ;
}
2017-03-18 10:19:31 -04:00
std : : string version ;
version . push_back ( reader . read < char > ( ) ) ;
if ( version ! = IW4X_MAT_VERSION )
2017-01-19 16:23:59 -05:00
{
2017-03-18 10:19:31 -04:00
Components : : Logger : : Error ( " Reading material '%s' failed, expected version is %d, but it was %d! " , name . data ( ) , atoi ( IW4X_MAT_VERSION ) , atoi ( version . data ( ) ) ) ;
2017-01-19 16:23:59 -05:00
}
2017-03-18 10:19:31 -04:00
Game : : Material * asset = reader . readObject < Game : : Material > ( ) ;
2017-01-19 16:23:59 -05:00
2018-05-09 08:33:52 -04:00
if ( asset - > info . name )
2017-01-19 16:23:59 -05:00
{
2018-05-09 08:33:52 -04:00
asset - > info . name = reader . readCString ( ) ;
2017-01-19 16:23:59 -05:00
}
2017-03-18 10:19:31 -04:00
if ( asset - > techniqueSet )
2017-01-19 16:23:59 -05:00
{
2017-03-18 10:19:31 -04:00
std : : string techset = reader . readString ( ) ;
2017-04-03 16:08:02 -04:00
if ( ! techset . empty ( ) & & techset . front ( ) = = ' , ' ) techset . erase ( techset . begin ( ) ) ;
2017-03-18 10:19:31 -04:00
asset - > techniqueSet = Components : : AssetHandler : : FindAssetForZone ( Game : : XAssetType : : ASSET_TYPE_TECHNIQUE_SET , techset . data ( ) , builder ) . techniqueSet ;
2017-04-15 19:51:41 -04:00
if ( ! asset - > techniqueSet )
2017-03-18 10:19:31 -04:00
{
2017-04-20 15:52:50 -04:00
// Workaround for effect techsets having _nofog suffix
std : : string suffix ;
2017-04-24 15:14:32 -04:00
if ( Utils : : String : : StartsWith ( techset , " effect_ " ) & & Utils : : String : : EndsWith ( techset , " _nofog " ) )
2017-04-20 15:52:50 -04:00
{
suffix = " _nofog " ;
Utils : : String : : Replace ( techset , suffix , " " ) ;
}
2017-04-15 19:51:41 -04:00
for ( int i = 0 ; i < ARRAYSIZE ( techsetSuffix ) ; + + i )
2017-03-18 10:19:31 -04:00
{
2017-04-20 15:52:50 -04:00
Game : : MaterialTechniqueSet * techsetPtr = Components : : AssetHandler : : FindAssetForZone ( Game : : XAssetType : : ASSET_TYPE_TECHNIQUE_SET , ( techset + techsetSuffix [ i ] + suffix ) . data ( ) , builder ) . techniqueSet ;
2017-04-15 19:51:41 -04:00
if ( techsetPtr )
{
asset - > techniqueSet = techsetPtr ;
if ( asset - > techniqueSet - > name [ 0 ] = = ' , ' ) continue ; // Try to find a better one
Components : : Logger : : Print ( " Techset '%s' has been mapped to '%s' \n " , techset . data ( ) , asset - > techniqueSet - > name ) ;
break ;
}
2017-03-18 10:19:31 -04:00
}
2017-01-19 16:23:59 -05:00
}
2017-03-18 10:19:31 -04:00
if ( ! asset - > techniqueSet )
2017-01-19 16:23:59 -05:00
{
2017-05-04 06:30:39 -04:00
Components : : Logger : : Error ( " Missing techset: '%s' not found " , techset . data ( ) ) ;
2017-01-19 16:23:59 -05:00
}
}
2017-03-18 10:19:31 -04:00
if ( asset - > textureTable )
2017-01-19 16:23:59 -05:00
{
2017-03-18 10:19:31 -04:00
asset - > textureTable = reader . readArray < Game : : MaterialTextureDef > ( asset - > textureCount ) ;
for ( char i = 0 ; i < asset - > textureCount ; + + i )
2017-01-19 16:23:59 -05:00
{
2017-03-18 10:19:31 -04:00
Game : : MaterialTextureDef * textureDef = & asset - > textureTable [ i ] ;
if ( textureDef - > semantic = = SEMANTIC_WATER_MAP )
{
2018-05-09 08:33:52 -04:00
if ( textureDef - > u . water )
2017-03-18 10:19:31 -04:00
{
Game : : water_t * water = reader . readObject < Game : : water_t > ( ) ;
2018-05-09 08:33:52 -04:00
textureDef - > u . water = water ;
2017-03-18 10:19:31 -04:00
// Save_water_t
if ( water - > H0 )
{
water - > H0 = reader . readArray < Game : : complex_s > ( water - > M * water - > N ) ;
}
if ( water - > wTerm )
{
water - > wTerm = reader . readArray < float > ( water - > M * water - > N ) ;
}
if ( water - > image )
{
water - > image = Components : : AssetHandler : : FindAssetForZone ( Game : : XAssetType : : ASSET_TYPE_IMAGE , reader . readString ( ) . data ( ) , builder ) . image ;
}
}
}
2018-05-09 08:33:52 -04:00
else if ( textureDef - > u . image )
2017-03-18 10:19:31 -04:00
{
2018-05-09 08:33:52 -04:00
textureDef - > u . image = Components : : AssetHandler : : FindAssetForZone ( Game : : XAssetType : : ASSET_TYPE_IMAGE , reader . readString ( ) . data ( ) , builder ) . image ;
2017-03-18 10:19:31 -04:00
}
2017-01-19 16:23:59 -05:00
}
2017-03-18 10:19:31 -04:00
}
2017-01-19 16:23:59 -05:00
2017-03-18 10:19:31 -04:00
if ( asset - > constantTable )
{
asset - > constantTable = reader . readArray < Game : : MaterialConstantDef > ( asset - > constantCount ) ;
}
2017-01-19 16:23:59 -05:00
2018-05-09 08:33:52 -04:00
if ( asset - > stateBitsTable )
2017-03-18 10:19:31 -04:00
{
2018-05-09 08:33:52 -04:00
asset - > stateBitsTable = reader . readArray < Game : : GfxStateBits > ( asset - > stateBitsCount ) ;
2017-01-19 16:23:59 -05:00
}
2017-03-18 10:19:31 -04:00
header - > material = asset ;
2017-01-19 16:23:59 -05:00
2017-04-15 16:50:20 -04:00
static thread_local bool replacementFound ;
replacementFound = false ;
2017-01-19 16:23:59 -05:00
// Find correct sortkey by comparing techsets
2017-05-01 07:08:34 -04:00
Game : : DB_EnumXAssetEntries ( Game : : XAssetType : : ASSET_TYPE_MATERIAL , [ asset ] ( Game : : XAssetEntry * entry )
2017-01-19 16:23:59 -05:00
{
2017-04-15 19:51:41 -04:00
if ( ! replacementFound )
2017-01-19 16:23:59 -05:00
{
2017-05-01 07:08:34 -04:00
Game : : XAssetHeader header = entry - > asset . header ;
const char * name = asset - > techniqueSet - > name ;
2017-04-15 19:51:41 -04:00
if ( name [ 0 ] = = ' , ' ) + + name ;
2017-01-19 16:23:59 -05:00
2017-04-15 19:51:41 -04:00
if ( std : : string ( name ) = = header . material - > techniqueSet - > name )
{
2018-05-09 08:33:52 -04:00
asset - > info . sortKey = header . material - > info . sortKey ;
2017-04-15 16:50:20 -04:00
2017-04-15 19:51:41 -04:00
// This is temp, as nobody has time to fix materials
2018-05-10 12:04:12 -04:00
asset - > stateBitsCount = header . material - > stateBitsCount ;
asset - > stateBitsTable = header . material - > stateBitsTable ;
std : : memcpy ( asset - > stateBitsEntry , header . material - > stateBitsEntry , 48 ) ;
2017-05-01 07:08:34 -04:00
asset - > constantCount = header . material - > constantCount ;
asset - > constantTable = header . material - > constantTable ;
2017-04-15 19:51:41 -04:00
replacementFound = true ;
}
2017-01-19 16:23:59 -05:00
}
2017-05-01 07:08:34 -04:00
} , false , false ) ;
2017-03-18 10:19:31 -04:00
2017-05-30 04:52:22 -04:00
if ( ! replacementFound )
2017-05-30 04:03:12 -04:00
{
2017-05-30 04:52:22 -04:00
auto techsetMatches = [ ] ( Game : : Material * m1 , Game : : Material * m2 )
{
Game : : MaterialTechniqueSet * t1 = m1 - > techniqueSet ;
Game : : MaterialTechniqueSet * t2 = m2 - > techniqueSet ;
if ( ! t1 | | ! t2 ) return false ;
2018-05-09 08:33:52 -04:00
if ( t1 - > remappedTechniqueSet & & t2 - > remappedTechniqueSet & & std : : string ( t1 - > remappedTechniqueSet - > name ) = = t2 - > remappedTechniqueSet - > name ) return true ;
2017-05-30 04:52:22 -04:00
for ( int i = 0 ; i < ARRAYSIZE ( t1 - > techniques ) ; + + i )
{
if ( ! t1 - > techniques [ i ] & & ! t2 - > techniques [ i ] ) continue ; ;
if ( ! t1 - > techniques [ i ] | | ! t2 - > techniques [ i ] ) return false ;
2021-04-04 06:06:24 -04:00
if ( t1 - > techniques [ i ] - > flags ! = t2 - > techniques [ i ] - > flags ) return false ;
2017-05-30 04:52:22 -04:00
}
2017-05-30 04:03:12 -04:00
2017-05-30 04:52:22 -04:00
return true ;
} ;
2017-05-30 04:03:12 -04:00
2021-04-04 06:06:24 -04:00
2017-05-30 04:52:22 -04:00
Game : : DB_EnumXAssetEntries ( Game : : XAssetType : : ASSET_TYPE_MATERIAL , [ asset , techsetMatches ] ( Game : : XAssetEntry * entry )
2017-05-30 04:03:12 -04:00
{
if ( ! replacementFound )
{
Game : : XAssetHeader header = entry - > asset . header ;
2017-05-30 04:52:22 -04:00
if ( techsetMatches ( header . material , asset ) )
2017-05-30 04:03:12 -04:00
{
2018-05-09 08:33:52 -04:00
Components : : Logger : : Print ( " Material %s with techset %s has been mapped to %s \n " , asset - > info . name , asset - > techniqueSet - > name , header . material - > techniqueSet - > name ) ;
asset - > info . sortKey = header . material - > info . sortKey ;
2017-05-30 04:03:12 -04:00
replacementFound = true ;
}
}
} , false , false ) ;
}
2017-04-24 15:14:32 -04:00
if ( ! replacementFound & & asset - > techniqueSet )
2017-04-15 16:50:20 -04:00
{
2018-05-09 08:33:52 -04:00
Components : : Logger : : Print ( " No replacement found for material %s with techset %s \n " , asset - > info . name , asset - > techniqueSet - > name ) ;
2021-04-04 06:06:24 -04:00
std : : string techName = asset - > techniqueSet - > name ;
if ( techSetCorrespondance . find ( techName ) ! = techSetCorrespondance . end ( ) ) {
auto iw4TechSetName = techSetCorrespondance [ techName ] ;
Game : : XAssetEntry * entry = Game : : DB_FindXAssetEntry ( Game : : XAssetType : : ASSET_TYPE_TECHNIQUE_SET , iw4TechSetName . data ( ) ) ;
if ( entry ) {
asset - > techniqueSet = entry - > asset . header . techniqueSet ;
Game : : DB_EnumXAssetEntries ( Game : : XAssetType : : ASSET_TYPE_MATERIAL , [ asset ] ( Game : : XAssetEntry * entry )
{
if ( ! replacementFound )
{
Game : : XAssetHeader header = entry - > asset . header ;
if ( header . material - > techniqueSet = = asset - > techniqueSet )
{
Components : : Logger : : Print ( " Material %s with techset %s has been mapped (last chance!) to %s \n " , asset - > info . name , asset - > techniqueSet - > name , header . material - > techniqueSet - > name ) ;
asset - > info . sortKey = header . material - > info . sortKey ;
replacementFound = true ;
}
}
} , false , false ) ;
if ( ! replacementFound ) {
Components : : Logger : : Print ( " Could not find any loaded material with techset %s, so I cannot set the sortkey for material %s \n " , asset - > techniqueSet - > name , asset - > info . name ) ;
}
}
else {
2021-04-05 10:25:44 -04:00
Components : : Logger : : Print ( " Could not find any loaded techset with iw4 name %s for iw3 techset %s \n " , iw4TechSetName . data ( ) , asset - > techniqueSet - > name ) ;
2021-04-04 06:06:24 -04:00
}
}
else {
Components : : Logger : : Print ( " Could not match iw3 techset %s with any of the techsets I know! This is a critical error, the map will not be playable. \n " , asset - > techniqueSet - > name ) ;
}
2017-04-15 16:50:20 -04:00
}
2017-03-18 10:19:31 -04:00
if ( ! reader . end ( ) )
{
Components : : Logger : : Error ( " Material data left! " ) ;
}
2018-05-09 05:18:31 -04:00
2018-05-10 12:04:12 -04:00
/*char baseIndex = 0;
2018-05-09 05:18:31 -04:00
for ( char i = 0 ; i < asset - > stateBitsCount ; + + i )
{
2018-05-09 08:33:52 -04:00
auto stateBits = asset - > stateBitsTable [ i ] ;
2018-05-09 05:18:31 -04:00
if ( stateBits . loadBits [ 0 ] = = 0x18128812 & &
stateBits . loadBits [ 1 ] = = 0xD ) // Seems to be like a default stateBit causing a 'generic' initialization
{
baseIndex = i ;
break ;
}
}
for ( int i = 0 ; i < 48 ; + + i )
{
if ( ! asset - > techniqueSet - > techniques [ i ] & & asset - > stateBitsEntry [ i ] ! = - 1 )
{
asset - > stateBitsEntry [ i ] = - 1 ;
}
if ( asset - > techniqueSet - > techniques [ i ] & & asset - > stateBitsEntry [ i ] = = - 1 )
{
asset - > stateBitsEntry [ i ] = baseIndex ;
}
2018-05-10 12:04:12 -04:00
} */
2017-01-19 16:23:59 -05:00
}
2018-12-17 08:29:18 -05:00
void IMaterial : : loadNative ( Game : : XAssetHeader * header , const std : : string & name , Components : : ZoneBuilder : : Zone * /*builder*/ )
2017-01-19 16:23:59 -05:00
{
header - > material = Components : : AssetHandler : : FindOriginalAsset ( this - > getType ( ) , name . data ( ) ) . material ;
}
2018-12-17 08:29:18 -05:00
void IMaterial : : loadJson ( Game : : XAssetHeader * header , const std : : string & name , Components : : ZoneBuilder : : Zone * builder )
2017-01-19 16:23:59 -05:00
{
Components : : FileSystem : : File materialInfo ( Utils : : String : : VA ( " materials/%s.json " , name . data ( ) ) ) ;
if ( ! materialInfo . exists ( ) ) return ;
std : : string errors ;
json11 : : Json infoData = json11 : : Json : : parse ( materialInfo . getBuffer ( ) , errors ) ;
if ( ! infoData . is_object ( ) )
{
Components : : Logger : : Error ( " Failed to load material information for %s! " , name . data ( ) ) ;
return ;
}
auto base = infoData [ " base " ] ;
if ( ! base . is_string ( ) )
{
Components : : Logger : : Error ( " No valid material base provided for %s! " , name . data ( ) ) ;
return ;
}
Game : : Material * baseMaterial = Game : : DB_FindXAssetHeader ( Game : : XAssetType : : ASSET_TYPE_MATERIAL , base . string_value ( ) . data ( ) ) . material ;
if ( ! baseMaterial ) // TODO: Maybe check if default asset? Maybe not? You could still want to use the default one as base!?
{
Components : : Logger : : Error ( " Basematerial '%s' not found for %s! " , base . string_value ( ) . data ( ) , name . data ( ) ) ;
return ;
}
Game : : Material * material = builder - > getAllocator ( ) - > allocate < Game : : Material > ( ) ;
if ( ! material )
{
Components : : Logger : : Error ( " Failed to allocate material structure! " ) ;
return ;
}
// Copy base material to our structure
std : : memcpy ( material , baseMaterial , sizeof ( Game : : Material ) ) ;
2018-05-09 08:33:52 -04:00
material - > info . name = builder - > getAllocator ( ) - > duplicateString ( name ) ;
2017-01-19 16:23:59 -05:00
2018-05-09 08:33:52 -04:00
material - > info . textureAtlasRowCount = 1 ;
material - > info . textureAtlasColumnCount = 1 ;
2017-01-19 16:23:59 -05:00
// Load animation frames
auto anims = infoData [ " anims " ] ;
if ( anims . is_array ( ) )
{
auto animCoords = anims . array_items ( ) ;
if ( animCoords . size ( ) > = 2 )
{
auto animCoordX = animCoords [ 0 ] ;
auto animCoordY = animCoords [ 1 ] ;
if ( animCoordX . is_number ( ) )
{
2018-05-09 08:33:52 -04:00
material - > info . textureAtlasColumnCount = static_cast < char > ( animCoordX . number_value ( ) ) & 0xFF ;
2017-01-19 16:23:59 -05:00
}
if ( animCoordY . is_number ( ) )
{
2018-05-09 08:33:52 -04:00
material - > info . textureAtlasRowCount = static_cast < char > ( animCoordY . number_value ( ) ) & 0xFF ;
2017-01-19 16:23:59 -05:00
}
}
}
// Model surface textures are special, they need a special order and whatnot
bool replaceTexture = Utils : : String : : StartsWith ( name , " mc/ " ) ;
if ( replaceTexture )
{
Game : : MaterialTextureDef * textureTable = builder - > getAllocator ( ) - > allocateArray < Game : : MaterialTextureDef > ( baseMaterial - > textureCount ) ;
std : : memcpy ( textureTable , baseMaterial - > textureTable , sizeof ( Game : : MaterialTextureDef ) * baseMaterial - > textureCount ) ;
material - > textureTable = textureTable ;
material - > textureCount = baseMaterial - > textureCount ;
}
// Load referenced textures
auto textures = infoData [ " textures " ] ;
if ( textures . is_array ( ) )
{
std : : vector < Game : : MaterialTextureDef > textureList ;
2017-05-30 14:31:00 -04:00
for ( auto & texture : textures . array_items ( ) )
2017-01-19 16:23:59 -05:00
{
if ( ! texture . is_array ( ) ) continue ;
if ( textureList . size ( ) > = 0xFF ) break ;
auto textureInfo = texture . array_items ( ) ;
if ( textureInfo . size ( ) < 2 ) continue ;
auto map = textureInfo [ 0 ] ;
auto image = textureInfo [ 1 ] ;
if ( ! map . is_string ( ) | | ! image . is_string ( ) ) continue ;
Game : : MaterialTextureDef textureDef ;
textureDef . semantic = 0 ; // No water image
2018-05-09 08:33:52 -04:00
textureDef . samplerState = - 30 ;
2017-01-19 16:23:59 -05:00
textureDef . nameEnd = map . string_value ( ) . back ( ) ;
textureDef . nameStart = map . string_value ( ) . front ( ) ;
textureDef . nameHash = Game : : R_HashString ( map . string_value ( ) . data ( ) ) ;
2018-05-09 08:33:52 -04:00
textureDef . u . image = Components : : AssetHandler : : FindAssetForZone ( Game : : XAssetType : : ASSET_TYPE_IMAGE , image . string_value ( ) , builder ) . image ;
2017-01-19 16:23:59 -05:00
if ( replaceTexture )
{
bool applied = false ;
for ( char i = 0 ; i < baseMaterial - > textureCount ; + + i )
{
if ( material - > textureTable [ i ] . nameHash = = textureDef . nameHash )
{
applied = true ;
2018-05-09 08:33:52 -04:00
material - > textureTable [ i ] . u . image = textureDef . u . image ;
2017-01-19 16:23:59 -05:00
break ;
}
}
if ( ! applied )
{
2018-05-09 08:33:52 -04:00
Components : : Logger : : Error ( 0 , " Unable to find texture for map '%s' in %s! " , map . string_value ( ) . data ( ) , baseMaterial - > info . name ) ;
2017-01-19 16:23:59 -05:00
}
}
else
{
textureList . push_back ( textureDef ) ;
}
}
2017-06-14 06:06:04 -04:00
if ( ! replaceTexture )
2017-01-19 16:23:59 -05:00
{
if ( ! textureList . empty ( ) )
{
Game : : MaterialTextureDef * textureTable = builder - > getAllocator ( ) - > allocateArray < Game : : MaterialTextureDef > ( textureList . size ( ) ) ;
if ( ! textureTable )
{
Components : : Logger : : Error ( " Failed to allocate texture table! " ) ;
return ;
}
std : : memcpy ( textureTable , textureList . data ( ) , sizeof ( Game : : MaterialTextureDef ) * textureList . size ( ) ) ;
material - > textureTable = textureTable ;
}
else
{
2017-01-20 16:41:03 -05:00
material - > textureTable = nullptr ;
2017-01-19 16:23:59 -05:00
}
material - > textureCount = static_cast < char > ( textureList . size ( ) ) & 0xFF ;
}
}
header - > material = material ;
}
void IMaterial : : mark ( Game : : XAssetHeader header , Components : : ZoneBuilder : : Zone * builder )
{
Game : : Material * asset = header . material ;
if ( asset - > techniqueSet )
{
builder - > loadAsset ( Game : : XAssetType : : ASSET_TYPE_TECHNIQUE_SET , asset - > techniqueSet ) ;
}
if ( asset - > textureTable )
{
for ( char i = 0 ; i < asset - > textureCount ; + + i )
{
2018-05-09 08:33:52 -04:00
if ( asset - > textureTable [ i ] . u . image )
2017-01-19 16:23:59 -05:00
{
if ( asset - > textureTable [ i ] . semantic = = SEMANTIC_WATER_MAP )
{
2018-05-09 08:33:52 -04:00
if ( asset - > textureTable [ i ] . u . water - > image )
2017-01-19 16:23:59 -05:00
{
2018-05-09 08:33:52 -04:00
builder - > loadAsset ( Game : : XAssetType : : ASSET_TYPE_IMAGE , asset - > textureTable [ i ] . u . water - > image ) ;
2017-01-19 16:23:59 -05:00
}
}
else
{
2018-05-09 08:33:52 -04:00
builder - > loadAsset ( Game : : XAssetType : : ASSET_TYPE_IMAGE , asset - > textureTable [ i ] . u . image ) ;
2017-01-19 16:23:59 -05:00
}
}
}
}
}
void IMaterial : : save ( Game : : XAssetHeader header , Components : : ZoneBuilder : : Zone * builder )
{
AssertSize ( Game : : Material , 96 ) ;
Utils : : Stream * buffer = builder - > getBuffer ( ) ;
Game : : Material * asset = header . material ;
Game : : Material * dest = buffer - > dest < Game : : Material > ( ) ;
buffer - > save ( asset ) ;
buffer - > pushBlock ( Game : : XFILE_BLOCK_VIRTUAL ) ;
2018-05-09 08:33:52 -04:00
if ( asset - > info . name )
2017-01-19 16:23:59 -05:00
{
2018-05-09 08:33:52 -04:00
buffer - > saveString ( builder - > getAssetName ( this - > getType ( ) , asset - > info . name ) ) ;
Utils : : Stream : : ClearPointer ( & dest - > info . name ) ;
2017-01-19 16:23:59 -05:00
}
if ( asset - > techniqueSet )
{
dest - > techniqueSet = builder - > saveSubAsset ( Game : : XAssetType : : ASSET_TYPE_TECHNIQUE_SET , asset - > techniqueSet ) . techniqueSet ;
}
if ( asset - > textureTable )
{
AssertSize ( Game : : MaterialTextureDef , 12 ) ;
// Pointer/Offset insertion is untested, but it worked in T6, so I think it's fine
if ( builder - > hasPointer ( asset - > textureTable ) )
{
dest - > textureTable = builder - > getPointer ( asset - > textureTable ) ;
}
else
{
buffer - > align ( Utils : : Stream : : ALIGN_4 ) ;
builder - > storePointer ( asset - > textureTable ) ;
Game : : MaterialTextureDef * destTextureTable = buffer - > dest < Game : : MaterialTextureDef > ( ) ;
buffer - > saveArray ( asset - > textureTable , asset - > textureCount ) ;
for ( char i = 0 ; i < asset - > textureCount ; + + i )
{
Game : : MaterialTextureDef * destTextureDef = & destTextureTable [ i ] ;
Game : : MaterialTextureDef * textureDef = & asset - > textureTable [ i ] ;
if ( textureDef - > semantic = = SEMANTIC_WATER_MAP )
{
AssertSize ( Game : : water_t , 68 ) ;
Game : : water_t * destWater = buffer - > dest < Game : : water_t > ( ) ;
2018-05-09 08:33:52 -04:00
Game : : water_t * water = textureDef - > u . water ;
2017-01-19 16:23:59 -05:00
if ( water )
{
buffer - > align ( Utils : : Stream : : ALIGN_4 ) ;
buffer - > save ( water ) ;
2018-05-09 08:33:52 -04:00
Utils : : Stream : : ClearPointer ( & destTextureDef - > u . water ) ;
2017-01-19 16:23:59 -05:00
// Save_water_t
if ( water - > H0 )
{
buffer - > align ( Utils : : Stream : : ALIGN_4 ) ;
buffer - > save ( water - > H0 , 8 , water - > M * water - > N ) ;
Utils : : Stream : : ClearPointer ( & destWater - > H0 ) ;
}
if ( water - > wTerm )
{
buffer - > align ( Utils : : Stream : : ALIGN_4 ) ;
buffer - > save ( water - > wTerm , 4 , water - > M * water - > N ) ;
Utils : : Stream : : ClearPointer ( & destWater - > wTerm ) ;
}
if ( water - > image )
{
destWater - > image = builder - > saveSubAsset ( Game : : XAssetType : : ASSET_TYPE_IMAGE , water - > image ) . image ;
}
}
}
2018-05-09 08:33:52 -04:00
else if ( textureDef - > u . image )
2017-01-19 16:23:59 -05:00
{
2018-05-09 08:33:52 -04:00
destTextureDef - > u . image = builder - > saveSubAsset ( Game : : XAssetType : : ASSET_TYPE_IMAGE , textureDef - > u . image ) . image ;
2017-01-19 16:23:59 -05:00
}
}
Utils : : Stream : : ClearPointer ( & dest - > textureTable ) ;
}
}
if ( asset - > constantTable )
{
AssertSize ( Game : : MaterialConstantDef , 32 ) ;
if ( builder - > hasPointer ( asset - > constantTable ) )
{
dest - > constantTable = builder - > getPointer ( asset - > constantTable ) ;
}
else
{
buffer - > align ( Utils : : Stream : : ALIGN_16 ) ;
builder - > storePointer ( asset - > constantTable ) ;
buffer - > saveArray ( asset - > constantTable , asset - > constantCount ) ;
Utils : : Stream : : ClearPointer ( & dest - > constantTable ) ;
}
}
2018-05-09 08:33:52 -04:00
if ( asset - > stateBitsTable )
2017-01-19 16:23:59 -05:00
{
2018-05-09 08:33:52 -04:00
if ( builder - > hasPointer ( asset - > stateBitsTable ) )
2017-01-19 16:23:59 -05:00
{
2018-05-09 08:33:52 -04:00
dest - > stateBitsTable = builder - > getPointer ( asset - > stateBitsTable ) ;
2017-01-19 16:23:59 -05:00
}
else
{
buffer - > align ( Utils : : Stream : : ALIGN_4 ) ;
2018-05-09 08:33:52 -04:00
builder - > storePointer ( asset - > stateBitsTable ) ;
2017-01-19 16:23:59 -05:00
2018-05-09 08:33:52 -04:00
buffer - > save ( asset - > stateBitsTable , 8 , asset - > stateBitsCount ) ;
Utils : : Stream : : ClearPointer ( & dest - > stateBitsTable ) ;
2017-01-19 16:23:59 -05:00
}
}
buffer - > popBlock ( ) ;
}
}