2011-08-17 21:50:33 +00:00
/*
* OpenClonk , http : //www.openclonk.org
*
2013-12-17 20:01:09 +00:00
* Copyright ( c ) 2009 - 2013 , The OpenClonk Team and contributors
2011-08-17 21:50:33 +00:00
*
2013-12-17 20:01:09 +00:00
* Distributed under the terms of the ISC license ; see accompanying file
* " COPYING " for details .
2011-08-17 21:50:33 +00:00
*
2013-12-17 20:01:09 +00:00
* " Clonk " is a registered trademark of Matthes Bender , used with permission .
* See accompanying file " TRADEMARK " for details .
2011-08-17 21:50:33 +00:00
*
2013-12-17 20:01:09 +00:00
* To redistribute this file separately , substitute the full license texts
* for the above references .
2011-08-17 21:50:33 +00:00
*/
# include "C4Include.h"
# include <StdMesh.h>
# include <StdMeshMaterial.h>
# include <StdMeshUpdate.h>
2014-12-26 12:46:14 +00:00
# include <StdMeshLoader.h>
2011-08-17 21:50:33 +00:00
StdMeshMaterialUpdate : : StdMeshMaterialUpdate ( StdMeshMatManager & manager ) :
MaterialManager ( manager )
{
}
void StdMeshMaterialUpdate : : Update ( StdMesh * mesh ) const
{
for ( std : : vector < StdSubMesh > : : iterator iter = mesh - > SubMeshes . begin ( ) ; iter ! = mesh - > SubMeshes . end ( ) ; + + iter )
{
2014-10-21 19:12:09 +00:00
std : : map < const StdMeshMaterial * , StdMeshMaterial > : : const_iterator mat_iter = Materials . find ( iter - > Material ) ;
2011-08-17 21:50:33 +00:00
if ( mat_iter ! = Materials . end ( ) )
{
const StdMeshMaterial * new_material = MaterialManager . GetMaterial ( mat_iter - > second . Name . getData ( ) ) ;
if ( new_material )
{
iter - > Material = new_material ;
}
else
{
// If no replacement material is available, then re-insert the previous
// material into the material map. This is mainly just to keep things
// going - next time the scenario will be started the mesh will fail
// to load because the material cannot be found.
2014-10-21 19:12:09 +00:00
MaterialManager . Materials [ mat_iter - > second . Name ] = mat_iter - > second ; // TODO: could be moved
2011-08-17 21:50:33 +00:00
iter - > Material = MaterialManager . GetMaterial ( mat_iter - > second . Name . getData ( ) ) ;
}
}
}
}
void StdMeshMaterialUpdate : : Update ( StdMeshInstance * instance ) const
{
2015-03-25 18:04:04 +00:00
for ( unsigned int i = 0 ; i < instance - > SubMeshInstances . size ( ) ; + + i )
2011-08-17 21:50:33 +00:00
{
StdSubMeshInstance * sub_instance = instance - > SubMeshInstances [ i ] ;
2014-12-26 12:46:14 +00:00
std : : map < const StdMeshMaterial * , StdMeshMaterial > : : const_iterator mat_iter = Materials . find ( sub_instance - > Material ) ;
2011-08-17 21:50:33 +00:00
if ( mat_iter ! = Materials . end ( ) )
{
// Material needs to be updated
const StdMeshMaterial * new_material = MaterialManager . GetMaterial ( mat_iter - > second . Name . getData ( ) ) ;
// If new material is not available, fall back to StdMesh (definition) material
2011-08-19 22:01:08 +00:00
if ( ! new_material ) new_material = instance - > GetMesh ( ) . GetSubMesh ( i ) . Material ;
2011-08-17 21:50:33 +00:00
sub_instance - > SetMaterial ( * new_material ) ;
}
}
2011-08-19 22:01:08 +00:00
}
void StdMeshMaterialUpdate : : Cancel ( ) const
{
// Reset all materials in manager
for ( std : : map < const StdMeshMaterial * , StdMeshMaterial > : : const_iterator iter = Materials . begin ( ) ; iter ! = Materials . end ( ) ; + + iter )
2014-10-21 19:12:09 +00:00
MaterialManager . Materials [ iter - > second . Name ] = iter - > second ; // TODO: could be moved
2011-08-17 21:50:33 +00:00
}
void StdMeshMaterialUpdate : : Add ( const StdMeshMaterial * material )
{
assert ( Materials . find ( material ) = = Materials . end ( ) ) ;
2014-10-21 19:12:09 +00:00
Materials [ material ] = * material ; // TODO: could be moved
2011-08-17 21:50:33 +00:00
}
2011-08-19 22:01:08 +00:00
StdMeshUpdate : : StdMeshUpdate ( const StdMesh & old_mesh ) :
2014-11-28 05:11:42 +00:00
OldMesh ( & old_mesh ) , BoneNamesByIndex ( OldMesh - > GetSkeleton ( ) . GetNumBones ( ) )
2011-08-19 22:01:08 +00:00
{
2014-11-28 05:11:42 +00:00
for ( unsigned int i = 0 ; i < OldMesh - > GetSkeleton ( ) . GetNumBones ( ) ; + + i )
BoneNamesByIndex [ i ] = OldMesh - > GetSkeleton ( ) . GetBone ( i ) . Name ;
2011-08-19 22:01:08 +00:00
}
void StdMeshUpdate : : Update ( StdMeshInstance * instance , const StdMesh & new_mesh ) const
{
assert ( & instance - > GetMesh ( ) = = OldMesh ) ;
// Update instance to represent new mesh
instance - > Mesh = & new_mesh ;
2014-11-28 05:11:42 +00:00
instance - > BoneTransforms = std : : vector < StdMeshMatrix > ( new_mesh . GetSkeleton ( ) . GetNumBones ( ) , StdMeshMatrix : : Identity ( ) ) ;
2011-08-19 22:01:08 +00:00
instance - > BoneTransformsDirty = true ;
for ( unsigned int i = 0 ; i < instance - > SubMeshInstances . size ( ) ; + + i )
delete instance - > SubMeshInstances [ i ] ;
instance - > SubMeshInstances . resize ( new_mesh . GetNumSubMeshes ( ) ) ;
for ( unsigned int i = 0 ; i < instance - > SubMeshInstances . size ( ) ; + + i )
2015-01-04 17:29:44 +00:00
{
2012-02-26 00:09:42 +00:00
instance - > SubMeshInstances [ i ] = new StdSubMeshInstance ( * instance , new_mesh . GetSubMesh ( i ) , instance - > GetCompletion ( ) ) ;
2011-08-19 22:01:08 +00:00
2014-12-26 12:46:14 +00:00
// Submeshes are reset to their default material,
// so the submesh order is unaltered
2015-01-04 17:29:44 +00:00
instance - > SubMeshInstancesOrdered = instance - > SubMeshInstances ;
2014-12-26 12:46:14 +00:00
// TODO: We might try to restore the previous mesh material here, using global material manager, maybe iff the number of submesh instances is unchanged.
2015-01-04 17:29:44 +00:00
}
2011-08-19 22:01:08 +00:00
// Update child bone of attach parent. If the bone does not exist anymore
// in the updated mesh, then detach the mesh from its parent
if ( instance - > AttachParent )
{
2013-05-27 17:12:05 +00:00
if ( ! instance - > AttachParent - > SetChildBone ( BoneNamesByIndex [ instance - > AttachParent - > ChildBone ] ) )
2011-08-19 22:01:08 +00:00
{
bool OwnChild = instance - > AttachParent - > OwnChild ;
instance - > AttachParent - > Parent - > DetachMesh ( instance - > AttachParent - > Number ) ;
// If the attachment owned the child instance then detach procedure
// deleted the child instance. In that case we do not want to proceed
// with the mesh update procedure.
if ( OwnChild ) return ;
}
}
// Update parent bones of attach children. If a bone does not exist in the
// updated mesh then detach the mesh from its parent.
std : : vector < unsigned int > Removal ;
for ( StdMeshInstance : : AttachedMeshIter iter = instance - > AttachedMeshesBegin ( ) ; iter ! = instance - > AttachedMeshesEnd ( ) ; + + iter )
{
2013-05-27 17:12:05 +00:00
if ( ! ( * iter ) - > SetParentBone ( BoneNamesByIndex [ ( * iter ) - > ParentBone ] ) )
2011-08-19 22:01:08 +00:00
{
// Do not detach the mesh right here so we can finish iterating over
// all attached meshes first.
Removal . push_back ( ( * iter ) - > Number ) ;
}
}
for ( unsigned int i = 0 ; i < Removal . size ( ) ; + + i )
instance - > DetachMesh ( Removal [ i ] ) ;
2014-12-26 12:46:14 +00:00
// Update custom nodes in the animation tree. Leaf nodes which refer to an animation that
// does not exist anymore are removed.
for ( unsigned int i = instance - > AnimationStack . size ( ) ; i > 0 ; - - i )
if ( ! UpdateAnimationNode ( instance , instance - > AnimationStack [ i - 1 ] ) )
instance - > StopAnimation ( instance - > AnimationStack [ i - 1 ] ) ;
}
bool StdMeshUpdate : : UpdateAnimationNode ( StdMeshInstance * instance , StdMeshInstance : : AnimationNode * node ) const
{
const StdMesh & new_mesh = * instance - > Mesh ;
switch ( node - > GetType ( ) )
{
case StdMeshInstance : : AnimationNode : : LeafNode :
// Animation pointer is updated by StdMeshAnimationUpdate
return true ;
case StdMeshInstance : : AnimationNode : : CustomNode :
{
// Update bone index by bone name
StdCopyStrBuf bone_name = BoneNamesByIndex [ node - > Custom . BoneIndex ] ;
const StdMeshBone * bone = new_mesh . GetSkeleton ( ) . GetBoneByName ( bone_name ) ;
if ( ! bone ) return false ;
node - > Custom . BoneIndex = bone - > Index ;
return true ;
}
case StdMeshInstance : : AnimationNode : : LinearInterpolationNode :
{
const bool left_result = UpdateAnimationNode ( instance , node - > GetLeftChild ( ) ) ;
const bool right_result = UpdateAnimationNode ( instance , node - > GetRightChild ( ) ) ;
// Remove this node completely
if ( ! left_result & & ! right_result )
return false ;
// Note that either of this also removes this node (and replaces by
// the other child in the tree).
if ( ! left_result )
instance - > StopAnimation ( node - > GetLeftChild ( ) ) ;
if ( ! right_result )
instance - > StopAnimation ( node - > GetRightChild ( ) ) ;
return true ;
}
default :
assert ( false ) ;
return false ;
}
}
StdMeshAnimationUpdate : : StdMeshAnimationUpdate ( const StdMeshSkeletonLoader & skeleton_loader )
{
// Store all animation names of all skeletons by pointer, we need those when
// updating the animation state of mesh instances after the update.
for ( StdMeshSkeletonLoader : : skeleton_iterator iter = skeleton_loader . skeletons_begin ( ) ; iter ! = skeleton_loader . skeletons_end ( ) ; + + iter )
{
const StdMeshSkeleton & skeleton = * iter - > second ;
for ( std : : map < StdCopyStrBuf , StdMeshAnimation > : : const_iterator iter = skeleton . Animations . begin ( ) ; iter ! = skeleton . Animations . end ( ) ; + + iter )
{
AnimationNames [ & iter - > second ] = iter - > first ;
}
}
}
void StdMeshAnimationUpdate : : Update ( StdMeshInstance * instance ) const
{
2011-08-19 22:01:08 +00:00
// Update the animation tree. Leaf nodes which refer to an animation that
// does not exist anymore are removed.
for ( unsigned int i = instance - > AnimationStack . size ( ) ; i > 0 ; - - i )
2014-12-26 12:46:14 +00:00
if ( ! UpdateAnimationNode ( instance , instance - > AnimationStack [ i - 1 ] ) )
2011-08-19 22:01:08 +00:00
instance - > StopAnimation ( instance - > AnimationStack [ i - 1 ] ) ;
}
2014-12-26 12:46:14 +00:00
bool StdMeshAnimationUpdate : : UpdateAnimationNode ( StdMeshInstance * instance , StdMeshInstance : : AnimationNode * node ) const
2011-08-19 22:01:08 +00:00
{
2014-12-26 12:46:14 +00:00
const StdMesh & new_mesh = * instance - > Mesh ;
2011-08-19 22:01:08 +00:00
switch ( node - > GetType ( ) )
{
case StdMeshInstance : : AnimationNode : : LeafNode :
{
// Find dead animation
std : : map < const StdMeshAnimation * , StdCopyStrBuf > : : const_iterator iter = AnimationNames . find ( node - > Leaf . Animation ) ;
2014-12-26 12:46:14 +00:00
// If this assertion fires, it typically means that UpdateAnimations() was called twice for the same mesh instance
2011-08-19 22:01:08 +00:00
assert ( iter ! = AnimationNames . end ( ) ) ;
// Update to new animation
2014-12-16 04:42:34 +00:00
node - > Leaf . Animation = new_mesh . GetSkeleton ( ) . GetAnimationByName ( iter - > second ) ;
2011-08-19 22:01:08 +00:00
if ( ! node - > Leaf . Animation ) return false ;
// Clamp provider value
StdMeshInstance : : ValueProvider * provider = node - > GetPositionProvider ( ) ;
C4Real min = Fix0 ;
C4Real max = ftofix ( node - > GetAnimation ( ) - > Length ) ;
2015-02-12 22:05:55 +00:00
provider - > Value = Clamp ( provider - > Value , min , max ) ;
2011-08-19 22:01:08 +00:00
return true ;
}
2013-05-27 17:12:05 +00:00
case StdMeshInstance : : AnimationNode : : CustomNode :
2014-12-26 12:46:14 +00:00
// Nothing to do here; bone index is updated in StdMeshUpdate
return true ;
2011-08-19 22:01:08 +00:00
case StdMeshInstance : : AnimationNode : : LinearInterpolationNode :
{
2014-12-26 12:46:14 +00:00
const bool left_result = UpdateAnimationNode ( instance , node - > GetLeftChild ( ) ) ;
const bool right_result = UpdateAnimationNode ( instance , node - > GetRightChild ( ) ) ;
2011-08-19 22:01:08 +00:00
// Remove this node completely
if ( ! left_result & & ! right_result )
return false ;
// Note that either of this also removes this node (and replaces by
// the other child in the tree).
if ( ! left_result )
instance - > StopAnimation ( node - > GetLeftChild ( ) ) ;
if ( ! right_result )
instance - > StopAnimation ( node - > GetRightChild ( ) ) ;
return true ;
}
default :
assert ( false ) ;
return false ;
}
}