2012-08-17 14:16:58 +00:00
#region Using Statements
using System ;
using System.Collections.Generic ;
using System.Linq ;
using System.Text ;
using ANX.Framework.Content.Pipeline.Graphics ;
using System.ComponentModel ;
2015-04-08 14:50:03 +02:00
using ANX.Framework.Graphics.PackedVector ;
using ANX.Framework.Graphics ;
using ANX.Framework.Content.Pipeline.Helpers ;
2012-08-17 14:16:58 +00:00
#endregion
// This file is part of the ANX.Framework created by the
// "ANX.Framework developer group" and released under the Ms-PL license.
// For details see: http://anxframework.codeplex.com/license
namespace ANX.Framework.Content.Pipeline.Processors
{
2015-04-08 14:50:03 +02:00
[ContentProcessor(DisplayName = "Model Processor - ANX Framework")]
2012-08-17 14:16:58 +00:00
public class ModelProcessor : ContentProcessor < NodeContent , ModelContent >
{
2015-04-08 14:50:03 +02:00
[DefaultValue(typeof(Color), "255; 0; 255; 255")]
2012-08-17 14:16:58 +00:00
public virtual Color ColorKeyColor { get ; set ; }
2015-04-08 14:50:03 +02:00
[DefaultValue(true)]
2012-08-17 14:16:58 +00:00
public virtual bool ColorKeyEnabled { get ; set ; }
2015-04-08 14:50:03 +02:00
[DefaultValue(MaterialProcessorDefaultEffect.BasicEffect)]
2012-08-17 14:16:58 +00:00
public virtual MaterialProcessorDefaultEffect DefaultEffect { get ; set ; }
2015-04-08 14:50:03 +02:00
[DefaultValue(true)]
2012-08-17 14:16:58 +00:00
public virtual bool GenerateMipmaps { get ; set ; }
2015-04-08 14:50:03 +02:00
[DefaultValue(false)]
2012-08-17 14:16:58 +00:00
public virtual bool GenerateTangentFrames { get ; set ; }
2015-04-08 14:50:03 +02:00
2012-08-17 14:16:58 +00:00
[DefaultValue(true)]
public virtual bool PremultiplyTextureAlpha { get ; set ; }
2015-04-08 14:50:03 +02:00
2012-08-17 14:16:58 +00:00
[DefaultValue(true)]
public virtual bool PremultiplyVertexColors { get ; set ; }
2015-04-08 14:50:03 +02:00
[DefaultValue(false)]
2012-08-17 14:16:58 +00:00
public virtual bool ResizeTexturesToPowerOfTwo { get ; set ; }
2015-04-08 14:50:03 +02:00
[DefaultValue(0f)]
2012-08-17 14:16:58 +00:00
public virtual float RotationX { get ; set ; }
2015-04-08 14:50:03 +02:00
[DefaultValue(0f)]
2012-08-17 14:16:58 +00:00
public virtual float RotationY { get ; set ; }
2015-04-08 14:50:03 +02:00
[DefaultValue(0f)]
2012-08-17 14:16:58 +00:00
public virtual float RotationZ { get ; set ; }
2015-04-08 14:50:03 +02:00
[DefaultValue(1f)]
2012-08-17 14:16:58 +00:00
public virtual float Scale { get ; set ; }
2015-04-08 14:50:03 +02:00
[DefaultValue(false)]
2012-08-17 14:16:58 +00:00
public virtual bool SwapWindingOrder { get ; set ; }
2015-04-08 14:50:03 +02:00
[DefaultValue(TextureProcessorOutputFormat.DxtCompressed)]
2012-08-17 14:16:58 +00:00
public virtual TextureProcessorOutputFormat TextureFormat { get ; set ; }
2015-04-08 14:50:03 +02:00
public ModelProcessor ( )
{
ColorKeyColor = Color . FromNonPremultiplied ( 255 , 0 , 255 , 255 ) ;
ColorKeyEnabled = true ;
DefaultEffect = MaterialProcessorDefaultEffect . BasicEffect ;
GenerateMipmaps = true ;
GenerateTangentFrames = false ;
PremultiplyTextureAlpha = true ;
PremultiplyVertexColors = true ;
ResizeTexturesToPowerOfTwo = false ;
RotationX = 0f ;
RotationY = 0f ;
RotationZ = 0f ;
Scale = 1f ;
SwapWindingOrder = false ;
TextureFormat = TextureProcessorOutputFormat . DxtCompressed ;
}
2012-08-17 14:16:58 +00:00
public override ModelContent Process ( NodeContent input , ContentProcessorContext context )
{
2015-04-08 14:50:03 +02:00
if ( input = = null )
throw new ArgumentNullException ( "input" ) ;
if ( context = = null )
throw new ArgumentNullException ( "context" ) ;
Matrix transform = Matrix . Identity ;
if ( this . RotationZ ! = 0f )
transform * = Matrix . CreateRotationZ ( this . RotationZ ) ;
if ( this . RotationX ! = 0f )
transform * = Matrix . CreateRotationX ( this . RotationX ) ;
if ( this . RotationY ! = 0f )
transform * = Matrix . CreateRotationY ( this . RotationY ) ;
if ( this . Scale ! = 1f )
transform * = Matrix . CreateScale ( this . Scale ) ;
if ( transform ! = Matrix . Identity )
MeshHelper . TransformScene ( input , transform ) ;
Dictionary < NodeContent , ModelBoneContent > convertedBones = new Dictionary < NodeContent , ModelBoneContent > ( ) ;
var rootBone = MeshHelper . FindSkeleton ( input ) ;
if ( rootBone = = null )
{
//Create a ModelBoneContent representing the rootBone.
SetupParentBoneHierarchy ( input , convertedBones ) ;
}
else
ConvertBones ( MeshHelper . FlattenSkeleton ( rootBone ) , convertedBones ) ;
var convertedRootBone = convertedBones . First ( ) . Value ;
var meshes = NodeContentHelper . EnumNodesOfType < MeshContent > ( input ) ;
this . ProcessGeometryUsingMaterials ( meshes , context ) ;
var convertedMeshes = ConvertMeshes ( meshes , context , convertedBones ) ;
return new ModelContent ( convertedRootBone , new List < ModelBoneContent > ( convertedBones . Values ) , new List < ModelMeshContent > ( convertedMeshes ) ) ;
}
private IEnumerable < ModelMeshContent > ConvertMeshes ( IEnumerable < MeshContent > meshes , ContentProcessorContext context , Dictionary < NodeContent , ModelBoneContent > convertedBones )
{
if ( meshes = = null )
throw new ArgumentNullException ( "geometries" ) ;
Dictionary < MeshContent , ModelMeshContent > result = new Dictionary < MeshContent , ModelMeshContent > ( ) ;
ConvertMeshes ( meshes , context , result , convertedBones ) ;
return result . Values ;
}
private void ConvertMeshes ( IEnumerable < MeshContent > meshes , ContentProcessorContext context , Dictionary < MeshContent , ModelMeshContent > convertedMeshes , Dictionary < NodeContent , ModelBoneContent > convertedBones )
{
Dictionary < MaterialContent , MaterialContent > convertedMaterials = new Dictionary < MaterialContent , MaterialContent > ( ) ;
foreach ( var mesh in meshes )
{
ModelMeshContent convertedMesh ;
if ( ! convertedMeshes . TryGetValue ( mesh , out convertedMesh ) )
{
MeshHelper . MergeDuplicatePositions ( mesh , 0f ) ;
MeshHelper . MergeDuplicateVertices ( mesh ) ;
if ( this . GenerateTangentFrames )
{
bool containsTangents = ! mesh . Geometry . Any ( ( x ) = > x . Vertices . Channels . Contains ( VertexChannelNames . Tangent ( 0 ) ) ) ;
bool containsBinormals = ! mesh . Geometry . Any ( ( x ) = > x . Vertices . Channels . Contains ( VertexChannelNames . Binormal ( 0 ) ) ) ;
if ( containsTangents | | containsBinormals )
{
string tangentChannelName = containsTangents ? VertexChannelNames . Tangent ( 0 ) : null ;
string binormalChannelName = containsBinormals ? VertexChannelNames . Binormal ( 0 ) : null ;
MeshHelper . CalculateTangentFrames ( mesh , VertexChannelNames . TextureCoordinate ( 0 ) , tangentChannelName , binormalChannelName ) ;
}
}
if ( this . SwapWindingOrder )
{
MeshHelper . SwapWindingOrder ( mesh ) ;
}
MeshHelper . CalculateNormals ( mesh , false ) ;
ProcessVertexChannels ( mesh , context ) ;
MeshHelper . OptimizeForCache ( mesh ) ;
convertedMesh = new ModelMeshContent ( )
{
Name = mesh . Name ,
SourceMesh = mesh ,
BoundingSphere = BoundingSphere . CreateFromPoints ( mesh . Positions ) ,
} ;
convertedMesh . ParentBone = SetupParentBoneHierarchy ( mesh , convertedBones ) ;
foreach ( var geometry in mesh . Geometry )
{
MaterialContent convertedMaterial = null ;
if ( geometry . Material ! = null )
{
if ( ! convertedMaterials . TryGetValue ( geometry . Material , out convertedMaterial ) )
{
convertedMaterial = this . ConvertMaterial ( geometry . Material , context ) ;
convertedMaterials . Add ( geometry . Material , convertedMaterial ) ;
}
}
var vertexBuffer = geometry . Vertices . CreateVertexBuffer ( ) ;
IndexCollection indices = new IndexCollection ( ) ;
indices . AddRange ( geometry . Indices ) ;
ModelMeshPartContent convertedGeometry = new ModelMeshPartContent ( )
{
Material = convertedMaterial ,
VertexBuffer = vertexBuffer ,
NumVertices = geometry . Vertices . VertexCount ,
PrimitiveCount = geometry . Indices . Count / 3 ,
VertexOffset = 0 , //All have custom vertex buffer, so no vertex offset.
StartIndex = 0 ,
IndexBuffer = indices ,
} ;
convertedMesh . MeshParts . Add ( convertedGeometry ) ;
}
convertedMeshes . Add ( mesh , convertedMesh ) ;
}
}
}
private ModelBoneContent SetupParentBoneHierarchy ( NodeContent node , Dictionary < NodeContent , ModelBoneContent > convertedBones )
{
if ( node = = null )
return null ;
ModelBoneContent convertedBone ;
if ( convertedBones . TryGetValue ( node , out convertedBone ) )
return convertedBone ;
if ( node is BoneContent )
{
BoneContent bone = ( BoneContent ) node ;
return ConvertBone ( bone , convertedBones ) ;
}
else
{
//Parent of mesh is not a bone, but the structure of the modelContent requires a bone parent for every mesh, so we have to create one and insert it into the hierarchy.
convertedBone = new ModelBoneContent ( )
{
Name = node . Name ,
Transform = node . Transform ,
Index = convertedBones . Count ,
} ;
//If another mesh finds us as its parent, it will try to reuse our newly created bone.
convertedBones . Add ( node , convertedBone ) ;
convertedBone . Parent = SetupParentBoneHierarchy ( node . Parent , convertedBones ) ;
if ( convertedBone . Parent ! = null )
convertedBone . Parent . Children . Add ( convertedBone ) ;
return convertedBone ;
}
}
private IEnumerable < ModelBoneContent > ConvertBones ( IEnumerable < BoneContent > bones )
{
if ( bones = = null )
throw new ArgumentNullException ( "bones" ) ;
Dictionary < NodeContent , ModelBoneContent > result = new Dictionary < NodeContent , ModelBoneContent > ( ) ;
ConvertBones ( bones , result ) ;
return result . Values ;
}
private void ConvertBones ( IEnumerable < BoneContent > bones , Dictionary < NodeContent , ModelBoneContent > convertedDict )
{
foreach ( var bone in bones )
{
ModelBoneContent convertedBone ;
if ( ! convertedDict . TryGetValue ( bone , out convertedBone ) )
{
convertedBone = new ModelBoneContent ( )
{
Name = bone . Name ,
Transform = bone . Transform ,
Index = convertedDict . Count ,
} ;
convertedDict . Add ( bone , convertedBone ) ;
if ( bone . Parent is BoneContent )
{
convertedBone . Parent = ConvertBone ( ( BoneContent ) bone . Parent , convertedDict ) ;
}
BoneContent [ ] boneChilds = bone . Children . OfType < BoneContent > ( ) . ToArray ( ) ;
ConvertBones ( boneChilds , convertedDict ) ;
foreach ( var child in boneChilds )
{
var convertedChild = convertedDict [ child ] ;
convertedBone . Children . Add ( convertedChild ) ;
}
}
}
2012-08-17 14:16:58 +00:00
}
2015-04-08 14:50:03 +02:00
private ModelBoneContent ConvertBone ( BoneContent bone , Dictionary < NodeContent , ModelBoneContent > convertedDict )
{
ModelBoneContent result ;
if ( ! convertedDict . TryGetValue ( bone , out result ) )
{
result = new ModelBoneContent ( )
{
Name = bone . Name ,
Transform = bone . Transform
} ;
//TODO: check on duplicates
//TODO: handle animations
convertedDict . Add ( bone , result ) ;
}
return result ;
}
/// <summary>
/// Called by the framework when the MaterialContent property of a GeometryContent object is encountered in the input node collection.
/// </summary>
/// <param name="material">The input material content.</param>
/// <param name="context">Context for the specified processor.</param>
/// <returns>The converted material content.</returns>
2012-08-17 14:16:58 +00:00
protected virtual MaterialContent ConvertMaterial ( MaterialContent material , ContentProcessorContext context )
{
2015-04-08 14:50:03 +02:00
OpaqueDataDictionary opaqueDataDictionary = new OpaqueDataDictionary ( ) ;
opaqueDataDictionary [ "ColorKeyColor" ] = this . ColorKeyColor ;
opaqueDataDictionary [ "ColorKeyEnabled" ] = this . ColorKeyEnabled ;
opaqueDataDictionary [ "DefaultEffect" ] = this . DefaultEffect ;
opaqueDataDictionary [ "GenerateMipmaps" ] = this . GenerateMipmaps ;
opaqueDataDictionary [ "PremultiplyTextureAlpha" ] = this . PremultiplyTextureAlpha ;
opaqueDataDictionary [ "ResizeTexturesToPowerOfTwo" ] = this . ResizeTexturesToPowerOfTwo ;
opaqueDataDictionary [ "TextureFormat" ] = this . TextureFormat ;
return context . Convert < MaterialContent , MaterialContent > ( material , typeof ( MaterialProcessor ) . Name , opaqueDataDictionary ) ;
}
/// <summary>
/// Maps the geometries in the meshes to their materials and calls <see cref="ProcessGeometryUsingMaterial"/> with it.
/// </summary>
/// <param name="meshes"></param>
/// <param name="context"></param>
private void ProcessGeometryUsingMaterials ( IEnumerable < MeshContent > meshes , ContentProcessorContext context )
{
Dictionary < MaterialContent , List < GeometryContent > > materialGeometryAssoc = new Dictionary < MaterialContent , List < GeometryContent > > ( ) ;
//We can't add null as key to a dictionary so we must have a seperate list where all the geometries without materials go.
List < GeometryContent > materiallessGeometries = new List < GeometryContent > ( ) ;
foreach ( var mesh in meshes )
{
foreach ( var geometry in mesh . Geometry )
{
MaterialContent material = geometry . Material ;
if ( material ! = null )
{
List < GeometryContent > materialGeometries ;
if ( ! materialGeometryAssoc . TryGetValue ( material , out materialGeometries ) )
{
materialGeometries = new List < GeometryContent > ( ) ;
materialGeometryAssoc . Add ( material , materialGeometries ) ;
}
materialGeometries . Add ( geometry ) ;
}
else
{
materiallessGeometries . Add ( geometry ) ;
}
}
}
foreach ( var pair in materialGeometryAssoc )
{
this . ProcessGeometryUsingMaterial ( pair . Key , pair . Value , context ) ;
}
if ( materiallessGeometries . Count > 0 )
{
this . ProcessGeometryUsingMaterial ( null , materiallessGeometries , context ) ;
}
2012-08-17 14:16:58 +00:00
}
2015-04-08 14:50:03 +02:00
/// <summary>
/// Processes all geometry using a specified material.
/// </summary>
/// <param name="material"></param>
/// <param name="geometryContent">A collection of all the geometry using the specified material.</param>
/// <param name="context"></param>
2012-08-17 14:16:58 +00:00
protected virtual void ProcessGeometryUsingMaterial ( MaterialContent material , IEnumerable < GeometryContent > geometryContent , ContentProcessorContext context )
2015-04-08 14:50:03 +02:00
{
if ( material = = null )
{
material = new BasicMaterialContent ( ) ;
foreach ( var geometry in geometryContent )
{
geometry . Material = material ;
}
}
MaterialProcessorDefaultEffect ? materialProcessorDefaultEffect = null ;
if ( material is BasicMaterialContent )
{
materialProcessorDefaultEffect = this . DefaultEffect ;
}
else if ( material is SkinnedMaterialContent )
{
materialProcessorDefaultEffect = MaterialProcessorDefaultEffect . SkinnedEffect ;
}
else if ( material is EnvironmentMapMaterialContent )
{
materialProcessorDefaultEffect = MaterialProcessorDefaultEffect . EnvironmentMapEffect ;
}
else if ( material is DualTextureMaterialContent )
{
materialProcessorDefaultEffect = MaterialProcessorDefaultEffect . DualTextureEffect ;
}
else if ( material is AlphaTestMaterialContent )
{
materialProcessorDefaultEffect = MaterialProcessorDefaultEffect . AlphaTestEffect ;
}
if ( materialProcessorDefaultEffect . HasValue )
{
bool vertexColorEnabled = false ;
int blendChannelCount = 0 ;
int textureChannelCount = 0 ;
switch ( materialProcessorDefaultEffect . Value )
{
case MaterialProcessorDefaultEffect . SkinnedEffect :
textureChannelCount = 1 ;
blendChannelCount = 1 ;
break ;
case MaterialProcessorDefaultEffect . EnvironmentMapEffect :
textureChannelCount = 1 ;
break ;
case MaterialProcessorDefaultEffect . DualTextureEffect :
textureChannelCount = 2 ;
vertexColorEnabled = true ;
break ;
case MaterialProcessorDefaultEffect . AlphaTestEffect :
textureChannelCount = 1 ;
vertexColorEnabled = true ;
break ;
default :
textureChannelCount = material . Textures . ContainsKey ( "Texture" ) ? 1 : 0 ;
vertexColorEnabled = true ;
break ;
}
foreach ( var geometry in geometryContent )
{
ValidateTextureChannelsExist ( geometry , textureChannelCount ) ;
ValidateWeightsChannelsExist ( geometry , blendChannelCount ) ;
}
if ( vertexColorEnabled )
{
//SetVertexColorEnabled(material, geometryContent);
}
}
}
private void SetVertexColorEnabled ( MaterialContent material , IEnumerable < GeometryContent > geometryContent )
2012-08-17 14:16:58 +00:00
{
throw new NotImplementedException ( ) ;
}
2015-04-08 14:50:03 +02:00
/// <summary>
/// Checks if the wanted number of texture channels exist within the geometry and if not an <see cref="InvalidContentException"/> gets thrown.
/// </summary>
/// <param name="geometry"></param>
/// <param name="channelCount"></param>
/// <exception cref="System.ArgumentNullException"></exception>
/// <exception cref="System.InvalidContentException"></exception>
protected void ValidateTextureChannelsExist ( GeometryContent geometry , int channelCount )
{
if ( geometry = = null )
throw new ArgumentNullException ( "geometry" ) ;
var channels = geometry . Vertices . Channels ;
for ( int i = 0 ; i < channelCount ; i + + )
{
if ( ! channels . Contains ( VertexChannelNames . TextureCoordinate ( i ) ) )
{
throw new InvalidContentException ( string . Format ( "The mesh \"{0}\", contains geometry that is missing texture coordinates for channel {1}." , geometry . Parent . Name , i ) , geometry . Identity ) ;
}
}
}
/// <summary>
/// Checks if the wanted number of blend index and blend weight channels exist within the geometry and if not an <see cref="InvalidContentException"/> gets thrown.
/// </summary>
/// <param name="geometry"></param>
/// <param name="channelCount"></param>
/// <exception cref="System.ArgumentNullException"></exception>
/// <exception cref="System.InvalidContentException"></exception>
protected void ValidateWeightsChannelsExist ( GeometryContent geometry , int channelCount )
{
if ( geometry = = null )
throw new ArgumentNullException ( "geometry" ) ;
var channels = geometry . Vertices . Channels ;
for ( int i = 0 ; i < channelCount ; i + + )
{
if ( ! channels . Contains ( VertexChannelNames . EncodeName ( VertexElementUsage . BlendIndices , i ) ) |
! channels . Contains ( VertexChannelNames . EncodeName ( VertexElementUsage . BlendWeight , i ) ) )
{
throw new InvalidContentException ( string . Format ( "The mesh \"{0}\", contains geometry that is missing vertex weights for channel {1}." , geometry . Parent . Name , i ) , geometry . Identity ) ;
}
}
}
private void ProcessVertexChannels ( MeshContent mesh , ContentProcessorContext context )
{
foreach ( var geometry in mesh . Geometry )
{
VertexChannelCollection channels = geometry . Vertices . Channels ;
for ( int i = 0 ; i < channels . Count ; i + + )
{
this . ProcessVertexChannel ( geometry , i , context ) ;
}
}
}
/// <summary>
/// Processes geometry content vertex channels at the specified index.
/// </summary>
/// <remarks>
/// This function will be called for each VertexChannel of Vertices found in the input mesh.
/// Subclasses of ModelProcessor can override ProcessVertexChannel to control how vertex data is processed.
/// The default implementation converts VertexElementUsage.Color channels to Color format, and replaces Weights channels with a
/// pair of VertexElementUsage.BlendIndices and VertexElementUsage.BlendIndices channels (using Byte4 format for the
/// VertexElementUsage.BlendWeight, Color for the VertexElementUsage.BlendWeight, and discarding excess weights if there are more
/// than four per vertex).
/// </remarks>
/// <param name="geometry"></param>
/// <param name="vertexChannelIndex"></param>
/// <param name="context"></param>
2012-08-17 14:16:58 +00:00
protected virtual void ProcessVertexChannel ( GeometryContent geometry , int vertexChannelIndex , ContentProcessorContext context )
{
2015-04-08 14:50:03 +02:00
switch ( VertexChannelNames . DecodeBaseName ( geometry . Vertices . Channels [ vertexChannelIndex ] . Name ) )
{
case "Color" :
this . ProcessColorChannel ( geometry , vertexChannelIndex , context ) ;
break ;
case "Weights" :
this . ProcessWeightsChannel ( geometry , vertexChannelIndex , context ) ;
break ;
}
}
/// <summary>
/// Processes the channel inside the geometry as a color channel.
/// <remarks>Gets called from <see cref="ProcessVertexChannel"/>.</remarks>
/// </summary>
/// <param name="geometry"></param>
/// <param name="vertexChannelIndex"></param>
/// <param name="context"></param>
/// <exception cref="System.ArgumentNullException"></exception>
/// <exception cref="System.InvalidContentException"></exception>
protected virtual void ProcessColorChannel ( GeometryContent geometry , int vertexChannelIndex , ContentProcessorContext context )
{
if ( geometry = = null )
throw new ArgumentNullException ( "geometry" ) ;
VertexChannelCollection channels = geometry . Vertices . Channels ;
try
{
channels . ConvertChannelContent < Color > ( vertexChannelIndex ) ;
}
catch ( Exception exc )
{
throw new InvalidContentException ( string . Format ( "Can't convert vertex channel \"{0}\" to element type {0} for color channel." , channels [ vertexChannelIndex ] . Name , typeof ( Color ) ) , exc ) ;
}
if ( this . PremultiplyVertexColors )
{
VertexChannel < Color > vertexChannel = channels . Get < Color > ( vertexChannelIndex ) ;
for ( int i = 0 ; i < vertexChannel . Count ; i + + )
{
Color color = vertexChannel [ i ] ;
vertexChannel [ i ] = Color . FromNonPremultiplied ( color . R , color . G , color . B , color . A ) ;
}
}
}
/// <summary>
/// Processes the channel inside the geometry as a weights channel.
/// <remarks>Gets called from <see cref="ProcessVertexChannel"/>.</remarks>
/// </summary>
/// <param name="geometry"></param>
/// <param name="vertexChannelIndex"></param>
/// <param name="context"></param>
/// <exception cref="System.ArgumentNullException"></exception>
/// <exception cref="System.InvalidContentException"></exception>
protected virtual void ProcessWeightsChannel ( GeometryContent geometry , int vertexChannelIndex , ContentProcessorContext context )
{
if ( geometry = = null )
throw new ArgumentNullException ( "geometry" ) ;
2012-08-17 14:16:58 +00:00
throw new NotImplementedException ( ) ;
2015-04-08 14:50:03 +02:00
//TODO: implement
/ * VertexChannelCollection channels = geometry . Vertices . Channels ;
VertexChannel vertexChannel = channels [ vertexChannelIndex ] ;
if ( ! ( vertexChannel is VertexChannel < BoneWeightCollection > ) )
{
throw new InvalidContentException ( string . Format ( "Expected vertex channel \"{0}\" to contain BoneWeightCollection, but found {1}." , vertexChannel . Name , vertexChannel . ElementType ) ) ;
}
VertexChannel < BoneWeightCollection > boneWeightsChannel = vertexChannel as VertexChannel < BoneWeightCollection > ;
Byte4 [ ] indices = new Byte4 [ boneWeightsChannel . Count ] ;
Vector4 [ ] weights = new Vector4 [ boneWeightsChannel . Count ] ;
for ( int i = 0 ; i < boneWeightsChannel . Count ; i + + )
{
BoneWeightCollection boneWeightCollection = boneWeightsChannel [ i ] ;
if ( boneWeightCollection = = null )
{
throw new InvalidContentException ( string . Format ( CultureInfo . CurrentCulture , Resources . NullVertexChannelEntry , new object [ ]
{
boneWeightsChannel . Name ,
typeof ( BoneWeightCollection ) . Name
} ) ) ;
}
ModelProcessor . ConvertVertexWeights ( boneWeightCollection , indices , weights , i , geometry ) ;
}
int usageIndex = VertexChannelNames . DecodeUsageIndex ( boneWeightsChannel . Name ) ;
string blendIndicesText = VertexChannelNames . EncodeName ( VertexElementUsage . BlendIndices , usageIndex ) ;
string blendWeightsText = VertexChannelNames . EncodeName ( VertexElementUsage . BlendWeight , usageIndex ) ;
if ( channels . Contains ( blendIndicesText ) )
{
throw new InvalidContentException ( string . Format ( CultureInfo . CurrentCulture , Resources . ConvertWeightsOutputAlreadyExists , new object [ ]
{
boneWeightsChannel . Name ,
blendIndicesText
} ) ) ;
}
if ( channels . Contains ( blendWeightsText ) )
{
throw new InvalidContentException ( string . Format ( CultureInfo . CurrentCulture , Resources . ConvertWeightsOutputAlreadyExists , new object [ ]
{
boneWeightsChannel . Name ,
blendWeightsText
} ) ) ;
}
channels . Insert < Byte4 > ( vertexChannelIndex + 1 , blendIndicesText , indices ) ;
channels . Insert < Vector4 > ( vertexChannelIndex + 2 , blendWeightsText , weights ) ;
channels . RemoveAt ( vertexChannelIndex ) ; * /
2012-08-17 14:16:58 +00:00
}
2015-04-08 14:50:03 +02:00
/ * private static void ConvertVertexWeights ( BoneWeightCollection inputWeights , Byte4 [ ] outputIndices , Vector4 [ ] outputWeights , int vertexIndex , GeometryContent geometry )
{
inputWeights . NormalizeWeights ( SkinnedEffect . MaxBonesPerVertex ) ;
for ( int i = 0 ; i < inputWeights . Count ; i + + )
{
BoneWeight boneWeight = inputWeights [ i ] ;
if ( ! boneIndices . TryGetValue ( boneWeight . BoneName , out ModelProcessor . tempIndices [ i ] ) )
{
throw new InvalidContentException ( string . Format ( CultureInfo . CurrentCulture , Resources . VertexHasUnknownBoneName , new object [ ]
{
boneWeight . BoneName
} ) , geometry . Parent . Identity ) ;
}
ModelProcessor . tempWeights [ i ] = boneWeight . Weight ;
}
for ( int j = inputWeights . Count ; j < 4 ; j + + )
{
ModelProcessor . tempIndices [ j ] = 0 ;
ModelProcessor . tempWeights [ j ] = 0f ;
}
outputIndices [ vertexIndex ] = new Byte4 ( ( float ) ModelProcessor . tempIndices [ 0 ] , ( float ) ModelProcessor . tempIndices [ 1 ] , ( float ) ModelProcessor . tempIndices [ 2 ] , ( float ) ModelProcessor . tempIndices [ 3 ] ) ;
outputWeights [ vertexIndex ] = new Vector4 ( ModelProcessor . tempWeights [ 0 ] , ModelProcessor . tempWeights [ 1 ] , ModelProcessor . tempWeights [ 2 ] , ModelProcessor . tempWeights [ 3 ] ) ;
} * /
2012-08-17 14:16:58 +00:00
}
}