2017-09-24 18:14:41 +08:00
using SharpDX ;
using System ;
2017-09-21 18:33:05 +08:00
using System.Collections.Generic ;
using System.ComponentModel ;
using System.Linq ;
using System.Text ;
using System.Threading.Tasks ;
2020-01-18 01:20:40 +08:00
using System.Xml ;
2017-09-21 18:33:05 +08:00
namespace CodeWalker.GameFiles
{
[TypeConverter(typeof(ExpandableObjectConverter))] public class ShaderGroup : ResourceSystemBlock
{
public override long BlockLength
{
get { return 64 ; }
}
// structure data
public uint VFT { get ; set ; }
2020-01-18 01:20:40 +08:00
public uint Unknown_4h { get ; set ; } = 1 ; // 0x00000001
2017-09-21 18:33:05 +08:00
public ulong TextureDictionaryPointer { get ; set ; }
public ulong ShadersPointer { get ; set ; }
public ushort ShadersCount1 { get ; set ; }
public ushort ShadersCount2 { get ; set ; }
public uint Unknown_1Ch { get ; set ; } // 0x00000000
public uint Unknown_20h { get ; set ; } // 0x00000000
public uint Unknown_24h { get ; set ; } // 0x00000000
public uint Unknown_28h { get ; set ; } // 0x00000000
public uint Unknown_2Ch { get ; set ; } // 0x00000000
2020-01-18 23:36:28 +08:00
public uint Unknown_30h { get ; set ; } //wtf is this?? (shadercount-1)*3+8 ..?
2017-09-21 18:33:05 +08:00
public uint Unknown_34h { get ; set ; } // 0x00000000
public uint Unknown_38h { get ; set ; } // 0x00000000
public uint Unknown_3Ch { get ; set ; } // 0x00000000
// reference data
public TextureDictionary TextureDictionary { get ; set ; }
public ResourcePointerArray64 < ShaderFX > Shaders { get ; set ; }
public override void Read ( ResourceDataReader reader , params object [ ] parameters )
{
// read structure data
this . VFT = reader . ReadUInt32 ( ) ;
this . Unknown_4h = reader . ReadUInt32 ( ) ;
this . TextureDictionaryPointer = reader . ReadUInt64 ( ) ;
this . ShadersPointer = reader . ReadUInt64 ( ) ;
this . ShadersCount1 = reader . ReadUInt16 ( ) ;
this . ShadersCount2 = reader . ReadUInt16 ( ) ;
this . Unknown_1Ch = reader . ReadUInt32 ( ) ;
this . Unknown_20h = reader . ReadUInt32 ( ) ;
this . Unknown_24h = reader . ReadUInt32 ( ) ;
this . Unknown_28h = reader . ReadUInt32 ( ) ;
this . Unknown_2Ch = reader . ReadUInt32 ( ) ;
this . Unknown_30h = reader . ReadUInt32 ( ) ;
this . Unknown_34h = reader . ReadUInt32 ( ) ;
this . Unknown_38h = reader . ReadUInt32 ( ) ;
this . Unknown_3Ch = reader . ReadUInt32 ( ) ;
// read reference data
this . TextureDictionary = reader . ReadBlockAt < TextureDictionary > (
this . TextureDictionaryPointer // offset
) ;
this . Shaders = reader . ReadBlockAt < ResourcePointerArray64 < ShaderFX > > (
this . ShadersPointer , // offset
this . ShadersCount1
) ;
2020-01-18 23:36:28 +08:00
// wtf is Unknown_30h ???
//switch (ShadersCount1)
//{
// case 1: if ((Unknown_30h != 8) && (Unknown_30h != 25))
// { }
// break;
// case 2: if ((Unknown_30h != 11) && (Unknown_30h != 61) && (Unknown_30h != 50) && (Unknown_30h != 51))
// { }
// break;
// case 3: if ((Unknown_30h != 15) && (Unknown_30h != 78))
// { }
// break;
// case 4: if ((Unknown_30h != 18) && (Unknown_30h != 108))
// { }
// break;
// case 5: if ((Unknown_30h != 22) && (Unknown_30h != 135) && (Unknown_30h != 137))
// { }
// break;
// case 6: if (Unknown_30h != 25)
// { }
// break;
// case 7: if (Unknown_30h != 29)
// { }
// break;
// case 8: if (Unknown_30h != 32)
// { }
// break;
// case 9: if (Unknown_30h != 36)
// { }
// break;
// case 10: if (Unknown_30h != 39)
// { }
// break;
// case 11: if (Unknown_30h != 43)
// { }
// break;
// case 12: if (Unknown_30h != 46)
// { }
// break;
// case 13: if (Unknown_30h != 50)
// { }
// break;
// case 14: if (Unknown_30h != 53)
// { }
// break;
// case 15: if (Unknown_30h != 57)
// { }
// break;
// case 16: if (Unknown_30h != 60)
// { }
// break;
// case 17: if (Unknown_30h != 64)
// { }
// break;
// case 18: if (Unknown_30h != 67)
// { }
// break;
// case 19: if (Unknown_30h != 71)
// { }
// break;
// case 20: if (Unknown_30h != 74)
// { }
// break;
// default:
// break;
//}
//var cnt = 8 + ((ShadersCount1 > 0) ? ShadersCount1-1 : 0) * 3;
//if (cnt != Unknown_30h)
//{ }
2017-09-21 18:33:05 +08:00
}
public override void Write ( ResourceDataWriter writer , params object [ ] parameters )
{
// update structure data
this . TextureDictionaryPointer = ( ulong ) ( this . TextureDictionary ! = null ? this . TextureDictionary . FilePosition : 0 ) ;
this . ShadersPointer = ( ulong ) ( this . Shaders ! = null ? this . Shaders . FilePosition : 0 ) ;
2019-01-28 10:13:45 +08:00
this . ShadersCount1 = ( ushort ) ( this . Shaders ! = null ? this . Shaders . Count : 0 ) ;
this . ShadersCount2 = this . ShadersCount1 ;
2017-09-21 18:33:05 +08:00
// write structure data
writer . Write ( this . VFT ) ;
writer . Write ( this . Unknown_4h ) ;
writer . Write ( this . TextureDictionaryPointer ) ;
writer . Write ( this . ShadersPointer ) ;
writer . Write ( this . ShadersCount1 ) ;
writer . Write ( this . ShadersCount2 ) ;
writer . Write ( this . Unknown_1Ch ) ;
writer . Write ( this . Unknown_20h ) ;
writer . Write ( this . Unknown_24h ) ;
writer . Write ( this . Unknown_28h ) ;
writer . Write ( this . Unknown_2Ch ) ;
writer . Write ( this . Unknown_30h ) ;
writer . Write ( this . Unknown_34h ) ;
writer . Write ( this . Unknown_38h ) ;
writer . Write ( this . Unknown_3Ch ) ;
}
2020-01-18 01:20:40 +08:00
public void WriteXml ( StringBuilder sb , int indent , string ddsfolder )
{
2020-01-18 23:36:28 +08:00
YdrXml . ValueTag ( sb , indent , "Unknown30" , Unknown_30h . ToString ( ) ) ;
if ( TextureDictionary ! = null )
{
TextureDictionary . WriteXmlNode ( TextureDictionary , sb , indent , ddsfolder , "TextureDictionary" ) ;
}
YdrXml . WriteItemArray ( sb , Shaders ? . data_items , indent , "Shaders" ) ;
2020-01-18 01:20:40 +08:00
}
public void ReadXml ( XmlNode node , string ddsfolder )
{
2020-01-18 23:36:28 +08:00
Unknown_30h = Xml . GetChildUIntAttribute ( node , "Unknown30" , "value" ) ;
var tnode = node . SelectSingleNode ( "TextureDictionary" ) ;
if ( tnode ! = null )
{
TextureDictionary = TextureDictionary . ReadXmlNode ( tnode , ddsfolder ) ;
}
var shaders = XmlMeta . ReadItemArray < ShaderFX > ( node , "Shaders" ) ;
if ( shaders ! = null )
{
Shaders = new ResourcePointerArray64 < ShaderFX > ( ) ;
Shaders . data_items = shaders ;
}
if ( ( shaders ! = null ) & & ( TextureDictionary ! = null ) )
{
foreach ( var shader in shaders )
{
var sparams = shader ? . ParametersList ? . Parameters ;
if ( sparams ! = null )
{
foreach ( var sparam in sparams )
{
if ( sparam . Data is TextureBase tex )
{
var tex2 = TextureDictionary . Lookup ( tex . NameHash ) ;
if ( tex2 ! = null )
{
sparam . Data = tex2 ; //swap the parameter out for the embedded texture
}
}
}
}
}
}
2020-01-18 01:20:40 +08:00
}
2017-09-21 18:33:05 +08:00
public override IResourceBlock [ ] GetReferences ( )
{
var list = new List < IResourceBlock > ( ) ;
if ( TextureDictionary ! = null ) list . Add ( TextureDictionary ) ;
if ( Shaders ! = null ) list . Add ( Shaders ) ;
return list . ToArray ( ) ;
}
}
2020-01-18 23:36:28 +08:00
[TypeConverter(typeof(ExpandableObjectConverter))] public class ShaderFX : ResourceSystemBlock , IMetaXmlItem
2017-09-21 18:33:05 +08:00
{
public override long BlockLength
{
get { return 48 ; }
}
// structure data
public ulong ParametersPointer { get ; set ; }
2019-11-25 17:44:16 +08:00
public MetaHash Name { get ; set ; } //decal_emissive_only, emissive, spec
2017-09-21 18:33:05 +08:00
public uint Unknown_Ch { get ; set ; } // 0x00000000
public byte ParameterCount { get ; set ; }
2019-03-20 18:21:47 +08:00
public byte RenderBucket { get ; set ; } // 2, 0,
2020-01-18 23:36:28 +08:00
public ushort Unknown_12h { get ; set ; } = 32768 ; // 32768 HasComment?
2019-03-20 18:21:47 +08:00
public ushort ParameterSize { get ; set ; } //112, 208, 320 (with 16h) 10485872, 17826000, 26214720
public ushort ParameterDataSize { get ; set ; } //160, 272, 400
2019-11-25 17:44:16 +08:00
public MetaHash FileName { get ; set ; } //decal_emissive_only.sps, emissive.sps, spec.sps
2017-09-21 18:33:05 +08:00
public uint Unknown_1Ch { get ; set ; } // 0x00000000
2019-03-20 18:21:47 +08:00
public uint RenderBucketMask { get ; set ; } //65284, 65281 DrawBucketMask? (1<<bucket) | 0xFF00
public ushort Unknown_24h { get ; set ; } //0 Instanced?
2017-09-21 18:33:05 +08:00
public byte Unknown_26h { get ; set ; } //0
public byte TextureParametersCount { get ; set ; }
public uint Unknown_28h { get ; set ; } // 0x00000000
public uint Unknown_2Ch { get ; set ; } // 0x00000000
// reference data
//public ResourceSimpleArray<ShaderParameter_GTA5_pc> Parameters { get; set; }
//public SimpleArrayOFFSET<uint_r> ParameterHashes { get; set; }
public ShaderParametersBlock ParametersList { get ; set ; }
public override void Read ( ResourceDataReader reader , params object [ ] parameters )
{
// read structure data
this . ParametersPointer = reader . ReadUInt64 ( ) ;
this . Name = new MetaHash ( reader . ReadUInt32 ( ) ) ;
this . Unknown_Ch = reader . ReadUInt32 ( ) ;
this . ParameterCount = reader . ReadByte ( ) ;
2019-03-20 18:21:47 +08:00
this . RenderBucket = reader . ReadByte ( ) ;
2017-09-21 18:33:05 +08:00
this . Unknown_12h = reader . ReadUInt16 ( ) ;
2019-03-20 18:21:47 +08:00
this . ParameterSize = reader . ReadUInt16 ( ) ;
this . ParameterDataSize = reader . ReadUInt16 ( ) ;
2017-09-21 18:33:05 +08:00
this . FileName = new MetaHash ( reader . ReadUInt32 ( ) ) ;
this . Unknown_1Ch = reader . ReadUInt32 ( ) ;
2019-03-20 18:21:47 +08:00
this . RenderBucketMask = reader . ReadUInt32 ( ) ;
2017-09-21 18:33:05 +08:00
this . Unknown_24h = reader . ReadUInt16 ( ) ;
this . Unknown_26h = reader . ReadByte ( ) ;
this . TextureParametersCount = reader . ReadByte ( ) ;
this . Unknown_28h = reader . ReadUInt32 ( ) ;
this . Unknown_2Ch = reader . ReadUInt32 ( ) ;
// read reference data
this . ParametersList = reader . ReadBlockAt < ShaderParametersBlock > (
this . ParametersPointer , // offset
this . ParameterCount
) ;
2020-01-18 23:36:28 +08:00
//// just testing...
//if (Unknown_12h != 32768)
//{
// if (Unknown_12h != 0)//des_aquaduct_root, rig_root_skin.... destructions?
// { }//no hit
//}
//if (RenderBucketMask != ((1 << RenderBucket) | 0xFF00))
//{ }//no hit
//if (ParameterSize != ParametersList?.ParametersSize)
//{ }//no hit
////if (ParameterDataSize != ParametersList?.ParametersDataSize)
//{
// var diff = ParameterDataSize - (ParametersList?.BlockLength ?? 0);
// switch (diff)
// {
// case 32:
// case 36:
// case 40:
// case 44:
// break;
// default:
// break;//no hit
// }
//}
//if (Unknown_24h != 0)
//{ }//no hit
//if (Unknown_26h != 0)
//{ }//no hit
2017-09-21 18:33:05 +08:00
}
public override void Write ( ResourceDataWriter writer , params object [ ] parameters )
{
// update structure data
this . ParametersPointer = ( ulong ) ( this . ParametersList ! = null ? this . ParametersList . FilePosition : 0 ) ;
2019-01-28 10:13:45 +08:00
this . ParameterCount = ( byte ) ( this . ParametersList ! = null ? this . ParametersList . Count : 0 ) ;
2017-09-21 18:33:05 +08:00
// write structure data
writer . Write ( this . ParametersPointer ) ;
writer . Write ( this . Name . Hash ) ;
writer . Write ( this . Unknown_Ch ) ;
writer . Write ( this . ParameterCount ) ;
2019-03-20 18:21:47 +08:00
writer . Write ( this . RenderBucket ) ;
2017-09-21 18:33:05 +08:00
writer . Write ( this . Unknown_12h ) ;
2019-03-20 18:21:47 +08:00
writer . Write ( this . ParameterSize ) ;
writer . Write ( this . ParameterDataSize ) ;
2017-09-21 18:33:05 +08:00
writer . Write ( this . FileName . Hash ) ;
writer . Write ( this . Unknown_1Ch ) ;
2019-03-20 18:21:47 +08:00
writer . Write ( this . RenderBucketMask ) ;
2017-09-21 18:33:05 +08:00
writer . Write ( this . Unknown_24h ) ;
writer . Write ( this . Unknown_26h ) ;
writer . Write ( this . TextureParametersCount ) ;
writer . Write ( this . Unknown_28h ) ;
writer . Write ( this . Unknown_2Ch ) ;
}
2020-01-18 23:36:28 +08:00
public void WriteXml ( StringBuilder sb , int indent )
{
YdrXml . StringTag ( sb , indent , "Name" , YdrXml . HashString ( Name ) ) ;
YdrXml . StringTag ( sb , indent , "FileName" , YdrXml . HashString ( FileName ) ) ;
YdrXml . ValueTag ( sb , indent , "RenderBucket" , RenderBucket . ToString ( ) ) ;
if ( ParametersList ! = null )
{
YdrXml . OpenTag ( sb , indent , "Parameters" ) ;
ParametersList . WriteXml ( sb , indent + 1 ) ;
YdrXml . CloseTag ( sb , indent , "Parameters" ) ;
}
}
public void ReadXml ( XmlNode node )
{
Name = XmlMeta . GetHash ( Xml . GetChildInnerText ( node , "Name" ) ) ;
FileName = XmlMeta . GetHash ( Xml . GetChildInnerText ( node , "FileName" ) ) ;
RenderBucket = ( byte ) Xml . GetChildUIntAttribute ( node , "RenderBucket" , "value" ) ;
RenderBucketMask = ( ( 1 u < < RenderBucket ) | 0xFF00 u ) ;
var pnode = node . SelectSingleNode ( "Parameters" ) ;
if ( pnode ! = null )
{
ParametersList = new ShaderParametersBlock ( ) ;
ParametersList . ReadXml ( pnode ) ;
ParameterCount = ( byte ) ParametersList . Count ;
ParameterSize = ParametersList . ParametersSize ;
ParameterDataSize = ParametersList . ParametersDataSize ; //is it right?
}
}
2017-09-21 18:33:05 +08:00
public override IResourceBlock [ ] GetReferences ( )
{
var list = new List < IResourceBlock > ( ) ;
if ( ParametersList ! = null ) list . Add ( ParametersList ) ;
return list . ToArray ( ) ;
}
public override string ToString ( )
{
return Name . ToString ( ) + " (" + FileName . ToString ( ) + ")" ;
}
2020-01-18 23:36:28 +08:00
2017-09-21 18:33:05 +08:00
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class ShaderParameter : ResourceSystemBlock
{
public override long BlockLength
{
get { return 16 ; }
}
// structure data
2020-01-18 01:20:40 +08:00
public byte DataType { get ; set ; } //0: texture, 1: vector4
2017-09-21 18:33:05 +08:00
public byte Unknown_1h { get ; set ; }
2020-01-18 23:36:28 +08:00
public ushort Unknown_2h { get ; set ; } //0
public uint Unknown_4h { get ; set ; } //0
2017-09-21 18:33:05 +08:00
public ulong DataPointer { get ; set ; }
//public IResourceBlock Data { get; set; }
public object Data { get ; set ; }
public override void Read ( ResourceDataReader reader , params object [ ] parameters )
{
// read structure data
this . DataType = reader . ReadByte ( ) ;
this . Unknown_1h = reader . ReadByte ( ) ;
this . Unknown_2h = reader . ReadUInt16 ( ) ;
this . Unknown_4h = reader . ReadUInt32 ( ) ;
this . DataPointer = reader . ReadUInt64 ( ) ;
// DONT READ DATA...
}
public override void Write ( ResourceDataWriter writer , params object [ ] parameters )
{
// write structure data
writer . Write ( this . DataType ) ;
writer . Write ( this . Unknown_1h ) ;
writer . Write ( this . Unknown_2h ) ;
writer . Write ( this . Unknown_4h ) ;
writer . Write ( this . DataPointer ) ;
// DONT WRITE DATA
}
public override IResourceBlock [ ] GetReferences ( )
{
var list = new List < IResourceBlock > ( base . GetReferences ( ) ) ;
//if (Data != null) list.Add(Data);
return list . ToArray ( ) ;
}
public override string ToString ( )
{
return ( Data ! = null ) ? Data . ToString ( ) : ( DataType . ToString ( ) + ": " + DataPointer . ToString ( ) ) ;
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class ShaderParametersBlock : ResourceSystemBlock
{
public override long BlockLength
{
get
{
long offset = 0 ;
foreach ( var x in Parameters )
{
offset + = 16 ;
}
foreach ( var x in Parameters )
{
offset + = 16 * x . DataType ;
}
offset + = Parameters . Length * 4 ;
return offset ;
}
}
2019-03-20 18:21:47 +08:00
public ushort ParametersSize
{
get
{
ushort size = ( ushort ) ( ( Parameters ? . Length ? ? 0 ) * 16 ) ;
foreach ( var x in Parameters )
{
size + = ( ushort ) ( 16 * x . DataType ) ;
}
return size ;
}
}
2020-01-18 23:36:28 +08:00
public ushort ParametersDataSize
{
get
{
ushort size = ( ushort ) ( BlockLength + 36 ) ; //TODO: figure out how to calculate this correctly!!
return size ;
}
}
2019-03-20 18:21:47 +08:00
public byte TextureParamsCount
{
get
{
byte c = 0 ;
foreach ( var x in Parameters )
{
if ( x . DataType = = 0 ) c + + ;
}
return c ;
}
}
2017-09-21 18:33:05 +08:00
public ShaderParameter [ ] Parameters { get ; set ; }
public MetaName [ ] Hashes { get ; set ; }
2019-01-28 10:13:45 +08:00
public int Count { get ; set ; }
private ResourceSystemStructBlock < Vector4 > [ ] ParameterDataBlocks = null ;
2017-09-21 18:33:05 +08:00
public override void Read ( ResourceDataReader reader , params object [ ] parameters )
{
2019-01-28 10:13:45 +08:00
Count = Convert . ToInt32 ( parameters [ 0 ] ) ;
2017-09-21 18:33:05 +08:00
var paras = new List < ShaderParameter > ( ) ;
2019-01-28 10:13:45 +08:00
for ( int i = 0 ; i < Count ; i + + )
2017-09-21 18:33:05 +08:00
{
paras . Add ( reader . ReadBlock < ShaderParameter > ( ) ) ;
}
int offset = 0 ;
2019-01-28 10:13:45 +08:00
for ( int i = 0 ; i < Count ; i + + )
2017-09-21 18:33:05 +08:00
{
var p = paras [ i ] ;
// read reference data
switch ( p . DataType )
{
case 0 :
offset + = 0 ;
2019-01-28 10:13:45 +08:00
p . Data = reader . ReadBlockAt < TextureBase > ( p . DataPointer ) ;
2017-09-21 18:33:05 +08:00
break ;
case 1 :
offset + = 16 ;
2019-01-28 10:13:45 +08:00
p . Data = reader . ReadStructAt < Vector4 > ( ( long ) p . DataPointer ) ;
2017-09-21 18:33:05 +08:00
break ;
default :
offset + = 16 * p . DataType ;
2018-03-10 22:27:13 +08:00
p . Data = reader . ReadStructsAt < Vector4 > ( p . DataPointer , p . DataType ) ;
2017-09-21 18:33:05 +08:00
break ;
}
}
2019-01-28 10:13:45 +08:00
reader . Position + = offset ; //Vector4 data gets embedded here... but why pointers in params also???
2017-09-21 18:33:05 +08:00
var hashes = new List < MetaName > ( ) ;
2019-01-28 10:13:45 +08:00
for ( int i = 0 ; i < Count ; i + + )
2017-09-21 18:33:05 +08:00
{
hashes . Add ( ( MetaName ) reader . ReadUInt32 ( ) ) ;
}
Parameters = paras . ToArray ( ) ;
Hashes = hashes . ToArray ( ) ;
2020-01-18 23:36:28 +08:00
//// just testing...
//for (int i = 0; i < Parameters.Length; i++)
//{
// var param = Parameters[i];
// if (param.DataType == 0)
// {
// if (param.Unknown_1h != ((param.Data == null) ? 10 : (i + 2)))
// { }
// }
// else
// {
// if (param.Unknown_1h != (160 + ((Parameters.Length - 1) - i)))
// { }
// }
//}
//if (Parameters.Length > 0)
//{
// var lparam = Parameters[Parameters.Length - 1];
// switch(lparam.Unknown_1h)
// {
// case 192:
// case 160:
// case 177:
// case 161:
// case 156:
// case 162:
// case 157:
// case 149:
// case 178:
// case 72:
// case 153:
// case 133:
// break;
// case 64://in ydd's
// case 130:
// case 180:
// break;
// default:
// break;
// }
//}
2017-09-21 18:33:05 +08:00
}
public override void Write ( ResourceDataWriter writer , params object [ ] parameters )
{
// update pointers...
//foreach (var f in Parameters)
// if (f.Data != null)
// f.DataPointer = (ulong)f.Data.Position;
// else
// f.DataPointer = 0;
2019-01-28 10:13:45 +08:00
for ( int i = 0 ; i < Parameters . Length ; i + + )
{
var param = Parameters [ i ] ;
if ( param . DataType = = 0 )
{
param . DataPointer = ( ulong ) ( ( param . Data as TextureBase ) ? . FilePosition ? ? 0 ) ;
}
else
{
var block = ( i < ParameterDataBlocks ? . Length ) ? ParameterDataBlocks [ i ] : null ;
if ( block ! = null )
{
param . DataPointer = ( ulong ) block . FilePosition ;
}
else
{
param . DataPointer = 0 ; //shouldn't happen!
}
}
}
2017-09-21 18:33:05 +08:00
// write parameter infos
foreach ( var f in Parameters )
writer . WriteBlock ( f ) ;
// write vector data
//foreach (var f in Parameters)
//{
// if (f.DataType != 0)
// writer.WriteBlock(f.Data);
//}
2019-01-28 10:13:45 +08:00
for ( int i = 0 ; i < Parameters . Length ; i + + )
{
var param = Parameters [ i ] ;
if ( param . DataType ! = 0 )
{
var block = ( i < ParameterDataBlocks ? . Length ) ? ParameterDataBlocks [ i ] : null ;
if ( block ! = null )
{
writer . WriteBlock ( block ) ;
}
else
{ } //shouldn't happen!
}
}
2017-09-21 18:33:05 +08:00
// write hashes
foreach ( var h in Hashes )
writer . Write ( ( uint ) h ) ;
}
2020-01-18 23:36:28 +08:00
public void WriteXml ( StringBuilder sb , int indent )
{
var cind = indent + 1 ;
for ( int i = 0 ; i < Count ; i + + )
{
var param = Parameters [ i ] ;
var hash = Hashes [ i ] ;
var typestr = "" ;
if ( param . DataType = = 0 ) typestr = "Texture" ;
else if ( param . DataType = = 1 ) typestr = "Vector" ;
else if ( param . DataType > 1 ) typestr = "Array" ;
var otstr = "Item name=\"" + YdrXml . HashString ( hash ) + "\" type=\"" + typestr + "\"" ;
if ( param . DataType = = 0 )
{
if ( param . Data is TextureBase tex )
{
YdrXml . OpenTag ( sb , indent , otstr ) ;
YdrXml . StringTag ( sb , cind , "Name" , YdrXml . XmlEscape ( tex . Name ) ) ;
YdrXml . ValueTag ( sb , cind , "Unk32" , tex . Unknown_32h . ToString ( ) ) ;
YdrXml . CloseTag ( sb , indent , "Item" ) ;
}
else
{
YdrXml . SelfClosingTag ( sb , indent , otstr ) ;
}
}
else if ( param . DataType = = 1 )
{
if ( param . Data is Vector4 vec )
{
YdrXml . SelfClosingTag ( sb , indent , otstr + " " + FloatUtil . GetVector4XmlString ( vec ) ) ;
}
else
{
YdrXml . SelfClosingTag ( sb , indent , otstr ) ;
}
}
else
{
if ( param . Data is Vector4 [ ] arr )
{
YdrXml . OpenTag ( sb , indent , otstr ) ;
foreach ( var vec in arr )
{
YdrXml . SelfClosingTag ( sb , cind , "Value " + FloatUtil . GetVector4XmlString ( vec ) ) ;
}
YdrXml . CloseTag ( sb , indent , "Item" ) ;
}
else
{
YdrXml . SelfClosingTag ( sb , indent , otstr ) ;
}
}
}
}
public void ReadXml ( XmlNode node )
{
var plist = new List < ShaderParameter > ( ) ;
var hlist = new List < MetaName > ( ) ;
var pnodes = node . SelectNodes ( "Item" ) ;
foreach ( XmlNode pnode in pnodes )
{
var p = new ShaderParameter ( ) ;
var h = ( MetaName ) ( uint ) XmlMeta . GetHash ( Xml . GetStringAttribute ( pnode , "name" ) ) ;
var type = Xml . GetStringAttribute ( pnode , "type" ) ;
if ( type = = "Texture" )
{
p . DataType = 0 ;
if ( pnode . SelectSingleNode ( "Name" ) ! = null )
{
var tex = new TextureBase ( ) ;
tex . ReadXml ( pnode , null ) ; //embedded textures will get replaced in ShaderFX ReadXML
p . Data = tex ;
}
}
else if ( type = = "Vector" )
{
p . DataType = 1 ;
float fx = Xml . GetFloatAttribute ( pnode , "x" ) ;
float fy = Xml . GetFloatAttribute ( pnode , "y" ) ;
float fz = Xml . GetFloatAttribute ( pnode , "z" ) ;
float fw = Xml . GetFloatAttribute ( pnode , "w" ) ;
p . Data = new Vector4 ( fx , fy , fz , fw ) ;
}
else if ( type = = "Array" )
{
p . DataType = 2 ;
var vecs = new List < Vector4 > ( ) ;
var inodes = pnode . SelectNodes ( "Value" ) ;
foreach ( XmlNode inode in inodes )
{
float fx = Xml . GetFloatAttribute ( inode , "x" ) ;
float fy = Xml . GetFloatAttribute ( inode , "y" ) ;
float fz = Xml . GetFloatAttribute ( inode , "z" ) ;
float fw = Xml . GetFloatAttribute ( inode , "w" ) ;
vecs . Add ( new Vector4 ( fx , fy , fz , fw ) ) ;
}
p . Data = vecs . ToArray ( ) ;
}
plist . Add ( p ) ;
hlist . Add ( h ) ;
}
Parameters = plist . ToArray ( ) ;
Hashes = hlist . ToArray ( ) ;
for ( int i = 0 ; i < Parameters . Length ; i + + )
{
var param = Parameters [ i ] ;
if ( param . DataType = = 0 )
{
param . Unknown_1h = ( byte ) ( i + 2 ) ; //wtf and why
}
}
var offset = 160 ;
for ( int i = Parameters . Length - 1 ; i > = 0 ; i - - )
{
var param = Parameters [ i ] ;
if ( param . DataType ! = 0 )
{
param . Unknown_1h = ( byte ) offset ; //wtf and why
offset + = param . DataType ;
}
}
}
2017-09-21 18:33:05 +08:00
public override IResourceBlock [ ] GetReferences ( )
{
var list = new List < IResourceBlock > ( ) ;
list . AddRange ( base . GetReferences ( ) ) ;
2019-01-28 10:13:45 +08:00
foreach ( var x in Parameters )
if ( x . DataType = = 0 )
list . Add ( x . Data as TextureBase ) ;
2017-09-21 18:33:05 +08:00
return list . ToArray ( ) ;
}
public override Tuple < long , IResourceBlock > [ ] GetParts ( )
{
var list = new List < Tuple < long , IResourceBlock > > ( ) ;
list . AddRange ( base . GetParts ( ) ) ;
long offset = 0 ;
foreach ( var x in Parameters )
{
list . Add ( new Tuple < long , IResourceBlock > ( offset , x ) ) ;
offset + = 16 ;
}
2019-01-28 10:13:45 +08:00
var blist = new List < ResourceSystemStructBlock < Vector4 > > ( ) ;
foreach ( var x in Parameters )
{
if ( x . DataType ! = 0 )
{
var vecs = x . Data as Vector4 [ ] ;
if ( vecs = = null )
{
vecs = new [ ] { ( Vector4 ) x . Data } ;
}
if ( vecs = = null )
{ }
var block = new ResourceSystemStructBlock < Vector4 > ( vecs ) ;
list . Add ( new Tuple < long , IResourceBlock > ( offset , block ) ) ;
blist . Add ( block ) ;
}
else
{
blist . Add ( null ) ;
}
offset + = 16 * x . DataType ;
}
ParameterDataBlocks = blist . ToArray ( ) ;
2017-09-21 18:33:05 +08:00
return list . ToArray ( ) ;
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class Skeleton : ResourceSystemBlock
{
public override long BlockLength
{
get { return 112 ; }
}
// structure data
public uint VFT { get ; set ; }
2019-11-26 14:00:41 +08:00
public uint Unknown_4h { get ; set ; } = 1 ; // 0x00000001
2017-09-21 18:33:05 +08:00
public uint Unknown_8h { get ; set ; } // 0x00000000
public uint Unknown_Ch { get ; set ; } // 0x00000000
2019-11-05 17:47:10 +08:00
public ulong BoneTagsPointer { get ; set ; }
2020-01-18 23:36:28 +08:00
public ushort BoneTagsCapacity { get ; set ; }
2020-01-18 01:20:40 +08:00
public ushort BoneTagsCount { get ; set ; }
2019-11-05 17:47:10 +08:00
public FlagsUint Unknown_1Ch { get ; set ; }
2017-09-21 18:33:05 +08:00
public ulong BonesPointer { get ; set ; }
public ulong TransformationsInvertedPointer { get ; set ; }
public ulong TransformationsPointer { get ; set ; }
public ulong ParentIndicesPointer { get ; set ; }
2019-11-05 17:47:10 +08:00
public ulong ChildIndicesPointer { get ; set ; }
2017-09-21 18:33:05 +08:00
public uint Unknown_48h { get ; set ; } // 0x00000000
public uint Unknown_4Ch { get ; set ; } // 0x00000000
public MetaHash Unknown_50h { get ; set ; }
public MetaHash Unknown_54h { get ; set ; }
public MetaHash Unknown_58h { get ; set ; }
2019-11-26 14:00:41 +08:00
public ushort Unknown_5Ch { get ; set ; } = 1 ; // 0x0001
2017-09-21 18:33:05 +08:00
public ushort BonesCount { get ; set ; }
2019-11-05 17:47:10 +08:00
public ushort ChildIndicesCount { get ; set ; }
2017-09-21 18:33:05 +08:00
public ushort Unknown_62h { get ; set ; } // 0x0000
public uint Unknown_64h { get ; set ; } // 0x00000000
public uint Unknown_68h { get ; set ; } // 0x00000000
public uint Unknown_6Ch { get ; set ; } // 0x00000000
// reference data
2019-11-05 17:47:10 +08:00
public ResourcePointerArray64 < SkeletonBoneTag > BoneTags { get ; set ; }
2017-09-21 18:33:05 +08:00
public ResourceSimpleArray < Bone > Bones { get ; set ; }
2018-03-10 22:27:13 +08:00
public Matrix [ ] TransformationsInverted { get ; set ; }
public Matrix [ ] Transformations { get ; set ; }
2019-11-06 01:53:20 +08:00
public short [ ] ParentIndices { get ; set ; }
public short [ ] ChildIndices { get ; set ; } //mapping child->parent indices, first child index, then parent
2017-09-21 18:33:05 +08:00
2019-01-28 10:13:45 +08:00
private ResourceSystemStructBlock < Matrix > TransformationsInvertedBlock = null ; //for saving only
private ResourceSystemStructBlock < Matrix > TransformationsBlock = null ;
2019-11-06 01:53:20 +08:00
private ResourceSystemStructBlock < short > ParentIndicesBlock = null ;
private ResourceSystemStructBlock < short > ChildIndicesBlock = null ;
2019-01-28 10:13:45 +08:00
2017-09-21 18:33:05 +08:00
2019-11-02 15:14:36 +08:00
public Dictionary < ushort , Bone > BonesMap { get ; set ; } //for convienience finding bones by tag
2019-11-26 14:00:41 +08:00
public Matrix3_s [ ] BoneTransforms ; //for rendering
2017-09-21 18:33:05 +08:00
public override void Read ( ResourceDataReader reader , params object [ ] parameters )
{
// read structure data
this . VFT = reader . ReadUInt32 ( ) ;
this . Unknown_4h = reader . ReadUInt32 ( ) ;
this . Unknown_8h = reader . ReadUInt32 ( ) ;
this . Unknown_Ch = reader . ReadUInt32 ( ) ;
2019-11-05 17:47:10 +08:00
this . BoneTagsPointer = reader . ReadUInt64 ( ) ;
2020-01-18 23:36:28 +08:00
this . BoneTagsCapacity = reader . ReadUInt16 ( ) ;
2020-01-18 01:20:40 +08:00
this . BoneTagsCount = reader . ReadUInt16 ( ) ;
2017-09-21 18:33:05 +08:00
this . Unknown_1Ch = reader . ReadUInt32 ( ) ;
this . BonesPointer = reader . ReadUInt64 ( ) ;
this . TransformationsInvertedPointer = reader . ReadUInt64 ( ) ;
this . TransformationsPointer = reader . ReadUInt64 ( ) ;
this . ParentIndicesPointer = reader . ReadUInt64 ( ) ;
2019-11-05 17:47:10 +08:00
this . ChildIndicesPointer = reader . ReadUInt64 ( ) ;
2017-09-21 18:33:05 +08:00
this . Unknown_48h = reader . ReadUInt32 ( ) ;
this . Unknown_4Ch = reader . ReadUInt32 ( ) ;
this . Unknown_50h = new MetaHash ( reader . ReadUInt32 ( ) ) ;
this . Unknown_54h = new MetaHash ( reader . ReadUInt32 ( ) ) ;
this . Unknown_58h = new MetaHash ( reader . ReadUInt32 ( ) ) ;
this . Unknown_5Ch = reader . ReadUInt16 ( ) ;
this . BonesCount = reader . ReadUInt16 ( ) ;
2019-11-05 17:47:10 +08:00
this . ChildIndicesCount = reader . ReadUInt16 ( ) ;
2017-09-21 18:33:05 +08:00
this . Unknown_62h = reader . ReadUInt16 ( ) ;
this . Unknown_64h = reader . ReadUInt32 ( ) ;
this . Unknown_68h = reader . ReadUInt32 ( ) ;
this . Unknown_6Ch = reader . ReadUInt32 ( ) ;
// read reference data
2019-11-05 17:47:10 +08:00
this . BoneTags = reader . ReadBlockAt < ResourcePointerArray64 < SkeletonBoneTag > > (
this . BoneTagsPointer , // offset
2020-01-18 23:36:28 +08:00
this . BoneTagsCapacity
2017-09-21 18:33:05 +08:00
) ;
this . Bones = reader . ReadBlockAt < ResourceSimpleArray < Bone > > (
this . BonesPointer , // offset
this . BonesCount
) ;
2018-03-10 22:27:13 +08:00
this . TransformationsInverted = reader . ReadStructsAt < Matrix > ( this . TransformationsInvertedPointer , this . BonesCount ) ;
this . Transformations = reader . ReadStructsAt < Matrix > ( this . TransformationsPointer , this . BonesCount ) ;
2019-11-06 01:53:20 +08:00
this . ParentIndices = reader . ReadShortsAt ( this . ParentIndicesPointer , this . BonesCount ) ;
this . ChildIndices = reader . ReadShortsAt ( this . ChildIndicesPointer , this . ChildIndicesCount ) ;
2017-09-23 19:46:49 +08:00
2019-11-26 14:00:41 +08:00
AssignBoneParents ( ) ;
2019-11-02 15:14:36 +08:00
2019-11-26 14:00:41 +08:00
BuildBonesMap ( ) ;
2020-01-18 23:36:28 +08:00
//BuildIndices();//testing!
//BuildBoneTags();//testing!
//BuildTransformations();//testing!
//if (BoneTagsCount != Math.Min(BonesCount, BoneTagsCapacity))
//{ }//no hits
2017-09-21 18:33:05 +08:00
}
public override void Write ( ResourceDataWriter writer , params object [ ] parameters )
{
// update structure data
2019-11-05 17:47:10 +08:00
this . BoneTagsPointer = ( ulong ) ( this . BoneTags ! = null ? this . BoneTags . FilePosition : 0 ) ;
2020-01-18 23:36:28 +08:00
this . BoneTagsCapacity = ( ushort ) ( this . BoneTags ! = null ? this . BoneTags . Count : 0 ) ;
2017-09-21 18:33:05 +08:00
this . BonesPointer = ( ulong ) ( this . Bones ! = null ? this . Bones . FilePosition : 0 ) ;
2019-01-28 10:13:45 +08:00
this . TransformationsInvertedPointer = ( ulong ) ( this . TransformationsInvertedBlock ! = null ? this . TransformationsInvertedBlock . FilePosition : 0 ) ;
this . TransformationsPointer = ( ulong ) ( this . TransformationsBlock ! = null ? this . TransformationsBlock . FilePosition : 0 ) ;
this . ParentIndicesPointer = ( ulong ) ( this . ParentIndicesBlock ! = null ? this . ParentIndicesBlock . FilePosition : 0 ) ;
2019-11-05 17:47:10 +08:00
this . ChildIndicesPointer = ( ulong ) ( this . ChildIndicesBlock ! = null ? this . ChildIndicesBlock . FilePosition : 0 ) ;
2019-01-28 10:13:45 +08:00
this . BonesCount = ( ushort ) ( this . Bones ! = null ? this . Bones . Count : 0 ) ;
2019-11-05 17:47:10 +08:00
this . ChildIndicesCount = ( ushort ) ( this . ChildIndicesBlock ! = null ? this . ChildIndicesBlock . ItemCount : 0 ) ;
2020-01-18 23:36:28 +08:00
this . BoneTagsCount = Math . Min ( BonesCount , BoneTagsCapacity ) ;
2019-01-28 10:13:45 +08:00
2017-09-21 18:33:05 +08:00
// write structure data
writer . Write ( this . VFT ) ;
writer . Write ( this . Unknown_4h ) ;
writer . Write ( this . Unknown_8h ) ;
writer . Write ( this . Unknown_Ch ) ;
2019-11-05 17:47:10 +08:00
writer . Write ( this . BoneTagsPointer ) ;
2020-01-18 23:36:28 +08:00
writer . Write ( this . BoneTagsCapacity ) ;
2020-01-18 01:20:40 +08:00
writer . Write ( this . BoneTagsCount ) ;
2017-09-21 18:33:05 +08:00
writer . Write ( this . Unknown_1Ch ) ;
writer . Write ( this . BonesPointer ) ;
writer . Write ( this . TransformationsInvertedPointer ) ;
writer . Write ( this . TransformationsPointer ) ;
writer . Write ( this . ParentIndicesPointer ) ;
2019-11-05 17:47:10 +08:00
writer . Write ( this . ChildIndicesPointer ) ;
2017-09-21 18:33:05 +08:00
writer . Write ( this . Unknown_48h ) ;
writer . Write ( this . Unknown_4Ch ) ;
writer . Write ( this . Unknown_50h ) ;
writer . Write ( this . Unknown_54h ) ;
writer . Write ( this . Unknown_58h ) ;
writer . Write ( this . Unknown_5Ch ) ;
writer . Write ( this . BonesCount ) ;
2019-11-05 17:47:10 +08:00
writer . Write ( this . ChildIndicesCount ) ;
2017-09-21 18:33:05 +08:00
writer . Write ( this . Unknown_62h ) ;
writer . Write ( this . Unknown_64h ) ;
writer . Write ( this . Unknown_68h ) ;
writer . Write ( this . Unknown_6Ch ) ;
}
2020-01-18 01:20:40 +08:00
public void WriteXml ( StringBuilder sb , int indent )
{
2020-01-18 23:36:28 +08:00
YdrXml . ValueTag ( sb , indent , "Unknown1C" , Unknown_1Ch . Value . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "Unknown50" , Unknown_50h . Hash . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "Unknown54" , Unknown_54h . Hash . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "Unknown58" , Unknown_58h . Hash . ToString ( ) ) ;
if ( Bones ? . Data ! = null )
{
YdrXml . WriteItemArray ( sb , Bones . Data . ToArray ( ) , indent , "Bones" ) ;
}
2020-01-18 01:20:40 +08:00
}
public void ReadXml ( XmlNode node )
{
2020-01-18 23:36:28 +08:00
Unknown_1Ch = Xml . GetChildUIntAttribute ( node , "Unknown1C" , "value" ) ;
Unknown_50h = Xml . GetChildUIntAttribute ( node , "Unknown50" , "value" ) ;
Unknown_54h = Xml . GetChildUIntAttribute ( node , "Unknown54" , "value" ) ;
Unknown_58h = Xml . GetChildUIntAttribute ( node , "Unknown58" , "value" ) ;
var bones = XmlMeta . ReadItemArray < Bone > ( node , "Bones" ) ;
if ( bones ! = null )
{
Bones = new ResourceSimpleArray < Bone > ( ) ;
Bones . Data = bones . ToList ( ) ;
}
BuildIndices ( ) ;
BuildBoneTags ( ) ;
BuildTransformations ( ) ;
AssignBoneParents ( ) ;
BuildBonesMap ( ) ;
2020-01-18 01:20:40 +08:00
}
2017-09-21 18:33:05 +08:00
public override IResourceBlock [ ] GetReferences ( )
{
var list = new List < IResourceBlock > ( ) ;
2019-11-05 17:47:10 +08:00
if ( BoneTags ! = null ) list . Add ( BoneTags ) ;
2017-09-21 18:33:05 +08:00
if ( Bones ! = null ) list . Add ( Bones ) ;
2019-01-28 10:13:45 +08:00
if ( TransformationsInverted ! = null )
{
TransformationsInvertedBlock = new ResourceSystemStructBlock < Matrix > ( TransformationsInverted ) ;
list . Add ( TransformationsInvertedBlock ) ;
}
if ( Transformations ! = null )
{
TransformationsBlock = new ResourceSystemStructBlock < Matrix > ( Transformations ) ;
list . Add ( TransformationsBlock ) ;
}
if ( ParentIndices ! = null )
{
2019-11-06 01:53:20 +08:00
ParentIndicesBlock = new ResourceSystemStructBlock < short > ( ParentIndices ) ;
2019-01-28 10:13:45 +08:00
list . Add ( ParentIndicesBlock ) ;
}
2019-11-05 17:47:10 +08:00
if ( ChildIndices ! = null )
2019-01-28 10:13:45 +08:00
{
2019-11-06 01:53:20 +08:00
ChildIndicesBlock = new ResourceSystemStructBlock < short > ( ChildIndices ) ;
2019-11-05 17:47:10 +08:00
list . Add ( ChildIndicesBlock ) ;
2019-01-28 10:13:45 +08:00
}
2017-09-21 18:33:05 +08:00
return list . ToArray ( ) ;
}
2019-11-26 14:00:41 +08:00
public void AssignBoneParents ( )
{
if ( ( Bones ! = null ) & & ( ParentIndices ! = null ) )
{
var maxcnt = Math . Min ( Bones . Count , ParentIndices . Length ) ;
for ( int i = 0 ; i < maxcnt ; i + + )
{
var bone = Bones [ i ] ;
var pind = ParentIndices [ i ] ;
if ( ( pind > = 0 ) & & ( pind < Bones . Count ) )
{
bone . Parent = Bones [ pind ] ;
}
}
}
}
public void BuildBonesMap ( )
{
BonesMap = new Dictionary < ushort , Bone > ( ) ;
if ( Bones ! = null )
{
for ( int i = 0 ; i < Bones . Count ; i + + )
{
var bone = Bones [ i ] ;
BonesMap [ bone . Tag ] = bone ;
bone . UpdateAnimTransform ( ) ;
2020-01-18 23:36:28 +08:00
bone . BindTransformInv = ( i < ( TransformationsInverted ? . Length ? ? 0 ) ) ? TransformationsInverted [ i ] : Matrix . Invert ( bone . AnimTransform ) ;
2019-11-26 14:00:41 +08:00
bone . BindTransformInv . M44 = 1.0f ;
bone . UpdateSkinTransform ( ) ;
2020-01-18 23:36:28 +08:00
bone . TransformUnk = ( i < ( Transformations ? . Length ? ? 0 ) ) ? Transformations [ i ] . Column4 : Vector4 . Zero ; //still dont know what this is
}
}
}
public void BuildIndices ( )
{
var parents = new List < short > ( ) ;
var childs = new List < short > ( ) ;
if ( Bones ! = null )
{
Bone lastbone = null ;
for ( int i = 0 ; i < Bones . Count ; i + + )
{
var bone = Bones [ i ] ;
var pind = bone . ParentIndex ;
parents . Add ( pind ) ;
if ( pind > = 0 )
{
childs . Add ( bone . Index ) ;
childs . Add ( pind ) ;
lastbone = bone ;
}
}
if ( lastbone ! = null )
{
var npad = 8 - ( childs . Count % 8 ) ;
if ( npad < 8 )
{
for ( int i = 0 ; i < npad ; i + = 2 )
{
childs . Add ( lastbone . Index ) ;
childs . Add ( lastbone . ParentIndex ) ;
}
}
2019-11-26 14:00:41 +08:00
}
2020-01-18 23:36:28 +08:00
////just testing - not really working properly - how to generate these arrays identical to originals? seem to have weird repeats? (not just end padding)
//var numchilds = ChildIndices?.Length ?? 0;
//if (numchilds < childs.Count)
//{ }
//else
//{
// for (int i = 0; i < numchilds; i++)
// {
// var oc = ChildIndices[i];
// var nc = childs[i];
// if (nc != oc)
// { }
// }
//}
2019-11-26 14:00:41 +08:00
}
2020-01-18 23:36:28 +08:00
ParentIndices = ( parents . Count > 0 ) ? parents . ToArray ( ) : null ;
ChildIndices = ( childs . Count > 0 ) ? childs . ToArray ( ) : null ;
}
public void BuildBoneTags ( )
{
var tags = new List < SkeletonBoneTag > ( ) ;
if ( Bones ? . Data ! = null )
{
for ( int i = 0 ; i < Bones . Count ; i + + )
{
var bone = Bones [ i ] ;
var tag = new SkeletonBoneTag ( ) ;
tag . BoneTag = bone . Tag ;
tag . BoneIndex = ( uint ) i ;
tags . Add ( tag ) ;
}
}
if ( tags . Count < 2 )
{
if ( BoneTags ! = null )
{ }
BoneTags = null ;
return ;
}
var numbuckets = GetNumHashBuckets ( tags . Count ) ;
var buckets = new List < SkeletonBoneTag > [ numbuckets ] ;
foreach ( var tag in tags )
{
var b = tag . BoneTag % numbuckets ;
var bucket = buckets [ b ] ;
if ( bucket = = null )
{
bucket = new List < SkeletonBoneTag > ( ) ;
buckets [ b ] = bucket ;
}
bucket . Add ( tag ) ;
}
var newtags = new List < SkeletonBoneTag > ( ) ;
foreach ( var b in buckets )
{
if ( ( b ? . Count ? ? 0 ) = = 0 ) newtags . Add ( null ) ;
else
{
b . Reverse ( ) ;
newtags . Add ( b [ 0 ] ) ;
var p = b [ 0 ] ;
for ( int i = 1 ; i < b . Count ; i + + )
{
var c = b [ i ] ;
c . Next = null ;
p . Next = c ;
p = c ;
}
}
}
//if (BoneTags?.data_items != null) //just testing - all ok
//{
// var numtags = BoneTags.data_items.Length;
// if (numbuckets != numtags)
// { }
// else
// {
// for (int i = 0; i < numtags; i++)
// {
// var ot = BoneTags.data_items[i];
// var nt = newtags[i];
// if ((ot == null) != (nt == null))
// { }
// else if (ot != null)
// {
// if (ot.BoneIndex != nt.BoneIndex)
// { }
// if (ot.BoneTag != nt.BoneTag)
// { }
// }
// }
// }
//}
BoneTags = new ResourcePointerArray64 < SkeletonBoneTag > ( ) ;
BoneTags . data_items = newtags . ToArray ( ) ;
}
public void BuildTransformations ( )
{
var transforms = new List < Matrix > ( ) ;
var transformsinv = new List < Matrix > ( ) ;
if ( Bones ? . Data ! = null )
{
foreach ( var bone in Bones . Data )
{
var pos = bone . Translation ;
var ori = bone . Rotation ;
var sca = bone . Scale ;
var m = Matrix . AffineTransformation ( 1.0f , ori , pos ) ; //(global transform)
m . ScaleVector * = sca ;
var mi = Matrix . Invert ( m ) ;
m . Column4 = bone . TransformUnk ; // new Vector4(0, 4, -3, 0);//???
mi . Column4 = Vector4 . Zero ;
transforms . Add ( m ) ;
transformsinv . Add ( mi ) ;
}
}
//if (Transformations != null) //just testing! - all ok
//{
// if (Transformations.Length != transforms.Count)
// { }
// else
// {
// for (int i = 0; i < Transformations.Length; i++)
// {
// if (Transformations[i].Column1 != transforms[i].Column1)
// { }
// if (Transformations[i].Column2 != transforms[i].Column2)
// { }
// if (Transformations[i].Column3 != transforms[i].Column3)
// { }
// if (Transformations[i].Column4 != transforms[i].Column4)
// { }
// }
// }
// if (TransformationsInverted.Length != transformsinv.Count)
// { }
// else
// {
// for (int i = 0; i < TransformationsInverted.Length; i++)
// {
// if (TransformationsInverted[i].Column4 != transformsinv[i].Column4)
// { }
// }
// }
//}
Transformations = ( transforms . Count > 0 ) ? transforms . ToArray ( ) : null ;
TransformationsInverted = ( transformsinv . Count > 0 ) ? transformsinv . ToArray ( ) : null ;
}
public static uint GetNumHashBuckets ( int nHashes )
{
//todo: refactor with same in Clip.cs?
if ( nHashes < 11 ) return 11 ;
else if ( nHashes < 29 ) return 29 ;
else if ( nHashes < 59 ) return 59 ;
else if ( nHashes < 107 ) return 107 ;
else if ( nHashes < 191 ) return 191 ;
else if ( nHashes < 331 ) return 331 ;
else if ( nHashes < 563 ) return 563 ;
else if ( nHashes < 953 ) return 953 ;
else if ( nHashes < 1609 ) return 1609 ;
else if ( nHashes < 2729 ) return 2729 ;
else if ( nHashes < 4621 ) return 4621 ;
else if ( nHashes < 7841 ) return 7841 ;
else if ( nHashes < 13297 ) return 13297 ;
else if ( nHashes < 22571 ) return 22571 ;
else if ( nHashes < 38351 ) return 38351 ;
else if ( nHashes < 65167 ) return 65167 ;
else /*if (nHashes < 65521)*/ return 65521 ;
//return ((uint)nHashes / 4) * 4 + 3;
2019-11-26 14:00:41 +08:00
}
public void ResetBoneTransforms ( )
{
if ( Bones ? . Data = = null ) return ;
foreach ( var bone in Bones . Data )
{
bone . ResetAnimTransform ( ) ;
}
UpdateBoneTransforms ( ) ;
}
public void UpdateBoneTransforms ( )
{
if ( Bones ? . Data = = null ) return ;
if ( ( BoneTransforms = = null ) | | ( BoneTransforms . Length ! = Bones . Data . Count ) )
{
BoneTransforms = new Matrix3_s [ Bones . Data . Count ] ;
}
for ( int i = 0 ; i < Bones . Data . Count ; i + + )
{
var bone = Bones . Data [ i ] ;
Matrix b = bone . SkinTransform ;
Matrix3_s bt = new Matrix3_s ( ) ;
bt . Row1 = b . Column1 ;
bt . Row2 = b . Column2 ;
bt . Row3 = b . Column3 ;
BoneTransforms [ i ] = bt ;
}
}
public Skeleton Clone ( )
{
var skel = new Skeleton ( ) ;
2020-01-18 23:36:28 +08:00
skel . BoneTagsCapacity = BoneTagsCapacity ;
2020-01-18 01:20:40 +08:00
skel . BoneTagsCount = BoneTagsCount ;
2019-11-26 14:00:41 +08:00
skel . Unknown_1Ch = Unknown_1Ch ;
skel . Unknown_50h = Unknown_50h ;
skel . Unknown_54h = Unknown_54h ;
skel . Unknown_58h = Unknown_58h ;
skel . BonesCount = BonesCount ;
skel . ChildIndicesCount = ChildIndicesCount ;
if ( BoneTags ! = null )
{
skel . BoneTags = new ResourcePointerArray64 < SkeletonBoneTag > ( ) ;
if ( BoneTags . data_items ! = null )
{
skel . BoneTags . data_items = new SkeletonBoneTag [ BoneTags . data_items . Length ] ;
for ( int i = 0 ; i < BoneTags . data_items . Length ; i + + )
{
var obt = BoneTags . data_items [ i ] ;
var nbt = new SkeletonBoneTag ( ) ;
skel . BoneTags . data_items [ i ] = nbt ;
while ( obt ! = null )
{
nbt . BoneTag = obt . BoneTag ;
nbt . BoneIndex = obt . BoneIndex ;
2020-01-18 23:36:28 +08:00
obt = obt . Next ;
2019-11-26 14:00:41 +08:00
if ( obt ! = null )
{
var nxt = new SkeletonBoneTag ( ) ;
2020-01-18 23:36:28 +08:00
nbt . Next = nxt ;
2019-11-26 14:00:41 +08:00
nbt = nxt ;
}
}
}
}
}
if ( Bones ! = null )
{
skel . Bones = new ResourceSimpleArray < Bone > ( ) ;
if ( Bones . Data ! = null )
{
skel . Bones . Data = new List < Bone > ( ) ;
for ( int i = 0 ; i < Bones . Data . Count ; i + + )
{
var ob = Bones . Data [ i ] ;
var nb = new Bone ( ) ;
nb . Rotation = ob . Rotation ;
nb . Translation = ob . Translation ;
nb . Scale = ob . Scale ;
nb . NextSiblingIndex = ob . NextSiblingIndex ;
nb . ParentIndex = ob . ParentIndex ;
nb . Flags = ob . Flags ;
nb . Index = ob . Index ;
nb . Tag = ob . Tag ;
nb . Index2 = ob . Index2 ;
nb . Name = ob . Name ;
nb . AnimRotation = ob . AnimRotation ;
nb . AnimTranslation = ob . AnimTranslation ;
nb . AnimScale = ob . AnimScale ;
nb . AnimTransform = ob . AnimTransform ;
nb . BindTransformInv = ob . BindTransformInv ;
nb . SkinTransform = ob . SkinTransform ;
skel . Bones . Data . Add ( nb ) ;
}
}
}
2019-11-27 12:01:43 +08:00
skel . TransformationsInverted = ( Matrix [ ] ) TransformationsInverted ? . Clone ( ) ;
skel . Transformations = ( Matrix [ ] ) Transformations ? . Clone ( ) ;
skel . ParentIndices = ( short [ ] ) ParentIndices ? . Clone ( ) ;
skel . ChildIndices = ( short [ ] ) ChildIndices ? . Clone ( ) ;
2019-11-26 14:00:41 +08:00
skel . AssignBoneParents ( ) ;
skel . BuildBonesMap ( ) ;
return skel ;
}
2017-09-21 18:33:05 +08:00
}
2020-01-18 23:36:28 +08:00
[TypeConverter(typeof(ExpandableObjectConverter))] public class SkeletonBoneTag : ResourceSystemBlock
2017-09-21 18:33:05 +08:00
{
public override long BlockLength
{
get { return 16 ; }
}
// structure data
2019-11-05 17:47:10 +08:00
public uint BoneTag { get ; set ; }
public uint BoneIndex { get ; set ; }
2020-01-18 23:36:28 +08:00
public ulong NextPointer { get ; set ; }
2017-09-21 18:33:05 +08:00
// reference data
2020-01-18 23:36:28 +08:00
public SkeletonBoneTag Next { get ; set ; } //don't know why it's linked here
2017-09-21 18:33:05 +08:00
public override void Read ( ResourceDataReader reader , params object [ ] parameters )
{
// read structure data
2019-11-05 17:47:10 +08:00
this . BoneTag = reader . ReadUInt32 ( ) ;
this . BoneIndex = reader . ReadUInt32 ( ) ;
2020-01-18 23:36:28 +08:00
this . NextPointer = reader . ReadUInt64 ( ) ;
2017-09-21 18:33:05 +08:00
// read reference data
2020-01-18 23:36:28 +08:00
this . Next = reader . ReadBlockAt < SkeletonBoneTag > (
this . NextPointer // offset
2017-09-21 18:33:05 +08:00
) ;
}
public override void Write ( ResourceDataWriter writer , params object [ ] parameters )
{
// update structure data
2020-01-18 23:36:28 +08:00
this . NextPointer = ( ulong ) ( this . Next ! = null ? this . Next . FilePosition : 0 ) ;
2017-09-21 18:33:05 +08:00
// write structure data
2019-11-05 17:47:10 +08:00
writer . Write ( this . BoneTag ) ;
writer . Write ( this . BoneIndex ) ;
2020-01-18 23:36:28 +08:00
writer . Write ( this . NextPointer ) ;
2020-01-18 01:20:40 +08:00
}
2017-09-21 18:33:05 +08:00
public override IResourceBlock [ ] GetReferences ( )
{
var list = new List < IResourceBlock > ( ) ;
2020-01-18 23:36:28 +08:00
if ( Next ! = null ) list . Add ( Next ) ;
2017-09-21 18:33:05 +08:00
return list . ToArray ( ) ;
}
2019-11-05 17:47:10 +08:00
public override string ToString ( )
{
return BoneTag . ToString ( ) + ": " + BoneIndex . ToString ( ) ;
}
2020-01-18 01:20:40 +08:00
2017-09-21 18:33:05 +08:00
}
2019-11-06 01:53:20 +08:00
[Flags] public enum EBoneFlags : ushort
{
None = 0 ,
RotX = 0x1 ,
RotY = 0x2 ,
RotZ = 0x4 ,
LimitRotation = 0x8 ,
TransX = 0x10 ,
TransY = 0x20 ,
TransZ = 0x40 ,
LimitTranslation = 0x80 ,
ScaleX = 0x100 ,
ScaleY = 0x200 ,
ScaleZ = 0x400 ,
LimitScale = 0x800 ,
Unk0 = 0x1000 ,
Unk1 = 0x2000 ,
Unk2 = 0x4000 ,
Unk3 = 0x8000 ,
}
2020-01-18 01:20:40 +08:00
[TypeConverter(typeof(ExpandableObjectConverter))] public class Bone : ResourceSystemBlock , IMetaXmlItem
2017-09-21 18:33:05 +08:00
{
public override long BlockLength
{
get { return 80 ; }
}
// structure data
2017-09-24 18:14:41 +08:00
public Quaternion Rotation { get ; set ; }
public Vector3 Translation { get ; set ; }
2018-08-12 00:13:52 +08:00
public uint Unknown_1Ch { get ; set ; } // 0x00000000 RHW?
2019-11-03 19:43:39 +08:00
public Vector3 Scale { get ; set ; }
2019-11-26 14:00:41 +08:00
public float Unknown_2Ch { get ; set ; } = 1.0f ; // 1.0 RHW?
2019-11-06 01:53:20 +08:00
public short NextSiblingIndex { get ; set ; } //limb end index? IK chain?
2017-09-24 18:14:41 +08:00
public short ParentIndex { get ; set ; }
2017-09-21 18:33:05 +08:00
public uint Unknown_34h { get ; set ; } // 0x00000000
public ulong NamePointer { get ; set ; }
2019-11-06 01:53:20 +08:00
public EBoneFlags Flags { get ; set ; }
public short Index { get ; set ; }
2019-11-05 17:47:10 +08:00
public ushort Tag { get ; set ; }
2020-01-18 23:36:28 +08:00
public short Index2 { get ; set ; } //always same as Index
2017-09-21 18:33:05 +08:00
public uint Unknown_48h { get ; set ; } // 0x00000000
public uint Unknown_4Ch { get ; set ; } // 0x00000000
// reference data
public string Name { get ; set ; }
2017-09-23 19:46:49 +08:00
public Bone Parent { get ; set ; }
2019-01-28 10:13:45 +08:00
private string_r NameBlock = null ;
2017-09-23 19:46:49 +08:00
2019-11-02 15:14:36 +08:00
//used by CW for animating skeletons.
2019-11-03 19:43:39 +08:00
public Quaternion AnimRotation ; //relative to parent
public Vector3 AnimTranslation ; //relative to parent
public Vector3 AnimScale ;
public Matrix AnimTransform ; //absolute world transform, animated
public Matrix BindTransformInv ; //inverse of bind pose transform
public Matrix SkinTransform ; //transform to use for skin meshes
2020-01-18 23:36:28 +08:00
public Vector4 TransformUnk { get ; set ; } //unknown value (column 4) from skeleton's transform array, used for IO purposes
2019-11-02 15:14:36 +08:00
2017-09-21 18:33:05 +08:00
public override void Read ( ResourceDataReader reader , params object [ ] parameters )
{
// read structure data
2017-09-24 18:14:41 +08:00
this . Rotation = new Quaternion ( reader . ReadVector4 ( ) ) ;
this . Translation = reader . ReadVector3 ( ) ;
2017-09-21 18:33:05 +08:00
this . Unknown_1Ch = reader . ReadUInt32 ( ) ;
2019-11-03 19:43:39 +08:00
this . Scale = reader . ReadVector3 ( ) ;
2017-09-21 18:33:05 +08:00
this . Unknown_2Ch = reader . ReadSingle ( ) ;
2019-11-06 01:53:20 +08:00
this . NextSiblingIndex = reader . ReadInt16 ( ) ;
2017-09-24 18:14:41 +08:00
this . ParentIndex = reader . ReadInt16 ( ) ;
2017-09-21 18:33:05 +08:00
this . Unknown_34h = reader . ReadUInt32 ( ) ;
this . NamePointer = reader . ReadUInt64 ( ) ;
2019-11-06 01:53:20 +08:00
this . Flags = ( EBoneFlags ) reader . ReadUInt16 ( ) ;
this . Index = reader . ReadInt16 ( ) ;
2019-11-05 17:47:10 +08:00
this . Tag = reader . ReadUInt16 ( ) ;
2019-11-06 01:53:20 +08:00
this . Index2 = reader . ReadInt16 ( ) ;
2017-09-21 18:33:05 +08:00
this . Unknown_48h = reader . ReadUInt32 ( ) ;
this . Unknown_4Ch = reader . ReadUInt32 ( ) ;
// read reference data
this . Name = reader . ReadStringAt ( //BlockAt<string_r>(
this . NamePointer // offset
) ;
2019-11-02 15:14:36 +08:00
2020-01-18 23:36:28 +08:00
//if (Index2 != Index)
//{ }//no hits
2019-11-02 15:14:36 +08:00
AnimRotation = Rotation ;
AnimTranslation = Translation ;
2019-11-03 19:43:39 +08:00
AnimScale = Scale ;
2017-09-21 18:33:05 +08:00
}
public override void Write ( ResourceDataWriter writer , params object [ ] parameters )
{
// update structure data
2019-01-28 10:13:45 +08:00
this . NamePointer = ( ulong ) ( this . NameBlock ! = null ? this . NameBlock . FilePosition : 0 ) ;
2017-09-21 18:33:05 +08:00
// write structure data
2017-09-24 18:14:41 +08:00
writer . Write ( this . Rotation . ToVector4 ( ) ) ;
writer . Write ( this . Translation ) ;
2017-09-21 18:33:05 +08:00
writer . Write ( this . Unknown_1Ch ) ;
2019-11-03 19:43:39 +08:00
writer . Write ( this . Scale ) ;
2017-09-21 18:33:05 +08:00
writer . Write ( this . Unknown_2Ch ) ;
2018-08-12 00:13:52 +08:00
writer . Write ( this . NextSiblingIndex ) ;
2017-09-24 18:14:41 +08:00
writer . Write ( this . ParentIndex ) ;
2017-09-21 18:33:05 +08:00
writer . Write ( this . Unknown_34h ) ;
writer . Write ( this . NamePointer ) ;
2019-11-06 01:53:20 +08:00
writer . Write ( ( ushort ) this . Flags ) ;
2019-11-05 17:47:10 +08:00
writer . Write ( this . Index ) ;
writer . Write ( this . Tag ) ;
writer . Write ( this . Index2 ) ;
2017-09-21 18:33:05 +08:00
writer . Write ( this . Unknown_48h ) ;
writer . Write ( this . Unknown_4Ch ) ;
}
2020-01-18 01:20:40 +08:00
public void WriteXml ( StringBuilder sb , int indent )
{
2020-01-18 23:36:28 +08:00
YdrXml . StringTag ( sb , indent , "Name" , Name ) ;
YdrXml . ValueTag ( sb , indent , "Tag" , Tag . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "Index" , Index . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "ParentIndex" , ParentIndex . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "SiblingIndex" , NextSiblingIndex . ToString ( ) ) ;
YdrXml . StringTag ( sb , indent , "Flags" , Flags . ToString ( ) ) ;
YdrXml . SelfClosingTag ( sb , indent , "Translation " + FloatUtil . GetVector3XmlString ( Translation ) ) ;
YdrXml . SelfClosingTag ( sb , indent , "Rotation " + FloatUtil . GetVector4XmlString ( Rotation . ToVector4 ( ) ) ) ;
YdrXml . SelfClosingTag ( sb , indent , "Scale " + FloatUtil . GetVector3XmlString ( Scale ) ) ;
YdrXml . SelfClosingTag ( sb , indent , "TransformUnk " + FloatUtil . GetVector4XmlString ( TransformUnk ) ) ;
2020-01-18 01:20:40 +08:00
}
public void ReadXml ( XmlNode node )
{
2020-01-18 23:36:28 +08:00
Name = Xml . GetChildInnerText ( node , "Name" ) ;
Tag = ( ushort ) Xml . GetChildUIntAttribute ( node , "Tag" , "value" ) ;
Index = ( short ) Xml . GetChildIntAttribute ( node , "Index" , "value" ) ;
Index2 = Index ;
ParentIndex = ( short ) Xml . GetChildIntAttribute ( node , "ParentIndex" , "value" ) ;
NextSiblingIndex = ( short ) Xml . GetChildIntAttribute ( node , "SiblingIndex" , "value" ) ;
Flags = Xml . GetChildEnumInnerText < EBoneFlags > ( node , "Flags" ) ;
Translation = Xml . GetChildVector3Attributes ( node , "Translation" , "x" , "y" , "z" ) ;
Rotation = Xml . GetChildVector4Attributes ( node , "Rotation" , "x" , "y" , "z" , "w" ) . ToQuaternion ( ) ;
Scale = Xml . GetChildVector3Attributes ( node , "Scale" , "x" , "y" , "z" ) ;
TransformUnk = Xml . GetChildVector4Attributes ( node , "TransformUnk" , "x" , "y" , "z" , "w" ) ;
2020-01-18 01:20:40 +08:00
}
2017-09-21 18:33:05 +08:00
public override IResourceBlock [ ] GetReferences ( )
{
var list = new List < IResourceBlock > ( ) ;
2019-01-28 10:13:45 +08:00
if ( Name ! = null )
{
NameBlock = ( string_r ) Name ;
list . Add ( NameBlock ) ;
}
2017-09-21 18:33:05 +08:00
return list . ToArray ( ) ;
}
public override string ToString ( )
{
2019-11-05 17:47:10 +08:00
return Tag . ToString ( ) + ": " + Name ;
2017-09-21 18:33:05 +08:00
}
2019-11-03 19:43:39 +08:00
public void UpdateAnimTransform ( )
{
//AnimTransform = Matrix.AffineTransformation(1.0f, AnimRotation, AnimTranslation);//(local transform)
var pos = AnimTranslation ;
var ori = AnimRotation ;
var sca = AnimScale ;
var pbone = Parent ;
while ( pbone ! = null )
{
2019-11-09 23:01:52 +08:00
pos = pbone . AnimRotation . Multiply ( pos /** pbone.AnimScale*/ ) + pbone . AnimTranslation ;
2019-11-03 19:43:39 +08:00
ori = pbone . AnimRotation * ori ;
pbone = pbone . Parent ;
}
AnimTransform = Matrix . AffineTransformation ( 1.0f , ori , pos ) ; //(global transform)
AnimTransform . ScaleVector * = sca ;
2019-11-03 21:04:02 +08:00
}
public void UpdateSkinTransform ( )
{
2019-11-03 19:43:39 +08:00
SkinTransform = BindTransformInv * AnimTransform ;
//SkinTransform = Matrix.Identity;//(for testing)
}
2019-11-05 18:13:04 +08:00
2019-11-08 15:58:56 +08:00
public void ResetAnimTransform ( )
{
AnimRotation = Rotation ;
AnimTranslation = Translation ;
AnimScale = Scale ;
UpdateAnimTransform ( ) ;
UpdateSkinTransform ( ) ;
}
2019-11-05 18:13:04 +08:00
public static uint ElfHash_Uppercased ( string str )
{
uint hash = 0 ;
uint x = 0 ;
uint i = 0 ;
for ( i = 0 ; i < str . Length ; i + + )
{
var c = ( ( byte ) str [ ( int ) i ] ) ;
if ( ( byte ) ( c - 'a' ) < = 25 u ) // to uppercase
c - = 32 ;
hash = ( hash < < 4 ) + c ;
if ( ( x = hash & 0xF0000000 ) ! = 0 )
{
hash ^ = ( x > > 24 ) ;
}
hash & = ~ x ;
}
return hash ;
}
public static ushort CalculateBoneHash ( string boneName )
{
return ( ushort ) ( ElfHash_Uppercased ( boneName ) % 0xFE8F + 0x170 ) ;
}
2017-09-21 18:33:05 +08:00
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class Joints : ResourceSystemBlock
{
public override long BlockLength
{
get { return 64 ; }
}
// structure data
public uint VFT { get ; set ; }
2020-01-18 01:20:40 +08:00
public uint Unknown_4h { get ; set ; } = 1 ; // 0x00000001
2017-09-21 18:33:05 +08:00
public uint Unknown_8h { get ; set ; } // 0x00000000
public uint Unknown_Ch { get ; set ; } // 0x00000000
public ulong RotationLimitsPointer { get ; set ; }
public ulong TranslationLimitsPointer { get ; set ; }
public uint Unknown_20h { get ; set ; } // 0x00000000
public uint Unknown_24h { get ; set ; } // 0x00000000
public uint Unknown_28h { get ; set ; } // 0x00000000
public uint Unknown_2Ch { get ; set ; } // 0x00000000
public ushort RotationLimitsCount { get ; set ; }
public ushort TranslationLimitsCount { get ; set ; }
public ushort Unknown_34h { get ; set ; } // 0x0000
2020-01-18 01:20:40 +08:00
public ushort Unknown_36h { get ; set ; } = 1 ; // 0x0001
2017-09-21 18:33:05 +08:00
public uint Unknown_38h { get ; set ; } // 0x00000000
public uint Unknown_3Ch { get ; set ; } // 0x00000000
// reference data
public JointRotationLimit_s [ ] RotationLimits { get ; set ; }
public JointTranslationLimit_s [ ] TranslationLimits { get ; set ; }
2019-01-28 10:13:45 +08:00
private ResourceSystemStructBlock < JointRotationLimit_s > RotationLimitsBlock = null ; //for saving only
private ResourceSystemStructBlock < JointTranslationLimit_s > TranslationLimitsBlock = null ;
2017-09-21 18:33:05 +08:00
public override void Read ( ResourceDataReader reader , params object [ ] parameters )
{
// read structure data
this . VFT = reader . ReadUInt32 ( ) ;
this . Unknown_4h = reader . ReadUInt32 ( ) ;
this . Unknown_8h = reader . ReadUInt32 ( ) ;
this . Unknown_Ch = reader . ReadUInt32 ( ) ;
this . RotationLimitsPointer = reader . ReadUInt64 ( ) ;
this . TranslationLimitsPointer = reader . ReadUInt64 ( ) ;
this . Unknown_20h = reader . ReadUInt32 ( ) ;
this . Unknown_24h = reader . ReadUInt32 ( ) ;
this . Unknown_28h = reader . ReadUInt32 ( ) ;
this . Unknown_2Ch = reader . ReadUInt32 ( ) ;
this . RotationLimitsCount = reader . ReadUInt16 ( ) ;
this . TranslationLimitsCount = reader . ReadUInt16 ( ) ;
this . Unknown_34h = reader . ReadUInt16 ( ) ;
this . Unknown_36h = reader . ReadUInt16 ( ) ;
this . Unknown_38h = reader . ReadUInt32 ( ) ;
this . Unknown_3Ch = reader . ReadUInt32 ( ) ;
// read reference data
this . RotationLimits = reader . ReadStructsAt < JointRotationLimit_s > ( this . RotationLimitsPointer , this . RotationLimitsCount ) ;
this . TranslationLimits = reader . ReadStructsAt < JointTranslationLimit_s > ( this . TranslationLimitsPointer , this . TranslationLimitsCount ) ;
}
public override void Write ( ResourceDataWriter writer , params object [ ] parameters )
{
// update structure data
2019-01-28 10:13:45 +08:00
this . RotationLimitsPointer = ( ulong ) ( this . RotationLimitsBlock ! = null ? this . RotationLimitsBlock . FilePosition : 0 ) ;
this . TranslationLimitsPointer = ( ulong ) ( this . TranslationLimitsBlock ! = null ? this . TranslationLimitsBlock . FilePosition : 0 ) ;
this . RotationLimitsCount = ( ushort ) ( this . RotationLimitsBlock ! = null ? this . RotationLimitsBlock . ItemCount : 0 ) ;
this . TranslationLimitsCount = ( ushort ) ( this . TranslationLimitsBlock ! = null ? this . TranslationLimitsBlock . ItemCount : 0 ) ;
2017-09-21 18:33:05 +08:00
// write structure data
writer . Write ( this . VFT ) ;
writer . Write ( this . Unknown_4h ) ;
writer . Write ( this . Unknown_8h ) ;
writer . Write ( this . Unknown_Ch ) ;
writer . Write ( this . RotationLimitsPointer ) ;
writer . Write ( this . TranslationLimitsPointer ) ;
writer . Write ( this . Unknown_20h ) ;
writer . Write ( this . Unknown_24h ) ;
writer . Write ( this . Unknown_28h ) ;
writer . Write ( this . Unknown_2Ch ) ;
writer . Write ( this . RotationLimitsCount ) ;
writer . Write ( this . TranslationLimitsCount ) ;
writer . Write ( this . Unknown_34h ) ;
writer . Write ( this . Unknown_36h ) ;
writer . Write ( this . Unknown_38h ) ;
writer . Write ( this . Unknown_3Ch ) ;
}
2020-01-18 01:20:40 +08:00
public void WriteXml ( StringBuilder sb , int indent )
{
if ( RotationLimits ! = null )
{
YdrXml . WriteItemArray ( sb , RotationLimits , indent , "RotationLimits" ) ;
}
if ( TranslationLimits ! = null )
{
YdrXml . WriteItemArray ( sb , TranslationLimits , indent , "TranslationLimits" ) ;
}
}
public void ReadXml ( XmlNode node )
{
RotationLimits = XmlMeta . ReadItemArray < JointRotationLimit_s > ( node , "RotationLimits" ) ;
TranslationLimits = XmlMeta . ReadItemArray < JointTranslationLimit_s > ( node , "TranslationLimits" ) ;
}
2017-09-21 18:33:05 +08:00
public override IResourceBlock [ ] GetReferences ( )
{
var list = new List < IResourceBlock > ( ) ;
2019-01-28 10:13:45 +08:00
if ( RotationLimits ! = null )
{
RotationLimitsBlock = new ResourceSystemStructBlock < JointRotationLimit_s > ( RotationLimits ) ;
list . Add ( RotationLimitsBlock ) ;
}
if ( TranslationLimits ! = null )
{
TranslationLimitsBlock = new ResourceSystemStructBlock < JointTranslationLimit_s > ( TranslationLimits ) ;
list . Add ( TranslationLimitsBlock ) ;
}
2017-09-21 18:33:05 +08:00
return list . ToArray ( ) ;
}
}
2020-01-18 01:20:40 +08:00
[TypeConverter(typeof(ExpandableObjectConverter))] public struct JointRotationLimit_s : IMetaXmlItem
2017-09-21 18:33:05 +08:00
{
// structure data
public uint Unknown_0h { get ; set ; } // 0x00000000
public uint Unknown_4h { get ; set ; } // 0x00000000
public ushort BoneId { get ; set ; }
public ushort Unknown_Ah { get ; set ; }
public uint Unknown_Ch { get ; set ; } // 0x00000001
public uint Unknown_10h { get ; set ; } // 0x00000003
public uint Unknown_14h { get ; set ; } // 0x00000000
public uint Unknown_18h { get ; set ; } // 0x00000000
public uint Unknown_1Ch { get ; set ; } // 0x00000000
public uint Unknown_20h { get ; set ; } // 0x00000000
public uint Unknown_24h { get ; set ; } // 0x00000000
public uint Unknown_28h { get ; set ; } // 0x00000000
public float Unknown_2Ch { get ; set ; } // 1.0
public uint Unknown_30h { get ; set ; } // 0x00000000
public uint Unknown_34h { get ; set ; } // 0x00000000
public uint Unknown_38h { get ; set ; } // 0x00000000
public uint Unknown_3Ch { get ; set ; } // 0x00000000
public float Unknown_40h { get ; set ; } // 1.0
public uint Unknown_44h { get ; set ; } // 0x00000000
public uint Unknown_48h { get ; set ; } // 0x00000000
public uint Unknown_4Ch { get ; set ; } // 0x00000000
public float Unknown_50h { get ; set ; } // -pi
public float Unknown_54h { get ; set ; } // pi
public float Unknown_58h { get ; set ; } // 1.0
2018-08-14 18:15:52 +08:00
public Vector3 Min { get ; set ; }
public Vector3 Max { get ; set ; }
2017-09-21 18:33:05 +08:00
public float Unknown_74h { get ; set ; } // pi
public float Unknown_78h { get ; set ; } // -pi
public float Unknown_7Ch { get ; set ; } // pi
public float Unknown_80h { get ; set ; } // pi
public float Unknown_84h { get ; set ; } // -pi
public float Unknown_88h { get ; set ; } // pi
public float Unknown_8Ch { get ; set ; } // pi
public float Unknown_90h { get ; set ; } // -pi
public float Unknown_94h { get ; set ; } // pi
public float Unknown_98h { get ; set ; } // pi
public float Unknown_9Ch { get ; set ; } // -pi
public float Unknown_A0h { get ; set ; } // pi
public float Unknown_A4h { get ; set ; } // pi
public float Unknown_A8h { get ; set ; } // -pi
public float Unknown_ACh { get ; set ; } // pi
public float Unknown_B0h { get ; set ; } // pi
public float Unknown_B4h { get ; set ; } // -pi
public float Unknown_B8h { get ; set ; } // pi
public uint Unknown_BCh { get ; set ; } // 0x00000100
2020-01-18 01:20:40 +08:00
2020-01-18 23:36:28 +08:00
private void Init ( )
2020-01-18 01:20:40 +08:00
{
var pi = ( float ) Math . PI ;
Unknown_0h = 0 ;
Unknown_4h = 0 ;
BoneId = 0 ;
Unknown_Ah = 0 ;
Unknown_Ch = 1 ;
Unknown_10h = 3 ;
Unknown_14h = 0 ;
Unknown_18h = 0 ;
Unknown_1Ch = 0 ;
Unknown_20h = 0 ;
Unknown_24h = 0 ;
Unknown_28h = 0 ;
Unknown_2Ch = 1.0f ;
Unknown_30h = 0 ;
Unknown_34h = 0 ;
Unknown_38h = 0 ;
Unknown_3Ch = 0 ;
Unknown_40h = 1.0f ;
Unknown_44h = 0 ;
Unknown_48h = 0 ;
Unknown_4Ch = 0 ;
Unknown_50h = - pi ;
Unknown_54h = pi ;
Unknown_58h = 1.0f ;
Min = Vector3 . Zero ;
Max = Vector3 . Zero ;
Unknown_74h = pi ;
Unknown_78h = - pi ;
Unknown_7Ch = pi ;
Unknown_80h = pi ;
Unknown_84h = - pi ;
Unknown_88h = pi ;
Unknown_8Ch = pi ;
Unknown_90h = - pi ;
Unknown_94h = pi ;
Unknown_98h = pi ;
Unknown_9Ch = - pi ;
Unknown_A0h = pi ;
Unknown_A4h = pi ;
Unknown_A8h = - pi ;
Unknown_ACh = pi ;
Unknown_B0h = pi ;
Unknown_B4h = - pi ;
Unknown_B8h = pi ;
Unknown_BCh = 0x100 ;
}
public void WriteXml ( StringBuilder sb , int indent )
{
YdrXml . ValueTag ( sb , indent , "BoneId" , BoneId . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "UnknownA" , Unknown_Ah . ToString ( ) ) ;
YdrXml . SelfClosingTag ( sb , indent , "Min " + FloatUtil . GetVector3XmlString ( Min ) ) ;
YdrXml . SelfClosingTag ( sb , indent , "Max " + FloatUtil . GetVector3XmlString ( Max ) ) ;
}
public void ReadXml ( XmlNode node )
{
2020-01-18 23:36:28 +08:00
Init ( ) ;
2020-01-18 01:20:40 +08:00
BoneId = ( ushort ) Xml . GetChildUIntAttribute ( node , "BoneId" , "value" ) ;
Unknown_Ah = ( ushort ) Xml . GetChildUIntAttribute ( node , "UnknownA" , "value" ) ;
Min = Xml . GetChildVector3Attributes ( node , "Min" , "x" , "y" , "z" ) ;
Max = Xml . GetChildVector3Attributes ( node , "Max" , "x" , "y" , "z" ) ;
}
2017-09-21 18:33:05 +08:00
}
2020-01-18 01:20:40 +08:00
[TypeConverter(typeof(ExpandableObjectConverter))] public struct JointTranslationLimit_s : IMetaXmlItem
2017-09-21 18:33:05 +08:00
{
public uint Unknown_0h { get ; set ; } // 0x00000000
public uint Unknown_4h { get ; set ; } // 0x00000000
public uint BoneId { get ; set ; }
public uint Unknown_Ch { get ; set ; } // 0x00000000
public uint Unknown_10h { get ; set ; } // 0x00000000
public uint Unknown_14h { get ; set ; } // 0x00000000
public uint Unknown_18h { get ; set ; } // 0x00000000
public uint Unknown_1Ch { get ; set ; } // 0x00000000
2018-03-10 22:27:13 +08:00
public Vector3 Min { get ; set ; }
2017-09-21 18:33:05 +08:00
public uint Unknown_2Ch { get ; set ; } // 0x00000000
2018-03-10 22:27:13 +08:00
public Vector3 Max { get ; set ; }
2017-09-21 18:33:05 +08:00
public uint Unknown_3Ch { get ; set ; } // 0x00000000
2020-01-18 01:20:40 +08:00
public void WriteXml ( StringBuilder sb , int indent )
{
YdrXml . ValueTag ( sb , indent , "BoneId" , BoneId . ToString ( ) ) ;
YdrXml . SelfClosingTag ( sb , indent , "Min " + FloatUtil . GetVector3XmlString ( Min ) ) ;
YdrXml . SelfClosingTag ( sb , indent , "Max " + FloatUtil . GetVector3XmlString ( Max ) ) ;
}
public void ReadXml ( XmlNode node )
{
BoneId = ( ushort ) Xml . GetChildUIntAttribute ( node , "BoneId" , "value" ) ;
Min = Xml . GetChildVector3Attributes ( node , "Min" , "x" , "y" , "z" ) ;
Max = Xml . GetChildVector3Attributes ( node , "Max" , "x" , "y" , "z" ) ;
}
2017-09-21 18:33:05 +08:00
}
2020-01-18 01:20:40 +08:00
[TypeConverter(typeof(ExpandableObjectConverter))] public class DrawableModel : ResourceSystemBlock , IMetaXmlItem
2017-09-21 18:33:05 +08:00
{
public override long BlockLength
{
get { return 48 ; }
}
// structure data
public uint VFT { get ; set ; }
2020-01-18 23:36:28 +08:00
public uint Unknown_4h { get ; set ; } = 1 ; // 0x00000001
2017-09-21 18:33:05 +08:00
public ulong GeometriesPointer { get ; set ; }
public ushort GeometriesCount1 { get ; set ; }
2020-01-18 23:36:28 +08:00
public ushort GeometriesCount2 { get ; set ; } //always equal to GeometriesCount1
2017-09-21 18:33:05 +08:00
public uint Unknown_14h { get ; set ; } // 0x00000000
2018-01-04 07:17:43 +08:00
public ulong BoundsPointer { get ; set ; }
2017-09-21 18:33:05 +08:00
public ulong ShaderMappingPointer { get ; set ; }
2019-03-20 18:21:47 +08:00
public uint SkeletonBinding { get ; set ; } //4th byte is bone index, 2nd byte for skin meshes
public ushort RenderMaskFlags { get ; set ; } //First byte is called "Mask" in GIMS EVO
2020-01-18 23:36:28 +08:00
public ushort GeometriesCount3 { get ; set ; } //always equal to GeometriesCount1, is it ShaderMappingCount?
public byte BoneIndex
{
get { return ( byte ) ( ( SkeletonBinding > > 24 ) & 0xFF ) ; }
set { SkeletonBinding = ( SkeletonBinding & 0x00FFFFFF ) + ( ( value & 0xFF u ) < < 24 ) ; }
}
public byte SkeletonBindUnk2 //always 0
{
get { return ( byte ) ( ( SkeletonBinding > > 16 ) & 0xFF ) ; }
set { SkeletonBinding = ( SkeletonBinding & 0xFF00FFFF ) + ( ( value & 0xFF u ) < < 16 ) ; }
}
public byte HasSkin //only 0 or 1
{
get { return ( byte ) ( ( SkeletonBinding > > 8 ) & 0xFF ) ; }
set { SkeletonBinding = ( SkeletonBinding & 0xFFFF00FF ) + ( ( value & 0xFF u ) < < 8 ) ; }
}
public byte SkeletonBindUnk1 //only 0 or 43 (in rare cases, see below)
{
get { return ( byte ) ( ( SkeletonBinding > > 0 ) & 0xFF ) ; }
set { SkeletonBinding = ( SkeletonBinding & 0xFFFFFF00 ) + ( ( value & 0xFF u ) < < 0 ) ; }
}
2017-09-21 18:33:05 +08:00
// reference data
public ResourcePointerArray64 < DrawableGeometry > Geometries { get ; set ; }
2018-01-04 07:17:43 +08:00
public AABB_s [ ] BoundsData { get ; set ; }
2017-09-21 18:33:05 +08:00
public ushort [ ] ShaderMapping { get ; set ; }
2019-01-28 10:13:45 +08:00
private ResourceSystemStructBlock < AABB_s > BoundsDataBlock = null ; //for saving only
private ResourceSystemStructBlock < ushort > ShaderMappingBlock = null ;
2017-09-21 18:33:05 +08:00
public long MemoryUsage
{
get
{
long val = 0 ;
if ( ( Geometries ! = null ) & & ( Geometries . data_items ! = null ) )
{
foreach ( var geom in Geometries . data_items )
{
if ( geom = = null ) continue ;
if ( geom . VertexData ! = null )
{
val + = geom . VertexData . MemoryUsage ;
}
if ( geom . IndexBuffer ! = null )
{
val + = geom . IndexBuffer . IndicesCount * 4 ;
}
if ( geom . VertexBuffer ! = null )
{
if ( ( geom . VertexBuffer . Data1 ! = null ) & & ( geom . VertexBuffer . Data1 ! = geom . VertexData ) )
{
val + = geom . VertexBuffer . Data1 . MemoryUsage ;
}
if ( ( geom . VertexBuffer . Data2 ! = null ) & & ( geom . VertexBuffer . Data2 ! = geom . VertexData ) )
{
val + = geom . VertexBuffer . Data2 . MemoryUsage ;
}
}
}
}
2018-01-04 07:17:43 +08:00
if ( BoundsData ! = null )
2017-09-21 18:33:05 +08:00
{
2018-01-04 07:17:43 +08:00
val + = BoundsData . Length * 32 ;
2017-09-21 18:33:05 +08:00
}
return val ;
}
}
public override void Read ( ResourceDataReader reader , params object [ ] parameters )
{
// read structure data
this . VFT = reader . ReadUInt32 ( ) ;
this . Unknown_4h = reader . ReadUInt32 ( ) ;
this . GeometriesPointer = reader . ReadUInt64 ( ) ;
this . GeometriesCount1 = reader . ReadUInt16 ( ) ;
this . GeometriesCount2 = reader . ReadUInt16 ( ) ;
this . Unknown_14h = reader . ReadUInt32 ( ) ;
2018-01-04 07:17:43 +08:00
this . BoundsPointer = reader . ReadUInt64 ( ) ;
2017-09-21 18:33:05 +08:00
this . ShaderMappingPointer = reader . ReadUInt64 ( ) ;
2019-03-20 18:21:47 +08:00
this . SkeletonBinding = reader . ReadUInt32 ( ) ;
this . RenderMaskFlags = reader . ReadUInt16 ( ) ;
this . GeometriesCount3 = reader . ReadUInt16 ( ) ;
2017-09-21 18:33:05 +08:00
// read reference data
this . Geometries = reader . ReadBlockAt < ResourcePointerArray64 < DrawableGeometry > > (
this . GeometriesPointer , // offset
this . GeometriesCount1
) ;
2018-01-04 07:17:43 +08:00
this . BoundsData = reader . ReadStructsAt < AABB_s > ( this . BoundsPointer , ( uint ) ( this . GeometriesCount1 > 1 ? this . GeometriesCount1 + 1 : this . GeometriesCount1 ) ) ;
2017-09-21 18:33:05 +08:00
this . ShaderMapping = reader . ReadUshortsAt ( this . ShaderMappingPointer , this . GeometriesCount1 ) ;
2020-01-18 23:36:28 +08:00
if ( Geometries ? . data_items ! = null )
{
for ( int i = 0 ; i < Geometries . data_items . Length ; i + + )
{
var geom = Geometries . data_items [ i ] ;
if ( geom ! = null )
{
geom . ShaderID = ( ( ShaderMapping ! = null ) & & ( i < ShaderMapping . Length ) ) ? ShaderMapping [ i ] : ( ushort ) 0 ;
geom . AABB = ( BoundsData ! = null ) ? ( ( BoundsData . Length > 1 ) & & ( ( i + 1 ) < BoundsData . Length ) ) ? BoundsData [ i + 1 ] : BoundsData [ 0 ] : new AABB_s ( ) ;
}
}
}
////just testing!
//if (SkeletonBindUnk2 != 0)
//{ }//no hit
//switch (SkeletonBindUnk1)
//{
// case 0:
// break;
// case 43://des_plog_light_root.ydr, des_heli_scrapyard_skin002.ydr, v_74_it1_ceiling_smoke_02_skin.ydr, buzzard2.yft, vader.yft, zombiea.yft
// break;
// default:
// break;//no hit
//}
//switch (HasSkin)
//{
// case 0:
// case 1:
// break;
// default:
// break;//no hit
//}
2017-09-21 18:33:05 +08:00
}
public override void Write ( ResourceDataWriter writer , params object [ ] parameters )
{
// update structure data
this . GeometriesPointer = ( ulong ) ( this . Geometries ! = null ? this . Geometries . FilePosition : 0 ) ;
2019-01-28 10:13:45 +08:00
this . GeometriesCount1 = ( ushort ) ( this . Geometries ! = null ? this . Geometries . Count : 0 ) ;
this . GeometriesCount2 = this . GeometriesCount1 ; //is this correct?
2019-03-20 18:21:47 +08:00
this . GeometriesCount3 = this . GeometriesCount1 ; //is this correct?
2019-01-28 10:13:45 +08:00
this . BoundsPointer = ( ulong ) ( this . BoundsDataBlock ! = null ? this . BoundsDataBlock . FilePosition : 0 ) ;
this . ShaderMappingPointer = ( ulong ) ( this . ShaderMappingBlock ! = null ? this . ShaderMappingBlock . FilePosition : 0 ) ;
2017-09-21 18:33:05 +08:00
// write structure data
writer . Write ( this . VFT ) ;
writer . Write ( this . Unknown_4h ) ;
writer . Write ( this . GeometriesPointer ) ;
writer . Write ( this . GeometriesCount1 ) ;
writer . Write ( this . GeometriesCount2 ) ;
writer . Write ( this . Unknown_14h ) ;
2018-01-04 07:17:43 +08:00
writer . Write ( this . BoundsPointer ) ;
2017-09-21 18:33:05 +08:00
writer . Write ( this . ShaderMappingPointer ) ;
2019-03-20 18:21:47 +08:00
writer . Write ( this . SkeletonBinding ) ;
writer . Write ( this . RenderMaskFlags ) ;
writer . Write ( this . GeometriesCount3 ) ;
2017-09-21 18:33:05 +08:00
}
2020-01-18 01:20:40 +08:00
public void WriteXml ( StringBuilder sb , int indent )
{
2020-01-18 23:36:28 +08:00
YdrXml . ValueTag ( sb , indent , "BoneIndex" , BoneIndex . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "HasSkin" , HasSkin . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "Unknown1" , SkeletonBindUnk1 . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "RenderMask" , RenderMaskFlags . ToString ( ) ) ;
2020-01-18 01:20:40 +08:00
if ( Geometries ? . data_items ! = null )
{
YdrXml . WriteItemArray ( sb , Geometries . data_items , indent , "Geometries" ) ;
}
}
public void ReadXml ( XmlNode node )
{
2020-01-18 23:36:28 +08:00
BoneIndex = ( byte ) Xml . GetChildUIntAttribute ( node , "BoneIndex" , "value" ) ;
HasSkin = ( byte ) Xml . GetChildUIntAttribute ( node , "HasSkin" , "value" ) ;
SkeletonBindUnk1 = ( byte ) Xml . GetChildUIntAttribute ( node , "Unknown1" , "value" ) ;
RenderMaskFlags = ( ushort ) Xml . GetChildUIntAttribute ( node , "RenderMask" , "value" ) ;
2020-01-18 01:20:40 +08:00
2020-01-18 23:36:28 +08:00
var aabbs = new List < AABB_s > ( ) ;
var shids = new List < ushort > ( ) ;
2020-01-18 01:20:40 +08:00
var geoms = XmlMeta . ReadItemArray < DrawableGeometry > ( node , "Geometries" ) ;
if ( geoms ! = null )
{
Geometries = new ResourcePointerArray64 < DrawableGeometry > ( ) ;
Geometries . data_items = geoms ;
2020-01-18 23:36:28 +08:00
foreach ( var geom in geoms )
{
aabbs . Add ( geom . AABB ) ;
shids . Add ( geom . ShaderID ) ;
}
2020-01-18 01:20:40 +08:00
}
2020-01-18 23:36:28 +08:00
BoundsData = ( aabbs . Count > 0 ) ? aabbs . ToArray ( ) : null ;
ShaderMapping = ( shids . Count > 0 ) ? shids . ToArray ( ) : null ;
2020-01-18 01:20:40 +08:00
}
2017-09-21 18:33:05 +08:00
2020-01-18 23:36:28 +08:00
2017-09-21 18:33:05 +08:00
public override IResourceBlock [ ] GetReferences ( )
{
var list = new List < IResourceBlock > ( ) ;
if ( Geometries ! = null ) list . Add ( Geometries ) ;
2019-01-28 10:13:45 +08:00
if ( BoundsData ! = null )
{
BoundsDataBlock = new ResourceSystemStructBlock < AABB_s > ( BoundsData ) ;
list . Add ( BoundsDataBlock ) ;
}
if ( ShaderMapping ! = null )
{
ShaderMappingBlock = new ResourceSystemStructBlock < ushort > ( ShaderMapping ) ;
list . Add ( ShaderMappingBlock ) ;
}
2017-09-21 18:33:05 +08:00
return list . ToArray ( ) ;
}
public override string ToString ( )
{
return "(" + Geometries . Count + " geometr" + ( Geometries . Count ! = 1 ? "ies)" : "y)" ) ;
}
2020-01-18 01:20:40 +08:00
2017-09-21 18:33:05 +08:00
}
2020-01-18 01:20:40 +08:00
[TypeConverter(typeof(ExpandableObjectConverter))] public class DrawableGeometry : ResourceSystemBlock , IMetaXmlItem
2017-09-21 18:33:05 +08:00
{
public override long BlockLength
{
get { return 152 ; }
}
// structure data
public uint VFT { get ; set ; }
2020-01-18 23:36:28 +08:00
public uint Unknown_4h { get ; set ; } = 1 ; // 0x00000001
2017-09-21 18:33:05 +08:00
public uint Unknown_8h { get ; set ; } // 0x00000000
public uint Unknown_Ch { get ; set ; } // 0x00000000
public uint Unknown_10h { get ; set ; } // 0x00000000
public uint Unknown_14h { get ; set ; } // 0x00000000
public ulong VertexBufferPointer { get ; set ; }
public uint Unknown_20h { get ; set ; } // 0x00000000
public uint Unknown_24h { get ; set ; } // 0x00000000
public uint Unknown_28h { get ; set ; } // 0x00000000
public uint Unknown_2Ch { get ; set ; } // 0x00000000
public uint Unknown_30h { get ; set ; } // 0x00000000
public uint Unknown_34h { get ; set ; } // 0x00000000
public ulong IndexBufferPointer { get ; set ; }
public uint Unknown_40h { get ; set ; } // 0x00000000
public uint Unknown_44h { get ; set ; } // 0x00000000
public uint Unknown_48h { get ; set ; } // 0x00000000
public uint Unknown_4Ch { get ; set ; } // 0x00000000
public uint Unknown_50h { get ; set ; } // 0x00000000
public uint Unknown_54h { get ; set ; } // 0x00000000
public uint IndicesCount { get ; set ; }
2018-01-04 07:17:43 +08:00
public uint TrianglesCount { get ; set ; }
2017-09-21 18:33:05 +08:00
public ushort VerticesCount { get ; set ; }
2020-01-18 23:36:28 +08:00
public ushort Unknown_62h { get ; set ; } = 3 ; // 0x0003 // indices per primitive (triangle)
2017-09-21 18:33:05 +08:00
public uint Unknown_64h { get ; set ; } // 0x00000000
public ulong BoneIdsPointer { get ; set ; }
public ushort VertexStride { get ; set ; }
2019-01-28 10:13:45 +08:00
public ushort BoneIdsCount { get ; set ; }
2017-09-21 18:33:05 +08:00
public uint Unknown_74h { get ; set ; } // 0x00000000
public ulong VertexDataPointer { get ; set ; }
public uint Unknown_80h { get ; set ; } // 0x00000000
public uint Unknown_84h { get ; set ; } // 0x00000000
public uint Unknown_88h { get ; set ; } // 0x00000000
public uint Unknown_8Ch { get ; set ; } // 0x00000000
public uint Unknown_90h { get ; set ; } // 0x00000000
public uint Unknown_94h { get ; set ; } // 0x00000000
// reference data
public VertexBuffer VertexBuffer { get ; set ; }
public IndexBuffer IndexBuffer { get ; set ; }
public ushort [ ] BoneIds { get ; set ; }
public VertexData VertexData { get ; set ; }
2020-01-18 23:36:28 +08:00
public ShaderFX Shader { get ; set ; } //written by parent DrawableBase, using ShaderID
public ushort ShaderID { get ; set ; } //read/written by parent model
public AABB_s AABB { get ; set ; } //read/written by parent model
2017-09-21 18:33:05 +08:00
2019-01-28 10:13:45 +08:00
private ResourceSystemStructBlock < ushort > BoneIdsBlock = null ; //for saving only
2019-03-21 22:29:37 +08:00
public bool UpdateRenderableParameters { get ; set ; } = false ; //used by model material editor...
2017-09-21 18:33:05 +08:00
public override void Read ( ResourceDataReader reader , params object [ ] parameters )
{
// read structure data
this . VFT = reader . ReadUInt32 ( ) ;
this . Unknown_4h = reader . ReadUInt32 ( ) ;
this . Unknown_8h = reader . ReadUInt32 ( ) ;
this . Unknown_Ch = reader . ReadUInt32 ( ) ;
this . Unknown_10h = reader . ReadUInt32 ( ) ;
this . Unknown_14h = reader . ReadUInt32 ( ) ;
this . VertexBufferPointer = reader . ReadUInt64 ( ) ;
this . Unknown_20h = reader . ReadUInt32 ( ) ;
this . Unknown_24h = reader . ReadUInt32 ( ) ;
this . Unknown_28h = reader . ReadUInt32 ( ) ;
this . Unknown_2Ch = reader . ReadUInt32 ( ) ;
this . Unknown_30h = reader . ReadUInt32 ( ) ;
this . Unknown_34h = reader . ReadUInt32 ( ) ;
this . IndexBufferPointer = reader . ReadUInt64 ( ) ;
this . Unknown_40h = reader . ReadUInt32 ( ) ;
this . Unknown_44h = reader . ReadUInt32 ( ) ;
this . Unknown_48h = reader . ReadUInt32 ( ) ;
this . Unknown_4Ch = reader . ReadUInt32 ( ) ;
this . Unknown_50h = reader . ReadUInt32 ( ) ;
this . Unknown_54h = reader . ReadUInt32 ( ) ;
this . IndicesCount = reader . ReadUInt32 ( ) ;
2018-01-04 07:17:43 +08:00
this . TrianglesCount = reader . ReadUInt32 ( ) ;
2017-09-21 18:33:05 +08:00
this . VerticesCount = reader . ReadUInt16 ( ) ;
this . Unknown_62h = reader . ReadUInt16 ( ) ;
this . Unknown_64h = reader . ReadUInt32 ( ) ;
this . BoneIdsPointer = reader . ReadUInt64 ( ) ;
this . VertexStride = reader . ReadUInt16 ( ) ;
2019-01-28 10:13:45 +08:00
this . BoneIdsCount = reader . ReadUInt16 ( ) ;
2017-09-21 18:33:05 +08:00
this . Unknown_74h = reader . ReadUInt32 ( ) ;
this . VertexDataPointer = reader . ReadUInt64 ( ) ;
this . Unknown_80h = reader . ReadUInt32 ( ) ;
this . Unknown_84h = reader . ReadUInt32 ( ) ;
this . Unknown_88h = reader . ReadUInt32 ( ) ;
this . Unknown_8Ch = reader . ReadUInt32 ( ) ;
this . Unknown_90h = reader . ReadUInt32 ( ) ;
this . Unknown_94h = reader . ReadUInt32 ( ) ;
// read reference data
this . VertexBuffer = reader . ReadBlockAt < VertexBuffer > (
this . VertexBufferPointer // offset
) ;
this . IndexBuffer = reader . ReadBlockAt < IndexBuffer > (
this . IndexBufferPointer // offset
) ;
2019-01-28 10:13:45 +08:00
this . BoneIds = reader . ReadUshortsAt ( this . BoneIdsPointer , this . BoneIdsCount ) ;
2017-09-21 18:33:05 +08:00
if ( this . BoneIds ! = null ) //skinned mesh bones to use? peds, also yft props...
{
}
if ( this . VertexBuffer ! = null )
{
2020-01-18 23:36:28 +08:00
this . VertexData = this . VertexBuffer . Data1 ? ? this . VertexBuffer . Data2 ;
//if (VertexBuffer.Data1 != VertexBuffer.Data2)
//{ }//no hit
//if (VertexDataPointer == 0)
//{ }//no hit
//else if (VertexDataPointer != VertexBuffer.DataPointer1)
//{
// ////some mods hit here!
// //try
// //{
// // this.VertexData = reader.ReadBlockAt<VertexData>(
// // this.VertexDataPointer, // offset
// // this.VertexStride,
// // this.VerticesCount,
// // this.VertexBuffer.Info
// // );
// //}
// //catch
// //{ }
//}
//if (VertexStride != VertexBuffer.VertexStride)
//{ }//no hit
//if (VertexStride != (VertexBuffer.Info?.Stride ?? 0))
//{ }//no hit
}
//else
//{ }//no hit
2017-09-21 18:33:05 +08:00
}
public override void Write ( ResourceDataWriter writer , params object [ ] parameters )
{
// update structure data
this . VertexBufferPointer = ( ulong ) ( this . VertexBuffer ! = null ? this . VertexBuffer . FilePosition : 0 ) ;
this . IndexBufferPointer = ( ulong ) ( this . IndexBuffer ! = null ? this . IndexBuffer . FilePosition : 0 ) ;
2019-01-28 10:13:45 +08:00
this . BoneIdsPointer = ( ulong ) ( this . BoneIdsBlock ! = null ? this . BoneIdsBlock . FilePosition : 0 ) ;
this . BoneIdsCount = ( ushort ) ( this . BoneIdsBlock ! = null ? this . BoneIdsBlock . ItemCount : 0 ) ;
2017-09-21 18:33:05 +08:00
this . VertexDataPointer = ( ulong ) ( this . VertexData ! = null ? this . VertexData . FilePosition : 0 ) ;
2020-01-18 23:36:28 +08:00
this . VerticesCount = ( ushort ) ( this . VertexData ! = null ? this . VertexData . VertexCount : 0 ) ; //TODO: fix?
this . VertexStride = ( ushort ) ( this . VertexBuffer ! = null ? this . VertexBuffer . VertexStride : 0 ) ; //TODO: fix?
this . IndicesCount = ( this . IndexBuffer ! = null ? this . IndexBuffer . IndicesCount : 0 ) ; //TODO: fix?
this . TrianglesCount = this . IndicesCount / 3 ; //TODO: fix?
2017-09-21 18:33:05 +08:00
// write structure data
writer . Write ( this . VFT ) ;
writer . Write ( this . Unknown_4h ) ;
writer . Write ( this . Unknown_8h ) ;
writer . Write ( this . Unknown_Ch ) ;
writer . Write ( this . Unknown_10h ) ;
writer . Write ( this . Unknown_14h ) ;
writer . Write ( this . VertexBufferPointer ) ;
writer . Write ( this . Unknown_20h ) ;
writer . Write ( this . Unknown_24h ) ;
writer . Write ( this . Unknown_28h ) ;
writer . Write ( this . Unknown_2Ch ) ;
writer . Write ( this . Unknown_30h ) ;
writer . Write ( this . Unknown_34h ) ;
writer . Write ( this . IndexBufferPointer ) ;
writer . Write ( this . Unknown_40h ) ;
writer . Write ( this . Unknown_44h ) ;
writer . Write ( this . Unknown_48h ) ;
writer . Write ( this . Unknown_4Ch ) ;
writer . Write ( this . Unknown_50h ) ;
writer . Write ( this . Unknown_54h ) ;
writer . Write ( this . IndicesCount ) ;
2018-01-04 07:17:43 +08:00
writer . Write ( this . TrianglesCount ) ;
2017-09-21 18:33:05 +08:00
writer . Write ( this . VerticesCount ) ;
writer . Write ( this . Unknown_62h ) ;
writer . Write ( this . Unknown_64h ) ;
writer . Write ( this . BoneIdsPointer ) ;
writer . Write ( this . VertexStride ) ;
2019-01-28 10:13:45 +08:00
writer . Write ( this . BoneIdsCount ) ;
2017-09-21 18:33:05 +08:00
writer . Write ( this . Unknown_74h ) ;
writer . Write ( this . VertexDataPointer ) ;
writer . Write ( this . Unknown_80h ) ;
writer . Write ( this . Unknown_84h ) ;
writer . Write ( this . Unknown_88h ) ;
writer . Write ( this . Unknown_8Ch ) ;
writer . Write ( this . Unknown_90h ) ;
writer . Write ( this . Unknown_94h ) ;
}
2020-01-18 01:20:40 +08:00
public void WriteXml ( StringBuilder sb , int indent )
{
2020-01-18 23:36:28 +08:00
YdrXml . ValueTag ( sb , indent , "ShaderIndex" , ShaderID . ToString ( ) ) ;
YdrXml . SelfClosingTag ( sb , indent , "BoundingBoxMin " + FloatUtil . GetVector4XmlString ( AABB . Min ) ) ;
YdrXml . SelfClosingTag ( sb , indent , "BoundingBoxMax " + FloatUtil . GetVector4XmlString ( AABB . Max ) ) ;
if ( BoneIds ! = null )
{
var ids = new StringBuilder ( ) ;
foreach ( var id in BoneIds )
{
if ( ids . Length > 0 ) ids . Append ( ", " ) ;
ids . Append ( id . ToString ( ) ) ;
}
YdrXml . StringTag ( sb , indent , "BoneIDs" , ids . ToString ( ) ) ;
}
if ( VertexBuffer ! = null )
{
YdrXml . OpenTag ( sb , indent , "VertexBuffer" ) ;
YdrXml . CloseTag ( sb , indent , "VertexBuffer" ) ;
}
if ( IndexBuffer ! = null )
{
YdrXml . OpenTag ( sb , indent , "IndexBuffer" ) ;
YdrXml . CloseTag ( sb , indent , "IndexBuffer" ) ;
}
2020-01-18 01:20:40 +08:00
}
public void ReadXml ( XmlNode node )
{
2020-01-18 23:36:28 +08:00
ShaderID = ( ushort ) Xml . GetChildUIntAttribute ( node , "ShaderIndex" , "value" ) ;
var aabb = new AABB_s ( ) ;
aabb . Min = Xml . GetChildVector4Attributes ( node , "BoundingBoxMin" , "x" , "y" , "z" , "w" ) ;
aabb . Max = Xml . GetChildVector4Attributes ( node , "BoundingBoxMax" , "x" , "y" , "z" , "w" ) ;
AABB = aabb ;
var bnode = node . SelectSingleNode ( "BoneIDs" ) ;
if ( bnode ! = null )
{
var astr = bnode . InnerText ;
var arr = astr . Split ( ',' ) ;
var blist = new List < ushort > ( ) ;
foreach ( var bstr in arr )
{
var tstr = bstr ? . Trim ( ) ;
if ( string . IsNullOrEmpty ( tstr ) ) continue ;
if ( ushort . TryParse ( tstr , out ushort u ) )
{
blist . Add ( u ) ;
}
}
BoneIds = ( blist . Count > 0 ) ? blist . ToArray ( ) : null ;
}
var vnode = node . SelectSingleNode ( "VertexBuffer" ) ;
if ( vnode ! = null )
{
}
var inode = node . SelectSingleNode ( "IndexBuffer" ) ;
if ( inode ! = null )
{
}
2020-01-18 01:20:40 +08:00
}
2017-09-21 18:33:05 +08:00
public override IResourceBlock [ ] GetReferences ( )
{
var list = new List < IResourceBlock > ( ) ;
if ( VertexBuffer ! = null ) list . Add ( VertexBuffer ) ;
if ( IndexBuffer ! = null ) list . Add ( IndexBuffer ) ;
2019-01-28 10:13:45 +08:00
if ( BoneIds ! = null )
{
BoneIdsBlock = new ResourceSystemStructBlock < ushort > ( BoneIds ) ;
list . Add ( BoneIdsBlock ) ;
}
2017-09-21 18:33:05 +08:00
if ( VertexData ! = null ) list . Add ( VertexData ) ;
return list . ToArray ( ) ;
}
public override string ToString ( )
{
return VerticesCount . ToString ( ) + " verts, " + Shader . ToString ( ) ;
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class VertexBuffer : ResourceSystemBlock
{
public override long BlockLength
{
get { return 128 ; }
}
// structure data
public uint VFT { get ; set ; }
2020-01-18 23:36:28 +08:00
public uint Unknown_4h { get ; set ; } = 1 ; // 0x00000001
2017-09-21 18:33:05 +08:00
public ushort VertexStride { get ; set ; }
2020-01-18 23:36:28 +08:00
public ushort Unknown_Ah { get ; set ; } //only 0 or 1024
2017-09-21 18:33:05 +08:00
public uint Unknown_Ch { get ; set ; } // 0x00000000
public ulong DataPointer1 { get ; set ; }
public uint VertexCount { get ; set ; }
public uint Unknown_1Ch { get ; set ; } // 0x00000000
public ulong DataPointer2 { get ; set ; }
public uint Unknown_28h { get ; set ; } // 0x00000000
public uint Unknown_2Ch { get ; set ; } // 0x00000000
public ulong InfoPointer { get ; set ; }
public uint Unknown_38h { get ; set ; } // 0x00000000
public uint Unknown_3Ch { get ; set ; } // 0x00000000
public uint Unknown_40h { get ; set ; } // 0x00000000
public uint Unknown_44h { get ; set ; } // 0x00000000
public uint Unknown_48h { get ; set ; } // 0x00000000
public uint Unknown_4Ch { get ; set ; } // 0x00000000
public uint Unknown_50h { get ; set ; } // 0x00000000
public uint Unknown_54h { get ; set ; } // 0x00000000
public uint Unknown_58h { get ; set ; } // 0x00000000
public uint Unknown_5Ch { get ; set ; } // 0x00000000
public uint Unknown_60h { get ; set ; } // 0x00000000
public uint Unknown_64h { get ; set ; } // 0x00000000
public uint Unknown_68h { get ; set ; } // 0x00000000
public uint Unknown_6Ch { get ; set ; } // 0x00000000
public uint Unknown_70h { get ; set ; } // 0x00000000
public uint Unknown_74h { get ; set ; } // 0x00000000
public uint Unknown_78h { get ; set ; } // 0x00000000
public uint Unknown_7Ch { get ; set ; } // 0x00000000
// reference data
public VertexData Data1 { get ; set ; }
public VertexData Data2 { get ; set ; }
public VertexDeclaration Info { get ; set ; }
/// <summary>
/// Reads the data-block from a stream.
/// </summary>
public override void Read ( ResourceDataReader reader , params object [ ] parameters )
{
// read structure data
this . VFT = reader . ReadUInt32 ( ) ;
this . Unknown_4h = reader . ReadUInt32 ( ) ;
this . VertexStride = reader . ReadUInt16 ( ) ;
this . Unknown_Ah = reader . ReadUInt16 ( ) ;
this . Unknown_Ch = reader . ReadUInt32 ( ) ;
this . DataPointer1 = reader . ReadUInt64 ( ) ;
this . VertexCount = reader . ReadUInt32 ( ) ;
this . Unknown_1Ch = reader . ReadUInt32 ( ) ;
this . DataPointer2 = reader . ReadUInt64 ( ) ;
this . Unknown_28h = reader . ReadUInt32 ( ) ;
this . Unknown_2Ch = reader . ReadUInt32 ( ) ;
this . InfoPointer = reader . ReadUInt64 ( ) ;
this . Unknown_38h = reader . ReadUInt32 ( ) ;
this . Unknown_3Ch = reader . ReadUInt32 ( ) ;
this . Unknown_40h = reader . ReadUInt32 ( ) ;
this . Unknown_44h = reader . ReadUInt32 ( ) ;
this . Unknown_48h = reader . ReadUInt32 ( ) ;
this . Unknown_4Ch = reader . ReadUInt32 ( ) ;
this . Unknown_50h = reader . ReadUInt32 ( ) ;
this . Unknown_54h = reader . ReadUInt32 ( ) ;
this . Unknown_58h = reader . ReadUInt32 ( ) ;
this . Unknown_5Ch = reader . ReadUInt32 ( ) ;
this . Unknown_60h = reader . ReadUInt32 ( ) ;
this . Unknown_64h = reader . ReadUInt32 ( ) ;
this . Unknown_68h = reader . ReadUInt32 ( ) ;
this . Unknown_6Ch = reader . ReadUInt32 ( ) ;
this . Unknown_70h = reader . ReadUInt32 ( ) ;
this . Unknown_74h = reader . ReadUInt32 ( ) ;
this . Unknown_78h = reader . ReadUInt32 ( ) ;
this . Unknown_7Ch = reader . ReadUInt32 ( ) ;
// read reference data
this . Info = reader . ReadBlockAt < VertexDeclaration > (
this . InfoPointer // offset
) ;
this . Data1 = reader . ReadBlockAt < VertexData > (
this . DataPointer1 , // offset
this . VertexStride ,
this . VertexCount ,
this . Info
) ;
this . Data2 = reader . ReadBlockAt < VertexData > (
this . DataPointer2 , // offset
this . VertexStride ,
this . VertexCount ,
this . Info
) ;
2020-01-18 23:36:28 +08:00
switch ( Unknown_Ah )
{
case 0 :
break ;
case 1024 : //micro flag? //micro_brow_down.ydr, micro_chin_pointed.ydr
break ;
default :
break ;
}
2017-09-21 18:33:05 +08:00
}
/// <summary>
/// Writes the data-block to a stream.
/// </summary>
public override void Write ( ResourceDataWriter writer , params object [ ] parameters )
{
// update structure data
2020-01-15 17:03:16 +08:00
this . VertexCount = ( uint ) ( this . Data1 ! = null ? this . Data1 . VertexCount : this . Data2 ! = null ? this . Data2 . VertexCount : 0 ) ;
2017-09-21 18:33:05 +08:00
this . DataPointer1 = ( ulong ) ( this . Data1 ! = null ? this . Data1 . FilePosition : 0 ) ;
this . DataPointer2 = ( ulong ) ( this . Data2 ! = null ? this . Data2 . FilePosition : 0 ) ;
this . InfoPointer = ( ulong ) ( this . Info ! = null ? this . Info . FilePosition : 0 ) ;
// write structure data
writer . Write ( this . VFT ) ;
writer . Write ( this . Unknown_4h ) ;
writer . Write ( this . VertexStride ) ;
writer . Write ( this . Unknown_Ah ) ;
writer . Write ( this . Unknown_Ch ) ;
writer . Write ( this . DataPointer1 ) ;
writer . Write ( this . VertexCount ) ;
writer . Write ( this . Unknown_1Ch ) ;
writer . Write ( this . DataPointer2 ) ;
writer . Write ( this . Unknown_28h ) ;
writer . Write ( this . Unknown_2Ch ) ;
writer . Write ( this . InfoPointer ) ;
writer . Write ( this . Unknown_38h ) ;
writer . Write ( this . Unknown_3Ch ) ;
writer . Write ( this . Unknown_40h ) ;
writer . Write ( this . Unknown_44h ) ;
writer . Write ( this . Unknown_48h ) ;
writer . Write ( this . Unknown_4Ch ) ;
writer . Write ( this . Unknown_50h ) ;
writer . Write ( this . Unknown_54h ) ;
writer . Write ( this . Unknown_58h ) ;
writer . Write ( this . Unknown_5Ch ) ;
writer . Write ( this . Unknown_60h ) ;
writer . Write ( this . Unknown_64h ) ;
writer . Write ( this . Unknown_68h ) ;
writer . Write ( this . Unknown_6Ch ) ;
writer . Write ( this . Unknown_70h ) ;
writer . Write ( this . Unknown_74h ) ;
writer . Write ( this . Unknown_78h ) ;
writer . Write ( this . Unknown_7Ch ) ;
}
/// <summary>
/// Returns a list of data blocks which are referenced by this block.
/// </summary>
public override IResourceBlock [ ] GetReferences ( )
{
var list = new List < IResourceBlock > ( ) ;
if ( Data1 ! = null ) list . Add ( Data1 ) ;
if ( Data2 ! = null ) list . Add ( Data2 ) ;
if ( Info ! = null ) list . Add ( Info ) ;
return list . ToArray ( ) ;
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class VertexData : ResourceSystemBlock
{
2019-01-28 10:13:45 +08:00
//private int length = 0;
2017-09-21 18:33:05 +08:00
public override long BlockLength
{
get
{
2019-01-28 10:13:45 +08:00
return VertexBytes ? . Length ? ? 0 ; //this.length;
2017-09-21 18:33:05 +08:00
}
}
public VertexDeclaration info { get ; set ; }
public object [ ] Data { get ; set ; }
public uint [ ] Types { get ; set ; }
public VertexType VertexType { get ; set ; }
public byte [ ] VertexBytes { get ; set ; }
public int VertexCount { get ; set ; }
public int VertexStride { get ; set ; }
public long MemoryUsage
{
get
{
return ( long ) VertexCount * ( long ) VertexStride ;
}
}
public override void Read ( ResourceDataReader reader , params object [ ] parameters )
{
VertexStride = Convert . ToInt32 ( parameters [ 0 ] ) ;
VertexCount = Convert . ToInt32 ( parameters [ 1 ] ) ;
2019-01-28 10:13:45 +08:00
info = ( VertexDeclaration ) parameters [ 2 ] ;
2017-09-21 18:33:05 +08:00
VertexType = ( VertexType ) info . Flags ;
VertexBytes = reader . ReadBytes ( VertexCount * VertexStride ) ;
switch ( info . Types )
{
case 8598872888530528662 : //YDR - 0x7755555555996996
break ;
case 216172782140628998 : //YFT - 0x030000000199A006
switch ( info . Flags )
{
case 16473 : VertexType = VertexType . PCCH2H4 ; break ; // PCCH2H4
default : break ;
}
break ;
case 216172782140612614 : //YFT - 0x0300000001996006 PNCH2H4
switch ( info . Flags )
{
case 89 : VertexType = VertexType . PNCH2 ; break ; // PNCH2
default : break ;
}
break ;
default :
break ;
}
}
public /*override*/ void ReadOrig ( ResourceDataReader reader , params object [ ] parameters )
{
int stride = Convert . ToInt32 ( parameters [ 0 ] ) ;
int count = Convert . ToInt32 ( parameters [ 1 ] ) ;
var info = ( VertexDeclaration ) parameters [ 2 ] ;
2019-01-28 10:13:45 +08:00
this . VertexCount = count ;
2017-09-21 18:33:05 +08:00
this . info = info ;
bool [ ] IsUsed = new bool [ 16 ] ;
for ( int i = 0 ; i < 16 ; i + + )
IsUsed [ i ] = ( ( info . Flags > > i ) & 0x1 ) = = 1 ;
Types = new uint [ 16 ] ;
for ( int i = 0 ; i < 16 ; i + + )
Types [ i ] = ( uint ) ( ( info . Types > > ( int ) ( 4 * i ) ) & 0xF ) ;
Data = new object [ 16 ] ;
for ( int i = 0 ; i < 16 ; i + + )
{
if ( IsUsed [ i ] )
{
switch ( Types [ i ] )
{
case 0 : Data [ i ] = new ushort [ 1 * count ] ; break ;
case 1 : Data [ i ] = new ushort [ 2 * count ] ; break ;
case 2 : Data [ i ] = new ushort [ 3 * count ] ; break ;
case 3 : Data [ i ] = new ushort [ 4 * count ] ; break ;
case 4 : Data [ i ] = new float [ 1 * count ] ; break ;
case 5 : Data [ i ] = new float [ 2 * count ] ; break ;
case 6 : Data [ i ] = new float [ 3 * count ] ; break ;
case 7 : Data [ i ] = new float [ 4 * count ] ; break ;
case 8 : Data [ i ] = new uint [ count ] ; break ;
case 9 : Data [ i ] = new uint [ count ] ; break ;
case 10 : Data [ i ] = new uint [ count ] ; break ;
default :
throw new Exception ( ) ;
}
}
}
long pos = reader . Position ;
// read...
for ( int i = 0 ; i < count ; i + + )
{
for ( int k = 0 ; k < 16 ; k + + )
{
if ( IsUsed [ k ] )
{
switch ( Types [ k ] )
{
// float16
case 0 :
{
var buf = Data [ k ] as ushort [ ] ;
buf [ i * 1 + 0 ] = reader . ReadUInt16 ( ) ;
break ;
}
case 1 :
{
var buf = Data [ k ] as ushort [ ] ;
buf [ i * 2 + 0 ] = reader . ReadUInt16 ( ) ;
buf [ i * 2 + 1 ] = reader . ReadUInt16 ( ) ;
break ;
}
case 2 :
{
var buf = Data [ k ] as ushort [ ] ;
buf [ i * 3 + 0 ] = reader . ReadUInt16 ( ) ;
buf [ i * 3 + 1 ] = reader . ReadUInt16 ( ) ;
buf [ i * 3 + 2 ] = reader . ReadUInt16 ( ) ;
break ;
}
case 3 :
{
var buf = Data [ k ] as ushort [ ] ;
buf [ i * 4 + 0 ] = reader . ReadUInt16 ( ) ;
buf [ i * 4 + 1 ] = reader . ReadUInt16 ( ) ;
buf [ i * 4 + 2 ] = reader . ReadUInt16 ( ) ;
buf [ i * 4 + 3 ] = reader . ReadUInt16 ( ) ;
break ;
}
// float32
case 4 :
{
var buf = Data [ k ] as float [ ] ;
buf [ i * 1 + 0 ] = reader . ReadSingle ( ) ;
break ;
}
case 5 :
{
var buf = Data [ k ] as float [ ] ;
buf [ i * 2 + 0 ] = reader . ReadSingle ( ) ;
buf [ i * 2 + 1 ] = reader . ReadSingle ( ) ;
break ;
}
case 6 :
{
var buf = Data [ k ] as float [ ] ;
buf [ i * 3 + 0 ] = reader . ReadSingle ( ) ;
buf [ i * 3 + 1 ] = reader . ReadSingle ( ) ;
buf [ i * 3 + 2 ] = reader . ReadSingle ( ) ;
break ;
}
case 7 :
{
var buf = Data [ k ] as float [ ] ;
buf [ i * 4 + 0 ] = reader . ReadSingle ( ) ;
buf [ i * 4 + 1 ] = reader . ReadSingle ( ) ;
buf [ i * 4 + 2 ] = reader . ReadSingle ( ) ;
buf [ i * 4 + 3 ] = reader . ReadSingle ( ) ;
break ;
}
case 8 :
case 9 :
case 10 :
{
var buf = Data [ k ] as uint [ ] ;
buf [ i * 1 + 0 ] = reader . ReadUInt32 ( ) ;
break ;
}
default :
throw new Exception ( ) ;
}
}
}
}
2019-01-28 10:13:45 +08:00
//this.length = stride * count;
2017-09-21 18:33:05 +08:00
}
2019-01-28 10:13:45 +08:00
public /*override*/ void WriteOrig ( ResourceDataWriter writer , params object [ ] parameters )
2017-09-21 18:33:05 +08:00
{
// write...
2019-01-28 10:13:45 +08:00
for ( int i = 0 ; i < VertexCount ; i + + )
2017-09-21 18:33:05 +08:00
{
for ( int k = 0 ; k < 16 ; k + + )
{
if ( Data [ k ] ! = null )
{
switch ( Types [ k ] )
{
// float16
case 0 :
{
var buf = Data [ k ] as ushort [ ] ;
writer . Write ( buf [ i * 1 + 0 ] ) ;
break ;
}
case 1 :
{
var buf = Data [ k ] as ushort [ ] ;
writer . Write ( buf [ i * 2 + 0 ] ) ;
writer . Write ( buf [ i * 2 + 1 ] ) ;
break ;
}
case 2 :
{
var buf = Data [ k ] as ushort [ ] ;
writer . Write ( buf [ i * 3 + 0 ] ) ;
writer . Write ( buf [ i * 3 + 1 ] ) ;
writer . Write ( buf [ i * 3 + 2 ] ) ;
break ;
}
case 3 :
{
var buf = Data [ k ] as ushort [ ] ;
writer . Write ( buf [ i * 4 + 0 ] ) ;
writer . Write ( buf [ i * 4 + 1 ] ) ;
writer . Write ( buf [ i * 4 + 2 ] ) ;
writer . Write ( buf [ i * 4 + 3 ] ) ;
break ;
}
// float32
case 4 :
{
var buf = Data [ k ] as float [ ] ;
writer . Write ( buf [ i * 1 + 0 ] ) ;
break ;
}
case 5 :
{
var buf = Data [ k ] as float [ ] ;
writer . Write ( buf [ i * 2 + 0 ] ) ;
writer . Write ( buf [ i * 2 + 1 ] ) ;
break ;
}
case 6 :
{
var buf = Data [ k ] as float [ ] ;
writer . Write ( buf [ i * 3 + 0 ] ) ;
writer . Write ( buf [ i * 3 + 1 ] ) ;
writer . Write ( buf [ i * 3 + 2 ] ) ;
break ;
}
case 7 :
{
var buf = Data [ k ] as float [ ] ;
writer . Write ( buf [ i * 4 + 0 ] ) ;
writer . Write ( buf [ i * 4 + 1 ] ) ;
writer . Write ( buf [ i * 4 + 2 ] ) ;
writer . Write ( buf [ i * 4 + 3 ] ) ;
break ;
}
case 8 :
case 9 :
case 10 :
{
var buf = Data [ k ] as uint [ ] ;
writer . Write ( buf [ i * 1 + 0 ] ) ;
break ;
}
default :
throw new Exception ( ) ;
}
}
}
}
}
2019-01-28 10:13:45 +08:00
public override void Write ( ResourceDataWriter writer , params object [ ] parameters )
{
if ( VertexBytes ! = null )
{
writer . Write ( VertexBytes ) ; //not dealing with individual vertex data here any more!
}
}
2017-09-21 18:33:05 +08:00
public override string ToString ( )
{
2019-01-28 10:13:45 +08:00
return "Type: " + VertexType . ToString ( ) + ", Count: " + VertexCount . ToString ( ) ;
2017-09-21 18:33:05 +08:00
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class VertexDeclaration : ResourceSystemBlock
{
public override long BlockLength
{
get { return 16 ; }
}
// structure data
public uint Flags { get ; set ; }
public ushort Stride { get ; set ; }
public byte Unknown_6h { get ; set ; }
public byte Count { get ; set ; }
public ulong Types { get ; set ; }
/// <summary>
/// Reads the data-block from a stream.
/// </summary>
public override void Read ( ResourceDataReader reader , params object [ ] parameters )
{
// read structure data
this . Flags = reader . ReadUInt32 ( ) ;
this . Stride = reader . ReadUInt16 ( ) ;
this . Unknown_6h = reader . ReadByte ( ) ;
this . Count = reader . ReadByte ( ) ;
this . Types = reader . ReadUInt64 ( ) ;
}
/// <summary>
/// Writes the data-block to a stream.
/// </summary>
public override void Write ( ResourceDataWriter writer , params object [ ] parameters )
{
// write structure data
writer . Write ( this . Flags ) ;
writer . Write ( this . Stride ) ;
writer . Write ( this . Unknown_6h ) ;
writer . Write ( this . Count ) ;
writer . Write ( this . Types ) ;
}
public ulong GetDeclarationId ( )
{
ulong res = 0 ;
for ( int i = 0 ; i < 16 ; i + + )
{
if ( ( ( Flags > > i ) & 1 ) = = 1 )
{
res + = ( Types & ( 0xF u < < ( i * 4 ) ) ) ;
}
}
return res ;
}
public override string ToString ( )
{
return Stride . ToString ( ) + ": " + Count . ToString ( ) + ": " + Flags . ToString ( ) + ": " + Types . ToString ( ) ;
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class IndexBuffer : ResourceSystemBlock
{
public override long BlockLength
{
get { return 96 ; }
}
// structure data
public uint VFT { get ; set ; }
public uint Unknown_4h { get ; set ; } // 0x00000001
public uint IndicesCount { get ; set ; }
public uint Unknown_Ch { get ; set ; } // 0x00000000
public ulong IndicesPointer { get ; set ; }
public uint Unknown_18h { get ; set ; } // 0x00000000
public uint Unknown_1Ch { get ; set ; } // 0x00000000
public uint Unknown_20h { get ; set ; } // 0x00000000
public uint Unknown_24h { get ; set ; } // 0x00000000
public uint Unknown_28h { get ; set ; } // 0x00000000
public uint Unknown_2Ch { get ; set ; } // 0x00000000
public uint Unknown_30h { get ; set ; } // 0x00000000
public uint Unknown_34h { get ; set ; } // 0x00000000
public uint Unknown_38h { get ; set ; } // 0x00000000
public uint Unknown_3Ch { get ; set ; } // 0x00000000
public uint Unknown_40h { get ; set ; } // 0x00000000
public uint Unknown_44h { get ; set ; } // 0x00000000
public uint Unknown_48h { get ; set ; } // 0x00000000
public uint Unknown_4Ch { get ; set ; } // 0x00000000
public uint Unknown_50h { get ; set ; } // 0x00000000
public uint Unknown_54h { get ; set ; } // 0x00000000
public uint Unknown_58h { get ; set ; } // 0x00000000
public uint Unknown_5Ch { get ; set ; } // 0x00000000
// reference data
//public ResourceSimpleArray<ushort_r> Indices;
public ushort [ ] Indices { get ; set ; }
2019-01-28 10:13:45 +08:00
private ResourceSystemStructBlock < ushort > IndicesBlock = null ; //only used when saving
2017-09-21 18:33:05 +08:00
/// <summary>
/// Reads the data-block from a stream.
/// </summary>
public override void Read ( ResourceDataReader reader , params object [ ] parameters )
{
// read structure data
this . VFT = reader . ReadUInt32 ( ) ;
this . Unknown_4h = reader . ReadUInt32 ( ) ;
this . IndicesCount = reader . ReadUInt32 ( ) ;
this . Unknown_Ch = reader . ReadUInt32 ( ) ;
this . IndicesPointer = reader . ReadUInt64 ( ) ;
this . Unknown_18h = reader . ReadUInt32 ( ) ;
this . Unknown_1Ch = reader . ReadUInt32 ( ) ;
this . Unknown_20h = reader . ReadUInt32 ( ) ;
this . Unknown_24h = reader . ReadUInt32 ( ) ;
this . Unknown_28h = reader . ReadUInt32 ( ) ;
this . Unknown_2Ch = reader . ReadUInt32 ( ) ;
this . Unknown_30h = reader . ReadUInt32 ( ) ;
this . Unknown_34h = reader . ReadUInt32 ( ) ;
this . Unknown_38h = reader . ReadUInt32 ( ) ;
this . Unknown_3Ch = reader . ReadUInt32 ( ) ;
this . Unknown_40h = reader . ReadUInt32 ( ) ;
this . Unknown_44h = reader . ReadUInt32 ( ) ;
this . Unknown_48h = reader . ReadUInt32 ( ) ;
this . Unknown_4Ch = reader . ReadUInt32 ( ) ;
this . Unknown_50h = reader . ReadUInt32 ( ) ;
this . Unknown_54h = reader . ReadUInt32 ( ) ;
this . Unknown_58h = reader . ReadUInt32 ( ) ;
this . Unknown_5Ch = reader . ReadUInt32 ( ) ;
// read reference data
//this.Indices = reader.ReadBlockAt<ResourceSimpleArray<ushort_r>>(
// this.IndicesPointer, // offset
// this.IndicesCount
//);
this . Indices = reader . ReadUshortsAt ( this . IndicesPointer , this . IndicesCount ) ;
}
/// <summary>
/// Writes the data-block to a stream.
/// </summary>
public override void Write ( ResourceDataWriter writer , params object [ ] parameters )
{
// update structure data
2019-01-28 10:13:45 +08:00
this . IndicesCount = ( uint ) ( this . IndicesBlock ! = null ? this . IndicesBlock . ItemCount : 0 ) ;
this . IndicesPointer = ( ulong ) ( this . IndicesBlock ! = null ? this . IndicesBlock . FilePosition : 0 ) ;
2017-09-21 18:33:05 +08:00
// write structure data
writer . Write ( this . VFT ) ;
writer . Write ( this . Unknown_4h ) ;
writer . Write ( this . IndicesCount ) ;
writer . Write ( this . Unknown_Ch ) ;
writer . Write ( this . IndicesPointer ) ;
writer . Write ( this . Unknown_18h ) ;
writer . Write ( this . Unknown_1Ch ) ;
writer . Write ( this . Unknown_20h ) ;
writer . Write ( this . Unknown_24h ) ;
writer . Write ( this . Unknown_28h ) ;
writer . Write ( this . Unknown_2Ch ) ;
writer . Write ( this . Unknown_30h ) ;
writer . Write ( this . Unknown_34h ) ;
writer . Write ( this . Unknown_38h ) ;
writer . Write ( this . Unknown_3Ch ) ;
writer . Write ( this . Unknown_40h ) ;
writer . Write ( this . Unknown_44h ) ;
writer . Write ( this . Unknown_48h ) ;
writer . Write ( this . Unknown_4Ch ) ;
writer . Write ( this . Unknown_50h ) ;
writer . Write ( this . Unknown_54h ) ;
writer . Write ( this . Unknown_58h ) ;
writer . Write ( this . Unknown_5Ch ) ;
}
/// <summary>
/// Returns a list of data blocks which are referenced by this block.
/// </summary>
public override IResourceBlock [ ] GetReferences ( )
{
var list = new List < IResourceBlock > ( ) ;
2019-01-28 10:13:45 +08:00
if ( Indices ! = null )
{
IndicesBlock = new ResourceSystemStructBlock < ushort > ( Indices ) ;
list . Add ( IndicesBlock ) ;
}
2017-09-21 18:33:05 +08:00
return list . ToArray ( ) ;
}
}
2019-12-03 21:52:22 +08:00
public enum LightType : byte
{
Point = 1 ,
Spot = 2 ,
Capsule = 4 ,
}
2020-01-18 01:20:40 +08:00
[TypeConverter(typeof(ExpandableObjectConverter))] public struct LightAttributes_s : IMetaXmlItem
2017-09-21 18:33:05 +08:00
{
// structure data
public uint Unknown_0h { get ; set ; } // 0x00000000
public uint Unknown_4h { get ; set ; } // 0x00000000
2019-12-03 21:52:22 +08:00
public Vector3 Position { get ; set ; }
2017-09-21 18:33:05 +08:00
public uint Unknown_14h { get ; set ; } // 0x00000000
public byte ColorR { get ; set ; }
public byte ColorG { get ; set ; }
public byte ColorB { get ; set ; }
2018-02-25 04:12:14 +08:00
public byte Flashiness { get ; set ; }
2017-09-21 18:33:05 +08:00
public float Intensity { get ; set ; }
2018-01-04 07:55:10 +08:00
public uint Flags { get ; set ; }
2017-09-21 18:33:05 +08:00
public ushort BoneId { get ; set ; }
2019-12-03 21:52:22 +08:00
public LightType Type { get ; set ; }
2018-02-25 04:12:14 +08:00
public byte GroupId { get ; set ; }
2018-01-04 07:55:10 +08:00
public uint TimeFlags { get ; set ; }
2017-09-21 18:33:05 +08:00
public float Falloff { get ; set ; }
public float FalloffExponent { get ; set ; }
2019-12-03 21:52:22 +08:00
public Vector3 CullingPlaneNormal { get ; set ; }
2017-09-21 18:33:05 +08:00
public float CullingPlaneOffset { get ; set ; }
public byte ShadowBlur { get ; set ; }
public byte Unknown_45h { get ; set ; }
public ushort Unknown_46h { get ; set ; }
public uint Unknown_48h { get ; set ; } // 0x00000000
public float VolumeIntensity { get ; set ; }
public float VolumeSizeScale { get ; set ; }
public byte VolumeOuterColorR { get ; set ; }
public byte VolumeOuterColorG { get ; set ; }
public byte VolumeOuterColorB { get ; set ; }
public byte LightHash { get ; set ; }
public float VolumeOuterIntensity { get ; set ; }
public float CoronaSize { get ; set ; }
public float VolumeOuterExponent { get ; set ; }
public byte LightFadeDistance { get ; set ; }
public byte ShadowFadeDistance { get ; set ; }
public byte SpecularFadeDistance { get ; set ; }
public byte VolumetricFadeDistance { get ; set ; }
public float ShadowNearClip { get ; set ; }
public float CoronaIntensity { get ; set ; }
public float CoronaZBias { get ; set ; }
2019-12-03 21:52:22 +08:00
public Vector3 Direction { get ; set ; }
public Vector3 Tangent { get ; set ; }
2017-09-21 18:33:05 +08:00
public float ConeInnerAngle { get ; set ; }
public float ConeOuterAngle { get ; set ; }
2019-12-03 21:52:22 +08:00
public Vector3 Extent { get ; set ; }
2020-01-18 01:20:40 +08:00
public MetaHash ProjectedTextureHash { get ; set ; }
2017-09-21 18:33:05 +08:00
public uint Unknown_A4h { get ; set ; } // 0x00000000
2020-01-18 01:20:40 +08:00
public void WriteXml ( StringBuilder sb , int indent )
{
YdrXml . SelfClosingTag ( sb , indent , "Position " + FloatUtil . GetVector3XmlString ( Position ) ) ;
YdrXml . SelfClosingTag ( sb , indent , string . Format ( "Colour r=\"{0}\" g=\"{1}\" b=\"{2}\"" , ColorR , ColorG , ColorB ) ) ;
YdrXml . ValueTag ( sb , indent , "Flashiness" , Flashiness . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "Intensity" , FloatUtil . ToString ( Intensity ) ) ;
YdrXml . ValueTag ( sb , indent , "Flags" , Flags . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "BoneId" , BoneId . ToString ( ) ) ;
YdrXml . StringTag ( sb , indent , "Type" , Type . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "GroupId" , GroupId . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "TimeFlags" , TimeFlags . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "Falloff" , FloatUtil . ToString ( Falloff ) ) ;
YdrXml . ValueTag ( sb , indent , "FalloffExponent" , FloatUtil . ToString ( FalloffExponent ) ) ;
YdrXml . SelfClosingTag ( sb , indent , "CullingPlaneNormal " + FloatUtil . GetVector3XmlString ( CullingPlaneNormal ) ) ;
YdrXml . ValueTag ( sb , indent , "CullingPlaneOffset" , FloatUtil . ToString ( CullingPlaneOffset ) ) ;
YdrXml . ValueTag ( sb , indent , "Unknown45" , Unknown_45h . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "Unknown46" , Unknown_46h . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "VolumeIntensity" , FloatUtil . ToString ( VolumeIntensity ) ) ;
YdrXml . ValueTag ( sb , indent , "VolumeSizeScale" , FloatUtil . ToString ( VolumeSizeScale ) ) ;
YdrXml . SelfClosingTag ( sb , indent , string . Format ( "VolumeOuterColour r=\"{0}\" g=\"{1}\" b=\"{2}\"" , VolumeOuterColorR , VolumeOuterColorG , VolumeOuterColorB ) ) ;
YdrXml . ValueTag ( sb , indent , "LightHash" , LightHash . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "VolumeOuterIntensity" , FloatUtil . ToString ( VolumeOuterIntensity ) ) ;
YdrXml . ValueTag ( sb , indent , "CoronaSize" , FloatUtil . ToString ( CoronaSize ) ) ;
YdrXml . ValueTag ( sb , indent , "VolumeOuterExponent" , FloatUtil . ToString ( VolumeOuterExponent ) ) ;
YdrXml . ValueTag ( sb , indent , "LightFadeDistance" , LightFadeDistance . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "ShadowFadeDistance" , ShadowFadeDistance . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "SpecularFadeDistance" , SpecularFadeDistance . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "VolumetricFadeDistance" , VolumetricFadeDistance . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "ShadowNearClip" , FloatUtil . ToString ( ShadowNearClip ) ) ;
YdrXml . ValueTag ( sb , indent , "CoronaIntensity" , FloatUtil . ToString ( CoronaIntensity ) ) ;
YdrXml . ValueTag ( sb , indent , "CoronaZBias" , FloatUtil . ToString ( CoronaZBias ) ) ;
YdrXml . SelfClosingTag ( sb , indent , "Direction " + FloatUtil . GetVector3XmlString ( Direction ) ) ;
YdrXml . SelfClosingTag ( sb , indent , "Tangent " + FloatUtil . GetVector3XmlString ( Tangent ) ) ;
YdrXml . ValueTag ( sb , indent , "ConeInnerAngle" , FloatUtil . ToString ( ConeInnerAngle ) ) ;
YdrXml . ValueTag ( sb , indent , "ConeOuterAngle" , FloatUtil . ToString ( ConeOuterAngle ) ) ;
YdrXml . SelfClosingTag ( sb , indent , "Extent " + FloatUtil . GetVector3XmlString ( Extent ) ) ;
YdrXml . StringTag ( sb , indent , "ProjectedTextureHash" , YdrXml . HashString ( ProjectedTextureHash ) ) ;
}
public void ReadXml ( XmlNode node )
{
Position = Xml . GetChildVector3Attributes ( node , "Position" , "x" , "y" , "z" ) ;
ColorR = ( byte ) Xml . GetChildUIntAttribute ( node , "Colour" , "r" ) ;
ColorG = ( byte ) Xml . GetChildUIntAttribute ( node , "Colour" , "g" ) ;
ColorB = ( byte ) Xml . GetChildUIntAttribute ( node , "Colour" , "b" ) ;
Flashiness = ( byte ) Xml . GetChildUIntAttribute ( node , "Flashiness" , "value" ) ;
Intensity = Xml . GetChildFloatAttribute ( node , "Intensity" , "value" ) ;
Flags = Xml . GetChildUIntAttribute ( node , "Flags" , "value" ) ;
BoneId = ( ushort ) Xml . GetChildUIntAttribute ( node , "BoneId" , "value" ) ;
Type = Xml . GetChildEnumInnerText < LightType > ( node , "Type" ) ;
GroupId = ( byte ) Xml . GetChildUIntAttribute ( node , "GroupId" , "value" ) ;
TimeFlags = Xml . GetChildUIntAttribute ( node , "TimeFlags" , "value" ) ;
Falloff = Xml . GetChildFloatAttribute ( node , "Falloff" , "value" ) ;
FalloffExponent = Xml . GetChildFloatAttribute ( node , "FalloffExponent" , "value" ) ;
CullingPlaneNormal = Xml . GetChildVector3Attributes ( node , "CullingPlaneNormal" , "x" , "y" , "z" ) ;
CullingPlaneOffset = Xml . GetChildFloatAttribute ( node , "CullingPlaneOffset" , "value" ) ;
Unknown_45h = ( byte ) Xml . GetChildUIntAttribute ( node , "Unknown45" , "value" ) ;
Unknown_46h = ( ushort ) Xml . GetChildUIntAttribute ( node , "Unknown46" , "value" ) ;
VolumeIntensity = Xml . GetChildFloatAttribute ( node , "VolumeIntensity" , "value" ) ;
VolumeSizeScale = Xml . GetChildFloatAttribute ( node , "VolumeSizeScale" , "value" ) ;
VolumeOuterColorR = ( byte ) Xml . GetChildUIntAttribute ( node , "VolumeOuterColour" , "r" ) ;
VolumeOuterColorG = ( byte ) Xml . GetChildUIntAttribute ( node , "VolumeOuterColour" , "g" ) ;
VolumeOuterColorB = ( byte ) Xml . GetChildUIntAttribute ( node , "VolumeOuterColour" , "b" ) ;
LightHash = ( byte ) Xml . GetChildUIntAttribute ( node , "LightHash" , "value" ) ;
VolumeOuterIntensity = Xml . GetChildFloatAttribute ( node , "VolumeOuterIntensity" , "value" ) ;
CoronaSize = Xml . GetChildFloatAttribute ( node , "CoronaSize" , "value" ) ;
VolumeOuterExponent = Xml . GetChildFloatAttribute ( node , "VolumeOuterExponent" , "value" ) ;
LightFadeDistance = ( byte ) Xml . GetChildUIntAttribute ( node , "LightFadeDistance" , "value" ) ;
ShadowFadeDistance = ( byte ) Xml . GetChildUIntAttribute ( node , "ShadowFadeDistance" , "value" ) ;
SpecularFadeDistance = ( byte ) Xml . GetChildUIntAttribute ( node , "SpecularFadeDistance" , "value" ) ;
VolumetricFadeDistance = ( byte ) Xml . GetChildUIntAttribute ( node , "VolumetricFadeDistance" , "value" ) ;
ShadowNearClip = Xml . GetChildFloatAttribute ( node , "ShadowNearClip" , "value" ) ;
CoronaIntensity = Xml . GetChildFloatAttribute ( node , "CoronaIntensity" , "value" ) ;
CoronaZBias = Xml . GetChildFloatAttribute ( node , "CoronaZBias" , "value" ) ;
Direction = Xml . GetChildVector3Attributes ( node , "Direction" , "x" , "y" , "z" ) ;
Tangent = Xml . GetChildVector3Attributes ( node , "Tangent" , "x" , "y" , "z" ) ;
ConeInnerAngle = Xml . GetChildFloatAttribute ( node , "ConeInnerAngle" , "value" ) ;
ConeOuterAngle = Xml . GetChildFloatAttribute ( node , "ConeOuterAngle" , "value" ) ;
Extent = Xml . GetChildVector3Attributes ( node , "Extent" , "x" , "y" , "z" ) ;
ProjectedTextureHash = XmlMeta . GetHash ( Xml . GetChildInnerText ( node , "ProjectedTextureHash" ) ) ;
}
2017-09-21 18:33:05 +08:00
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class DrawableBase : ResourceFileBase
{
public override long BlockLength
{
get { return 168 ; }
}
// structure data
public ulong ShaderGroupPointer { get ; set ; }
public ulong SkeletonPointer { get ; set ; }
2018-03-10 22:27:13 +08:00
public Vector3 BoundingCenter { get ; set ; }
2017-09-21 18:33:05 +08:00
public float BoundingSphereRadius { get ; set ; }
2018-03-10 22:27:13 +08:00
public Vector4 BoundingBoxMin { get ; set ; }
public Vector4 BoundingBoxMax { get ; set ; }
2017-09-21 18:33:05 +08:00
public ulong DrawableModelsHighPointer { get ; set ; }
public ulong DrawableModelsMediumPointer { get ; set ; }
public ulong DrawableModelsLowPointer { get ; set ; }
public ulong DrawableModelsVeryLowPointer { get ; set ; }
2019-03-20 18:21:47 +08:00
public float LodDistHigh { get ; set ; }
public float LodDistMed { get ; set ; }
public float LodDistLow { get ; set ; }
public float LodDistVlow { get ; set ; }
2017-09-21 18:33:05 +08:00
public uint Unknown_80h { get ; set ; }
public uint Unknown_84h { get ; set ; }
public uint Unknown_88h { get ; set ; }
public uint Unknown_8Ch { get ; set ; }
public ulong JointsPointer { get ; set ; }
2019-03-20 18:21:47 +08:00
public ushort Unknown_98h { get ; set ; }
public ushort Unknown_9Ah { get ; set ; }
2017-09-21 18:33:05 +08:00
public uint Unknown_9Ch { get ; set ; } // 0x00000000
public ulong DrawableModelsXPointer { get ; set ; }
// reference data
public ShaderGroup ShaderGroup { get ; set ; }
public Skeleton Skeleton { get ; set ; }
public ResourcePointerList64 < DrawableModel > DrawableModelsHigh { get ; set ; }
public ResourcePointerList64 < DrawableModel > DrawableModelsMedium { get ; set ; }
public ResourcePointerList64 < DrawableModel > DrawableModelsLow { get ; set ; }
public ResourcePointerList64 < DrawableModel > DrawableModelsVeryLow { get ; set ; }
public Joints Joints { get ; set ; }
public ResourcePointerList64 < DrawableModel > DrawableModelsX { get ; set ; }
public DrawableModel [ ] AllModels { get ; set ; }
public Dictionary < ulong , VertexDeclaration > VertexDecls { get ; set ; }
public object Owner { get ; set ; }
public long MemoryUsage
{
get
{
long val = 0 ;
if ( AllModels ! = null )
{
foreach ( DrawableModel m in AllModels )
{
if ( m ! = null )
{
val + = m . MemoryUsage ;
}
}
}
if ( ( ShaderGroup ! = null ) & & ( ShaderGroup . TextureDictionary ! = null ) )
{
val + = ShaderGroup . TextureDictionary . MemoryUsage ;
}
return val ;
}
}
public override void Read ( ResourceDataReader reader , params object [ ] parameters )
{
base . Read ( reader , parameters ) ;
// read structure data
this . ShaderGroupPointer = reader . ReadUInt64 ( ) ;
this . SkeletonPointer = reader . ReadUInt64 ( ) ;
2018-03-10 22:27:13 +08:00
this . BoundingCenter = reader . ReadStruct < Vector3 > ( ) ;
2017-09-21 18:33:05 +08:00
this . BoundingSphereRadius = reader . ReadSingle ( ) ;
2018-03-10 22:27:13 +08:00
this . BoundingBoxMin = reader . ReadStruct < Vector4 > ( ) ;
this . BoundingBoxMax = reader . ReadStruct < Vector4 > ( ) ;
2017-09-21 18:33:05 +08:00
this . DrawableModelsHighPointer = reader . ReadUInt64 ( ) ;
this . DrawableModelsMediumPointer = reader . ReadUInt64 ( ) ;
this . DrawableModelsLowPointer = reader . ReadUInt64 ( ) ;
this . DrawableModelsVeryLowPointer = reader . ReadUInt64 ( ) ;
2019-03-20 18:21:47 +08:00
this . LodDistHigh = reader . ReadSingle ( ) ;
this . LodDistMed = reader . ReadSingle ( ) ;
this . LodDistLow = reader . ReadSingle ( ) ;
this . LodDistVlow = reader . ReadSingle ( ) ;
2017-09-21 18:33:05 +08:00
this . Unknown_80h = reader . ReadUInt32 ( ) ;
this . Unknown_84h = reader . ReadUInt32 ( ) ;
this . Unknown_88h = reader . ReadUInt32 ( ) ;
this . Unknown_8Ch = reader . ReadUInt32 ( ) ;
this . JointsPointer = reader . ReadUInt64 ( ) ;
2019-03-20 18:21:47 +08:00
this . Unknown_98h = reader . ReadUInt16 ( ) ;
this . Unknown_9Ah = reader . ReadUInt16 ( ) ;
2017-09-21 18:33:05 +08:00
this . Unknown_9Ch = reader . ReadUInt32 ( ) ;
this . DrawableModelsXPointer = reader . ReadUInt64 ( ) ;
// read reference data
this . ShaderGroup = reader . ReadBlockAt < ShaderGroup > (
this . ShaderGroupPointer // offset
) ;
this . Skeleton = reader . ReadBlockAt < Skeleton > (
this . SkeletonPointer // offset
) ;
this . DrawableModelsHigh = reader . ReadBlockAt < ResourcePointerList64 < DrawableModel > > (
this . DrawableModelsHighPointer // offset
) ;
this . DrawableModelsMedium = reader . ReadBlockAt < ResourcePointerList64 < DrawableModel > > (
this . DrawableModelsMediumPointer // offset
) ;
this . DrawableModelsLow = reader . ReadBlockAt < ResourcePointerList64 < DrawableModel > > (
this . DrawableModelsLowPointer // offset
) ;
this . DrawableModelsVeryLow = reader . ReadBlockAt < ResourcePointerList64 < DrawableModel > > (
this . DrawableModelsVeryLowPointer // offset
) ;
this . Joints = reader . ReadBlockAt < Joints > (
this . JointsPointer // offset
) ;
this . DrawableModelsX = reader . ReadBlockAt < ResourcePointerList64 < DrawableModel > > (
this . DrawableModelsXPointer // offset
) ;
var allModels = new List < DrawableModel > ( ) ;
if ( DrawableModelsHigh ! = null ) allModels . AddRange ( DrawableModelsHigh . data_items ) ;
if ( DrawableModelsMedium ! = null ) allModels . AddRange ( DrawableModelsMedium . data_items ) ;
if ( DrawableModelsLow ! = null ) allModels . AddRange ( DrawableModelsLow . data_items ) ;
if ( DrawableModelsVeryLow ! = null ) allModels . AddRange ( DrawableModelsVeryLow . data_items ) ;
if ( ( DrawableModelsX ! = null ) & & ( DrawableModelsX ! = DrawableModelsHigh ) )
{
allModels . AddRange ( DrawableModelsX . data_items ) ;
}
AllModels = allModels . ToArray ( ) ;
var vds = new Dictionary < ulong , VertexDeclaration > ( ) ;
foreach ( DrawableModel model in AllModels )
{
foreach ( var geom in model . Geometries . data_items )
{
var info = geom . VertexBuffer . Info ;
var declid = info . GetDeclarationId ( ) ;
if ( ! vds . ContainsKey ( declid ) )
{
vds . Add ( declid , info ) ;
}
//else //debug test
//{
// if ((VertexDecls[declid].Stride != info.Stride)||(VertexDecls[declid].Types != info.Types))
// {
// }
//}
}
}
VertexDecls = new Dictionary < ulong , VertexDeclaration > ( vds ) ;
AssignGeometryShaders ( ShaderGroup ) ;
}
public override void Write ( ResourceDataWriter writer , params object [ ] parameters )
{
base . Write ( writer , parameters ) ;
// update structure data
this . ShaderGroupPointer = ( ulong ) ( this . ShaderGroup ! = null ? this . ShaderGroup . FilePosition : 0 ) ;
this . SkeletonPointer = ( ulong ) ( this . Skeleton ! = null ? this . Skeleton . FilePosition : 0 ) ;
this . DrawableModelsHighPointer = ( ulong ) ( this . DrawableModelsHigh ! = null ? this . DrawableModelsHigh . FilePosition : 0 ) ;
this . DrawableModelsMediumPointer = ( ulong ) ( this . DrawableModelsMedium ! = null ? this . DrawableModelsMedium . FilePosition : 0 ) ;
this . DrawableModelsLowPointer = ( ulong ) ( this . DrawableModelsLow ! = null ? this . DrawableModelsLow . FilePosition : 0 ) ;
this . DrawableModelsVeryLowPointer = ( ulong ) ( this . DrawableModelsVeryLow ! = null ? this . DrawableModelsVeryLow . FilePosition : 0 ) ;
this . JointsPointer = ( ulong ) ( this . Joints ! = null ? this . Joints . FilePosition : 0 ) ;
this . DrawableModelsXPointer = ( ulong ) ( this . DrawableModelsX ! = null ? this . DrawableModelsX . FilePosition : 0 ) ;
// write structure data
writer . Write ( this . ShaderGroupPointer ) ;
writer . Write ( this . SkeletonPointer ) ;
2019-01-28 10:13:45 +08:00
writer . Write ( this . BoundingCenter ) ;
2017-09-21 18:33:05 +08:00
writer . Write ( this . BoundingSphereRadius ) ;
2019-01-28 10:13:45 +08:00
writer . Write ( this . BoundingBoxMin ) ;
writer . Write ( this . BoundingBoxMax ) ;
2017-09-21 18:33:05 +08:00
writer . Write ( this . DrawableModelsHighPointer ) ;
writer . Write ( this . DrawableModelsMediumPointer ) ;
writer . Write ( this . DrawableModelsLowPointer ) ;
writer . Write ( this . DrawableModelsVeryLowPointer ) ;
2019-03-20 18:21:47 +08:00
writer . Write ( this . LodDistHigh ) ;
writer . Write ( this . LodDistMed ) ;
writer . Write ( this . LodDistLow ) ;
writer . Write ( this . LodDistVlow ) ;
2017-09-21 18:33:05 +08:00
writer . Write ( this . Unknown_80h ) ;
writer . Write ( this . Unknown_84h ) ;
writer . Write ( this . Unknown_88h ) ;
writer . Write ( this . Unknown_8Ch ) ;
writer . Write ( this . JointsPointer ) ;
writer . Write ( this . Unknown_98h ) ;
2019-03-20 18:21:47 +08:00
writer . Write ( this . Unknown_9Ah ) ;
2017-09-21 18:33:05 +08:00
writer . Write ( this . Unknown_9Ch ) ;
writer . Write ( this . DrawableModelsXPointer ) ;
}
2020-01-18 01:20:40 +08:00
public virtual void WriteXml ( StringBuilder sb , int indent , string ddsfolder )
{
YdrXml . SelfClosingTag ( sb , indent , "BoundingSphereCenter " + FloatUtil . GetVector3XmlString ( BoundingCenter ) ) ;
YdrXml . ValueTag ( sb , indent , "BoundingSphereRadius" , FloatUtil . ToString ( BoundingSphereRadius ) ) ;
YdrXml . SelfClosingTag ( sb , indent , "BoundingBoxMin " + FloatUtil . GetVector4XmlString ( BoundingBoxMin ) ) ;
YdrXml . SelfClosingTag ( sb , indent , "BoundingBoxMax " + FloatUtil . GetVector4XmlString ( BoundingBoxMax ) ) ;
YdrXml . ValueTag ( sb , indent , "LodDistHigh" , FloatUtil . ToString ( LodDistHigh ) ) ;
YdrXml . ValueTag ( sb , indent , "LodDistMed" , FloatUtil . ToString ( LodDistMed ) ) ;
YdrXml . ValueTag ( sb , indent , "LodDistLow" , FloatUtil . ToString ( LodDistLow ) ) ;
YdrXml . ValueTag ( sb , indent , "LodDistVlow" , FloatUtil . ToString ( LodDistVlow ) ) ;
YdrXml . ValueTag ( sb , indent , "Unknown80" , Unknown_80h . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "Unknown84" , Unknown_84h . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "Unknown88" , Unknown_88h . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "Unknown8C" , Unknown_8Ch . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "Unknown98" , Unknown_98h . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "Unknown9A" , Unknown_9Ah . ToString ( ) ) ;
if ( ShaderGroup ! = null )
{
YdrXml . OpenTag ( sb , indent , "ShaderGroup" ) ;
ShaderGroup . WriteXml ( sb , indent + 1 , ddsfolder ) ;
YdrXml . CloseTag ( sb , indent , "ShaderGroup" ) ;
}
if ( Skeleton ! = null )
{
YdrXml . OpenTag ( sb , indent , "Skeleton" ) ;
Skeleton . WriteXml ( sb , indent + 1 ) ;
YdrXml . CloseTag ( sb , indent , "Skeleton" ) ;
}
if ( Joints ! = null )
{
YdrXml . OpenTag ( sb , indent , "Joints" ) ;
Joints . WriteXml ( sb , indent + 1 ) ;
YdrXml . CloseTag ( sb , indent , "Joints" ) ;
}
if ( DrawableModelsHigh ? . data_items ! = null )
{
YdrXml . WriteItemArray ( sb , DrawableModelsHigh . data_items , indent , "DrawableModelsHigh" ) ;
}
if ( DrawableModelsMedium ? . data_items ! = null )
{
YdrXml . WriteItemArray ( sb , DrawableModelsMedium . data_items , indent , "DrawableModelsMedium" ) ;
}
if ( DrawableModelsLow ? . data_items ! = null )
{
YdrXml . WriteItemArray ( sb , DrawableModelsLow . data_items , indent , "DrawableModelsLow" ) ;
}
if ( DrawableModelsVeryLow ? . data_items ! = null )
{
YdrXml . WriteItemArray ( sb , DrawableModelsVeryLow . data_items , indent , "DrawableModelsVeryLow" ) ;
}
if ( ( DrawableModelsX ? . data_items ! = null ) & & ( DrawableModelsX ! = DrawableModelsHigh ) ) //is this right? duplicates..?
{
YdrXml . WriteItemArray ( sb , DrawableModelsX . data_items , indent , "DrawableModelsX" ) ;
}
}
public virtual void ReadXml ( XmlNode node , string ddsfolder )
{
BoundingCenter = Xml . GetChildVector3Attributes ( node , "BoundingSphereCenter" , "x" , "y" , "z" ) ;
BoundingSphereRadius = Xml . GetChildFloatAttribute ( node , "BoundingSphereRadius" , "value" ) ;
BoundingBoxMin = Xml . GetChildVector4Attributes ( node , "BoundingBoxMin" , "x" , "y" , "z" , "w" ) ;
BoundingBoxMax = Xml . GetChildVector4Attributes ( node , "BoundingBoxMax" , "x" , "y" , "z" , "w" ) ;
LodDistHigh = Xml . GetChildFloatAttribute ( node , "LodDistHigh" , "value" ) ;
LodDistMed = Xml . GetChildFloatAttribute ( node , "LodDistMed" , "value" ) ;
LodDistLow = Xml . GetChildFloatAttribute ( node , "LodDistLow" , "value" ) ;
LodDistVlow = Xml . GetChildFloatAttribute ( node , "LodDistVlow" , "value" ) ;
Unknown_80h = Xml . GetChildUIntAttribute ( node , "Unknown80" , "value" ) ;
Unknown_84h = Xml . GetChildUIntAttribute ( node , "Unknown84" , "value" ) ;
Unknown_88h = Xml . GetChildUIntAttribute ( node , "Unknown88" , "value" ) ;
Unknown_8Ch = Xml . GetChildUIntAttribute ( node , "Unknown8C" , "value" ) ;
Unknown_98h = ( ushort ) Xml . GetChildUIntAttribute ( node , "Unknown98" , "value" ) ;
Unknown_9Ah = ( ushort ) Xml . GetChildUIntAttribute ( node , "Unknown9A" , "value" ) ;
var sgnode = node . SelectSingleNode ( "ShaderGroup" ) ;
if ( sgnode ! = null )
{
ShaderGroup = new ShaderGroup ( ) ;
ShaderGroup . ReadXml ( sgnode , ddsfolder ) ;
}
var sknode = node . SelectSingleNode ( "Skeleton" ) ;
if ( sknode ! = null )
{
Skeleton = new Skeleton ( ) ;
Skeleton . ReadXml ( sknode ) ;
}
var jnode = node . SelectSingleNode ( "Joints" ) ;
if ( jnode ! = null )
{
Joints = new Joints ( ) ;
Joints . ReadXml ( jnode ) ;
}
var dmhigh = XmlMeta . ReadItemArray < DrawableModel > ( node , "DrawableModelsHigh" ) ;
if ( dmhigh ! = null )
{
DrawableModelsHigh = new ResourcePointerList64 < DrawableModel > ( ) ;
DrawableModelsHigh . data_items = dmhigh ;
}
var dmmed = XmlMeta . ReadItemArray < DrawableModel > ( node , "DrawableModelsMedium" ) ;
if ( dmmed ! = null )
{
DrawableModelsMedium = new ResourcePointerList64 < DrawableModel > ( ) ;
DrawableModelsMedium . data_items = dmmed ;
}
var dmlow = XmlMeta . ReadItemArray < DrawableModel > ( node , "DrawableModelsLow" ) ;
if ( dmlow ! = null )
{
DrawableModelsLow = new ResourcePointerList64 < DrawableModel > ( ) ;
DrawableModelsLow . data_items = dmlow ;
}
var dmvlow = XmlMeta . ReadItemArray < DrawableModel > ( node , "DrawableModelsVeryLow" ) ;
if ( dmvlow ! = null )
{
DrawableModelsVeryLow = new ResourcePointerList64 < DrawableModel > ( ) ;
DrawableModelsVeryLow . data_items = dmvlow ;
}
var dmx = XmlMeta . ReadItemArray < DrawableModel > ( node , "DrawableModelsX" ) ;
if ( dmx ! = null )
{
DrawableModelsX = new ResourcePointerList64 < DrawableModel > ( ) ;
DrawableModelsX . data_items = dmx ;
}
}
2017-09-21 18:33:05 +08:00
public override IResourceBlock [ ] GetReferences ( )
{
var list = new List < IResourceBlock > ( base . GetReferences ( ) ) ;
if ( ShaderGroup ! = null ) list . Add ( ShaderGroup ) ;
if ( Skeleton ! = null ) list . Add ( Skeleton ) ;
if ( DrawableModelsHigh ! = null ) list . Add ( DrawableModelsHigh ) ;
if ( DrawableModelsMedium ! = null ) list . Add ( DrawableModelsMedium ) ;
if ( DrawableModelsLow ! = null ) list . Add ( DrawableModelsLow ) ;
if ( DrawableModelsVeryLow ! = null ) list . Add ( DrawableModelsVeryLow ) ;
if ( Joints ! = null ) list . Add ( Joints ) ;
if ( DrawableModelsX ! = null ) list . Add ( DrawableModelsX ) ;
return list . ToArray ( ) ;
}
2019-11-27 12:01:43 +08:00
2020-01-18 01:20:40 +08:00
public void AssignGeometryShaders ( ShaderGroup shaderGrp )
{
if ( shaderGrp ! = null )
{
ShaderGroup = shaderGrp ;
}
//map the shaders to the geometries
if ( ShaderGroup ! = null )
{
var shaders = ShaderGroup . Shaders . data_items ;
foreach ( DrawableModel model in AllModels )
{
2020-01-18 23:36:28 +08:00
if ( model ? . Geometries ? . data_items = = null ) continue ;
2020-01-18 01:20:40 +08:00
int geomcount = model . Geometries . data_items . Length ;
for ( int i = 0 ; i < geomcount ; i + + )
{
var geom = model . Geometries . data_items [ i ] ;
2020-01-18 23:36:28 +08:00
var sid = geom . ShaderID ;
2020-01-18 01:20:40 +08:00
geom . Shader = ( sid < shaders . Length ) ? shaders [ sid ] : null ;
}
}
}
else
{
}
}
2019-11-27 12:01:43 +08:00
public DrawableBase ShallowCopy ( )
{
DrawableBase r = null ;
if ( this is FragDrawable fd )
{
var f = new FragDrawable ( ) ;
f . Unknown_0A8h = fd . Unknown_0A8h ;
f . Unknown_0ACh = fd . Unknown_0ACh ;
f . FragMatrix = fd . FragMatrix ;
f . FragMatricesIndsCount = fd . FragMatricesIndsCount ;
f . FragMatricesCount = fd . FragMatricesCount ;
f . Count3 = fd . Count3 ;
f . Count4 = fd . Count4 ;
f . Bound = fd . Bound ;
f . FragMatricesInds = fd . FragMatricesInds ;
f . FragMatrices = fd . FragMatrices ;
f . Name = fd . Name ;
f . OwnerFragment = fd . OwnerFragment ;
f . OwnerFragmentPhys = fd . OwnerFragmentPhys ;
r = f ;
}
if ( this is Drawable dd )
{
var d = new Drawable ( ) ;
d . LightAttributes = dd . LightAttributes ;
d . Name = dd . Name ;
d . Bound = dd . Bound ;
r = d ;
}
if ( r ! = null )
{
r . BoundingCenter = BoundingCenter ;
r . BoundingSphereRadius = BoundingSphereRadius ;
r . BoundingBoxMin = BoundingBoxMin ;
r . BoundingBoxMax = BoundingBoxMax ;
r . LodDistHigh = LodDistHigh ;
r . LodDistMed = LodDistMed ;
r . LodDistLow = LodDistLow ;
r . LodDistVlow = LodDistVlow ;
r . Unknown_80h = Unknown_80h ;
r . Unknown_84h = Unknown_84h ;
r . Unknown_88h = Unknown_88h ;
r . Unknown_8Ch = Unknown_8Ch ;
r . Unknown_98h = Unknown_98h ;
r . Unknown_9Ah = Unknown_9Ah ;
r . ShaderGroup = ShaderGroup ;
r . Skeleton = Skeleton ? . Clone ( ) ;
r . DrawableModelsHigh = DrawableModelsHigh ;
r . DrawableModelsMedium = DrawableModelsMedium ;
r . DrawableModelsLow = DrawableModelsLow ;
r . DrawableModelsVeryLow = DrawableModelsVeryLow ;
r . DrawableModelsX = DrawableModelsX ;
r . Joints = Joints ;
r . AllModels = AllModels ;
r . VertexDecls = VertexDecls ;
r . Owner = Owner ;
}
return r ;
}
2017-09-21 18:33:05 +08:00
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class Drawable : DrawableBase
{
public override long BlockLength
{
get { return 208 ; }
}
// structure data
public ulong NamePointer { get ; set ; }
2019-01-27 14:14:10 +08:00
public ResourceSimpleList64_s < LightAttributes_s > LightAttributes { get ; set ; }
2017-09-21 18:33:05 +08:00
public uint Unknown_C0h { get ; set ; } // 0x00000000
public uint Unknown_C4h { get ; set ; } // 0x00000000
public ulong BoundPointer { get ; set ; }
// reference data
public string Name { get ; set ; }
public Bounds Bound { get ; set ; }
public string ErrorMessage { get ; set ; }
2019-01-28 10:13:45 +08:00
private string_r NameBlock = null ; //only used when saving..
2017-09-21 18:33:05 +08:00
public override void Read ( ResourceDataReader reader , params object [ ] parameters )
{
base . Read ( reader , parameters ) ;
// read structure data
this . NamePointer = reader . ReadUInt64 ( ) ;
2019-01-27 14:14:10 +08:00
this . LightAttributes = reader . ReadBlock < ResourceSimpleList64_s < LightAttributes_s > > ( ) ;
2017-09-21 18:33:05 +08:00
this . Unknown_C0h = reader . ReadUInt32 ( ) ;
this . Unknown_C4h = reader . ReadUInt32 ( ) ;
this . BoundPointer = reader . ReadUInt64 ( ) ;
try
{
// read reference data
this . Name = reader . ReadStringAt ( //BlockAt<string_r>(
this . NamePointer // offset
) ;
this . Bound = reader . ReadBlockAt < Bounds > (
this . BoundPointer // offset
) ;
2020-01-06 19:17:51 +08:00
if ( Bound ! = null )
{
Bound . Owner = this ;
}
2017-09-21 18:33:05 +08:00
}
catch ( Exception ex ) //sometimes error here for loading particles! different drawable type? base only?
{
ErrorMessage = ex . ToString ( ) ;
}
}
public override void Write ( ResourceDataWriter writer , params object [ ] parameters )
{
base . Write ( writer , parameters ) ;
// update structure data
2019-01-28 10:13:45 +08:00
this . NamePointer = ( ulong ) ( this . NameBlock ! = null ? this . NameBlock . FilePosition : 0 ) ;
2017-09-21 18:33:05 +08:00
this . BoundPointer = ( ulong ) ( this . Bound ! = null ? this . Bound . FilePosition : 0 ) ;
// write structure data
writer . Write ( this . NamePointer ) ;
2019-01-27 14:14:10 +08:00
writer . WriteBlock ( this . LightAttributes ) ;
2017-09-21 18:33:05 +08:00
writer . Write ( this . Unknown_C0h ) ;
writer . Write ( this . Unknown_C4h ) ;
writer . Write ( this . BoundPointer ) ;
}
2020-01-18 01:20:40 +08:00
public override void WriteXml ( StringBuilder sb , int indent , string ddsfolder )
{
2020-01-18 23:36:28 +08:00
YdrXml . StringTag ( sb , indent , "Name" , YdrXml . XmlEscape ( Name ) ) ;
2020-01-18 01:20:40 +08:00
base . WriteXml ( sb , indent , ddsfolder ) ;
Bounds . WriteXmlNode ( Bound , sb , indent ) ;
if ( LightAttributes ? . data_items ! = null )
{
YdrXml . WriteItemArray ( sb , LightAttributes . data_items , indent , "LightAttributes" ) ;
}
}
public override void ReadXml ( XmlNode node , string ddsfolder )
{
Name = Xml . GetChildInnerText ( node , "Name" ) ;
base . ReadXml ( node , ddsfolder ) ;
var bnode = node . SelectSingleNode ( "Bounds" ) ;
if ( bnode ! = null )
{
Bound = Bounds . ReadXmlNode ( bnode , this ) ;
}
var lights = XmlMeta . ReadItemArray < LightAttributes_s > ( node , "LightAttributes" ) ;
if ( lights ! = null )
{
LightAttributes = new ResourceSimpleList64_s < LightAttributes_s > ( ) ;
LightAttributes . data_items = lights ;
}
}
public static void WriteXmlNode ( Drawable d , StringBuilder sb , int indent , string ddsfolder , string name = "Drawable" )
{
if ( d = = null ) return ;
YdrXml . OpenTag ( sb , indent , name ) ;
d . WriteXml ( sb , indent + 1 , ddsfolder ) ;
YdrXml . CloseTag ( sb , indent , name ) ;
}
public static Drawable ReadXmlNode ( XmlNode node , string ddsfolder )
{
if ( node = = null ) return null ;
var d = new Drawable ( ) ;
d . ReadXml ( node , ddsfolder ) ;
return d ;
}
2017-09-21 18:33:05 +08:00
public override IResourceBlock [ ] GetReferences ( )
{
var list = new List < IResourceBlock > ( base . GetReferences ( ) ) ;
2019-01-28 10:13:45 +08:00
if ( Name ! = null )
{
NameBlock = ( string_r ) Name ;
list . Add ( NameBlock ) ;
}
2017-09-21 18:33:05 +08:00
if ( Bound ! = null ) list . Add ( Bound ) ;
return list . ToArray ( ) ;
}
2019-01-27 14:14:10 +08:00
public override Tuple < long , IResourceBlock > [ ] GetParts ( )
{
return new Tuple < long , IResourceBlock > [ ] {
new Tuple < long , IResourceBlock > ( 0xB0 , LightAttributes ) ,
} ;
}
2017-09-21 18:33:05 +08:00
public override string ToString ( )
{
return Name ;
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class DrawableBaseDictionary : ResourceFileBase
{
public override long BlockLength
{
get { return 64 ; }
}
// structure data
public uint Unknown_10h { get ; set ; }
public uint Unknown_14h { get ; set ; }
public uint Unknown_18h { get ; set ; }
public uint Unknown_1Ch { get ; set ; }
public ulong HashesPointer { get ; set ; }
public ushort HashesCount1 { get ; set ; }
public ushort HashesCount2 { get ; set ; }
public uint Unknown_2Ch { get ; set ; }
public ulong DrawablesPointer { get ; set ; }
public ushort DrawablesCount1 { get ; set ; }
public ushort DrawablesCount2 { get ; set ; }
public uint Unknown_3Ch { get ; set ; }
// reference data
//public ResourceSimpleArray<uint_r> Hashes { get; set; }
public uint [ ] Hashes { get ; set ; }
public ResourcePointerArray64 < DrawableBase > Drawables { get ; set ; }
2019-01-28 10:13:45 +08:00
private ResourceSystemStructBlock < uint > HashesBlock = null ; //only used for saving
2017-09-21 18:33:05 +08:00
/// <summary>
/// Reads the data-block from a stream.
/// </summary>
public override void Read ( ResourceDataReader reader , params object [ ] parameters )
{
base . Read ( reader , parameters ) ;
// read structure data
this . Unknown_10h = reader . ReadUInt32 ( ) ;
this . Unknown_14h = reader . ReadUInt32 ( ) ;
this . Unknown_18h = reader . ReadUInt32 ( ) ;
this . Unknown_1Ch = reader . ReadUInt32 ( ) ;
this . HashesPointer = reader . ReadUInt64 ( ) ;
this . HashesCount1 = reader . ReadUInt16 ( ) ;
this . HashesCount2 = reader . ReadUInt16 ( ) ;
this . Unknown_2Ch = reader . ReadUInt32 ( ) ;
this . DrawablesPointer = reader . ReadUInt64 ( ) ;
this . DrawablesCount1 = reader . ReadUInt16 ( ) ;
this . DrawablesCount2 = reader . ReadUInt16 ( ) ;
this . Unknown_3Ch = reader . ReadUInt32 ( ) ;
// read reference data
//this.Hashes = reader.ReadBlockAt<ResourceSimpleArray<uint_r>>(
// this.HashesPointer, // offset
// this.HashesCount1
//);
this . Hashes = reader . ReadUintsAt ( this . HashesPointer , this . HashesCount1 ) ;
this . Drawables = reader . ReadBlockAt < ResourcePointerArray64 < DrawableBase > > (
this . DrawablesPointer , // offset
this . DrawablesCount1
) ;
}
/// <summary>
/// Writes the data-block to a stream.
/// </summary>
public override void Write ( ResourceDataWriter writer , params object [ ] parameters )
{
base . Write ( writer , parameters ) ;
// update structure data
2019-01-28 10:13:45 +08:00
this . HashesPointer = ( ulong ) ( this . HashesBlock ! = null ? this . HashesBlock . FilePosition : 0 ) ;
this . HashesCount1 = ( ushort ) ( this . HashesBlock ! = null ? this . HashesBlock . ItemCount : 0 ) ;
this . HashesCount2 = ( ushort ) ( this . HashesBlock ! = null ? this . HashesBlock . ItemCount : 0 ) ;
2017-09-21 18:33:05 +08:00
this . DrawablesPointer = ( ulong ) ( this . Drawables ! = null ? this . Drawables . FilePosition : 0 ) ;
2019-01-28 10:13:45 +08:00
this . DrawablesCount1 = ( ushort ) ( this . Drawables ! = null ? this . Drawables . Count : 0 ) ;
this . DrawablesCount2 = ( ushort ) ( this . Drawables ! = null ? this . Drawables . Count : 0 ) ;
2017-09-21 18:33:05 +08:00
// write structure data
writer . Write ( this . Unknown_10h ) ;
writer . Write ( this . Unknown_14h ) ;
writer . Write ( this . Unknown_18h ) ;
writer . Write ( this . Unknown_1Ch ) ;
writer . Write ( this . HashesPointer ) ;
writer . Write ( this . HashesCount1 ) ;
writer . Write ( this . HashesCount2 ) ;
writer . Write ( this . Unknown_2Ch ) ;
writer . Write ( this . DrawablesPointer ) ;
writer . Write ( this . DrawablesCount1 ) ;
writer . Write ( this . DrawablesCount2 ) ;
writer . Write ( this . Unknown_3Ch ) ;
}
/// <summary>
/// Returns a list of data blocks which are referenced by this block.
/// </summary>
public override IResourceBlock [ ] GetReferences ( )
{
var list = new List < IResourceBlock > ( base . GetReferences ( ) ) ;
2019-01-28 10:13:45 +08:00
if ( Hashes ! = null )
{
HashesBlock = new ResourceSystemStructBlock < uint > ( Hashes ) ;
list . Add ( HashesBlock ) ;
}
2017-09-21 18:33:05 +08:00
if ( Drawables ! = null ) list . Add ( Drawables ) ;
return list . ToArray ( ) ;
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class DrawableDictionary : ResourceFileBase
{
public override long BlockLength
{
get { return 64 ; }
}
// structure data
public uint Unknown_10h { get ; set ; } // 0x00000000
public uint Unknown_14h { get ; set ; } // 0x00000000
public uint Unknown_18h { get ; set ; } // 0x00000001
public uint Unknown_1Ch { get ; set ; } // 0x00000000
public ulong HashesPointer { get ; set ; }
public ushort HashesCount1 { get ; set ; }
public ushort HashesCount2 { get ; set ; }
public uint Unknown_2Ch { get ; set ; } // 0x00000000
public ulong DrawablesPointer { get ; set ; }
public ushort DrawablesCount1 { get ; set ; }
public ushort DrawablesCount2 { get ; set ; }
public uint Unknown_3Ch { get ; set ; } // 0x00000000
// reference data
//public ResourceSimpleArray<uint_r> Hashes { get; set; }
public uint [ ] Hashes { get ; set ; }
public ResourcePointerArray64 < Drawable > Drawables { get ; set ; }
2019-01-28 10:13:45 +08:00
private ResourceSystemStructBlock < uint > HashesBlock = null ; //only used for saving
2017-09-21 18:33:05 +08:00
public long MemoryUsage
{
get
{
long val = 0 ;
if ( ( Drawables ! = null ) & & ( Drawables . data_items ! = null ) )
{
foreach ( var drawable in Drawables . data_items )
{
val + = drawable . MemoryUsage ;
}
}
return val ;
}
}
public override void Read ( ResourceDataReader reader , params object [ ] parameters )
{
base . Read ( reader , parameters ) ;
// read structure data
this . Unknown_10h = reader . ReadUInt32 ( ) ;
this . Unknown_14h = reader . ReadUInt32 ( ) ;
this . Unknown_18h = reader . ReadUInt32 ( ) ;
this . Unknown_1Ch = reader . ReadUInt32 ( ) ;
this . HashesPointer = reader . ReadUInt64 ( ) ;
this . HashesCount1 = reader . ReadUInt16 ( ) ;
this . HashesCount2 = reader . ReadUInt16 ( ) ;
this . Unknown_2Ch = reader . ReadUInt32 ( ) ;
this . DrawablesPointer = reader . ReadUInt64 ( ) ;
this . DrawablesCount1 = reader . ReadUInt16 ( ) ;
this . DrawablesCount2 = reader . ReadUInt16 ( ) ;
this . Unknown_3Ch = reader . ReadUInt32 ( ) ;
// read reference data
this . Hashes = reader . ReadUintsAt ( this . HashesPointer , this . HashesCount1 ) ;
this . Drawables = reader . ReadBlockAt < ResourcePointerArray64 < Drawable > > (
this . DrawablesPointer , // offset
this . DrawablesCount1
) ;
}
public override void Write ( ResourceDataWriter writer , params object [ ] parameters )
{
base . Write ( writer , parameters ) ;
// update structure data
2019-01-28 10:13:45 +08:00
this . HashesPointer = ( ulong ) ( this . HashesBlock ! = null ? this . HashesBlock . FilePosition : 0 ) ;
this . HashesCount1 = ( ushort ) ( this . HashesBlock ! = null ? this . HashesBlock . ItemCount : 0 ) ;
this . HashesCount2 = ( ushort ) ( this . HashesBlock ! = null ? this . HashesBlock . ItemCount : 0 ) ;
2017-09-21 18:33:05 +08:00
this . DrawablesPointer = ( ulong ) ( this . Drawables ! = null ? this . Drawables . FilePosition : 0 ) ;
2019-01-28 10:13:45 +08:00
this . DrawablesCount1 = ( ushort ) ( this . Drawables ! = null ? this . Drawables . Count : 0 ) ;
this . DrawablesCount2 = ( ushort ) ( this . Drawables ! = null ? this . Drawables . Count : 0 ) ;
2017-09-21 18:33:05 +08:00
// write structure data
writer . Write ( this . Unknown_10h ) ;
writer . Write ( this . Unknown_14h ) ;
writer . Write ( this . Unknown_18h ) ;
writer . Write ( this . Unknown_1Ch ) ;
writer . Write ( this . HashesPointer ) ;
writer . Write ( this . HashesCount1 ) ;
writer . Write ( this . HashesCount2 ) ;
writer . Write ( this . Unknown_2Ch ) ;
writer . Write ( this . DrawablesPointer ) ;
writer . Write ( this . DrawablesCount1 ) ;
writer . Write ( this . DrawablesCount2 ) ;
writer . Write ( this . Unknown_3Ch ) ;
}
2020-01-18 01:20:40 +08:00
public void WriteXml ( StringBuilder sb , int indent , string ddsfolder )
{
if ( Drawables ? . data_items ! = null )
{
foreach ( var d in Drawables . data_items )
{
YddXml . OpenTag ( sb , indent , "Item" ) ;
d . WriteXml ( sb , indent + 1 , ddsfolder ) ;
YddXml . CloseTag ( sb , indent , "Item" ) ;
}
}
}
public void ReadXml ( XmlNode node , string ddsfolder )
{
var drawables = new List < Drawable > ( ) ;
var drawablehashes = new List < uint > ( ) ;
var inodes = node . SelectNodes ( "Item" ) ;
if ( inodes ! = null )
{
foreach ( XmlNode inode in inodes )
{
var d = new Drawable ( ) ;
d . ReadXml ( inode , ddsfolder ) ;
drawables . Add ( d ) ;
drawablehashes . Add ( JenkHash . GenHash ( d . Name ) ) ; //TODO: check this!
}
}
Hashes = drawablehashes . ToArray ( ) ;
Drawables = new ResourcePointerArray64 < Drawable > ( ) ;
Drawables . data_items = drawables . ToArray ( ) ;
}
public static void WriteXmlNode ( DrawableDictionary d , StringBuilder sb , int indent , string ddsfolder , string name = "DrawableDictionary" )
{
if ( d = = null ) return ;
YddXml . OpenTag ( sb , indent , name ) ;
d . WriteXml ( sb , indent + 1 , ddsfolder ) ;
YddXml . CloseTag ( sb , indent , name ) ;
}
public static DrawableDictionary ReadXmlNode ( XmlNode node , string ddsfolder )
{
if ( node = = null ) return null ;
var d = new DrawableDictionary ( ) ;
d . ReadXml ( node , ddsfolder ) ;
return d ;
}
2017-09-21 18:33:05 +08:00
public override IResourceBlock [ ] GetReferences ( )
{
var list = new List < IResourceBlock > ( base . GetReferences ( ) ) ;
2019-01-28 10:13:45 +08:00
if ( Hashes ! = null )
{
HashesBlock = new ResourceSystemStructBlock < uint > ( Hashes ) ;
list . Add ( HashesBlock ) ;
}
2017-09-21 18:33:05 +08:00
if ( Drawables ! = null ) list . Add ( Drawables ) ;
return list . ToArray ( ) ;
}
}
}