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-21 00:12:36 +08:00
public uint Unknown_4h = 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 ; }
2020-01-21 00:12:36 +08:00
public uint Unknown_1Ch ; // 0x00000000
public ulong Unknown_20h ; // 0x0000000000000000
public ulong Unknown_28h ; // 0x0000000000000000
2020-01-18 23:36:28 +08:00
public uint Unknown_30h { get ; set ; } //wtf is this?? (shadercount-1)*3+8 ..?
2020-01-21 00:12:36 +08:00
public uint Unknown_34h ; // 0x00000000
public ulong Unknown_38h ; // 0x0000000000000000
2017-09-21 18:33:05 +08:00
// reference data
public TextureDictionary TextureDictionary { get ; set ; }
public ResourcePointerArray64 < ShaderFX > Shaders { get ; set ; }
2020-01-19 23:08:04 +08:00
public int TotalParameters
{
get
{
int c = 0 ;
if ( Shaders ? . data_items ! = null )
{
foreach ( var s in Shaders . data_items )
{
c + = s . ParameterCount ;
}
}
return c ;
}
}
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 . TextureDictionaryPointer = reader . ReadUInt64 ( ) ;
this . ShadersPointer = reader . ReadUInt64 ( ) ;
this . ShadersCount1 = reader . ReadUInt16 ( ) ;
this . ShadersCount2 = reader . ReadUInt16 ( ) ;
this . Unknown_1Ch = reader . ReadUInt32 ( ) ;
2020-01-21 00:12:36 +08:00
this . Unknown_20h = reader . ReadUInt64 ( ) ;
this . Unknown_28h = reader . ReadUInt64 ( ) ;
2017-09-21 18:33:05 +08:00
this . Unknown_30h = reader . ReadUInt32 ( ) ;
this . Unknown_34h = reader . ReadUInt32 ( ) ;
2020-01-21 00:12:36 +08:00
this . Unknown_38h = reader . ReadUInt64 ( ) ;
2017-09-21 18:33:05 +08:00
// 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
2020-01-21 00:12:36 +08:00
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)
//{ }
2020-01-21 00:12:36 +08:00
//if (Unknown_4h != 1)
//{ }
//if (Unknown_1Ch != 0)
//{ }
//if (Unknown_20h != 0)
//{ }
//if (Unknown_28h != 0)
//{ }
//if (Unknown_34h != 0)
//{ }
//if (Unknown_38h != 0)
//{ }
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_28h ) ;
writer . Write ( this . Unknown_30h ) ;
writer . Write ( this . Unknown_34h ) ;
writer . Write ( this . Unknown_38h ) ;
}
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
2020-01-21 00:12:36 +08:00
public uint Unknown_Ch ; // 0x00000000
2017-09-21 18:33:05 +08:00
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
2020-01-21 00:12:36 +08:00
public uint Unknown_1Ch ; // 0x00000000
2019-03-20 18:21:47 +08:00
public uint RenderBucketMask { get ; set ; } //65284, 65281 DrawBucketMask? (1<<bucket) | 0xFF00
2020-01-21 00:12:36 +08:00
public ushort Unknown_24h ; // 0x0000
public byte Unknown_26h ; // 0x00
2017-09-21 18:33:05 +08:00
public byte TextureParametersCount { get ; set ; }
2020-01-21 00:12:36 +08:00
public ulong Unknown_28h ; // 0x0000000000000000
2017-09-21 18:33:05 +08:00
// 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 ( ) ;
2020-01-21 00:12:36 +08:00
this . Unknown_28h = reader . ReadUInt64 ( ) ;
2017-09-21 18:33:05 +08:00
// 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
2020-01-21 00:12:36 +08:00
//if (Unknown_Ch != 0)
//{ }//no hit
//if (Unknown_1Ch != 0)
//{ }//no hit
//if (Unknown_28h != 0)
//{ }//no hit
2020-01-18 23:36:28 +08:00
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 ) ;
}
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-21 00:12:36 +08:00
public ushort Unknown_2h ; // 0x0000
public uint Unknown_4h ; // 0x00000000
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 ;
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 ] ;
2020-01-19 23:08:04 +08:00
var name = ( ShaderParamNames ) Hashes [ i ] ;
2020-01-18 23:36:28 +08:00
var typestr = "" ;
if ( param . DataType = = 0 ) typestr = "Texture" ;
else if ( param . DataType = = 1 ) typestr = "Vector" ;
else if ( param . DataType > 1 ) typestr = "Array" ;
2020-01-19 23:08:04 +08:00
var otstr = "Item name=\"" + name . ToString ( ) + "\" type=\"" + typestr + "\"" ;
2020-01-18 23:36:28 +08:00
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 ( ) ;
2020-01-19 23:08:04 +08:00
var h = ( MetaName ) ( uint ) XmlMeta . GetHash ( Xml . GetStringAttribute ( pnode , "name" ) ? . ToLowerInvariant ( ) ) ;
2020-01-18 23:36:28 +08:00
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" )
{
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 ( ) ;
2020-01-22 20:36:34 +08:00
p . DataType = ( byte ) vecs . Count ;
2020-01-18 23:36:28 +08:00
}
plist . Add ( p ) ;
hlist . Add ( h ) ;
}
Parameters = plist . ToArray ( ) ;
Hashes = hlist . ToArray ( ) ;
2020-01-19 23:08:04 +08:00
Count = plist . Count ;
2020-01-18 23:36:28 +08:00
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
2020-01-21 00:12:36 +08:00
public ulong Unknown_8h ; // 0x0000000000000000
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 ; }
2020-01-21 00:12:36 +08:00
public ulong Unknown_48h ; // 0x0000000000000000
2017-09-21 18:33:05 +08:00
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 ; }
2020-01-21 00:12:36 +08:00
public ushort Unknown_62h ; // 0x0000
public uint Unknown_64h ; // 0x00000000
public ulong Unknown_68h ; // 0x0000000000000000
2017-09-21 18:33:05 +08:00
// 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 ( ) ;
2020-01-21 00:12:36 +08:00
this . Unknown_8h = reader . ReadUInt64 ( ) ;
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 ( ) ;
2020-01-21 00:12:36 +08:00
this . Unknown_48h = reader . ReadUInt64 ( ) ;
2017-09-21 18:33:05 +08:00
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 ( ) ;
2020-01-21 00:12:36 +08:00
this . Unknown_68h = reader . ReadUInt64 ( ) ;
2017-09-21 18:33:05 +08:00
// 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
2020-01-21 00:12:36 +08:00
//if (Unknown_8h != 0)
//{ }
//if (Unknown_48h != 0)
//{ }
//if (Unknown_62h != 0)
//{ }
//if (Unknown_64h != 0)
//{ }
//if (Unknown_68h != 0)
//{ }
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 ) ;
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_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 ) ;
}
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 ; }
2020-01-21 00:12:36 +08:00
public uint Unknown_1Ch ; // 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 ; }
2020-01-21 00:12:36 +08:00
public uint Unknown_34h ; // 0x00000000
2017-09-21 18:33:05 +08:00
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
2020-01-21 00:12:36 +08:00
public ulong Unknown_48h ; // 0x0000000000000000
2017-09-21 18:33:05 +08:00
// 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 ( ) ;
2020-01-21 00:12:36 +08:00
this . Unknown_48h = reader . ReadUInt64 ( ) ;
2017-09-21 18:33:05 +08:00
// 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 ;
2020-01-21 00:12:36 +08:00
//if (Unknown_1Ch != 0)
//{ }
//if (Unknown_34h != 0)
//{ }
//if (Unknown_48h != 0)
//{ }
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 ) ;
}
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" ) ;
2020-01-21 23:45:27 +08:00
Translation = Xml . GetChildVector3Attributes ( node , "Translation" ) ;
Rotation = Xml . GetChildVector4Attributes ( node , "Rotation" ) . ToQuaternion ( ) ;
Scale = Xml . GetChildVector3Attributes ( node , "Scale" ) ;
TransformUnk = Xml . GetChildVector4Attributes ( node , "TransformUnk" ) ;
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-21 00:12:36 +08:00
public uint Unknown_4h = 1 ; // 0x00000001
public ulong Unknown_8h ; // 0x0000000000000000
2017-09-21 18:33:05 +08:00
public ulong RotationLimitsPointer { get ; set ; }
public ulong TranslationLimitsPointer { get ; set ; }
2020-01-21 00:12:36 +08:00
public ulong Unknown_20h ; // 0x0000000000000000
public ulong Unknown_28h ; // 0x0000000000000000
2017-09-21 18:33:05 +08:00
public ushort RotationLimitsCount { get ; set ; }
public ushort TranslationLimitsCount { get ; set ; }
2020-01-21 00:12:36 +08:00
public ushort Unknown_34h ; // 0x0000
public ushort Unknown_36h = 1 ; // 0x0001
public ulong Unknown_38h ; // 0x0000000000000000
2017-09-21 18:33:05 +08:00
// 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 ( ) ;
2020-01-21 00:12:36 +08:00
this . Unknown_8h = reader . ReadUInt64 ( ) ;
2017-09-21 18:33:05 +08:00
this . RotationLimitsPointer = reader . ReadUInt64 ( ) ;
this . TranslationLimitsPointer = reader . ReadUInt64 ( ) ;
2020-01-21 00:12:36 +08:00
this . Unknown_20h = reader . ReadUInt64 ( ) ;
this . Unknown_28h = reader . ReadUInt64 ( ) ;
2017-09-21 18:33:05 +08:00
this . RotationLimitsCount = reader . ReadUInt16 ( ) ;
this . TranslationLimitsCount = reader . ReadUInt16 ( ) ;
this . Unknown_34h = reader . ReadUInt16 ( ) ;
this . Unknown_36h = reader . ReadUInt16 ( ) ;
2020-01-21 00:12:36 +08:00
this . Unknown_38h = reader . ReadUInt64 ( ) ;
2017-09-21 18:33:05 +08:00
// read reference data
this . RotationLimits = reader . ReadStructsAt < JointRotationLimit_s > ( this . RotationLimitsPointer , this . RotationLimitsCount ) ;
this . TranslationLimits = reader . ReadStructsAt < JointTranslationLimit_s > ( this . TranslationLimitsPointer , this . TranslationLimitsCount ) ;
2020-01-21 00:12:36 +08:00
//if (Unknown_4h != 1)
//{ }
//if (Unknown_8h != 0)
//{ }
//if (Unknown_20h != 0)
//{ }
//if (Unknown_28h != 0)
//{ }
//if (Unknown_34h != 0)
//{ }
//if (Unknown_36h != 1)
//{ }
//if (Unknown_38h != 0)
//{ }
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 . 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 . RotationLimitsPointer ) ;
writer . Write ( this . TranslationLimitsPointer ) ;
writer . Write ( this . Unknown_20h ) ;
writer . Write ( this . Unknown_28h ) ;
writer . Write ( this . RotationLimitsCount ) ;
writer . Write ( this . TranslationLimitsCount ) ;
writer . Write ( this . Unknown_34h ) ;
writer . Write ( this . Unknown_36h ) ;
writer . Write ( this . Unknown_38h ) ;
}
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" ) ;
2020-01-21 23:45:27 +08:00
Min = Xml . GetChildVector3Attributes ( node , "Min" ) ;
Max = Xml . GetChildVector3Attributes ( node , "Max" ) ;
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 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" ) ;
2020-01-21 23:45:27 +08:00
Min = Xml . GetChildVector3Attributes ( node , "Min" ) ;
Max = Xml . GetChildVector3Attributes ( node , "Max" ) ;
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 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-21 00:12:36 +08:00
public uint Unknown_4h = 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
2020-01-21 00:12:36 +08:00
public uint Unknown_14h ; // 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 ) ; }
}
2020-01-19 23:08:04 +08:00
public byte RenderMask
{
get { return ( byte ) ( ( RenderMaskFlags > > 0 ) & 0xFF ) ; }
set { RenderMaskFlags = ( ushort ) ( ( RenderMaskFlags & 0xFF00 u ) + ( ( value & 0xFF u ) < < 0 ) ) ; }
}
public byte Flags
{
get { return ( byte ) ( ( RenderMaskFlags > > 8 ) & 0xFF ) ; }
set { RenderMaskFlags = ( ushort ) ( ( RenderMaskFlags & 0xFF u ) + ( ( value & 0xFF u ) < < 8 ) ) ; }
}
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
//}
2020-01-21 00:12:36 +08:00
//if (Unknown_4h != 1)
//{ }//no hit
//if (Unknown_14h != 0)
//{ }//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-19 23:08:04 +08:00
YdrXml . ValueTag ( sb , indent , "RenderMask" , RenderMask . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "Flags" , Flags . ToString ( ) ) ;
2020-01-18 23:36:28 +08:00
YdrXml . ValueTag ( sb , indent , "HasSkin" , HasSkin . ToString ( ) ) ;
2020-01-19 23:08:04 +08:00
YdrXml . ValueTag ( sb , indent , "BoneIndex" , BoneIndex . ToString ( ) ) ;
2020-01-18 23:36:28 +08:00
YdrXml . ValueTag ( sb , indent , "Unknown1" , SkeletonBindUnk1 . 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-19 23:08:04 +08:00
RenderMask = ( byte ) Xml . GetChildUIntAttribute ( node , "RenderMask" , "value" ) ;
Flags = ( byte ) Xml . GetChildUIntAttribute ( node , "Flags" , "value" ) ;
2020-01-18 23:36:28 +08:00
HasSkin = ( byte ) Xml . GetChildUIntAttribute ( node , "HasSkin" , "value" ) ;
2020-01-19 23:08:04 +08:00
BoneIndex = ( byte ) Xml . GetChildUIntAttribute ( node , "BoneIndex" , "value" ) ;
2020-01-18 23:36:28 +08:00
SkeletonBindUnk1 = ( byte ) Xml . GetChildUIntAttribute ( node , "Unknown1" , "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-19 23:08:04 +08:00
var min = new Vector4 ( float . MaxValue ) ;
var max = new Vector4 ( float . MinValue ) ;
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-19 23:08:04 +08:00
min = Vector4 . Min ( min , geom . AABB . Min ) ;
max = Vector4 . Max ( max , geom . AABB . Max ) ;
2020-01-18 23:36:28 +08:00
}
2020-01-19 23:08:04 +08:00
GeometriesCount1 = GeometriesCount2 = GeometriesCount3 = ( ushort ) geoms . Length ;
2020-01-18 01:20:40 +08:00
}
2020-01-19 23:08:04 +08:00
if ( aabbs . Count > 1 )
{
var outeraabb = new AABB_s ( ) { Min = min , Max = max } ;
aabbs . Insert ( 0 , outeraabb ) ;
}
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-21 00:12:36 +08:00
public uint Unknown_4h = 1 ; // 0x00000001
public ulong Unknown_8h ; // 0x0000000000000000
public ulong Unknown_10h ; // 0x0000000000000000
2017-09-21 18:33:05 +08:00
public ulong VertexBufferPointer { get ; set ; }
2020-01-21 00:12:36 +08:00
public ulong Unknown_20h ; // 0x0000000000000000
public ulong Unknown_28h ; // 0x0000000000000000
public ulong Unknown_30h ; // 0x0000000000000000
2017-09-21 18:33:05 +08:00
public ulong IndexBufferPointer { get ; set ; }
2020-01-21 00:12:36 +08:00
public ulong Unknown_40h ; // 0x0000000000000000
public ulong Unknown_48h ; // 0x0000000000000000
public ulong Unknown_50h ; // 0x0000000000000000
2017-09-21 18:33:05 +08:00
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-21 00:12:36 +08:00
public ushort Unknown_62h = 3 ; // 0x0003 // indices per primitive (triangle)
public uint Unknown_64h ; // 0x00000000
2017-09-21 18:33:05 +08:00
public ulong BoneIdsPointer { get ; set ; }
public ushort VertexStride { get ; set ; }
2019-01-28 10:13:45 +08:00
public ushort BoneIdsCount { get ; set ; }
2020-01-21 00:12:36 +08:00
public uint Unknown_74h ; // 0x00000000
2017-09-21 18:33:05 +08:00
public ulong VertexDataPointer { get ; set ; }
2020-01-21 00:12:36 +08:00
public ulong Unknown_80h ; // 0x0000000000000000
public ulong Unknown_88h ; // 0x0000000000000000
public ulong Unknown_90h ; // 0x0000000000000000
2017-09-21 18:33:05 +08:00
// 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 ( ) ;
2020-01-21 00:12:36 +08:00
this . Unknown_8h = reader . ReadUInt64 ( ) ;
this . Unknown_10h = reader . ReadUInt64 ( ) ;
2017-09-21 18:33:05 +08:00
this . VertexBufferPointer = reader . ReadUInt64 ( ) ;
2020-01-21 00:12:36 +08:00
this . Unknown_20h = reader . ReadUInt64 ( ) ;
this . Unknown_28h = reader . ReadUInt64 ( ) ;
this . Unknown_30h = reader . ReadUInt64 ( ) ;
2017-09-21 18:33:05 +08:00
this . IndexBufferPointer = reader . ReadUInt64 ( ) ;
2020-01-21 00:12:36 +08:00
this . Unknown_40h = reader . ReadUInt64 ( ) ;
this . Unknown_48h = reader . ReadUInt64 ( ) ;
this . Unknown_50h = reader . ReadUInt64 ( ) ;
2017-09-21 18:33:05 +08:00
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 ( ) ;
2020-01-21 00:12:36 +08:00
this . Unknown_80h = reader . ReadUInt64 ( ) ;
this . Unknown_88h = reader . ReadUInt64 ( ) ;
this . Unknown_90h = reader . ReadUInt64 ( ) ;
2017-09-21 18:33:05 +08:00
// 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
2020-01-21 00:12:36 +08:00
//if (Unknown_4h != 1)
//{ }
//if (Unknown_8h != 0)
//{ }
//if (Unknown_10h != 0)
//{ }
//if (Unknown_20h != 0)
//{ }
//if (Unknown_28h != 0)
//{ }
//if (Unknown_30h != 0)
//{ }
//if (Unknown_40h != 0)
//{ }
//if (Unknown_48h != 0)
//{ }
//if (Unknown_50h != 0)
//{ }
//if (Unknown_64h != 0)
//{ }
//if (Unknown_74h != 0)
//{ }
//if (Unknown_80h != 0)
//{ }
//if (Unknown_88h != 0)
//{ }
//if (Unknown_90h != 0)
//{ }
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_10h ) ;
writer . Write ( this . VertexBufferPointer ) ;
writer . Write ( this . Unknown_20h ) ;
writer . Write ( this . Unknown_28h ) ;
writer . Write ( this . Unknown_30h ) ;
writer . Write ( this . IndexBufferPointer ) ;
writer . Write ( this . Unknown_40h ) ;
writer . Write ( this . Unknown_48h ) ;
writer . Write ( this . Unknown_50h ) ;
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_88h ) ;
writer . Write ( this . Unknown_90h ) ;
}
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" ) ;
2020-01-19 23:08:04 +08:00
VertexBuffer . WriteXml ( sb , indent + 1 ) ;
2020-01-18 23:36:28 +08:00
YdrXml . CloseTag ( sb , indent , "VertexBuffer" ) ;
}
if ( IndexBuffer ! = null )
{
YdrXml . OpenTag ( sb , indent , "IndexBuffer" ) ;
2020-01-19 23:08:04 +08:00
IndexBuffer . WriteXml ( sb , indent + 1 ) ;
2020-01-18 23:36:28 +08:00
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 ( ) ;
2020-01-21 23:45:27 +08:00
aabb . Min = Xml . GetChildVector4Attributes ( node , "BoundingBoxMin" ) ;
aabb . Max = Xml . GetChildVector4Attributes ( node , "BoundingBoxMax" ) ;
2020-01-18 23:36:28 +08:00
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 )
{
2020-01-19 23:08:04 +08:00
VertexBuffer = new VertexBuffer ( ) ;
VertexBuffer . ReadXml ( vnode ) ;
VertexData = VertexBuffer . Data1 ? ? VertexBuffer . Data2 ;
2020-01-18 23:36:28 +08:00
}
var inode = node . SelectSingleNode ( "IndexBuffer" ) ;
if ( inode ! = null )
{
2020-01-19 23:08:04 +08:00
IndexBuffer = new IndexBuffer ( ) ;
IndexBuffer . ReadXml ( inode ) ;
2020-01-18 23:36:28 +08:00
}
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-21 00:12:36 +08:00
public uint Unknown_4h = 1 ; // 0x00000001
2017-09-21 18:33:05 +08:00
public ushort VertexStride { get ; set ; }
2020-01-19 23:08:04 +08:00
public ushort Flags { get ; set ; } //only 0 or 1024
2020-01-21 00:12:36 +08:00
public uint Unknown_Ch ; // 0x00000000
2017-09-21 18:33:05 +08:00
public ulong DataPointer1 { get ; set ; }
public uint VertexCount { get ; set ; }
2020-01-21 00:12:36 +08:00
public uint Unknown_1Ch ; // 0x00000000
2017-09-21 18:33:05 +08:00
public ulong DataPointer2 { get ; set ; }
2020-01-21 00:12:36 +08:00
public ulong Unknown_28h ; // 0x0000000000000000
2017-09-21 18:33:05 +08:00
public ulong InfoPointer { get ; set ; }
2020-01-21 00:12:36 +08:00
public ulong Unknown_38h ; // 0x0000000000000000
public ulong Unknown_40h ; // 0x0000000000000000
public ulong Unknown_48h ; // 0x0000000000000000
public ulong Unknown_50h ; // 0x0000000000000000
public ulong Unknown_58h ; // 0x0000000000000000
public ulong Unknown_60h ; // 0x0000000000000000
public ulong Unknown_68h ; // 0x0000000000000000
public ulong Unknown_70h ; // 0x0000000000000000
public ulong Unknown_78h ; // 0x0000000000000000
2017-09-21 18:33:05 +08:00
// reference data
public VertexData Data1 { get ; set ; }
public VertexData Data2 { get ; set ; }
public VertexDeclaration Info { get ; set ; }
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 ( ) ;
2020-01-19 23:08:04 +08:00
this . Flags = reader . ReadUInt16 ( ) ;
2017-09-21 18:33:05 +08:00
this . Unknown_Ch = reader . ReadUInt32 ( ) ;
this . DataPointer1 = reader . ReadUInt64 ( ) ;
this . VertexCount = reader . ReadUInt32 ( ) ;
this . Unknown_1Ch = reader . ReadUInt32 ( ) ;
this . DataPointer2 = reader . ReadUInt64 ( ) ;
2020-01-21 00:12:36 +08:00
this . Unknown_28h = reader . ReadUInt64 ( ) ;
2017-09-21 18:33:05 +08:00
this . InfoPointer = reader . ReadUInt64 ( ) ;
2020-01-21 00:12:36 +08:00
this . Unknown_38h = reader . ReadUInt64 ( ) ;
this . Unknown_40h = reader . ReadUInt64 ( ) ;
this . Unknown_48h = reader . ReadUInt64 ( ) ;
this . Unknown_50h = reader . ReadUInt64 ( ) ;
this . Unknown_58h = reader . ReadUInt64 ( ) ;
this . Unknown_60h = reader . ReadUInt64 ( ) ;
this . Unknown_68h = reader . ReadUInt64 ( ) ;
this . Unknown_70h = reader . ReadUInt64 ( ) ;
this . Unknown_78h = reader . ReadUInt64 ( ) ;
2017-09-21 18:33:05 +08:00
// 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
2020-01-19 23:08:04 +08:00
//switch (Flags)
//{
// case 0:
// break;
// case 1024://micro flag? //micro_brow_down.ydr, micro_chin_pointed.ydr
// break;
// default:
// break;
//}
2020-01-18 23:36:28 +08:00
2020-01-21 00:12:36 +08:00
//if (Unknown_4h != 1)
//{ }
//if (Unknown_Ch != 0)
//{ }
//if (Unknown_1Ch != 0)
//{ }
//if (Unknown_28h != 0)
//{ }
//if (Unknown_38h != 0)
//{ }
//if (Unknown_40h != 0)
//{ }
//if (Unknown_48h != 0)
//{ }
//if (Unknown_50h != 0)
//{ }
//if (Unknown_58h != 0)
//{ }
//if (Unknown_60h != 0)
//{ }
//if (Unknown_68h != 0)
//{ }
//if (Unknown_70h != 0)
//{ }
//if (Unknown_78h != 0)
//{ }
2017-09-21 18:33:05 +08:00
}
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 ) ;
2020-01-19 23:08:04 +08:00
writer . Write ( this . Flags ) ;
2017-09-21 18:33:05 +08:00
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 . InfoPointer ) ;
writer . Write ( this . Unknown_38h ) ;
writer . Write ( this . Unknown_40h ) ;
writer . Write ( this . Unknown_48h ) ;
writer . Write ( this . Unknown_50h ) ;
writer . Write ( this . Unknown_58h ) ;
writer . Write ( this . Unknown_60h ) ;
writer . Write ( this . Unknown_68h ) ;
writer . Write ( this . Unknown_70h ) ;
writer . Write ( this . Unknown_78h ) ;
}
2020-01-19 23:08:04 +08:00
public void WriteXml ( StringBuilder sb , int indent )
{
YdrXml . ValueTag ( sb , indent , "Flags" , Flags . ToString ( ) ) ;
if ( Info ! = null )
{
2020-01-21 00:12:36 +08:00
Info . WriteXml ( sb , indent , "Layout" ) ;
2020-01-19 23:08:04 +08:00
}
if ( Data1 ! = null )
{
YdrXml . OpenTag ( sb , indent , "Data" ) ;
Data1 . WriteXml ( sb , indent + 1 ) ;
YdrXml . CloseTag ( sb , indent , "Data" ) ;
}
if ( ( Data2 ! = null ) & & ( Data2 ! = Data1 ) )
{
YdrXml . OpenTag ( sb , indent , "Data2" ) ;
Data2 . WriteXml ( sb , indent + 1 ) ;
YdrXml . CloseTag ( sb , indent , "Data2" ) ;
}
}
public void ReadXml ( XmlNode node )
{
Flags = ( ushort ) Xml . GetChildUIntAttribute ( node , "Flags" , "value" ) ;
var inode = node . SelectSingleNode ( "Layout" ) ;
if ( inode ! = null )
{
Info = new VertexDeclaration ( ) ;
Info . ReadXml ( inode ) ;
VertexStride = Info . Stride ;
}
var dnode = node . SelectSingleNode ( "Data" ) ;
if ( dnode ! = null )
{
Data1 = new VertexData ( ) ;
Data1 . ReadXml ( dnode , Info ) ;
Data2 = Data1 ;
VertexCount = ( uint ) Data1 . VertexCount ;
}
var dnode2 = node . SelectSingleNode ( "Data2" ) ;
if ( dnode2 ! = null )
{
Data2 = new VertexData ( ) ;
Data2 . ReadXml ( dnode2 , Info ) ;
}
}
2017-09-21 18:33:05 +08:00
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
}
}
2020-01-19 23:08:04 +08:00
public int VertexStride { get ; set ; }
public int VertexCount { get ; set ; }
public VertexDeclaration Info { get ; set ; }
2017-09-21 18:33:05 +08:00
public VertexType VertexType { get ; set ; }
2020-01-19 23:08:04 +08:00
2017-09-21 18:33:05 +08:00
public byte [ ] VertexBytes { 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 ] ) ;
2020-01-19 23:08:04 +08:00
Info = ( VertexDeclaration ) parameters [ 2 ] ;
VertexType = ( VertexType ) Info . Flags ;
2017-09-21 18:33:05 +08:00
VertexBytes = reader . ReadBytes ( VertexCount * VertexStride ) ;
2020-01-19 23:08:04 +08:00
switch ( Info . Types )
2017-09-21 18:33:05 +08:00
{
2020-01-19 23:08:04 +08:00
case VertexDeclarationTypes . GTAV1 : //YDR - 0x7755555555996996
2017-09-21 18:33:05 +08:00
break ;
2020-01-19 23:08:04 +08:00
case VertexDeclarationTypes . GTAV2 : //YFT - 0x030000000199A006
switch ( Info . Flags )
2017-09-21 18:33:05 +08:00
{
case 16473 : VertexType = VertexType . PCCH2H4 ; break ; // PCCH2H4
default : break ;
}
break ;
2020-01-19 23:08:04 +08:00
case VertexDeclarationTypes . GTAV3 : //YFT - 0x0300000001996006 PNCH2H4
switch ( Info . Flags )
2017-09-21 18:33:05 +08:00
{
case 89 : VertexType = VertexType . PNCH2 ; break ; // PNCH2
default : break ;
}
break ;
default :
break ;
}
}
2020-01-19 23:08:04 +08:00
public override void Write ( ResourceDataWriter writer , params object [ ] parameters )
2017-09-21 18:33:05 +08:00
{
2020-01-19 23:08:04 +08:00
if ( VertexBytes ! = null )
{
writer . Write ( VertexBytes ) ; //not dealing with individual vertex data here any more!
}
}
public void WriteXml ( StringBuilder sb , int indent )
{
var flags = Info ? . Flags ? ? 0 ;
var row = new StringBuilder ( ) ;
for ( int v = 0 ; v < VertexCount ; v + + )
2017-09-21 18:33:05 +08:00
{
2020-01-19 23:08:04 +08:00
row . Clear ( ) ;
for ( int k = 0 ; k < 16 ; k + + )
2017-09-21 18:33:05 +08:00
{
2020-01-19 23:08:04 +08:00
if ( ( ( flags > > k ) & 0x1 ) = = 1 )
2017-09-21 18:33:05 +08:00
{
2020-01-19 23:08:04 +08:00
if ( row . Length > 0 ) row . Append ( " " ) ;
var str = GetString ( v , k , " " ) ;
row . Append ( str ) ;
2017-09-21 18:33:05 +08:00
}
}
2020-01-19 23:08:04 +08:00
YdrXml . Indent ( sb , indent ) ;
sb . AppendLine ( row . ToString ( ) ) ;
2017-09-21 18:33:05 +08:00
}
2020-01-19 23:08:04 +08:00
}
public void ReadXml ( XmlNode node , VertexDeclaration info )
{
Info = info ;
VertexType = ( VertexType ) ( info ? . Flags ? ? 0 ) ;
2017-09-21 18:33:05 +08:00
2020-01-19 23:08:04 +08:00
if ( Info ! = null )
2017-09-21 18:33:05 +08:00
{
2020-01-19 23:08:04 +08:00
var flags = Info . Flags ;
var stride = Info . Stride ;
var vstrs = new List < string [ ] > ( ) ;
var coldelim = new [ ] { ' ' , '\t' } ;
var rowdelim = new [ ] { '\n' } ;
var rows = node ? . InnerText ? . Trim ( ) ? . Split ( rowdelim , StringSplitOptions . RemoveEmptyEntries ) ;
if ( rows ! = null )
2017-09-21 18:33:05 +08:00
{
2020-01-19 23:08:04 +08:00
foreach ( var row in rows )
2017-09-21 18:33:05 +08:00
{
2020-01-19 23:08:04 +08:00
var rowt = row . Trim ( ) ;
if ( string . IsNullOrEmpty ( rowt ) ) continue ;
var cols = row . Split ( coldelim , StringSplitOptions . RemoveEmptyEntries ) ;
vstrs . Add ( cols ) ;
}
}
if ( vstrs . Count > 0 )
{
AllocateData ( vstrs . Count ) ;
for ( int v = 0 ; v < vstrs . Count ; v + + )
{
var vstr = vstrs [ v ] ;
var sind = 0 ;
for ( int k = 0 ; k < 16 ; k + + )
2017-09-21 18:33:05 +08:00
{
2020-01-19 23:08:04 +08:00
if ( ( ( flags > > k ) & 0x1 ) = = 1 )
{
SetString ( v , k , vstr , ref sind ) ;
}
2017-09-21 18:33:05 +08:00
}
}
}
}
}
2020-01-19 23:08:04 +08:00
public void AllocateData ( int vertexCount )
{
if ( Info ! = null )
2017-09-21 18:33:05 +08:00
{
2020-01-19 23:08:04 +08:00
var stride = Info . Stride ;
var byteCount = vertexCount * stride ;
VertexBytes = new byte [ byteCount ] ;
VertexCount = vertexCount ;
}
}
2017-09-21 18:33:05 +08:00
2020-01-19 23:08:04 +08:00
public void SetString ( int v , int c , string [ ] strs , ref int sind )
{
if ( ( Info ! = null ) & & ( VertexBytes ! = null ) & & ( strs ! = null ) )
{
var ind = sind ;
float f ( int i ) = > FloatUtil . Parse ( strs [ ind + i ] . Trim ( ) ) ;
byte b ( int i ) { if ( byte . TryParse ( strs [ ind + i ] . Trim ( ) , out byte x ) ) return x ; else return 0 ; }
var ct = Info . GetComponentType ( c ) ;
var cc = VertexComponentTypes . GetComponentCount ( ct ) ;
if ( sind + cc > strs . Length )
{ return ; }
switch ( ct )
2017-09-21 18:33:05 +08:00
{
2020-01-19 23:08:04 +08:00
case VertexComponentType . Float : SetFloat ( v , c , f ( 0 ) ) ; break ;
case VertexComponentType . Float2 : SetVector2 ( v , c , new Vector2 ( f ( 0 ) , f ( 1 ) ) ) ; break ;
case VertexComponentType . Float3 : SetVector3 ( v , c , new Vector3 ( f ( 0 ) , f ( 1 ) , f ( 2 ) ) ) ; break ;
case VertexComponentType . Float4 : SetVector4 ( v , c , new Vector4 ( f ( 0 ) , f ( 1 ) , f ( 2 ) , f ( 3 ) ) ) ; break ;
case VertexComponentType . Dec3N : SetDec3N ( v , c , new Vector3 ( f ( 0 ) , f ( 1 ) , f ( 2 ) ) ) ; break ;
case VertexComponentType . Half2 : SetHalf2 ( v , c , new Half2 ( f ( 0 ) , f ( 1 ) ) ) ; break ;
case VertexComponentType . Half4 : SetHalf4 ( v , c , new Half4 ( f ( 0 ) , f ( 1 ) , f ( 2 ) , f ( 3 ) ) ) ; break ;
case VertexComponentType . Colour : SetColour ( v , c , new Color ( b ( 0 ) , b ( 1 ) , b ( 2 ) , b ( 3 ) ) ) ; break ;
case VertexComponentType . UByte4 : SetUByte4 ( v , c , new Color ( b ( 0 ) , b ( 1 ) , b ( 2 ) , b ( 3 ) ) ) ; break ;
default :
break ;
}
sind + = cc ;
}
}
public void SetFloat ( int v , int c , float val )
{
if ( ( Info ! = null ) & & ( VertexBytes ! = null ) )
{
var s = Info . Stride ;
var co = Info . GetComponentOffset ( c ) ;
var o = ( v * s ) + co ;
var e = o + 4 ; //sizeof(float)
if ( e < = VertexBytes . Length )
{
var b = BitConverter . GetBytes ( val ) ;
Buffer . BlockCopy ( b , 0 , VertexBytes , o , 4 ) ;
}
}
}
public void SetVector2 ( int v , int c , Vector2 val )
{
if ( ( Info ! = null ) & & ( VertexBytes ! = null ) )
{
var s = Info . Stride ;
var co = Info . GetComponentOffset ( c ) ;
var o = ( v * s ) + co ;
var e = o + 8 ; //sizeof(Vector2)
if ( e < = VertexBytes . Length )
{
var x = BitConverter . GetBytes ( val . X ) ;
var y = BitConverter . GetBytes ( val . Y ) ;
Buffer . BlockCopy ( x , 0 , VertexBytes , o + 0 , 4 ) ;
Buffer . BlockCopy ( y , 0 , VertexBytes , o + 4 , 4 ) ;
}
}
}
public void SetVector3 ( int v , int c , Vector3 val )
{
if ( ( Info ! = null ) & & ( VertexBytes ! = null ) )
{
var s = Info . Stride ;
var co = Info . GetComponentOffset ( c ) ;
var o = ( v * s ) + co ;
var e = o + 12 ; //sizeof(Vector3)
if ( e < = VertexBytes . Length )
{
var x = BitConverter . GetBytes ( val . X ) ;
var y = BitConverter . GetBytes ( val . Y ) ;
var z = BitConverter . GetBytes ( val . Z ) ;
Buffer . BlockCopy ( x , 0 , VertexBytes , o + 0 , 4 ) ;
Buffer . BlockCopy ( y , 0 , VertexBytes , o + 4 , 4 ) ;
Buffer . BlockCopy ( z , 0 , VertexBytes , o + 8 , 4 ) ;
}
}
}
public void SetVector4 ( int v , int c , Vector4 val )
{
if ( ( Info ! = null ) & & ( VertexBytes ! = null ) )
{
var s = Info . Stride ;
var co = Info . GetComponentOffset ( c ) ;
var o = ( v * s ) + co ;
var e = o + 16 ; //sizeof(Vector4)
if ( e < = VertexBytes . Length )
{
var x = BitConverter . GetBytes ( val . X ) ;
var y = BitConverter . GetBytes ( val . Y ) ;
var z = BitConverter . GetBytes ( val . Z ) ;
var w = BitConverter . GetBytes ( val . W ) ;
Buffer . BlockCopy ( x , 0 , VertexBytes , o + 0 , 4 ) ;
Buffer . BlockCopy ( y , 0 , VertexBytes , o + 4 , 4 ) ;
Buffer . BlockCopy ( z , 0 , VertexBytes , o + 8 , 4 ) ;
Buffer . BlockCopy ( w , 0 , VertexBytes , o + 12 , 4 ) ;
}
}
}
public void SetDec3N ( int v , int c , Vector3 val )
{
//see https://docs.microsoft.com/en-us/previous-versions/windows/desktop/bb322868(v%3Dvs.85)
if ( ( Info ! = null ) & & ( VertexBytes ! = null ) )
{
var s = Info . Stride ;
var co = Info . GetComponentOffset ( c ) ;
var o = ( v * s ) + co ;
var e = o + 4 ; //sizeof(Dec3N)
if ( e < = VertexBytes . Length )
{
var sx = ( val . X < 0.0f ) ;
var sy = ( val . X < 0.0f ) ;
var sz = ( val . X < 0.0f ) ;
var x = Math . Min ( ( uint ) ( Math . Abs ( val . X ) * 511.0f ) , 511 ) ;
var y = Math . Min ( ( uint ) ( Math . Abs ( val . Y ) * 511.0f ) , 511 ) ;
var z = Math . Min ( ( uint ) ( Math . Abs ( val . Z ) * 511.0f ) , 511 ) ;
var ux = ( ( sx ? ~ x : x ) & 0x1FF ) + ( sx ? 0x200 : 0 ) ;
var uy = ( ( sy ? ~ y : y ) & 0x1FF ) + ( sy ? 0x200 : 0 ) ;
var uz = ( ( sz ? ~ z : z ) & 0x1FF ) + ( sz ? 0x200 : 0 ) ;
var uw = 0 u ;
var u = ux + ( uy < < 10 ) + ( uz < < 20 ) + ( uw < < 30 ) ;
var b = BitConverter . GetBytes ( u ) ;
Buffer . BlockCopy ( b , 0 , VertexBytes , o , 4 ) ;
}
}
}
public void SetHalf2 ( int v , int c , Half2 val )
{
if ( ( Info ! = null ) & & ( VertexBytes ! = null ) )
{
var s = Info . Stride ;
var co = Info . GetComponentOffset ( c ) ;
var o = ( v * s ) + co ;
var e = o + 4 ; //sizeof(Half2)
if ( e < = VertexBytes . Length )
{
var x = BitConverter . GetBytes ( val . X . RawValue ) ;
var y = BitConverter . GetBytes ( val . Y . RawValue ) ;
Buffer . BlockCopy ( x , 0 , VertexBytes , o + 0 , 2 ) ;
Buffer . BlockCopy ( y , 0 , VertexBytes , o + 2 , 2 ) ;
}
}
}
public void SetHalf4 ( int v , int c , Half4 val )
{
if ( ( Info ! = null ) & & ( VertexBytes ! = null ) )
{
var s = Info . Stride ;
var co = Info . GetComponentOffset ( c ) ;
var o = ( v * s ) + co ;
var e = o + 8 ; //sizeof(Half4)
if ( e < = VertexBytes . Length )
{
var x = BitConverter . GetBytes ( val . X . RawValue ) ;
var y = BitConverter . GetBytes ( val . Y . RawValue ) ;
var z = BitConverter . GetBytes ( val . Z . RawValue ) ;
var w = BitConverter . GetBytes ( val . W . RawValue ) ;
Buffer . BlockCopy ( x , 0 , VertexBytes , o + 0 , 2 ) ;
Buffer . BlockCopy ( y , 0 , VertexBytes , o + 2 , 2 ) ;
Buffer . BlockCopy ( z , 0 , VertexBytes , o + 4 , 2 ) ;
Buffer . BlockCopy ( w , 0 , VertexBytes , o + 6 , 2 ) ;
}
}
}
public void SetColour ( int v , int c , Color val )
{
if ( ( Info ! = null ) & & ( VertexBytes ! = null ) )
{
var s = Info . Stride ;
var co = Info . GetComponentOffset ( c ) ;
var o = ( v * s ) + co ;
var e = o + 4 ; //sizeof(Color)
if ( e < = VertexBytes . Length )
{
var u = val . ToRgba ( ) ;
var b = BitConverter . GetBytes ( u ) ;
Buffer . BlockCopy ( b , 0 , VertexBytes , o , 4 ) ;
}
}
}
public void SetUByte4 ( int v , int c , Color val )
{
if ( ( Info ! = null ) & & ( VertexBytes ! = null ) )
{
var s = Info . Stride ;
var co = Info . GetComponentOffset ( c ) ;
var o = ( v * s ) + co ;
var e = o + 4 ; //sizeof(UByte4)
if ( e < = VertexBytes . Length )
{
var u = val . ToRgba ( ) ;
var b = BitConverter . GetBytes ( u ) ;
Buffer . BlockCopy ( b , 0 , VertexBytes , o , 4 ) ;
2017-09-21 18:33:05 +08:00
}
}
}
2020-01-19 23:08:04 +08:00
public string GetString ( int v , int c , string d = ", " )
2019-01-28 10:13:45 +08:00
{
2020-01-19 23:08:04 +08:00
if ( ( Info ! = null ) & & ( VertexBytes ! = null ) )
2019-01-28 10:13:45 +08:00
{
2020-01-19 23:08:04 +08:00
var ct = Info . GetComponentType ( c ) ;
switch ( ct )
{
case VertexComponentType . Float : return FloatUtil . ToString ( GetFloat ( v , c ) ) ;
case VertexComponentType . Float2 : return FloatUtil . GetVector2String ( GetVector2 ( v , c ) , d ) ;
case VertexComponentType . Float3 : return FloatUtil . GetVector3String ( GetVector3 ( v , c ) , d ) ;
case VertexComponentType . Float4 : return FloatUtil . GetVector4String ( GetVector4 ( v , c ) , d ) ;
case VertexComponentType . Dec3N : return FloatUtil . GetVector3String ( GetDec3N ( v , c ) , d ) ;
case VertexComponentType . Half2 : return FloatUtil . GetHalf2String ( GetHalf2 ( v , c ) , d ) ;
case VertexComponentType . Half4 : return FloatUtil . GetHalf4String ( GetHalf4 ( v , c ) , d ) ;
case VertexComponentType . Colour : return FloatUtil . GetColourString ( GetColour ( v , c ) , d ) ;
case VertexComponentType . UByte4 : return FloatUtil . GetColourString ( GetUByte4 ( v , c ) , d ) ;
default :
break ;
}
}
return string . Empty ;
}
public float GetFloat ( int v , int c )
{
if ( ( Info ! = null ) & & ( VertexBytes ! = null ) )
{
var s = Info . Stride ;
var co = Info . GetComponentOffset ( c ) ;
var o = ( v * s ) + co ;
var e = o + 4 ; //sizeof(float)
if ( e < = VertexBytes . Length )
{
var f = BitConverter . ToSingle ( VertexBytes , o ) ;
return f ;
}
}
return 0 ;
}
public Vector2 GetVector2 ( int v , int c )
{
if ( ( Info ! = null ) & & ( VertexBytes ! = null ) )
{
var s = Info . Stride ;
var co = Info . GetComponentOffset ( c ) ;
var o = ( v * s ) + co ;
var e = o + 8 ; //sizeof(Vector2)
if ( e < = VertexBytes . Length )
{
var x = BitConverter . ToSingle ( VertexBytes , o + 0 ) ;
var y = BitConverter . ToSingle ( VertexBytes , o + 4 ) ;
return new Vector2 ( x , y ) ;
}
}
return Vector2 . Zero ;
}
public Vector3 GetVector3 ( int v , int c )
{
if ( ( Info ! = null ) & & ( VertexBytes ! = null ) )
{
var s = Info . Stride ;
var co = Info . GetComponentOffset ( c ) ;
var o = ( v * s ) + co ;
var e = o + 12 ; //sizeof(Vector3)
if ( e < = VertexBytes . Length )
{
var x = BitConverter . ToSingle ( VertexBytes , o + 0 ) ;
var y = BitConverter . ToSingle ( VertexBytes , o + 4 ) ;
var z = BitConverter . ToSingle ( VertexBytes , o + 8 ) ;
return new Vector3 ( x , y , z ) ;
}
}
return Vector3 . Zero ;
}
public Vector4 GetVector4 ( int v , int c )
{
if ( ( Info ! = null ) & & ( VertexBytes ! = null ) )
{
var s = Info . Stride ;
var co = Info . GetComponentOffset ( c ) ;
var o = ( v * s ) + co ;
var e = o + 16 ; //sizeof(Vector4)
if ( e < = VertexBytes . Length )
{
var x = BitConverter . ToSingle ( VertexBytes , o + 0 ) ;
var y = BitConverter . ToSingle ( VertexBytes , o + 4 ) ;
var z = BitConverter . ToSingle ( VertexBytes , o + 8 ) ;
var w = BitConverter . ToSingle ( VertexBytes , o + 12 ) ;
return new Vector4 ( x , y , z , w ) ;
}
}
return Vector4 . Zero ;
}
public Vector3 GetDec3N ( int v , int c )
{
//see https://docs.microsoft.com/en-us/previous-versions/windows/desktop/bb322868(v%3Dvs.85)
if ( ( Info ! = null ) & & ( VertexBytes ! = null ) )
{
var s = Info . Stride ;
var co = Info . GetComponentOffset ( c ) ;
var o = ( v * s ) + co ;
var e = o + 4 ; //sizeof(Dec3N)
if ( e < = VertexBytes . Length )
{
var u = BitConverter . ToUInt32 ( VertexBytes , o ) ;
var ux = ( u > > 0 ) & 0x3FF ;
var uy = ( u > > 10 ) & 0x3FF ;
var uz = ( u > > 20 ) & 0x3FF ;
var uw = ( u > > 30 ) ;
var sx = ( ux & 0x200 ) > 0 ;
var sy = ( uy & 0x200 ) > 0 ;
var sz = ( uz & 0x200 ) > 0 ;
var x = ( ( sx ? ~ ux : ux ) & 0x1FF ) / ( sx ? - 511.0f : 511.0f ) ;
var y = ( ( sy ? ~ uy : uy ) & 0x1FF ) / ( sy ? - 511.0f : 511.0f ) ;
var z = ( ( sz ? ~ uz : uz ) & 0x1FF ) / ( sz ? - 511.0f : 511.0f ) ;
return new Vector3 ( x , y , z ) ;
}
}
return Vector3 . Zero ;
}
public Half2 GetHalf2 ( int v , int c )
{
if ( ( Info ! = null ) & & ( VertexBytes ! = null ) )
{
var s = Info . Stride ;
var co = Info . GetComponentOffset ( c ) ;
var o = ( v * s ) + co ;
var e = o + 4 ; //sizeof(Half2)
if ( e < = VertexBytes . Length )
{
var x = BitConverter . ToUInt16 ( VertexBytes , o + 0 ) ;
var y = BitConverter . ToUInt16 ( VertexBytes , o + 2 ) ;
return new Half2 ( x , y ) ;
}
}
return new Half2 ( 0 , 0 ) ;
}
public Half4 GetHalf4 ( int v , int c )
{
if ( ( Info ! = null ) & & ( VertexBytes ! = null ) )
{
var s = Info . Stride ;
var co = Info . GetComponentOffset ( c ) ;
var o = ( v * s ) + co ;
var e = o + 8 ; //sizeof(Half4)
if ( e < = VertexBytes . Length )
{
var x = BitConverter . ToUInt16 ( VertexBytes , o + 0 ) ;
var y = BitConverter . ToUInt16 ( VertexBytes , o + 2 ) ;
var z = BitConverter . ToUInt16 ( VertexBytes , o + 4 ) ;
var w = BitConverter . ToUInt16 ( VertexBytes , o + 6 ) ;
return new Half4 ( x , y , z , w ) ;
}
}
return new Half4 ( 0 , 0 , 0 , 0 ) ;
}
public Color GetColour ( int v , int c )
{
if ( ( Info ! = null ) & & ( VertexBytes ! = null ) )
{
var s = Info . Stride ;
var co = Info . GetComponentOffset ( c ) ;
var o = ( v * s ) + co ;
var e = o + 4 ; //sizeof(Color)
if ( e < = VertexBytes . Length )
{
var rgba = BitConverter . ToUInt32 ( VertexBytes , o ) ;
return new Color ( rgba ) ;
}
}
return Color . Black ;
}
public Color GetUByte4 ( int v , int c )
{
//Color is the same as UByte4 really
if ( ( Info ! = null ) & & ( VertexBytes ! = null ) )
{
var s = Info . Stride ;
var co = Info . GetComponentOffset ( c ) ;
var o = ( v * s ) + co ;
var e = o + 4 ; //sizeof(UByte4)
if ( e < = VertexBytes . Length )
{
var rgba = BitConverter . ToUInt32 ( VertexBytes , o ) ;
return new Color ( rgba ) ;
}
2019-01-28 10:13:45 +08:00
}
2020-01-19 23:08:04 +08:00
return new Color ( 0 , 0 , 0 , 0 ) ;
2019-01-28 10:13:45 +08:00
}
2020-01-19 23:08:04 +08:00
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 ; }
2020-01-19 23:08:04 +08:00
public byte Unknown_6h { get ; set ; } //0
2017-09-21 18:33:05 +08:00
public byte Count { get ; set ; }
2020-01-19 23:08:04 +08:00
public VertexDeclarationTypes Types { get ; set ; }
2017-09-21 18:33:05 +08:00
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 ( ) ;
2020-01-19 23:08:04 +08:00
this . Types = ( VertexDeclarationTypes ) reader . ReadUInt64 ( ) ;
////just testing!
//UpdateCountAndStride();
//if (Unknown_6h != 0)
//{ }//no hit
2017-09-21 18:33:05 +08:00
2020-01-19 23:08:04 +08:00
}
2017-09-21 18:33:05 +08:00
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 ) ;
2020-01-19 23:08:04 +08:00
writer . Write ( ( ulong ) this . Types ) ;
}
2020-01-21 00:12:36 +08:00
public void WriteXml ( StringBuilder sb , int indent , string name )
2020-01-19 23:08:04 +08:00
{
2020-01-21 00:12:36 +08:00
YdrXml . OpenTag ( sb , indent , name + " type=\"" + Types . ToString ( ) + "\"" ) ;
2020-01-19 23:08:04 +08:00
for ( int k = 0 ; k < 16 ; k + + )
{
if ( ( ( Flags > > k ) & 0x1 ) = = 1 )
{
var componentSemantic = ( VertexSemantics ) k ;
var tag = componentSemantic . ToString ( ) ;
2020-01-21 00:12:36 +08:00
YdrXml . SelfClosingTag ( sb , indent + 1 , tag ) ;
2020-01-19 23:08:04 +08:00
}
}
2020-01-21 00:12:36 +08:00
YdrXml . CloseTag ( sb , indent , name ) ;
2020-01-19 23:08:04 +08:00
}
public void ReadXml ( XmlNode node )
{
2020-01-21 00:12:36 +08:00
if ( node = = null ) return ;
2020-01-19 23:08:04 +08:00
Types = Xml . GetEnumValue < VertexDeclarationTypes > ( Xml . GetStringAttribute ( node , "type" ) ) ;
uint f = 0 ;
foreach ( XmlNode cnode in node . ChildNodes )
{
if ( cnode is XmlElement celem )
{
var componentSematic = Xml . GetEnumValue < VertexSemantics > ( celem . Name ) ;
var idx = ( int ) componentSematic ;
f = f | ( 1 u < < idx ) ;
}
}
Flags = f ;
UpdateCountAndStride ( ) ;
2017-09-21 18:33:05 +08:00
}
public ulong GetDeclarationId ( )
{
ulong res = 0 ;
for ( int i = 0 ; i < 16 ; i + + )
{
if ( ( ( Flags > > i ) & 1 ) = = 1 )
{
2020-01-19 23:08:04 +08:00
res + = ( ( ulong ) Types & ( 0xF u < < ( i * 4 ) ) ) ;
2017-09-21 18:33:05 +08:00
}
}
return res ;
}
2020-01-19 23:08:04 +08:00
public VertexComponentType GetComponentType ( int index )
{
//index is the flags bit index
return ( VertexComponentType ) ( ( ( ulong ) Types > > ( index * 4 ) ) & 0x0000000F ) ;
}
public int GetComponentOffset ( int index )
{
//index is the flags bit index
var offset = 0 ;
for ( int k = 0 ; k < index ; k + + )
{
if ( ( ( Flags > > k ) & 0x1 ) = = 1 )
{
var componentType = GetComponentType ( k ) ;
offset + = VertexComponentTypes . GetSizeInBytes ( componentType ) ;
}
}
return offset ;
}
public void UpdateCountAndStride ( )
{
var cnt = 0 ;
var str = 0 ;
for ( int k = 0 ; k < 16 ; k + + )
{
if ( ( ( Flags > > k ) & 0x1 ) = = 1 )
{
var componentType = GetComponentType ( k ) ;
str + = VertexComponentTypes . GetSizeInBytes ( componentType ) ;
cnt + + ;
}
}
////just testing
//if (Count != cnt)
//{ }//no hit
//if (Stride != str)
//{ }//no hit
Count = ( byte ) cnt ;
Stride = ( ushort ) str ;
}
2017-09-21 18:33:05 +08:00
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 ; }
2020-01-21 00:12:36 +08:00
public uint Unknown_4h = 1 ; // 0x00000001
2017-09-21 18:33:05 +08:00
public uint IndicesCount { get ; set ; }
2020-01-21 00:12:36 +08:00
public uint Unknown_Ch ; // 0x00000000
2017-09-21 18:33:05 +08:00
public ulong IndicesPointer { get ; set ; }
2020-01-21 00:12:36 +08:00
public ulong Unknown_18h ; // 0x0000000000000000
public ulong Unknown_20h ; // 0x0000000000000000
public ulong Unknown_28h ; // 0x0000000000000000
public ulong Unknown_30h ; // 0x0000000000000000
public ulong Unknown_38h ; // 0x0000000000000000
public ulong Unknown_40h ; // 0x0000000000000000
public ulong Unknown_48h ; // 0x0000000000000000
public ulong Unknown_50h ; // 0x0000000000000000
public ulong Unknown_58h ; // 0x0000000000000000
2017-09-21 18:33:05 +08:00
// 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
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 ( ) ;
2020-01-21 00:12:36 +08:00
this . Unknown_18h = reader . ReadUInt64 ( ) ;
this . Unknown_20h = reader . ReadUInt64 ( ) ;
this . Unknown_28h = reader . ReadUInt64 ( ) ;
this . Unknown_30h = reader . ReadUInt64 ( ) ;
this . Unknown_38h = reader . ReadUInt64 ( ) ;
this . Unknown_40h = reader . ReadUInt64 ( ) ;
this . Unknown_48h = reader . ReadUInt64 ( ) ;
this . Unknown_50h = reader . ReadUInt64 ( ) ;
this . Unknown_58h = reader . ReadUInt64 ( ) ;
2017-09-21 18:33:05 +08:00
// read reference data
//this.Indices = reader.ReadBlockAt<ResourceSimpleArray<ushort_r>>(
// this.IndicesPointer, // offset
// this.IndicesCount
//);
this . Indices = reader . ReadUshortsAt ( this . IndicesPointer , this . IndicesCount ) ;
2020-01-21 00:12:36 +08:00
//if (Unknown_4h != 1)
//{ }
//if (Unknown_Ch != 0)
//{ }
//if (Unknown_18h != 0)
//{ }
//if (Unknown_20h != 0)
//{ }
//if (Unknown_28h != 0)
//{ }
//if (Unknown_30h != 0)
//{ }
//if (Unknown_38h != 0)
//{ }
//if (Unknown_40h != 0)
//{ }
//if (Unknown_48h != 0)
//{ }
//if (Unknown_50h != 0)
//{ }
//if (Unknown_58h != 0)
//{ }
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 . 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_20h ) ;
writer . Write ( this . Unknown_28h ) ;
writer . Write ( this . Unknown_30h ) ;
writer . Write ( this . Unknown_38h ) ;
writer . Write ( this . Unknown_40h ) ;
writer . Write ( this . Unknown_48h ) ;
writer . Write ( this . Unknown_50h ) ;
writer . Write ( this . Unknown_58h ) ;
}
2020-01-19 23:08:04 +08:00
public void WriteXml ( StringBuilder sb , int indent )
{
if ( Indices ! = null )
{
YdrXml . WriteRawArray ( sb , Indices , indent , "Data" , "" , null , 24 ) ;
}
}
public void ReadXml ( XmlNode node )
{
var inode = node . SelectSingleNode ( "Data" ) ;
if ( inode ! = null )
{
Indices = Xml . GetRawUshortArray ( node ) ;
IndicesCount = ( uint ) ( Indices ? . Length ? ? 0 ) ;
}
}
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 ( 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 )
{
2020-01-21 23:45:27 +08:00
Position = Xml . GetChildVector3Attributes ( node , "Position" ) ;
2020-01-18 01:20:40 +08:00
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" ) ;
2020-01-21 23:45:27 +08:00
CullingPlaneNormal = Xml . GetChildVector3Attributes ( node , "CullingPlaneNormal" ) ;
2020-01-18 01:20:40 +08:00
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" ) ;
2020-01-21 23:45:27 +08:00
Direction = Xml . GetChildVector3Attributes ( node , "Direction" ) ;
Tangent = Xml . GetChildVector3Attributes ( node , "Tangent" ) ;
2020-01-18 01:20:40 +08:00
ConeInnerAngle = Xml . GetChildFloatAttribute ( node , "ConeInnerAngle" , "value" ) ;
ConeOuterAngle = Xml . GetChildFloatAttribute ( node , "ConeOuterAngle" , "value" ) ;
2020-01-21 23:45:27 +08:00
Extent = Xml . GetChildVector3Attributes ( node , "Extent" ) ;
2020-01-18 01:20:40 +08:00
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 ; }
2020-01-19 23:08:04 +08:00
public uint RenderMaskFlagsHigh { get ; set ; }
public uint RenderMaskFlagsMed { get ; set ; }
public uint RenderMaskFlagsLow { get ; set ; }
public uint RenderMaskFlagsVlow { get ; set ; }
2017-09-21 18:33:05 +08:00
public ulong JointsPointer { get ; set ; }
2020-01-21 00:12:36 +08:00
public ushort Unknown_98h { get ; set ; } // 0x0000
2019-03-20 18:21:47 +08:00
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 ; }
2020-01-19 23:08:04 +08:00
public byte FlagsHigh
{
get { return ( byte ) ( RenderMaskFlagsHigh & 0xFF ) ; }
set { RenderMaskFlagsHigh = ( RenderMaskFlagsHigh & 0xFFFFFF00 ) + ( value & 0xFF u ) ; }
}
public byte FlagsMed
{
get { return ( byte ) ( RenderMaskFlagsMed & 0xFF ) ; }
set { RenderMaskFlagsMed = ( RenderMaskFlagsMed & 0xFFFFFF00 ) + ( value & 0xFF u ) ; }
}
public byte FlagsLow
{
get { return ( byte ) ( RenderMaskFlagsLow & 0xFF ) ; }
set { RenderMaskFlagsLow = ( RenderMaskFlagsLow & 0xFFFFFF00 ) + ( value & 0xFF u ) ; }
}
public byte FlagsVlow
{
get { return ( byte ) ( RenderMaskFlagsVlow & 0xFF ) ; }
set { RenderMaskFlagsVlow = ( RenderMaskFlagsVlow & 0xFFFFFF00 ) + ( value & 0xFF u ) ; }
}
public byte RenderMaskHigh
{
get { return ( byte ) ( ( RenderMaskFlagsHigh > > 8 ) & 0xFF ) ; }
set { RenderMaskFlagsHigh = ( RenderMaskFlagsHigh & 0xFFFF00FF ) + ( ( value & 0xFF u ) < < 8 ) ; }
}
public byte RenderMaskMed
{
get { return ( byte ) ( ( RenderMaskFlagsMed > > 8 ) & 0xFF ) ; }
set { RenderMaskFlagsMed = ( RenderMaskFlagsMed & 0xFFFF00FF ) + ( ( value & 0xFF u ) < < 8 ) ; }
}
public byte RenderMaskLow
{
get { return ( byte ) ( ( RenderMaskFlagsLow > > 8 ) & 0xFF ) ; }
set { RenderMaskFlagsLow = ( RenderMaskFlagsLow & 0xFFFF00FF ) + ( ( value & 0xFF u ) < < 8 ) ; }
}
public byte RenderMaskVlow
{
get { return ( byte ) ( ( RenderMaskFlagsVlow > > 8 ) & 0xFF ) ; }
set { RenderMaskFlagsVlow = ( RenderMaskFlagsVlow & 0xFFFF00FF ) + ( ( value & 0xFF u ) < < 8 ) ; }
}
2017-09-21 18:33:05 +08:00
// 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 ( ) ;
2020-01-22 20:36:34 +08:00
this . BoundingCenter = reader . ReadVector3 ( ) ;
2017-09-21 18:33:05 +08:00
this . BoundingSphereRadius = reader . ReadSingle ( ) ;
2020-01-22 20:36:34 +08:00
this . BoundingBoxMin = reader . ReadVector4 ( ) ;
this . BoundingBoxMax = reader . ReadVector4 ( ) ;
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 ( ) ;
2020-01-19 23:08:04 +08:00
this . RenderMaskFlagsHigh = reader . ReadUInt32 ( ) ;
this . RenderMaskFlagsMed = reader . ReadUInt32 ( ) ;
this . RenderMaskFlagsLow = reader . ReadUInt32 ( ) ;
this . RenderMaskFlagsVlow = reader . ReadUInt32 ( ) ;
2017-09-21 18:33:05 +08:00
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
) ;
2020-01-22 20:36:34 +08:00
BuildAllModels ( ) ;
BuildVertexDecls ( ) ;
2017-09-21 18:33:05 +08:00
AssignGeometryShaders ( ShaderGroup ) ;
2020-01-19 23:08:04 +08:00
////just testing!!!
//if ((DrawableModelsHigh?.data_items != null) != (Unknown_80h != 0))
//{ }//no hit
//if ((DrawableModelsMedium?.data_items != null) != (Unknown_84h != 0))
//{ }//no hit
//if ((DrawableModelsLow?.data_items != null) != (Unknown_88h != 0))
//{ }//no hit
//if ((DrawableModelsVeryLow?.data_items != null) != (Unknown_8Ch != 0))
//{ }//no hit
//if ((Unknown_80h & 0xFFFF0000) > 0)
//{ }//no hit
//if ((Unknown_84h & 0xFFFF0000) > 0)
//{ }//no hit
//if ((Unknown_88h & 0xFFFF0000) > 0)
//{ }//no hit
//if ((Unknown_8Ch & 0xFFFF0000) > 0)
//{ }//no hit
//BuildRenderMasks();
//switch (FlagsHigh)
//{
// case 2:
// case 1:
// case 13:
// case 4:
// case 12:
// case 5:
// case 3:
// case 8:
// case 9:
// case 15:
// case 130:
// case 11:
// case 10:
// case 7:
// case 131:
// case 129:
// case 75:
// case 69:
// case 6:
// case 64:
// case 14:
// case 77:
// case 73:
// case 76:
// case 71:
// case 79:
// case 65:
// case 0://some yft's have null HD models
// case 19:
// case 51:
// break;
// default:
// break;
//}
//switch (FlagsMed)
//{
// case 0:
// case 1:
// case 9:
// case 8:
// case 13:
// case 3:
// case 2:
// case 5:
// case 11:
// case 15:
// case 10:
// case 12:
// case 4:
// case 7:
// case 51:
// break;
// default:
// break;
//}
//switch (FlagsLow)
//{
// case 0:
// case 9:
// case 1:
// case 8:
// case 5:
// case 3:
// case 13:
// case 2:
// case 11:
// case 15:
// case 4:
// case 7:
// case 51:
// break;
// default:
// break;
//}
//switch (FlagsVlow)
//{
// case 0:
// case 1:
// case 9:
// case 3:
// case 7:
// case 5:
// case 49:
// case 51:
// case 11:
// break;
// default:
// break;
//}
//switch (Unknown_98h)
//{
// case 0:
// break;
// default:
// break;//no hit
//}
//switch (Unknown_9Ah)//wtf isthis? flags?
//{
// case 18:
// case 33:
// case 34:
// case 46:
// case 58:
// case 209:
// case 71:
// case 172:
// case 64:
// case 122:
// case 96:
// case 248:
// case 147:
// case 51:
// case 159:
// case 134:
// case 108:
// case 83:
// case 336:
// case 450:
// case 197:
// case 374:
// case 184:
// case 310:
// case 36:
// case 386:
// case 285:
// case 260:
// case 77:
// case 361:
// case 235:
// case 91:
// case 223:
// case 1207:
// case 2090:
// case 45:
// case 52:
// case 526:
// case 3081:
// case 294:
// case 236:
// case 156:
// break;
// default://still lots more..
// break;
//}
2017-09-21 18:33:05 +08:00
}
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 ) ;
2020-01-19 23:08:04 +08:00
writer . Write ( this . RenderMaskFlagsHigh ) ;
writer . Write ( this . RenderMaskFlagsMed ) ;
writer . Write ( this . RenderMaskFlagsLow ) ;
writer . Write ( this . RenderMaskFlagsVlow ) ;
2017-09-21 18:33:05 +08:00
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 ) ) ;
2020-01-19 23:08:04 +08:00
YdrXml . ValueTag ( sb , indent , "FlagsHigh" , FlagsHigh . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "FlagsMed" , FlagsMed . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "FlagsLow" , FlagsLow . ToString ( ) ) ;
YdrXml . ValueTag ( sb , indent , "FlagsVlow" , FlagsVlow . ToString ( ) ) ;
2020-01-18 01:20:40 +08:00
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 )
{
2020-01-21 23:45:27 +08:00
BoundingCenter = Xml . GetChildVector3Attributes ( node , "BoundingSphereCenter" ) ;
2020-01-18 01:20:40 +08:00
BoundingSphereRadius = Xml . GetChildFloatAttribute ( node , "BoundingSphereRadius" , "value" ) ;
2020-01-21 23:45:27 +08:00
BoundingBoxMin = Xml . GetChildVector4Attributes ( node , "BoundingBoxMin" ) ;
BoundingBoxMax = Xml . GetChildVector4Attributes ( node , "BoundingBoxMax" ) ;
2020-01-18 01:20:40 +08:00
LodDistHigh = Xml . GetChildFloatAttribute ( node , "LodDistHigh" , "value" ) ;
LodDistMed = Xml . GetChildFloatAttribute ( node , "LodDistMed" , "value" ) ;
LodDistLow = Xml . GetChildFloatAttribute ( node , "LodDistLow" , "value" ) ;
LodDistVlow = Xml . GetChildFloatAttribute ( node , "LodDistVlow" , "value" ) ;
2020-01-19 23:08:04 +08:00
FlagsHigh = ( byte ) Xml . GetChildUIntAttribute ( node , "FlagsHigh" , "value" ) ;
FlagsMed = ( byte ) Xml . GetChildUIntAttribute ( node , "FlagsMed" , "value" ) ;
FlagsLow = ( byte ) Xml . GetChildUIntAttribute ( node , "FlagsLow" , "value" ) ;
FlagsVlow = ( byte ) Xml . GetChildUIntAttribute ( node , "FlagsVlow" , "value" ) ;
2020-01-18 01:20:40 +08:00
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 ;
}
2020-01-19 23:08:04 +08:00
else
{
DrawableModelsX = DrawableModelsHigh ;
}
BuildRenderMasks ( ) ;
2020-01-22 20:36:34 +08:00
BuildAllModels ( ) ;
BuildVertexDecls ( ) ;
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 > ( 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 )
{
2020-01-22 20:36:34 +08:00
//if (shaderGrp != null)
//{
// ShaderGroup = shaderGrp;
//}
2020-01-18 01:20:40 +08:00
//map the shaders to the geometries
2020-01-22 20:36:34 +08:00
if ( shaderGrp ! = null )
2020-01-18 01:20:40 +08:00
{
2020-01-22 20:36:34 +08:00
var shaders = shaderGrp . Shaders . data_items ;
2020-01-18 01:20:40 +08:00
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
2020-01-22 20:36:34 +08:00
public void BuildAllModels ( )
{
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 ( ) ;
}
public void BuildVertexDecls ( )
{
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 ) ;
}
2020-01-19 23:08:04 +08:00
public void BuildRenderMasks ( )
{
var hmask = BuildRenderMask ( DrawableModelsHigh ? . data_items ) ;
var mmask = BuildRenderMask ( DrawableModelsMedium ? . data_items ) ;
var lmask = BuildRenderMask ( DrawableModelsLow ? . data_items ) ;
var vmask = BuildRenderMask ( DrawableModelsVeryLow ? . data_items ) ;
////just testing
//if (hmask != RenderMaskHigh)
//{ }//no hit
//if (mmask != RenderMaskMed)
//{ }//no hit
//if (lmask != RenderMaskLow)
//{ }//no hit
//if (vmask != RenderMaskVlow)
//{ }//no hit
RenderMaskHigh = hmask ;
RenderMaskMed = mmask ;
RenderMaskLow = lmask ;
RenderMaskVlow = vmask ;
}
private byte BuildRenderMask ( DrawableModel [ ] models )
{
byte mask = 0 ;
if ( models ! = null )
{
foreach ( var model in models )
{
mask = ( byte ) ( mask | model . RenderMask ) ;
}
}
return mask ;
}
2019-11-27 12:01:43 +08:00
public DrawableBase ShallowCopy ( )
{
DrawableBase r = null ;
if ( this is FragDrawable fd )
{
var f = new FragDrawable ( ) ;
f . FragMatrix = fd . FragMatrix ;
f . FragMatricesIndsCount = fd . FragMatricesIndsCount ;
2020-01-21 00:12:36 +08:00
f . FragMatricesCapacity = fd . FragMatricesCapacity ;
2019-11-27 12:01:43 +08:00
f . FragMatricesCount = fd . FragMatricesCount ;
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 ;
2020-01-19 23:08:04 +08:00
r . RenderMaskFlagsHigh = RenderMaskFlagsHigh ;
r . RenderMaskFlagsMed = RenderMaskFlagsMed ;
r . RenderMaskFlagsLow = RenderMaskFlagsLow ;
r . RenderMaskFlagsVlow = RenderMaskFlagsVlow ;
2019-11-27 12:01:43 +08:00
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 ; }
2020-01-21 00:12:36 +08:00
public ulong ParticlesPointer { get ; set ; } // pointer in YPT files! TODO: investigate what it points to!
2017-09-21 18:33:05 +08:00
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 > > ( ) ;
2020-01-21 00:12:36 +08:00
this . ParticlesPointer = reader . ReadUInt64 ( ) ;
2017-09-21 18:33:05 +08:00
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 ( ) ;
}
2020-01-21 00:12:36 +08:00
if ( ParticlesPointer ! = 0 )
{ }
2017-09-21 18:33:05 +08:00
}
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 ) ;
2020-01-21 00:12:36 +08:00
writer . Write ( this . ParticlesPointer ) ;
2017-09-21 18:33:05 +08:00
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 )
{
2020-01-21 00:12:36 +08:00
YdrXml . WriteItemArray ( sb , LightAttributes . data_items , indent , "Lights" ) ;
2020-01-18 01:20:40 +08:00
}
}
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 ) ;
}
2020-01-19 23:08:04 +08:00
LightAttributes = new ResourceSimpleList64_s < LightAttributes_s > ( ) ;
2020-01-21 00:12:36 +08:00
LightAttributes . data_items = XmlMeta . ReadItemArray < LightAttributes_s > ( node , "Lights" ) ;
2020-01-19 23:08:04 +08:00
2020-01-18 01:20:40 +08:00
}
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
2020-01-21 00:12:36 +08:00
public ulong Unknown_10h ; // 0x0000000000000000
public ulong Unknown_18h = 1 ; // 0x0000000000000001
2017-09-21 18:33:05 +08:00
public ulong HashesPointer { get ; set ; }
public ushort HashesCount1 { get ; set ; }
public ushort HashesCount2 { get ; set ; }
2020-01-21 00:12:36 +08:00
public uint Unknown_2Ch ; // 0x00000000
2017-09-21 18:33:05 +08:00
public ulong DrawablesPointer { get ; set ; }
public ushort DrawablesCount1 { get ; set ; }
public ushort DrawablesCount2 { get ; set ; }
2020-01-21 00:12:36 +08:00
public uint Unknown_3Ch ; // 0x00000000
2017-09-21 18:33:05 +08:00
// 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
2020-01-21 00:12:36 +08:00
this . Unknown_10h = reader . ReadUInt64 ( ) ;
this . Unknown_18h = reader . ReadUInt64 ( ) ;
2017-09-21 18:33:05 +08:00
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
) ;
2020-01-21 00:12:36 +08:00
//if (Unknown_10h != 0)
//{ }
//if (Unknown_18h != 1)
//{ }
//if (Unknown_2Ch != 0)
//{ }
//if (Unknown_3Ch != 0)
//{ }
2017-09-21 18:33:05 +08:00
}
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_18h ) ;
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 ( ) ;
}
}
}