/** * Copyright (c) 2003-2009, Xith3D Project Group all rights reserved. * * Portions based on the Java3D interface, Copyright by Sun Microsystems. * Many thanks to the developers of Java3D and Sun Microsystems for their * innovation and design. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the 'Xith3D Project Group' nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) A * RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE */ package org.xith3d.loaders.models.util.animations; import org.jagatoo.loaders.models._util.AnimationType; import org.openmali.FastMath; import org.openmali.vecmath2.Matrix3f; import org.openmali.vecmath2.Matrix4f; import org.openmali.vecmath2.Vector3f; import org.openmali.vecmath2.util.MatrixUtils; import org.xith3d.loaders.models.Model; import org.xith3d.loaders.models.animations.KeyFrameController; import org.xith3d.loaders.models.animations.MeshTransformKeyFrame; import org.xith3d.loaders.models.animations.MeshTransformKeyFrameController; import org.xith3d.loaders.models.animations.ModelAnimation; import org.xith3d.loaders.models.animations.PrecomputedAnimationKeyFrame; import org.xith3d.loaders.models.animations.PrecomputedAnimationKeyFrameController; import org.xith3d.scenegraph.Geometry; import org.xith3d.scenegraph.Shape3D; import org.xith3d.scenegraph.TransformGroup; /** * Utility methods for model animatios. * * @author Marvin Froehlich (aka Qudus) */ public class AnimationTools { private static Geometry copyGeometry( Geometry sourceGeom ) { Geometry copy = sourceGeom.cloneNodeComponent( true ); //copy.setOptimization( org.xith3d.scenegraph.Geometry.Optimization.USE_DISPLAY_LISTS ); if ( !sourceGeom.hasVertexAttributes() && !sourceGeom.isInterleaved() ) // TODO: Remove vertex-attribs-condition! { if ( sourceGeom.hasColors() ) copy.setColorData( sourceGeom.getColorData() ); if ( sourceGeom.hasTextureCoordinates() ) { for ( int i = 0; i < sourceGeom.getNumTextureUnits(); i++ ) { copy.setTexCoordData( i, sourceGeom.getTexCoordsData( i ) ); } } // TODO: Implement vertex-attribute buffer sharing. /* if ( sourceGeom.hasVertexAttributes() ) { for ( int i = 0; i < sourceGeom.getVertexAttributesCount(); i++ ) { copy.setVertexAttributesData( i, sourceGeom.getVertexAttributesData( i ) ); } } */ /* if ( sourceGeom.hasIndex() ) { ( (IndexedGeometryArray)copy ).setIn } */ } return ( copy ); } public static void precomputeAnimations( Model model, float fps ) { // Check, if all animation controllers are suitable for bein precomputed... ModelAnimation[] animations = model.getAnimations(); for ( int i = 0; i < animations.length; i++ ) { for ( int j = 0; j < animations[i].getControllers().length; j++ ) { AnimationType animType = animations[i].getControllers()[j].getAnimationType(); if ( ( animType == AnimationType.MESH_TRANSFORM ) || ( animType == AnimationType.PRECOMPUTED ) ) { throw new Error( "Cannot precompute an animation of the type " + animType ); } } } // Conditions are met. Now let's got for precomputation... ModelAnimation[] newAnimations = new ModelAnimation[ animations.length ]; for ( int i = 0; i < animations.length; i++ ) { ModelAnimation animation = animations[i]; int numFrames = (int)( fps * animation.getDuration() ); PrecomputedAnimationKeyFrameController[] controllers = new PrecomputedAnimationKeyFrameController[ animation.getControllers().length ]; for ( int j = 0; j < animation.getControllers().length; j++ ) { KeyFrameController sourceController = animation.getControllers()[j]; Shape3D shape = (Shape3D)sourceController.getTarget(); PrecomputedAnimationKeyFrame[] frames = new PrecomputedAnimationKeyFrame[ numFrames ]; for ( int k = 0; k < numFrames; k++ ) { float absAnimTime = k * animation.getDuration() / numFrames; sourceController.update( true, absAnimTime, animation ); Matrix4f[] mountTransforms = null; if ( model.getMountTransforms() != null ) { mountTransforms = new Matrix4f[ model.getMountTransforms().length ]; for ( int m = 0; m < mountTransforms.length; m++ ) { model.getMountTransform( m ).getTransform().get( mountTransforms[m] ); } } frames[k] = new PrecomputedAnimationKeyFrame( copyGeometry( shape.getGeometry() ) ); } controllers[j] = new PrecomputedAnimationKeyFrameController( frames, shape ); } newAnimations[i] = new ModelAnimation( animation.getName(), numFrames, fps, controllers ); newAnimations[i].setMountTransformFrames( animation.getMountTransformFrames() ); } model.setAnimations( newAnimations ); } public static MeshTransformKeyFrameController createRotationalKeyFrameController( Vector3f axis, float startAngle, float stopAngle, boolean backwards, int numFrames, TransformGroup target ) { float totalAngleDelta = stopAngle - startAngle; Matrix3f rot = Matrix3f.fromPool(); MeshTransformKeyFrame[] frames = new MeshTransformKeyFrame[ numFrames ]; for ( int i = 0; i < numFrames; i++ ) { float time = (float)i / (float)numFrames; float angle = ( startAngle + ( totalAngleDelta * time ) ) % FastMath.TWO_PI; if ( backwards ) angle = FastMath.TWO_PI - angle; MatrixUtils.getRotationMatrix( axis, angle, rot ); Matrix4f transform = new Matrix4f( rot ); frames[i] = new MeshTransformKeyFrame( time, transform ); } Matrix3f.toPool( rot ); return ( new MeshTransformKeyFrameController( frames, target ) ); } public static MeshTransformKeyFrameController createRotationalKeyFrameController( Vector3f axis, boolean backwards, int numFrames, TransformGroup target ) { return ( createRotationalKeyFrameController( axis, 0f, FastMath.TWO_PI, backwards, numFrames, target ) ); } }