3 * Copyright (c) 2007-2010 SlimDX Group
\r
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
\r
6 * of this software and associated documentation files (the "Software"), to deal
\r
7 * in the Software without restriction, including without limitation the rights
\r
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
\r
9 * copies of the Software, and to permit persons to whom the Software is
\r
10 * furnished to do so, subject to the following conditions:
\r
12 * The above copyright notice and this permission notice shall be included in
\r
13 * all copies or substantial portions of the Software.
\r
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
\r
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
\r
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
\r
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
\r
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
\r
27 #include "../stack_array.h"
\r
28 #include "../DataStream.h"
\r
29 #include "../ComObject.h"
\r
32 #include "IndexBuffer.h"
\r
34 #include "SkinInfo.h"
\r
36 #include "Direct3D9Exception.h"
\r
38 using namespace System;
\r
44 SkinInfo::SkinInfo( int vertexCount, array<VertexElement>^ vertexDeclaration, int boneCount )
\r
46 ID3DXSkinInfo *result;
\r
48 pin_ptr<VertexElement> pinnedDecl = &vertexDeclaration[0];
\r
50 HRESULT hr = D3DXCreateSkinInfo( vertexCount, reinterpret_cast<const D3DVERTEXELEMENT9*>( pinnedDecl ),
\r
51 boneCount, &result );
\r
53 if( RECORD_D3D9( hr ).IsFailure )
\r
54 throw gcnew Direct3D9Exception( Result::Last );
\r
56 Construct( result );
\r
59 SkinInfo::SkinInfo( BaseMesh^ mesh, int boneCount, array<BoneCombination^>^ boneCombinationTable )
\r
61 ID3DXSkinInfo *result;
\r
63 int length = boneCombinationTable->Length;
\r
64 stack_array<D3DXBONECOMBINATION> bones = stackalloc( D3DXBONECOMBINATION, length );
\r
65 for( int i = 0; i < length; i++ )
\r
66 bones[i] = boneCombinationTable[i]->ToUnmanaged();
\r
68 HRESULT hr = D3DXCreateSkinInfoFromBlendedMesh( mesh->InternalPointer, boneCount, &bones[0], &result );
\r
70 for( int i = 0; i < length; i++ )
\r
71 delete[] bones[i].BoneId;
\r
73 if( RECORD_D3D9( hr ).IsFailure )
\r
74 throw gcnew Direct3D9Exception( Result::Last );
\r
76 Construct( result );
\r
79 SkinInfo::SkinInfo( int vertexCount, SlimDX::Direct3D9::VertexFormat fvf, int boneCount )
\r
81 ID3DXSkinInfo *result;
\r
83 HRESULT hr = D3DXCreateSkinInfoFVF( vertexCount, static_cast<DWORD>( fvf ),
\r
84 boneCount, &result );
\r
86 if( RECORD_D3D9( hr ).IsFailure )
\r
87 throw gcnew Direct3D9Exception( Result::Last );
\r
89 Construct( result );
\r
92 SkinInfo^ SkinInfo::Clone()
\r
94 ID3DXSkinInfo *result;
\r
96 HRESULT hr = InternalPointer->Clone( &result );
\r
98 if( RECORD_D3D9( hr ).IsFailure )
\r
101 return gcnew SkinInfo( result, nullptr );
\r
104 Mesh^ SkinInfo::ConvertToBlendedMesh( Mesh^ mesh, array<int>^ adjacency,
\r
105 [Out] array<int>^% faceRemap, [Out] array<int>^% vertexRemap, [Out] int% maxVertexInfluence,
\r
106 [Out] array<BoneCombination^>^% boneCombinationTable )
\r
113 DWORD *adjacencyIn = NULL;
\r
115 faceRemap = gcnew array<int>( mesh->FaceCount );
\r
117 array<int>^ adjacencyOut = gcnew array<int>( mesh->FaceCount * 3 );
\r
119 pin_ptr<int> pinnedAdjIn;
\r
120 pin_ptr<int> pinnedAdjOut = &adjacencyOut[0];
\r
121 pin_ptr<int> pinnedFR = &faceRemap[0];
\r
123 if( adjacency != nullptr )
\r
125 pinnedAdjIn = &adjacency[0];
\r
126 adjacencyIn = reinterpret_cast<DWORD*>( pinnedAdjIn );
\r
129 HRESULT hr = InternalPointer->ConvertToBlendedMesh( mesh->InternalPointer, 0, adjacencyIn,
\r
130 reinterpret_cast<DWORD*>( pinnedAdjOut ), reinterpret_cast<DWORD*>( pinnedFR ), &vr, &mvi, &bcc, &bct, &result );
\r
132 if( RECORD_D3D9( hr ).IsFailure )
\r
134 boneCombinationTable = nullptr;
\r
135 maxVertexInfluence = 0;
\r
136 vertexRemap = nullptr;
\r
137 faceRemap = nullptr;
\r
141 boneCombinationTable = gcnew array<BoneCombination^>( bcc );
\r
142 LPD3DXBONECOMBINATION pointer = reinterpret_cast<LPD3DXBONECOMBINATION>( bct->GetBufferPointer() );
\r
144 for( DWORD i = 0; i < bcc; i++ )
\r
146 boneCombinationTable[i] = BoneCombination::FromUnmanaged( pointer[i] );
\r
147 boneCombinationTable[i]->BoneIds = gcnew array<int>( mvi );
\r
148 for( DWORD j = 0; j < mvi; j++ )
\r
149 boneCombinationTable[i]->BoneIds[j] = pointer[i].BoneId[j];
\r
152 Mesh^ out = Mesh::FromPointer( result );
\r
153 if( adjacency != nullptr )
\r
154 out->SetAdjacency( adjacencyOut );
\r
156 out->SetAdjacency( NULL );
\r
158 maxVertexInfluence = mvi;
\r
159 vertexRemap = Utilities::ReadRange<int>( vr, result->GetNumVertices() );
\r
163 Mesh^ SkinInfo::ConvertToBlendedMesh( Mesh^ mesh, array<int>^ adjacency,
\r
164 [Out] int% maxVertexInfluence, [Out] array<BoneCombination^>^% boneCombinationTable )
\r
170 DWORD *adjacencyIn = NULL;
\r
172 array<int>^ adjacencyOut = gcnew array<int>( mesh->FaceCount * 3 );
\r
174 pin_ptr<int> pinnedAdjIn;
\r
175 pin_ptr<int> pinnedAdjOut = &adjacencyOut[0];
\r
177 if( adjacency != nullptr )
\r
179 pinnedAdjIn = &adjacency[0];
\r
180 adjacencyIn = reinterpret_cast<DWORD*>( pinnedAdjIn );
\r
183 HRESULT hr = InternalPointer->ConvertToBlendedMesh( mesh->InternalPointer, 0, adjacencyIn,
\r
184 reinterpret_cast<DWORD*>( pinnedAdjOut ), NULL, NULL, &mvi, &bcc, &bct, &result );
\r
186 if( RECORD_D3D9( hr ).IsFailure )
\r
188 boneCombinationTable = nullptr;
\r
189 maxVertexInfluence = 0;
\r
193 boneCombinationTable = gcnew array<BoneCombination^>( bcc );
\r
194 LPD3DXBONECOMBINATION pointer = reinterpret_cast<LPD3DXBONECOMBINATION>( bct->GetBufferPointer() );
\r
196 for( DWORD i = 0; i < bcc; i++ )
\r
198 boneCombinationTable[i] = BoneCombination::FromUnmanaged( pointer[i] );
\r
199 boneCombinationTable[i]->BoneIds = gcnew array<int>( mvi );
\r
200 for( DWORD j = 0; j < mvi; j++ )
\r
201 boneCombinationTable[i]->BoneIds[j] = pointer[i].BoneId[j];
\r
204 Mesh^ out = Mesh::FromPointer( result );
\r
205 if( adjacency != nullptr )
\r
206 out->SetAdjacency( adjacencyOut );
\r
208 out->SetAdjacency( NULL );
\r
210 maxVertexInfluence = mvi;
\r
214 Mesh^ SkinInfo::ConvertToIndexedBlendedMesh( Mesh^ mesh, int paletteSize, array<int>^ adjacency,
\r
215 [Out] array<int>^% faceRemap, [Out] array<int>^% vertexRemap, [Out] int% maxVertexInfluence,
\r
216 [Out] array<BoneCombination^>^% boneCombinationTable )
\r
223 DWORD *adjacencyIn = NULL;
\r
225 faceRemap = gcnew array<int>( mesh->FaceCount );
\r
227 array<int>^ adjacencyOut = gcnew array<int>( mesh->FaceCount * 3 );
\r
229 pin_ptr<int> pinnedAdjIn;
\r
230 pin_ptr<int> pinnedAdjOut = &adjacencyOut[0];
\r
232 if( adjacency != nullptr )
\r
234 pinnedAdjIn = &adjacency[0];
\r
235 adjacencyIn = reinterpret_cast<DWORD*>( pinnedAdjIn );
\r
238 pin_ptr<int> pinnedFR = &faceRemap[0];
\r
240 HRESULT hr = InternalPointer->ConvertToIndexedBlendedMesh( mesh->InternalPointer, 0, paletteSize, adjacencyIn,
\r
241 reinterpret_cast<DWORD*>( pinnedAdjOut ), reinterpret_cast<DWORD*>( pinnedFR ), &vr, &mvi, &bcc, &bct, &result );
\r
243 if( RECORD_D3D9( hr ).IsFailure )
\r
245 boneCombinationTable = nullptr;
\r
246 maxVertexInfluence = 0;
\r
247 vertexRemap = nullptr;
\r
248 faceRemap = nullptr;
\r
252 boneCombinationTable = gcnew array<BoneCombination^>( bcc );
\r
253 LPD3DXBONECOMBINATION pointer = reinterpret_cast<LPD3DXBONECOMBINATION>( bct->GetBufferPointer() );
\r
255 for( DWORD i = 0; i < bcc; i++ )
\r
257 boneCombinationTable[i] = BoneCombination::FromUnmanaged( pointer[i] );
\r
258 boneCombinationTable[i]->BoneIds = gcnew array<int>( paletteSize );
\r
259 for( int j = 0; j < paletteSize; j++ )
\r
260 boneCombinationTable[i]->BoneIds[j] = pointer[i].BoneId[j];
\r
263 Mesh^ out = Mesh::FromPointer( result );
\r
264 if( adjacency != nullptr )
\r
265 out->SetAdjacency( adjacencyOut );
\r
267 out->SetAdjacency( NULL );
\r
269 maxVertexInfluence = mvi;
\r
270 vertexRemap = Utilities::ReadRange<int>( vr, result->GetNumVertices() );
\r
274 Mesh^ SkinInfo::ConvertToIndexedBlendedMesh( Mesh^ mesh, int paletteSize, array<int>^ adjacency,
\r
275 [Out] int% maxVertexInfluence, [Out] array<BoneCombination^>^% boneCombinationTable )
\r
281 DWORD *adjacencyIn = NULL;
\r
283 array<int>^ adjacencyOut = gcnew array<int>( mesh->FaceCount * 3 );
\r
285 pin_ptr<int> pinnedAdjIn;
\r
286 pin_ptr<int> pinnedAdjOut = &adjacencyOut[0];
\r
288 if( adjacency != nullptr )
\r
290 pinnedAdjIn = &adjacency[0];
\r
291 adjacencyIn = reinterpret_cast<DWORD*>( pinnedAdjIn );
\r
294 HRESULT hr = InternalPointer->ConvertToIndexedBlendedMesh( mesh->InternalPointer, 0, paletteSize, adjacencyIn,
\r
295 reinterpret_cast<DWORD*>( pinnedAdjOut ), NULL, NULL, &mvi, &bcc, &bct, &result );
\r
297 if( RECORD_D3D9( hr ).IsFailure )
\r
299 boneCombinationTable = nullptr;
\r
300 maxVertexInfluence = 0;
\r
304 boneCombinationTable = gcnew array<BoneCombination^>( bcc );
\r
305 LPD3DXBONECOMBINATION pointer = reinterpret_cast<LPD3DXBONECOMBINATION>( bct->GetBufferPointer() );
\r
307 for( DWORD i = 0; i < bcc; i++ )
\r
309 boneCombinationTable[i] = BoneCombination::FromUnmanaged( pointer[i] );
\r
310 boneCombinationTable[i]->BoneIds = gcnew array<int>( paletteSize );
\r
311 for( int j = 0; j < paletteSize; j++ )
\r
312 boneCombinationTable[i]->BoneIds[j] = pointer[i].BoneId[j];
\r
315 Mesh^ out = Mesh::FromPointer( result );
\r
316 if( adjacency != nullptr )
\r
317 out->SetAdjacency( adjacencyOut );
\r
319 out->SetAdjacency( NULL );
\r
321 maxVertexInfluence = mvi;
\r
325 int SkinInfo::FindBoneVertexInfluenceIndex( int bone, int vertex )
\r
329 HRESULT hr = InternalPointer->FindBoneVertexInfluenceIndex( bone, vertex, &influence );
\r
331 if( RECORD_D3D9( hr ).IsFailure )
\r
337 Result SkinInfo::GetBoneInfluence( int bone, [Out] array<int>^% vertices, [Out] array<float>^% weights )
\r
339 int count = GetBoneInfluenceCount( bone );
\r
340 vertices = gcnew array<int>( count );
\r
341 weights = gcnew array<float>( count );
\r
343 pin_ptr<int> pinnedVerts = &vertices[0];
\r
344 pin_ptr<float> pinnedWeights = &weights[0];
\r
346 HRESULT hr = InternalPointer->GetBoneInfluence( bone, reinterpret_cast<DWORD*>( pinnedVerts ),
\r
347 reinterpret_cast<float*>( pinnedWeights ) );
\r
349 if( RECORD_D3D9( hr ).IsFailure )
\r
351 vertices = nullptr;
\r
355 return Result::Last;
\r
358 Result SkinInfo::SetBoneInfluence( int bone, array<int>^ vertices, array<float>^ weights )
\r
360 pin_ptr<int> pinnedVerts = &vertices[0];
\r
361 pin_ptr<float> pinnedWeights = &weights[0];
\r
363 HRESULT hr = InternalPointer->SetBoneInfluence( bone, vertices->Length, reinterpret_cast<const DWORD*>( pinnedVerts ),
\r
364 reinterpret_cast<const float*>( pinnedWeights ) );
\r
366 return RECORD_D3D9( hr );
\r
369 String^ SkinInfo::GetBoneName( int bone )
\r
371 return gcnew String( InternalPointer->GetBoneName( bone ) );
\r
374 Result SkinInfo::SetBoneName( int bone, String^ name )
\r
376 array<unsigned char>^ nameBytes = System::Text::ASCIIEncoding::ASCII->GetBytes( name );
\r
377 pin_ptr<unsigned char> pinnedName = &nameBytes[0];
\r
379 HRESULT hr = InternalPointer->SetBoneName( bone, reinterpret_cast<LPCSTR>( pinnedName ) );
\r
380 return RECORD_D3D9( hr );
\r
383 Result SkinInfo::GetBoneVertexInfluence( int bone, int influence, [Out] float% weight, [Out] int% vertex )
\r
388 HRESULT hr = InternalPointer->GetBoneVertexInfluence( bone, influence, &w, &v );
\r
390 if( RECORD_D3D9( hr ).IsFailure )
\r
401 return Result::Last;
\r
404 Result SkinInfo::SetBoneVertexInfluence( int bone, int influence, float weight )
\r
406 HRESULT hr = InternalPointer->SetBoneVertexInfluence( bone, influence, weight );
\r
407 return RECORD_D3D9( hr );
\r
410 Matrix SkinInfo::GetBoneOffsetMatrix( int bone )
\r
412 return Matrix::FromD3DXMATRIX( *InternalPointer->GetBoneOffsetMatrix( bone ) );
\r
415 Result SkinInfo::SetBoneOffsetMatrix( int bone, Matrix matrix )
\r
417 HRESULT hr = InternalPointer->SetBoneOffsetMatrix( bone, reinterpret_cast<D3DXMATRIX*>( &matrix ) );
\r
418 return RECORD_D3D9( hr );
\r
421 array<VertexElement>^ SkinInfo::GetDeclaration()
\r
423 D3DVERTEXELEMENT9 elementBuffer[MAX_FVF_DECL_SIZE];
\r
424 HRESULT hr = InternalPointer->GetDeclaration( elementBuffer );
\r
426 if( RECORD_D3D9( hr ).IsFailure )
\r
429 // Apparently the returned decl does not include an End element. This is bizarre and confusing,
\r
430 // not to mention completely unexpected. We patch it up here.
\r
431 int count = D3DXGetDeclLength( elementBuffer ) + 1;
\r
432 array<VertexElement>^ elements = gcnew array<VertexElement>( count );
\r
433 pin_ptr<VertexElement> pinnedElements = &elements[0];
\r
434 memcpy( pinnedElements, elementBuffer, count * sizeof(D3DVERTEXELEMENT9) );
\r
435 elements[count - 1] = VertexElement::VertexDeclarationEnd;
\r
440 Result SkinInfo::SetDeclaration( array<VertexElement>^ declaration )
\r
442 pin_ptr<VertexElement> pinnedDecl = &declaration[0];
\r
444 HRESULT hr = InternalPointer->SetDeclaration( reinterpret_cast<D3DVERTEXELEMENT9*>( pinnedDecl ) );
\r
445 return RECORD_D3D9( hr );
\r
448 int SkinInfo::GetMaxFaceInfluences( IndexBuffer^ indexBuffer, int faceCount )
\r
452 HRESULT hr = InternalPointer->GetMaxFaceInfluences( indexBuffer->InternalPointer, faceCount, &ret );
\r
454 if( RECORD_D3D9( hr ).IsFailure )
\r
460 Result SkinInfo::Remap( array<int>^ remapData )
\r
462 pin_ptr<int> pinnedData = &remapData[0];
\r
464 HRESULT hr = InternalPointer->Remap( remapData->Length, reinterpret_cast<DWORD*>( pinnedData ) );
\r
465 return RECORD_D3D9( hr );
\r
468 Result SkinInfo::UpdateSkinnedMesh( array<Matrix>^ boneTransforms, array<Matrix>^ boneInvTransposeTransforms, DataStream^ source, DataStream^ destination )
\r
470 pin_ptr<Matrix> pinnedTransforms = &boneTransforms[0];
\r
471 pin_ptr<Matrix> pinnedInvTransforms = &boneInvTransposeTransforms[0];
\r
473 HRESULT hr = InternalPointer->UpdateSkinnedMesh( reinterpret_cast<const D3DXMATRIX*>( pinnedTransforms ),
\r
474 reinterpret_cast<const D3DXMATRIX*>( pinnedInvTransforms ), source->PositionPointer, destination->PositionPointer );
\r
475 return RECORD_D3D9( hr );
\r
478 int SkinInfo::GetBoneInfluenceCount( int bone )
\r
480 return InternalPointer->GetNumBoneInfluences( bone );
\r
483 int SkinInfo::MaximumVertexInfluences::get()
\r
487 HRESULT hr = InternalPointer->GetMaxVertexInfluences( &result );
\r
489 if( RECORD_D3D9( hr ).IsFailure )
\r
495 int SkinInfo::BoneCount::get()
\r
497 return InternalPointer->GetNumBones();
\r
500 float SkinInfo::MinimumBoneInfluence::get()
\r
502 return InternalPointer->GetMinBoneInfluence();
\r
505 void SkinInfo::MinimumBoneInfluence::set( float value )
\r
507 HRESULT hr = InternalPointer->SetMinBoneInfluence( value );
\r
511 SlimDX::Direct3D9::VertexFormat SkinInfo::VertexFormat::get()
\r
513 return static_cast<SlimDX::Direct3D9::VertexFormat>( InternalPointer->GetFVF() );
\r
516 void SkinInfo::VertexFormat::set( SlimDX::Direct3D9::VertexFormat value )
\r
518 HRESULT hr = InternalPointer->SetFVF( static_cast<DWORD>( value ) );
\r