diff --git a/include/IAnimatedMesh.h b/include/IAnimatedMesh.h index 6a3d9f98..22acd538 100644 --- a/include/IAnimatedMesh.h +++ b/include/IAnimatedMesh.h @@ -7,12 +7,12 @@ #include "IUnknown.h" #include "aabbox3d.h" +#include "IMesh.h" namespace irr { namespace scene { - class IMesh; enum E_ANIMATED_MESH_TYPE { @@ -20,10 +20,10 @@ namespace scene EAMT_UNKNOWN = 0, //! Quake 2 MD2 model file - EAMT_MD2, + EAMT_MD2, //! Quake 3 MD3 model file - EAMT_MD3, + EAMT_MD3, //! Milkshape 3d skeletal animation file EAMT_MS3D, @@ -37,8 +37,8 @@ namespace scene //! 3D Studio .3ds file EAMT_3DS, - //! Microsoft Direct3D .x-file. Can contain static and skeletal animated - //! skinned meshes. This is the standard and best supported + //! Microsoft Direct3D .x-file. Can contain static and skeletal animated + //! skinned meshes. This is the standard and best supported //! format of the Irrlicht Engine. EAMT_X, @@ -53,20 +53,20 @@ namespace scene EAMT_CSM, //! .oct file for Paul Nette's FSRad or from Murphy McCauley's Blender .oct exporter. - //! The oct file format contains 3D geometry and lightmaps and can + //! The oct file format contains 3D geometry and lightmaps and can //! be loaded directly by Irrlicht EAMT_OCT, - //! Blitz Basic .b3d file, the file format by Mark Sibly - EAMT_B3D + //! genetic skinned mesh + EAMT_SKINNED }; //! Interface for an animated mesh. - /** There are already simple implementations of this interface available so + /** There are already simple implementations of this interface available so you don't have to implement this interface on your own if you need to: - You might want to use irr::scene::SAnimatedMesh, irr::scene::SMesh, + You might want to use irr::scene::SAnimatedMesh, irr::scene::SMesh, irr::scene::SMeshBuffer etc. */ - class IAnimatedMesh : public virtual IUnknown + class IAnimatedMesh : public IMesh { public: @@ -86,7 +86,7 @@ namespace scene \param startFrameLoop: Because some animated meshes (.MD2) are blended between 2 static frames, and maybe animated in a loop, the startFrameLoop and the endFrameLoop have to be defined, to prevent the animation to be blended between frames which are - outside of this loop. + outside of this loop. If startFrameLoop and endFrameLoop are both -1, they are ignored. \param endFrameLoop: see startFrameLoop. \return Returns the animated mesh based on a detail level. */ diff --git a/include/IAnimatedMeshB3d.h b/include/IAnimatedMeshB3d.h deleted file mode 100644 index 2f337423..00000000 --- a/include/IAnimatedMeshB3d.h +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (C) 2002-2007 Nikolaus Gebhardt -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#ifndef __I_ANIMATED_MESH_B3D_H_INCLUDED__ -#define __I_ANIMATED_MESH_B3D_H_INCLUDED__ - -#include "IAnimatedMesh.h" -#include "irrArray.h" -#include "matrix4.h" - -namespace irr -{ -namespace scene -{ - class ISceneNode; - class ISceneManager; - - //! Interface for using some special functions of B3d meshes - /** Please note that the B3d Mesh's frame numbers are scaled by 100 */ - class IAnimatedMeshB3d : public IAnimatedMesh - { - public: - - //! Returns a pointer to a transformation matrix of a part of the - //! mesh based on a frame time. This is used for being able to attach - //! objects to parts of animated meshes. For example a weapon to an animated - //! hand. - //! \param jointNumber: Zero based index of joint. The last joint has the number - //! IAnimatedMeshB3d::getJointCount()-1; - //! \param frame: Frame of the animation. - //! \return Returns a pointer to the matrix of the mesh part or - //! null if an error occured. - virtual core::matrix4* getMatrixOfJoint(s32 jointNumber, s32 frame) = 0; - - - //! Returns a pointer to a local matrix of a Joint, can be used to control the animation - virtual core::matrix4* getLocalMatrixOfJoint(s32 jointNumber) = 0; - - //! Returns a pointer to a matrix of a part of the mesh unanimated - virtual core::matrix4* getMatrixOfJointUnanimated(s32 jointNumber) = 0; - - - //! Move this Joint's local matrix when animating - //! \param jointNumber: Zero based index of joint. The last joint has the number - //! IAnimatedMeshB3d::getJointCount()-1; - //! \param On: False= Leave joint's local matrix, True= Animate - //! (not used yet) - virtual void setJointAnimation(s32 jointNumber, bool On) = 0; - - - //! Gets joint count. - //! \return Returns amount of joints in the skeletal animated mesh. - virtual s32 getJointCount() const = 0; - - //! Gets the name of a joint. - //! \param number: Zero based index of joint. The last joint has the number - //! IAnimatedMeshB3d::getJointCount()-1; - //! \return Returns name of joint and null if an error happened. - virtual const c8* getJointName(s32 number) const = 0; - - //! Gets a joint number from its name - //! \param name: Name of the joint. - //! \return Returns the number of the joint or -1 if not found. - virtual s32 getJointNumber(const c8* name) const = 0; - - //!Update Normals when Animating - //!False= Don't (default) - //!True= Update normals, slower - virtual void updateNormalsWhenAnimating(bool on) = 0; - - - //!Sets Interpolation Mode - //!0- Constant - //!1- Linear (default) - virtual void setInterpolationMode(s32 mode) = 0; - - //!Want should happen on when animating - //!0-Nothing - //!1-Update nodes only - //!2-Update skin only - //!3-Update both nodes and skin (default) - virtual void setAnimateMode(s32 mode) = 0; - - //!Convert all mesh buffers to use tangent vertices - virtual void convertToTangents() =0; - - - virtual void recoverJointsFromMesh(core::array &JointChildSceneNodes)=0; - virtual void tranferJointsToMesh(core::array &JointChildSceneNodes)=0; - virtual void createJoints(core::array &JointChildSceneNodes, ISceneNode* AnimatedMeshSceneNode, ISceneManager* SceneManager)=0; - - }; - -} // end namespace scene -} // end namespace irr - -#endif - - diff --git a/include/IAnimatedMeshMS3D.h b/include/IAnimatedMeshMS3D.h deleted file mode 100644 index 27a184ea..00000000 --- a/include/IAnimatedMeshMS3D.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (C) 2002-2007 Nikolaus Gebhardt / Fabio Concas / Thomas Alten -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#ifndef __I_ANIMATED_MESH_MS3D_H_INCLUDED__ -#define __I_ANIMATED_MESH_MS3D_H_INCLUDED__ - -#include "IAnimatedMesh.h" -#include "matrix4.h" - -namespace irr -{ -namespace scene -{ - //! Interface for using some special functions of MS3D meshes - class IAnimatedMeshMS3D : public IAnimatedMesh - { - public: - - //! Returns a pointer to a transformation matrix of a part of the - //! mesh based on a frame time. This is used for being able to attach - //! objects to parts of animated meshes. For example a weapon to an animated - //! hand. - //! \param jointNumber: Zero based index of joint. The last joint has the number - //! IAnimatedMeshMS3D::getJointCount()-1; - //! \param frame: Frame of the animation. - //! \return Returns a pointer to the matrix of the mesh part or - //! null if an error occured. - virtual core::matrix4* getMatrixOfJoint(s32 jointNumber, s32 frame) = 0; - - //! Gets joint count. - //! \return Returns amount of joints in the skeletal animated mesh. - virtual s32 getJointCount() const = 0; - - //! Gets the name of a joint. - //! \param number: Zero based index of joint. The last joint has the number - //! IAnimatedMeshMS3D::getJointCount()-1; - //! \return Returns name of joint and null if an error happened. - virtual const c8* getJointName(s32 number) const = 0; - - //! Gets a joint number from its name - //! \param name: Name of the joint. - //! \return Returns the number of the joint or -1 if not found. - virtual s32 getJointNumber(const c8* name) const = 0; - - }; - -} // end namespace scene -} // end namespace irr - -#endif - diff --git a/include/IAnimatedMeshSceneNode.h b/include/IAnimatedMeshSceneNode.h index c9776c25..95fd1d50 100644 --- a/include/IAnimatedMeshSceneNode.h +++ b/include/IAnimatedMeshSceneNode.h @@ -6,6 +6,7 @@ #define __I_ANIMATED_MESH_SCENE_NODE_H_INCLUDED__ #include "ISceneNode.h" +#include "IBoneSceneNode.h" #include "IAnimatedMeshMD2.h" #include "IAnimatedMeshMD3.h" #include "IShadowVolumeSceneNode.h" @@ -54,7 +55,7 @@ namespace scene //! \param frame: Number of the frame to let the animation be started from. //! The frame number must be a valid frame number of the IMesh used by this //! scene node. Set IAnimatedMesh::getMesh() for details. - virtual void setCurrentFrame(s32 frame) = 0; + virtual void setCurrentFrame(f32 frame) = 0; //! Sets the frame numbers between the animation is looped. //! The default is 0 - MaximalFrameCount of the mesh. @@ -84,6 +85,26 @@ namespace scene virtual IShadowVolumeSceneNode* addShadowVolumeSceneNode(s32 id=-1, bool zfailmethod=true, f32 infinity=10000.0f) = 0; + + //! Returns a pointer to a child node, which has the same transformation as + //! the corresponding joint, if the mesh in this scene node is a ms3d mesh. + //! Otherwise 0 is returned. With this method it is possible to + //! attach scene nodes to joints more easily. In this way, it is + //! for example possible to attach a weapon to the left hand of an + //! animated model. This example shows how: + //! \code + //! ISceneNode* hand = + //! yourAnimatedMeshSceneNode->getJointNode("LeftHand"); + //! hand->addChild(weaponSceneNode); + //! \endcode + //! Please note that the SceneNode returned by this method may not exist + //! before this call and is created by it. (Todo: Rewrite) + //! \param jointName: Name of the joint. + //! \return Returns a pointer to the scene node which represents the joint + //! with the specified name. Returns 0 if the contained mesh is not an + //! ms3d mesh or the name of the joint could not be found. + virtual IBoneSceneNode* getJointNode(const c8* jointName)=0; + //! Returns a pointer to a child node, which has the same transformation as //! the corresponding joint, if the mesh in this scene node is a ms3d mesh. //! Otherwise 0 is returned. With this method it is possible to @@ -122,25 +143,6 @@ namespace scene //! ms3d mesh or the name of the joint could not be found. virtual ISceneNode* getXJointNode(const c8* jointName) = 0; - //! Returns a pointer to a child node, which has the same transformation as - //! the corresponding joint, if the mesh in this scene node is a b3d mesh. - //! Otherwise 0 is returned. With this method it is possible to - //! attach scene nodes to joints more easily. In this way, it is - //! for example possible to attach a weapon to the left hand of an - //! animated model. This example shows how: - //! \code - //! ISceneNode* hand = - //! yourB3DAnimatedMeshSceneNode->getB3DJointNode("LeftHand"); - //! hand->addChild(weaponSceneNode); - //! \endcode - //! Please note that the SceneNode returned by this method may not exist - //! before this call and is created by it. - //! \param jointName: Name of the joint. - //! \return Returns a pointer to the scene node which represents the joint - //! with the specified name. Returns 0 if the contained mesh is not an - //! ms3d mesh or the name of the joint could not be found. - virtual ISceneNode* getB3DJointNode(const c8* jointName) = 0; - //! Starts a default MD2 animation. //! With this method it is easily possible to start a Run, Attack, //! Die or whatever animation, if the mesh contained in this scene @@ -165,7 +167,7 @@ namespace scene virtual bool setMD2Animation(const c8* animationName) = 0; //! Returns the current displayed frame number. - virtual s32 getFrameNr() const = 0; + virtual f32 getFrameNr() const = 0; //! Returns the current start frame number. virtual s32 getStartFrame() const = 0; //! Returns the current end frame number. @@ -199,6 +201,16 @@ namespace scene // or the absolutetransformation if it's a normal scenenode virtual const SMD3QuaterionTag& getMD3TagTransformation( const core::stringc & tagname) = 0; + //! Set the joint update mode (0-unused, 1-get joints only, 2-set joints only, 3-move and set) + virtual void setJointMode(s32 mode)=0; + + //! Sets the transition time in seconds (note: This needs to enable joints, and setJointmode maybe set to 2) + //! you must call animateJoints(), or the mesh will not animate + virtual void setTransitionTime(f32 Time) =0; + + //! updates the joint positions of this mesh + virtual void animateJoints() = 0; + }; } // end namespace scene diff --git a/include/IAnimatedMeshX.h b/include/IAnimatedMeshX.h deleted file mode 100644 index 874e4384..00000000 --- a/include/IAnimatedMeshX.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (C) 2002-2007 Nikolaus Gebhardt -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#ifndef __I_ANIMATED_MESH_X_H_INCLUDED__ -#define __I_ANIMATED_MESH_X_H_INCLUDED__ - -#include "IAnimatedMesh.h" -#include "irrArray.h" -#include "matrix4.h" - -namespace irr -{ -namespace scene -{ - //! Interface for using some special functions of X meshes - class IAnimatedMeshX : public IAnimatedMesh - { - public: - - //! Returns a pointer to a transformation matrix of a part of the - //! mesh based on a frame time. This is used for being able to attach - //! objects to parts of animated meshes. For example a weapon to an animated - //! hand. - //! \param jointNumber: Zero based index of joint. The last joint has the number - //! IAnimatedMeshX::getJointCount()-1; - //! \param frame: Frame of the animation. - //! \return Returns a pointer to the matrix of the mesh part or - //! null if an error occured. - virtual core::matrix4* getMatrixOfJoint(s32 jointNumber, s32 frame) = 0; - - //! Gets joint count. - //! \return Returns amount of joints in the skeletal animated mesh. - virtual s32 getJointCount() const = 0; - - //! Gets the name of a joint. - //! \param number: Zero based index of joint. The last joint has the number - //! IAnimatedMeshX::getJointCount()-1; - //! \return Returns name of joint and null if an error happened. - virtual const c8* getJointName(s32 number) const = 0; - - //! Gets a joint number from its name - //! \param name: Name of the joint. - //! \return Returns the number of the joint or -1 if not found. - virtual s32 getJointNumber(const c8* name) const = 0; - - //! Returns a pointer to list of points containing the skeleton. - //! Draw a line between point 1 and 2, and 3 and 4 and 5 and 6 - //! and so on to visualize this. Only for debug purposes. If you - //! use an .x-File with the IAnimatedMeshSceneNode and turn DebugDataVisible - //! to true, the Scene node will visualize the skeleton using this - //! method. - virtual const core::array* getDrawableSkeleton(s32 frame) = 0; - - //! Returns amount of animations in .X-file. - virtual s32 getAnimationCount() const = 0; - - //! Returns the name of an animation. - //! \param idx: Zero based Index of the animation. Must be a value between - //! 0 and getAnimationCount()-1; - //! \return Returns pointer to the string of the name of the animation. - //! Returns 0 if an animation with this index does not exist. - virtual const c8* getAnimationName(s32 idx) const = 0; - - //! Sets an animation as animation to play back. - //! \param idx: Zero based Index of the animation. Must be a value between - //! 0 and getAnimationCount()-1; - virtual void setCurrentAnimation(s32 idx) = 0; - - //! Sets an animation as animation to play back. - //! \param name: Name of the animtion. - //! \return Returns true if successful, and false if the specified animation - //! does not exist. - virtual bool setCurrentAnimation(const c8* name) = 0; - }; - -} // end namespace scene -} // end namespace irr - -#endif - diff --git a/include/IBoneSceneNode.h b/include/IBoneSceneNode.h new file mode 100644 index 00000000..8ad2e401 --- /dev/null +++ b/include/IBoneSceneNode.h @@ -0,0 +1,97 @@ +#ifndef __I_BONE_SCENE_NODE_H_INCLUDED__ +#define __I_BONE_SCENE_NODE_H_INCLUDED__ + +// Used with SkinnedMesh and IAnimatedMeshSceneNode, for boned meshes + +#include "ISceneNode.h" + +namespace irr +{ +namespace scene +{ + + //! Enumeration for different bone animation modes + enum E_BONE_ANIMATION_MODE + { + //! The bone is usually animated, unless it's parent is not animated + EBAM_AUTOMATIC=0, + + //! The bone is animated by the skin, if it's parent is not animated + //! then animation will resume from this bone onward + EBAM_ANIMATED, + + //! The bone is not animated by the skin + EBAM_UNANIMATED, + + //! Not an animation mode, just here to count the available modes + EBAM_COUNT + + }; + + //! Names for bone animation modes + const c8* const BoneAnimationModeNames[] = + { + "automatic", + "animated", + "unanimated", + 0, + }; + + + class IBoneSceneNode : public ISceneNode + { + public: + + IBoneSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id=-1) : + ISceneNode(parent, mgr, id),positionHint(-1),scaleHint(-1),rotationHint(-1) { } + + //! Returns the name of the bone + virtual const c8* getBoneName() const = 0; + + //! Returns the index of the bone + virtual u32 getBoneIndex() const = 0; + + //! Sets the animation mode of the bone. Returns true if successful. + virtual bool setAnimationMode(E_BONE_ANIMATION_MODE mode) = 0; + + //! Gets the current animation mode of the bone + virtual E_BONE_ANIMATION_MODE getAnimationMode() const = 0; + + //! returns the axis aligned bounding box of this node + virtual const core::aabbox3d& getBoundingBox() const = 0; + + //! Returns the relative transformation of the scene node. + //virtual core::matrix4 getRelativeTransformation() const = 0; + + virtual void OnAnimate(u32 timeMs) =0; + + //! Does nothing as bones are not visible + virtual void render() { }; + + + virtual void setAbsoluteTransformation(core::matrix4 transformation) + { + AbsoluteTransformation=transformation; + } + + + + //! updates the absolute position based on the relative and the parents position + virtual void updateAbsolutePositionOfAllChildren()=0; + + + + + + s32 positionHint; + s32 scaleHint; + s32 rotationHint; + + + }; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/ISkinnedMesh.h b/include/ISkinnedMesh.h new file mode 100644 index 00000000..592e0270 --- /dev/null +++ b/include/ISkinnedMesh.h @@ -0,0 +1,215 @@ +// Copyright (C) 2002-2006 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_SKINNED_MESH_H_INCLUDED__ +#define __I_SKINNED_MESH_H_INCLUDED__ + +#include "irrArray.h" +#include "IBoneSceneNode.h" +#include "IAnimatedMesh.h" +#include "SSkinMeshBuffer.h" + +namespace irr +{ +namespace scene +{ + + enum E_INTERPOLATION_MODE + { + // constant interpolation + EIM_CONSTANT = 0, + + // linear interpolation + EIM_LINEAR, + + //! count of all available interpolation modes + EIM_COUNT + }; + + + //! Interface for using some special functions of Skinned meshes + class ISkinnedMesh : public IAnimatedMesh + { + public: + + //! Gets joint count. + //! \return Returns amount of joints in the skeletal animated mesh. + virtual s32 getJointCount() const = 0; + + //! Gets the name of a joint. + //! \param number: Zero based index of joint. The last joint has the number + //! IAnimatedMeshB3d::getJointCount()-1; + //! \return Returns name of joint and null if an error happened. + virtual const c8* getJointName(s32 number) const = 0; + + //! Gets a joint number from its name + //! \param name: Name of the joint. + //! \return Returns the number of the joint or -1 if not found. + virtual s32 getJointNumber(const c8* name) const = 0; + + //! uses animation from another mesh + //! the animation is linked (not copied) based on joint names (so make sure they are unique) + //! \return Returns true if all joints in this mesh were matched up (empty names will not be matched, and it's case sensitive) + //! unmatched joints will not be animated + virtual bool useAnimationFrom(ISkinnedMesh *mesh) = 0; + + //!Update Normals when Animating + //!False= Don't (default) + //!True= Update normals, slower + virtual void updateNormalsWhenAnimating(bool on) = 0; + + //!Sets Interpolation Mode + virtual void setInterpolationMode(E_INTERPOLATION_MODE mode) = 0; + + //! Animates this mesh's joints based on frame input + virtual void animateMesh(f32 frame, f32 blend)=0; + + //! Preforms a software skin on this mesh based of joint positions + virtual void skinMesh() = 0; + + //!Recovers the joints from the mesh + virtual void recoverJointsFromMesh(core::array &JointChildSceneNodes) = 0; + + //!Tranfers the joint data to the mesh + virtual void tranferJointsToMesh(core::array &JointChildSceneNodes) = 0; + + //!Creates an array of joints from this mesh + virtual void createJoints(core::array &JointChildSceneNodes, + IAnimatedMeshSceneNode* AnimatedMeshSceneNode, ISceneManager* SceneManager) = 0; + + virtual void convertMeshToTangents() = 0; + + //! A vertex weight + struct SWeight + { + //! Index of the mesh buffer + u16 buffer_id; //I doubt 32bits is needed + + //! Index of the vertex + u32 vertex_id; //Store global ID here + + //! Weight Strength/Percentage (0-1) + f32 strength; + + private: + //! Internal members used by CSkinnedMesh + friend class CSkinnedMesh; + bool *Moved; + core::vector3df StaticPos; + core::vector3df StaticNormal; + }; + + + //! Animation keyframe which describes a new position, scale or rotation + struct SPositionKey + { + f32 frame; + core::vector3df position; + }; + + struct SScaleKey + { + f32 frame; + core::vector3df scale; + }; + + struct SRotationKey + { + f32 frame; + core::quaternion rotation; + }; + + //! Joints + struct SJoint + { + SJoint() : + Name(""), LocalMatrix(), + Children(), PositionKeys(), ScaleKeys(), RotationKeys(), Weights(), + UseAnimationFrom(0), LocalAnimatedMatrix_Animated(false),positionHint(-1),scaleHint(-1),rotationHint(-1) + { + } + + //! The name of this joint + core::stringc Name; + + //! Local matrix of this joint + core::matrix4 LocalMatrix; + + //! List of child joints + core::array Children; + + //! Animation keys causing translation change + core::array PositionKeys; + + //! Animation keys causing scale change + core::array ScaleKeys; + + //! Animation keys causing rotation change + core::array RotationKeys; + + //! Skin weights + core::array Weights; + + //! Unnecessary for loaders, will be overwritten on finalize + core::matrix4 GlobalMatrix; + core::matrix4 GlobalAnimatedMatrix; + core::matrix4 LocalAnimatedMatrix; + core::vector3df Animatedposition; + core::vector3df Animatedscale; + core::quaternion Animatedrotation; + + core::matrix4 GlobalInversedMatrix; //the x format pre-calculates this + + private: + //! Internal members used by CSkinnedMesh + friend class CSkinnedMesh; + + SJoint *UseAnimationFrom; + bool LocalAnimatedMatrix_Animated; + + s32 positionHint; + s32 scaleHint; + s32 rotationHint; + + }; + + + + + + + //Interface for the mesh loaders (finalize should lock these functions, and they should have some prefix like loader_ + + //these functions will use the needed arrays, set vaules, etc to help the loaders + + //! exposed for loaders to add mesh buffers + virtual core::array &getMeshBuffers() = 0; + + //! alternative method for adding joints + virtual core::array &getAllJoints() = 0; + + //! loaders should call this after populating the mesh + virtual void finalize() = 0; + + + + + virtual SSkinMeshBuffer *createBuffer() = 0; + + virtual SJoint *createJoint(SJoint *parent=0) = 0; + + virtual SPositionKey *createPositionKey(SJoint *joint) = 0; + virtual SScaleKey *createScaleKey(SJoint *joint) = 0; + virtual SRotationKey *createRotationKey(SJoint *joint) = 0; + + virtual SWeight *createWeight(SJoint *joint) = 0; + }; + +} // end namespace scene +} // end namespace irr + +#endif + + + diff --git a/include/IrrCompileConfig.h b/include/IrrCompileConfig.h index a5265ece..57af47ed 100644 --- a/include/IrrCompileConfig.h +++ b/include/IrrCompileConfig.h @@ -6,7 +6,7 @@ #define __IRR_COMPILE_CONFIG_H_INCLUDED__ //! Irrlicht SDK Version -#define IRRLICHT_SDK_VERSION "1.3.1" +#define IRRLICHT_SDK_VERSION "1.4RC" //! The defines for different operating system are: //! _IRR_XBOX_PLATFORM_ for XBox @@ -213,6 +213,46 @@ Note that the engine will run in D3D REF for this, which is a lot slower than HA //#define BURNINGVIDEO_RENDERER_ULTRA_FAST +//! Define _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_ if you want to use bone based +/** animated meshes. If you compile without this, you will be unable to load +B3D, MS3D or X meshes */ +#define _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_ + +#ifdef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_ +//! Define _IRR_COMPILE_WITH_B3D_LOADER_ if you want to use Blitz3D files +#define _IRR_COMPILE_WITH_B3D_LOADER_ +//! Define _IRR_COMPILE_WITH_B3D_LOADER_ if you want to Milkshape files +#define _IRR_COMPILE_WITH_MS3D_LOADER_ +//! Define _IRR_COMPILE_WITH_X_LOADER_ if you want to use Microsoft X files +#define _IRR_COMPILE_WITH_X_LOADER_ +#endif + +//! Define _IRR_COMPILE_WITH_MD2_LOADER_ if you want to load Quake 2 animated files +#define _IRR_COMPILE_WITH_MD2_LOADER_ +//! Define _IRR_COMPILE_WITH_MD3_LOADER_ if you want to load Quake 3 animated files +#define _IRR_COMPILE_WITH_MD3_LOADER_ + +//! Define _IRR_COMPILE_WITH_3DS_LOADER_ if you want to load 3D Studio Max files +#define _IRR_COMPILE_WITH_3DS_LOADER_ +//! Define _IRR_COMPILE_WITH_COLLADA_LOADER_ if you want to load Collada files +#define _IRR_COMPILE_WITH_COLLADA_LOADER_ +//! Define _IRR_COMPILE_WITH_CSM_LOADER_ if you want to load Cartography Shop files +#define _IRR_COMPILE_WITH_CSM_LOADER_ +//! Define _IRR_COMPILE_WITH_BSP_LOADER_ if you want to load Quake 3 BSP files +#define _IRR_COMPILE_WITH_BSP_LOADER_ +//! Define _IRR_COMPILE_WITH_DMF_LOADER_ if you want to load DeleD files +#define _IRR_COMPILE_WITH_DMF_LOADER_ +//! Define _IRR_COMPILE_WITH_LMTS_LOADER_ if you want to load LMTools files +#define _IRR_COMPILE_WITH_LMTS_LOADER_ +//! Define _IRR_COMPILE_WITH_MY3D_LOADER_ if you want to load MY3D files +#define _IRR_COMPILE_WITH_MY3D_LOADER_ +//! Define _IRR_COMPILE_WITH_OBJ_LOADER_ if you want to load Wavefront OBJ files +#define _IRR_COMPILE_WITH_OBJ_LOADER_ +//! Define _IRR_COMPILE_WITH_OCT_LOADER_ if you want to load FSRad OCT files +#define _IRR_COMPILE_WITH_OCT_LOADER_ +//! Define _IRR_COMPILE_WITH_OGRE_LOADER_ if you want to load Ogre 3D files +#define _IRR_COMPILE_WITH_OGRE_LOADER_ + //! Set FPU settings /** Irrlicht should use approximate float and integer fpu techniques precision will be lower but speed higher. currently X86 only diff --git a/include/SAnimatedMesh.h b/include/SAnimatedMesh.h index db935821..3d6998d9 100644 --- a/include/SAnimatedMesh.h +++ b/include/SAnimatedMesh.h @@ -63,7 +63,7 @@ namespace scene //! 255 the highest level of detail. Most meshes will ignore the detail level. //! \param startFrameLoop: start frame //! \param endFrameLoop: end frame - //! \return Returns the animated mesh based on a detail level. + //! \return Returns the animated mesh based on a detail level. virtual IMesh* getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop=-1, s32 endFrameLoop=-1) { if (Meshes.empty()) @@ -83,7 +83,7 @@ namespace scene } } - + //! Returns an axis aligned bounding box of the mesh. //! \return A bounding box of this mesh is returned. virtual const core::aabbox3d& getBoundingBox() const @@ -107,16 +107,42 @@ namespace scene Box = Meshes[0]->getBoundingBox(); for (u32 i=1; igetBoundingBox()); + Box.addInternalBox(Meshes[i]->getBoundingBox()); } - //! Returns the type of the animated mesh. virtual E_ANIMATED_MESH_TYPE getMeshType() const { return Type; } + //! returns amount of mesh buffers. + virtual u32 getMeshBufferCount() const + { + return 0; + } + + //! returns pointer to a mesh buffer + virtual IMeshBuffer* getMeshBuffer(u32 nr) const + { + return 0; + } + + //! Returns pointer to a mesh buffer which fits a material + /** \param material: material to search for + \return Returns the pointer to the mesh buffer or + NULL if there is no such mesh buffer. */ + virtual IMeshBuffer* getMeshBuffer( const video::SMaterial &material) const + { + return 0; + } + + virtual void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) + { + return; + } + + core::aabbox3d Box; core::array Meshes; E_ANIMATED_MESH_TYPE Type; diff --git a/include/SSkinMeshBuffer.h b/include/SSkinMeshBuffer.h new file mode 100644 index 00000000..57771cdc --- /dev/null +++ b/include/SSkinMeshBuffer.h @@ -0,0 +1,232 @@ +// Copyright (C) 2002-2006 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_SKIN_MESH_BUFFER_H_INCLUDED__ +#define __I_SKIN_MESH_BUFFER_H_INCLUDED__ + +#include "IMeshBuffer.h" +#include "S3DVertex.h" + +namespace irr +{ +namespace scene +{ + +//! A mesh buffer able to choose between +//! S3DVertex2TCoords, S3DVertex and S3DVertexTangents at runtime +struct SSkinMeshBuffer : public IMeshBuffer +{ + SSkinMeshBuffer(video::E_VERTEX_TYPE vt=video::EVT_STANDARD) : VertexType(vt) + { + #ifdef _DEBUG + setDebugName("SSkinMeshBuffer"); + #endif + } + + virtual ~SSkinMeshBuffer() {} + + virtual const video::SMaterial& getMaterial() const + { + return Material; + } + + virtual video::SMaterial& getMaterial() + { + return Material; + } + + virtual video::S3DVertex *getVertex(u32 index) + { + switch (VertexType) + { + case video::EVT_2TCOORDS: return (video::S3DVertex*)&Vertices_2TCoords[index]; + case video::EVT_TANGENTS: return (video::S3DVertex*)&Vertices_Tangents[index]; + default: return &Vertices_Standard[index]; + } + } + + virtual const void* getVertices() const + { + switch (VertexType) + { + case video::EVT_2TCOORDS: return Vertices_2TCoords.const_pointer(); + case video::EVT_TANGENTS: return Vertices_Tangents.const_pointer(); + default: return Vertices_Standard.const_pointer(); + } + } + + virtual void* getVertices() + { + switch (VertexType) + { + case video::EVT_2TCOORDS: return Vertices_2TCoords.pointer(); + case video::EVT_TANGENTS: return Vertices_Tangents.pointer(); + default: return Vertices_Standard.pointer(); + } + } + + virtual u32 getVertexCount() const + { + switch (VertexType) + { + case video::EVT_2TCOORDS: return Vertices_2TCoords.size(); + case video::EVT_TANGENTS: return Vertices_Tangents.size(); + default: return Vertices_Standard.size(); + } + } + + virtual const u16* getIndices() const + { + return Indices.const_pointer(); + } + + virtual u16* getIndices() + { + return Indices.pointer(); + } + + virtual u32 getIndexCount() const + { + return Indices.size(); + } + + virtual const core::aabbox3d& getBoundingBox() const + { + return BoundingBox; + } + + virtual void setBoundingBox( const core::aabbox3df& box) + { + BoundingBox = box; + } + + virtual void recalculateBoundingBox() + { + switch (VertexType) + { + case video::EVT_STANDARD: + { + if (Vertices_Standard.empty()) + BoundingBox.reset(0,0,0); + else + { + BoundingBox.reset(Vertices_Standard[0].Pos); + for (u32 i=1; i Vertices_Tangents; + core::array Vertices_2TCoords; + core::array Vertices_Standard; + core::array Indices; + core::aabbox3d BoundingBox; +}; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/include/irrlicht.h b/include/irrlicht.h index a6fa2f7d..249a2da0 100644 --- a/include/irrlicht.h +++ b/include/irrlicht.h @@ -18,11 +18,11 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. - Please note that the Irrlicht Engine is based in part on the work of the + Please note that the Irrlicht Engine is based in part on the work of the Independent JPEG Group, the zlib and the libPng. This means that if you use the Irrlicht Engine in your product, you must acknowledge somewhere in your documentation that you've used the IJG code. It would also be nice to mention - that you use the Irrlicht Engine, the zlib and libPng. See the README files + that you use the Irrlicht Engine, the zlib and libPng. See the README files in the jpeglib, the zlib and libPng for further informations. */ @@ -43,13 +43,10 @@ #include "IAnimatedMesh.h" #include "IAnimatedMeshMD2.h" #include "IAnimatedMeshMD3.h" -#include "IAnimatedMeshMS3D.h" -#include "IAnimatedMeshMS3D.h" #include "IQ3LevelMesh.h" -#include "IAnimatedMeshX.h" -#include "IAnimatedMeshB3d.h" #include "IAnimatedMeshSceneNode.h" #include "IBillboardSceneNode.h" +#include "IBoneSceneNode.h" #include "ICameraSceneNode.h" #include "IDummyTransformationSceneNode.h" #include "IEventReceiver.h" @@ -104,6 +101,7 @@ #include "ISceneNodeAnimatorCollisionResponse.h" #include "IShaderConstantSetCallBack.h" #include "IParticleSystemSceneNode.h" // also includes all emitters and attractors +#include "ISkinnedMesh.h" #include "ITerrainSceneNode.h" #include "ITextSceneNode.h" #include "ITexture.h" @@ -147,8 +145,8 @@ * Welcome to the Irrlicht Engine API documentation. * Here you'll find any information you'll need to develop applications with * the Irrlicht Engine. If you are looking for a tutorial on how to start, you'll - * find some on the homepage of the Irrlicht Engine at - * irrlicht.sourceforge.net + * find some on the homepage of the Irrlicht Engine at + * irrlicht.sourceforge.net * or inside the SDK in the examples directory. * * The Irrlicht Engine is intended to be an easy-to-use 3d engine, so @@ -166,7 +164,7 @@ * * \section irrexample Short example * - * A simple application, starting up the engine, loading a Quake 2 animated + * A simple application, starting up the engine, loading a Quake 2 animated * model file and the corresponding texture, animating and displaying it * in front of a blue background and placing a user controlable 3d camera * would look like the following code. I think this example shows the usage @@ -200,7 +198,7 @@ * * // add a first person shooter style user controlled camera * scenemgr->addCameraSceneNodeFPS(); - * + * * // draw everything * while(device->run() && driver) * { @@ -231,10 +229,10 @@ * * As you can see, the engine uses namespaces. Everything in the engine is * placed into the namespace 'irr', but there are also 5 sub namespaces. - * You can find a list of all namespaces with descriptions at the - * namespaces page. + * You can find a list of all namespaces with descriptions at the + * namespaces page. * This is also a good place to start reading the documentation. If you - * don't want to write the namespace names all the time, just use all namespaces like + * don't want to write the namespace names all the time, just use all namespaces like * this: * \code * using namespace core; @@ -257,7 +255,7 @@ namespace irr //! Creates an Irrlicht device. The Irrlicht device is the root object for using the engine. /** If you need more parameters to be passed to the creation of the Irrlicht Engine device, use the createDeviceEx() function. - \param deviceType: Type of the device. This can currently be video::EDT_NULL, + \param deviceType: Type of the device. This can currently be video::EDT_NULL, video::EDT_SOFTWARE, video::EDT_BURNINGSVIDEO, video::EDT_DIRECT3D8, video::EDT_DIRECT3D9 and video::EDT_OPENGL. \param windowSize: Size of the window or the video mode in fullscreen mode. \param bits: Bits per pixel in fullscreen mode. Ignored if windowed mode. @@ -266,7 +264,7 @@ namespace irr \param stencilbuffer: Specifies if the stencil buffer should be enabled. Set this to true, if you want the engine be able to draw stencil buffer shadows. Note that not all devices are able to use the stencil buffer. If they don't no shadows will be drawn. - \param vsync: Specifies vertical syncronisation: If set to true, the driver will wait + \param vsync: Specifies vertical syncronisation: If set to true, the driver will wait for the vertical retrace period, otherwise not. \param receiver: A user created event receiver. \param sdk_version_do_not_use: Don't use or change this parameter. Always set it to @@ -284,13 +282,13 @@ namespace irr IEventReceiver* receiver = 0, const c8* sdk_version_do_not_use = IRRLICHT_SDK_VERSION); - //! Creates an Irrlicht device with the option to specify advanced parameters. + //! Creates an Irrlicht device with the option to specify advanced parameters. /** Usually you should used createDevice() for creating an Irrlicht Engine device. Use this function only if you wish to specify advanced parameters like a window handle in which the device should be created. \param parameters: Structure containing advanced parameters for the creation of the device. See irr::SIrrlichtCreationParameters for details. - \return Returns pointer to the created IrrlichtDevice or null if the + \return Returns pointer to the created IrrlichtDevice or null if the device could not be created. */ IRRLICHT_API IrrlichtDevice* IRRCALLCONV createDeviceEx( const SIrrlichtCreationParameters& parameters); diff --git a/source/Irrlicht/C3DSMeshFileLoader.cpp b/source/Irrlicht/C3DSMeshFileLoader.cpp index e832e261..9388ba3c 100644 --- a/source/Irrlicht/C3DSMeshFileLoader.cpp +++ b/source/Irrlicht/C3DSMeshFileLoader.cpp @@ -2,6 +2,9 @@ // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_3DS_LOADER_ + #include "C3DSMeshFileLoader.h" #include "os.h" #include "SMeshBuffer.h" @@ -1262,3 +1265,4 @@ void C3DSMeshFileLoader::readString(io::IReadFile* file, ChunkData& data, core:: } // end namespace scene } // end namespace irr +#endif // _IRR_COMPILE_WITH_3DS_LOADER_ diff --git a/source/Irrlicht/CAnimatedMeshB3d.cpp b/source/Irrlicht/CAnimatedMeshB3d.cpp deleted file mode 100644 index 47153c21..00000000 --- a/source/Irrlicht/CAnimatedMeshB3d.cpp +++ /dev/null @@ -1,1957 +0,0 @@ -// Copyright (C) 2002-2007 Nikolaus Gebhardt -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -// B3D file loader by Luke Hoschke, File format by Mark Sibly - -#include "CAnimatedMeshB3d.h" -#include "os.h" -#include "IVideoDriver.h" -#include "ISceneNode.h" - -namespace irr -{ -namespace scene -{ - - -struct B3dChunkHeader -{ - c8 name[4]; - s32 size; -}; - - -//! constructor -CAnimatedMeshB3d::CAnimatedMeshB3d(video::IVideoDriver* driver) -: Driver(driver) -{ - if (Driver) - Driver->grab(); -} - - -//! destructor -CAnimatedMeshB3d::~CAnimatedMeshB3d() -{ - - if (Driver) - Driver->drop(); - - s32 n; - for (n=BaseVertices.size()-1; n>=0; --n) - { - delete BaseVertices[n]; - BaseVertices.erase(n); - } - - for (n=Buffers.size()-1; n>=0; --n) - { - delete Buffers[n]; - Buffers.erase(n); - } - - for (n=Materials.size()-1; n>=0; --n) - { - if (Materials[n].Material) - delete Materials[n].Material; - Materials.erase(n); - } - - for (n=Nodes.size()-1; n>=0; --n) - { - delete Nodes[n]; - Nodes.erase(n); - } - -} - - - -core::stringc CAnimatedMeshB3d::readString(io::IReadFile* file) -{ - core::stringc newstring; - - while (file->getPos() <= file->getSize() ) - { - c8 character; - file->read(&character, sizeof(character)); - - if (character==0) - return newstring; - - newstring.append(character); - } - return newstring; -} - - - -core::stringc CAnimatedMeshB3d::stripPathString(core::string oldstring, bool keepPath) -{ - s32 lastA=oldstring.findLast('/'); // forward slash - s32 lastB=oldstring.findLast('\\'); // back slash - - if (!keepPath) - { - if (lastA==-1 && lastB==-1) - return oldstring; - } - else - { - if (lastA==-1 && lastB==-1) - return core::stringc(); - } - - - if (lastA > lastB) - { - if (!keepPath) - return oldstring.subString(lastA+1, oldstring.size() - (lastA+1)); - else - return oldstring.subString(0, lastA + 1); - } - else - { - if (!keepPath) - return oldstring.subString(lastB+1, oldstring.size() - (lastB+1)); - else - return oldstring.subString(0, lastB + 1); - } -} - - - -void CAnimatedMeshB3d::readFloats(io::IReadFile* file, f32* vec, u32 count) -{ - file->read(vec, count*sizeof(f32)); - #ifdef __BIG_ENDIAN__ - for (u32 n=0; ngetTextureCreationFlag(video::ETCF_ALWAYS_32_BIT); - - Driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true); - - - while(B3dStack.getLast().startposition + B3dStack.getLast().length>file->getPos()) //this chunk repeats - { - core::stringc TextureName=readString(file); - - TextureName=stripPathString(file->getFileName(),true) + stripPathString(TextureName,false); - - SB3dTexture B3dTexture; - - B3dTexture.Texture=Driver->getTexture ( TextureName.c_str() ); - - file->read(&B3dTexture.Flags, sizeof(s32)); - file->read(&B3dTexture.Blend, sizeof(s32)); - readFloats(file, &B3dTexture.Xpos, 1); - readFloats(file, &B3dTexture.Ypos, 1); - readFloats(file, &B3dTexture.Xscale, 1); - readFloats(file, &B3dTexture.Yscale, 1); - readFloats(file, &B3dTexture.Angle, 1); - - #ifdef __BIG_ENDIAN__ - B3dTexture.Flags = os::Byteswap::byteswap(B3dTexture.Flags); - B3dTexture.Blend = os::Byteswap::byteswap(B3dTexture.Blend); - #endif - - Textures.push_back(B3dTexture); - - /* - Flags: - 1: Color (default) - 2: Alpha - 4: Masked - 8: Mipmapped - 16: Clamp U - 32: Clamp V - 64: Spherical environment map - 128: Cubic environment map - 256: Store texture in vram - 512: Force the use of high color textures - 65536: texture uses secondary UV values - - Blend: - 0: Do not blend - 1: No blend, or Alpha (alpha when texture loaded with alpha flag - not recommended for multitexturing - see below) - 2: Multiply (default) - 3: Add - 4: Dot3 - 5: Multiply 2 - */ - } - - B3dStack.erase(B3dStack.size()-1); - - Driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, Previous32BitTextureFlag); - - return true; -} - - - - -bool CAnimatedMeshB3d::ReadChunkBRUS(io::IReadFile* file) -{ - - s32 n_texs; - - file->read(&n_texs, sizeof(s32)); - - #ifdef __BIG_ENDIAN__ - n_texs = os::Byteswap::byteswap(n_texs); - #endif - - while(B3dStack.getLast().startposition + B3dStack.getLast().length>file->getPos()) //this chunk repeats - { - // This is what blitz basic calls a brush, like a Irrlicht Material - core::stringc MaterialName=readString(file); //Not used but we still need the read it - - SB3dMaterial B3dMaterial; - - B3dMaterial.Material = new irr::video::SMaterial(); - - B3dMaterial.Textures[0]=0; - B3dMaterial.Textures[1]=0; - - s32 texture_id[8]; - texture_id[0]=-1; - texture_id[1]=-1; - - file->read(&B3dMaterial.red, sizeof(B3dMaterial.red)); - file->read(&B3dMaterial.green, sizeof(B3dMaterial.green)); - file->read(&B3dMaterial.blue, sizeof(B3dMaterial.blue)); - file->read(&B3dMaterial.alpha, sizeof(B3dMaterial.alpha)); - file->read(&B3dMaterial.shininess, sizeof(B3dMaterial.shininess)); - file->read(&B3dMaterial.blend, sizeof(B3dMaterial.blend)); - file->read(&B3dMaterial.fx, sizeof(B3dMaterial.fx)); - - for (s32 n=0; n < n_texs; ++n) - { - file->read(&texture_id[n], sizeof(s32)); //I'm not sure of getting the sizeof an array - //cout << "Material is using texture id:"<< texture_id[n] <Textures[0] = B3dMaterial.Textures[0]->Texture; - if (B3dMaterial.Textures[1] != 0) - B3dMaterial.Material->Textures[1] = B3dMaterial.Textures[1]->Texture; - - //the other textures are skipped, irrlicht I think can only have 2 Textures per Material - - if (B3dMaterial.Textures[1] != 0 && B3dMaterial.Textures[0] == 0) //It could happen - { - B3dMaterial.Textures[0] = B3dMaterial.Textures[1]; - B3dMaterial.Textures[1] = 0; - } - - //Hacky code to convert blitz fx to irrlicht... - if (B3dMaterial.Textures[1]) //Two textures - { - if (B3dMaterial.alpha==1) - { - if (B3dMaterial.Textures[1]->Blend & 5) - { - //B3dMaterial.Material->MaterialType = video::EMT_LIGHTMAP; - B3dMaterial.Material->MaterialType = video::EMT_LIGHTMAP_M2 ; - } - else - { - B3dMaterial.Material->MaterialType = video::EMT_LIGHTMAP; - } - } - else - { - //B3dMaterial.Material->MaterialType = video::EMT_LIGHTMAP; - //B3dMaterial.Material->MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; - //B3dMaterial.Material->MaterialTypeParam=B3dMaterial.alpha; - B3dMaterial.Material->MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; - } - } - else if (B3dMaterial.Textures[0]) //one texture - { - if (B3dMaterial.Textures[0]->Flags & 2) // Alpha mapped - { - B3dMaterial.Material->MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; - } - else if (B3dMaterial.Textures[0]->Flags & 4) // Masked - { - // Not working like blitz basic, because Irrlicht is using alpha to mask, not colour like blitz basic - - B3dMaterial.Material->MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; - - } - else if (B3dMaterial.alpha == 1) - { - B3dMaterial.Material->MaterialType = video::EMT_SOLID; - } - else - { - //B3dMaterial.Material->MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; - //B3dMaterial.Material->MaterialTypeParam=B3dMaterial.alpha; - B3dMaterial.Material->MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; - } - } - else //No texture - { - - if (B3dMaterial.alpha == 1) - { - B3dMaterial.Material->MaterialType = video::EMT_SOLID; - } - else - { - B3dMaterial.Material->MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; - } - } - - - if (B3dMaterial.fx & 32) //force vertex alpha-blending - { - B3dMaterial.Material->MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; - //B3dMaterial.Material->Lighting=false; - } - - - // Material fx... - - if (B3dMaterial.fx & 1) //full-bright - { - //B3dMaterial.Material->AmbientColor = video::SColor(1, 1, 1, 1).toSColor (); - B3dMaterial.Material->AmbientColor = video::SColor(255, 255, 255, 255); - //B3dMaterial.Material->EmissiveColor = video::SColorf(1, 1, 1, 0).toSColor ();//Would be too bright and brighter than blitz basic - B3dMaterial.Material->Lighting = false; - } - else - { - B3dMaterial.Material->AmbientColor = video::SColorf(B3dMaterial.red, B3dMaterial.green, B3dMaterial.blue, B3dMaterial.alpha).toSColor (); - } - - if (B3dMaterial.fx & 4) //flatshaded - B3dMaterial.Material->GouraudShading = false; - - if (B3dMaterial.fx & 16) //disable backface culling - B3dMaterial.Material->BackfaceCulling = false; - - - B3dMaterial.Material->DiffuseColor = video::SColorf(B3dMaterial.red, B3dMaterial.green, B3dMaterial.blue, B3dMaterial.alpha).toSColor (); - B3dMaterial.Material->EmissiveColor = video::SColorf(0.5, 0.5, 0.5, 0).toSColor (); //Thoughts, I'm no sure what I should set it to? - //B3dMaterial.Material->SpecularColor = video::SColorf(0, 0, 0, 0).toSColor (); //? - B3dMaterial.Material->Shininess = B3dMaterial.shininess; - - Materials.push_back(B3dMaterial); - } - - B3dStack.erase(B3dStack.size()-1); - - return true; -} - - - -bool CAnimatedMeshB3d::ReadChunkMESH(io::IReadFile* file, SB3dNode *InNode) -{ - - s32 Vertices_Start=BaseVertices.size(); //B3Ds have Vertex ID's local within the mesh I don't want this - - s32 brush_id; - - file->read(&brush_id, sizeof(brush_id)); - - #ifdef __BIG_ENDIAN__ - brush_id = os::Byteswap::byteswap(brush_id); - #endif - - NormalsInFile=false; - - - - while(B3dStack.getLast().startposition + B3dStack.getLast().length>file->getPos()) //this chunk repeats - { - - B3dStack.push_back(B3dChunk()); - - B3dChunkHeader header; - file->read(&header, sizeof(header)); - - #ifdef __BIG_ENDIAN__ - header.size = os::Byteswap::byteswap(header.size); - #endif - - B3dStack.getLast().name[0]=header.name[0]; - B3dStack.getLast().name[1]=header.name[1]; //Not sure of an easier way - B3dStack.getLast().name[2]=header.name[2]; - B3dStack.getLast().name[3]=header.name[3]; - - B3dStack.getLast().length = header.size + 8; - - B3dStack.getLast().startposition = file->getPos() - 8; - - bool read=false; - - if ( strncmp( B3dStack.getLast().name, "VRTS", 4 ) == 0 ) - { - read=true; - if (!ReadChunkVRTS(file,InNode ,0, Vertices_Start)) - return false; - } - else if ( strncmp( B3dStack.getLast().name, "TRIS", 4 ) == 0 ) - { - read=true; - - SB3DMeshBuffer *MeshBuffer = new SB3DMeshBuffer(); - MeshBuffer->VertexType=video::EVT_STANDARD; - - if (brush_id!=-1) - MeshBuffer->Material=(*Materials[brush_id].Material); - - if(ReadChunkTRIS(file,InNode ,MeshBuffer, Vertices_Start)==false) - return false; - - MeshBuffer->recalculateBoundingBox(); - - if (!NormalsInFile && MeshBuffer->Material.Lighting) // No point wasting time of lightmapped levels - { - s32 i; - - for ( i=0; i<(s32)MeshBuffer->Indices.size(); i+=3) - { - core::plane3d p( MeshBuffer->getVertex(MeshBuffer->Indices[i+0])->Pos, - MeshBuffer->getVertex(MeshBuffer->Indices[i+1])->Pos, - MeshBuffer->getVertex(MeshBuffer->Indices[i+2])->Pos); - - MeshBuffer->getVertex(MeshBuffer->Indices[i+0])->Normal += p.Normal; - MeshBuffer->getVertex(MeshBuffer->Indices[i+1])->Normal += p.Normal; - MeshBuffer->getVertex(MeshBuffer->Indices[i+2])->Normal += p.Normal; - } - - for ( i = 0; i<(s32)MeshBuffer->getVertexCount(); ++i ) - { - MeshBuffer->getVertex(i)->Normal.normalize (); - BaseVertices[Vertices_Start+i]->Normal=MeshBuffer->getVertex(i)->Normal; - } - } - - Buffers.push_back(MeshBuffer); - - } - - if (!read) - { - os::Printer::log("Unknown chunk found in mesh - skipping"); - file->seek( (B3dStack.getLast().startposition + B3dStack.getLast().length) , false); - B3dStack.erase(B3dStack.size()-1); - } - } - - - B3dStack.erase(B3dStack.size()-1); - - return true; -} - -/* -VRTS: - int flags ;1=normal values present, 2=rgba values present - int tex_coord_sets ;texture coords per vertex (eg: 1 for simple U/V) max=8 - int tex_coord_set_size ;components per set (eg: 2 for simple U/V) max=4 - { - float x,y,z ;always present - float nx,ny,nz ;vertex normal: present if (flags&1) - float red,green,blue,alpha ;vertex color: present if (flags&2) - float tex_coords[tex_coord_sets][tex_coord_set_size] ;tex coords - } -*/ - -bool CAnimatedMeshB3d::ReadChunkVRTS(io::IReadFile* file, SB3dNode *InNode, SB3DMeshBuffer *MeshBuffer,s32 Vertices_Start) -{ - - s32 flags, tex_coord_sets, tex_coord_set_size; - - file->read(&flags, sizeof(flags)); - file->read(&tex_coord_sets, sizeof(tex_coord_sets)); - file->read(&tex_coord_set_size, sizeof(tex_coord_set_size)); - - #ifdef __BIG_ENDIAN__ - flags = os::Byteswap::byteswap(flags); - tex_coord_sets = os::Byteswap::byteswap(tex_coord_sets); - tex_coord_set_size = os::Byteswap::byteswap(tex_coord_set_size); - #endif - - if (tex_coord_sets >= 3 || tex_coord_set_size >= 4) // Something is wrong - { - os::Printer::log("tex_coord_sets or tex_coord_set_size too big", file->getFileName(), ELL_ERROR); - return false; - } - - //------ Allocate Memory, for speed -----------// - - s32 MemoryNeeded = B3dStack.getLast().length / sizeof(f32); - s32 NumberOfReads = 3; - - if (flags & 1) NumberOfReads += 3; - if (flags & 2) NumberOfReads += 4; - - for (s32 i=0; i file->getPos()) // this chunk repeats - { - f32 x=0.0f, y=0.0f, z=0.0f; - f32 nx=0.0f, ny=0.0f, nz=0.0f; - f32 red=1.0f, green=1.0f, blue=1.0f, alpha=1.0f; - f32 tex_coords[3][4]; - - file->read(&x, sizeof(x)); - file->read(&y, sizeof(y)); - file->read(&z, sizeof(z)); - - if (flags & 1) - { - NormalsInFile = true; - file->read(&nx, sizeof(nx)); - file->read(&ny, sizeof(ny)); - file->read(&nz, sizeof(nz)); - } - - if (flags & 2) - { - file->read(&red, sizeof(red)); - file->read(&green, sizeof(green)); - file->read(&blue, sizeof(blue)); - file->read(&alpha, sizeof(alpha)); - } - - for (s32 i=0; iread(&tex_coords[i][j], sizeof(f32)); - - #ifdef __BIG_ENDIAN__ - x = os::Byteswap::byteswap(x); - y = os::Byteswap::byteswap(y); - z = os::Byteswap::byteswap(z); - - if (flags&1) - { - nx = os::Byteswap::byteswap(nx); - ny = os::Byteswap::byteswap(ny); - nz = os::Byteswap::byteswap(nz); - } - - if (flags & 2) - { - red = os::Byteswap::byteswap(red); - green = os::Byteswap::byteswap(green); - blue = os::Byteswap::byteswap(blue); - alpha = os::Byteswap::byteswap(alpha); - } - - for (s32 i=0; i<=tex_coord_sets-1; i++) - for (s32 j=0; j<=tex_coord_set_size-1; j++) - tex_coords[i][j] = os::Byteswap::byteswap(tex_coords[i][j]); - #endif - - f32 tu=0.0f, tv=0.0f; - - if (tex_coord_sets >= 1 && tex_coord_set_size >= 2) - { - tu=tex_coords[0][0]; - tv=tex_coords[0][1]; - } - - f32 tu2=0.0f, tv2=0.0f; - - if (tex_coord_sets>=2 && tex_coord_set_size>=2) - { - tu2=tex_coords[1][0]; - tv2=tex_coords[1][1]; - } - - // Create Vertex... - video::S3DVertex2TCoords *Vertex=new video::S3DVertex2TCoords - (x, y, z, video::SColorf(red, green, blue, alpha).toSColor(), tu, tv, tu2, tv2); - //video::S3DVertex *Vertex=new video::S3DVertex - // (x, y, z, nx, ny, nz, video::SColorf(red, green, blue, alpha).toSColor(), tu, tv); - - Vertex->Normal = core::vector3df(nx, ny, nz); // should this be effected by the Node's Global Matrix (eg rotation)? - - // Transform the Vertex position by nested node... - core::matrix4 VertexMatrix; - VertexMatrix.setTranslation(Vertex->Pos); - - //Vertices_GlobalPosition.push_back(Vertex->Pos); - - //Normal_GlobalRotation.push_back(Vertex->Normal); - - VertexMatrix=InNode->GlobalMatrix*VertexMatrix; - Vertex->Pos=VertexMatrix.getTranslation(); - - - //Add it... - - BaseVertices.push_back(Vertex); - - Vertices_Moved.push_back(false); - AnimatedVertices_VertexID.push_back(-1); - AnimatedVertices_MeshBuffer.push_back(0); - Vertices_Alpha.push_back(alpha); - } - - B3dStack.erase(B3dStack.size()-1); - - return true; -} - - -bool CAnimatedMeshB3d::ReadChunkTRIS(io::IReadFile* file, SB3dNode *InNode, SB3DMeshBuffer *MeshBuffer,s32 Vertices_Start) -{ - - s32 triangle_brush_id; // Note: Irrlicht can't have different brushes for each triangle (I'm using a workaround) - - file->read(&triangle_brush_id, sizeof(triangle_brush_id)); - - #ifdef __BIG_ENDIAN__ - triangle_brush_id = os::Byteswap::byteswap(triangle_brush_id); - #endif - - SB3dMaterial *B3dMaterial; - - if (triangle_brush_id != -1) - B3dMaterial = &Materials[triangle_brush_id]; - else - B3dMaterial = 0; - - if (B3dMaterial) - MeshBuffer->Material = (*B3dMaterial->Material); - - s32 MemoryNeeded = B3dStack.getLast().length / sizeof(s32); - - MeshBuffer->Indices.reallocate(MemoryNeeded + MeshBuffer->Indices.size() + 1); - - while(B3dStack.getLast().startposition + B3dStack.getLast().length > file->getPos()) // this chunk repeats - { - s32 vertex_id[3]; - - file->read(&vertex_id[0], sizeof(s32)); - file->read(&vertex_id[1], sizeof(s32)); - file->read(&vertex_id[2], sizeof(s32)); - - #ifdef __BIG_ENDIAN__ - vertex_id[0] = os::Byteswap::byteswap(vertex_id[0]); - vertex_id[1] = os::Byteswap::byteswap(vertex_id[1]); - vertex_id[2] = os::Byteswap::byteswap(vertex_id[2]); - #endif - - - vertex_id[0] += Vertices_Start; - vertex_id[1] += Vertices_Start; - vertex_id[2] += Vertices_Start; - - for(s32 i=0; i<3; ++i) - { - if (AnimatedVertices_VertexID[ vertex_id[i] ] == -1) - { - if (BaseVertices[ vertex_id[i] ]->TCoords2 != core::vector2d(0,0)) - { - MeshBuffer->MoveTo_2TCoords(); - } - - - if (MeshBuffer->VertexType == video::EVT_STANDARD) - MeshBuffer->Vertices_Standard.push_back( *((video::S3DVertex*)BaseVertices[ vertex_id[i] ] ) ); - else - MeshBuffer->Vertices_2TCoords.push_back(*BaseVertices[ vertex_id[i] ] ); - - AnimatedVertices_VertexID[ vertex_id[i] ] = MeshBuffer->getVertexCount()-1; - AnimatedVertices_MeshBuffer[ vertex_id[i] ] = MeshBuffer; - - // Apply Material... - irr::video::S3DVertex *Vertex=MeshBuffer->getVertex(MeshBuffer->getVertexCount()-1); - - - if (Vertices_Alpha[ vertex_id[i] ] != 1.0f) - Vertex->Color.setAlpha( (s32)(Vertices_Alpha[ vertex_id[i] ] * 255.0f) ); - else if (B3dMaterial) - Vertex->Color.setAlpha( (s32)(B3dMaterial->alpha * 255.0f) ); - - if (B3dMaterial) - { - // A bit of a hack, there - if (B3dMaterial->Textures[0]) - { - Vertex->TCoords.X *=B3dMaterial->Textures[0]->Xscale; - Vertex->TCoords.Y *=B3dMaterial->Textures[0]->Yscale; - } - - /* - if (B3dMaterial->Textures[1]) - { - Vertex->TCoords2.X *=B3dMaterial->Textures[1]->Xscale; - Vertex->TCoords2.Y *=B3dMaterial->Textures[1]->Yscale; - } - */ - - } - - - } - } - - MeshBuffer->Indices.push_back( AnimatedVertices_VertexID[ vertex_id[0] ] ); - MeshBuffer->Indices.push_back( AnimatedVertices_VertexID[ vertex_id[1] ] ); - MeshBuffer->Indices.push_back( AnimatedVertices_VertexID[ vertex_id[2] ] ); - } - - B3dStack.erase(B3dStack.size()-1); - - return true; -} - -bool CAnimatedMeshB3d::ReadChunkNODE(io::IReadFile* file, SB3dNode *InNode) -{ - - core::stringc NodeName = readString(file); - - f32 position[3]; - f32 scale[3]; - f32 rotation[4]; - - s32 n; - - for (n=0; n<=2; n++) - file->read(&position[n], sizeof(f32)); - - for (n=0; n<=2; n++) - file->read(&scale[n], sizeof(f32)); - - for (n=0; n<=3; n++) - file->read(&rotation[n], sizeof(f32)); - - #ifdef __BIG_ENDIAN__ - for (n=0; n<=2; n++) - position[n] = os::Byteswap::byteswap(position[n]); - - for (n=0; n<=2; n++) - scale[n] = os::Byteswap::byteswap(scale[n]); - - for (n=0; n<=3; n++) - rotation[n] = os::Byteswap::byteswap(rotation[n]); - #endif - - - SB3dNode *Node = new SB3dNode(); - Node->Name = NodeName; - - Node->Animate = true; - Node->AnimatingPositionKeys = false; - Node->AnimatingScaleKeys = false; - Node->AnimatingRotationKeys = false; - Node->HasScaleAnimation = false; - - Node->position = core::vector3df(position[0],position[1],position[2]); - Node->scale = core::vector3df(scale[0],scale[1],scale[2]); - Node->rotation = core::quaternion(rotation[1], rotation[2], rotation[3], rotation[0]); // meant to be in this order - Node->Animatedposition = Node->position; - Node->Animatedscale = Node->scale; - Node->Animatedrotation = Node->rotation; - - irr::core::matrix4 positionMatrix; - positionMatrix.setTranslation(Node->position); - irr::core::matrix4 scaleMatrix; - scaleMatrix.setScale(Node->scale); - irr::core::matrix4 rotationMatrix = Node->rotation.getMatrix(); - Node->LocalMatrix = positionMatrix * rotationMatrix * scaleMatrix; - Node->LocalAnimatedMatrix = Node->LocalMatrix; //For non-animated meshes - - if (!InNode) - { - Node->GlobalMatrix = Node->LocalMatrix; - RootNodes.push_back(Node); - } - else - { - Node->GlobalMatrix = InNode->GlobalMatrix * Node->LocalMatrix; - } - - Node->GlobalInversedMatrix = Node->GlobalMatrix; - Node->GlobalInversedMatrix.makeInverse(); // slow - - Nodes.push_back(Node); - - if (InNode != 0) - InNode->Nodes.push_back(Node); - - while(B3dStack.getLast().startposition + B3dStack.getLast().length > file->getPos()) // this chunk repeats - { - B3dStack.push_back(B3dChunk()); - - B3dChunkHeader header; - file->read(&header, sizeof(header)); - - #ifdef __BIG_ENDIAN__ - header.size = os::Byteswap::byteswap(header.size); - #endif - - B3dStack.getLast().name[0] = header.name[0]; - B3dStack.getLast().name[1] = header.name[1]; //Not sure of an easier way - B3dStack.getLast().name[2] = header.name[2]; - B3dStack.getLast().name[3] = header.name[3]; - B3dStack.getLast().length = header.size+8; - B3dStack.getLast().startposition = file->getPos() - 8; - - bool read = false; - - if ( strncmp( B3dStack.getLast().name, "NODE", 4 ) == 0 ) - { - read = true; - if (!ReadChunkNODE(file, Node)) - return false; - } - else if ( strncmp( B3dStack.getLast().name, "MESH", 4 ) == 0 ) - { - read = true; - if (!ReadChunkMESH(file,Node)) - return false; - } - else if ( strncmp( B3dStack.getLast().name, "ANIM", 4 ) == 0 ) - { - read = true; - if (!ReadChunkANIM(file,Node)) - return false; - } - else if ( strncmp( B3dStack.getLast().name, "BONE", 4 ) == 0 ) - { - read = true; - if (!ReadChunkBONE(file,Node)) - return false; - } - else if ( strncmp( B3dStack.getLast().name, "KEYS", 4 ) == 0 ) - { - read = true; - if(!ReadChunkKEYS(file,Node)) - return false; - } - - if (!read) - { - os::Printer::log("Unknown chunk found in node - skipping"); - file->seek( (B3dStack.getLast().startposition + B3dStack.getLast().length), false); - B3dStack.erase(B3dStack.size()-1); - } - } - - B3dStack.erase(B3dStack.size()-1); - - return true; -} - - - - -bool CAnimatedMeshB3d::ReadChunkBONE(io::IReadFile* file, SB3dNode *InNode) -{ - - if (B3dStack.getLast().length > 8) - { - while(B3dStack.getLast().startposition + B3dStack.getLast().length>file->getPos()) // this chunk repeats - { - SB3dBone Bone; - - file->read(&Bone.vertex_id, sizeof(Bone.vertex_id)); - file->read(&Bone.weight, sizeof(Bone.weight)); - - #ifdef __BIG_ENDIAN__ - Bone.vertex_id = os::Byteswap::byteswap(Bone.vertex_id); - Bone.weight = os::Byteswap::byteswap(Bone.weight); - #endif - - if (Bone.weight != 0 || Bone.weight < 0) - { - HasBones = true; - InNode->Bones.push_back(Bone); - } - - } - } - - B3dStack.erase(B3dStack.size()-1); - return true; -} - - - - -bool CAnimatedMeshB3d::ReadChunkKEYS(io::IReadFile* file, SB3dNode *InNode) -{ - - s32 flags; - file->read(&flags, sizeof(flags)); - #ifdef __BIG_ENDIAN__ - flags = os::Byteswap::byteswap(flags); - #endif - - while(B3dStack.getLast().startposition + B3dStack.getLast().length>file->getPos()) //this chunk repeats - { - - if (flags & 2) //scale - InNode->HasScaleAnimation = true; - - s32 frame; - - f32 positionData[3]; - f32 scaleData[3]; - f32 rotationData[4]; - - file->read(&frame, sizeof(frame)); - - if (flags&1) - readFloats(file, positionData, 3); - - if (flags&2) - readFloats(file, scaleData, 3); - - if (flags&4) - readFloats(file, rotationData, 4); - - #ifdef __BIG_ENDIAN__ - frame = os::Byteswap::byteswap(frame); - #endif - - frame *= 100; // Scale the animation frames up - - core::vector3df position = core::vector3df(positionData[0], positionData[1], positionData[2]); - core::vector3df scale = core::vector3df(scaleData[0], scaleData[1], scaleData[2]); - core::quaternion rotation = core::quaternion(rotationData[1], rotationData[2], rotationData[3], rotationData[0]); // meant to be in this order - - - // Workout what types of keys need to animate - - if (InNode->PositionKeys.size() > 0) - if (flags&1 && InNode->Animatedposition != position) - InNode->AnimatingPositionKeys = true; - - if (InNode->ScaleKeys.size() > 0) - if (flags&2 && InNode->Animatedscale != scale) - InNode->AnimatingScaleKeys = true; - - if (InNode->RotationKeys.size() > 0) - { - if (flags & 4) - { - if (InNode->Animatedrotation.W != rotation.W - || InNode->Animatedrotation.X != rotation.X - || InNode->Animatedrotation.Y != rotation.Y - || InNode->Animatedrotation.Z != rotation.Z) - { - InNode->AnimatingRotationKeys = true; - } - } - } - - if (flags & 1) - InNode->Animatedposition = position; - - if (flags & 2) - InNode->Animatedscale = scale; - - if (flags & 4) - InNode->Animatedrotation = rotation; - - - // Add key frame - - if (flags & 1) - { - SB3dPositionKey Key; - Key.frame = frame; - Key.position = position; - InNode->PositionKeys.push_back(Key); - } - if (flags & 2) - { - SB3dScaleKey Key; - Key.frame = frame; - Key.scale=scale; - InNode->ScaleKeys.push_back(Key); - } - if (flags & 4) - { - SB3dRotationKey Key; - Key.frame = frame; - Key.rotation = rotation; - InNode->RotationKeys.push_back(Key); - } - - } - - B3dStack.erase(B3dStack.size()-1); - return true; -} - - -bool CAnimatedMeshB3d::ReadChunkANIM(io::IReadFile* file, SB3dNode *InNode) -{ - - file->read(&AnimFlags, sizeof(s32)); - file->read(&AnimFrames, sizeof(s32)); - readFloats(file, &AnimFPS, 1); - - #ifdef __BIG_ENDIAN__ - AnimFlags = os::Byteswap::byteswap(AnimFlags); - AnimFrames = os::Byteswap::byteswap(AnimFrames); - #endif - - AnimFrames*=100; - - totalTime=(f32)AnimFrames; - HasAnimation = 1; - lastCalculatedFrame = -1; - - B3dStack.erase(B3dStack.size()-1); - return true; -} - - - -bool CAnimatedMeshB3d::loadFile(io::IReadFile* file) -{ - if (!file) - return false; - - totalTime = 0; - HasAnimation = 0; - - HasBones = 0; - lastCalculatedFrame = -1; - lastAnimateMode = -1; - - AnimFlags = 0; // Unused for now - AnimFrames = 1; // how many frames in anim - AnimFPS = 0.0f; - - AnimateNormals = false; - - InterpolationMode = 1; // Set linear interpolation animation - AnimateMode = 3; // Update both the nodes and the skin in animation - - B3dChunkHeader header; - - file->read(&header, sizeof(header)); - - #ifdef __BIG_ENDIAN__ - header.size = os::Byteswap::byteswap(header.size); - #endif - - if ( strncmp( header.name, "BB3D", 4 ) != 0 ) - { - os::Printer::log("File is not a b3d file. Loading failed", file->getFileName(), ELL_ERROR); - return false; - } - - // header Chunk size here - - B3dStack.clear(); - - B3dStack.push_back(B3dChunk()); - B3dStack.getLast().name[0] = header.name[0]; - B3dStack.getLast().name[1] = header.name[1]; - B3dStack.getLast().name[2] = header.name[2]; - B3dStack.getLast().name[3] = header.name[3]; - B3dStack.getLast().startposition = file->getPos()-8; - B3dStack.getLast().length = header.size+8; - - //Get file version... - - u32 FileVersion; - file->read(&FileVersion, sizeof(FileVersion)); - #ifdef __BIG_ENDIAN__ - FileVersion = os::Byteswap::byteswap(FileVersion); - #endif - - while (B3dStack.getLast().startposition + B3dStack.getLast().length > file->getPos()) - { - - B3dStack.push_back(B3dChunk()); - - file->read(&header, sizeof(header)); - - #ifdef __BIG_ENDIAN__ - header.size = os::Byteswap::byteswap(header.size); - #endif - - B3dStack.getLast().name[0] = header.name[0]; - B3dStack.getLast().name[1] = header.name[1]; - B3dStack.getLast().name[2] = header.name[2]; - B3dStack.getLast().name[3] = header.name[3]; - B3dStack.getLast().startposition = file->getPos() - 8; - B3dStack.getLast().length = header.size + 8; - - bool read = false; - - if ( strncmp( B3dStack.getLast().name, "TEXS", 4 ) == 0 ) - { - read = true; - if (!ReadChunkTEXS(file)) - return false; - } - else if ( strncmp( B3dStack.getLast().name, "BRUS", 4 ) == 0 ) - { - read = true; - if (!ReadChunkBRUS(file)) - return false; - } - else if ( strncmp( B3dStack.getLast().name, "NODE", 4 ) == 0 ) - { - read = true; - if (!ReadChunkNODE(file, (SB3dNode*)0) ) - return false; - } - - if (!read) - { - os::Printer::log("Unknown chunk found in mesh base - skipping"); - - file->seek( (B3dStack.getLast().startposition + B3dStack.getLast().length) , false); - - B3dStack.erase(B3dStack.size()-1); - - } - } - - B3dStack.clear(); - - if (HasBones) - normalizeWeights(); - - - // Get BoundingBox... - if (Buffers.empty()) - BoundingBox.reset(0,0,0); - else - { - BoundingBox.reset(Buffers[0]->BoundingBox.MaxEdge); - for (s32 i=0; i<(s32)Buffers.size(); ++i) - { - BoundingBox.addInternalBox(Buffers[i]->BoundingBox); - } - } - - // For skinning - for (s32 i=0; i<(s32)Nodes.size(); ++i) - { - SB3dNode *Node = Nodes[i]; - for (s32 j=0; j<(s32)Node->Bones.size(); ++j) - { - Node->Bones[j].pos = BaseVertices[Node->Bones[j].vertex_id]->Pos; - Node->Bones[j].normal = BaseVertices[Node->Bones[j].vertex_id]->Normal; - Node->Bones[j].vertex = - AnimatedVertices_MeshBuffer[ Node->Bones[j].vertex_id ]->getVertex( - AnimatedVertices_VertexID[ Node->Bones[j].vertex_id ] ); - } - } - - return true; -} - - - - - - - -void CAnimatedMeshB3d::normalizeWeights() -{ - - // Normalise the weights on bones - - s32 i; - core::array Vertices_TotalWeight; - - Vertices_TotalWeight.set_used(BaseVertices.size()); - - for (i=0; i<(s32)Vertices_TotalWeight.size(); ++i) - Vertices_TotalWeight[i] = 0; - - for (i=0; i<(s32)Nodes.size(); ++i) - { - SB3dNode *Node=Nodes[i]; - for (s32 j=0; j<(s32)Node->Bones.size(); ++j) - Vertices_TotalWeight[ Node->Bones[j].vertex_id ] += Node->Bones[j].weight; - } - - for (i=0; i<(s32)Nodes.size(); ++i) - { - SB3dNode *Node=Nodes[i]; - for (s32 j=0; j<(s32)Node->Bones.size(); ++j) - { - f32 total = Vertices_TotalWeight[ Node->Bones[j].vertex_id ]; - if (total != 0 && total != 1) - Node->Bones[j].weight /= total; - } - } -} - - - - -//! returns the amount of frames in milliseconds. If the amount is 1, it is a static (=non animated) mesh. -s32 CAnimatedMeshB3d::getFrameCount() -{ - return AnimFrames; -} - -//! returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail. Note, that some Meshes will ignore the detail level. -IMesh* CAnimatedMeshB3d::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop) -{ - animate(frame,startFrameLoop, endFrameLoop); - return this; -} - -//! Returns a pointer to a transformation matrix of a part of the -//! mesh based on a frame time. -core::matrix4* CAnimatedMeshB3d::getMatrixOfJoint(s32 jointNumber, s32 frame) -{ - if (!HasAnimation || jointNumber < 0 || jointNumber >= (s32)Nodes.size()) - return 0; - - return &Nodes[jointNumber]->GlobalAnimatedMatrix; -} - -core::matrix4* CAnimatedMeshB3d::getLocalMatrixOfJoint(s32 jointNumber) -{ - if (!HasAnimation || jointNumber < 0 || jointNumber >= (s32)Nodes.size()) - return 0; - - return &Nodes[jointNumber]->LocalMatrix; -} - - -core::matrix4* CAnimatedMeshB3d::getMatrixOfJointUnanimated(s32 jointNumber) -{ - if (!HasAnimation || jointNumber < 0 || jointNumber >= (s32)Nodes.size()) - return 0; - - return &Nodes[jointNumber]->GlobalMatrix; -} - -//! Gets joint count. -s32 CAnimatedMeshB3d::getJointCount() const -{ - return Nodes.size(); -} - - -//! Gets the name of a joint. -void CAnimatedMeshB3d::setJointAnimation(s32 jointNumber, bool On) -{ - if (jointNumber < 0 || jointNumber >= (s32)Nodes.size()) - return; - Nodes[jointNumber]->Animate = On; -} - - -//! Gets the name of a joint. -const c8* CAnimatedMeshB3d::getJointName(s32 number) const -{ - if (number < 0 || number >= (s32)Nodes.size()) - return 0; - return Nodes[number]->Name.c_str(); -} - - - -//! Gets a joint number from its name -s32 CAnimatedMeshB3d::getJointNumber(const c8* name) const -{ - for (s32 i=0; i<(s32)Nodes.size(); ++i) - if (Nodes[i]->Name == name) - return i; - - return -1; -} - - -void CAnimatedMeshB3d::CalculateGlobalMatrixes(SB3dNode *Node,SB3dNode *ParentNode) -{ - if (!Node && ParentNode) // bit of protection from endless loops - return; - - if (!Node) - { - for (s32 i=0; i<(s32)RootNodes.size(); ++i) - CalculateGlobalMatrixes(RootNodes[i],0); - return; - } - - if (!ParentNode) - Node->GlobalAnimatedMatrix = Node->LocalAnimatedMatrix; - else - Node->GlobalAnimatedMatrix = ParentNode->GlobalAnimatedMatrix * Node->LocalAnimatedMatrix; - - for (s32 j=0; j<(s32)Node->Nodes.size(); ++j) - CalculateGlobalMatrixes(Node->Nodes[j],Node); -} - - -void CAnimatedMeshB3d::animateSkin(f32 frame,f32 startFrame, f32 endFrame,SB3dNode *Node,SB3dNode *ParentNode) -{ - // Get animated matrix... - if (!ParentNode) - Node->GlobalAnimatedMatrix = Node->LocalAnimatedMatrix; - else - Node->GlobalAnimatedMatrix = ParentNode->GlobalAnimatedMatrix * Node->LocalAnimatedMatrix; - - if (Node->Bones.size()) - { - core::matrix4 VerticesMatrixMove(core::matrix4::EM4CONST_NOTHING); - VerticesMatrixMove.setbyproduct(Node->GlobalAnimatedMatrix,Node->GlobalInversedMatrix); - core::vector3df ThisVertexMove, ThisNormalMove; - SB3dBone *Bone; - - //__ Skin Vertex's Normals __// - if (AnimateNormals) - { - for (u32 i=0; iBones.size(); ++i) - { - Bone=&Node->Bones[i]; - //Transform normal... - //Normal_Rotation=&Base_Vertex->Normal; - ThisNormalMove.X = Bone->normal.X*VerticesMatrixMove[0] + Bone->normal.Y*VerticesMatrixMove[4] + Bone->normal.Z*VerticesMatrixMove[8]; - ThisNormalMove.Y = Bone->normal.X*VerticesMatrixMove[1] + Bone->normal.Y*VerticesMatrixMove[5] + Bone->normal.Z*VerticesMatrixMove[9]; - ThisNormalMove.Z = Bone->normal.X*VerticesMatrixMove[2] + Bone->normal.Y*VerticesMatrixMove[6] + Bone->normal.Z*VerticesMatrixMove[10]; - - if (!Vertices_Moved[Bone->vertex_id]) - Bone->vertex->Normal = ThisNormalMove*Bone->weight; - else - Bone->vertex->Normal = Bone->vertex->Normal + (ThisNormalMove * Bone->weight); - } - } - - - //__ Skin Vertex's Position __// - for (u32 i=0; iBones.size(); ++i) - { - Bone=&Node->Bones[i]; - - // Transform vector... - ThisVertexMove.X = VerticesMatrixMove[0]*Bone->pos.X + VerticesMatrixMove[4]*Bone->pos.Y + VerticesMatrixMove[8]*Bone->pos.Z + VerticesMatrixMove[12]; - ThisVertexMove.Y = VerticesMatrixMove[1]*Bone->pos.X + VerticesMatrixMove[5]*Bone->pos.Y + VerticesMatrixMove[9]*Bone->pos.Z + VerticesMatrixMove[13]; - ThisVertexMove.Z = VerticesMatrixMove[2]*Bone->pos.X + VerticesMatrixMove[6]*Bone->pos.Y + VerticesMatrixMove[10]*Bone->pos.Z + VerticesMatrixMove[14]; - - if (!Vertices_Moved[Bone->vertex_id]) - { - Vertices_Moved[Bone->vertex_id] = true; - Bone->vertex->Pos = ThisVertexMove * Bone->weight; - } - else - { - Bone->vertex->Pos = Bone->vertex->Pos + (ThisVertexMove*Bone->weight); - } - } - - } - - - for (s32 j=0; j<(s32)Node->Nodes.size(); ++j) - animateSkin(frame, startFrame, endFrame, Node->Nodes[j], Node); - -} - - - -void CAnimatedMeshB3d::getNodeAnimation(f32 frame,SB3dNode *Node,core::vector3df &position, core::vector3df &scale, core::quaternion &rotation) -{ - - bool foundPosition = false; - bool foundScale = false; - bool foundRotation = false; - - s32 LastPosition = -1; - s32 LastScale = -1; - s32 LastRotation = -1; - - s32 j, k; - - if (Node->AnimatingPositionKeys) - { - j=0; - for (k=0; k < (s32)Node->PositionKeys.size(); k += 40) - { - if (Node->PositionKeys[k].frame < frame) - j=k; - else - break; - } - - for (; j<(s32)Node->PositionKeys.size(); j++) - { - SB3dPositionKey *Key=&Node->PositionKeys[j]; - if (Key->frame >= frame) - { - if (InterpolationMode == 0) - { - // Constant interpolate... - if (LastPosition != -1) - position = Node->PositionKeys[LastPosition].position; - else - position = Key->position; - - } - else if (InterpolationMode == 1) - { - //Linear interpolate... - if (LastPosition == -1) - position = Key->position; - else - { - SB3dPositionKey *LastKey = &Node->PositionKeys[LastPosition]; - if (Key->position == LastKey->position) - position = Key->position; - else - { - f32 fd1 = frame-LastKey->frame; - f32 fd2 = Key->frame-frame; - position = ((Key->position-LastKey->position)/(fd1+fd2))*fd1 + LastKey->position; - } - } - } - foundPosition = true; - break; - } - LastPosition = j; - - } - if (!foundPosition && LastPosition != -1) - position = Node->PositionKeys[LastPosition].position; - } - - - - if (Node->AnimatingRotationKeys) - { - - j=0; - for (k=0; k<(s32)Node->RotationKeys.size(); k += 40) - { - if (Node->RotationKeys[k].frame < frame) - j=k; - else - break; - } - - for (; j<(s32)Node->RotationKeys.size(); ++j) - { - SB3dRotationKey *Key = &Node->RotationKeys[j]; - - if (Key->frame >= frame) - { - if (InterpolationMode == 0) - { - // Constant interpolate... - if (LastRotation != -1) - rotation = Node->RotationKeys[LastRotation].rotation; - else - rotation = Key->rotation; - } - else if (InterpolationMode == 1) - { - // Linear interpolate... - - if (LastRotation == -1) - rotation = Key->rotation; - else - { - SB3dRotationKey *LastKey=&Node->RotationKeys[LastRotation]; - if (Key->rotation == LastKey->rotation) - rotation = Key->rotation; - else - { - f32 fd1 = frame-LastKey->frame; - f32 fd2 = Key->frame - frame; - f32 t = (1.0f/(fd1+fd2))*fd1; - rotation.slerp(LastKey->rotation, Key->rotation, t); - } - } - } - foundRotation = true; - break; - } - LastRotation = j; - - } - if (!foundRotation && LastRotation != -1) - rotation = Node->RotationKeys[LastRotation].rotation; - } - - if (Node->AnimatingScaleKeys) - { - j=0; - for (k=0; k<(s32)Node->ScaleKeys.size(); k+=40) - { - if (Node->ScaleKeys[k].frame < frame) - j = k; - else - break; - } - - for (; j<(s32)Node->ScaleKeys.size(); j++) - { - SB3dScaleKey *Key = &Node->ScaleKeys[j]; - - if (Key->frame >= frame) - { - if (InterpolationMode == 0) - { - // Constant interpolate... - if (LastScale != -1) - scale = Node->ScaleKeys[LastScale].scale; - else - scale = Key->scale; - } - else if (InterpolationMode == 1) - { - // Linear interpolate... - - if (LastScale == -1) - scale = Key->scale; - else - { - SB3dScaleKey *LastKey = &Node->ScaleKeys[LastScale]; - if (Key->scale == LastKey->scale) - scale = Key->scale; - else - { - f32 fd1 = frame-LastKey->frame; - f32 fd2 = Key->frame - frame; - scale = (((Key->scale-LastKey->scale)/(fd1+fd2))*fd1) + LastKey->scale; - } - } - } - foundScale = true; - break; - } - LastScale = j; - - } - if (!foundScale && LastScale != -1) - scale = Node->ScaleKeys[LastScale].scale; - } - - -} - - - -void CAnimatedMeshB3d::animateNodes(f32 frame,f32 startFrame, f32 endFrame) -{ - for (s32 i=0; i<(s32)Nodes.size(); ++i) - { - SB3dNode *Node = Nodes[i]; - - if (Node->Animate) - { - - //Get keyframe... - core::vector3df position = Node->position; - core::vector3df scale = Node->scale; - core::quaternion rotation = Node->rotation; - - getNodeAnimation(frame, Node, position, scale, rotation); - - Node->Animatedposition = position; - Node->Animatedscale = scale; - Node->Animatedrotation = rotation; - - core::matrix4 positionMatrix; - positionMatrix.setTranslation(Node->Animatedposition); - - core::matrix4 rotationMatrix; - rotationMatrix = Node->Animatedrotation.getMatrix(); - - if (!Node->HasScaleAnimation) - { - Node->LocalAnimatedMatrix = positionMatrix * rotationMatrix; - } - else - { - core::matrix4 scaleMatrix; - scaleMatrix.setScale(Node->Animatedscale); - Node->LocalAnimatedMatrix = positionMatrix * rotationMatrix * scaleMatrix; - } - - } - } -} - - -void CAnimatedMeshB3d::animate(s32 intframe,s32 startFrameLoop, s32 endFrameLoop)// Why cannot this be "animate(f32 frame)", it would make so much nicer animations -{ - - if ( !HasAnimation || (lastCalculatedFrame == intframe && lastAnimateMode == AnimateMode) ) - return; - - lastCalculatedFrame = intframe; - lastAnimateMode = AnimateMode; - - f32 frame = (f32)intframe; - f32 startFrame = (f32)startFrameLoop; - f32 endFrame = (f32)endFrameLoop; - - - - if (AnimateMode & 1) // Update Nodes - animateNodes(frame, startFrame, endFrame); - - - - if (AnimateMode & 2) // Update skin - { - // Reset skin - s32 i; - for (i=0; i<(s32)Vertices_Moved.size(); ++i) - Vertices_Moved[i]=false; - - for (i=0; i<(s32)RootNodes.size(); ++i) - { - animateSkin(frame, startFrame, endFrame, RootNodes[i], 0); - } - /* - if (AnimateNormals) - { - for (i=0; i<(s32)Nodes.size(); ++i) - { - SB3dNode *Node = Nodes[i]; - for (s32 j=0; j<(s32)Node->Bones.size(); ++j) - { - u16 VertexID = AnimatedVertices_VertexID[ Node->Bones[j].vertex_id ]; - SB3DMeshBuffer *MeshBuffer = AnimatedVertices_MeshBuffer[ Node->Bones[j].vertex_id ]; - video::S3DVertex2TCoords *Vertex = &MeshBuffer->Vertices[VertexID]; - //video::S3DVertex *Vertex = &MeshBuffer->Vertices[VertexID]; - //Vertex->Normal.normalize(); - } - } - } - */ - } - - - -} - - -//! returns amount of mesh buffers. -u32 CAnimatedMeshB3d::getMeshBufferCount() const -{ - return Buffers.size(); -} - - -//! returns pointer to a mesh buffer -IMeshBuffer* CAnimatedMeshB3d::getMeshBuffer(u32 nr) const -{ - if (nr < Buffers.size()) - return Buffers[nr]; - else - return 0; -} - -//! Returns pointer to a mesh buffer which fits a material -IMeshBuffer* CAnimatedMeshB3d::getMeshBuffer( const video::SMaterial &material) const -{ - for (u32 i=0; i < Buffers.size(); ++i) - { - if (Buffers[i]->getMaterial() == material) - return Buffers[i]; - } - return 0; -} - -//! returns an axis aligned bounding box -const core::aabbox3d& CAnimatedMeshB3d::getBoundingBox() const -{ - return BoundingBox; -} - -//! set user axis aligned bounding box -void CAnimatedMeshB3d::setBoundingBox( const core::aabbox3df& box) -{ - BoundingBox = box; -} - -//! sets a flag of all contained materials to a new value -void CAnimatedMeshB3d::setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) -{ - for (s32 i=0; i < (s32)Buffers.size(); ++i) - Buffers[i]->Material.setFlag(flag, newvalue); -} - -//! Returns the type of the animated mesh. -E_ANIMATED_MESH_TYPE CAnimatedMeshB3d::getMeshType() const -{ - return EAMT_B3D; -} - -//!Update Normals when Animating -//!False= Don't (default) -//!True= Update normals, slower -void CAnimatedMeshB3d::updateNormalsWhenAnimating(bool on) -{ - AnimateNormals = on; -} - -//!Sets Interpolation Mode -//!0- Constant -//!1- Linear (default) -void CAnimatedMeshB3d::setInterpolationMode(s32 mode) -{ - InterpolationMode = mode; -} - -//!Want should happen on when animating -//!0-Nothing -//!1-Update nodes only -//!2-Update skin only -//!3-Update both nodes and skin (default) -void CAnimatedMeshB3d::setAnimateMode(s32 mode) -{ - AnimateMode = mode; -} - - - - - - -void CAnimatedMeshB3d::recoverJointsFromMesh(core::array &JointChildSceneNodes) -{ - // Note: This function works because of the way the b3d fomat nests nodes, other mesh loaders may need a different function - for (s32 i=0; i<(s32)Nodes.size(); ++i) - { - ISceneNode* node = JointChildSceneNodes[i]; - SB3dNode *B3dNode = Nodes[i]; - node->setPosition( B3dNode->LocalAnimatedMatrix.getTranslation() ); - node->setRotation( B3dNode->LocalAnimatedMatrix.getRotationDegrees() ); - //node->setScale( B3dNode->LocalAnimatedMatrix.getScale() ); - node->updateAbsolutePosition(); // works because of nests nodes - } -} - -void CAnimatedMeshB3d::tranferJointsToMesh(core::array &JointChildSceneNodes) -{ - for (s32 i=0;i<(s32)Nodes.size();++i) - { - ISceneNode* node = JointChildSceneNodes[i]; - SB3dNode *B3dNode = Nodes[i]; - B3dNode->LocalAnimatedMatrix.setTranslation( node->getPosition() ); - B3dNode->LocalAnimatedMatrix.setRotationDegrees( node->getRotation() ); - //B3dNode->LocalAnimatedMatrix.setScale( node->getScale() ); - } - lastCalculatedFrame = -1; -} - -void CAnimatedMeshB3d::createJoints(core::array &JointChildSceneNodes, ISceneNode* AnimatedMeshSceneNode, ISceneManager* SceneManager) -{ - // Note: This function works because of the way the b3d format nests nodes, other mesh loaders may need a different function - createSkelton_Helper(SceneManager, JointChildSceneNodes, AnimatedMeshSceneNode, 0, 0, 0); -} - -void CAnimatedMeshB3d::createSkelton_Helper(ISceneManager* SceneManager, core::array &JointChildSceneNodes, ISceneNode* AnimatedMeshSceneNode, ISceneNode* ParentNode, SB3dNode *ParentB3dNode,SB3dNode *B3dNode) -{ - // Note: This function works because of the way the b3d fomat nests nodes, other mesh loaders may need a different function - if (!ParentNode) - { - for (s32 i=0; i<(s32)RootNodes.size(); ++i) - { - B3dNode = RootNodes[i]; - ISceneNode* node = SceneManager->addEmptySceneNode(AnimatedMeshSceneNode); - JointChildSceneNodes.push_back(node); - for (s32 j=0; j<(s32)B3dNode->Nodes.size(); ++j) - createSkelton_Helper(SceneManager, JointChildSceneNodes, AnimatedMeshSceneNode, node, B3dNode, B3dNode->Nodes[j]); - } - } - else - { - ISceneNode* node = SceneManager->addEmptySceneNode(ParentNode); - JointChildSceneNodes.push_back(node); - for (s32 j=0; j<(s32)B3dNode->Nodes.size(); ++j) - createSkelton_Helper(SceneManager, JointChildSceneNodes, AnimatedMeshSceneNode, node, B3dNode, B3dNode->Nodes[j]); - } -} - - - -void CAnimatedMeshB3d::convertToTangents() -{ - - // now calculate tangents - for (u32 b=0; b < Buffers.size(); ++b) - { - if (Buffers[b]) - { - - Buffers[b]->MoveTo_Tangents(); - - s32 idxCnt = Buffers[b]->getIndexCount(); - - u16* idx = Buffers[b]->getIndices(); - video::S3DVertexTangents* v = - (video::S3DVertexTangents*)Buffers[b]->getVertices(); - - for (s32 i=0; iBones.size(); ++j) - { - Node->Bones[j].pos = BaseVertices[Node->Bones[j].vertex_id]->Pos; - Node->Bones[j].normal = BaseVertices[Node->Bones[j].vertex_id]->Normal; - Node->Bones[j].vertex = - AnimatedVertices_MeshBuffer[ Node->Bones[j].vertex_id ]->getVertex( - AnimatedVertices_VertexID[ Node->Bones[j].vertex_id ] ); - } - } - -} - - - -void CAnimatedMeshB3d::calculateTangents( - core::vector3df& normal, - core::vector3df& tangent, - core::vector3df& binormal, - core::vector3df& vt1, core::vector3df& vt2, core::vector3df& vt3, // vertices - core::vector2df& tc1, core::vector2df& tc2, core::vector2df& tc3) // texture coords -{ - core::vector3df v1 = vt1 - vt2; - core::vector3df v2 = vt3 - vt1; - normal = v2.crossProduct(v1); - normal.normalize(); - - // binormal - - f32 deltaX1 = tc1.X - tc2.X; - f32 deltaX2 = tc3.X - tc1.X; - binormal = (v1 * deltaX2) - (v2 * deltaX1); - binormal.normalize(); - - // tangent - - f32 deltaY1 = tc1.Y - tc2.Y; - f32 deltaY2 = tc3.Y - tc1.Y; - tangent = (v1 * deltaY2) - (v2 * deltaY1); - tangent.normalize(); - - // adjust - - core::vector3df txb = tangent.crossProduct(binormal); - if (txb.dotProduct(normal) < 0.0f) - { - tangent *= -1.0f; - binormal *= -1.0f; - } -} - - - - - - -} // end namespace scene -} // end namespace irr - - diff --git a/source/Irrlicht/CAnimatedMeshB3d.h b/source/Irrlicht/CAnimatedMeshB3d.h deleted file mode 100644 index 1113dea8..00000000 --- a/source/Irrlicht/CAnimatedMeshB3d.h +++ /dev/null @@ -1,504 +0,0 @@ -// Copyright (C) 2002-2007 Nikolaus Gebhardt -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - - -//B3D file loader by Luke Hoschke, File format by Mark Sibly - -#ifndef __C_ANIMATED_MESH_B3D_H_INCLUDED__ -#define __C_ANIMATED_MESH_B3D_H_INCLUDED__ - -#include "IAnimatedMeshB3d.h" -#include "IMesh.h" -#include "IReadFile.h" - -#include "SMeshBuffer.h" -#include "S3DVertex.h" - -#include "irrString.h" -#include "matrix4.h" -#include "quaternion.h" - -namespace irr -{ -namespace video -{ - class IVideoDriver; -} // end namespace video -namespace scene -{ - class CAnimatedMeshB3d : public IAnimatedMeshB3d, public IMesh - { - public: - - //! constructor - CAnimatedMeshB3d(video::IVideoDriver* driver); - - //! destructor - virtual ~CAnimatedMeshB3d(); - - //! loads an B3d file - virtual bool loadFile(io::IReadFile* file); - - //! returns the amount of frames in milliseconds. If the amount is 1, it is a static (=non animated) mesh. - virtual s32 getFrameCount(); - - //! returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail. Note, that some Meshes will ignore the detail level. - virtual IMesh* getMesh(s32 frame, s32 detailLevel=255, s32 startFrameLoop=-1, s32 endFrameLoop=-1); - - //! returns amount of mesh buffers. - virtual u32 getMeshBufferCount() const; - - //! returns pointer to a mesh buffer - virtual IMeshBuffer* getMeshBuffer(u32 nr) const; - - //! Returns pointer to a mesh buffer which fits a material - /** \param material: material to search for - \return Returns the pointer to the mesh buffer or - NULL if there is no such mesh buffer. */ - virtual IMeshBuffer* getMeshBuffer( const video::SMaterial &material) const; - - //! returns an axis aligned bounding box - virtual const core::aabbox3d& getBoundingBox() const; - - //! set user axis aligned bounding box - virtual void setBoundingBox( const core::aabbox3df& box); - - //! sets a flag of all contained materials to a new value - virtual void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue); - - //! Returns the type of the animated mesh. - virtual E_ANIMATED_MESH_TYPE getMeshType() const; - - //! Returns a pointer to a transformation matrix of a part of the - //! mesh based on a frame time. - virtual core::matrix4* getMatrixOfJoint(s32 jointNumber, s32 frame); - - //! Gets joint count. - virtual s32 getJointCount() const; - - //! Gets the name of a joint. - virtual const c8* getJointName(s32 number) const; - - //! Gets a joint number from its name - virtual s32 getJointNumber(const c8* name) const; - - - virtual core::matrix4* getLocalMatrixOfJoint(s32 jointNumber); - - virtual core::matrix4* getMatrixOfJointUnanimated(s32 jointNumber); - - virtual void setJointAnimation(s32 jointNumber, bool On); - - //!Update Normals when Animating - //!False= Don't (default) - //!True= Update normals, slower - virtual void updateNormalsWhenAnimating(bool on); - - - //!Sets Interpolation Mode - //!0- Constant - //!1- Linear (default) - virtual void setInterpolationMode(s32 mode); - - //!Want should happen on when animating - //!0-Nothing - //!1-Update nodes only - //!2-Update skin only - //!3-Update both nodes and skin (default) - virtual void setAnimateMode(s32 mode); - - - //!Convert all mesh buffers to use tangent vertices - virtual void convertToTangents(); - - - - //New Animation System Stuff (WIP)... - virtual void recoverJointsFromMesh(core::array &JointChildSceneNodes); - virtual void tranferJointsToMesh(core::array &JointChildSceneNodes); - virtual void createJoints(core::array &JointChildSceneNodes, ISceneNode* AnimatedMeshSceneNode, ISceneManager* SceneManager); - - - - - -private: - struct SB3DMeshBuffer : public IMeshBuffer - { - SB3DMeshBuffer() - { - #ifdef _DEBUG - setDebugName("SSkinMeshBuffer"); - #endif - } - - ~SB3DMeshBuffer() {}; - - virtual const video::SMaterial& getMaterial() const - { - return Material; - } - - virtual video::SMaterial& getMaterial() - { - return Material; - } - - virtual video::S3DVertex *getVertex(u32 index) - { - if (VertexType==video::EVT_STANDARD) return &Vertices_Standard[index]; - if (VertexType==video::EVT_TANGENTS) return (video::S3DVertex*)&Vertices_Tangents[index]; - return (video::S3DVertex*)&Vertices_2TCoords[index]; - } - - virtual const void* getVertices() const - { - if (VertexType==video::EVT_STANDARD) return Vertices_Standard.const_pointer(); - if (VertexType==video::EVT_TANGENTS) return Vertices_Tangents.const_pointer(); - return Vertices_2TCoords.const_pointer(); - } - - virtual void* getVertices() - { - if (VertexType==video::EVT_STANDARD) return Vertices_Standard.pointer(); - if (VertexType==video::EVT_TANGENTS) return Vertices_Tangents.pointer(); - return Vertices_2TCoords.pointer(); - } - - virtual u32 getVertexCount() const - { - if (VertexType==video::EVT_STANDARD) return Vertices_Standard.size(); - if (VertexType==video::EVT_TANGENTS) return Vertices_Tangents.size(); - return Vertices_2TCoords.size(); - } - - virtual const u16* getIndices() const - { - return Indices.const_pointer(); - } - - virtual u16* getIndices() - { - return Indices.pointer(); - } - - virtual u32 getIndexCount() const - { - return Indices.size(); - } - - virtual const core::aabbox3d& getBoundingBox() const - { - return BoundingBox; - } - - virtual void setBoundingBox( const core::aabbox3df& box) - { - BoundingBox = box; - } - - virtual void recalculateBoundingBox() - { - if (VertexType==video::EVT_STANDARD) - { - if (Vertices_Standard.empty()) - BoundingBox.reset(0,0,0); - else - { - BoundingBox.reset(Vertices_Standard[0].Pos); - for (u32 i=1; i Vertices_Tangents; - core::array Vertices_2TCoords; - core::array Vertices_Standard; - core::array Indices; - core::aabbox3d BoundingBox; - }; - - struct B3dChunk - { - c8 name[4]; - s32 length; - s32 startposition; - }; - - s32 AnimFlags; - s32 AnimFrames; //how many frames in anim - f32 AnimFPS; - - struct SB3dBone - { - s32 vertex_id; - f32 weight; - core::vector3df pos; - core::vector3df normal; - video::S3DVertex *vertex; - }; - - struct SB3dPositionKey - { - s32 frame; - core::vector3df position; - }; - - struct SB3dScaleKey - { - s32 frame; - core::vector3df scale; - }; - - struct SB3dRotationKey - { - s32 frame; - core::quaternion rotation; - }; - - struct SB3dNode - { - core::stringc Name; - - core::vector3df position; - core::vector3df scale; - core::quaternion rotation; - - core::vector3df Animatedposition; - core::vector3df Animatedscale; - core::quaternion Animatedrotation; - - core::matrix4 GlobalAnimatedMatrix; - core::matrix4 LocalAnimatedMatrix; - - core::matrix4 LocalMatrix; - core::matrix4 GlobalMatrix; - core::matrix4 GlobalInversedMatrix; - - bool Animate; //Move this nodes local matrix when animating? - bool AnimatingPositionKeys; - bool AnimatingScaleKeys; - bool AnimatingRotationKeys; - - bool HasScaleAnimation; - - core::array PositionKeys; - core::array ScaleKeys; - core::array RotationKeys; - - core::array Bones; - - core::array Nodes; - - }; - - core::array Nodes; - - core::array RootNodes; - - struct SB3dTexture - { - irr::video::ITexture* Texture; - s32 Flags; - s32 Blend; - f32 Xpos; - f32 Ypos; - f32 Xscale; - f32 Yscale; - f32 Angle; - }; - - struct SB3dMaterial - { - irr::video::SMaterial* Material; - f32 red, green, blue, alpha; - f32 shininess; - s32 blend,fx; - SB3dTexture *Textures[2]; - - }; - - bool ReadChunkTEXS(io::IReadFile* file); - bool ReadChunkBRUS(io::IReadFile* file); - bool ReadChunkMESH(io::IReadFile* file, SB3dNode *InNode); - bool ReadChunkVRTS(io::IReadFile* file, SB3dNode *InNode, SB3DMeshBuffer *MeshBuffer, s32 Vertices_Start); - bool ReadChunkTRIS(io::IReadFile* file, SB3dNode *InNode, SB3DMeshBuffer *MeshBuffer, s32 Vertices_Start); - bool ReadChunkNODE(io::IReadFile* file, SB3dNode *InNode); - bool ReadChunkBONE(io::IReadFile* file, SB3dNode *InNode); - bool ReadChunkKEYS(io::IReadFile* file, SB3dNode *InNode); - bool ReadChunkANIM(io::IReadFile* file, SB3dNode *InNode); - - void normalizeWeights(); - void animate(s32 frame,s32 startFrameLoop, s32 endFrameLoop); - void CalculateGlobalMatrixes(SB3dNode *Node,SB3dNode *ParentNode); - void animateSkin(f32 frame,f32 startFrame, f32 endFrame,SB3dNode *InNode,SB3dNode *ParentNode); - void getNodeAnimation(f32 frame,SB3dNode *Node,core::vector3df &position, core::vector3df &scale, core::quaternion &rotation); - void animateNodes(f32 frame,f32 startFrame, f32 endFrame); - void slerp(core::quaternion A,core::quaternion B,core::quaternion &C,f32 t); - - void calculateTangents(core::vector3df& normal, - core::vector3df& tangent, core::vector3df& binormal, - core::vector3df& vt1, core::vector3df& vt2, core::vector3df& vt3, - core::vector2df& tc1, core::vector2df& tc2, core::vector2df& tc3); - - - void createSkelton_Helper(ISceneManager* SceneManager, core::array &JointChildSceneNodes, ISceneNode *AnimatedMeshSceneNode, ISceneNode* ParentNode, SB3dNode *ParentB3dNode, SB3dNode *B3dNode); - - - - core::array B3dStack; - - f32 totalTime; - bool HasAnimation; - bool HasBones; - - s32 lastCalculatedFrame; - s32 lastAnimateMode; - - bool NormalsInFile; - bool AnimateNormals; - - //0- Constant 1- Linear - s32 InterpolationMode; - - //0-None 1-Update nodes only 2-Update skin only 3-Update both nodes and skin - s32 AnimateMode; - - core::stringc readString(io::IReadFile* file); - core::stringc stripPathString(core::stringc oldstring, bool keepPath); - void readFloats(io::IReadFile* file, f32* vec, u32 count); - - core::aabbox3d BoundingBox; - core::array Materials; - core::array Textures; - - core::array BaseVertices; - - core::array Vertices_Moved; - core::array Vertices_Alpha; - core::array AnimatedVertices_VertexID; - core::array AnimatedVertices_MeshBuffer; - core::array Buffers; - - video::IVideoDriver* Driver; - }; - -} // end namespace scene -} // end namespace irr - -#endif - - diff --git a/source/Irrlicht/CAnimatedMeshMD2.cpp b/source/Irrlicht/CAnimatedMeshMD2.cpp index 0365d3f8..82b27112 100644 --- a/source/Irrlicht/CAnimatedMeshMD2.cpp +++ b/source/Irrlicht/CAnimatedMeshMD2.cpp @@ -2,6 +2,9 @@ // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_MD2_LOADER_ + #include "CAnimatedMeshMD2.h" #include "os.h" #include "SColor.h" @@ -758,3 +761,4 @@ const c8* CAnimatedMeshMD2::getAnimationName(s32 nr) const } // end namespace scene } // end namespace irr +#endif // _IRR_COMPILE_WITH_MD2_LOADER_ diff --git a/source/Irrlicht/CAnimatedMeshMD2.h b/source/Irrlicht/CAnimatedMeshMD2.h index a092b4c8..30703444 100644 --- a/source/Irrlicht/CAnimatedMeshMD2.h +++ b/source/Irrlicht/CAnimatedMeshMD2.h @@ -18,7 +18,7 @@ namespace irr namespace scene { - class CAnimatedMeshMD2 : public IAnimatedMeshMD2, public IMesh + class CAnimatedMeshMD2 : public IAnimatedMeshMD2 { public: @@ -45,7 +45,7 @@ namespace scene //! Returns pointer to a mesh buffer which fits a material /** \param material: material to search for - \return Returns the pointer to the mesh buffer or + \return Returns the pointer to the mesh buffer or NULL if there is no such mesh buffer. */ virtual IMeshBuffer* getMeshBuffer( const video::SMaterial &material) const; @@ -62,18 +62,18 @@ namespace scene virtual E_ANIMATED_MESH_TYPE getMeshType() const; //! Returns frame loop data for a special MD2 animation type. - virtual void getFrameLoop(EMD2_ANIMATION_TYPE, + virtual void getFrameLoop(EMD2_ANIMATION_TYPE, s32& outBegin, s32& outEnd, s32& outFps) const; //! Returns frame loop data for a special MD2 animation type. - virtual bool getFrameLoop(const c8* name, + virtual bool getFrameLoop(const c8* name, s32& outBegin, s32& outEnd, s32& outFps) const; //! Returns amount of md2 animations in this file. virtual s32 getAnimationCount() const; - //! Returns name of md2 animation. - //! \param nr: Zero based index of animation. + //! Returns name of md2 animation. + //! \param nr: Zero based index of animation. virtual const c8* getAnimationName(s32 nr) const; private: diff --git a/source/Irrlicht/CAnimatedMeshMD3.cpp b/source/Irrlicht/CAnimatedMeshMD3.cpp index 4b25d4f8..11e6f1e9 100644 --- a/source/Irrlicht/CAnimatedMeshMD3.cpp +++ b/source/Irrlicht/CAnimatedMeshMD3.cpp @@ -2,6 +2,9 @@ // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_MD3_LOADER_ + #include "CAnimatedMeshMD3.h" #include "os.h" @@ -411,3 +414,4 @@ E_ANIMATED_MESH_TYPE CAnimatedMeshMD3::getMeshType() const } // end namespace scene } // end namespace irr +#endif // _IRR_COMPILE_WITH_MD3_LOADER_ diff --git a/source/Irrlicht/CAnimatedMeshMD3.h b/source/Irrlicht/CAnimatedMeshMD3.h index 1a834258..88eddaee 100644 --- a/source/Irrlicht/CAnimatedMeshMD3.h +++ b/source/Irrlicht/CAnimatedMeshMD3.h @@ -43,6 +43,43 @@ namespace scene virtual const core::aabbox3d& getBoundingBox() const; virtual E_ANIMATED_MESH_TYPE getMeshType() const; + + //link? + + //! returns amount of mesh buffers. + virtual u32 getMeshBufferCount() const + { + return 0; + } + + //! returns pointer to a mesh buffer + virtual IMeshBuffer* getMeshBuffer(u32 nr) const + { + return 0; + } + + //! Returns pointer to a mesh buffer which fits a material + /** \param material: material to search for + \return Returns the pointer to the mesh buffer or + NULL if there is no such mesh buffer. */ + virtual IMeshBuffer* getMeshBuffer( const video::SMaterial &material) const + { + return 0; + } + + virtual void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) + { + return; + } + + //! set user axis aligned bounding box + virtual void setBoundingBox( const core::aabbox3df& box) + { + return; + } + + + private: //! animates one frame inline void Animate (u32 frame); @@ -62,7 +99,7 @@ namespace scene SCacheInfo ( s32 frame = -1, s32 start = -1, s32 end = -1 ) : Frame ( frame ), startFrameLoop ( start ), endFrameLoop ( end ) {} - + bool operator == ( const SCacheInfo &other ) const { return 0 == memcmp ( this, &other, sizeof ( SCacheInfo ) ); diff --git a/source/Irrlicht/CAnimatedMeshMS3D.cpp b/source/Irrlicht/CAnimatedMeshMS3D.cpp deleted file mode 100644 index 2ec76487..00000000 --- a/source/Irrlicht/CAnimatedMeshMS3D.cpp +++ /dev/null @@ -1,751 +0,0 @@ -// Copyright (C) 2002-2007 Nikolaus Gebhardt -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#include "CAnimatedMeshMS3D.h" -#include "os.h" -#include "IVideoDriver.h" -#include "quaternion.h" - -namespace irr -{ -namespace scene -{ - - -// byte-align structures -#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__) -# pragma pack( push, packing ) -# pragma pack( 1 ) -# define PACK_STRUCT -#elif defined( __GNUC__ ) -# define PACK_STRUCT __attribute__((packed)) -#else -# error compiler not supported -#endif - -// File header -struct MS3DHeader -{ - c8 ID[10]; - s32 Version; -} PACK_STRUCT; - -// Vertex information -struct MS3DVertex -{ - u8 Flags; - f32 Vertex[3]; - s8 BoneID; - u8 RefCount; -} PACK_STRUCT; - -// Triangle information -struct MS3DTriangle -{ - u16 Flags; - u16 VertexIndices[3]; - f32 VertexNormals[3][3]; - f32 S[3], T[3]; - u8 SmoothingGroup; - u8 GroupIndex; -} PACK_STRUCT; - -// Material information -struct MS3DMaterial -{ - s8 Name[32]; - f32 Ambient[4]; - f32 Diffuse[4]; - f32 Specular[4]; - f32 Emissive[4]; - f32 Shininess; // 0.0f - 128.0f - f32 Transparency; // 0.0f - 1.0f - u8 Mode; // 0, 1, 2 is unused now - s8 Texture[128]; - s8 Alphamap[128]; -} PACK_STRUCT; - -// Joint information -struct MS3DJoint -{ - u8 Flags; - s8 Name[32]; - s8 ParentName[32]; - f32 Rotation[3]; - f32 Translation[3]; - u16 NumRotationKeyframes; - u16 NumTranslationKeyframes; -} PACK_STRUCT; - -// Keyframe data -struct MS3DKeyframe -{ - f32 Time; - f32 Parameter[3]; -} PACK_STRUCT; - -// Default alignment -#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__) -# pragma pack( pop, packing ) -#endif - -#undef PACK_STRUCT - - -//! constructor -CAnimatedMeshMS3D::CAnimatedMeshMS3D(video::IVideoDriver* driver) -: Driver(driver) -{ - if (Driver) - Driver->grab(); - - lastCalculatedFrame = -1; -} - - - -//! destructor -CAnimatedMeshMS3D::~CAnimatedMeshMS3D() -{ - if (Driver) - Driver->drop(); -} - - - -//! loads an ms3d file -bool CAnimatedMeshMS3D::loadFile(io::IReadFile* file) -{ - u32 i=0; - - if (!file) - return false; - - HasAnimation = false; - - // find file size - - size_t fileSize = file->getSize(); - - // read whole file - - u8* buffer = new u8[fileSize]; - size_t read = (s32)file->read(buffer, fileSize); - if (read != fileSize) - { - delete [] buffer; - os::Printer::log("Could not read full file. Loading failed", file->getFileName(), ELL_ERROR); - return false; - } - - // read header - - const u8 *pPtr = (u8*)((void*)buffer); - MS3DHeader *pHeader = (MS3DHeader*)pPtr; - pPtr += sizeof(MS3DHeader); - - if ( strncmp( pHeader->ID, "MS3D000000", 10 ) != 0 ) - { - delete [] buffer; - os::Printer::log("Not a valid Milkshape3D Model File. Loading failed", file->getFileName(), ELL_ERROR); - return false; - } - -#ifdef __BIG_ENDIAN__ - pHeader->Version = os::Byteswap::byteswap(pHeader->Version); -#endif - if ( pHeader->Version < 3 || pHeader->Version > 4 ) - { - delete [] buffer; - os::Printer::log("Only Milkshape3D version 1.3 and 1.4 is supported. Loading failed", file->getFileName(), ELL_ERROR); - return false; - } - - // get pointers to data - - // vertices - u16 numVertices = *(u16*)pPtr; -#ifdef __BIG_ENDIAN__ - numVertices = os::Byteswap::byteswap(numVertices); -#endif - pPtr += sizeof(u16); - MS3DVertex *vertices = (MS3DVertex*)pPtr; - pPtr += sizeof(MS3DVertex) * numVertices; -#ifdef __BIG_ENDIAN__ - for (i=0; iAmbient[j] = os::Byteswap::byteswap(material->Ambient[j]); - for (u32 j=0; j<4; ++j) - material->Diffuse[j] = os::Byteswap::byteswap(material->Diffuse[j]); - for (u32 j=0; j<4; ++j) - material->Specular[j] = os::Byteswap::byteswap(material->Specular[j]); - for (u32 j=0; j<4; ++j) - material->Emissive[j] = os::Byteswap::byteswap(material->Emissive[j]); - material->Shininess = os::Byteswap::byteswap(material->Shininess); - material->Transparency = os::Byteswap::byteswap(material->Transparency); -#endif - pPtr += sizeof(MS3DMaterial); - - Buffers.push_back(SSharedMeshBuffer(&AnimatedVertices)); - SSharedMeshBuffer& tmpBuffer = Buffers.getLast(); - - tmpBuffer.Material.MaterialType = video::EMT_SOLID; - - tmpBuffer.Material.AmbientColor = video::SColorf(material->Ambient[0], material->Ambient[1], material->Ambient[2], material->Ambient[3]).toSColor (); - tmpBuffer.Material.DiffuseColor = video::SColorf(material->Diffuse[0], material->Diffuse[1], material->Diffuse[2], material->Diffuse[3]).toSColor (); - tmpBuffer.Material.EmissiveColor = video::SColorf(material->Emissive[0], material->Emissive[1], material->Emissive[2], material->Emissive[3]).toSColor (); - tmpBuffer.Material.SpecularColor = video::SColorf(material->Specular[0], material->Specular[1], material->Specular[2], material->Specular[3]).toSColor (); - tmpBuffer.Material.Shininess = material->Shininess; - tmpBuffer.Material.Textures[0] = Driver->getTexture((const c8*)material->Texture); - if (tmpBuffer.Material.Textures[0]==0) - tmpBuffer.Material.Textures[0] = Driver->getTexture(strrchr((const c8*)material->Texture, '/')+1); - } - - // animation time - f32 framesPerSecond = *(f32*)pPtr; -#ifdef __BIG_ENDIAN__ - framesPerSecond = os::Byteswap::byteswap(framesPerSecond); -#endif - pPtr += sizeof(f32) * 2; // fps and current time - - s32 frameCount = *(s32*)pPtr; -#ifdef __BIG_ENDIAN__ - frameCount = os::Byteswap::byteswap(frameCount); -#endif - pPtr += sizeof(s32); - - totalTime = (frameCount / framesPerSecond) * 1000.0f; - - u16 jointCount = *(u16*)pPtr; -#ifdef __BIG_ENDIAN__ - jointCount = os::Byteswap::byteswap(jointCount); -#endif - pPtr += sizeof(u16); - - // load joints - SJoint t; - - for (i=0; iRotation[j] = os::Byteswap::byteswap(pJoint->Rotation[j]); - for (u32 j=0; j<3; ++j) - pJoint->Translation[j] = os::Byteswap::byteswap(pJoint->Translation[j]); - pJoint->NumRotationKeyframes= os::Byteswap::byteswap(pJoint->NumRotationKeyframes); - pJoint->NumTranslationKeyframes = os::Byteswap::byteswap(pJoint->NumTranslationKeyframes); -#endif - pPtr += sizeof(MS3DJoint); - Joints.push_back(t); - SJoint& jnt = Joints[Joints.size()-1]; - - jnt.Name = pJoint->Name; - jnt.Index = i; - jnt.Rotation.X = pJoint->Rotation[0]; - jnt.Rotation.Y = pJoint->Rotation[1]; - jnt.Rotation.Z = pJoint->Rotation[2]; - jnt.Translation.X = pJoint->Translation[0]; - jnt.Translation.Y = pJoint->Translation[1]; - jnt.Translation.Z = pJoint->Translation[2]; - jnt.ParentName = pJoint->ParentName; - jnt.Parent = -1; - - if (pJoint->NumRotationKeyframes || - pJoint->NumTranslationKeyframes) - HasAnimation = true; - - // get rotation keyframes - for (u32 j=0; jNumRotationKeyframes; ++j) - { - MS3DKeyframe* kf = (MS3DKeyframe*)pPtr; -#ifdef __BIG_ENDIAN__ - kf->Time = os::Byteswap::byteswap(kf->Time); - for (u32 l=0; l<3; ++l) - kf->Parameter[l] = os::Byteswap::byteswap(kf->Parameter[l]); -#endif - pPtr += sizeof(MS3DKeyframe); - - SKeyframe k; - k.timeindex = kf->Time * 1000.0f; - k.data.X = kf->Parameter[0]; - k.data.Y = kf->Parameter[1]; - k.data.Z = kf->Parameter[2]; - jnt.RotationKeys.push_back(k); - } - - // get translation keyframes - for (u32 j=0; jNumTranslationKeyframes; ++j) - { - MS3DKeyframe* kf = (MS3DKeyframe*)pPtr; -#ifdef __BIG_ENDIAN__ - kf->Time = os::Byteswap::byteswap(kf->Time); - for (u32 l=0; l<3; ++l) - kf->Parameter[l] = os::Byteswap::byteswap(kf->Parameter[l]); -#endif - pPtr += sizeof(MS3DKeyframe); - - SKeyframe k; - k.timeindex = kf->Time * 1000.0f; - k.data.X = kf->Parameter[0]; - k.data.Y = kf->Parameter[1]; - k.data.Z = kf->Parameter[2]; - jnt.TranslationKeys.push_back(k); - } - } - - //find parent of every joint - for (i=0; i=0 && boneid<(s32)Joints.size()) - Joints[boneid].VertexIds.push_back(Vertices.size()); - - Vertices.push_back(v); - index = Vertices.size() - 1; - } - Indices.push_back(index); - } - } - - //create groups - s32 iIndex = -1; - for (i=0; i= Buffers.size()) - grp.MaterialIdx = 0; - - core::array& indices = Buffers[grp.MaterialIdx].Indices; - - for (u32 k=0; k& keys, f32 time, core::vector3df& outdata) const -{ - if (keys.size()) - { - if (time < keys[0].timeindex) - { - outdata = keys[0].data; - return; - } - if (time > keys.getLast().timeindex) - { - outdata = keys.getLast().data; - return; - } - - for (u32 i=0; i= time) - { - f32 interpolate = (time - keys[i].timeindex)/(keys[i+1].timeindex - keys[i].timeindex); - outdata = keys[i].data + ((keys[i+1].data - keys[i].data) * interpolate); - return; - } - } - } -} - - -void CAnimatedMeshMS3D::getKeyframeRotation(const core::array& keys, f32 time, core::vector3df& outdata) const -{ - if (keys.size()) - { - if (time < keys[0].timeindex) - { - outdata = keys[0].data; - return; - } - if (time > keys.getLast().timeindex) - { - outdata = keys.getLast().data; - return; - } - - for (u32 i=0; i= time) - { -// core::quaternion q1(keys[i].data); -// core::quaternion q2(keys[i+1].data); - f32 interpolate = (time - keys[i].timeindex)/(keys[i+1].timeindex - keys[i].timeindex); - core::quaternion q; - q.slerp(keys[i].data, keys[i+1].data, interpolate); - q.toEuler(outdata); - return; - } - } - } -} - - -//! Returns a pointer to a transformation matrix of a part of the -//! mesh based on a frame time. -core::matrix4* CAnimatedMeshMS3D::getMatrixOfJoint(s32 jointNumber, s32 frame) -{ - if (jointNumber < 0 || jointNumber >= (s32)Joints.size()) - return 0; - - animate(frame); - - return &Joints[jointNumber].AbsoluteTransformationAnimated; -} - - -//! Gets joint count. -s32 CAnimatedMeshMS3D::getJointCount() const -{ - return Joints.size(); -} - - -//! Gets the name of a joint. -const c8* CAnimatedMeshMS3D::getJointName(s32 number) const -{ - if (number < 0 || number >= (s32)Joints.size()) - return 0; - return Joints[number].Name.c_str(); -} - - -//! Gets a joint number from its name -s32 CAnimatedMeshMS3D::getJointNumber(const c8* name) const -{ - for (s32 i=0; i<(s32)Joints.size(); ++i) - if (Joints[i].Name == name) - return i; - - return -1; -} - - -void CAnimatedMeshMS3D::animate(s32 frame) -{ - if (!HasAnimation || lastCalculatedFrame == frame) - return; - - f32 time = (f32)frame; - core::matrix4 transform; - lastCalculatedFrame = frame; - u32 i; - - for (i=0; i& CAnimatedMeshMS3D::getBoundingBox() const -{ - return BoundingBox; -} - - -//! set user axis aligned bounding box -void CAnimatedMeshMS3D::setBoundingBox( const core::aabbox3df& box) -{ - BoundingBox = box; -} - -//! sets a flag of all contained materials to a new value -void CAnimatedMeshMS3D::setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) -{ - for (u32 i=0; i& getBoundingBox() const; - - //! set user axis aligned bounding box - virtual void setBoundingBox( const core::aabbox3df& box); - - //! sets a flag of all contained materials to a new value - virtual void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue); - - //! Returns the type of the animated mesh. - virtual E_ANIMATED_MESH_TYPE getMeshType() const; - - //! Returns a pointer to a transformation matrix of a part of the - //! mesh based on a frame time. - virtual core::matrix4* getMatrixOfJoint(s32 jointNumber, s32 frame); - - //! Gets joint count. - virtual s32 getJointCount() const; - - //! Gets the name of a joint. - virtual const c8* getJointName(s32 number) const; - - //! Gets a joint number from its name - virtual s32 getJointNumber(const c8* name) const; - - private: - - struct SKeyframe - { - f32 timeindex; - core::vector3df data; // translation or rotation - }; - - struct SJoint - { - core::stringc Name; - s32 Index; - core::vector3df Rotation; - core::vector3df Translation; - - core::matrix4 RelativeTransformation; - core::matrix4 AbsoluteTransformation; - core::matrix4 AbsoluteTransformationAnimated; - - core::array TranslationKeys; - core::array RotationKeys; - core::array VertexIds; - - s32 Parent; - core::stringc ParentName; - }; - - struct SGroup - { - core::stringc Name; - core::array VertexIds; - - u16 MaterialIdx; - }; - - void animate(s32 frame); - void getKeyframeData(const core::array& keys, f32 time, core::vector3df& outdata) const; - void getKeyframeRotation(const core::array& keys, f32 time, core::vector3df& outdata) const; - - core::aabbox3d BoundingBox; - - core::array Vertices; - core::array AnimatedVertices; - core::array Indices; - - core::array Joints; - core::array Groups; - core::array Buffers; - - f32 totalTime; - bool HasAnimation; - s32 lastCalculatedFrame; - - video::IVideoDriver* Driver; - }; - -} // end namespace scene -} // end namespace irr - -#endif - diff --git a/source/Irrlicht/CAnimatedMeshSceneNode.cpp b/source/Irrlicht/CAnimatedMeshSceneNode.cpp index affd5582..fd4c6c76 100644 --- a/source/Irrlicht/CAnimatedMeshSceneNode.cpp +++ b/source/Irrlicht/CAnimatedMeshSceneNode.cpp @@ -8,17 +8,17 @@ #include "S3DVertex.h" #include "os.h" #include "CShadowVolumeSceneNode.h" -#include "IAnimatedMeshMS3D.h" #include "IAnimatedMeshMD3.h" -#include "IAnimatedMeshX.h" -#include "IAnimatedMeshB3d.h" +#include "ISkinnedMesh.h" #include "IDummyTransformationSceneNode.h" +#include "IBoneSceneNode.h" #include "IMaterialRenderer.h" #include "IMesh.h" #include "IMeshCache.h" #include "IAnimatedMesh.h" #include "quaternion.h" + namespace irr { namespace scene @@ -30,7 +30,9 @@ CAnimatedMeshSceneNode::CAnimatedMeshSceneNode(IAnimatedMesh* mesh, ISceneNode* const core::vector3df& position, const core::vector3df& rotation, const core::vector3df& scale) : IAnimatedMeshSceneNode(parent, mgr, id, position, rotation, scale), Mesh(0), BeginFrameTime(0), StartFrame(0), EndFrame(0), FramesPerSecond(25.f / 1000.f ), - CurrentFrameNr(0), Looping(true), ReadOnlyMaterials(false), + CurrentFrameNr(0.f), JointMode(0), JointsUsed(0), + TransitionTime(0), Transiting(0), TransitingBlend(0), + Looping(true), ReadOnlyMaterials(false), LoopCallBack(0), PassCount(0), Shadow(0) { #ifdef _DEBUG @@ -53,9 +55,9 @@ CAnimatedMeshSceneNode::~CAnimatedMeshSceneNode() if (Shadow) Shadow->drop(); - for (u32 i=0; idrop(); + //for (u32 i=0; idrop(); if (LoopCallBack) LoopCallBack->drop(); @@ -63,44 +65,101 @@ CAnimatedMeshSceneNode::~CAnimatedMeshSceneNode() + + + + + + + + //! Sets the current frame. From now on the animation is played from this frame. -void CAnimatedMeshSceneNode::setCurrentFrame(s32 frame) +void CAnimatedMeshSceneNode::setCurrentFrame(f32 frame) { // if you pass an out of range value, we just clamp it - CurrentFrameNr = core::s32_clamp ( frame, StartFrame, EndFrame ); + CurrentFrameNr = core::clamp ( frame, (f32)StartFrame, (f32)EndFrame ); BeginFrameTime = os::Timer::getTime() - (s32)((CurrentFrameNr - StartFrame) / FramesPerSecond); + + beginTransition(); //transite to this frame if enabled + } //! Returns the current displayed frame number. -s32 CAnimatedMeshSceneNode::getFrameNr() const +f32 CAnimatedMeshSceneNode::getFrameNr() const { return CurrentFrameNr; } -u32 CAnimatedMeshSceneNode::buildFrameNr(u32 timeMs) +f32 CAnimatedMeshSceneNode::buildFrameNr(u32 timeMs) { - const s32 deltaFrame = core::floor32 ( f32 ( timeMs - BeginFrameTime ) * FramesPerSecond ); + + if (Transiting!=0) + { + TransitingBlend=f32(timeMs-BeginFrameTime) * Transiting; + if (TransitingBlend>1) + { + Transiting=0; + TransitingBlend=0; + } + } + + if (StartFrame==EndFrame) return StartFrame; //Support for non animated meshes + if (FramesPerSecond==0) return StartFrame; + if (Looping) { - const s32 len = EndFrame - StartFrame + 1; // play animation looped - return StartFrame + ( deltaFrame % len ); + + if (FramesPerSecond>0) //forwards... + { + const s32 lenInTime = s32( f32(EndFrame - StartFrame) / FramesPerSecond); + return StartFrame + ( (timeMs - BeginFrameTime) % lenInTime) *FramesPerSecond; + } + else //backwards... + { + const s32 lenInTime = s32( f32(EndFrame - StartFrame) / -FramesPerSecond); + return EndFrame - ( (timeMs - BeginFrameTime) % lenInTime)*-FramesPerSecond; + } } else { // play animation non looped - s32 frame = StartFrame + deltaFrame; - if (frame > EndFrame) + f32 frame; + + if (FramesPerSecond>0) //forwards... { - frame = EndFrame; - if (LoopCallBack) - LoopCallBack->OnAnimationEnd(this); + + const f32 deltaFrame = core::floor32 ( f32 ( timeMs - BeginFrameTime ) * FramesPerSecond ); + + frame = StartFrame + deltaFrame; + + if (frame > (f32)EndFrame) + { + frame = (f32)EndFrame; + if (LoopCallBack) + LoopCallBack->OnAnimationEnd(this); + } } + else //backwards... (untested) + { + const f32 deltaFrame = core::floor32 ( f32 ( timeMs - BeginFrameTime ) * -FramesPerSecond ); + + frame = EndFrame - deltaFrame; + + if (frame < (f32)StartFrame) + { + frame = (f32)StartFrame; + if (LoopCallBack) + LoopCallBack->OnAnimationEnd(this); + } + + } + return frame; } } @@ -157,14 +216,23 @@ void CAnimatedMeshSceneNode::OnRegisterSceneNode() //! OnAnimate() is called just before rendering the whole scene. void CAnimatedMeshSceneNode::OnAnimate(u32 timeMs) { + CurrentFrameNr = buildFrameNr ( timeMs ); if ( Mesh ) { - Box = Mesh->getBoundingBox(); //can we remove this, the box is set on 'setMesh', and without it the user can set their own boundingbox (if the normal one is too small) without it being overwritten + /* + scene::IMesh *m = Mesh->getMesh(CurrentFrameNr, 255, StartFrame, EndFrame); + if ( m ) + { + Box = m->getBoundingBox(); + } + */ } + IAnimatedMeshSceneNode::OnAnimate ( timeMs ); + } @@ -189,13 +257,46 @@ void CAnimatedMeshSceneNode::render() if (!Mesh || !driver) return; + bool isTransparentPass = SceneManager->getSceneNodeRenderPass() == scene::ESNRP_TRANSPARENT; ++PassCount; - s32 frame = getFrameNr(); - scene::IMesh* m = Mesh->getMesh(frame, 255, StartFrame, EndFrame); + f32 frame = getFrameNr(); + + scene::IMesh* m; + + if (Mesh->getMeshType() != EAMT_SKINNED) + m = Mesh->getMesh((s32)frame, 255, StartFrame, EndFrame); + else + { + ISkinnedMesh* skinnedMesh=(ISkinnedMesh*)Mesh; + + if (JointMode &2)//write to mesh + skinnedMesh->tranferJointsToMesh(JointChildSceneNodes); + else + skinnedMesh->animateMesh(frame, 1.0f); + + skinnedMesh->skinMesh(); + + if (JointMode &1)//read from mesh + { + skinnedMesh->recoverJointsFromMesh(JointChildSceneNodes); + + //---slow--- + for (u32 n=0;ngetParent()==this) + { + JointChildSceneNodes[n]->updateAbsolutePositionOfAllChildren(); //temp, should be an option + } + + } + + + m=skinnedMesh; + } + if ( 0 == m ) { @@ -209,21 +310,6 @@ void CAnimatedMeshSceneNode::render() u32 i,g; - // update all dummy transformation nodes - if (!JointChildSceneNodes.empty() && Mesh && - (Mesh->getMeshType() == EAMT_MS3D || Mesh->getMeshType() == EAMT_X || Mesh->getMeshType() == EAMT_B3D )) - { - IAnimatedMeshMS3D* amm = (IAnimatedMeshMS3D*)Mesh; - core::matrix4* m; - - for ( i=0; i< JointChildSceneNodes.size(); ++i) - if (JointChildSceneNodes[i]) - { - m = amm->getMatrixOfJoint(i, frame); - if (m) - JointChildSceneNodes[i]->getRelativeTransformationMatrix() = *m; - } - } if (Shadow && PassCount==1) Shadow->setMeshToRenderFrom(m); @@ -290,14 +376,21 @@ void CAnimatedMeshSceneNode::render() // show skeleton if ( DebugDataVisible & scene::EDS_SKELETON ) { - if (Mesh->getMeshType() == EAMT_X) + if (Mesh->getMeshType() == EAMT_SKINNED) { - // draw skeleton - const core::array* ds = - ((IAnimatedMeshX*)Mesh)->getDrawableSkeleton(frame); - for ( g=0; g < ds->size(); g +=2 ) - driver->draw3DLine((*ds)[g], (*ds)[g+1], video::SColor(0,51,66,255)); + // draw skeleton + + + for ( g=0; g < ((ISkinnedMesh*)Mesh)->getAllJoints().size(); g +=1 ) + { + ISkinnedMesh::SJoint *joint=((ISkinnedMesh*)Mesh)->getAllJoints()[g]; + + for (u32 n=0;nChildren.size();++n) + { + driver->draw3DLine(joint->GlobalAnimatedMatrix.getTranslation(), joint->Children[n]->GlobalAnimatedMatrix.getTranslation(), video::SColor(0,51,66,255)); + } + } } // show tag for quake3 models @@ -321,7 +414,7 @@ void CAnimatedMeshSceneNode::render() core::matrix4 m; - SMD3QuaterionTagList *taglist = ((IAnimatedMeshMD3*)Mesh)->getTagList ( getFrameNr(), + SMD3QuaterionTagList *taglist = ((IAnimatedMeshMD3*)Mesh)->getTagList ( (s32)getFrameNr(), 255, getStartFrame (), getEndFrame () @@ -394,6 +487,8 @@ void CAnimatedMeshSceneNode::render() } } } + + } @@ -489,39 +584,46 @@ IShadowVolumeSceneNode* CAnimatedMeshSceneNode::addShadowVolumeSceneNode(s32 id, +IBoneSceneNode* CAnimatedMeshSceneNode::getJointNode(const c8* jointName) +{ + + if (!Mesh || Mesh->getMeshType() != EAMT_SKINNED) + return 0; + + checkJoints(); + + + ISkinnedMesh *skinnedMesh=(ISkinnedMesh*)Mesh; + + s32 number = skinnedMesh->getJointNumber(jointName); + + if (number == -1) + { + os::Printer::log("Joint with specified name not found in skinned mesh.", jointName, ELL_WARNING); + return 0; + } + + if ((s32)JointChildSceneNodes.size() <= number) + { + os::Printer::log("Joint was found in mesh, but is not loaded into node", jointName, ELL_WARNING); + return 0; + } + + return (IBoneSceneNode*)JointChildSceneNodes[number]; //JointChildSceneNodes will only be IBoneSceneNode later + +} + + + + //! Returns a pointer to a child node, which has the same transformation as //! the corrsesponding joint, if the mesh in this scene node is a ms3d mesh. ISceneNode* CAnimatedMeshSceneNode::getMS3DJointNode(const c8* jointName) { - if (!Mesh || Mesh->getMeshType() != EAMT_MS3D) - return 0; - IAnimatedMeshMS3D* amm = (IAnimatedMeshMS3D*)Mesh; - s32 jointCount = amm->getJointCount(); - s32 number = amm->getJointNumber(jointName); + //return getJointNode(jointName); - if (number == -1) - { - os::Printer::log("Joint with specified name not found in ms3d mesh.", jointName, ELL_WARNING); - return 0; - } - - if (JointChildSceneNodes.empty()) - { - // allocate joints for the first time. - JointChildSceneNodes.set_used(jointCount); - for (s32 i=0; iaddDummyTransformationSceneNode(this); - JointChildSceneNodes[number]->grab(); - } - - return JointChildSceneNodes[number]; + return 0; } @@ -529,72 +631,12 @@ ISceneNode* CAnimatedMeshSceneNode::getMS3DJointNode(const c8* jointName) //! the corrsesponding joint, if the mesh in this scene node is a ms3d mesh. ISceneNode* CAnimatedMeshSceneNode::getXJointNode(const c8* jointName) { - if (!Mesh || Mesh->getMeshType() != EAMT_X) - return 0; + //return getJointNode(jointName); - IAnimatedMeshX* amm = (IAnimatedMeshX*)Mesh; - s32 jointCount = amm->getJointCount(); - s32 number = amm->getJointNumber(jointName); - - if (number == -1) - { - os::Printer::log("Joint with specified name not found in x mesh.", jointName, ELL_WARNING); - return 0; - } - - if (JointChildSceneNodes.empty()) - { - // allocate joints for the first time. - JointChildSceneNodes.set_used(jointCount); - for (s32 i=0; iaddDummyTransformationSceneNode(this); - JointChildSceneNodes[number]->grab(); - } - - return JointChildSceneNodes[number]; + return 0; } -//! Returns a pointer to a child node, which has the same transformation as -//! the corrsesponding joint, if the mesh in this scene node is a b3d mesh. -ISceneNode* CAnimatedMeshSceneNode::getB3DJointNode(const c8* jointName) -{ - if (!Mesh || Mesh->getMeshType() != EAMT_B3D) - return 0; - - IAnimatedMeshB3d* amm = (IAnimatedMeshB3d*)Mesh; - s32 jointCount = amm->getJointCount(); - s32 number = amm->getJointNumber(jointName); - - if (number == -1) - { - os::Printer::log("Joint with specified name not found in b3d mesh.", jointName, ELL_WARNING); - return 0; - } - - if (JointChildSceneNodes.empty()) - { - // allocate joints for the first time. - JointChildSceneNodes.set_used(jointCount); - for (s32 i=0; iaddDummyTransformationSceneNode(this); - JointChildSceneNodes[number]->grab(); - } - - return JointChildSceneNodes[number]; -} //! Removes a child from this scene node. //! Implemented here, to be able to remove the shadow properly, if there is one, @@ -608,17 +650,20 @@ bool CAnimatedMeshSceneNode::removeChild(ISceneNode* child) return true; } - if (ISceneNode::removeChild(child)) + if (JointsUsed) //stop it doing weird things while the joints are being made { - for (s32 i=0; i<(s32)JointChildSceneNodes.size(); ++i) - if (JointChildSceneNodes[i] == child) + if (ISceneNode::removeChild(child)) { - JointChildSceneNodes[i]->drop(); - JointChildSceneNodes[i] = 0; + for (s32 i=0; i<(s32)JointChildSceneNodes.size(); ++i) + if (JointChildSceneNodes[i] == child) + { + //JointChildSceneNodes[i]->drop(); + JointChildSceneNodes[i] = 0; + return true; + } + return true; } - - return true; } return false; @@ -804,7 +849,7 @@ void CAnimatedMeshSceneNode::updateAbsolutePosition() SMD3QuaterionTag relative( RelativeTranslation, RelativeRotation ); SMD3QuaterionTagList *taglist; - taglist = ( (IAnimatedMeshMD3*) Mesh )->getTagList ( getFrameNr(),255,getStartFrame (),getEndFrame () ); + taglist = ( (IAnimatedMeshMD3*) Mesh )->getTagList ( (s32)getFrameNr(),255,getStartFrame (),getEndFrame () ); if ( taglist ) { MD3Special.AbsoluteTagList.Container.set_used ( taglist->size () ); @@ -818,6 +863,166 @@ void CAnimatedMeshSceneNode::updateAbsolutePosition() } +//! Set the joint update mode (0-unused, 1-get joints only, 2-set joints only, 3-move and set) +void CAnimatedMeshSceneNode::setJointMode(s32 mode) +{ + checkJoints(); + + if (mode<0) mode=0; + if (mode>3) mode=3; + + JointMode=mode; +} + + +//! Sets the transition time in seconds (note: This needs to enable joints, and setJointmode maybe set to 2) +//! you must call animateJoints(), or the mesh will not animate +void CAnimatedMeshSceneNode::setTransitionTime(f32 Time) +{ + if (Time!=0) checkJoints(); + if (!(JointMode &2)) setJointMode(2); + TransitionTime=u32(Time*1000.0f); +} + +//! updates the joint positions of this mesh +void CAnimatedMeshSceneNode::animateJoints() +{ + checkJoints(); + + if (Mesh && Mesh->getMeshType() == EAMT_SKINNED ) + { + if (JointsUsed) + { + f32 frame = getFrameNr(); //old? + + ISkinnedMesh* skinnedMesh=(ISkinnedMesh*)Mesh; + + skinnedMesh->animateMesh(frame, 1.0f); + + skinnedMesh->recoverJointsFromMesh( JointChildSceneNodes); + + //---slow--- + for (u32 n=0;ngetParent()==this) + { + JointChildSceneNodes[n]->updateAbsolutePositionOfAllChildren(); //temp, should be an option + } + + //----------------------------------------- + // Transition + //----------------------------------------- + + if (Transiting!=0) + { + u32 n; + + //Check the array is big enough (not really needed) + if (PretransitingSave.size()setPosition(PretransitingSave[n].getTranslation()*InvTransitingBlend+ + JointChildSceneNodes[n]->getPosition()*TransitingBlend); + + + //------Rotation------ + + //Code is slow, needs to be fixed up + + core::quaternion RotationStart, RotationEnd; + core::quaternion QRotation; + core::vector3df tmpVector; + + tmpVector=PretransitingSave[n].getRotationDegrees(); + RotationStart.set(tmpVector.X*core::DEGTORAD ,tmpVector.Y*core::DEGTORAD,tmpVector.Z*core::DEGTORAD); + + tmpVector=JointChildSceneNodes[n]->getRotation(); + RotationEnd.set(tmpVector.X*core::DEGTORAD ,tmpVector.Y*core::DEGTORAD,tmpVector.Z*core::DEGTORAD); + + QRotation.slerp(RotationStart, RotationEnd, TransitingBlend); + + QRotation.toEuler (tmpVector); + tmpVector.X*=core::RADTODEG; tmpVector.Y*=core::RADTODEG; tmpVector.Z*=core::RADTODEG; //convert from radians back to degrees + JointChildSceneNodes[n]->setRotation( tmpVector ); + + + //------Scale------ + + //JointChildSceneNodes[n]->setScale(PretransitingSave[n].getScale()*InvTransitingBlend+ + // JointChildSceneNodes[n]->getScale()*TransitingBlend); + + } + + } + + } + } + +} + + + + +void CAnimatedMeshSceneNode::checkJoints() +{ + if (!Mesh || Mesh->getMeshType() != EAMT_SKINNED) + return; + + if (!JointsUsed) + { + + + //Create joints for SkinnedMesh + + ((ISkinnedMesh*)Mesh)->createJoints( JointChildSceneNodes,this,SceneManager); + ((ISkinnedMesh*)Mesh)->recoverJointsFromMesh( JointChildSceneNodes); + + + JointsUsed=true; + JointMode=1; + + } + +} + +void CAnimatedMeshSceneNode::beginTransition() +{ + if (!JointsUsed) return; + + u32 n; + + if (TransitionTime!=0) + { + //Check the array is big enough + if (PretransitingSave.size()getRelativeTransformation(); + + Transiting=1.0f/f32(TransitionTime); + + } +} + + + + + + } // end namespace scene } // end namespace irr diff --git a/source/Irrlicht/CAnimatedMeshSceneNode.h b/source/Irrlicht/CAnimatedMeshSceneNode.h index d1c1c02e..fd4ccf5e 100644 --- a/source/Irrlicht/CAnimatedMeshSceneNode.h +++ b/source/Irrlicht/CAnimatedMeshSceneNode.h @@ -8,6 +8,9 @@ #include "IAnimatedMeshSceneNode.h" #include "IAnimatedMesh.h" +#include "matrix4.h" + + namespace irr { namespace scene @@ -28,7 +31,7 @@ namespace scene virtual ~CAnimatedMeshSceneNode(); //! sets the current frame. from now on the animation is played from this frame. - virtual void setCurrentFrame(s32 frame); + virtual void setCurrentFrame(f32 frame); //! frame virtual void OnRegisterSceneNode(); @@ -72,6 +75,10 @@ namespace scene virtual IShadowVolumeSceneNode* addShadowVolumeSceneNode(s32 id, bool zfailmethod=true, f32 infinity=10000.0f); + //! Returns a pointer to a child node, which has the same transformation as + //! the corrsesponding joint, if the mesh in this scene node is a skinned mesh. + virtual IBoneSceneNode* getJointNode(const c8* jointName); + //! Returns a pointer to a child node, which has the same transformation as //! the corrsesponding joint, if the mesh in this scene node is a ms3d mesh. virtual ISceneNode* getMS3DJointNode(const c8* jointName); @@ -80,10 +87,6 @@ namespace scene //! the corrsesponding joint, if the mesh in this scene node is a x mesh. virtual ISceneNode* getXJointNode(const c8* jointName); - //! Returns a pointer to a child node, which has the same transformation as - //! the corresponding joint, if the mesh in this scene node is a b3d mesh. - virtual ISceneNode* getB3DJointNode(const c8* jointName); - //! Removes a child from this scene node. //! Implemented here, to be able to remove the shadow properly, if there is one, //! or to remove attached childs. @@ -96,7 +99,7 @@ namespace scene virtual bool setMD2Animation(const c8* animationName); //! Returns the current displayed frame number. - virtual s32 getFrameNr() const; + virtual f32 getFrameNr() const; //! Returns the current start frame number. virtual s32 getStartFrame() const; //! Returns the current end frame number. @@ -132,9 +135,24 @@ namespace scene //! updates the absolute position based on the relative and the parents position virtual void updateAbsolutePosition(); + + //! Set the joint update mode (0-unused, 1-get joints only, 2-set joints only, 3-move and set) + virtual void setJointMode(s32 mode); + + //! Sets the transition time in seconds (note: This needs to enable joints, and setJointmode maybe set to 2) + //! you must call animateJoints(), or the mesh will not animate + virtual void setTransitionTime(f32 Time); + + //! updates the joint positions of this mesh + virtual void animateJoints(); + private: - u32 buildFrameNr( u32 timeMs); + f32 buildFrameNr( u32 timeMs); + + void checkJoints(); + + void beginTransition(); core::array Materials; core::aabbox3d Box; @@ -145,7 +163,15 @@ namespace scene s32 EndFrame; f32 FramesPerSecond; - s32 CurrentFrameNr; + f32 CurrentFrameNr; + + s32 JointMode; //0-unused, 1-get joints only, 2-set joints only, 3-move and set + bool JointsUsed; + + u32 TransitionTime; //Transition time in millisecs + + f32 Transiting; //is mesh transiting (plus cache of TransitionTime) + f32 TransitingBlend; //0-1, calculated on buildFrameNr bool Looping; bool ReadOnlyMaterials; @@ -155,7 +181,9 @@ namespace scene IShadowVolumeSceneNode* Shadow; - core::array JointChildSceneNodes; + core::array JointChildSceneNodes; + core::array PretransitingSave; + struct SMD3Special { diff --git a/source/Irrlicht/CB3DMeshFileLoader.cpp b/source/Irrlicht/CB3DMeshFileLoader.cpp new file mode 100644 index 00000000..8b80ed2e --- /dev/null +++ b/source/Irrlicht/CB3DMeshFileLoader.cpp @@ -0,0 +1,1005 @@ + +// B3D Mesh loader +//file format designed by mark sibly for the blitz3d engine and has been declared public domain +//loader by luke hoschke + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_B3D_LOADER_ + +#include "CB3DMeshFileLoader.h" + +#include "IVideoDriver.h" +#include "os.h" + + + +namespace irr +{ +namespace scene +{ + +//! Constructor +CB3DMeshFileLoader::CB3DMeshFileLoader(scene::ISceneManager* smgr) +: B3dStack(), NormalsInFile(false), SceneManager(smgr), AnimatedMesh(0), file(0) +{ + #ifdef _DEBUG + setDebugName("CB3DMeshFileLoader"); + #endif +} + +//! destructor +CB3DMeshFileLoader::~CB3DMeshFileLoader() +{ + s32 n; + + for (n=Materials.size()-1; n>=0; --n) + { + if (Materials[n].Material) + delete Materials[n].Material; + } + +} + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".bsp") +bool CB3DMeshFileLoader::isALoadableFileExtension(const c8* fileName) +{ + return strstr(fileName, ".b3d") != 0; +} + +//! creates/loads an animated mesh from the file. +//! \return Pointer to the created mesh. Returns 0 if loading failed. +//! If you no longer need the mesh, you should call IAnimatedMesh::drop(). +//! See IUnknown::drop() for more information. +IAnimatedMesh* CB3DMeshFileLoader::createMesh(irr::io::IReadFile* f) +{ + + if (!f) + return 0; + + file = f; + AnimatedMesh = new scene::CSkinnedMesh(); + + Buffers = &AnimatedMesh->getMeshBuffers(); + AllJoints = &AnimatedMesh->getAllJoints(); + + if ( load() ) + { + AnimatedMesh->finalize(); + } + else + { + AnimatedMesh->drop(); + AnimatedMesh = 0; + } + + return AnimatedMesh; +} + +bool CB3DMeshFileLoader::load() +{ + + B3dStack.clear(); + + NormalsInFile=false; + + + + + //------ Get header ------ + + SB3dChunkHeader header; + file->read(&header, sizeof(header)); + + #ifdef __BIG_ENDIAN__ + header.size = os::Byteswap::byteswap(header.size); + #endif + + if ( strncmp( header.name, "BB3D", 4 ) != 0 ) + { + os::Printer::log("File is not a b3d file. Loading failed (No header found)", file->getFileName(), ELL_ERROR); + return false; + } + + // Add main chunk... + B3dStack.push_back(SB3dChunk()); + B3dStack.getLast().name[0] = header.name[0]; + B3dStack.getLast().name[1] = header.name[1]; + B3dStack.getLast().name[2] = header.name[2]; + B3dStack.getLast().name[3] = header.name[3]; + B3dStack.getLast().startposition = file->getPos()-8; + B3dStack.getLast().length = header.size+8; + + // Get file version, but ignore it, as it's not important with b3d files... + u32 FileVersion; + file->read(&FileVersion, sizeof(FileVersion)); + #ifdef __BIG_ENDIAN__ + FileVersion = os::Byteswap::byteswap(FileVersion); + #endif + + //------ Read main chunk ------ + + while ( B3dStack.getLast().startposition+B3dStack.getLast().length > file->getPos() ) + { + B3dStack.push_back(SB3dChunk()); + + file->read(&header, sizeof(header)); + + #ifdef __BIG_ENDIAN__ + header.size = os::Byteswap::byteswap(header.size); + #endif + + B3dStack.getLast().name[0] = header.name[0]; + B3dStack.getLast().name[1] = header.name[1]; + B3dStack.getLast().name[2] = header.name[2]; + B3dStack.getLast().name[3] = header.name[3]; + B3dStack.getLast().startposition = file->getPos() - 8; + B3dStack.getLast().length = header.size + 8; + + bool knownChunk = false; + + if ( strncmp( B3dStack.getLast().name, "TEXS", 4 ) == 0 ) + { + knownChunk=true; + if (!readChunkTEXS()) + return false; + } + else if ( strncmp( B3dStack.getLast().name, "BRUS", 4 ) == 0 ) + { + knownChunk=true; + if (!readChunkBRUS()) + return false; + } + else if ( strncmp( B3dStack.getLast().name, "NODE", 4 ) == 0 ) + { + knownChunk=true; + if (!readChunkNODE((CSkinnedMesh::SJoint*)0) ) + return false; + } + + if (!knownChunk) + { + os::Printer::log("Unknown chunk found in mesh base - skipping"); + file->seek( (B3dStack.getLast().startposition + B3dStack.getLast().length) , false); + B3dStack.erase(B3dStack.size()-1); + } + } + + B3dStack.clear(); + + BaseVertices.clear(); + AnimatedVertices_VertexID.clear(); + AnimatedVertices_BufferID.clear(); + + Materials.clear(); + Textures.clear(); + + BaseVertices.clear(); + + Buffers=0; + AllJoints=0; + + + + return true; + +} + + +bool CB3DMeshFileLoader::readChunkNODE(CSkinnedMesh::SJoint *InJoint) +{ + + core::stringc JointName = readString(); + + f32 position[3], scale[3], rotation[4]; + s32 n; + + for (n=0; n<=2; n++) + file->read(&position[n], sizeof(f32)); + + for (n=0; n<=2; n++) + file->read(&scale[n], sizeof(f32)); + + for (n=0; n<=3; n++) + file->read(&rotation[n], sizeof(f32)); + + #ifdef __BIG_ENDIAN__ + for (n=0; n<=2; n++) + position[n] = os::Byteswap::byteswap(position[n]); + + for (n=0; n<=2; n++) + scale[n] = os::Byteswap::byteswap(scale[n]); + + for (n=0; n<=3; n++) + rotation[n] = os::Byteswap::byteswap(rotation[n]); + #endif + + CSkinnedMesh::SJoint *Joint = AnimatedMesh->createJoint(InJoint); + + Joint->Name = JointName; + Joint->Animatedposition = core::vector3df(position[0],position[1],position[2]) ; + Joint->Animatedscale = core::vector3df(scale[0],scale[1],scale[2]); + Joint->Animatedrotation = core::quaternion(rotation[1], rotation[2], rotation[3], rotation[0]); + + //Build LocalMatrix: + + irr::core::matrix4 positionMatrix; positionMatrix.setTranslation( Joint->Animatedposition ); + irr::core::matrix4 scaleMatrix; scaleMatrix.setScale( Joint->Animatedscale ); + irr::core::matrix4 rotationMatrix = Joint->Animatedrotation.getMatrix(); + + Joint->LocalMatrix = positionMatrix * rotationMatrix * scaleMatrix; + + if (InJoint) + Joint->GlobalMatrix = InJoint->GlobalMatrix * Joint->LocalMatrix; + else + Joint->GlobalMatrix = Joint->LocalMatrix; + + while(B3dStack.getLast().startposition + B3dStack.getLast().length > file->getPos()) // this chunk repeats + { + B3dStack.push_back(SB3dChunk()); + + SB3dChunkHeader header; + file->read(&header, sizeof(header)); + + #ifdef __BIG_ENDIAN__ + header.size = os::Byteswap::byteswap(header.size); + #endif + + B3dStack.getLast().name[0] = header.name[0]; + B3dStack.getLast().name[1] = header.name[1]; + B3dStack.getLast().name[2] = header.name[2]; + B3dStack.getLast().name[3] = header.name[3]; + B3dStack.getLast().length = header.size+8; + B3dStack.getLast().startposition = file->getPos() - 8; + + bool knownChunk = false; + + if ( strncmp( B3dStack.getLast().name, "NODE", 4 ) == 0 ) + { + knownChunk = true; + if (!readChunkNODE(Joint)) + return false; + } + else if ( strncmp( B3dStack.getLast().name, "MESH", 4 ) == 0 ) + { + knownChunk = true; + if (!readChunkMESH(Joint)) + return false; + } + else if ( strncmp( B3dStack.getLast().name, "ANIM", 4 ) == 0 ) + { + knownChunk = true; + if (!readChunkANIM(Joint)) + return false; + } + else if ( strncmp( B3dStack.getLast().name, "BONE", 4 ) == 0 ) + { + knownChunk = true; + if (!readChunkBONE(Joint)) + return false; + } + else if ( strncmp( B3dStack.getLast().name, "KEYS", 4 ) == 0 ) + { + knownChunk = true; + if(!readChunkKEYS(Joint)) + return false; + } + + if (!knownChunk) + { + os::Printer::log("Unknown chunk found in node chunk - skipping"); + file->seek( (B3dStack.getLast().startposition + B3dStack.getLast().length), false); + B3dStack.erase(B3dStack.size()-1); + } + } + + B3dStack.erase(B3dStack.size()-1); + + return true; +} + +bool CB3DMeshFileLoader::readChunkMESH(CSkinnedMesh::SJoint *InJoint) +{ + + s32 Vertices_Start=BaseVertices.size(); //B3Ds have Vertex ID's local within the mesh I don't want this + + s32 brush_id; + + file->read(&brush_id, sizeof(brush_id)); + + #ifdef __BIG_ENDIAN__ + brush_id = os::Byteswap::byteswap(brush_id); + #endif + + NormalsInFile=false; + + while(B3dStack.getLast().startposition + B3dStack.getLast().length>file->getPos()) //this chunk repeats + { + + B3dStack.push_back(SB3dChunk()); + + SB3dChunkHeader header; + file->read(&header, sizeof(header)); + + #ifdef __BIG_ENDIAN__ + header.size = os::Byteswap::byteswap(header.size); + #endif + + B3dStack.getLast().name[0]=header.name[0]; + B3dStack.getLast().name[1]=header.name[1]; //Not sure of an easier way + B3dStack.getLast().name[2]=header.name[2]; + B3dStack.getLast().name[3]=header.name[3]; + B3dStack.getLast().length = header.size + 8; + B3dStack.getLast().startposition = file->getPos() - 8; + + bool knownChunk=false; + + if ( strncmp( B3dStack.getLast().name, "VRTS", 4 ) == 0 ) + { + knownChunk=true; + if (!readChunkVRTS(InJoint, 0, Vertices_Start)) + return false; + } + else if ( strncmp( B3dStack.getLast().name, "TRIS", 4 ) == 0 ) + { + knownChunk=true; + + scene::SSkinMeshBuffer *MeshBuffer = AnimatedMesh->createBuffer(); + + if (brush_id!=-1) + MeshBuffer->Material=(*Materials[brush_id].Material); + + if(readChunkTRIS(InJoint, MeshBuffer,AnimatedMesh->getMeshBuffers().size()-1, Vertices_Start)==false) + return false; + + if (!NormalsInFile && MeshBuffer->Material.Lighting) // No point wasting time on lightmapped levels + { + s32 i; + + for ( i=0; i<(s32)MeshBuffer->Indices.size(); i+=3) + { + core::plane3d p( MeshBuffer->getVertex(MeshBuffer->Indices[i+0])->Pos, + MeshBuffer->getVertex(MeshBuffer->Indices[i+1])->Pos, + MeshBuffer->getVertex(MeshBuffer->Indices[i+2])->Pos); + + MeshBuffer->getVertex(MeshBuffer->Indices[i+0])->Normal += p.Normal; + MeshBuffer->getVertex(MeshBuffer->Indices[i+1])->Normal += p.Normal; + MeshBuffer->getVertex(MeshBuffer->Indices[i+2])->Normal += p.Normal; + } + + for ( i = 0; i<(s32)MeshBuffer->getVertexCount(); ++i ) + { + MeshBuffer->getVertex(i)->Normal.normalize (); + BaseVertices[Vertices_Start+i]->Normal=MeshBuffer->getVertex(i)->Normal; + } + } + + + + } + + if (!knownChunk) + { + os::Printer::log("Unknown chunk found in mesh - skipping"); + file->seek( (B3dStack.getLast().startposition + B3dStack.getLast().length) , false); + B3dStack.erase(B3dStack.size()-1); + } + } + + B3dStack.erase(B3dStack.size()-1); + + return true; +} + + +/* +VRTS: + int flags ;1=normal values present, 2=rgba values present + int tex_coord_sets ;texture coords per vertex (eg: 1 for simple U/V) max=8 + int tex_coord_set_size ;components per set (eg: 2 for simple U/V) max=4 + { + float x,y,z ;always present + float nx,ny,nz ;vertex normal: present if (flags&1) + float red,green,blue,alpha ;vertex color: present if (flags&2) + float tex_coords[tex_coord_sets][tex_coord_set_size] ;tex coords + } +*/ +bool CB3DMeshFileLoader::readChunkVRTS(CSkinnedMesh::SJoint *InJoint, scene::SSkinMeshBuffer* MeshBuffer, s32 Vertices_Start) +{ + + s32 flags, tex_coord_sets, tex_coord_set_size; + + file->read(&flags, sizeof(flags)); + file->read(&tex_coord_sets, sizeof(tex_coord_sets)); + file->read(&tex_coord_set_size, sizeof(tex_coord_set_size)); + + #ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); + tex_coord_sets = os::Byteswap::byteswap(tex_coord_sets); + tex_coord_set_size = os::Byteswap::byteswap(tex_coord_set_size); + #endif + + if (tex_coord_sets >= 3 || tex_coord_set_size >= 4) // Something is wrong + { + os::Printer::log("tex_coord_sets or tex_coord_set_size too big", file->getFileName(), ELL_ERROR); + return false; + } + + //------ Allocate Memory, for speed -----------// + + s32 MemoryNeeded = B3dStack.getLast().length / sizeof(f32); + s32 NumberOfReads = 3; + + if (flags & 1) NumberOfReads += 3; + if (flags & 2) NumberOfReads += 4; + + for (s32 i=0; i file->getPos()) // this chunk repeats + { + f32 x=0.0f, y=0.0f, z=0.0f; + f32 nx=0.0f, ny=0.0f, nz=0.0f; + f32 red=1.0f, green=1.0f, blue=1.0f, alpha=1.0f; + f32 tex_coords[3][4]; + + file->read(&x, sizeof(x)); + file->read(&y, sizeof(y)); + file->read(&z, sizeof(z)); + + if (flags & 1) + { + NormalsInFile = true; + file->read(&nx, sizeof(nx)); + file->read(&ny, sizeof(ny)); + file->read(&nz, sizeof(nz)); + } + + if (flags & 2) + { + file->read(&red, sizeof(red)); + file->read(&green, sizeof(green)); + file->read(&blue, sizeof(blue)); + file->read(&alpha, sizeof(alpha)); + } + + for (s32 i=0; iread(&tex_coords[i][j], sizeof(f32)); + + #ifdef __BIG_ENDIAN__ + x = os::Byteswap::byteswap(x); + y = os::Byteswap::byteswap(y); + z = os::Byteswap::byteswap(z); + + if (flags&1) + { + nx = os::Byteswap::byteswap(nx); + ny = os::Byteswap::byteswap(ny); + nz = os::Byteswap::byteswap(nz); + } + + if (flags & 2) + { + red = os::Byteswap::byteswap(red); + green = os::Byteswap::byteswap(green); + blue = os::Byteswap::byteswap(blue); + alpha = os::Byteswap::byteswap(alpha); + } + + for (s32 i=0; i<=tex_coord_sets-1; i++) + for (s32 j=0; j<=tex_coord_set_size-1; j++) + tex_coords[i][j] = os::Byteswap::byteswap(tex_coords[i][j]); + #endif + + f32 tu=0.0f, tv=0.0f; + if (tex_coord_sets >= 1 && tex_coord_set_size >= 2) + { + tu=tex_coords[0][0]; + tv=tex_coords[0][1]; + } + + f32 tu2=0.0f, tv2=0.0f; + if (tex_coord_sets>=2 && tex_coord_set_size>=2) + { + tu2=tex_coords[1][0]; + tv2=tex_coords[1][1]; + } + + // Create Vertex... + video::S3DVertex2TCoords *Vertex=new video::S3DVertex2TCoords + (x, y, z, video::SColorf(red, green, blue, alpha).toSColor(), tu, tv, tu2, tv2); + Vertex->Normal = core::vector3df(nx, ny, nz); + + // Transform the Vertex position by nested node... + core::matrix4 VertexMatrix; + VertexMatrix.setTranslation(Vertex->Pos); + + VertexMatrix = InJoint->GlobalMatrix * VertexMatrix; + Vertex->Pos = VertexMatrix.getTranslation(); + + //Add it... + + BaseVertices.push_back(Vertex); + + AnimatedVertices_VertexID.push_back(-1); + AnimatedVertices_BufferID.push_back(-1); + } + + B3dStack.erase(B3dStack.size()-1); + + return true; +} + + +bool CB3DMeshFileLoader::readChunkTRIS(CSkinnedMesh::SJoint *InJoint, scene::SSkinMeshBuffer *MeshBuffer, u32 MeshBufferID, s32 Vertices_Start) +{ + + s32 triangle_brush_id; // Note: Irrlicht can't have different brushes for each triangle (I'm using a workaround) + + file->read(&triangle_brush_id, sizeof(triangle_brush_id)); + + #ifdef __BIG_ENDIAN__ + triangle_brush_id = os::Byteswap::byteswap(triangle_brush_id); + #endif + + SB3dMaterial *B3dMaterial; + + if (triangle_brush_id != -1) + B3dMaterial = &Materials[triangle_brush_id]; + else + B3dMaterial = 0; + + if (B3dMaterial) + MeshBuffer->Material = (*B3dMaterial->Material); + + s32 MemoryNeeded = B3dStack.getLast().length / sizeof(s32); + MeshBuffer->Indices.reallocate(MemoryNeeded + MeshBuffer->Indices.size() + 1); + + while(B3dStack.getLast().startposition + B3dStack.getLast().length > file->getPos()) // this chunk repeats + { + s32 vertex_id[3]; + + file->read(&vertex_id[0], sizeof(s32)); + file->read(&vertex_id[1], sizeof(s32)); + file->read(&vertex_id[2], sizeof(s32)); + + #ifdef __BIG_ENDIAN__ + vertex_id[0] = os::Byteswap::byteswap(vertex_id[0]); + vertex_id[1] = os::Byteswap::byteswap(vertex_id[1]); + vertex_id[2] = os::Byteswap::byteswap(vertex_id[2]); + #endif + + //Make Ids global: + vertex_id[0] += Vertices_Start; + vertex_id[1] += Vertices_Start; + vertex_id[2] += Vertices_Start; + + for(s32 i=0; i<3; ++i) + { + if (AnimatedVertices_VertexID[ vertex_id[i] ] == -1) //If this vertex is not in the meshbuffer + { + + //Check for lightmapping: + if (BaseVertices[ vertex_id[i] ]->TCoords2 != core::vector2d(0,0)) + MeshBuffer->MoveTo_2TCoords(); //Will only affect the meshbuffer the first time this is called + + //Add the vertex to the meshbuffer: + if (MeshBuffer->VertexType == video::EVT_STANDARD) + MeshBuffer->Vertices_Standard.push_back( *((video::S3DVertex*)BaseVertices[ vertex_id[i] ] ) ); + else + MeshBuffer->Vertices_2TCoords.push_back(*BaseVertices[ vertex_id[i] ] ); + + //create vertex id to meshbuffer index link: + AnimatedVertices_VertexID[ vertex_id[i] ] = MeshBuffer->getVertexCount()-1; + AnimatedVertices_BufferID[ vertex_id[i] ] = MeshBufferID; + + if (B3dMaterial) + { + // Apply Material/Colour/etc... + irr::video::S3DVertex *Vertex=MeshBuffer->getVertex(MeshBuffer->getVertexCount()-1); + + if (Vertex->Color.getAlpha() == 255) //Note: Irrlicht docs state that 0 is opaque, are they wrong? + Vertex->Color.setAlpha( (s32)(B3dMaterial->alpha * 255.0f) ); + + + // Use texture's scale + if (B3dMaterial->Textures[0]) + { + Vertex->TCoords.X *=B3dMaterial->Textures[0]->Xscale; + Vertex->TCoords.Y *=B3dMaterial->Textures[0]->Yscale; + } + /* + if (B3dMaterial->Textures[1]) + { + Vertex->TCoords2.X *=B3dMaterial->Textures[1]->Xscale; + Vertex->TCoords2.Y *=B3dMaterial->Textures[1]->Yscale; + } + */ + + } + } + } + + MeshBuffer->Indices.push_back( AnimatedVertices_VertexID[ vertex_id[0] ] ); + MeshBuffer->Indices.push_back( AnimatedVertices_VertexID[ vertex_id[1] ] ); + MeshBuffer->Indices.push_back( AnimatedVertices_VertexID[ vertex_id[2] ] ); + } + + B3dStack.erase(B3dStack.size()-1); + + return true; +} + + + +bool CB3DMeshFileLoader::readChunkBONE(CSkinnedMesh::SJoint *InJoint) +{ + + if (B3dStack.getLast().length > 8) + { + while(B3dStack.getLast().startposition + B3dStack.getLast().length>file->getPos()) // this chunk repeats + { + CSkinnedMesh::SWeight *Weight=AnimatedMesh->createWeight(InJoint); + + u32 GlobalVertexID; + + file->read(&GlobalVertexID, sizeof(GlobalVertexID)); + file->read(&Weight->strength, sizeof(Weight->strength)); + + #ifdef __BIG_ENDIAN__ + GlobalVertexID = os::Byteswap::byteswap(GlobalVertexID); + Weight->strength = os::Byteswap::byteswap(Weight->strength); + #endif + + + if (AnimatedVertices_VertexID[GlobalVertexID]==-1) + { + os::Printer::log("B3dMeshLoader: Weight has bad vertex id (no link to meshbuffer index found)"); + Weight->vertex_id = Weight->buffer_id = 0; + } + else + { + //Find the MeshBuffer and Vertex index from the Global Vertex ID: + Weight->vertex_id = AnimatedVertices_VertexID[GlobalVertexID]; + Weight->buffer_id = AnimatedVertices_BufferID[GlobalVertexID]; + } + } + } + + B3dStack.erase(B3dStack.size()-1); + return true; +} + + + +bool CB3DMeshFileLoader::readChunkKEYS(CSkinnedMesh::SJoint *InJoint) +{ + + s32 flags; + file->read(&flags, sizeof(flags)); + #ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); + #endif + + while(B3dStack.getLast().startposition + B3dStack.getLast().length>file->getPos()) //this chunk repeats + { + s32 frame; + + f32 positionData[3]; + f32 scaleData[3]; + f32 rotationData[4]; + + file->read(&frame, sizeof(frame)); + + if (flags&1) + readFloats(positionData, 3); + + if (flags&2) + readFloats(scaleData, 3); + + if (flags&4) + readFloats(rotationData, 4); + + #ifdef __BIG_ENDIAN__ + frame = os::Byteswap::byteswap(frame); + #endif + + //frame *= 100; // Scale the animation frames up + + core::vector3df position = core::vector3df(positionData[0], positionData[1], positionData[2]); + core::vector3df scale = core::vector3df(scaleData[0], scaleData[1], scaleData[2]); + core::quaternion rotation = core::quaternion(rotationData[1], rotationData[2], rotationData[3], rotationData[0]); // meant to be in this order + + // Add key frame + + if (flags & 1) + { + CSkinnedMesh::SPositionKey *Key=AnimatedMesh->createPositionKey(InJoint); + Key->frame = (f32)frame; + Key->position = position; + } + if (flags & 2) + { + CSkinnedMesh::SScaleKey *Key=AnimatedMesh->createScaleKey(InJoint); + Key->frame = (f32)frame; + Key->scale=scale; + } + if (flags & 4) + { + CSkinnedMesh::SRotationKey *Key=AnimatedMesh->createRotationKey(InJoint); + Key->frame = (f32)frame; + Key->rotation = rotation; + } + } + + B3dStack.erase(B3dStack.size()-1); + return true; +} + + +bool CB3DMeshFileLoader::readChunkANIM(CSkinnedMesh::SJoint *InJoint) +{ + s32 AnimFlags; //not stored\used + s32 AnimFrames;//not stored\used + f32 AnimFPS; //not stored\used + + file->read(&AnimFlags, sizeof(s32)); + file->read(&AnimFrames, sizeof(s32)); + readFloats(&AnimFPS, 1); + + #ifdef __BIG_ENDIAN__ + AnimFlags = os::Byteswap::byteswap(AnimFlags); + AnimFrames = os::Byteswap::byteswap(AnimFrames); + #endif + + //AnimFrames*=100; //unneed soon... + + B3dStack.erase(B3dStack.size()-1); + return true; +} + +bool CB3DMeshFileLoader::readChunkTEXS() +{ + + bool Previous32BitTextureFlag = SceneManager->getVideoDriver()->getTextureCreationFlag(video::ETCF_ALWAYS_32_BIT); + SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true); + + while(B3dStack.getLast().startposition + B3dStack.getLast().length>file->getPos()) //this chunk repeats + { + core::stringc TextureName=readString(); + + TextureName=stripPathFromString(file->getFileName(),true) + stripPathFromString(TextureName,false); + + SB3dTexture B3dTexture; + B3dTexture.Texture=SceneManager->getVideoDriver()->getTexture ( TextureName.c_str() ); + + file->read(&B3dTexture.Flags, sizeof(s32)); + file->read(&B3dTexture.Blend, sizeof(s32)); + readFloats(&B3dTexture.Xpos, 1); + readFloats(&B3dTexture.Ypos, 1); + readFloats(&B3dTexture.Xscale, 1); + readFloats(&B3dTexture.Yscale, 1); + readFloats(&B3dTexture.Angle, 1); + + #ifdef __BIG_ENDIAN__ + B3dTexture.Flags = os::Byteswap::byteswap(B3dTexture.Flags); + B3dTexture.Blend = os::Byteswap::byteswap(B3dTexture.Blend); + #endif + + Textures.push_back(B3dTexture); + } + + B3dStack.erase(B3dStack.size()-1); + + SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, Previous32BitTextureFlag); + + return true; +} + +bool CB3DMeshFileLoader::readChunkBRUS() +{ + + s32 n_texs; + + file->read(&n_texs, sizeof(s32)); + + #ifdef __BIG_ENDIAN__ + n_texs = os::Byteswap::byteswap(n_texs); + #endif + + while(B3dStack.getLast().startposition + B3dStack.getLast().length>file->getPos()) //this chunk repeats + { + // This is what blitz basic calls a brush, like a Irrlicht Material + + core::stringc MaterialName=readString(); //Not used but we still need the read it + + SB3dMaterial B3dMaterial; + + B3dMaterial.Material = new irr::video::SMaterial(); + B3dMaterial.Textures[0]=0; + B3dMaterial.Textures[1]=0; + + s32 texture_id[8]; + texture_id[0]=-1; + texture_id[1]=-1; + + file->read(&B3dMaterial.red, sizeof(B3dMaterial.red)); + file->read(&B3dMaterial.green, sizeof(B3dMaterial.green)); + file->read(&B3dMaterial.blue, sizeof(B3dMaterial.blue)); + file->read(&B3dMaterial.alpha, sizeof(B3dMaterial.alpha)); + file->read(&B3dMaterial.shininess, sizeof(B3dMaterial.shininess)); + file->read(&B3dMaterial.blend, sizeof(B3dMaterial.blend)); + file->read(&B3dMaterial.fx, sizeof(B3dMaterial.fx)); + + for (s32 n=0; n < n_texs; ++n) + file->read(&texture_id[n], sizeof(s32)); //I'm not sure of getting the sizeof an array + + #ifdef __BIG_ENDIAN__ + B3dMaterial.red = os::Byteswap::byteswap(B3dMaterial.red); + B3dMaterial.green = os::Byteswap::byteswap(B3dMaterial.green); + B3dMaterial.blue = os::Byteswap::byteswap(B3dMaterial.blue); + B3dMaterial.alpha = os::Byteswap::byteswap(B3dMaterial.alpha); + B3dMaterial.shininess = os::Byteswap::byteswap(B3dMaterial.shininess); + B3dMaterial.blend = os::Byteswap::byteswap(B3dMaterial.blend); + B3dMaterial.fx = os::Byteswap::byteswap(B3dMaterial.fx); + + for (s32 n=0; n < n_texs; ++n) + texture_id[n] = os::Byteswap::byteswap(texture_id[n]); + #endif + + //------ Get pointers to the texture, based on the IDs ------ + if (texture_id[0] != -1) + B3dMaterial.Textures[0]=&Textures[texture_id[0]]; + if (texture_id[1] != -1) + B3dMaterial.Textures[1]=&Textures[texture_id[1]]; + + + //Fixes problems when the lightmap is on the first texture: + if (texture_id[0] != -1) + if (Textures[texture_id[0]].Flags & 65536) // 65536 = secondary UV + { + SB3dTexture *TmpTexture; + TmpTexture = B3dMaterial.Textures[1]; + B3dMaterial.Textures[1] = B3dMaterial.Textures[0]; + B3dMaterial.Textures[0] = TmpTexture; + } + + if (B3dMaterial.Textures[0] != 0) + B3dMaterial.Material->Textures[0] = B3dMaterial.Textures[0]->Texture; + if (B3dMaterial.Textures[1] != 0) + B3dMaterial.Material->Textures[1] = B3dMaterial.Textures[1]->Texture; + + //If the first texture is empty: + if (B3dMaterial.Textures[1] != 0 && B3dMaterial.Textures[0] == 0) + { + B3dMaterial.Textures[0] = B3dMaterial.Textures[1]; + B3dMaterial.Textures[1] = 0; + } + + //------ Convert blitz flags/blend to irrlicht ------- + + //Two textures: + if (B3dMaterial.Textures[1]) + { + if (B3dMaterial.alpha==1) + { + if (B3dMaterial.Textures[1]->Blend & 5) //(Multiply 2) + B3dMaterial.Material->MaterialType = video::EMT_LIGHTMAP_M2; + else + B3dMaterial.Material->MaterialType = video::EMT_LIGHTMAP; + } + else + B3dMaterial.Material->MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; + } + + //One texture: + else if (B3dMaterial.Textures[0]) + { + if (B3dMaterial.Textures[0]->Flags & 2) //(Alpha mapped) + B3dMaterial.Material->MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; + else if (B3dMaterial.Textures[0]->Flags & 4) //(Masked) + B3dMaterial.Material->MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; // Todo: create color key texture + else if (B3dMaterial.alpha == 1) + B3dMaterial.Material->MaterialType = video::EMT_SOLID; + else + B3dMaterial.Material->MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; + } + + //No texture: + else + { + if (B3dMaterial.alpha == 1) + B3dMaterial.Material->MaterialType = video::EMT_SOLID; + else + B3dMaterial.Material->MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; + } + + B3dMaterial.Material->AmbientColor = video::SColorf(B3dMaterial.red, B3dMaterial.green, B3dMaterial.blue, B3dMaterial.alpha).toSColor (); + + //------ Material fx ------ + + if (B3dMaterial.fx & 1) //full-bright + { + B3dMaterial.Material->AmbientColor = video::SColor(255, 255, 255, 255); + B3dMaterial.Material->Lighting = false; + } + + //if (B3dMaterial.fx & 2) //use vertex colors instead of brush color + + if (B3dMaterial.fx & 4) //flatshaded + B3dMaterial.Material->GouraudShading = false; + + if (B3dMaterial.fx & 16) //disable backface culling + B3dMaterial.Material->BackfaceCulling = false; + + if (B3dMaterial.fx & 32) //force vertex alpha-blending + B3dMaterial.Material->MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; + + B3dMaterial.Material->DiffuseColor = video::SColorf(B3dMaterial.red, B3dMaterial.green, B3dMaterial.blue, B3dMaterial.alpha).toSColor (); + B3dMaterial.Material->EmissiveColor = video::SColorf(0.5, 0.5, 0.5, 0).toSColor (); + B3dMaterial.Material->SpecularColor = video::SColorf(0, 0, 0, 0).toSColor (); + B3dMaterial.Material->Shininess = B3dMaterial.shininess; + + Materials.push_back(B3dMaterial); + } + + B3dStack.erase(B3dStack.size()-1); + + return true; +} + +core::stringc CB3DMeshFileLoader::readString() +{ + core::stringc newstring; + while (file->getPos() <= file->getSize()) + { + c8 character; + file->read(&character, sizeof(character)); + if (character==0) return newstring; + newstring.append(character); + } + return newstring; +} + +core::stringc CB3DMeshFileLoader::stripPathFromString(core::stringc string, bool returnPath) +{ + s32 slashIndex=string.findLast('/'); // forward slash + s32 backSlash=string.findLast('\\'); // back slash + + if (backSlash>slashIndex) slashIndex=backSlash; + + if (slashIndex==-1)//no slashes found + if (returnPath) + return core::stringc(); //no path to return + else + return string; + + if (returnPath) + return string.subString(0, slashIndex + 1); + else + return string.subString(slashIndex+1, string.size() - (slashIndex+1)); +} + +void CB3DMeshFileLoader::readFloats(f32* vec, u32 count) +{ + file->read(vec, count*sizeof(f32)); + #ifdef __BIG_ENDIAN__ + for (u32 n=0; n B3dStack; + + bool NormalsInFile; + + core::array Materials; + core::array Textures; + + core::array AnimatedVertices_VertexID; + + core::array AnimatedVertices_BufferID; + + core::array BaseVertices; + + + core::array *Buffers; + core::array *AllJoints; + + // + ISceneManager* SceneManager; + CSkinnedMesh* AnimatedMesh; + io::IReadFile* file; + + + +}; + +} // end namespace scene +} // end namespace irr + +#endif // __C_B3D_MESH_LOADER_H_INCLUDED__ + diff --git a/source/Irrlicht/CBSPMeshFileLoader.cpp b/source/Irrlicht/CBSPMeshFileLoader.cpp new file mode 100644 index 00000000..1148800a --- /dev/null +++ b/source/Irrlicht/CBSPMeshFileLoader.cpp @@ -0,0 +1,87 @@ +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_BSP_LOADER_ + +#include "CBSPMeshFileLoader.h" +#include "CQ3LevelMesh.h" + +namespace irr +{ +namespace scene +{ + +//! Constructor +CBSPMeshFileLoader::CBSPMeshFileLoader(io::IFileSystem* fs,video::IVideoDriver* driver, scene::ISceneManager* smgr) +: FileSystem(fs), Driver(driver), SceneManager(smgr) +{ + if (FileSystem) + FileSystem->grab(); + + if (Driver) + Driver->grab(); + +} + + + +//! destructor +CBSPMeshFileLoader::~CBSPMeshFileLoader() +{ + if (FileSystem) + FileSystem->drop(); + + if (Driver) + Driver->drop(); + +} + + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".bsp") +bool CBSPMeshFileLoader::isALoadableFileExtension(const c8* filename) +{ + return strstr(filename, ".bsp") || strstr(filename, ".shader"); +} + + + +//! creates/loads an animated mesh from the file. +//! \return Pointer to the created mesh. Returns 0 if loading failed. +//! If you no longer need the mesh, you should call IAnimatedMesh::drop(). +//! See IUnknown::drop() for more information. +IAnimatedMesh* CBSPMeshFileLoader::createMesh(irr::io::IReadFile* file) +{ + // load quake 3 bsp + if (strstr(file->getFileName(), ".bsp")) + { + CQ3LevelMesh* q = new CQ3LevelMesh(FileSystem, Driver, SceneManager); + + q->getShader ( "scripts/models.shader", 1 ); + q->getShader ( "scripts/liquid.shader", 1 ); + //q->getShader ( "scripts/sky.shader", 1 ); + + if ( q->loadFile(file) ) + return q; + + q->drop(); + } + + // load quake 3 shader container + if (strstr(file->getFileName(), ".shader")) + { + CQ3LevelMesh* q = new CQ3LevelMesh(FileSystem, Driver, SceneManager); + q->getShader ( file->getFileName(), 1 ); + return q; + } + + return 0; +} + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_BSP_LOADER_ diff --git a/source/Irrlicht/CDefaultMeshFormatLoader.h b/source/Irrlicht/CBSPMeshFileLoader.h similarity index 66% rename from source/Irrlicht/CDefaultMeshFormatLoader.h rename to source/Irrlicht/CBSPMeshFileLoader.h index 6dda26be..c3dd9b05 100644 --- a/source/Irrlicht/CDefaultMeshFormatLoader.h +++ b/source/Irrlicht/CBSPMeshFileLoader.h @@ -2,8 +2,8 @@ // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h -#ifndef __C_DEFAULT_MESH_FORMAT_LOADER_H_INCLUDED__ -#define __C_DEFAULT_MESH_FORMAT_LOADER_H_INCLUDED__ +#ifndef __C_BSP_MESH_FILE_LOADER_H_INCLUDED__ +#define __C_BSP_MESH_FILE_LOADER_H_INCLUDED__ #include "IMeshLoader.h" #include "IFileSystem.h" @@ -15,17 +15,16 @@ namespace irr namespace scene { -//! Meshloader capable of loading all Irrlicht default build in formats. -/** Which are: Quake 3 Bsp level, Quake 2 MD2 model, Milkshape .ms3d model. */ -class CDefaultMeshFormatLoader : public IMeshLoader +//! Meshloader capable of loading Quake 3 BSP files and shaders +class CBSPMeshFileLoader : public IMeshLoader { public: //! Constructor - CDefaultMeshFormatLoader(io::IFileSystem* fs, video::IVideoDriver* driver, scene::ISceneManager* smgr); + CBSPMeshFileLoader(io::IFileSystem* fs, video::IVideoDriver* driver, scene::ISceneManager* smgr); //! destructor - virtual ~CDefaultMeshFormatLoader(); + virtual ~CBSPMeshFileLoader(); //! returns true if the file maybe is able to be loaded by this class //! based on the file extension (e.g. ".bsp") diff --git a/source/Irrlicht/CBoneSceneNode.cpp b/source/Irrlicht/CBoneSceneNode.cpp new file mode 100644 index 00000000..83eee19c --- /dev/null +++ b/source/Irrlicht/CBoneSceneNode.cpp @@ -0,0 +1,124 @@ + +#include "CBoneSceneNode.h" + + + +namespace irr +{ +namespace scene +{ + +//! constructor +CBoneSceneNode::CBoneSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, + u32 boneIndex, const c8* boneName) +: IBoneSceneNode(parent, mgr, id), AnimationMode(EBAM_AUTOMATIC), + BoneIndex(boneIndex), BoneName(boneName) +{ + +} + +//! destructor +CBoneSceneNode::~CBoneSceneNode() +{ + +} + +//! Returns the name of the bone +const c8* CBoneSceneNode::getBoneName() const +{ + return BoneName.c_str(); +} + +//! Returns the index of the bone +u32 CBoneSceneNode::getBoneIndex() const +{ + return BoneIndex; +} + +//! Sets the animation mode of the bone. Returns true if successful. +bool CBoneSceneNode::setAnimationMode(E_BONE_ANIMATION_MODE mode) +{ + AnimationMode = mode; + return true; +} + +//! Gets the current animation mode of the bone +E_BONE_ANIMATION_MODE CBoneSceneNode::getAnimationMode() const +{ + return AnimationMode; +} + +//! returns the axis aligned bounding box of this node +const core::aabbox3d& CBoneSceneNode::getBoundingBox() const +{ + return Box; +} +/* +//! Returns the relative transformation of the scene node. +core::matrix4 CBoneSceneNode::getRelativeTransformation() const +{ + return core::matrix4(); // RelativeTransformation; +} +*/ + +void CBoneSceneNode::OnAnimate(u32 timeMs) +{ + if (IsVisible) + { + // animate this node with all animators + + core::list::Iterator ait = Animators.begin(); + for (; ait != Animators.end(); ++ait) + (*ait)->animateNode(this, timeMs); + + // update absolute position + //updateAbsolutePosition(); + + // perform the post render process on all children + core::list::Iterator it = Children.begin(); + for (; it != Children.end(); ++it) + (*it)->OnAnimate(timeMs); + } +} + + + + +void CBoneSceneNode::helper_updateAbsolutePositionOfAllChildren(ISceneNode *Node) +{ + Node->updateAbsolutePosition(); + + core::list::Iterator it = Node->getChildren().begin(); + for (; it != Node->getChildren().end(); ++it) + { + helper_updateAbsolutePositionOfAllChildren( (*it) ); + } +} + + +void CBoneSceneNode::updateAbsolutePositionOfAllChildren() +{ + helper_updateAbsolutePositionOfAllChildren( this ); +} + + + + + +void CBoneSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) +{ + out->addInt("BoneIndex", BoneIndex); + out->addString("BoneName", BoneName.c_str()); + out->addEnum("AnimationMode", AnimationMode, BoneAnimationModeNames); +} + +void CBoneSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + BoneIndex = in->getAttributeAsInt("BoneIndex"); + BoneName = in->getAttributeAsString("BoneName"); + AnimationMode = (E_BONE_ANIMATION_MODE)in->getAttributeAsEnumeration("AnimationMode", BoneAnimationModeNames); + // todo: add/replace bone in parent with bone from mesh +} + +} // namespace scene +} // namespace irr diff --git a/source/Irrlicht/CBoneSceneNode.h b/source/Irrlicht/CBoneSceneNode.h new file mode 100644 index 00000000..8efd9f03 --- /dev/null +++ b/source/Irrlicht/CBoneSceneNode.h @@ -0,0 +1,71 @@ +#ifndef __C_BONE_SCENE_NODE_H_INCLUDED__ +#define __C_BONE_SCENE_NODE_H_INCLUDED__ + +// Used with SkinnedMesh and IAnimatedMeshSceneNode, for boned meshes + +#include "IBoneSceneNode.h" +#include "irrString.h" + + +namespace irr +{ +namespace scene +{ + + class CBoneSceneNode : public IBoneSceneNode + { + public: + + //! constructor + CBoneSceneNode(ISceneNode* parent, ISceneManager* mgr, + s32 id=-1, u32 boneIndex=0, const c8* boneName=0); + + //! destructor + ~CBoneSceneNode(); + + //! Returns the name of the bone + virtual const c8* getBoneName() const; + + //! Returns the index of the bone + virtual u32 getBoneIndex() const; + + //! Sets the animation mode of the bone. Returns true if successful. + virtual bool setAnimationMode(E_BONE_ANIMATION_MODE mode); + + //! Gets the current animation mode of the bone + virtual E_BONE_ANIMATION_MODE getAnimationMode() const; + + //! returns the axis aligned bounding box of this node + virtual const core::aabbox3d& getBoundingBox() const; + + //! Returns the relative transformation of the scene node. + //virtual core::matrix4 getRelativeTransformation() const; + + virtual void OnAnimate(u32 timeMs); + + + void helper_updateAbsolutePositionOfAllChildren(ISceneNode *Node); + + virtual void updateAbsolutePositionOfAllChildren(); + + //! Writes attributes of the scene node. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0); + + //! Reads attributes of the scene node. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0); + + private: + E_BONE_ANIMATION_MODE AnimationMode; + u32 BoneIndex; + core::stringc BoneName; + + core::aabbox3d Box; + }; + +} // end namespace scene +} // end namespace irr + + + +#endif + diff --git a/source/Irrlicht/CCSMLoader.cpp b/source/Irrlicht/CCSMLoader.cpp index e18d2376..8d634c2f 100644 --- a/source/Irrlicht/CCSMLoader.cpp +++ b/source/Irrlicht/CCSMLoader.cpp @@ -5,6 +5,9 @@ // This file was written by Saurav Mohapatra and modified by Nikolaus Gebhardt. // See CCSMLoader.h for details. +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_CSM_LOADER_ + #include "CCSMLoader.h" #include "os.h" #include "IFileSystem.h" @@ -871,3 +874,4 @@ namespace scene } // end namespace } // end namespace +#endif // _IRR_COMPILE_WITH_CSM_LOADER_ diff --git a/source/Irrlicht/CColladaFileLoader.cpp b/source/Irrlicht/CColladaFileLoader.cpp index d4972542..a702ab50 100644 --- a/source/Irrlicht/CColladaFileLoader.cpp +++ b/source/Irrlicht/CColladaFileLoader.cpp @@ -2,6 +2,9 @@ // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_COLLADA_LOADER_ + #include "CColladaFileLoader.h" #include "os.h" #include "IXMLReader.h" @@ -1564,3 +1567,4 @@ void CColladaFileLoader::uriToId(core::stringc& str) } // end namespace scene } // end namespace irr +#endif // _IRR_COMPILE_WITH_COLLADA_LOADER_ diff --git a/source/Irrlicht/CDMFLoader.cpp b/source/Irrlicht/CDMFLoader.cpp index 9dd003b5..9bd340b2 100644 --- a/source/Irrlicht/CDMFLoader.cpp +++ b/source/Irrlicht/CDMFLoader.cpp @@ -13,6 +13,9 @@ See the header file for additional information including use and distribution rights. */ +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_DMF_LOADER_ + #include "CDMFLoader.h" #include "ISceneManager.h" #include "IAttributes.h" @@ -441,3 +444,5 @@ bool CDMFLoader::isALoadableFileExtension(const c8* filename) } // end namespace scene } // end namespace irr +#endif // _IRR_COMPILE_WITH_DMF_LOADER_ + diff --git a/source/Irrlicht/CDefaultMeshFormatLoader.cpp b/source/Irrlicht/CDefaultMeshFormatLoader.cpp deleted file mode 100644 index 9ee0dccd..00000000 --- a/source/Irrlicht/CDefaultMeshFormatLoader.cpp +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (C) 2002-2007 Nikolaus Gebhardt -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#include "CDefaultMeshFormatLoader.h" -#include "CAnimatedMeshMD2.h" -#include "CAnimatedMeshMS3D.h" -#include "CQ3LevelMesh.h" -#include "CAnimatedMeshB3d.h" - -namespace irr -{ -namespace scene -{ - -//! Constructor -CDefaultMeshFormatLoader::CDefaultMeshFormatLoader(io::IFileSystem* fs,video::IVideoDriver* driver, scene::ISceneManager* smgr) -: FileSystem(fs), Driver(driver), SceneManager(smgr) -{ - if (FileSystem) - FileSystem->grab(); - - if (Driver) - Driver->grab(); - -} - - - -//! destructor -CDefaultMeshFormatLoader::~CDefaultMeshFormatLoader() -{ - if (FileSystem) - FileSystem->drop(); - - if (Driver) - Driver->drop(); - -} - - - -//! returns true if the file maybe is able to be loaded by this class -//! based on the file extension (e.g. ".bsp") -bool CDefaultMeshFormatLoader::isALoadableFileExtension(const c8* filename) -{ - return strstr(filename, ".md2") || strstr(filename, ".b3d") || - strstr(filename, ".ms3d") || strstr(filename, ".bsp") || - strstr(filename, ".shader"); -} - - - -//! creates/loads an animated mesh from the file. -//! \return Pointer to the created mesh. Returns 0 if loading failed. -//! If you no longer need the mesh, you should call IAnimatedMesh::drop(). -//! See IUnknown::drop() for more information. -IAnimatedMesh* CDefaultMeshFormatLoader::createMesh(irr::io::IReadFile* file) -{ - IAnimatedMesh* msh = 0; - - // This method loads a mesh if it cans. - // Someday I will have to refactor this, and split the DefaultMeshFormatloader - // into one loader for every format. - - bool success = false; - - // load quake 2 md2 model - if (strstr(file->getFileName(), ".md2")) - { - msh = new CAnimatedMeshMD2(); - success = ((CAnimatedMeshMD2*)msh)->loadFile(file); - if (success) - return msh; - - msh->drop(); - } - - // load milkshape - if (strstr(file->getFileName(), ".ms3d")) - { - msh = new CAnimatedMeshMS3D(Driver); - success = ((CAnimatedMeshMS3D*)msh)->loadFile(file); - if (success) - return msh; - - msh->drop(); - } - - // load quake 3 bsp - if (strstr(file->getFileName(), ".bsp")) - { - CQ3LevelMesh* q = new CQ3LevelMesh(FileSystem, Driver, SceneManager); - - q->getShader ( "scripts/models.shader", 1 ); - q->getShader ( "scripts/liquid.shader", 1 ); - //q->getShader ( "scripts/sky.shader", 1 ); - - if ( q->loadFile(file) ) - return q; - - q->drop(); - } - - // load quake 3 shader container - if (strstr(file->getFileName(), ".shader")) - { - CQ3LevelMesh* q = new CQ3LevelMesh(FileSystem, Driver, SceneManager); - q->getShader ( file->getFileName(), 1 ); - return q; - } - - // load blitz basic - if (strstr(file->getFileName(), ".b3d")) - { - file->seek(0); - - msh = new CAnimatedMeshB3d(Driver); - success = ((CAnimatedMeshB3d*)msh)->loadFile(file); - if (success) - return msh; - - msh->drop(); - } - - return 0; -} - -} // end namespace scene -} // end namespace irr - diff --git a/source/Irrlicht/CLMTSMeshFileLoader.cpp b/source/Irrlicht/CLMTSMeshFileLoader.cpp index 94c1c3d4..b3eb0e9f 100644 --- a/source/Irrlicht/CLMTSMeshFileLoader.cpp +++ b/source/Irrlicht/CLMTSMeshFileLoader.cpp @@ -74,6 +74,9 @@ Version 1.0 - 29 July 2004 */ ////////////////////////////////////////////////////////////////////// +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_LMTS_LOADER_ + #include "SMeshBufferLightMap.h" #include "SAnimatedMesh.h" #include "SMeshBuffer.h" @@ -354,3 +357,5 @@ void CLMTSMeshFileLoader::loadTextures() } // end namespace scene } // end namespace irr + +#endif // _IRR_COMPILE_WITH_LMTS_LOADER_ diff --git a/source/Irrlicht/CMD2MeshFileLoader.cpp b/source/Irrlicht/CMD2MeshFileLoader.cpp new file mode 100644 index 00000000..d39aabfe --- /dev/null +++ b/source/Irrlicht/CMD2MeshFileLoader.cpp @@ -0,0 +1,54 @@ +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_MD2_LOADER_ + +#include "CMD2MeshFileLoader.h" +#include "CAnimatedMeshMD2.h" + +namespace irr +{ +namespace scene +{ + +//! Constructor +CMD2MeshFileLoader::CMD2MeshFileLoader() +{ +} + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".bsp") +bool CMD2MeshFileLoader::isALoadableFileExtension(const c8* filename) +{ + return strstr(filename, ".md2")!=0; +} + + + +//! creates/loads an animated mesh from the file. +//! \return Pointer to the created mesh. Returns 0 if loading failed. +//! If you no longer need the mesh, you should call IAnimatedMesh::drop(). +//! See IUnknown::drop() for more information. +IAnimatedMesh* CMD2MeshFileLoader::createMesh(irr::io::IReadFile* file) +{ + IAnimatedMesh* msh = 0; + + bool success = false; + msh = new CAnimatedMeshMD2(); + success = ((CAnimatedMeshMD2*)msh)->loadFile(file); + if (success) + return msh; + + msh->drop(); + + return 0; +} + +} // end namespace scene +} // end namespace irr + + +#endif // _IRR_COMPILE_WITH_MD2_LOADER_ diff --git a/source/Irrlicht/CMD2MeshFileLoader.h b/source/Irrlicht/CMD2MeshFileLoader.h new file mode 100644 index 00000000..a692e10f --- /dev/null +++ b/source/Irrlicht/CMD2MeshFileLoader.h @@ -0,0 +1,39 @@ +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_MD2_MESH_FILE_LOADER_H_INCLUDED__ +#define __C_MD2_MESH_FILE_LOADER_H_INCLUDED__ + +#include "IMeshLoader.h" + +namespace irr +{ +namespace scene +{ + +//! Meshloader capable of loading MD2 files +class CMD2MeshFileLoader : public IMeshLoader +{ +public: + + //! Constructor + CMD2MeshFileLoader(); + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".bsp") + virtual bool isALoadableFileExtension(const c8* fileName); + + //! creates/loads an animated mesh from the file. + //! \return Pointer to the created mesh. Returns 0 if loading failed. + //! If you no longer need the mesh, you should call IAnimatedMesh::drop(). + //! See IUnknown::drop() for more information. + virtual IAnimatedMesh* createMesh(irr::io::IReadFile* file); + +}; + +} // end namespace scene +} // end namespace irr + +#endif // __C_MD2_MESH_LOADER_H_INCLUDED__ + diff --git a/source/Irrlicht/CMD3MeshFileLoader.cpp b/source/Irrlicht/CMD3MeshFileLoader.cpp index 5fcbf450..603e9956 100644 --- a/source/Irrlicht/CMD3MeshFileLoader.cpp +++ b/source/Irrlicht/CMD3MeshFileLoader.cpp @@ -2,6 +2,9 @@ // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_MD3_LOADER_ + #include "CMD3MeshFileLoader.h" #include "CAnimatedMeshMD3.h" #include "irrString.h" @@ -47,3 +50,4 @@ IAnimatedMesh* CMD3MeshFileLoader::createMesh(irr::io::IReadFile* file) } // end namespace scene } // end namespace irr +#endif // _IRR_COMPILE_WITH_MD3_LOADER_ diff --git a/source/Irrlicht/CMS3DMeshFileLoader.cpp b/source/Irrlicht/CMS3DMeshFileLoader.cpp new file mode 100644 index 00000000..31e44d31 --- /dev/null +++ b/source/Irrlicht/CMS3DMeshFileLoader.cpp @@ -0,0 +1,605 @@ +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_MS3D_LOADER_ + +#include "IReadFile.h" +#include "os.h" +#include "CMS3DMeshFileLoader.h" +#include "CSkinnedMesh.h" + + + +namespace irr +{ +namespace scene +{ + +// byte-align structures +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__) +# pragma pack( push, packing ) +# pragma pack( 1 ) +# define PACK_STRUCT +#elif defined( __GNUC__ ) +# define PACK_STRUCT __attribute__((packed)) +#else +# error compiler not supported +#endif + +// File header +struct MS3DHeader +{ + c8 ID[10]; + s32 Version; +} PACK_STRUCT; + +// Vertex information +struct MS3DVertex +{ + u8 Flags; + f32 Vertex[3]; + s8 BoneID; + u8 RefCount; +} PACK_STRUCT; + +// Triangle information +struct MS3DTriangle +{ + u16 Flags; + u16 VertexIndices[3]; + f32 VertexNormals[3][3]; + f32 S[3], T[3]; + u8 SmoothingGroup; + u8 GroupIndex; +} PACK_STRUCT; + +// Material information +struct MS3DMaterial +{ + s8 Name[32]; + f32 Ambient[4]; + f32 Diffuse[4]; + f32 Specular[4]; + f32 Emissive[4]; + f32 Shininess; // 0.0f - 128.0f + f32 Transparency; // 0.0f - 1.0f + u8 Mode; // 0, 1, 2 is unused now + s8 Texture[128]; + s8 Alphamap[128]; +} PACK_STRUCT; + +// Joint information +struct MS3DJoint +{ + u8 Flags; + s8 Name[32]; + s8 ParentName[32]; + f32 Rotation[3]; + f32 Translation[3]; + u16 NumRotationKeyframes; + u16 NumTranslationKeyframes; +} PACK_STRUCT; + +// Keyframe data +struct MS3DKeyframe +{ + f32 Time; + f32 Parameter[3]; +} PACK_STRUCT; + +// Default alignment +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__) +# pragma pack( pop, packing ) +#endif + +#undef PACK_STRUCT + +//! Constructor +CMS3DMeshFileLoader::CMS3DMeshFileLoader(video::IVideoDriver *driver) +: Driver(driver), AnimatedMesh(0) +{ +} + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".bsp") +bool CMS3DMeshFileLoader::isALoadableFileExtension(const c8* filename) +{ + return strstr(filename, ".ms3d")!=0; +} + + + +//! creates/loads an animated mesh from the file. +//! \return Pointer to the created mesh. Returns 0 if loading failed. +//! If you no longer need the mesh, you should call IAnimatedMesh::drop(). +//! See IUnknown::drop() for more information. +IAnimatedMesh* CMS3DMeshFileLoader::createMesh(irr::io::IReadFile* file) +{ + if (!file) + return 0; + + AnimatedMesh = new CSkinnedMesh(); + + if ( load(file) ) + { + AnimatedMesh->finalize(); + } + else + { + AnimatedMesh->drop(); + AnimatedMesh = 0; + } + + return AnimatedMesh; +} + + +//! loads an md2 file +bool CMS3DMeshFileLoader::load(io::IReadFile* file) +{ + if (!file) + return false; + + // find file size + s32 fileSize = file->getSize(); + + // read whole file + + u8* buffer = new u8[fileSize]; + s32 read = file->read(buffer, fileSize); + if (read != fileSize) + { + delete [] buffer; + os::Printer::log("Could not read full file. Loading failed", file->getFileName(), ELL_ERROR); + return false; + } + + // read header + + const u8 *pPtr = (u8*)((void*)buffer); + MS3DHeader *pHeader = (MS3DHeader*)pPtr; + pPtr += sizeof(MS3DHeader); + + if ( strncmp( pHeader->ID, "MS3D000000", 10 ) != 0 ) + { + delete [] buffer; + os::Printer::log("Not a valid Milkshape3D Model File. Loading failed", file->getFileName(), ELL_ERROR); + return false; + } + +#ifdef __BIG_ENDIAN__ + pHeader->Version = os::Byteswap::byteswap(pHeader->Version); +#endif + if ( pHeader->Version < 3 || pHeader->Version > 4 ) + { + delete [] buffer; + os::Printer::log("Only Milkshape3D version 1.3 and 1.4 is supported. Loading failed", file->getFileName(), ELL_ERROR); + return false; + } + + // get pointers to data + + // vertices + u16 numVertices = *(u16*)pPtr; +#ifdef __BIG_ENDIAN__ + numVertices = os::Byteswap::byteswap(numVertices); +#endif + pPtr += sizeof(u16); + MS3DVertex *vertices = (MS3DVertex*)pPtr; + pPtr += sizeof(MS3DVertex) * numVertices; +#ifdef __BIG_ENDIAN__ + for (u16 tmp=0; tmpcreateBuffer(); + + } + + for (i=0; iAmbient[j] = os::Byteswap::byteswap(material->Ambient[j]); + for (u16 j=0; j<4; ++j) + material->Diffuse[j] = os::Byteswap::byteswap(material->Diffuse[j]); + for (u16 j=0; j<4; ++j) + material->Specular[j] = os::Byteswap::byteswap(material->Specular[j]); + for (u16 j=0; j<4; ++j) + material->Emissive[j] = os::Byteswap::byteswap(material->Emissive[j]); + material->Shininess = os::Byteswap::byteswap(material->Shininess); + material->Transparency = os::Byteswap::byteswap(material->Transparency); +#endif + pPtr += sizeof(MS3DMaterial); + + + scene::SSkinMeshBuffer *tmpBuffer = AnimatedMesh->createBuffer(); + + tmpBuffer->Material.MaterialType = video::EMT_SOLID; + + tmpBuffer->Material.AmbientColor = video::SColorf(material->Ambient[0], material->Ambient[1], material->Ambient[2], material->Ambient[3]).toSColor (); + tmpBuffer->Material.DiffuseColor = video::SColorf(material->Diffuse[0], material->Diffuse[1], material->Diffuse[2], material->Diffuse[3]).toSColor (); + tmpBuffer->Material.EmissiveColor = video::SColorf(material->Emissive[0], material->Emissive[1], material->Emissive[2], material->Emissive[3]).toSColor (); + tmpBuffer->Material.SpecularColor = video::SColorf(material->Specular[0], material->Specular[1], material->Specular[2], material->Specular[3]).toSColor (); + tmpBuffer->Material.Shininess = material->Shininess; + + core::stringc TexturePath=(const c8*)material->Texture; + TexturePath.trim(); + if (TexturePath!="") + { + TexturePath=stripPathFromString(file->getFileName(),true) + stripPathFromString(TexturePath,false); + tmpBuffer->Material.Textures[0] = Driver->getTexture(TexturePath.c_str() ); + } + + core::stringc AlphamapPath=(const c8*)material->Alphamap; + AlphamapPath.trim(); + if (AlphamapPath!="") + { + AlphamapPath=stripPathFromString(file->getFileName(),true) + stripPathFromString(AlphamapPath,false); + tmpBuffer->Material.Textures[2] = Driver->getTexture(AlphamapPath.c_str() ); + } + + } + + // animation time + f32 framesPerSecond = *(f32*)pPtr; +#ifdef __BIG_ENDIAN__ + framesPerSecond = os::Byteswap::byteswap(framesPerSecond); +#endif + pPtr += sizeof(f32) * 2; // fps and current time + + + if (framesPerSecond==0) + framesPerSecond=1; + + s32 frameCount = *(s32*)pPtr; +#ifdef __BIG_ENDIAN__ + frameCount = os::Byteswap::byteswap(frameCount); +#endif + pPtr += sizeof(s32); + + + u16 jointCount = *(u16*)pPtr; +#ifdef __BIG_ENDIAN__ + jointCount = os::Byteswap::byteswap(jointCount); +#endif + pPtr += sizeof(u16); + + + core::array ParentNames; + + // load joints + for (i=0; iRotation[j] = os::Byteswap::byteswap(pJoint->Rotation[j]); + for (j=0; j<3; ++j) + pJoint->Translation[j] = os::Byteswap::byteswap(pJoint->Translation[j]); + pJoint->NumRotationKeyframes= os::Byteswap::byteswap(pJoint->NumRotationKeyframes); + pJoint->NumTranslationKeyframes = os::Byteswap::byteswap(pJoint->NumTranslationKeyframes); +#endif + pPtr += sizeof(MS3DJoint); + + + + ISkinnedMesh::SJoint *jnt = AnimatedMesh->createJoint(); + + /* + jnt.Name = pJoint->Name; + jnt.Index = i; + jnt.Rotation.X = pJoint->Rotation[0]; + jnt.Rotation.Y = pJoint->Rotation[1]; + jnt.Rotation.Z = pJoint->Rotation[2]; + jnt.Translation.X = pJoint->Translation[0]; + jnt.Translation.Y = pJoint->Translation[1]; + jnt.Translation.Z = pJoint->Translation[2]; + jnt.ParentName = pJoint->ParentName; + jnt.Parent = -1; + */ + + jnt->Name = pJoint->Name; + + jnt->LocalMatrix.makeIdentity(); + + + jnt->LocalMatrix.setRotationRadians( + core::vector3df(pJoint->Rotation[0], pJoint->Rotation[1], pJoint->Rotation[2]) ); + + jnt->LocalMatrix.setTranslation( + core::vector3df(pJoint->Translation[0], pJoint->Translation[1], pJoint->Translation[2]) ); + + + ParentNames.push_back( (c8*)pJoint->ParentName ); + + /*if (pJoint->NumRotationKeyframes || + pJoint->NumTranslationKeyframes) + HasAnimation = true;*/ + + + + + // get rotation keyframes + for (j=0; j < pJoint->NumRotationKeyframes; ++j) + { + MS3DKeyframe* kf = (MS3DKeyframe*)pPtr; +#ifdef __BIG_ENDIAN__ + kf->Time = os::Byteswap::byteswap(kf->Time); + for (u32 l=0; l<3; ++l) + kf->Parameter[l] = os::Byteswap::byteswap(kf->Parameter[l]); +#endif + pPtr += sizeof(MS3DKeyframe); + + ISkinnedMesh::SRotationKey *k=AnimatedMesh->createRotationKey(jnt); + k->frame = kf->Time * framesPerSecond; + + core::matrix4 tmpMatrix; + + tmpMatrix.setRotationRadians( + core::vector3df(kf->Parameter[0], kf->Parameter[1], kf->Parameter[2]) ); + + tmpMatrix=jnt->LocalMatrix*tmpMatrix; + + k->rotation = core::quaternion(tmpMatrix); + + //fix + //k->rotation = core::vector3df + // (kf->Parameter[0],//+pJoint->Rotation[0]*core::RADTODEG, + // kf->Parameter[1],//+pJoint->Rotation[1]*core::RADTODEG, + // kf->Parameter[2]);//+pJoint->Rotation[2]*core::RADTODEG); + + } + + // get translation keyframes + for (j=0; jNumTranslationKeyframes; ++j) + { + MS3DKeyframe* kf = (MS3DKeyframe*)pPtr; +#ifdef __BIG_ENDIAN__ + kf->Time = os::Byteswap::byteswap(kf->Time); + for (u32 l=0; l<3; ++l) + kf->Parameter[l] = os::Byteswap::byteswap(kf->Parameter[l]); +#endif + pPtr += sizeof(MS3DKeyframe); + + ISkinnedMesh::SPositionKey *k=AnimatedMesh->createPositionKey(jnt); + k->frame = kf->Time * framesPerSecond; + + k->position = core::vector3df + (kf->Parameter[0]+pJoint->Translation[0], + kf->Parameter[1]+pJoint->Translation[1], + kf->Parameter[2]+pJoint->Translation[2]); + + + } + } + + //find parent of every joint + for (u32 jointnum=0; jointnumgetAllJoints().size(); ++jointnum) + { + for (u32 j2=0; j2getAllJoints().size(); ++j2) + { + if (jointnum != j2 && ParentNames[jointnum] == AnimatedMesh->getAllJoints()[j2]->Name ) + { + AnimatedMesh->getAllJoints()[j2]->Children.push_back(AnimatedMesh->getAllJoints()[jointnum]); + break; + } + } + } + /*if (Joints[jointnum].Parent == -1) + os::Printer::log("Found joint in model without parent.", ELL_WARNING);*/ + + + // create vertices and indices, attach them to the joints. + video::S3DVertex v; + core::array *Vertices; + core::array Indices; + + for (i=0; igetMeshBuffers()[tmp]->Vertices_Standard; + + for (u16 j = 0; j<3; ++j) + { + v.TCoords.X = triangles[i].S[j]; + v.TCoords.Y = triangles[i].T[j]; + + v.Normal.X = triangles[i].VertexNormals[j][0]; + v.Normal.Y = triangles[i].VertexNormals[j][1]; + v.Normal.Z = triangles[i].VertexNormals[j][2]; + + if(triangles[i].GroupIndex < Groups.size() && Groups[triangles[i].GroupIndex].MaterialIdx < AnimatedMesh->getMeshBuffers().size()) + v.Color = AnimatedMesh->getMeshBuffers()[Groups[triangles[i].GroupIndex].MaterialIdx]->Material.DiffuseColor; + else + v.Color.set(255,255,255,255); + v.Pos.X = vertices[triangles[i].VertexIndices[j]].Vertex[0]; + v.Pos.Y = vertices[triangles[i].VertexIndices[j]].Vertex[1]; + v.Pos.Z = vertices[triangles[i].VertexIndices[j]].Vertex[2]; + + // check if we already have this vertex in our vertex array + s32 index = -1; + for (u32 iV = 0; iV < Vertices->size(); ++iV) + { + if (v == (*Vertices)[iV]) + { + index = (s32)iV; + break; + } + } + if (index == -1) + { + s32 boneid = vertices[triangles[i].VertexIndices[j]].BoneID; + if (boneid>=0 && boneid<(s32)AnimatedMesh->getAllJoints().size()) + { + ISkinnedMesh::SWeight *w=AnimatedMesh->createWeight(AnimatedMesh->getAllJoints()[boneid]); + w->buffer_id = Groups[triangles[i].GroupIndex].MaterialIdx; + w->strength = 1.0f; + w->vertex_id = Vertices->size(); + //Joints[boneid]->VertexIds.push_back(Vertices.size()); + + + } + + Vertices->push_back(v); + index = Vertices->size() - 1; + } + Indices.push_back(index); + } + } + + //create groups + s32 iIndex = -1; + for (i=0; i= AnimatedMesh->getMeshBuffers().size()) + grp.MaterialIdx = 0; + + core::array& indices = AnimatedMesh->getMeshBuffers()[grp.MaterialIdx]->Indices; + + for (u32 k=0; k < grp.VertexIds.size(); ++k) + for (u32 l=0; l<3; ++l) + indices.push_back(Indices[++iIndex]); + } + + // calculate bounding box +/* + // inverse translate and rotate all vertices for making animation easier + if (HasAnimation) + for (i=0; islashIndex) slashIndex=backSlash; + + if (slashIndex==-1)//no slashes found + if (returnPath) + return core::stringc(); //no path to return + else + return string; + + if (returnPath) + return string.subString(0, slashIndex + 1); + else + return string.subString(slashIndex+1, string.size() - (slashIndex+1)); +} + + +} // end namespace scene +} // end namespace irr + +#endif diff --git a/source/Irrlicht/CMS3DMeshFileLoader.h b/source/Irrlicht/CMS3DMeshFileLoader.h new file mode 100644 index 00000000..3e9b9ea8 --- /dev/null +++ b/source/Irrlicht/CMS3DMeshFileLoader.h @@ -0,0 +1,59 @@ +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __C_MS3D_MESH_FILE_LOADER_H_INCLUDED__ +#define __C_MS3D_MESH_FILE_LOADER_H_INCLUDED__ + +#include "IMeshLoader.h" +#include "IVideoDriver.h" +#include "CSkinnedMesh.h" + +namespace irr +{ +namespace scene +{ + +//! Meshloader capable of loading Milkshape 3D files +class CMS3DMeshFileLoader : public IMeshLoader +{ +public: + + //! Constructor + CMS3DMeshFileLoader(video::IVideoDriver* driver); + + //! returns true if the file maybe is able to be loaded by this class + //! based on the file extension (e.g. ".bsp") + virtual bool isALoadableFileExtension(const c8* fileName); + + //! creates/loads an animated mesh from the file. + //! \return Pointer to the created mesh. Returns 0 if loading failed. + //! If you no longer need the mesh, you should call IAnimatedMesh::drop(). + //! See IUnknown::drop() for more information. + virtual IAnimatedMesh* createMesh(irr::io::IReadFile* file); + +private: + + core::stringc stripPathFromString(core::stringc string, bool returnPath); + + bool load(irr::io::IReadFile* file); + video::IVideoDriver* Driver; + CSkinnedMesh* AnimatedMesh; + + struct SGroup + { + core::stringc Name; + core::array VertexIds; + u16 MaterialIdx; + }; + + core::array Groups; + +}; + +} // end namespace scene +} // end namespace irr + +#endif + + diff --git a/source/Irrlicht/CMY3DMeshFileLoader.cpp b/source/Irrlicht/CMY3DMeshFileLoader.cpp index cb05f1e9..4cd96654 100644 --- a/source/Irrlicht/CMY3DMeshFileLoader.cpp +++ b/source/Irrlicht/CMY3DMeshFileLoader.cpp @@ -8,6 +8,9 @@ // This tool created by ZDimitor everyone can use it as wants //-------------------------------------------------------------------------------- +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_MY3D_LOADER_ + #include "CMY3DMeshFileLoader.h" #include "SAnimatedMesh.h" @@ -837,3 +840,5 @@ core::array& CMY3DMeshFileLoader::getChildNodes() } // end namespace scnene } // end namespace irr + +#endif // _IRR_COMPILE_WITH_MY3D_LOADER_ diff --git a/source/Irrlicht/COBJMeshFileLoader.cpp b/source/Irrlicht/COBJMeshFileLoader.cpp index 6d21012c..bb58a8e7 100644 --- a/source/Irrlicht/COBJMeshFileLoader.cpp +++ b/source/Irrlicht/COBJMeshFileLoader.cpp @@ -2,6 +2,9 @@ // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_OBJ_LOADER_ + #include "COBJMeshFileLoader.h" #include "SMeshBuffer.h" #include "SAnimatedMesh.h" @@ -762,3 +765,5 @@ void COBJMeshFileLoader::cleanUp() } // end namespace scene } // end namespace irr + +#endif // _IRR_COMPILE_WITH_OBJ_LOADER_ diff --git a/source/Irrlicht/COCTLoader.cpp b/source/Irrlicht/COCTLoader.cpp index 8c308b8d..89f6c9b0 100644 --- a/source/Irrlicht/COCTLoader.cpp +++ b/source/Irrlicht/COCTLoader.cpp @@ -9,6 +9,9 @@ // // See the header file for additional information including use and distribution rights. +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_OCT_LOADER_ + #include "COCTLoader.h" #include "ISceneManager.h" #include "os.h" @@ -382,3 +385,5 @@ bool COCTLoader::isALoadableFileExtension(const c8* filename) } // end namespace scene } // end namespace irr + +#endif // _IRR_COMPILE_WITH_OCT_LOADER_ diff --git a/source/Irrlicht/COgreMeshFileLoader.cpp b/source/Irrlicht/COgreMeshFileLoader.cpp index 64b953d9..1a7d17c5 100644 --- a/source/Irrlicht/COgreMeshFileLoader.cpp +++ b/source/Irrlicht/COgreMeshFileLoader.cpp @@ -3,6 +3,9 @@ // For conditions of distribution and use, see copyright notice in irrlicht.h // orginally written by Christian Stehno, modified by Nikolaus Gebhardt +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_OGRE_LOADER_ + #include "COgreMeshFileLoader.h" #include "os.h" #include "SMeshBuffer.h" @@ -1028,3 +1031,4 @@ void COgreMeshFileLoader::clearMeshes() } // end namespace scene } // end namespace irr +#endif // _IRR_COMPILE_WITH_OGRE_LOADER_ diff --git a/source/Irrlicht/CQ3LevelMesh.cpp b/source/Irrlicht/CQ3LevelMesh.cpp index af2407fa..3bae7630 100644 --- a/source/Irrlicht/CQ3LevelMesh.cpp +++ b/source/Irrlicht/CQ3LevelMesh.cpp @@ -2,6 +2,9 @@ // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_BSP_LOADER_ + #include "CQ3LevelMesh.h" #include "ISceneManager.h" #include "os.h" @@ -24,7 +27,7 @@ CQ3LevelMesh::CQ3LevelMesh(io::IFileSystem* fs, video::IVideoDriver* driver, sce { #ifdef _DEBUG IUnknown::setDebugName("CQ3LevelMesh"); - #endif + #endif s32 i; for ( i = 0; i!= quake3::E_Q3_MESH_SIZE; ++i ) @@ -53,7 +56,7 @@ CQ3LevelMesh::~CQ3LevelMesh() if (LightMaps) delete [] LightMaps; - + if (Vertices) delete [] Vertices; @@ -71,7 +74,7 @@ CQ3LevelMesh::~CQ3LevelMesh() if (LeafFaces) delete [] LeafFaces; - + if (MeshVerts) delete [] MeshVerts; @@ -461,7 +464,7 @@ void CQ3LevelMesh::parser_nextToken () } // take /[name] as valid token..?!?!?. mhmm, maybe break; - + case '\n': Parser.tokenresult = Q3_TOKEN_EOL; return; @@ -889,14 +892,14 @@ void CQ3LevelMesh::constructMesh2() } // end switch } } - + } //! constructs a mesh from the quake 3 level file. void CQ3LevelMesh::constructMesh() { - // reserve buffer. + // reserve buffer. s32 i; // new ISO for scoping problem with some compilers for (i=0; i<(NumTextures+1) * (NumLightMaps+1); ++i) @@ -938,9 +941,9 @@ void CQ3LevelMesh::constructMesh() s32 idx = meshBuffer->getVertexCount(); s32 vidxes[3]; - vidxes[0] = MeshVerts[Faces[i].meshVertIndex + tf +0] + vidxes[0] = MeshVerts[Faces[i].meshVertIndex + tf +0] + Faces[i].vertexIndex; - vidxes[1] = MeshVerts[Faces[i].meshVertIndex + tf +1] + vidxes[1] = MeshVerts[Faces[i].meshVertIndex + tf +1] + Faces[i].vertexIndex; vidxes[2] = MeshVerts[Faces[i].meshVertIndex + tf +2] + Faces[i].vertexIndex; @@ -970,7 +973,7 @@ void CQ3LevelMesh::constructMesh() break; } // end switch } - + } // helper method for creating curved surfaces, sent in by Dean P. Macri. @@ -1257,7 +1260,7 @@ void CQ3LevelMesh::createCurvedSurface2 ( SMeshBufferLightMap* meshBuffer, if ( !v.equals ( m, tolerance ) ) continue; - meshBuffer->Vertices[k].Pos = v; + meshBuffer->Vertices[k].Pos = v; //Bezier.Patch->Vertices[j].Pos = m; } } @@ -1450,7 +1453,7 @@ const quake3::SShader * CQ3LevelMesh::getShader ( const c8 * filename, s32 fileN search.name = filename; s32 index; - + //! is Shader already in cache? index = Shader.linear_search ( search ); if ( index >= 0 ) @@ -1632,7 +1635,7 @@ void CQ3LevelMesh::loadTextures() tex.set_used(NumTextures+1); tex[0] = 0; - + s32 t;// new ISO for scoping problem with some compilers for (t=1; t<(NumTextures+1); ++t) @@ -1676,7 +1679,7 @@ void CQ3LevelMesh::loadTextures() // lightmap is a CTexture::R8G8B8 format lmapImg = Driver->createImageFromData( - video::ECF_R8G8B8, + video::ECF_R8G8B8, lmapsize, LightMaps[t-1].imageBits, true, false ); @@ -1722,7 +1725,7 @@ void CQ3LevelMesh::cleanMeshes () { // delete Meshbuffer Mesh[g]->MeshBuffers[i]->drop(); - Mesh[g]->MeshBuffers.erase(i); + Mesh[g]->MeshBuffers.erase(i); } else ++i; @@ -1751,7 +1754,7 @@ void CQ3LevelMesh::calcBoundingBoxes () //! loads a texture video::ITexture* CQ3LevelMesh::loadTexture ( const tStringList &stringList ) { - static const char * extension[2] = + static const char * extension[2] = { ".jpg", ".tga" @@ -1797,7 +1800,7 @@ void CQ3LevelMesh::loadTextures2() // lightmap is a CTexture::R8G8B8 format lmapImg = Driver->createImageFromData( - video::ECF_R8G8B8, + video::ECF_R8G8B8, lmapsize, LightMaps[t].imageBits, true, false ); @@ -1808,7 +1811,7 @@ void CQ3LevelMesh::loadTextures2() // load textures Tex.set_used( NumTextures+1 ); - + const quake3::SShader * shader; core::stringc list; @@ -1869,6 +1872,11 @@ const core::aabbox3d& CQ3LevelMesh::getBoundingBox() const return Mesh[0]->getBoundingBox(); } +void CQ3LevelMesh::setBoundingBox( const core::aabbox3df& box) +{ + return Mesh[0]->setBoundingBox(box); //? +} + //! Returns the type of the animated mesh. E_ANIMATED_MESH_TYPE CQ3LevelMesh::getMeshType() const @@ -1879,3 +1887,4 @@ E_ANIMATED_MESH_TYPE CQ3LevelMesh::getMeshType() const } // end namespace scene } // end namespace irr +#endif // _IRR_COMPILE_WITH_BSP_LOADER_ diff --git a/source/Irrlicht/CQ3LevelMesh.h b/source/Irrlicht/CQ3LevelMesh.h index 411a871c..04fc7242 100644 --- a/source/Irrlicht/CQ3LevelMesh.h +++ b/source/Irrlicht/CQ3LevelMesh.h @@ -44,6 +44,9 @@ namespace scene //! \return A bounding box of this mesh is returned. virtual const core::aabbox3d& getBoundingBox() const; + virtual void setBoundingBox( const core::aabbox3df& box); + + //! Returns the type of the animated mesh. virtual E_ANIMATED_MESH_TYPE getMeshType() const; @@ -57,6 +60,40 @@ namespace scene //! get's an interface to the entities virtual const quake3::tQ3EntityList & getEntityList (); + + + //Link to held meshes? ... + + + //! returns amount of mesh buffers. + virtual u32 getMeshBufferCount() const + { + return 0; + } + + //! returns pointer to a mesh buffer + virtual IMeshBuffer* getMeshBuffer(u32 nr) const + { + return 0; + } + + //! Returns pointer to a mesh buffer which fits a material + /** \param material: material to search for + \return Returns the pointer to the mesh buffer or + NULL if there is no such mesh buffer. */ + virtual IMeshBuffer* getMeshBuffer( const video::SMaterial &material) const + { + return 0; + } + + virtual void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) + { + return; + } + + + + private: //! constructs a mesh from the quake 3 level file. @@ -104,45 +141,45 @@ namespace scene { s32 offset; s32 length; - }; + }; struct tBSPHeader { s32 strID; // This should always be 'IBSP' s32 version; // This should be 0x2e for Quake 3 files - }; + }; struct tBSPVertex { - f32 vPosition[3]; // (x, y, z) position. + f32 vPosition[3]; // (x, y, z) position. f32 vTextureCoord[2]; // (u, v) texture coordinate f32 vLightmapCoord[2]; // (u, v) lightmap coordinate f32 vNormal[3]; // (x, y, z) normal vector - u8 color[4]; // RGBA color for the vertex + u8 color[4]; // RGBA color for the vertex }; struct tBSPFace { - s32 textureID; // The index into the texture array - s32 effect; // The index for the effects (or -1 = n/a) - s32 type; // 1=polygon, 2=patch, 3=mesh, 4=billboard - s32 vertexIndex; // The index into this face's first vertex - s32 numOfVerts; // The number of vertices for this face - s32 meshVertIndex; // The index into the first meshvertex - s32 numMeshVerts; // The number of mesh vertices - s32 lightmapID; // The texture index for the lightmap - s32 lMapCorner[2]; // The face's lightmap corner in the image - s32 lMapSize[2]; // The size of the lightmap section - f32 lMapPos[3]; // The 3D origin of lightmap. - f32 lMapBitsets[2][3]; // The 3D space for s and t unit vectors. - f32 vNormal[3]; // The face normal. - s32 size[2]; // The bezier patch dimensions. + s32 textureID; // The index into the texture array + s32 effect; // The index for the effects (or -1 = n/a) + s32 type; // 1=polygon, 2=patch, 3=mesh, 4=billboard + s32 vertexIndex; // The index into this face's first vertex + s32 numOfVerts; // The number of vertices for this face + s32 meshVertIndex; // The index into the first meshvertex + s32 numMeshVerts; // The number of mesh vertices + s32 lightmapID; // The texture index for the lightmap + s32 lMapCorner[2]; // The face's lightmap corner in the image + s32 lMapSize[2]; // The size of the lightmap section + f32 lMapPos[3]; // The 3D origin of lightmap. + f32 lMapBitsets[2][3]; // The 3D space for s and t unit vectors. + f32 vNormal[3]; // The face normal. + s32 size[2]; // The bezier patch dimensions. }; struct tBSPTexture { - c8 strName[64]; // The name of the texture w/o the extension - u32 flags; // The surface flags (unknown) + c8 strName[64]; // The name of the texture w/o the extension + u32 flags; // The surface flags (unknown) u32 contents; // The content flags (unknown) }; @@ -153,29 +190,29 @@ namespace scene struct tBSPNode { - s32 plane; // The index into the planes array - s32 front; // The child index for the front node - s32 back; // The child index for the back node - s32 mins[3]; // The bounding box min position. - s32 maxs[3]; // The bounding box max position. - }; + s32 plane; // The index into the planes array + s32 front; // The child index for the front node + s32 back; // The child index for the back node + s32 mins[3]; // The bounding box min position. + s32 maxs[3]; // The bounding box max position. + }; struct tBSPLeaf { - s32 cluster; // The visibility cluster - s32 area; // The area portal - s32 mins[3]; // The bounding box min position - s32 maxs[3]; // The bounding box max position - s32 leafface; // The first index into the face array - s32 numOfLeafFaces; // The number of faces for this leaf - s32 leafBrush; // The first index for into the brushes - s32 numOfLeafBrushes; // The number of brushes for this leaf - }; + s32 cluster; // The visibility cluster + s32 area; // The area portal + s32 mins[3]; // The bounding box min position + s32 maxs[3]; // The bounding box max position + s32 leafface; // The first index into the face array + s32 numOfLeafFaces; // The number of faces for this leaf + s32 leafBrush; // The first index for into the brushes + s32 numOfLeafBrushes; // The number of brushes for this leaf + }; struct tBSPPlane { - f32 vNormal[3]; // Plane normal. - f32 d; // The plane distance from origin + f32 vNormal[3]; // Plane normal. + f32 d; // The plane distance from origin }; struct tBSPVisData @@ -183,44 +220,44 @@ namespace scene s32 numOfClusters; // The number of clusters s32 bytesPerCluster; // Bytes (8 bits) in the cluster's bitset c8 *pBitsets; // Array of bytes holding the cluster vis. - }; + }; - struct tBSPBrush + struct tBSPBrush { - s32 brushSide; // The starting brush side for the brush + s32 brushSide; // The starting brush side for the brush s32 numOfBrushSides; // Number of brush sides for the brush s32 textureID; // The texture index for the brush - }; + }; - struct tBSPBrushSide + struct tBSPBrushSide { s32 plane; // The plane index s32 textureID; // The texture index - }; + }; - struct tBSPModel + struct tBSPModel { f32 min[3]; // The min position for the bounding box - f32 max[3]; // The max position for the bounding box. - s32 faceIndex; // The first face index in the model - s32 numOfFaces; // The number of faces in the model - s32 brushIndex; // The first brush index in the model + f32 max[3]; // The max position for the bounding box. + s32 faceIndex; // The first face index in the model + s32 numOfFaces; // The number of faces in the model + s32 brushIndex; // The first brush index in the model s32 numOfBrushes; // The number brushes for the model - }; + }; struct tBSPShader { - c8 strName[64]; // The name of the shader file - s32 brushIndex; // The brush index for this shader + c8 strName[64]; // The name of the shader file + s32 brushIndex; // The brush index for this shader s32 unknown; // This is 99% of the time 5 - }; + }; struct tBSPLights { u8 ambient[3]; // This is the ambient color in RGB u8 directional[3]; // This is the directional color in RGB - u8 direction[2]; // The direction of the light: [phi,theta] - }; + u8 direction[2]; // The direction of the light: [phi,theta] + }; void loadTextures (tBSPLump* l, io::IReadFile* file); // Load the textures void loadLightmaps (tBSPLump* l, io::IReadFile* file); // Load the lightmaps @@ -299,7 +336,7 @@ namespace scene s32 Level; core::array column[3]; - + }; SBezier Bezier; @@ -331,7 +368,7 @@ namespace scene s32 *LeafFaces; s32 NumLeafFaces; - s32 *MeshVerts; // The vertex offsets for a mesh + s32 *MeshVerts; // The vertex offsets for a mesh s32 NumMeshVerts; tBSPBrush* Brushes; diff --git a/source/Irrlicht/CSceneManager.cpp b/source/Irrlicht/CSceneManager.cpp index a38338d9..d0c81609 100644 --- a/source/Irrlicht/CSceneManager.cpp +++ b/source/Irrlicht/CSceneManager.cpp @@ -2,6 +2,7 @@ // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h +#include "IrrCompileConfig.h" #include "CSceneManager.h" #include "IVideoDriver.h" #include "IFileSystem.h" @@ -17,18 +18,65 @@ #include "CGeometryCreator.h" -#include "CDefaultMeshFormatLoader.h" +#ifdef _IRR_COMPILE_WITH_BSP_LOADER_ +#include "CBSPMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_MD2_LOADER_ +#include "CMD2MeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_MS3D_LOADER_ +#include "CMS3DMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_3DS_LOADER_ #include "C3DSMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_X_LOADER_ #include "CXMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_OCT_LOADER_ #include "COCTLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_CSM_LOADER_ #include "CCSMLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_LMTS_LOADER_ #include "CLMTSMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_MY3D_LOADER_ #include "CMY3DMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_COLLADA_LOADER_ #include "CColladaFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_DMF_LOADER_ #include "CDMFLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_OGRE_LOADER_ #include "COgreMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_OBJ_LOADER_ #include "COBJMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_MD3_LOADER_ #include "CMD3MeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_B3D_LOADER_ +#include "CB3DMeshFileLoader.h" +#endif #include "CCubeSceneNode.h" #include "CSphereSceneNode.h" @@ -116,22 +164,56 @@ CSceneManager::CSceneManager(video::IVideoDriver* driver, io::IFileSystem* fs, // create manipulator MeshManipulator = new CMeshManipulator(); - // add default format loader + // add file format loaders - MeshLoaderList.push_back(new CDefaultMeshFormatLoader(FileSystem, Driver, this)); + + #ifdef _IRR_COMPILE_WITH_BSP_LOADER_ + MeshLoaderList.push_back(new CBSPMeshFileLoader(FileSystem, Driver, this)); + #endif + #ifdef _IRR_COMPILE_WITH_MD2_LOADER_ + MeshLoaderList.push_back(new CMD2MeshFileLoader()); + #endif + #ifdef _IRR_COMPILE_WITH_MS3D_LOADER_ + MeshLoaderList.push_back(new CMS3DMeshFileLoader(Driver)); + #endif + #ifdef _IRR_COMPILE_WITH_3DS_LOADER_ MeshLoaderList.push_back(new C3DSMeshFileLoader(MeshManipulator,FileSystem, Driver)); - MeshLoaderList.push_back(new CXMeshFileLoader(MeshManipulator, Driver)); + #endif + #ifdef _IRR_COMPILE_WITH_X_LOADER_ + MeshLoaderList.push_back(new CXMeshFileLoader(this)); + #endif + #ifdef _IRR_COMPILE_WITH_OCT_LOADER_ MeshLoaderList.push_back(new COCTLoader(Driver)); + #endif + #ifdef _IRR_COMPILE_WITH_CSM_LOADER_ MeshLoaderList.push_back(new CCSMLoader(this, FileSystem)); + #endif + #ifdef _IRR_COMPILE_WITH_LMTS_LOADER_ MeshLoaderList.push_back(new CLMTSMeshFileLoader(FileSystem, Driver, &Parameters)); + #endif + #ifdef _IRR_COMPILE_WITH_MY3D_LOADER_ MeshLoaderList.push_back(new CMY3DMeshFileLoader(FileSystem, Driver, this)); + #endif + #ifdef _IRR_COMPILE_WITH_COLLADA_LOADER_ MeshLoaderList.push_back(new CColladaFileLoader(Driver, this, FileSystem)); + #endif + #ifdef _IRR_COMPILE_WITH_DMF_LOADER_ MeshLoaderList.push_back(new CDMFLoader(Driver, this)); + #endif + #ifdef _IRR_COMPILE_WITH_OGRE_LOADER_ MeshLoaderList.push_back(new COgreMeshFileLoader(MeshManipulator, FileSystem, Driver)); + #endif + #ifdef _IRR_COMPILE_WITH_OBJ_LOADER_ MeshLoaderList.push_back(new COBJMeshFileLoader(FileSystem, Driver)); + #endif + #ifdef _IRR_COMPILE_WITH_MD3_LOADER_ MeshLoaderList.push_back(new CMD3MeshFileLoader(FileSystem, Driver)); - // factories + #endif + #ifdef _IRR_COMPILE_WITH_B3D_LOADER_ + MeshLoaderList.push_back(new CB3DMeshFileLoader(this)); + #endif + // factories ISceneNodeFactory* factory = new CDefaultSceneNodeFactory(this); registerSceneNodeFactory(factory); factory->drop(); diff --git a/source/Irrlicht/CSkinnedMesh.cpp b/source/Irrlicht/CSkinnedMesh.cpp new file mode 100644 index 00000000..66de6b9f --- /dev/null +++ b/source/Irrlicht/CSkinnedMesh.cpp @@ -0,0 +1,1326 @@ +// Copyright (C) 2002-2006 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_ + +#include "CSkinnedMesh.h" +#include "CBoneSceneNode.h" +#include "IAnimatedMeshSceneNode.h" +#include "os.h" + +#include + + +namespace irr +{ +namespace scene +{ + + +//! constructor +CSkinnedMesh::CSkinnedMesh() +: SkinningBuffers(0), HasAnimation(0), PreparedForSkinning(0), + AnimationFrames(0.f), lastAnimatedFrame(0.f), lastSkinnedFrame(0.f), + BoneControlUsed(false), AnimateNormals(0), InterpolationMode(EIM_LINEAR) +{ + #ifdef _DEBUG + setDebugName("CSkinnedMesh"); + #endif + + SkinningBuffers=&LocalBuffers; +} + + +//! destructor +CSkinnedMesh::~CSkinnedMesh() +{ + u32 n; + + for (n=0;ndrop(); + } +} + + +//! returns the amount of frames in milliseconds. If the amount is 1, it is a static (=non animated) mesh. +s32 CSkinnedMesh::getFrameCount() +{ + return (s32)AnimationFrames; +} + + +//! returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail. Note, that some Meshes will ignore the detail level. +IMesh* CSkinnedMesh::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop) +{ + //animate(frame,startFrameLoop, endFrameLoop); + if (frame==-1) + return this; + + animateMesh((f32)frame, 1.0f); + buildAll_LocalAnimatedMatrices(); + buildAll_GlobalAnimatedMatrices(); + skinMesh(); + return this; +} + + + +//-------------------------------------------------------------------------- +// Keyframe Animation +//-------------------------------------------------------------------------- + + +//! Animates this mesh's joints based on frame input +//! blend: {0-old position, 1-New position} +void CSkinnedMesh::animateMesh(f32 frame, f32 blend) +{ + if ( !HasAnimation || lastAnimatedFrame==frame) + return; + + lastAnimatedFrame=frame; + + if (blend<=0) + return; //No need to animate + + for (u32 i=0; iAnimatedposition; + core::vector3df oldScale = Joint->Animatedscale; + core::quaternion oldRotation = Joint->Animatedrotation; + + core::vector3df position =oldPosition; + core::vector3df scale =oldScale; + core::quaternion rotation =oldRotation; + + if (!BoneControlUsed) + { + Joint->positionHint=-1; + Joint->scaleHint=-1; + Joint->rotationHint=-1; + } + + getFrameData(frame, Joint, + position, Joint->positionHint, + scale, Joint->scaleHint, + rotation, Joint->rotationHint); + + if (blend==1.0f) + { + //No blending need: + Joint->Animatedposition = position; + Joint->Animatedscale = scale; + Joint->Animatedrotation = rotation; + } + else + { + //Blend animation: + + f32 invBlend=1-blend; + + Joint->Animatedposition = (position * blend) + (oldPosition* invBlend ); + Joint->Animatedscale = (scale * blend) + (oldScale* invBlend ); + Joint->Animatedrotation.slerp(oldRotation, rotation, blend); + + } + + //Node: + //_LocalAnimatedMatrix needs to be built at some point, but this function maybe called lots of times for + //one render (to play two animations at the same time) _LocalAnimatedMatrix only needs to be built once. + //a call to buildAllLocalAnimatedMatrices is needed before skinning the mesh, and before the user gets the joints to move + + //---------------- + // Temp! + buildAll_LocalAnimatedMatrices(); + //----------------- + + } + + BoneControlUsed=false; +} + +void CSkinnedMesh::buildAll_LocalAnimatedMatrices() +{ + for (u32 i=0; iUseAnimationFrom && + (Joint->UseAnimationFrom->PositionKeys.size() || + Joint->UseAnimationFrom->ScaleKeys.size() || + Joint->UseAnimationFrom->RotationKeys.size() )) + { + Joint->LocalAnimatedMatrix.makeIdentity(); + Joint->LocalAnimatedMatrix.setTranslation(Joint->Animatedposition); + Joint->LocalAnimatedMatrix*=Joint->Animatedrotation.getMatrix(); + + if (Joint->ScaleKeys.size()) + { + //Joint->_LocalAnimatedMatrix.setScale(Joint->_Animatedscale); + core::matrix4 scaleMatrix; + scaleMatrix.setScale(Joint->Animatedscale); + Joint->LocalAnimatedMatrix *= scaleMatrix; + } + } + else + { + Joint->LocalAnimatedMatrix=Joint->LocalMatrix; + } + + } +} + +void CSkinnedMesh::buildAll_GlobalAnimatedMatrices(SJoint *Joint, SJoint *ParentJoint) +{ + + if (!Joint) + { + for (u32 i=0; iGlobalAnimatedMatrix = Joint->LocalAnimatedMatrix; + else + Joint->GlobalAnimatedMatrix = ParentJoint->GlobalAnimatedMatrix * Joint->LocalAnimatedMatrix; + } + + for (u32 j=0; jChildren.size(); ++j) + buildAll_GlobalAnimatedMatrices(Joint->Children[j], Joint); +} + +void CSkinnedMesh::getFrameData(f32 frame, SJoint *Joint, + core::vector3df &position, s32 &positionHint, + core::vector3df &scale, s32 &scaleHint, + core::quaternion &rotation, s32 &rotationHint) +{ + s32 foundPositionIndex = -1; + s32 foundScaleIndex = -1; + s32 foundRotationIndex = -1; + + if (Joint->UseAnimationFrom) + { + core::array &PositionKeys=Joint->UseAnimationFrom->PositionKeys; + core::array &ScaleKeys=Joint->UseAnimationFrom->ScaleKeys; + core::array &RotationKeys=Joint->UseAnimationFrom->RotationKeys; + + if (PositionKeys.size()) + { + foundPositionIndex = -1; + + //Test the Hints... + if (positionHint>0 && positionHint < (s32)PositionKeys.size() ) + { + //check this hint + if (PositionKeys[positionHint].frame>=frame && PositionKeys[positionHint-1].frame=frame && + PositionKeys[positionHint+0].frame= frame) //Keys should to be sorted by frame + { + foundPositionIndex=i; + positionHint=i; + break; + } + } + } + + //Do interpolation... + if (foundPositionIndex!=-1) + { + if (InterpolationMode==EIM_CONSTANT || foundPositionIndex==0) + { + position = PositionKeys[foundPositionIndex].position; + } + else if (InterpolationMode==EIM_LINEAR) + { + SPositionKey *KeyA = &PositionKeys[foundPositionIndex]; + SPositionKey *KeyB = &PositionKeys[foundPositionIndex-1]; + + f32 fd1 = frame-KeyA->frame; + f32 fd2 = KeyB->frame-frame; + position = ((KeyB->position-KeyA->position)/(fd1+fd2))*fd1 + KeyA->position; + } + } + } + + //------------------------------------------------------------ + + if (ScaleKeys.size()) + { + foundScaleIndex = -1; + + //Test the Hints... + if (scaleHint>0 && scaleHint < (s32)ScaleKeys.size() ) + { + //check this hint + if (ScaleKeys[scaleHint].frame>=frame && ScaleKeys[scaleHint-1].frame=frame && + ScaleKeys[scaleHint+0].frame= frame) //Keys should to be sorted by frame + { + foundScaleIndex=i; + scaleHint=i; + break; + } + } + } + + //Do interpolation... + if (foundScaleIndex!=-1) + { + if (InterpolationMode==EIM_CONSTANT || foundScaleIndex==0) + { + scale = ScaleKeys[foundScaleIndex].scale; + } + else if (InterpolationMode==EIM_LINEAR) + { + SScaleKey *KeyA = &ScaleKeys[foundScaleIndex]; + SScaleKey *KeyB = &ScaleKeys[foundScaleIndex-1]; + + f32 fd1 = frame-KeyA->frame; + f32 fd2 = KeyB->frame-frame; + scale = ((KeyB->scale-KeyA->scale)/(fd1+fd2))*fd1 + KeyA->scale; + } + } + } + + //------------------------------------------------------------- + + if (RotationKeys.size()) + { + foundRotationIndex = -1; + + //Test the Hints... + if (rotationHint>0 && rotationHint < (s32)RotationKeys.size() ) + { + //check this hint + if (RotationKeys[rotationHint].frame>=frame && RotationKeys[rotationHint-1].frame=frame && + RotationKeys[rotationHint+0].frame= frame) //Keys should to be sorted by frame + { + foundRotationIndex=i; + rotationHint=i; + break; + } + } + } + + //Do interpolation... + if (foundRotationIndex!=-1) + { + if (InterpolationMode==EIM_CONSTANT || foundRotationIndex==0) + { + rotation = RotationKeys[foundRotationIndex].rotation; + } + else if (InterpolationMode==EIM_LINEAR) + { + SRotationKey *KeyA = &RotationKeys[foundRotationIndex]; + SRotationKey *KeyB = &RotationKeys[foundRotationIndex-1]; + + f32 fd1 = frame-KeyA->frame; + f32 fd2 = KeyB->frame - frame; + f32 t = (1.0f/(fd1+fd2))*fd1; + + /* + f32 t = 0; + if (KeyA->frame!=KeyB->frame) + t = (frame-KeyA->frame) / (KeyB->frame - KeyA->frame); + */ + + rotation.slerp(KeyA->rotation, KeyB->rotation, t); + + } + } + } + } + +} + +//-------------------------------------------------------------------------- +// Software Skinning +//-------------------------------------------------------------------------- + +//! Preforms a software skin on this mesh based of joint positions +void CSkinnedMesh::skinMesh() +{ + + if ( !HasAnimation) + return; + + //---------------- + // Temp! + buildAll_GlobalAnimatedMatrices(); + //----------------- + + //Software skin.... + + + + //clear skinning helper array + u32 i; + for (i=0; iWeights.size()) + { + //Find this joints pull on vertices... + core::matrix4 JointVertexPull(core::matrix4::EM4CONST_NOTHING); + JointVertexPull.setbyproduct(Joint->GlobalAnimatedMatrix, Joint->GlobalInversedMatrix); + + core::vector3df ThisVertexMove, ThisNormalMove; + + SWeight *Weight; + + core::array &BuffersUsed=*SkinningBuffers; + + //Skin Vertices Normals... + + //Skin Vertices Positions... + for (u32 i=0; iWeights.size(); ++i) + { + Weight=&Joint->Weights[i]; + + // Pull this vertex... + ThisVertexMove.X = JointVertexPull[0]*Weight->StaticPos.X + JointVertexPull[4]*Weight->StaticPos.Y + JointVertexPull[8]*Weight->StaticPos.Z + JointVertexPull[12]; + ThisVertexMove.Y = JointVertexPull[1]*Weight->StaticPos.X + JointVertexPull[5]*Weight->StaticPos.Y + JointVertexPull[9]*Weight->StaticPos.Z + JointVertexPull[13]; + ThisVertexMove.Z = JointVertexPull[2]*Weight->StaticPos.X + JointVertexPull[6]*Weight->StaticPos.Y + JointVertexPull[10]*Weight->StaticPos.Z + JointVertexPull[14]; + + if (AnimateNormals) + { + ThisNormalMove.X = JointVertexPull[0]*Weight->StaticNormal.X + JointVertexPull[4]*Weight->StaticNormal.Y + JointVertexPull[8]*Weight->StaticNormal.Z; + ThisNormalMove.Y = JointVertexPull[1]*Weight->StaticNormal.X + JointVertexPull[5]*Weight->StaticNormal.Y + JointVertexPull[9]*Weight->StaticNormal.Z; + ThisNormalMove.Z = JointVertexPull[2]*Weight->StaticNormal.X + JointVertexPull[6]*Weight->StaticNormal.Y + JointVertexPull[10]*Weight->StaticNormal.Z; + } + + + + if (! (*Weight->Moved) ) + { + (*Weight->Moved) = true; + + BuffersUsed[Weight->buffer_id]->getVertex(Weight->vertex_id)->Pos = (ThisVertexMove * Weight->strength); + + if (AnimateNormals) BuffersUsed[Weight->buffer_id]->getVertex(Weight->vertex_id)->Normal = (ThisNormalMove * Weight->strength); + + //(*Weight->_Pos) = ThisVertexMove * Weight->strength; + } + else + { + BuffersUsed[Weight->buffer_id]->getVertex(Weight->vertex_id)->Pos += (ThisVertexMove* Weight->strength); + + if (AnimateNormals) BuffersUsed[Weight->buffer_id]->getVertex(Weight->vertex_id)->Normal += (ThisNormalMove * Weight->strength); + + //(*Weight->_Pos) += (ThisVertexMove * Weight->strength); + } + } + } + + //Skin all children + for (u32 j=0; jChildren.size(); ++j) + SkinJoint(Joint->Children[j], Joint); +} + + +E_ANIMATED_MESH_TYPE CSkinnedMesh::getMeshType() const +{ + return EAMT_SKINNED; +} + + +//! Gets joint count. +s32 CSkinnedMesh::getJointCount() const +{ + return AllJoints.size(); +} + + +//! Gets the name of a joint. +const c8* CSkinnedMesh::getJointName(s32 number) const +{ + if (number < 0 || number >= (s32)AllJoints.size()) + return 0; + return AllJoints[number]->Name.c_str(); +} + + +//! Gets a joint number from its name +s32 CSkinnedMesh::getJointNumber(const c8* name) const +{ + for (s32 i=0; i<(s32)AllJoints.size(); ++i) + { + if (AllJoints[i]->Name == name) + return i; + } + + return -1; +} + + +//! returns amount of mesh buffers. +u32 CSkinnedMesh::getMeshBufferCount() const +{ + return LocalBuffers.size(); +} + + +//! returns pointer to a mesh buffer +IMeshBuffer* CSkinnedMesh::getMeshBuffer(u32 nr) const +{ + if (nr < LocalBuffers.size()) + return LocalBuffers[nr]; + else + return 0; +} + + +//! Returns pointer to a mesh buffer which fits a material +IMeshBuffer* CSkinnedMesh::getMeshBuffer(const video::SMaterial &material) const +{ + for (u32 i=0; igetMaterial() == material) + return LocalBuffers[i]; + } + return 0; +} + + +//! returns an axis aligned bounding box +const core::aabbox3d& CSkinnedMesh::getBoundingBox() const +{ + return BoundingBox; +} + + +//! set user axis aligned bounding box +void CSkinnedMesh::setBoundingBox( const core::aabbox3df& box) +{ + BoundingBox = box; +} + + +//! sets a flag of all contained materials to a new value +void CSkinnedMesh::setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) +{ + for (u32 i=0; iMaterial.setFlag(flag,newvalue); +} + + +//! uses animation from another mesh +bool CSkinnedMesh::useAnimationFrom(ISkinnedMesh *mesh) +{ + bool unmatched=false; + + for(u32 i=0;iUseAnimationFrom=0; + + if (joint->Name=="") + unmatched=true; + else + { + for(u32 j=0;jgetAllJoints().size();++j) + { + SJoint *otherJoint=mesh->getAllJoints()[j]; + if (joint->Name==otherJoint->Name) + { + joint->UseAnimationFrom=otherJoint; + } + } + if (!joint->UseAnimationFrom) unmatched=true; + } + } + + checkForAnimation(); + + return !unmatched; +} + + +//!Update Normals when Animating +//!False= Don't (default) +//!True= Update normals, slower +void CSkinnedMesh::updateNormalsWhenAnimating(bool on) +{ + AnimateNormals = on; +} + + +//!Sets Interpolation Mode +void CSkinnedMesh::setInterpolationMode(E_INTERPOLATION_MODE mode) +{ + InterpolationMode = mode; +} + + +core::array &CSkinnedMesh::getMeshBuffers() +{ + return LocalBuffers; +} + + +core::array &CSkinnedMesh::getAllJoints() +{ + return AllJoints; +} + + +void CSkinnedMesh::CalculateGlobalMatrixes(SJoint *Joint,SJoint *ParentJoint) +{ + if (!Joint && ParentJoint) // bit of protection from endless loops + return; + + //Go thought the root bones + if (!Joint) + { + for (u32 i=0; iGlobalMatrix = Joint->LocalMatrix; + else + Joint->GlobalMatrix = ParentJoint->GlobalMatrix * Joint->LocalMatrix; + + Joint->LocalAnimatedMatrix=Joint->LocalMatrix; + Joint->GlobalAnimatedMatrix=Joint->GlobalMatrix; + + if (Joint->GlobalInversedMatrix.isIdentity())//might be pre calculated + { + Joint->GlobalInversedMatrix = Joint->GlobalMatrix; + Joint->GlobalInversedMatrix.makeInverse(); // slow + } + + for (u32 j=0; jChildren.size(); ++j) + CalculateGlobalMatrixes(Joint->Children[j],Joint); +} + + +void CSkinnedMesh::checkForAnimation() +{ + u32 i,j; + //Check for animation... + HasAnimation = false; + for(i=0;iUseAnimationFrom) + { + if (AllJoints[i]->UseAnimationFrom->PositionKeys.size() || + AllJoints[i]->UseAnimationFrom->ScaleKeys.size() || + AllJoints[i]->UseAnimationFrom->RotationKeys.size() ) + { + HasAnimation = true; + } + } + } + + if (HasAnimation) + { + + //--- Find the length of the animation --- + AnimationFrames=0; + for(i=0;iUseAnimationFrom) + { + if (AllJoints[i]->UseAnimationFrom->PositionKeys.size()) + if (AllJoints[i]->UseAnimationFrom->PositionKeys.getLast().frame > AnimationFrames) + AnimationFrames=AllJoints[i]->UseAnimationFrom->PositionKeys.getLast().frame; + + if (AllJoints[i]->UseAnimationFrom->ScaleKeys.size()) + if (AllJoints[i]->UseAnimationFrom->ScaleKeys.getLast().frame > AnimationFrames) + AnimationFrames=AllJoints[i]->UseAnimationFrom->ScaleKeys.getLast().frame; + + if (AllJoints[i]->UseAnimationFrom->RotationKeys.size()) + if (AllJoints[i]->UseAnimationFrom->RotationKeys.getLast().frame > AnimationFrames) + AnimationFrames=AllJoints[i]->UseAnimationFrom->RotationKeys.getLast().frame; + } + } + } + + if (HasAnimation && !PreparedForSkinning) + { + PreparedForSkinning=true; + + //check for bugs: + for(i=0; i < AllJoints.size(); ++i) + { + SJoint *Joint = AllJoints[i]; + for (j=0; jWeights.size(); ++j) + { + u16 buffer_id=Joint->Weights[j].buffer_id; + u32 vertex_id=Joint->Weights[j].vertex_id; + + //check for invalid ids + if (buffer_id>=LocalBuffers.size()) + { + os::Printer::log("Skinned Mesh: Weight buffer id too large"); + Joint->Weights[j].buffer_id = Joint->Weights[j].vertex_id =0; + } + else if (vertex_id>=LocalBuffers[buffer_id]->getVertexCount()) + { + os::Printer::log("Skinned Mesh: Weight vertex id too large"); + Joint->Weights[j].buffer_id = Joint->Weights[j].vertex_id =0; + } + + } + } + + //An array used in skinning + + for (i=0; iWeights.size(); ++j) + { + u32 vertex_id=Joint->Weights[j].vertex_id; + u32 buffer_id=Joint->Weights[j].buffer_id; + + Joint->Weights[j].Moved = &Vertices_Moved[buffer_id] [vertex_id]; + Joint->Weights[j].StaticPos = LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos; + Joint->Weights[j].StaticNormal = LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal; + + + //Joint->Weights[j]._Pos=&Buffers[buffer_id]->getVertex(vertex_id)->Pos; + } + } + + // normalize weights + normalizeWeights(); + } +} + + +//! called by loader after populating with mesh and bone data +void CSkinnedMesh::finalize() +{ + u32 i=0,j=0; + + lastAnimatedFrame=-1; + lastSkinnedFrame=-1; + AnimateNormals=false; + + //calculate bounding box + + for (i=0; irecalculateBoundingBox(); + } + + // Get BoundingBox... + if (LocalBuffers.empty()) + BoundingBox.reset(0,0,0); + else + { + BoundingBox.reset(LocalBuffers[0]->BoundingBox.MaxEdge); + for (u32 i=0; iBoundingBox); + } + } + + //add 5% padding to bounding box + core::vector3df Padding=BoundingBox.getExtent()*0.05f; + BoundingBox.MinEdge-=Padding; + BoundingBox.MaxEdge+=Padding; + + + if (AllJoints.size() || RootJoints.size()) + { + // populate AllJoints or RootJoints, depending on which is empty + if (!RootJoints.size()) + { + + for(u32 CheckingIdx=0; CheckingIdx < AllJoints.size(); ++CheckingIdx) + { + + bool foundParent=false; + for(i=0; i < AllJoints.size(); ++i) + { + for(u32 n=0; n < AllJoints[i]->Children.size(); ++n) + { + if (AllJoints[i]->Children[n] == AllJoints[CheckingIdx]) + foundParent=true; + } + } + + if (!foundParent) + RootJoints.push_back(AllJoints[CheckingIdx]); + } + } + else + { + AllJoints=RootJoints; + } + } + + for(i=0; i < AllJoints.size(); ++i) + { + AllJoints[i]->UseAnimationFrom=AllJoints[i]; + } + + //Set array sizes... + + for (i=0; i() ); + Vertices_Moved[i].set_used(LocalBuffers[i]->getVertexCount()); + } + + + //Todo: optimise keys here... + + + checkForAnimation(); + + + if (HasAnimation) + { + + //--- optimize and check keyframes --- + for(i=0;i &PositionKeys =AllJoints[i]->PositionKeys; + core::array &ScaleKeys = AllJoints[i]->ScaleKeys; + core::array &RotationKeys = AllJoints[i]->RotationKeys; + + + if (PositionKeys.size()>2) + for(j=0;j1) + for(j=0;j= PositionKeys[j+1].frame) //bad frame, unneed and may cause problems + { + PositionKeys.erase(j+1); + j--; + } + } + + if (ScaleKeys.size()>2) + for(j=0;j1) + for(j=0;j= ScaleKeys[j+1].frame) //bad frame, unneed and may cause problems + { + ScaleKeys.erase(j+1); + j--; + } + } + + if (RotationKeys.size()>2) + for(j=0;j1) + for(j=0;j= RotationKeys[j+1].frame) //bad frame, unneed and may cause problems + { + RotationKeys.erase(j+1); + j--; + } + } + + + //Fill empty keyframe areas + if (PositionKeys.size()) + { + SPositionKey *Key; + Key=&PositionKeys[0];//getFirst + if (Key->frame!=0) + { + PositionKeys.push_front(*Key); + Key=&PositionKeys[0];//getFirst + Key->frame=0; + } + + Key=&PositionKeys.getLast(); + if (Key->frame!=AnimationFrames) + { + PositionKeys.push_back(*Key); + Key=&PositionKeys.getLast(); + Key->frame=AnimationFrames; + } + } + + if (ScaleKeys.size()) + { + SScaleKey *Key; + Key=&ScaleKeys[0];//getFirst + if (Key->frame!=0) + { + ScaleKeys.push_front(*Key); + Key=&ScaleKeys[0];//getFirst + Key->frame=0; + } + + Key=&ScaleKeys.getLast(); + if (Key->frame!=AnimationFrames) + { + ScaleKeys.push_back(*Key); + Key=&ScaleKeys.getLast(); + Key->frame=AnimationFrames; + } + } + + if (RotationKeys.size()) + { + SRotationKey *Key; + Key=&RotationKeys[0];//getFirst + if (Key->frame!=0) + { + RotationKeys.push_front(*Key); + Key=&RotationKeys[0];//getFirst + Key->frame=0; + } + + Key=&RotationKeys.getLast(); + if (Key->frame!=AnimationFrames) + { + RotationKeys.push_back(*Key); + Key=&RotationKeys.getLast(); + Key->frame=AnimationFrames; + } + } + } + } + + //Needed for animation and skinning... + + CalculateGlobalMatrixes(0,0); + + //animateMesh(0, 1); + //buildAll_LocalAnimatedMatrices(); + //buildAll_GlobalAnimatedMatrices(); +} + + +scene::SSkinMeshBuffer *CSkinnedMesh::createBuffer() +{ + scene::SSkinMeshBuffer *buffer=new scene::SSkinMeshBuffer(); + LocalBuffers.push_back(buffer); + return buffer; +} + + +CSkinnedMesh::SJoint *CSkinnedMesh::createJoint(SJoint *parent) +{ + SJoint *joint=new SJoint; + + AllJoints.push_back(joint); + if (!parent) + { + //Add root joints to array in finalize() + } + else + { + //Set parent (Be careful of the mesh loader also setting the parent) + parent->Children.push_back(joint); + } + + return joint; +} + + +CSkinnedMesh::SPositionKey *CSkinnedMesh::createPositionKey(SJoint *joint) +{ + if (!joint) + return 0; + SPositionKey *key; + + joint->PositionKeys.push_back(SPositionKey()); + key=&joint->PositionKeys.getLast(); + + key->frame=0; + return key; +} + + +CSkinnedMesh::SScaleKey *CSkinnedMesh::createScaleKey(SJoint *joint) +{ + if (!joint) + return 0; + SScaleKey *key; + + joint->ScaleKeys.push_back(SScaleKey()); + key=&joint->ScaleKeys.getLast(); + + return key; +} + + +CSkinnedMesh::SRotationKey *CSkinnedMesh::createRotationKey(SJoint *joint) +{ + if (!joint) + return 0; + SRotationKey *key; + + joint->RotationKeys.push_back(SRotationKey()); + key=&joint->RotationKeys.getLast(); + + return key; +} + + +CSkinnedMesh::SWeight *CSkinnedMesh::createWeight(SJoint *joint) +{ + if (!joint) + return 0; + + joint->Weights.push_back(SWeight()); + + SWeight *weight=&joint->Weights.getLast(); + + //Could do stuff here... + + return weight; +} + + +void CSkinnedMesh::normalizeWeights() +{ + // node: unsure if weights ids are going to be used. + + // Normalise the weights on bones.... + + u32 i,j; + core::array< core::array > Vertices_TotalWeight; + + for (i=0; i()); + Vertices_TotalWeight[i].set_used(LocalBuffers[i]->getVertexCount()); + } + + + for (i=0; iWeights.size(); ++j) + { + if (Joint->Weights[j].strength<=0)//Check for invalid weights + { + Joint->Weights.erase(j); + j--; + } + else + { + Vertices_TotalWeight[ Joint->Weights[j].buffer_id ] [ Joint->Weights[j].vertex_id ] += Joint->Weights[j].strength; + } + } + } + + for (i=0; iWeights.size(); ++j) + { + f32 total = Vertices_TotalWeight[ Joint->Weights[j].buffer_id ] [ Joint->Weights[j].vertex_id ]; + if (total != 0 && total != 1) + Joint->Weights[j].strength /= total; + } + } +} + + +void CSkinnedMesh::recoverJointsFromMesh(core::array &JointChildSceneNodes) +{ + for (u32 i=0;isetPosition( joint->LocalAnimatedMatrix.getTranslation() ); + node->setRotation( joint->LocalAnimatedMatrix.getRotationDegrees() ); + + //node->setScale( joint->LocalAnimatedMatrix.getScale() ); + + node->positionHint=joint->positionHint; + node->scaleHint=joint->scaleHint; + node->rotationHint=joint->rotationHint; + + //node->setAbsoluteTransformation(joint->GlobalMatrix); //not going to work + + //Note: This updateAbsolutePosition will not work well if joints are not nested like b3d + //node->updateAbsolutePosition(); + } +} + +void CSkinnedMesh::tranferJointsToMesh(core::array &JointChildSceneNodes) +{ + for (u32 i=0;iLocalAnimatedMatrix.setTranslation( node->getPosition() ); + joint->LocalAnimatedMatrix.setRotationDegrees( node->getRotation() ); + //joint->LocalAnimatedMatrix.setScale( node->getScale() ); + + joint->positionHint=node->positionHint; + joint->scaleHint=node->scaleHint; + joint->rotationHint=node->rotationHint; + } + //Remove cache, temp... + lastAnimatedFrame=-1; + lastSkinnedFrame=-1; + + BoneControlUsed=true; +} + +void CSkinnedMesh::createJoints(core::array &JointChildSceneNodes, + IAnimatedMeshSceneNode* AnimatedMeshSceneNode, ISceneManager* SceneManager) +{ + u32 i; + + //Create new joints + for (i=0;iName.c_str()); + + JointChildSceneNodes.push_back(node); + } + + //Match up parents + for (i=0;iChildren.size();++n) + { + if (parentTest->Children[n]==joint) + { + parentID=j; + break; + } + } + } + } + + if (parentID!=-1) + node->setParent( JointChildSceneNodes[parentID] ); + else + node->setParent( AnimatedMeshSceneNode ); + + node->drop(); + } +} + +void CSkinnedMesh::convertMeshToTangents() +{ + // now calculate tangents + for (u32 b=0; b < LocalBuffers.size(); ++b) + { + if (LocalBuffers[b]) + { + LocalBuffers[b]->MoveTo_Tangents(); + + s32 idxCnt = LocalBuffers[b]->getIndexCount(); + + u16* idx = LocalBuffers[b]->getIndices(); + video::S3DVertexTangents* v = + (video::S3DVertexTangents*)LocalBuffers[b]->getVertices(); + + for (s32 i=0; i + +#include "ISkinnedMesh.h" + +namespace irr +{ +namespace scene +{ + + class IAnimatedMeshSceneNode; + class IBoneSceneNode; + + class CSkinnedMesh: public ISkinnedMesh + { + public: + + //! constructor + CSkinnedMesh(); + + //! destructor + virtual ~CSkinnedMesh(); + + //! returns the amount of frames. If the amount is 1, it is a static (=non animated) mesh. + virtual s32 getFrameCount(); + + //! returns the animated mesh based on a detail level (which is ignored) + virtual IMesh* getMesh(s32 frame, s32 detailLevel=255, s32 startFrameLoop=-1, s32 endFrameLoop=-1); + + //! Animates this mesh's joints based on frame input + //! blend: {0-old position, 1-New position} + virtual void animateMesh(f32 frame, f32 blend); + + //! Preforms a software skin on this mesh based of joint positions + virtual void skinMesh(); + + //! returns amount of mesh buffers. + virtual u32 getMeshBufferCount() const; + + //! returns pointer to a mesh buffer + virtual IMeshBuffer* getMeshBuffer(u32 nr) const; + + //! Returns pointer to a mesh buffer which fits a material + /** \param material: material to search for + \return Returns the pointer to the mesh buffer or + NULL if there is no such mesh buffer. */ + virtual IMeshBuffer* getMeshBuffer( const video::SMaterial &material) const; + + //! returns an axis aligned bounding box + virtual const core::aabbox3d& getBoundingBox() const; + + //! set user axis aligned bounding box + virtual void setBoundingBox( const core::aabbox3df& box); + + //! sets a flag of all contained materials to a new value + virtual void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue); + + //! Returns the type of the animated mesh. + virtual E_ANIMATED_MESH_TYPE getMeshType() const; + + //! Gets joint count. + virtual s32 getJointCount() const; + + //! Gets the name of a joint. + virtual const c8* getJointName(s32 number) const; + + //! Gets a joint number from its name + virtual s32 getJointNumber(const c8* name) const; + + //! uses animation from another mesh + virtual bool useAnimationFrom(ISkinnedMesh *mesh); + + //! Update Normals when Animating + //! False= Don't (default) + //! True = Update normals, slower + virtual void updateNormalsWhenAnimating(bool on); + + //! Sets Interpolation Mode + virtual void setInterpolationMode(E_INTERPOLATION_MODE mode); + + //! Recovers the joints from the mesh + virtual void recoverJointsFromMesh(core::array &JointChildSceneNodes); + + //! Tranfers the joint data to the mesh + virtual void tranferJointsToMesh(core::array &JointChildSceneNodes); + + //! Creates an array of joints from this mesh + virtual void createJoints(core::array &JointChildSceneNodes, IAnimatedMeshSceneNode* AnimatedMeshSceneNode, ISceneManager* SceneManager); + + + virtual void convertMeshToTangents(); + + + + + + //Interface for the mesh loaders (finalize should lock these functions, and they should have some prefix like loader_ + + //these functions will use the needed arrays, set vaules, etc to help the loaders + + //! exposed for loaders to add mesh buffers + virtual core::array &getMeshBuffers(); + + //! alternative method for adding joints + virtual core::array &getAllJoints(); + + //! loaders should call this after populating the mesh + virtual void finalize(); + + + + + virtual SSkinMeshBuffer *createBuffer(); + + virtual SJoint *createJoint(SJoint *parent=0); + + virtual SPositionKey *createPositionKey(SJoint *joint); + virtual SScaleKey *createScaleKey(SJoint *joint); + virtual SRotationKey *createRotationKey(SJoint *joint); + + virtual SWeight *createWeight(SJoint *joint); + + + + + +private: + + void checkForAnimation(); + + void normalizeWeights(); + + void buildAll_LocalAnimatedMatrices(); //public? + + void buildAll_GlobalAnimatedMatrices(SJoint *Joint=0, SJoint *ParentJoint=0); + + void getFrameData(f32 frame,SJoint *Node,core::vector3df &position, s32 &positionHint, core::vector3df &scale, s32 &scaleHint, core::quaternion &rotation, s32 &rotationHint); + + void CalculateGlobalMatrixes(SJoint *Joint,SJoint *ParentJoint); + + void SkinJoint(SJoint *Joint, SJoint *ParentJoint); + + void calculateTangents(core::vector3df& normal, + core::vector3df& tangent, core::vector3df& binormal, + core::vector3df& vt1, core::vector3df& vt2, core::vector3df& vt3, + core::vector2df& tc1, core::vector2df& tc2, core::vector2df& tc3); + + //void createSkelton_Helper(ISceneManager* SceneManager, core::array &JointChildSceneNodes, IAnimatedMeshSceneNode *AnimatedMeshSceneNode, ISceneNode* ParentNode, SJoint *ParentNode, SJoint *Node); + + + core::array *SkinningBuffers; //Meshbuffer to skin, default is to skin localBuffers + + core::array LocalBuffers; + + core::array AllJoints; + core::array RootJoints; + + bool HasAnimation; + + bool PreparedForSkinning; + + f32 AnimationFrames; + + f32 lastAnimatedFrame; + f32 lastSkinnedFrame; + bool BoneControlUsed; + + bool AnimateNormals; + + E_INTERPOLATION_MODE InterpolationMode; + + core::aabbox3d BoundingBox; + + core::array< core::array > Vertices_Moved; + }; + +} // end namespace scene +} // end namespace irr + +#endif + + + diff --git a/source/Irrlicht/CXAnimationPlayer.cpp b/source/Irrlicht/CXAnimationPlayer.cpp deleted file mode 100644 index f0abce3d..00000000 --- a/source/Irrlicht/CXAnimationPlayer.cpp +++ /dev/null @@ -1,863 +0,0 @@ -// Copyright (C) 2002-2007 Nikolaus Gebhardt -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#include "CXAnimationPlayer.h" -#include "ISceneNode.h" -#include "IVideoDriver.h" -#include "os.h" -#include "SMeshBuffer.h" -#include "IMeshManipulator.h" - -namespace irr -{ -namespace scene -{ - -//! constructor -CXAnimationPlayer::CXAnimationPlayer(CXFileReader* reader, - video::IVideoDriver* driver, - IMeshManipulator* manip, - const c8* filename) -: Reader(reader), Driver(driver), AnimatedMesh(0), - FileName(filename), Manipulator(manip), IsAnimatedSkinnedMesh(false), - CurrentAnimationTime(-1.0f), LastAnimationTime(1.0f), - CurrentAnimationSet(0), DebugSkeletonCrossSize(1.0f) -{ - OriginalMesh = new scene::SMesh(); - - if (!Reader) - return; - - if (Driver) - Driver->grab(); - - if (Manipulator) - Manipulator->grab(); - - Reader->grab(); - - createAnimationData(); -} - - - -//! destructor -CXAnimationPlayer::~CXAnimationPlayer() -{ - OriginalMesh->drop(); - - if (Reader) - Reader->drop(); - - if (Driver) - Driver->drop(); - - if (AnimatedMesh) - AnimatedMesh->drop(); - - if (Manipulator) - Manipulator->drop(); -} - - - -//! Gets the frame count of the animated mesh. -s32 CXAnimationPlayer::getFrameCount() -{ - return IsAnimatedSkinnedMesh ? (s32)LastAnimationTime : 1; -} - - - -//! Returns the IMesh interface for a frame. -IMesh* CXAnimationPlayer::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop) -{ - if (!IsAnimatedSkinnedMesh) - return OriginalMesh; - - if (CurrentAnimationTime != (f32)frame) - { - - CurrentAnimationTime = (f32)frame; - animateSkeleton(); - modifySkin(); - updateBoundingBoxFromAnimation(); - } - return AnimatedMesh; -} - - - -//! Returns an axis aligned bounding box of the mesh. -const core::aabbox3d& CXAnimationPlayer::getBoundingBox() const -{ - return Box; -} - - - -//! Returns the type of the animated mesh. -E_ANIMATED_MESH_TYPE CXAnimationPlayer::getMeshType() const -{ - return EAMT_X; -} - - - -void CXAnimationPlayer::createAnimationData() -{ - int i, iCnt; - // get joints from x-file - core::array& pgRootFrames = Reader->getRootFrames(); - iCnt = pgRootFrames.size(); - for( i = 0; i < iCnt; i++ ) - { - createJointData(pgRootFrames[i], -1); - - createMeshData(); - - if (IsAnimatedSkinnedMesh && AnimatedMesh) - { - animateSkeleton(); - modifySkin(); - updateBoundingBoxFromAnimation(); - DebugSkeletonCrossSize = AnimatedMesh->getBoundingBox().getExtent().X / 20.0f; - } - else - DebugSkeletonCrossSize = OriginalMesh->getBoundingBox().getExtent().X / 20.0f; - } -} - - -void CXAnimationPlayer::createMeshData() -{ - int i, iCnt; - core::array& pgRootFrames = Reader->getRootFrames(); - iCnt = pgRootFrames.size(); - for( i = 0; i < iCnt; i++ ) - { - // create mesh - addFrameToMesh(pgRootFrames[i]); - - // recalculate box - OriginalMesh->recalculateBoundingBox(); - - // store box (fix by jox, thnx) - Box = OriginalMesh->getBoundingBox(); - - // sort weights in joints - for (s32 j=0; j<(s32)Joints.size(); ++j) - Joints[j].Weights.sort(); - - // copy mesh - AnimatedMesh = Manipulator->createMeshCopy(OriginalMesh); - - // create and link animation data - prepareAnimationData(); - - // first animation - animateSkeleton(); - modifySkin(); - } -} - - -void CXAnimationPlayer::addFrameToMesh(CXFileReader::SXFrame& frame) -{ - // go through all meshes - for (u32 m=0; maddMeshBuffer(buf); - buf->drop(); - - // new weights buffer - Weights.push_back( core::array() ); - - // create material - buf->Material = getMaterialFromXMaterial( - frame.Meshes[m].MaterialList.Materials[mt]); - - // add all faces of this material - addFacesToBuffer(OriginalMesh->MeshBuffers.size()-1, - frame.Meshes[m], mt, frame); - buf->recalculateBoundingBox(); - } - } - - // add child frames - for (u32 c=0; cgetTexture(xmat.TextureFileName.c_str()); - if (mat.Textures[0] == 0) - // use path from .x file with texture name - mat.Textures[0] = Driver->getTexture(getTextureFileName(xmat.TextureFileName).c_str()); - } - - return mat; -} - - - -void CXAnimationPlayer::addFacesToBuffer(s32 meshbuffernr, CXFileReader::SXMesh& mesh, s32 matnr, const CXFileReader::SXFrame& frame) -{ - scene::SMeshBuffer* buf = (SMeshBuffer*)OriginalMesh->MeshBuffers[meshbuffernr]; - - u32 tcnt = mesh.TextureCoords.size(); - u32 ncnt = mesh.Normals.size(); - u32 ccnt = mesh.VertexColors.size(); - - // precompute which joint belongs to which weight array - core::array< s32 > jointNumberWeightNumberMap; - for (u32 w=0; wMaterial.DiffuseColor; - - s32 nidx = buf->Vertices.linear_reverse_search(v); - bool alreadyIn = (nidx != -1); - - if (!alreadyIn) - { - nidx = buf->Vertices.size(); - buf->Indices.push_back(nidx); - buf->Vertices.push_back(v); - Weights[meshbuffernr].push_back(SVertexWeight()); - } - else - buf->Indices.push_back(nidx); - - bool isWeighted = alreadyIn; - - // add weight data of this vertex to all joints - if (!alreadyIn) - for (s32 w=0; w<(s32)mesh.SkinWeights.size(); ++w) - { - s32 vertexinweights = mesh.SkinWeights[w].Weights.binary_search(CXFileReader::SXWeight(idx)); - - if (vertexinweights != -1) - { - s32 jnr = jointNumberWeightNumberMap[w]; - - if (jnr != -1) - { - // weight per joint - Joints[jnr].Weights.push_back(SWeightData( - meshbuffernr, - nidx, - mesh.SkinWeights[w].Weights[vertexinweights].Weight)); - - // weight per vertex - SVertexWeight& weight = Weights[meshbuffernr].pointer()[nidx]; - weight.add(mesh.SkinWeights[w].Weights[vertexinweights].Weight, jnr); - - isWeighted = true; - } - } - } // end for all weights - - // if this vertex does not have a weight, create a virtual new - // joint and attach it to this one - if (!isWeighted) - addVirtualWeight(meshbuffernr, nidx, mesh, frame); - - } // end for all faces - - } // end for all materials - } - - // generate missing normals - if (!ncnt) - { - // Using Mesh manipulator - Manipulator->recalculateNormals ( buf, true ); - } - - /*// transform vertices and normals - core::matrix4 mat = frame.LocalMatrix; - - s32 vcnt = buf->Vertices.size(); - for (s32 u=0; uVertices[u].Pos); - mat.rotateVect(buf->Vertices[u].Normal); - }*/ -} - - -void CXAnimationPlayer::addVirtualWeight(s32 meshbuffernr, s32 vtxidx, CXFileReader::SXMesh& mesh, - const CXFileReader::SXFrame& frame) -{ - // find original joint of vertex - s32 jnr = getJointNumberFromName(frame.Name); - if (jnr == -1) - return; - - // weight per joint - Joints[jnr].Weights.push_back(SWeightData( - meshbuffernr, - vtxidx, - 1.0f)); - - // weight per vertex - SVertexWeight& weight = Weights[meshbuffernr].pointer()[vtxidx]; - weight.add(1.0f, jnr); -} - - - -s32 CXAnimationPlayer::getJointNumberFromName(const core::stringc& name) const -{ - for (s32 i=0; i<(s32)Joints.size(); ++i) - if (Joints[i].Name == name) - return i; - - return -1; -} - - - -//! Use .x file path as prefix for texture -core::stringc CXAnimationPlayer::getTextureFileName(const core::stringc& texture) -{ - s32 idx = -1; - idx = FileName.findLast('/'); - - if (idx == -1) - idx = FileName.findLast('\\'); - - if (idx == -1) - return texture; - - return FileName.subString(0, idx+1)+texture; -} - - - -void CXAnimationPlayer::createJointData(const CXFileReader::SXFrame& f, s32 JointParent) -{ - // add joint - s32 index = Joints.size(); - Joints.push_back(SJoint()); - SJoint& j = Joints.getLast(); - - j.Parent = JointParent; - j.GlobalMatrix = f.GlobalMatrix; - j.LocalMatrix = f.LocalMatrix; - j.AnimatedMatrix = j.GlobalMatrix; - j.LocalAnimatedMatrix = j.LocalMatrix; - j.CombinedAnimationMatrix = j.AnimatedMatrix * j.MatrixOffset; - j.IsVirtualJoint = false; - - j.Name = f.Name; - - // add all children - for (s32 i=0; i<(s32)f.ChildFrames.size(); ++i) - createJointData(f.ChildFrames[i], index); -} - - -//! Returns a pointer to a transformation matrix -core::matrix4* CXAnimationPlayer::getMatrixOfJoint(s32 jointNumber, s32 frame) -{ - if (jointNumber < 0 || jointNumber >= (s32)Joints.size()) - return 0; - - return &Joints[jointNumber].AnimatedMatrix; -} - - -//! Gets joint count. -s32 CXAnimationPlayer::getJointCount() const -{ - return Joints.size(); -} - - -//! Gets the name of a joint. -const c8* CXAnimationPlayer::getJointName(s32 number) const -{ - if (number<0 || number>=(s32)Joints.size()) - return 0; - - return Joints[number].Name.c_str(); -} - - -//! Gets a joint number from its name -s32 CXAnimationPlayer::getJointNumber(const c8* name) const -{ - for (s32 i=0; i<(s32)Joints.size(); ++i) - if (Joints[i].Name == name) - return i; - - return -1; -} - - -//! Returns a pointer to list of points containing the skeleton. -const core::array* CXAnimationPlayer::getDrawableSkeleton(s32 frame) -{ - DebugSkeleton.clear(); - - f32 k = DebugSkeletonCrossSize; - f32 p = 0.0f; - - for (s32 i=0; i<(s32)Joints.size(); ++i) - { - core::vector3df start(p,p,p); - core::vector3df end(p,p,p); - - Joints[i].AnimatedMatrix.transformVect(start); - - DebugSkeleton.push_back(start); - DebugSkeleton.push_back(start + core::vector3df(0,k,0)); - DebugSkeleton.push_back(start); - DebugSkeleton.push_back(start + core::vector3df(0,-k,0)); - DebugSkeleton.push_back(start); - DebugSkeleton.push_back(start + core::vector3df(k,0,0)); - DebugSkeleton.push_back(start); - DebugSkeleton.push_back(start + core::vector3df(-k,0,0)); - DebugSkeleton.push_back(start); - DebugSkeleton.push_back(start + core::vector3df(0,0,k)); - DebugSkeleton.push_back(start); - DebugSkeleton.push_back(start + core::vector3df(0,0,-k)); - - if (Joints[i].Parent != -1) - { - Joints[Joints[i].Parent].AnimatedMatrix.transformVect(end); - - DebugSkeleton.push_back(end); - DebugSkeleton.push_back(start); - } - } - - return &DebugSkeleton; -} - - -//! animates the skeleton based on the animation data -void CXAnimationPlayer::animateSkeleton() -{ - if (!AnimationSets.empty()) - { - // reset joints - for (u32 jii=0; jii= CurrentAnimationTime) - { - idx1 = t; - idx2 = (t+1) % currentSet.Animations[i].Times.size(); - break; - } - } - - if (idx1 == -1) - continue; - - // calculate interpolation factor - f32 factor = (CurrentAnimationTime - currentSet.Animations[i].Times[idx1]) / - (currentSet.Animations[i].Times[idx2] - currentSet.Animations[i].Times[idx1]); - - // animate it - switch(currentSet.Animations[i].keyType) - { - case 0: // rotation - { - // with this code, rotations are not 100% ok, they are - // mirrored. - core::quaternion q; - q.slerp(currentSet.Animations[i].Quaternions[idx1], - currentSet.Animations[i].Quaternions[idx2], - factor); - - joint.LocalAnimatedMatrix *= q.getMatrix(); - joint.WasAnimatedThisFrame = true; - } - break; - case 1: // scale - { - core::matrix4 mat1, mat2; - mat1.setScale(currentSet.Animations[i].Vectors[idx1]); - mat2.setScale(currentSet.Animations[i].Vectors[idx2]); - - joint.LocalAnimatedMatrix *= mat1.interpolate(mat2, factor); - joint.WasAnimatedThisFrame = true; - } - break; - case 2: // position - { - core::matrix4 mat1, mat2; - mat1.setTranslation(currentSet.Animations[i].Vectors[idx1]); - mat2.setTranslation(currentSet.Animations[i].Vectors[idx2]); - - joint.LocalAnimatedMatrix *= mat1.interpolate(mat2, factor); - joint.WasAnimatedThisFrame = true; - } - break; - case 4: - case 3: // matrix - { - joint.LocalAnimatedMatrix = - currentSet.Animations[i].Matrices[idx1].interpolate( - currentSet.Animations[i].Matrices[idx2], factor); - - joint.WasAnimatedThisFrame = true; - } - break; - } - - } - } - - // update all joints - for (s32 ji=0; ji<(s32)Joints.size(); ++ji) - { - if (!Joints[ji].WasAnimatedThisFrame) - Joints[ji].LocalAnimatedMatrix = Joints[ji].LocalMatrix; - - Joints[ji].AnimatedMatrix = Joints[ji].LocalAnimatedMatrix; - - if (Joints[ji].Parent != -1) - Joints[ji].AnimatedMatrix = Joints[Joints[ji].Parent].AnimatedMatrix * Joints[ji].AnimatedMatrix; - - Joints[ji].CombinedAnimationMatrix = Joints[ji].AnimatedMatrix * - Joints[ji].MatrixOffset; - } -} - - -//! modifies the skin based on the animated skeleton -void CXAnimationPlayer::modifySkin() -{ - // set animated vertices to zero - for (s32 k=0; k<(s32)Joints.size(); ++k) - { - for (s32 w=0; w<(s32)Joints[k].Weights.size(); ++w) - { - SWeightData& wd = Joints[k].Weights[w]; - -#ifdef _XREADER_DEBUG - if (wd.buffer >= AnimatedMesh->getMeshBufferCount() || - wd.vertex >= AnimatedMesh->getMeshBuffer(wd.buffer)->getVertexCount()) - os::Printer::log("CXAnimationPlayer: Invalid Weights"); -#endif - - video::S3DVertex* nv = (video::S3DVertex*)AnimatedMesh->getMeshBuffer(wd.buffer)->getVertices(); - nv[wd.vertex].Pos.set(0,0,0); - } - } - - -#ifdef _XREADER_DEBUG - bool somethingIsWrong = false; - - // check if all vertices are set to zero - for (u32 mb=0; mbgetMeshBufferCount(); ++mb) - { - video::S3DVertex* v = (video::S3DVertex*)AnimatedMesh->getMeshBuffer(mb)->getVertices(); - s32 c = AnimatedMesh->getMeshBuffer(mb)->getVertexCount(); - for (s32 vt=0; vtgetMeshBufferCount()); - os::Printer::log(tmp); - - for (u32 mb=0; mbgetMeshBufferCount(); ++mb) - { - sprintf(tmp, "CXAnimationPlayer: Meshbuffer #%d: %d vertices", mb, AnimatedMesh->getMeshBuffer(mb)->getVertexCount()); - os::Printer::log(tmp); - } - } -#endif - - // transform vertices - for (u32 mb=0; mbgetMeshBufferCount(); ++mb) - { - video::S3DVertex* av = (video::S3DVertex*)AnimatedMesh->getMeshBuffer(mb)->getVertices(); - video::S3DVertex* ov = (video::S3DVertex*)OriginalMesh->getMeshBuffer(mb)->getVertices(); - const u32 c = AnimatedMesh->getMeshBuffer(mb)->getVertexCount(); - for (u32 vt=0; vtgetAnimationSetCount(); - for (s32 i=0; igetAnimationSet(i); - mySet.AnimationName = readerSet.AnimationName; - - // through all animations - for (s32 a=0; a<(s32)readerSet.Animations.size(); ++a) - { - // through all keys - for (s32 k=0; k<(s32)readerSet.Animations[a].Keys.size(); ++k) - { - // link with joint - s32 jntnr = getJointNumberFromName(readerSet.Animations[a].FrameName); - - if (jntnr == -1) - { - os::Printer::log( - "CXAnimationPlayer: Animationtrack without corresponding joint found", - readerSet.Animations[a].FrameName.c_str()); - continue; - } - - // copy track - s32 keyCount = (s32)readerSet.Animations[a].Keys[k].numberOfKeys; - if (!keyCount) - { - os::Printer::log( - "CXAnimationPlayer: Skipping Animationtrack with zero key frames", - readerSet.Animations[a].FrameName.c_str()); - continue; - } - - // add new track - mySet.Animations.push_back(SXAnimationTrack()); - SXAnimationTrack& myTrack = mySet.Animations.getLast(); - myTrack.jointNr = jntnr; - IsAnimatedSkinnedMesh = true; - - s32 type = readerSet.Animations[a].Keys[k].keyType; - s32 l; - myTrack.keyType = type; - - #ifdef _XREADER_DEBUG - char tmp[255]; - sprintf(tmp, "adding track %s with %d keys, type:%d", readerSet.Animations[a].FrameName.c_str(), keyCount, type); - os::Printer::log(tmp); - #endif - - switch(type) - { - case 0: // quaternion - for (l=0; l LastAnimationTime) - LastAnimationTime = myTrack.Times.getLast(); - } - } - } - - // sort animation tracks - mySet.Animations.sort(); - } -} - -void CXAnimationPlayer::updateBoundingBoxFromAnimation() -{ - if (!Joints.size()) - return; - - bool first = true; - - for (u32 i=0; iBoundingBox = Box; -} - -//! Returns amount of animations in .X-file. -s32 CXAnimationPlayer::getAnimationCount() const -{ - return AnimationSets.size(); -} - -//! Returns the name of an animation. -const c8* CXAnimationPlayer::getAnimationName(s32 idx) const -{ - if (idx < 0 || idx >= (s32)AnimationSets.size()) - return 0; - - return AnimationSets[idx].AnimationName.c_str(); -} - - -//! Sets an animation as animation to play back. -void CXAnimationPlayer::setCurrentAnimation(s32 idx) -{ - if (idx < 0 || idx >= (s32)AnimationSets.size()) - return; - - CurrentAnimationSet = idx; -} - - -//! Sets an animation as animation to play back. -bool CXAnimationPlayer::setCurrentAnimation(const c8* name) -{ - for (s32 i=0; i<(s32)AnimationSets.size(); ++i) - if (AnimationSets[i].AnimationName == name) - { - CurrentAnimationSet = i; - return true; - } - - return false; -} - - -} // end namespace scene -} // end namespace irr - diff --git a/source/Irrlicht/CXAnimationPlayer.h b/source/Irrlicht/CXAnimationPlayer.h deleted file mode 100644 index 25bae750..00000000 --- a/source/Irrlicht/CXAnimationPlayer.h +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright (C) 2002-2007 Nikolaus Gebhardt -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#ifndef __C_X_ANIMATION_PLAYER_H_INCLUDED__ -#define __C_X_ANIMATION_PLAYER_H_INCLUDED__ - -#include "IAnimatedMeshX.h" -#include "CXFileReader.h" -#include "SMesh.h" -#include "SMeshBuffer.h" - -namespace irr -{ -namespace video -{ - class IVideoDriver; -} -namespace scene -{ - class IMeshManipulator; - - class CXAnimationPlayer : public IAnimatedMeshX - { - public: - - //! constructor - CXAnimationPlayer(CXFileReader* reader, - video::IVideoDriver* driver, - IMeshManipulator* manip, - const c8* filename); - - //! destructor - virtual ~CXAnimationPlayer(); - - //! Gets the frame count of the animated mesh. - virtual s32 getFrameCount(); - - //! Returns the IMesh interface for a frame. - virtual IMesh* getMesh(s32 frame, s32 detailLevel=255, s32 startFrameLoop=-1, s32 endFrameLoop=-1); - - //! Returns an axis aligned bounding box of the mesh. - virtual const core::aabbox3d& getBoundingBox() const; - - //! Returns the type of the animated mesh. - virtual E_ANIMATED_MESH_TYPE getMeshType() const; - - //! Returns a pointer to a transformation matrix - virtual core::matrix4* getMatrixOfJoint(s32 jointNumber, s32 frame); - - //! Gets joint count. - virtual s32 getJointCount() const; - - //! Gets the name of a joint. - virtual const c8* getJointName(s32 number) const; - - //! Gets a joint number from its name - virtual s32 getJointNumber(const c8* name) const; - - //! Returns a pointer to list of points containing the skeleton. - virtual const core::array* getDrawableSkeleton(s32 frame); - - //! Returns amount of animations in .X-file. - virtual s32 getAnimationCount() const; - - //! Returns the name of an animation. - virtual const c8* getAnimationName(s32 idx) const; - - //! Sets an animation as animation to play back. - virtual void setCurrentAnimation(s32 idx); - - //! Sets an animation as animation to play back. - virtual bool setCurrentAnimation(const c8* name); - - private: - - struct SWeightData - { - SWeightData() {}; - - SWeightData(const SWeightData& other) - : buffer(other.buffer), vertex(other.vertex), weight(other.weight) - {} - - SWeightData(s32 b, s32 v, f32 w) - : buffer(b), vertex(v), weight(w) - {} - - s32 buffer; - s32 vertex; - f32 weight; - - bool operator <(const SWeightData& other) const - { - return (buffer < other.buffer || - (buffer == other.buffer && - vertex < other.vertex) || - (buffer == other.buffer && - vertex == other.vertex && - weight < other.weight)); - } - }; - - struct SVertexWeight - { - SVertexWeight() : weightCount(0) {} - - // weight per vertex, at maximum, 4 joints per vertex - f32 weight[4]; - s32 joint[4]; - - s32 weightCount; - - void add(f32 _weight, s32 _joint) - { - if (weightCount == 4) - return; - - weight[weightCount] = _weight; - joint[weightCount] = _joint; - ++weightCount; - } - }; - - struct SJoint - { - s32 Parent; // index of parent - core::array Weights; - core::matrix4 MatrixOffset; - core::matrix4 LocalMatrix; - core::matrix4 GlobalMatrix; - core::matrix4 AnimatedMatrix; - core::matrix4 LocalAnimatedMatrix; - core::matrix4 CombinedAnimationMatrix; // for faster computing - core::stringc Name; - bool IsVirtualJoint; // for in .x file not weighted vertices - bool WasAnimatedThisFrame; // used by animateSkeleton() - }; - - void createAnimationData(); - void createJointData(const CXFileReader::SXFrame& f, s32 JointParent); - void createMeshData(); - void addFrameToMesh(CXFileReader::SXFrame& frame); - video::SMaterial getMaterialFromXMaterial(const CXFileReader::SXMaterial& xmat); - void addFacesToBuffer(s32 meshbuffernr, CXFileReader::SXMesh& mesh, s32 matnr, const CXFileReader::SXFrame& frame); - //! use .x file path as prefix for texture - core::stringc getTextureFileName(const core::stringc& texture); - - s32 getJointNumberFromName(const core::stringc& name) const; - - //! prepares animation data which was read in from the .x file - void prepareAnimationData(); - - //! animates the skeleton based on the animation data - void animateSkeleton(); - - //! modifies the skin based on the animated skeleton - void modifySkin(); - - void updateBoundingBoxFromAnimation(); - - void addVirtualWeight(s32 meshbuffernr, s32 vtxidx, CXFileReader::SXMesh& mesh, - const CXFileReader::SXFrame& frame); - - CXFileReader* Reader; - video::IVideoDriver* Driver; - scene::SMesh *OriginalMesh; - scene::SMesh *AnimatedMesh; - core::aabbox3df Box; - core::stringc FileName; - IMeshManipulator* Manipulator; - core::array DebugSkeleton; - bool IsAnimatedSkinnedMesh; - - core::array Joints; - - f32 CurrentAnimationTime; - f32 LastAnimationTime; - s32 CurrentAnimationSet; - f32 DebugSkeletonCrossSize; - - // one array of weights per mesh buffer - core::array< core::array > Weights; - - // data for animations - - struct SXAnimationTrack - { - s32 jointNr; - s32 keyType; // 0=rotation, 1=scale, 2=position, 3=matrix - - core::array Quaternions; - core::array Vectors; - core::array Matrices; - core::array Times; - - bool operator <(SXAnimationTrack& other) const - { - if (jointNr != other.jointNr) - return (jointNr < other.jointNr); - - return keyType > other.keyType; - } - }; - - struct SXAnimationSet - { - core::stringc AnimationName; - core::array Animations; - }; - - core::array AnimationSets; - }; - -} // end namespace scene -} // end namespace irr - -#endif - diff --git a/source/Irrlicht/CXFileReader.cpp b/source/Irrlicht/CXFileReader.cpp deleted file mode 100644 index 620198bf..00000000 --- a/source/Irrlicht/CXFileReader.cpp +++ /dev/null @@ -1,1927 +0,0 @@ -// Copyright (C) 2002-2007 Nikolaus Gebhardt -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#include "CXFileReader.h" -#include "os.h" -#include "fast_atof.h" -#include "coreutil.h" - -namespace irr -{ -namespace scene -{ - -CXFileReader::CXFileReader(io::IReadFile* file) -: MajorVersion(0), MinorVersion(0), binary(false), binaryNumCount(0), - Buffer(0), Size(0), FloatSize(0), P(0), End(0), ErrorHappened(false), - m_bFrameRemoved(false), m_pgCurFrame(0) -{ - if (!file) - { - ErrorHappened = true; - return; - } - - if (!readFileIntoMemory(file)) - { - ErrorHappened = true; - return; - } - - if (!parseFile()) - { - ErrorHappened = true; - return; - } - -#ifdef _XREADER_DEBUG - for( unsigned int i = 0; i < RootFrames.size(); i++ ) - validateMesh(&RootFrames[i]); -#endif - - for( unsigned int i = 0; i < RootFrames.size(); i++ ) - { - computeGlobalFrameMatrices(RootFrames[i], 0 ); - } -} - - -CXFileReader::~CXFileReader() -{ - if (Buffer) - delete [] Buffer; - - for (u32 i=0; iMeshes.size(); ++m) - { - s32 vcnt = frame->Meshes[m].Vertices.size(); - s32 icnt = frame->Meshes[m].Indices.size(); - s32 ncnt = frame->Meshes[m].Normals.size(); - s32 nicnt = frame->Meshes[m].NormalIndices.size(); - - // validate indices in mesh - s32 i; - - for (i=0; iMeshes[m].Indices[i] < 0) - { - sprintf(tmp, "XLoader error: index %d smaller than 0 in mesh %u: %d, frame '%s'", - i, m, frame->Meshes[m].Indices[i], frame->Name.c_str()); - os::Printer::log(tmp, ELL_ERROR); - error = true; - } - - if (frame->Meshes[m].Indices[i] > vcnt-1) - { - sprintf(tmp, "XLoader error: invalid index %d in mesh %u: %d, frame '%s'", - i, m, frame->Meshes[m].Indices[i], frame->Name.c_str()); - os::Printer::log(tmp, ELL_ERROR); - error = true; - } - } - - // validate normal indices - - for (i=0; iMeshes[m].NormalIndices[i] < 0) - { - sprintf(tmp, "XLoader error: normal index %d smaller than 0 in mesh %u: %d, frame '%s'", - i, m, frame->Meshes[m].NormalIndices[i], frame->Name.c_str()); - os::Printer::log(tmp, ELL_ERROR); - error = true; - } - - if (frame->Meshes[m].NormalIndices[i] > ncnt-1) - { - sprintf(tmp, "XLoader error: invalid normal index %d in mesh %u: %d, frame '%s'", - i, m, frame->Meshes[m].NormalIndices[i], frame->Name.c_str()); - os::Printer::log(tmp, ELL_ERROR); - error = true; - } - } - } - - - // validate child frames - for (u32 i=0; iChildFrames.size(); ++i) - if (!validateMesh(&frame->ChildFrames[i])) - error = true; - - return error; -} - - -//! Reads file into memory -bool CXFileReader::readFileIntoMemory(io::IReadFile* file) -{ - s32 Size = file->getSize(); - if (Size < 12) - { - os::Printer::log("X File is too small.", ELL_WARNING); - return false; - } - - Buffer = new c8[Size]; - - //! read all into memory - file->seek(0); // apparently sometimes files have been read already, so reset it - if (file->read(Buffer, Size) != Size) - { - os::Printer::log("Could not read from x file.", ELL_WARNING); - return false; - } - - End = Buffer + Size; - - //! check header "xof " - if (strncmp(Buffer, "xof ", 4)!=0) - { - os::Printer::log("Not an x file, wrong header.", ELL_WARNING); - return false; - } - - //! read minor and major version, e.g. 0302 or 0303 - c8 tmp[3]; - tmp[2] = 0x0; - tmp[0] = Buffer[4]; - tmp[1] = Buffer[5]; - MajorVersion = strtol(tmp, (char**) &P, 10); - - tmp[0] = Buffer[6]; - tmp[1] = Buffer[7]; - MinorVersion = strtol(tmp, (char**) &P, 10); - - //! read format - if (strncmp(&Buffer[8], "txt ", 4) ==0) - binary = false; - else if (strncmp(&Buffer[8], "bin ", 4) ==0) - binary = true; - else - { - os::Printer::log("Only uncompressed x files currently supported.", ELL_WARNING); - return false; - } - binaryNumCount=0; - - //! read float size - if (strncmp(&Buffer[12], "0032", 4) ==0) - FloatSize = 4; - else if (strncmp(&Buffer[12], "0064", 4) ==0) - FloatSize = 8; - else - { - os::Printer::log("Float size not supported.", ELL_WARNING); - return false; - } - - P = &Buffer[16]; - - readUntilEndOfLine(); - - return true; -} - -//! Parses the file -bool CXFileReader::parseFile() -{ - u32 u32Idx; - while(parseDataObject()) - { - // loop - } - // loop through hiearchy and combine frames that have no mesh - // and no name into its parent - - m_bFrameRemoved = false; - for( u32Idx = 0; u32Idx < RootFrames.size(); u32Idx++ ) - { - optimizeFrames( &RootFrames[ u32Idx ], 0 ); - } - while( m_bFrameRemoved ) - { - m_bFrameRemoved = false; - for( u32Idx = 0; u32Idx < RootFrames.size(); u32Idx++ ) - { - optimizeFrames( &RootFrames[ u32Idx ], 0 ); - } - } - return true; -} - -//! loop through hiearchy and combine frames that have no mesh or name into parent frame -void CXFileReader::optimizeFrames( SXFrame * pgFrame, SXFrame * pgParent ) -{ - if( pgParent ) - { - if( (0 == pgParent->Meshes.size()) && - (0 == strlen( pgFrame->Name.c_str() )) && - strlen( pgParent->Name.c_str() ) ) - { - // combine this frame with parent - // add child frames to parent - pgParent->LocalMatrix *= pgFrame->LocalMatrix; - - u32 c; - - for( c=0; cChildFrames.size(); ++c ) - { - // add child frames to parent - pgParent->ChildFrames.push_back(pgFrame->ChildFrames[c]); - } - - // add meshes to parent - - for( c=0; cMeshes.size(); ++c ) - { - // add meshes frames to parent - pgParent->Meshes.push_back( pgFrame->Meshes[c] ); - } - - // remove child frames in our list - pgFrame->ChildFrames.clear(); - - // remove meshes - pgFrame->Meshes.clear(); - - // find ourselve and remove from parent frame - for( c=0; c< pgParent->ChildFrames.size(); ++c ) - { - if( &pgParent->ChildFrames[c] == pgFrame ) - { - //found ourself - pgParent->ChildFrames.erase( c, 1 ); - m_bFrameRemoved = true; - return; - } - } - } - } - for (u32 c=0; cChildFrames.size(); ++c) - optimizeFrames( &pgFrame->ChildFrames[c], pgFrame ); -} - - -//! Parses the next Data object in the file -bool CXFileReader::parseDataObject() -{ - core::stringc objectName = getNextToken(); - - if (objectName.size() == 0) - return false; - - // parse specific object - - if (objectName == "template") - return parseDataObjectTemplate(); - else - if (objectName == "Frame") - { - if (!m_pgCurFrame) - { - RootFrames.push_back(SXFrame()); - m_pgCurFrame = &RootFrames.getLast(); - } - else - { - m_pgCurFrame->ChildFrames.push_back(SXFrame()); - m_pgCurFrame = &(m_pgCurFrame->ChildFrames.getLast()); - } - return parseDataObjectFrame( * m_pgCurFrame ); - } - else - if (objectName == "Mesh") - { - // some meshes have no frames at all - if (!m_pgCurFrame) - { - RootFrames.push_back(SXFrame()); - m_pgCurFrame = &RootFrames.getLast(); - } - m_pgCurFrame->Meshes.push_back(SXMesh()); - return parseDataObjectMesh(m_pgCurFrame->Meshes.getLast()); - } - else - if (objectName == "AnimationSet") - { - AnimationSets.push_back(SXAnimationSet()); - return parseDataObjectAnimationSet(AnimationSets.getLast()); - } - else - if (objectName == "Material") - { - // template materials now available thanks to joeWright - TemplateMaterials.push_back(SXTemplateMaterial()); - TemplateMaterials.getLast().Name = getNextToken(); - return parseDataObjectMaterial(TemplateMaterials.getLast().Material); - } - - os::Printer::log("Unknown data object in x file", objectName.c_str()); - - return parseUnknownDataObject(); -} - - -bool CXFileReader::parseDataObjectFrame(SXFrame& frame) -{ -#ifdef _XREADER_DEBUG - os::Printer::log("CXFileReader: Reading frame"); -#endif - - // A coordinate frame, or "frame of reference." The Frame template - // is open and can contain any object. The Direct3D extensions (D3DX) - // mesh-loading functions recognize Mesh, FrameTransformMatrix, and - // Frame template instances as child objects when loading a Frame - // instance. - - if (!readHeadOfDataObject(&frame.Name)) - { - os::Printer::log("No opening brace in Frame found in x file", ELL_WARNING); - return false; - } - - // Now inside a frame. - // read tokens until closing brace is reached. - - while(true) - { - core::stringc objectName = getNextToken(); - - if (objectName.size() == 0) - { - os::Printer::log("Unexpected ending found in Frame in x file.", ELL_WARNING); - return false; - } - else - if (objectName == "}") - { - break; // frame finished - } - else - if (objectName == "Frame") - { - frame.ChildFrames.push_back(SXFrame()); - if (!parseDataObjectFrame(frame.ChildFrames.getLast())) - return false; - } - else - if (objectName == "FrameTransformMatrix") - { - if (!parseDataObjectTransformationMatrix(frame.LocalMatrix)) - return false; - } - else - if (objectName == "Mesh") - { - frame.Meshes.push_back(SXMesh()); - if (!parseDataObjectMesh(frame.Meshes.getLast())) - return false; - } - else - { - os::Printer::log("Unknown data object in frame in x file", objectName.c_str()); - if (!parseUnknownDataObject()) - return false; - } - - } - - return true; -} - - -bool CXFileReader::parseDataObjectTransformationMatrix(core::matrix4 &mat) -{ -#ifdef _XREADER_DEBUG - os::Printer::log("CXFileReader: Reading Transformation Matrix"); -#endif - - if (!readHeadOfDataObject()) - { - os::Printer::log("No opening brace in Transformation Matrix found in x file", ELL_WARNING); - return false; - } - - if (binary) - { - // read matrix in binary format - if (readBinWord() != 7) - { - os::Printer::log("Binary X: Mesh: Expecting float list (for matrix)", ELL_WARNING); - return false; - } - - if (readBinDWord() != 0x10) - { - os::Printer::log("Binary X: Mesh: Should be 16 floats in matrix", ELL_WARNING); - return false; - } - } - - for (s32 i=0; i<4; ++i) - for (s32 j=0; j<4; ++j) - mat(i,j)=readFloat(); - - if (!checkForTwoFollowingSemicolons()) - { - os::Printer::log("No finishing semicolon in Transformation Matrix found in x file", ELL_WARNING); - return false; - } - - if (getNextToken() != "}") - { - os::Printer::log("No closing brace in Transformation Matrix found in x file", ELL_WARNING); - return false; - } - - return true; -} - - -bool CXFileReader::parseDataObjectTemplate() -{ -#ifdef _XREADER_DEBUG - os::Printer::log("CXFileReader: Reading template"); -#endif - - // parse a template data object. Currently not stored. - core::stringc name = getNextToken(); - - // ignore left delimiter - if (getNextToken() != "{") - { - os::Printer::log("Left delimiter in template data object missing.", - name.c_str(), ELL_ERROR); - return false; - } - - // read GUID - core::stringc guid = getNextToken(); - - // read and ignore data members - while(true) - { - core::stringc s = getNextToken(); - - if (s == "}") - break; - - if (s.size() == 0) - return false; - } - - return true; -} - - -bool CXFileReader::parseDataObjectMesh(SXMesh &mesh) -{ -#ifdef _XREADER_DEBUG - os::Printer::log("CXFileReader: Reading mesh"); -#endif - - if (!readHeadOfDataObject(&mesh.Name)) - { - os::Printer::log("No opening brace in Mesh found in x file", ELL_WARNING); - return false; - } - - // read vertex count - s32 nVertices = readInt(); - - // read vertices - mesh.Vertices.set_used(nVertices); - - s32 count=0; - if (binary) - { - // read vertices in binary format - if (readBinWord() != 7) - { - os::Printer::log("Binary X: Mesh: Expecting float list (for vertices)", ELL_WARNING); - return false; - } - count = readBinDWord(); - if (count != (nVertices * 3)) - { - os::Printer::log("Binary X: Mesh: Value count not matching vertices count", ELL_WARNING); - return false; - } - } - - for (s32 n=0; n polygonfaces; - s32 currentIndex = 0; - - for (s32 k=0; k& indexCountPerFace) -{ -#ifdef _XREADER_DEBUG - os::Printer::log("CXFileReader: Reading mesh material list"); -#endif - - if (!readHeadOfDataObject()) - { - os::Printer::log("No opening brace in Mesh Material List found in x file", ELL_WARNING); - return false; - } - - // read material count - readInt(); - - // read non triangulated face material index count - s32 nFaceIndices = readInt(); - - // read non triangulated face indices - - core::array nonTriFaceIndices; - nonTriFaceIndices.set_used(nFaceIndices); - - for (s32 i=0; i= End) - return false; - - if (P[0] != '"') - return false; - ++P; - - while(P < End && P[0]!='"') - { - out.append(P[0]); - ++P; - } - - if ( P[1] != ';' || P[0] != '"') - return false; - P+=2; - - return true; -} - - -bool CXFileReader::parseDataObjectAnimationSet(SXAnimationSet& set) -{ - #ifdef _XREADER_DEBUG - os::Printer::log("CXFileReader: Reading animation set"); - #endif - - if (!readHeadOfDataObject(&set.AnimationName)) - { - os::Printer::log("No opening brace in Animation Set found in x file", ELL_WARNING); - return false; - } - - while(true) - { - core::stringc objectName = getNextToken(); - - if (objectName.size() == 0) - { - os::Printer::log("Unexpected ending found in Animation set in x file.", ELL_WARNING); - return false; - } - else - if (objectName == "}") - { - break; // animation set finished - } - else - if (objectName == "Animation") - { - set.Animations.push_back(SXAnimation()); - if (!parseDataObjectAnimation(set.Animations.getLast())) - return false; - } - else - { - os::Printer::log("Unknown data object in animation set in x file", objectName.c_str()); - if (!parseUnknownDataObject()) - return false; - } - } - return true; -} - - - -bool CXFileReader::parseDataObjectAnimation(SXAnimation& anim) -{ -#ifdef _XREADER_DEBUG - os::Printer::log("CXFileReader: reading animation"); -#endif - - if (!readHeadOfDataObject()) - { - os::Printer::log("No opening brace in Animation found in x file", ELL_WARNING); - return false; - } - - anim.closed = true; - anim.linearPositionQuality = true; - - while(true) - { - core::stringc objectName = getNextToken(); - - if (objectName.size() == 0) - { - os::Printer::log("Unexpected ending found in Animation in x file.", ELL_WARNING); - return false; - } - else - if (objectName == "}") - { - break; // animation finished - } - else - if (objectName == "AnimationKey") - { - anim.Keys.push_back(SXAnimationKey()); - if (!parseDataObjectAnimationKey(anim.Keys.getLast())) - return false; - } - else - if (objectName == "AnimationOptions") - { - //TODO: parse options. - if (!parseUnknownDataObject()) - return false; - } - else - if (objectName == "{") - { - // read frame name - anim.FrameName = getNextToken(); - core::stringc end = getNextToken(); - if (end.size() == 0 || end != "}") - { - os::Printer::log("Unexpected ending found in Animation in x file.", ELL_WARNING); - return false; - } - } - else - { - if (objectName.size()>2 && objectName[0] == '{' && - objectName[objectName.size()-1] == '}') - { - anim.FrameName = objectName.subString(1,objectName.size()-2); - } - else - { - os::Printer::log("Unknown data object in animation in x file", objectName.c_str()); - if (!parseUnknownDataObject()) - return false; - } - } - } - return true; -} - - - -bool CXFileReader::parseDataObjectAnimationKey(SXAnimationKey& animkey) -{ -#ifdef _XREADER_DEBUG - os::Printer::log("CXFileReader: reading animation key"); -#endif - - if (!readHeadOfDataObject()) - { - os::Printer::log("No opening brace in Animation Key found in x file", ELL_WARNING); - return false; - } - - // read key type - animkey.keyType = readInt(); - - if ((animkey.keyType < 0) || (animkey.keyType > 4)) - { - os::Printer::log("Unknown key type found in Animation Key in x file", ELL_WARNING); - return false; - } - - // read number of keys - animkey.numberOfKeys = readInt(); - - // eat the semicolon after the "0". if there are keys present, readInt() - // does this for us. If there aren't, we need to do it explicitly - if (!binary && animkey.numberOfKeys == 0) - getNextToken(); // skip semicolon - - animkey.init(); - - // read keys - switch(animkey.keyType) - { - case 0: - { - //read quaternions - for (s32 i=0; i& normals, - core::array< s32 >& normalIndices, - s32 triangulatedIndexCount, - core::array< s32 >& indexCountPerFace) -{ -#ifdef _XREADER_DEBUG - os::Printer::log("CXFileReader: reading mesh normals"); -#endif - - if (!readHeadOfDataObject()) - { - os::Printer::log("No opening brace in Mesh Normals found in x file", ELL_WARNING); - return false; - } - - // read count - s32 nNormals; - s32 count; - nNormals = readInt(); - normals.set_used(nNormals); - - // read normals - if (binary) - { - if (readBinWord() != 7) - { - os::Printer::log("Binary X: MeshNormals: Expecting float list", ELL_WARNING); - return false; - } - count = readBinDWord(); - if (count != nNormals * 3) - { - os::Printer::log("Binary X: MeshNormals: Value count not equal to normal count", ELL_WARNING); - return false; - } - } - for (s32 i=0; i polygonfaces; - for (s32 k=0; k& textureCoords) -{ -#ifdef _XREADER_DEBUG - os::Printer::log("CXFileReader: reading mesh texture coordinates"); -#endif - - if (!readHeadOfDataObject()) - { - os::Printer::log("No opening brace in Mesh Texture Coordinates found in x file", ELL_WARNING); - return false; - } - - s32 nCoords; - u32 count; - nCoords = readInt(); - if (binary) - { - if (readBinWord() != 7) - { - os::Printer::log("Binary X: MeshTextureCoords: Expecting float list", ELL_WARNING); - return false; - } - count = readBinDWord(); - } - textureCoords.set_used(nCoords); - - for (s32 i=0; i& vertexColors) -{ -#ifdef _XREADER_DEBUG - os::Printer::log("CXFileReader: reading mesh vertex colors"); -#endif - - if (!readHeadOfDataObject()) - { - os::Printer::log("No opening brace for Mesh Vertex Colors found in x file", ELL_WARNING); - return false; - } - - s32 nColors; - u32 count; - nColors = readInt(); - if (binary) - { - if (readBinWord() != 7) - { - os::Printer::log("Binary X: MeshVertexColors: Expecting float list", ELL_WARNING); - return false; - } - count = readBinDWord(); - } - vertexColors.set_used(nColors); - - for (s32 i=0; i"; - case 5: - // GUID token - P += 16; - return ""; - case 6: - len = readBinDWord(); - P += (len * 4); - return ""; - case 7: - len = readBinDWord(); - P += (len * FloatSize); - return ""; - case 0x0a: - return "{"; - case 0x0b: - return "}"; - case 0x0c: - return "("; - case 0x0d: - return ")"; - case 0x0e: - return "["; - case 0x0f: - return "]"; - case 0x10: - return "<"; - case 0x11: - return ">"; - case 0x12: - return "."; - case 0x13: - return ","; - case 0x14: - return ";"; - case 0x1f: - return "template"; - case 0x28: - return "WORD"; - case 0x29: - return "DWORD"; - case 0x2a: - return "FLOAT"; - case 0x2b: - return "DOUBLE"; - case 0x2c: - return "CHAR"; - case 0x2d: - return "UCHAR"; - case 0x2e: - return "SWORD"; - case 0x2f: - return "SDWORD"; - case 0x30: - return "void"; - case 0x31: - return "string"; - case 0x32: - return "unicode"; - case 0x34: - return "array"; - } - } - // process text-formatted file - else - { - findNextNoneWhiteSpace(); - - if (P >= End) - return s; - - while(P < End && !core::isspace(P[0])) - { - s.append(P[0]); - ++P; - } - } - return s; -} - - -//! places pointer to next begin of a token, which must be a number, -// and ignores comments -void CXFileReader::findNextNoneWhiteSpaceNumber() -{ - if (binary) - return; - - while(true) - { - while((P < End) && (P[0] != '-') && (P[0] != '.') && - !( core::isdigit(P[0]))) - ++P; - - if (P >= End) - return; - - // check if this is a comment - if ((P[0] == '/' && P[1] == '/') || P[0] == '#') - readUntilEndOfLine(); - else - break; - } - -} - -// places pointer to next begin of a token, and ignores comments -void CXFileReader::findNextNoneWhiteSpace() -{ - if (binary) - return; - - while(true) - { - while(P < End && (P[0]==' ' || P[0]=='\n' || P[0]=='\r' || P[0]=='\t')) - ++P; - - if (P >= End) - return; - - // check if this is a comment - if ((P[0] == '/' && P[1] == '/') || - P[0] == '#') - readUntilEndOfLine(); - else - break; - } -} - - -void CXFileReader::readUntilEndOfLine() -{ - if (binary) - return; - - while(P < End) - { - if (P[0] == '\n') - { - ++P; - return; - } - - ++P; - } -} - - -//! Returns if the loaded mesh is static -bool CXFileReader::isStaticMesh() const -{ - return AnimationSets.empty(); -} - -//! returns count of animations -s32 CXFileReader::getAnimationSetCount() const -{ - return AnimationSets.size(); -} - -//! returns a specific animation set -CXFileReader::SXAnimationSet& CXFileReader::getAnimationSet(s32 i) -{ - return AnimationSets[i]; -} - -//! returns the root frame of the mesh -core::array & CXFileReader::getRootFrames() -{ - return RootFrames; -} - - -void CXFileReader::computeGlobalFrameMatrices(SXFrame& frame, const SXFrame* const parent) -{ - if (!parent) - frame.GlobalMatrix = frame.LocalMatrix; - else - frame.GlobalMatrix = parent->GlobalMatrix * frame.LocalMatrix; - -#ifdef _XREADER_DEBUG - char tmp[255]; - sprintf(tmp, "CXFileReader: Frame %s ", frame.Name.c_str()); - os::Printer::log(tmp); - for (int i=0; i<4; ++i) - { - sprintf(tmp, " %f, %f, %f, %f", - frame.LocalMatrix(i,0), - frame.LocalMatrix(i,1), - frame.LocalMatrix(i,2), - frame.LocalMatrix(i,3)); - os::Printer::log(tmp); - } -#endif - for (u32 c=0; c & getRootFrames(); - - struct SXMaterial - { - video::SColorf FaceColor; // note: RGBA - f32 Power; - video::SColorf Specular; // RGB - video::SColorf Emissive; // RGB - core::stringc TextureFileName; - }; - - struct SXMeshMaterialList - { - core::array FaceIndices; // index of material for each face - core::array Materials; // material array - }; - - struct SXTemplateMaterial - { - core::stringc Name; // template name from Xfile - SXMaterial Material; // material - }; - - struct SXIndexedColor - { - s32 Index; - video::SColorf Color; - }; - - struct SXSkinMeshHeader - { - s32 MaxSkinWeightsPerVertex; // Maximum number of transforms that affect a vertex in the mesh. - s32 MaxSkinWeightsPerFace; // Maximum number of unique transforms that affect the three vertices of any face. - s32 BoneCount; // Number of bones that affect vertices in this mesh. - }; - - struct SXWeight - { - SXWeight() {}; - SXWeight(s32 vtidx): VertexIndex(vtidx) {} - - s32 VertexIndex; - f32 Weight; - - bool operator <(const SXWeight& other) const - { - return VertexIndex < other.VertexIndex; - } - }; - - struct SXSkinWeight - { - core::stringc TransformNodeName; // name of the bone - core::array< SXWeight > Weights; - core::matrix4 MatrixOffset; // transforms the mesh vertices to the space of the bone - // When concatenated to the bone's transform, this provides the - // world space coordinates of the mesh as affected by the bone - }; - - struct SXMesh - { - // this mesh contains triangulated texture data. - // because in an .x file, faces can be made of more than 3 - // vertices, the indices data structure is triangulated during the - // loading process. The IndexCountPerFace array is filled during - // this triangulation process and stores how much indices belong to - // every face. This data structure can be ignored, because all data - // in this structure is triangulated. - - core::stringc Name; - core::array Vertices; - core::array< s32 > Indices; // triangle indices - - // optional: - - core::array TextureCoords; - core::array Normals; - core::array NormalIndices; // amount is equal to Indices amount - - core::array< s32 > IndexCountPerFace; // default 3, but could be more - core::array< SXIndexedColor > VertexColors; - core::array< SXSkinWeight > SkinWeights; - SXMeshMaterialList MaterialList; - SXSkinMeshHeader SkinMeshHeader; - }; - - struct SXFrame - { - SXFrame() : iLevel(0), pParent(0) { } - - int iLevel; - SXFrame * pParent; - core::stringc Name; - core::matrix4 LocalMatrix; - core::matrix4 GlobalMatrix; - - core::array Meshes; - core::array ChildFrames; - }; - - struct SXAnimationKey - { - SXAnimationKey() : keyType(-1), numberOfKeys(0), time(0), data(0) { } - - void del() - { - delete [] time; - - switch(keyType) - { - case -1: break; - case 0 : delete [] (core::quaternion*)data; break; - case 1 : - case 2 : delete [] (core::vector3df*)data; break; - case 3 : - case 4 : delete [] (core::matrix4*)data; break; - } - } - - void init() - { - time = new s32[numberOfKeys]; - - switch(keyType) - { - case 0 : data = new core::quaternion[numberOfKeys]; break; - case 1 : - case 2 : data = new core::vector3df[numberOfKeys]; break; - case 3 : - case 4 : data = new core::matrix4[numberOfKeys]; break; - } - - } - - core::matrix4& getMatrix(s32 nr) const - { - return ((core::matrix4*)data)[nr]; - } - - core::vector3df& getVector(s32 nr) const - { - return ((core::vector3df*)data)[nr]; - } - - core::quaternion& getQuaternion(s32 nr) const - { - return ((core::quaternion*)data)[nr]; - } - - s32 keyType; // 0=rotation, 1=scale, 2=position, 3=matrix - s32 numberOfKeys; - - s32* time; - void* data; - }; - - struct SXAnimation - { - core::stringc FrameName; - core::array Keys; - - // optional, from AnimationOptions: - bool closed; // default true - bool linearPositionQuality; // if false: spline position quality - }; - - struct SXAnimationSet - { - core::stringc AnimationName; - core::array Animations; - }; - -private: - - //! Parses the file - bool parseFile(); - - //! Reads file into memory - bool readFileIntoMemory(io::IReadFile* file); - - //! Parses the next Data object in the file - bool parseDataObject(); - - //! places pointer to next begin of a token, and ignores comments - void findNextNoneWhiteSpace(); - - //! places pointer to next begin of a token, which must be a number, - // and ignores comments - void findNextNoneWhiteSpaceNumber(); - - //! returns next parseable token. Returns empty string if no token there - core::stringc getNextToken(); - - //! reads header of dataobject including the opening brace. - //! returns false if error happened, and writes name of object - //! if there is one - bool readHeadOfDataObject(core::stringc* outname=0); - - //! checks for two following semicolons, returns false if they are not there - bool checkForTwoFollowingSemicolons(); - - //! reads a x file style string - bool getNextTokenAsString(core::stringc& out); - - inline u16 readBinWord(); - inline u32 readBinDWord(); - inline s32 readInt(); - inline f32 readFloat(); - inline bool readVector2(core::vector2df& vec); - inline bool readVector3(core::vector3df& vec); - inline bool readRGB(video::SColorf& color); - inline bool readRGBA(video::SColorf& color); - - bool parseDataObjectTemplate(); - bool parseDataObjectFrame(SXFrame &frame); - bool parseDataObjectTransformationMatrix(core::matrix4 &mat); - bool parseDataObjectMesh(SXMesh &mesh); - bool parseDataObjectMeshNormals(core::array& normals, - core::array< s32 >& normalIndices, s32 triangulatedIndexCount, - core::array< s32 >& indexCountPerFace); - bool parseDataObjectMeshTextureCoords(core::array& textureCoords); - bool parseDataObjectMeshVertexColors(core::array& vertexColors); - bool parseDataObjectMeshMaterialList(SXMeshMaterialList& materiallist, - s32 triangulatedIndexCount, core::array< s32 >& indexCountPerFace); - bool parseDataObjectMaterial(SXMaterial& material); - bool parseDataObjectTextureFilename(core::stringc& texturename); - bool parseDataObjectSkinMeshHeader(SXSkinMeshHeader& header); - bool parseDataObjectSkinWeights(SXSkinWeight& weights); - bool parseDataObjectAnimationSet(SXAnimationSet& set); - bool parseDataObjectAnimation(SXAnimation& anim); - bool parseDataObjectAnimationKey(SXAnimationKey& animkey); - bool parseUnknownDataObject(); - - void readUntilEndOfLine(); - - void computeGlobalFrameMatrices(SXFrame& frame, const SXFrame* const parent); - void optimizeFrames( SXFrame * pgFrame, SXFrame * pgParent ); - bool validateMesh(SXFrame* frame); - - s32 MajorVersion; - s32 MinorVersion; - bool binary; - s32 binaryNumCount; - - c8* Buffer; - s32 Size; - c8 FloatSize; - const c8* P; - c8* End; - - bool ErrorHappened; - - bool m_bFrameRemoved; - SXFrame * m_pgCurFrame; - core::arrayRootFrames; - core::array AnimationSets; - core::array TemplateMaterials; -}; - -} // end namespace scene -} // end namespace irr - -#endif - diff --git a/source/Irrlicht/CXMeshFileLoader.cpp b/source/Irrlicht/CXMeshFileLoader.cpp index 7b26310c..571d2c2d 100644 --- a/source/Irrlicht/CXMeshFileLoader.cpp +++ b/source/Irrlicht/CXMeshFileLoader.cpp @@ -2,13 +2,15 @@ // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_X_LOADER_ + #include "CXMeshFileLoader.h" #include "os.h" -#include "SMeshBuffer.h" -#include "SAnimatedMesh.h" -#include "CXFileReader.h" -#include "CXAnimationPlayer.h" -#include "IMeshManipulator.h" + +#include "fast_atof.h" +#include "coreutil.h" namespace irr { @@ -16,66 +18,2259 @@ namespace scene { //! Constructor -CXMeshFileLoader::CXMeshFileLoader(IMeshManipulator* manip, - video::IVideoDriver* driver) -: Manipulator(manip), Driver(driver) +CXMeshFileLoader::CXMeshFileLoader(scene::ISceneManager* smgr) +: SceneManager(smgr), Buffers(0), AllJoints(0), AnimatedMesh(0), file(0), + MajorVersion(0), MinorVersion(0), binary(false), binaryNumCount(0), + Buffer(0), Size(0), FloatSize(0), P(0), End(0), ErrorHappened(false), + CurFrame(0) { - if (Manipulator) - Manipulator->grab(); - - if (Driver) - Driver->grab(); } - //! destructor CXMeshFileLoader::~CXMeshFileLoader() { - if (Manipulator) - Manipulator->drop(); - - if (Driver) - Driver->drop(); + TemplateMaterials.clear(); } - //! returns true if the file maybe is able to be loaded by this class //! based on the file extension (e.g. ".bsp") bool CXMeshFileLoader::isALoadableFileExtension(const c8* filename) { - return strstr(filename, ".x")!=0; + return strstr(filename, ".x") != 0; } - //! creates/loads an animated mesh from the file. //! \return Pointer to the created mesh. Returns 0 if loading failed. //! If you no longer need the mesh, you should call IAnimatedMesh::drop(). //! See IUnknown::drop() for more information. -IAnimatedMesh* CXMeshFileLoader::createMesh(io::IReadFile* file) +IAnimatedMesh* CXMeshFileLoader::createMesh(irr::io::IReadFile* f) { - if (!file) + if (!f) return 0; - IAnimatedMesh* mesh = 0; - CXFileReader *xreader = new CXFileReader(file); + file = f; + AnimatedMesh = new CSkinnedMesh(); - if (xreader->errorHappened()) + Buffers = &AnimatedMesh->getMeshBuffers(); + AllJoints = &AnimatedMesh->getAllJoints(); + + if ( load() ) { - xreader->drop(); - return 0; + AnimatedMesh->finalize(); + } + else + { + AnimatedMesh->drop(); + AnimatedMesh = 0; } - mesh = new CXAnimationPlayer(xreader, Driver, Manipulator, - file->getFileName()); + //Clear up - xreader->drop(); - return mesh; + file=0; + MajorVersion=0; + MinorVersion=0; + binary=0; + binaryNumCount=0; + Buffer=0; + Size=0; + FloatSize=0; + P=0; + End=0; + ErrorHappened=0; + CurFrame=0; + TemplateMaterials.clear(); + + Meshes.clear(); + + return AnimatedMesh; +} + + +bool CXMeshFileLoader::load() +{ + if (!readFileIntoMemory()) + return false; + + if (!parseFile()) + return false; + + for (u32 n=0;nMaterials.size()) Mesh->Materials.push_back(video::SMaterial()); + + u32 i; + + for (i=0;iMaterials.size();++i) + { + Mesh->Buffers.push_back( AnimatedMesh->createBuffer() ); + Mesh->Buffers.getLast()->Material=Mesh->Materials[i]; + } + + + #ifdef BETTER_MESHBUFFER_SPLITTING_FOR_X + + //the same vertex can be used in many different meshbuffers, but it's slow to work out + + core::array< core::array< u32 > > VerticesLink; + core::array< core::array< u32 > > VerticesLinkBuffer; + + for (i=0;iVertices.size();++i) + { + VerticesLinkBuffer.push_back( core::array< u32 >() ); + VerticesLink.push_back( core::array< u32 >() ); + } + + for (i=0;iFaceIndices.size();++i) + { + for (u32 id=i*3+0;id<=i*3+2;++id) + { + core::array< u32 > &Array=VerticesLinkBuffer[ Mesh->Indices[id] ]; + bool found=false; + + for (u32 j=0;j< Array.size() ;++j) + if (Array[j]==Mesh->FaceIndices[i]) found=true; + + if (!found) + Array.push_back( Mesh->FaceIndices[i] ); + } + } + + + for (i=0;iVertices.size();++i) + { + core::array< u32 > &Array=VerticesLinkBuffer[i]; + for (u32 j=0;j < Array.size(); ++j) + { + scene::SSkinMeshBuffer *Buffer=Mesh->Buffers[ Array[j] ]; + VerticesLink[i].push_back( Buffer->Vertices_Standard.size() ); + Buffer->Vertices_Standard.push_back( Mesh->Vertices[i] ); + } + } + + for (i=0;iFaceIndices.size();++i) + { + scene::SSkinMeshBuffer *Buffer=Mesh->Buffers[ Mesh->FaceIndices[i] ]; + + for (u32 id=i*3+0;id<=i*3+2;++id) + { + core::array< u32 > &Array=VerticesLinkBuffer[ Mesh->Indices[id] ]; + + for (u32 j=0;j< Array.size() ;++j) + { + if ( Array[j]== Mesh->FaceIndices[i] ) + Buffer->Indices.push_back( VerticesLink[ Mesh->Indices[id] ][j] ); + } + } + } + + for (i=0;igetAllJoints().size();++i) + { + + ISkinnedMesh::SJoint *Joint=AnimatedMesh->getAllJoints()[i]; + + for (u32 j=0;jWeights.size();++j) + { + u32 id; + + ISkinnedMesh::SWeight *Weight=&Joint->Weights[j]; + id=Weight->vertex_id; + + if (VerticesLinkBuffer[id].size()==1) + { + Weight->vertex_id=VerticesLink[id][0]; + Weight->buffer_id=VerticesLinkBuffer[id][0]; + } + + if (VerticesLinkBuffer[id].size()>1) + { + for (u32 k=1;k< VerticesLinkBuffer[id].size() ;++k) + { + ISkinnedMesh::SWeight *WeightClone=AnimatedMesh->createWeight(Joint); + WeightClone->strength=Weight->strength; + WeightClone->vertex_id=VerticesLink[id][k]; + WeightClone->buffer_id=VerticesLinkBuffer[id][k]; + } + } + + } + + } + #else + + core::array< u32 > VerticesLink; + core::array< u32 > VerticesLinkBuffer; + + VerticesLinkBuffer.set_used(Mesh->Vertices.size()); + VerticesLink.set_used(Mesh->Vertices.size()); + + for (i=0;iVertices.size();++i) + { + VerticesLinkBuffer[i]=0; + VerticesLink[i]=0; + } + + for (i=0;iFaceIndices.size();++i) + { + for (u32 id=i*3+0;id<=i*3+2;++id) + { + VerticesLinkBuffer[ Mesh->Indices[id] ] = Mesh->FaceIndices[i]; + } + } + + + for (i=0;iVertices.size();++i) + { + + scene::SSkinMeshBuffer *Buffer=Mesh->Buffers[ VerticesLinkBuffer[i] ]; + + VerticesLink[i] = Buffer->Vertices_Standard.size(); + Buffer->Vertices_Standard.push_back( Mesh->Vertices[i] ); + + } + + for (i=0;iFaceIndices.size();++i) + { + scene::SSkinMeshBuffer *Buffer=Mesh->Buffers[ Mesh->FaceIndices[i] ]; + + for (u32 id=i*3+0;id<=i*3+2;++id) + { + Buffer->Indices.push_back( VerticesLink[ Mesh->Indices[id] ] ); + } + } + + for (i=0;igetAllJoints().size();++i) + { + + ISkinnedMesh::SJoint *Joint=AnimatedMesh->getAllJoints()[i]; + + for (u32 j=0;jWeights.size();++j) + { + u32 id; + + ISkinnedMesh::SWeight *Weight=&Joint->Weights[j]; + + id=Weight->vertex_id; + + Weight->vertex_id=VerticesLink[id]; + Weight->buffer_id=VerticesLinkBuffer[id]; + } + } + #endif + } + + return true; +} + + + +//! Reads file into memory +bool CXMeshFileLoader::readFileIntoMemory() +{ + s32 Size = file->getSize(); + if (Size < 12) + { + os::Printer::log("X File is too small.", ELL_WARNING); + return false; + } + + Buffer = new c8[Size]; + + //! read all into memory + file->seek(0); // apparently sometimes files have been read already, so reset it + if (file->read(Buffer, Size) != Size) + { + os::Printer::log("Could not read from x file.", ELL_WARNING); + return false; + } + + End = Buffer + Size; + + //! check header "xof " + if (strncmp(Buffer, "xof ", 4)!=0) + { + os::Printer::log("Not an x file, wrong header.", ELL_WARNING); + return false; + } + + //! read minor and major version, e.g. 0302 or 0303 + c8 tmp[3]; + tmp[2] = 0x0; + tmp[0] = Buffer[4]; + tmp[1] = Buffer[5]; + MajorVersion = strtol(tmp, (char**) &P, 10); + + tmp[0] = Buffer[6]; + tmp[1] = Buffer[7]; + MinorVersion = strtol(tmp, (char**) &P, 10); + + //! read format + if (strncmp(&Buffer[8], "txt ", 4) ==0) + binary = false; + else if (strncmp(&Buffer[8], "bin ", 4) ==0) + binary = true; + else + { + os::Printer::log("Only uncompressed x files currently supported.", ELL_WARNING); + return false; + } + binaryNumCount=0; + + //! read float size + if (strncmp(&Buffer[12], "0032", 4) ==0) + FloatSize = 4; + else if (strncmp(&Buffer[12], "0064", 4) ==0) + FloatSize = 8; + else + { + os::Printer::log("Float size not supported.", ELL_WARNING); + return false; + } + + P = &Buffer[16]; + + readUntilEndOfLine(); + + return true; +} + + +//! Parses the file +bool CXMeshFileLoader::parseFile() +{ + while(parseDataObject()) + { + // loop + } + + return true; +} + + +//! Parses the next Data object in the file +bool CXMeshFileLoader::parseDataObject() +{ + core::stringc objectName = getNextToken(); + + if (objectName.size() == 0) + return false; + + // parse specific object + + os::Printer::log("debug DataObject:", objectName.c_str() ); + + if (objectName == "template") + return parseDataObjectTemplate(); + else + if (objectName == "Frame") + { + + return parseDataObjectFrame( 0 ); + } + else + if (objectName == "Mesh") + { + // some meshes have no frames at all + //CurFrame = AnimatedMesh->createJoint(0); + + //CurFrame->Meshes.push_back(SXMesh()); + //return parseDataObjectMesh(CurFrame->Meshes.getLast()); + + SXMesh *Mesh=new SXMesh; + + //Mesh->Buffer=AnimatedMesh->createBuffer(); + Meshes.push_back(Mesh); + + + return parseDataObjectMesh ( *Mesh ); + } + else + if (objectName == "AnimationSet") + { + return parseDataObjectAnimationSet(); + } + else + if (objectName == "Material") + { + // template materials now available thanks to joeWright + TemplateMaterials.push_back(SXTemplateMaterial()); + TemplateMaterials.getLast().Name = getNextToken(); + return parseDataObjectMaterial(TemplateMaterials.getLast().Material); + } + else + if (objectName == "}") + { + os::Printer::log("} found in dataObject"); + return true; + } + + os::Printer::log("Unknown data object in x file", objectName.c_str()); + + return parseUnknownDataObject(); +} + + +bool CXMeshFileLoader::parseDataObjectTemplate() +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: Reading template"); +#endif + + // parse a template data object. Currently not stored. + core::stringc name = getNextToken(); + + // ignore left delimiter + if (getNextToken() != "{") + { + os::Printer::log("Left delimiter in template data object missing.", + name.c_str(), ELL_ERROR); + return false; + } + + // read GUID + core::stringc guid = getNextToken(); + + // read and ignore data members + while(true) + { + core::stringc s = getNextToken(); + + if (s == "}") + break; + + if (s.size() == 0) + return false; + } + + return true; +} + + + +bool CXMeshFileLoader::parseDataObjectFrame( CSkinnedMesh::SJoint *Parent ) +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: Reading frame"); +#endif + + // A coordinate frame, or "frame of reference." The Frame template + // is open and can contain any object. The Direct3D extensions (D3DX) + // mesh-loading functions recognize Mesh, FrameTransformMatrix, and + // Frame template instances as child objects when loading a Frame + // instance. + + core::stringc Name; + + if (!readHeadOfDataObject(&Name)) + { + os::Printer::log("No opening brace in Frame found in x file", ELL_WARNING); + return false; + } + + CSkinnedMesh::SJoint *joint=0; + + if (Name!="") + { + for (u32 n=0;n < AnimatedMesh->getAllJoints().size();++n) + { + if (AnimatedMesh->getAllJoints()[n]->Name==Name) + joint=AnimatedMesh->getAllJoints()[n]; + } + } + + if (!joint) + { + os::Printer::log("creating joint ", Name.c_str()); + joint=AnimatedMesh->createJoint(Parent); + joint->Name=Name; + } + else + { + os::Printer::log("using joint ", Name.c_str()); + if (Parent) + Parent->Children.push_back(joint); + } + + // Now inside a frame. + // read tokens until closing brace is reached. + + while(true) + { + core::stringc objectName = getNextToken(); + + os::Printer::log("debug DataObject in frame:", objectName.c_str() ); + + if (objectName.size() == 0) + { + os::Printer::log("Unexpected ending found in Frame in x file.", ELL_WARNING); + return false; + } + else + if (objectName == "}") + { + break; // frame finished + } + else + if (objectName == "Frame") + { + + if (!parseDataObjectFrame(joint)) + return false; + } + else + if (objectName == "FrameTransformMatrix") + { + //if (!parseDataObjectTransformationMatrix(joint->LocalMatrix)) + + if (!parseDataObjectTransformationMatrix(joint->LocalMatrix)) + return false; + + //joint->LocalAnimatedMatrix + + + //joint->LocalAnimatedMatrix.makeInverse(); + + //joint->LocalMatrix=tmp*joint->LocalAnimatedMatrix; + + + } + else + if (objectName == "Mesh") + { + /* + frame.Meshes.push_back(SXMesh()); + if (!parseDataObjectMesh(frame.Meshes.getLast())) + return false; + */ + SXMesh *Mesh=new SXMesh; + + Meshes.push_back(Mesh); + + return parseDataObjectMesh ( *Mesh ); + } + else + { + os::Printer::log("Unknown data object in frame in x file", objectName.c_str()); + if (!parseUnknownDataObject()) + return false; + } + + } + + return true; +} + + +bool CXMeshFileLoader::parseDataObjectTransformationMatrix(core::matrix4 &mat) +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: Reading Transformation Matrix"); +#endif + + if (!readHeadOfDataObject()) + { + os::Printer::log("No opening brace in Transformation Matrix found in x file", ELL_WARNING); + return false; + } + + if (binary) + { + // read matrix in binary format + if (readBinWord() != 7) + { + os::Printer::log("Binary X: Mesh: Expecting float list (for matrix)", ELL_WARNING); + return false; + } + + if (readBinDWord() != 0x10) + { + os::Printer::log("Binary X: Mesh: Should be 16 floats in matrix", ELL_WARNING); + return false; + } + } + + for (s32 i=0; i<4; ++i) + for (s32 j=0; j<4; ++j) + mat(i,j)=readFloat(); + + if (!checkForTwoFollowingSemicolons()) + { + os::Printer::log("No finishing semicolon in Transformation Matrix found in x file", ELL_WARNING); + return false; + } + + if (getNextToken() != "}") + { + os::Printer::log("No closing brace in Transformation Matrix found in x file", ELL_WARNING); + return false; + } + + return true; +} + + + +bool CXMeshFileLoader::parseDataObjectMesh(SXMesh &mesh) +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: Reading mesh"); +#endif + + core::stringc name; + + if (!readHeadOfDataObject(&name)) + { + os::Printer::log("No opening brace in Mesh found in x file", ELL_WARNING); + return false; + } + + // read vertex count + s32 nVertices = readInt(); + + + // read vertices + mesh.Vertices.set_used(nVertices); //luke: change + for (s32 nums=0; nums polygonfaces; + s32 currentIndex = 0; + + for (s32 k=0; kgetAllJoints().size();++n) + { + if (AnimatedMesh->getAllJoints()[n]->Name==TransformNodeName) + joint=AnimatedMesh->getAllJoints()[n]; + } + + if (!joint) + { + //os::Printer::log("no joints with correct name for weights,", TransformNodeName.c_str()); + //return false; + + os::Printer::log("pre-creating joint for skinning ", TransformNodeName.c_str()); + joint=AnimatedMesh->createJoint(0); + joint->Name=TransformNodeName; + } + + + core::array Weights_Index; + core::array Weights_Strength; + + // read vertex weights + s32 nWeights = readInt(); + + Weights_Index.set_used(nWeights); + Weights_Strength.set_used(nWeights); + + // read vertex indices + + s32 i; + + for (i=0; iGlobalInversedMatrix=MatrixOffset; + + for (i=0; icreateWeight(joint); + + weight->buffer_id=0; + weight->vertex_id=Weights_Index[i]; + weight->strength=Weights_Strength[i]; + } + + if (!checkForTwoFollowingSemicolons()) + { + os::Printer::log("No finishing semicolon in Skin Weights found in x file", ELL_WARNING); + return false; + } + + if (getNextToken() != "}") + { + os::Printer::log("No closing brace in Skin Weights found in x file", ELL_WARNING); + return false; + } + + return true; +} + + +bool CXMeshFileLoader::parseDataObjectSkinMeshHeader() +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: Reading skin mesh header"); +#endif + + if (!readHeadOfDataObject()) + { + os::Printer::log("No opening brace in Skin Mesh header found in x file", ELL_WARNING); + return false; + } + + readInt(); //MaxSkinWeightsPerVertex + readInt(); //MaxSkinWeightsPerFace + readInt(); //BoneCount + if (!binary) + getNextToken(); // skip semicolon + core::stringc objectName = getNextToken(); + + if (objectName != "}") + { + os::Printer::log("No closing brace in skin mesh header in x file", objectName.c_str()); + return false; + } + + return true; +} + + +bool CXMeshFileLoader::parseDataObjectMeshNormals(SXMesh &mesh) +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: reading mesh normals"); +#endif + + if (!readHeadOfDataObject()) + { + os::Printer::log("No opening brace in Mesh Normals found in x file", ELL_WARNING); + return false; + } + + // read count + s32 nNormals; + s32 count; + nNormals = readInt(); + //normals.set_used(nNormals); + + // read normals + if (binary) + { + if (readBinWord() != 7) + { + os::Printer::log("Binary X: MeshNormals: Expecting float list", ELL_WARNING); + return false; + } + count = readBinDWord(); + if (count != nNormals * 3) + { + os::Printer::log("Binary X: MeshNormals: Value count not equal to normal count", ELL_WARNING); + return false; + } + } + for (s32 i=0; i normalIndices; + + s32 triangulatedIndexCount=mesh.Indices.size(); + + // read face normal indices + s32 nFNormals = readInt(); + + normalIndices.set_used(triangulatedIndexCount); + + + s32 normalidx = 0; + core::array polygonfaces; + for (s32 k=0; k=mesh.Vertices.size() ) + { + os::Printer::log("index value in parseDataObjectMeshVertexColors out of bounds", ELL_WARNING); + return false; + } + readRGBA(mesh.Vertices[i].Color); + } + + core::stringc tmp=getNextToken(); + if (tmp != ";") + { + os::Printer::log("is (;)[", tmp.c_str()); + os::Printer::log("No finishing semicolon in Mesh Vertex Colors Array found in x file", ELL_WARNING); + return false; + } + + if (getNextToken() != "}") + { + os::Printer::log("No closing brace in Mesh Texture Coordinates Array found in x file", ELL_WARNING); + return false; + } + + return true; +} + + + +bool CXMeshFileLoader::parseDataObjectMeshMaterialList(SXMesh &mesh) +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: Reading mesh material list"); +#endif + + if (!readHeadOfDataObject()) + { + os::Printer::log("No opening brace in Mesh Material List found in x file", ELL_WARNING); + return false; + } + + // read material count + readInt(); + + // read non triangulated face material index count + s32 nFaceIndices = readInt(); + + // read non triangulated face indices + + core::array nonTriFaceIndices; + nonTriFaceIndices.set_used(nFaceIndices); + + for (s32 i=0; igetFileName(),true) + stripPathFromString(TextureFileName,false); + + material.Textures[0]=SceneManager->getVideoDriver()->getTexture ( TextureFileName.c_str() ); + } + else + { + os::Printer::log("Unknown data object in material in x file", objectName.c_str()); + if (!parseUnknownDataObject()) + return false; + } + + } + + return true; +} + + +bool CXMeshFileLoader::parseDataObjectAnimationSet() +{ + #ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: Reading animation set"); + #endif + + os::Printer::log("parseDataObjectAnimationSet()", ELL_WARNING); + + core::stringc AnimationName; + + if (!readHeadOfDataObject(&AnimationName)) + { + os::Printer::log("No opening brace in Animation Set found in x file", ELL_WARNING); + return false; + } + + while(true) + { + core::stringc objectName = getNextToken(); + + if (objectName.size() == 0) + { + os::Printer::log("Unexpected ending found in Animation set in x file.", ELL_WARNING); + return false; + } + else + if (objectName == "}") + { + break; // animation set finished + } + else + if (objectName == "Animation") + { + if (!parseDataObjectAnimation()) + return false; + } + else + { + os::Printer::log("Unknown data object in animation set in x file", objectName.c_str()); + if (!parseUnknownDataObject()) + return false; + } + } + return true; +} + + +bool CXMeshFileLoader::parseDataObjectAnimation() +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: reading animation"); +#endif + + if (!readHeadOfDataObject()) + { + os::Printer::log("No opening brace in Animation found in x file", ELL_WARNING); + return false; + } + + //anim.closed = true; + //anim.linearPositionQuality = true; + CSkinnedMesh::SJoint *joint=0; + + CSkinnedMesh::SJoint animationDump; + + core::stringc FrameName=""; + + while(true) + { + core::stringc objectName = getNextToken(); + + + if (objectName.size() == 0) + { + os::Printer::log("Unexpected ending found in Animation in x file.", ELL_WARNING); + return false; + } + else + if (objectName == "}") + { + break; // animation finished + } + else + if (objectName == "AnimationKey") + { + if (!joint) + { + os::Printer::log("no joint to write animation to, dumping in temp joint"); + + if (!parseDataObjectAnimationKey(&animationDump)) + return false; + } + else + { + if (!parseDataObjectAnimationKey(joint)) + return false; + } + } + else + if (objectName == "AnimationOptions") + { + //TODO: parse options. + if (!parseUnknownDataObject()) + return false; + } + else + if (objectName == "{") + { + // read frame name + + FrameName = getNextToken(); + + core::stringc end = getNextToken(); + if (end.size() == 0 || end != "}") + { + os::Printer::log("Unexpected ending found in Animation in x file.", ELL_WARNING); + return false; + } + } + else + { + if (objectName.size()>2 && objectName[0] == '{' && + objectName[objectName.size()-1] == '}') + { + FrameName = objectName.subString(1,objectName.size()-2); + } + else + { + os::Printer::log("Unknown data object in animation in x file", objectName.c_str()); + if (!parseUnknownDataObject()) + return false; + } + } + + if (FrameName!="" && !joint) + { + os::Printer::log("getting name: ", FrameName.c_str()); + + for (u32 n=0;n < AnimatedMesh->getAllJoints().size();++n) + { + if (AnimatedMesh->getAllJoints()[n]->Name==FrameName) + joint=AnimatedMesh->getAllJoints()[n]; + } + if (!joint) + { + //os::Printer::log("no joints with correct name for animation,", FrameName.c_str()); + //return false; + + os::Printer::log("pre-creating joint for animation ", FrameName.c_str()); + joint=AnimatedMesh->createJoint(0); + joint->Name=FrameName; + } + + u32 n; + + for (n=0;nposition+=joint->LocalMatrix.getTranslation(); + + joint->PositionKeys.push_back(*key); + } + + for (n=0;nscale*=joint->LocalMatrix.getScale(); + + joint->ScaleKeys.push_back(*key); + } + + for (n=0;nrotation.X, key->rotation.Y, key->rotation.Z) ); + + tmpMatrix=joint->LocalMatrix*tmpMatrix; + + //key->rotation = core::quaternion(tmpMatrix); + + joint->RotationKeys.push_back(*key); + } + } + } + + if (FrameName=="") + os::Printer::log("joint name was never given"); + + return true; +} + + +bool CXMeshFileLoader::parseDataObjectAnimationKey(ISkinnedMesh::SJoint *joint) +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: reading animation key"); +#endif + + if (!readHeadOfDataObject()) + { + os::Printer::log("No opening brace in Animation Key found in x file", ELL_WARNING); + return false; + } + + // read key type + + s32 keyType = readInt(); + + if ((keyType < 0) || (keyType > 4)) + { + os::Printer::log("Unknown key type found in Animation Key in x file", ELL_WARNING); + return false; + } + + // read number of keys + s32 numberOfKeys = readInt(); + + // eat the semicolon after the "0". if there are keys present, readInt() + // does this for us. If there aren't, we need to do it explicitly + if (!binary && numberOfKeys == 0) + getNextToken(); // skip semicolon + + + for (s32 i=0; icreateRotationKey(joint); + key->frame=(f32)time; + key->rotation.set(X,Y,Z,W); + } + break; + case 1: //scale + case 2: //position + { + // read vectors + + // read time + s32 time = readInt(); + + // read count + if (readInt() != 3) + { + os::Printer::log("Expected 3 numbers in animation key in x file", ELL_WARNING); + return false; + } + + if (binary) + { + if (readBinWord() != 7) + { + os::Printer::log("Binary X: Animation Key: Expecting float list", ELL_WARNING); + return false; + } + + if (readBinDWord() != 3) + { + os::Printer::log("Binary X: Animation Key : Value count not correct", ELL_WARNING); + return false; + } + } + + core::vector3df vector; + readVector3(vector); + + if (!checkForTwoFollowingSemicolons()) + { + os::Printer::log("No finishing semicolon after vector animation key in x file", ELL_WARNING); + return false; + } + + if (keyType==2) + { + ISkinnedMesh::SPositionKey *key=AnimatedMesh->createPositionKey(joint); + key->frame=(f32)time; + key->position=vector; + } + else + { + ISkinnedMesh::SScaleKey *key=AnimatedMesh->createScaleKey(joint); + key->frame=(f32)time; + key->scale=vector; + } + } + break; + case 3: + case 4: + { + // read matrix + + // read time + s32 time = readInt(); + + // read count + if (readInt() != 16) + { + os::Printer::log("Expected 16 numbers in animation key in x file", ELL_WARNING); + return false; + } + + // read matrix + if (binary) + { + if (readBinWord() != 7) + { + os::Printer::log("Binary X: Animation Key: Expecting float list", ELL_WARNING); + return false; + } + + if (readBinDWord() != 16) + { + os::Printer::log("Binary X: Animation Key : Value count not correct", ELL_WARNING); + return false; + } + } + + core::matrix4 Matrix; + + for (s32 m=0; m<4; ++m) + for (s32 n=0; n<4; ++n) + Matrix(m,n) = readFloat(); + + + //Matrix=joint->LocalMatrix*Matrix; + + if (!checkForTwoFollowingSemicolons()) + { + os::Printer::log("No finishing semicolon after matrix animation key in x file", ELL_WARNING); + return false; + } + + //core::vector3df rotation = Matrix.getRotationDegrees(); + + ISkinnedMesh::SRotationKey *keyR=AnimatedMesh->createRotationKey(joint); + keyR->frame=(f32)time; + //keyR->rotation.set(rotation.X*core::DEGTORAD,rotation.Y*core::DEGTORAD,rotation.Z*core::DEGTORAD); + keyR->rotation= core::quaternion(Matrix); + + + ISkinnedMesh::SPositionKey *keyP=AnimatedMesh->createPositionKey(joint); + keyP->frame=(f32)time; + keyP->position=Matrix.getTranslation(); + + core::vector3df scale=Matrix.getScale(); + + //if (scale.X==0) scale.X=1; + //if (scale.Y==0) scale.Y=1; + //if (scale.Z==0) scale.Z=1; +/* + ISkinnedMesh::SScaleKey *keyS=AnimatedMesh->createScaleKey(joint); + keyS->frame=(f32)time; + keyS->scale=scale; +*/ + + //os::Printer::log("x ", core::stringc(Matrix.getScale().X).c_str()); + //os::Printer::log("y ", core::stringc(Matrix.getScale().Y).c_str()); + //os::Printer::log("z ", core::stringc(Matrix.getScale().Z).c_str()); + + } + break; + } // end switch + } + + if (!binary) + getNextToken(); // skip another semicolon + core::stringc objectName = getNextToken(); + + if (objectName != "}") + { + os::Printer::log("No closing brace in animation key in x file", objectName.c_str()); + return false; + } + + return true; +} + + +bool CXMeshFileLoader::parseDataObjectTextureFilename(core::stringc& texturename) +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: reading texture filename"); +#endif + + if (!readHeadOfDataObject()) + { + os::Printer::log("No opening brace in Texture filename found in x file", ELL_WARNING); + return false; + } + + if (!getNextTokenAsString(texturename)) + { + os::Printer::log("Unknown syntax while reading texture filename string in x file", ELL_WARNING); + return false; + } + + if (getNextToken() != "}") + { + os::Printer::log("No closing brace in Texture filename found in x file", ELL_WARNING); + return false; + } + + return true; +} + + +bool CXMeshFileLoader::parseUnknownDataObject() +{ + // find opening delimiter + while(true) + { + core::stringc t = getNextToken(); + + if (t.size() == 0) + return false; + + if (t == "{") + break; + } + + s32 counter = 1; + + // parse until closing delimiter + + while(counter) + { + core::stringc t = getNextToken(); + + if (t.size() == 0) + return false; + + if (t == "{") + ++counter; + else + if (t == "}") + --counter; + } + + return true; +} + + +//! checks for two following semicolons, returns false if they are not there +bool CXMeshFileLoader::checkForOneFollowingSemicolons() +{ + if (binary) + return true; + + findNextNoneWhiteSpace(); + if (P[0] != ';') + return false; + ++P; + + return true; +} + + +//! checks for two following semicolons, returns false if they are not there +bool CXMeshFileLoader::checkForTwoFollowingSemicolons() +{ + if (binary) + return true; + + for (s32 k=0; k<2; ++k) + { + findNextNoneWhiteSpace(); + if (P[0] != ';') + return false; + ++P; + } + + return true; +} + + +//! reads header of dataobject including the opening brace. +//! returns false if error happened, and writes name of object +//! if there is one +bool CXMeshFileLoader::readHeadOfDataObject(core::stringc* outname) +{ + core::stringc nameOrBrace = getNextToken(); + if (nameOrBrace != "{") + { + if (outname) + (*outname) = nameOrBrace; + + if (nameOrBrace.size() != 0 && + nameOrBrace[nameOrBrace.size()-1] == '{') + { + (*outname) = nameOrBrace.subString(0, nameOrBrace.size()-1); + return true; + } + + if (getNextToken() != "{") + return false; + } + + return true; +} + + +//! returns next parseable token. Returns empty string if no token there +core::stringc CXMeshFileLoader::getNextToken() +{ + core::stringc s; + + // process binary-formatted file + if (binary) + { + // in binary mode it will only return NAME and STRING token + // and (correctly) skip over other tokens. + + s16 tok = readBinWord(); + s32 len; + + // standalone tokens + switch (tok) { + case 1: + // name token + len = readBinDWord(); + s = core::stringc(P, len); + P += len; + return s; + case 2: + // string token + len = readBinDWord(); + s = core::stringc(P, len); + P += (len + 2); + return s; + case 3: + // integer token + P += 4; + return ""; + case 5: + // GUID token + P += 16; + return ""; + case 6: + len = readBinDWord(); + P += (len * 4); + return ""; + case 7: + len = readBinDWord(); + P += (len * FloatSize); + return ""; + case 0x0a: + return "{"; + case 0x0b: + return "}"; + case 0x0c: + return "("; + case 0x0d: + return ")"; + case 0x0e: + return "["; + case 0x0f: + return "]"; + case 0x10: + return "<"; + case 0x11: + return ">"; + case 0x12: + return "."; + case 0x13: + return ","; + case 0x14: + return ";"; + case 0x1f: + return "template"; + case 0x28: + return "WORD"; + case 0x29: + return "DWORD"; + case 0x2a: + return "FLOAT"; + case 0x2b: + return "DOUBLE"; + case 0x2c: + return "CHAR"; + case 0x2d: + return "UCHAR"; + case 0x2e: + return "SWORD"; + case 0x2f: + return "SDWORD"; + case 0x30: + return "void"; + case 0x31: + return "string"; + case 0x32: + return "unicode"; + case 0x34: + return "array"; + } + } + // process text-formatted file + else + { + findNextNoneWhiteSpace(); + + if (P >= End) + return s; + + + char last=0; + + //&& last!=';' && last!='}' && last!='{' && last!=',' + + while(P < End && !core::isspace(P[0]) ) //Luke:Not only space? + { + last=P[0]; + + s.append(P[0]); + ++P; + } + + //os::Printer::log("end" ); + + } + return s; +} + + +//! places pointer to next begin of a token, which must be a number, +// and ignores comments +void CXMeshFileLoader::findNextNoneWhiteSpaceNumber() +{ + if (binary) + return; + + while(true) + { + while((P < End) && (P[0] != '-') && (P[0] != '.') && + !( core::isdigit(P[0]))) + ++P; + + if (P >= End) + return; + + // check if this is a comment + if ((P[0] == '/' && P[1] == '/') || P[0] == '#') + readUntilEndOfLine(); + else + break; + } + +} + +// places pointer to next begin of a token, and ignores comments +void CXMeshFileLoader::findNextNoneWhiteSpace() +{ + if (binary) + return; + + while(true) + { + while(P < End && (P[0]==' ' || P[0]=='\n' || P[0]=='\r' || P[0]=='\t')) + ++P; + + if (P >= End) + return; + + // check if this is a comment + if ((P[0] == '/' && P[1] == '/') || + P[0] == '#') + readUntilEndOfLine(); + else + break; + } +} + + +//! reads a x file style string +bool CXMeshFileLoader::getNextTokenAsString(core::stringc& out) +{ + if (binary) + { + out=getNextToken(); + return true; + } + findNextNoneWhiteSpace(); + + if (P >= End) + return false; + + if (P[0] != '"') + return false; + ++P; + + while(P < End && P[0]!='"') + { + out.append(P[0]); + ++P; + } + + if ( P[1] != ';' || P[0] != '"') + return false; + P+=2; + + return true; +} + + +void CXMeshFileLoader::readUntilEndOfLine() +{ + if (binary) + return; + + while(P < End) + { + if (P[0] == '\n') + { + ++P; + return; + } + + ++P; + } +} + + +u16 CXMeshFileLoader::readBinWord() +{ + u8 *Q = (u8 *)P; + u16 tmp = 0; + tmp = Q[0] + (Q[1] << 8); + P += 2; + return tmp; +} + + +u32 CXMeshFileLoader::readBinDWord() +{ + u8 *Q = (u8 *)P; + u32 tmp = 0; + tmp = Q[0] + (Q[1] << 8) + (Q[2] << 16) + (Q[3] << 24); + P += 4; + return tmp; +} + + +s32 CXMeshFileLoader::readInt() +{ + if (binary) + { + if (!binaryNumCount) + { + readBinWord(); // 0x06 + binaryNumCount=readBinDWord(); // 0x0001 + } + --binaryNumCount; + return readBinDWord(); + } + else + { + f32 ftmp; + findNextNoneWhiteSpaceNumber(); + P = core::fast_atof_move(P, ftmp); + return (s32)ftmp; + } +} + + +f32 CXMeshFileLoader::readFloat() +{ + if (binary) + { + if (FloatSize == 8) + { + char tmp[8]; + memcpy(tmp, P, 8); + P += 8; + return (f32)(*(f64 *)tmp); + } + else + { + char tmp[4]; + memcpy(tmp, P, 4); + P += 4; + return *(f32 *)tmp; + } + } + findNextNoneWhiteSpaceNumber(); + f32 ftmp; + P = core::fast_atof_move(P, ftmp); + return ftmp; +} + + +// read 2-dimensional vector. Stops at semicolon after second value for text file format +bool CXMeshFileLoader::readVector2(core::vector2df& vec) +{ + vec.X = readFloat(); + vec.Y = readFloat(); + return true; +} + + +// read 3-dimensional vector. Stops at semicolon after third value for text file format +bool CXMeshFileLoader::readVector3(core::vector3df& vec) +{ + vec.X = readFloat(); + vec.Y = readFloat(); + vec.Z = readFloat(); + return true; +} + + +// read color without alpha value. Stops after second semicolon after blue value +bool CXMeshFileLoader::readRGB(video::SColorf& color) +{ + color.r = readFloat(); + color.g = readFloat(); + color.b = readFloat(); + color.a = 1.0f; + return checkForOneFollowingSemicolons(); +} + + +// read color with alpha value. Stops after second semicolon after blue value +bool CXMeshFileLoader::readRGBA(video::SColorf& color) +{ + color.r = readFloat(); + color.g = readFloat(); + color.b = readFloat(); + color.a = readFloat(); + return checkForOneFollowingSemicolons(); +} + + +// read color without alpha value. Stops after second semicolon after blue value +bool CXMeshFileLoader::readRGB(video::SColor& color) +{ + color.setRed( (u32)(readFloat()*255)) ; + color.setGreen( (u32)(readFloat()*255)) ; + color.setBlue( (u32)(readFloat()*255)) ; + color.setAlpha( 255 ); + return checkForOneFollowingSemicolons(); +} + + +// read color with alpha value. Stops after second semicolon after blue value +bool CXMeshFileLoader::readRGBA(video::SColor& color) +{ + color.setRed( (u32)(readFloat()*255)) ; + color.setGreen( (u32)(readFloat()*255)) ; + color.setBlue( (u32)(readFloat()*255)) ; + color.setAlpha( (u32)(readFloat()*255)) ; + return checkForOneFollowingSemicolons(); +} + + +core::stringc CXMeshFileLoader::stripPathFromString(core::stringc string, bool returnPath) +{ + s32 slashIndex=string.findLast('/'); // forward slash + s32 backSlash=string.findLast('\\'); // back slash + + if (backSlash>slashIndex) slashIndex=backSlash; + + if (slashIndex==-1)//no slashes found + if (returnPath) + return core::stringc(); //no path to return + else + return string; + + if (returnPath) + return string.subString(0, slashIndex + 1); + else + return string.subString(slashIndex+1, string.size() - (slashIndex+1)); } } // end namespace scene } // end namespace irr +#endif // _IRR_COMPILE_WITH_X_LOADER_ + diff --git a/source/Irrlicht/CXMeshFileLoader.h b/source/Irrlicht/CXMeshFileLoader.h index 281bb612..922ab460 100644 --- a/source/Irrlicht/CXMeshFileLoader.h +++ b/source/Irrlicht/CXMeshFileLoader.h @@ -6,12 +6,13 @@ #define __C_X_MESH_FILE_LOADER_H_INCLUDED__ #include "IMeshLoader.h" -#include "IFileSystem.h" +#include "IReadFile.h" + #include "IVideoDriver.h" #include "irrString.h" -#include "SMesh.h" -#include "CXFileReader.h" -#include "SMeshBuffer.h" + +#include "CSkinnedMesh.h" + namespace irr { @@ -25,7 +26,7 @@ class CXMeshFileLoader : public IMeshLoader public: //! Constructor - CXMeshFileLoader(IMeshManipulator* manip, video::IVideoDriver* driver); + CXMeshFileLoader(scene::ISceneManager* smgr); //! destructor virtual ~CXMeshFileLoader(); @@ -40,10 +41,148 @@ public: //! See IUnknown::drop() for more information. virtual IAnimatedMesh* createMesh(irr::io::IReadFile* file); + struct SXTemplateMaterial + { + core::stringc Name; // template name from Xfile + video::SMaterial Material; // material + }; + + struct SXMesh + { + // this mesh contains triangulated texture data. + // because in an .x file, faces can be made of more than 3 + // vertices, the indices data structure is triangulated during the + // loading process. The IndexCountPerFace array is filled during + // this triangulation process and stores how much indices belong to + // every face. This data structure can be ignored, because all data + // in this structure is triangulated. + + core::stringc Name; + + core::array< s32 > IndexCountPerFace; // default 3, but could be more + + core::array Buffers; + + core::array Vertices; + + core::array Indices; + + core::array FaceIndices; // index of material for each face + + core::array Materials; // material array + }; + + private: - IMeshManipulator* Manipulator; - video::IVideoDriver* Driver; + bool load(); + + bool readFileIntoMemory(); + + bool parseFile(); + + + bool parseDataObject(); + + bool parseDataObjectTemplate(); + + bool parseDataObjectFrame(CSkinnedMesh::SJoint *parent); + + bool parseDataObjectTransformationMatrix(core::matrix4 &mat); + + bool parseDataObjectMesh(SXMesh &mesh); + + bool parseDataObjectSkinWeights(SXMesh &mesh); + + bool parseDataObjectSkinMeshHeader(); + + bool parseDataObjectMeshNormals(SXMesh &mesh); + + bool parseDataObjectMeshTextureCoords(SXMesh &mesh); + + bool parseDataObjectMeshVertexColors(SXMesh &mesh); + + bool parseDataObjectMeshMaterialList(SXMesh &mesh); + + bool parseDataObjectMaterial(video::SMaterial& material); + + bool parseDataObjectAnimationSet(); + + bool parseDataObjectAnimation(); + + bool parseDataObjectAnimationKey(ISkinnedMesh::SJoint *joint); + + bool parseDataObjectTextureFilename(core::stringc& texturename); + + bool parseUnknownDataObject(); + + //! places pointer to next begin of a token, and ignores comments + void findNextNoneWhiteSpace(); + + //! places pointer to next begin of a token, which must be a number, + // and ignores comments + void findNextNoneWhiteSpaceNumber(); + + //! returns next parseable token. Returns empty string if no token there + core::stringc getNextToken(); + + //! reads header of dataobject including the opening brace. + //! returns false if error happened, and writes name of object + //! if there is one + bool readHeadOfDataObject(core::stringc* outname=0); + + //! checks for one following semicolons, returns false if they are not there + bool checkForOneFollowingSemicolons(); + + //! checks for two following semicolons, returns false if they are not there + bool checkForTwoFollowingSemicolons(); + + //! reads a x file style string + bool getNextTokenAsString(core::stringc& out); + + + void readUntilEndOfLine(); + + core::stringc stripPathFromString(core::stringc string, bool returnPath); + + u16 readBinWord(); + u32 readBinDWord(); + s32 readInt(); + f32 readFloat(); + bool readVector2(core::vector2df& vec); + bool readVector3(core::vector3df& vec); + bool readRGB(video::SColorf& color); + bool readRGBA(video::SColorf& color); + + bool readRGB(video::SColor& color); + bool readRGBA(video::SColor& color); + + ISceneManager* SceneManager; + + core::array *Buffers; + core::array *AllJoints; + + CSkinnedMesh* AnimatedMesh; + io::IReadFile* file; + + s32 MajorVersion; + s32 MinorVersion; + bool binary; + s32 binaryNumCount; + + c8* Buffer; + s32 Size; + c8 FloatSize; + const c8* P; + c8* End; + + bool ErrorHappened; + + CSkinnedMesh::SJoint *CurFrame; + + core::array Meshes; + + core::array TemplateMaterials; }; } // end namespace scene diff --git a/source/Irrlicht/Irrlicht8.0.vcproj b/source/Irrlicht/Irrlicht8.0.vcproj index f8622339..9e611b28 100644 --- a/source/Irrlicht/Irrlicht8.0.vcproj +++ b/source/Irrlicht/Irrlicht8.0.vcproj @@ -719,6 +719,10 @@ RelativePath=".\..\..\include\IShadowVolumeSceneNode.h" > + + @@ -1687,14 +1691,6 @@ RelativePath=".\C3DSMeshFileLoader.h" > - - - - @@ -1712,11 +1708,19 @@ > + + + + - - - - @@ -1759,6 +1755,14 @@ RelativePath=".\CLMTSMeshFileLoader.h" > + + + + @@ -1767,6 +1771,14 @@ RelativePath=".\CMD3MeshFileLoader.h" > + + + + @@ -1815,6 +1827,14 @@ RelativePath=".\CQ3LevelMesh.h" > + + + + @@ -1863,6 +1883,14 @@ RelativePath=".\CBillboardSceneNode.h" > + + + + diff --git a/source/Irrlicht/Irrlicht_Win32-gcc.cbp b/source/Irrlicht/Irrlicht_Win32-gcc.cbp index 7e0b4c0f..f1a5ea75 100644 --- a/source/Irrlicht/Irrlicht_Win32-gcc.cbp +++ b/source/Irrlicht/Irrlicht_Win32-gcc.cbp @@ -1,50 +1,47 @@ - - + - + - diff --git a/source/Irrlicht/Makefile b/source/Irrlicht/Makefile index 34a4e8d7..e2241c6f 100644 --- a/source/Irrlicht/Makefile +++ b/source/Irrlicht/Makefile @@ -1,7 +1,7 @@ -VERSION = 1.3.1 -# Irrlicht Engine 1.3.1 +VERSION = 1.4RC +# Irrlicht Engine 1.4RC # Makefile for Linux, created by N.Gebhardt. -# +# # To use, just run: # # make @@ -14,12 +14,15 @@ VERSION = 1.3.1 # make sharedlib # make install # -# Please note that Irrlicht as shared lib is just experimental and +# Please note that Irrlicht as shared lib is just experimental and # probably not tested. # #List of object files, separated based on engine architecture -IRROBJ = C3DSMeshFileLoader.o COgreMeshFileLoader.o COBJMeshFileLoader.o CAnimatedMeshMD2.o CAnimatedMeshMD3.o CMD3MeshFileLoader.o CAnimatedMeshMS3D.o CAnimatedMeshB3d.o CAnimatedMeshSceneNode.o CBillboardSceneNode.o CCameraFPSSceneNode.o CCameraMayaSceneNode.o CCameraSceneNode.o CColladaFileLoader.o CCSMLoader.o CDefaultMeshFormatLoader.o CDMFLoader.o CDummyTransformationSceneNode.o CEmptySceneNode.o CGeometryCreator.o CLightSceneNode.o CLMTSMeshFileLoader.o CMeshManipulator.o CMeshSceneNode.o CMetaTriangleSelector.o CMY3DMeshFileLoader.o COCTLoader.o COctTreeSceneNode.o COctTreeTriangleSelector.o CParticleAnimatedMeshSceneNodeEmitter.o CParticleBoxEmitter.o CParticleCylinderEmitter.o CParticleMeshEmitter.o CParticlePointEmitter.o CParticleRingEmitter.o CParticleSphereEmitter.o CParticleAttractionAffector.o CParticleFadeOutAffector.o CParticleGravityAffector.o CParticleRotationAffector.o CParticleSystemSceneNode.o CQ3LevelMesh.o CSceneCollisionManager.o CSceneManager.o CSceneNodeAnimatorCollisionResponse.o CSceneNodeAnimatorDelete.o CSceneNodeAnimatorFlyCircle.o CSceneNodeAnimatorFlyStraight.o CSceneNodeAnimatorFollowSpline.o CSceneNodeAnimatorRotation.o CSceneNodeAnimatorTexture.o CShadowVolumeSceneNode.o CSkyBoxSceneNode.o CSkyDomeSceneNode.o CTerrainSceneNode.o CTerrainTriangleSelector.o CCubeSceneNode.o CSphereSceneNode.o CTextSceneNode.o CTriangleBBSelector.o CTriangleSelector.o CWaterSurfaceSceneNode.o CXAnimationPlayer.o CXFileReader.o CXMeshFileLoader.o CMeshCache.o CDefaultSceneNodeAnimatorFactory.o CDefaultSceneNodeFactory.o CQuake3ShaderSceneNode.o +IRRMESHOBJ = CSkinnedMesh.o CBSPMeshFileLoader.o CMD2MeshFileLoader.o CMD3MeshFileLoader.o CMS3DMeshFileLoader.o CB3DMeshFileLoader.o CBoneSceneNode.o CBSPMeshFileLoader.o C3DSMeshFileLoader.o COgreMeshFileLoader.o COBJMeshFileLoader.o CAnimatedMeshMD2.o CAnimatedMeshMD3.o CMD3MeshFileLoader.o CAnimatedMeshSceneNode.o CColladaFileLoader.o CCSMLoader.o CDMFLoader.o CLMTSMeshFileLoader.o CMeshSceneNode.o CMY3DMeshFileLoader.o COCTLoader.o CQ3LevelMesh.o CXMeshFileLoader.o CQuake3ShaderSceneNode.o +IRROBJ = CBillboardSceneNode.o CCameraFPSSceneNode.o CCameraMayaSceneNode.o CCameraSceneNode.o CDummyTransformationSceneNode.o CEmptySceneNode.o CGeometryCreator.o CLightSceneNode.o CMeshManipulator.o CMetaTriangleSelector.o COctTreeSceneNode.o COctTreeTriangleSelector.o CSceneCollisionManager.o CSceneManager.o CShadowVolumeSceneNode.o CSkyBoxSceneNode.o CSkyDomeSceneNode.o CTerrainSceneNode.o CTerrainTriangleSelector.o CCubeSceneNode.o CSphereSceneNode.o CTextSceneNode.o CTriangleBBSelector.o CTriangleSelector.o CWaterSurfaceSceneNode.o CMeshCache.o CDefaultSceneNodeAnimatorFactory.o CDefaultSceneNodeFactory.o +IRRPARTICLEOBJ = CParticleAnimatedMeshSceneNodeEmitter.o CParticleBoxEmitter.o CParticleCylinderEmitter.o CParticleMeshEmitter.o CParticlePointEmitter.o CParticleRingEmitter.o CParticleSphereEmitter.o CParticleAttractionAffector.o CParticleFadeOutAffector.o CParticleGravityAffector.o CParticleRotationAffector.o CParticleSystemSceneNode.o +IRRANIMOBJ = CSceneNodeAnimatorCollisionResponse.o CSceneNodeAnimatorDelete.o CSceneNodeAnimatorFlyCircle.o CSceneNodeAnimatorFlyStraight.o CSceneNodeAnimatorFollowSpline.o CSceneNodeAnimatorRotation.o CSceneNodeAnimatorTexture.o IRRVIDEOOBJ = COpenGLDriver.o COpenGLNormalMapRenderer.o COpenGLParallaxMapRenderer.o COpenGLShaderMaterialRenderer.o COpenGLTexture.o COpenGLSLMaterialRenderer.o COpenGLExtensionHandler.o CD3D8Driver.o CD3D8NormalMapRenderer.o CD3D8ParallaxMapRenderer.o CD3D8ShaderMaterialRenderer.o CD3D8Texture.o CColorConverter.o CFPSCounter.o CImage.o CImageLoaderBMP.o CImageLoaderJPG.o CImageLoaderPCX.o CImageLoaderPNG.o CImageLoaderPSD.o CImageLoaderTGA.o CImageWriterBMP.o CImageWriterJPG.o CImageWriterPCX.o CImageWriterPNG.o CImageWriterPPM.o CImageWriterPSD.o CImageWriterTGA.o CNullDriver.o CD3D9Driver.o CD3D9HLSLMaterialRenderer.o CD3D9NormalMapRenderer.o CD3D9ParallaxMapRenderer.o CD3D9ShaderMaterialRenderer.o CD3D9Texture.o CVideoModeList.o IRRSWRENDEROBJ = CSoftwareDriver.o CSoftwareTexture.o CTRFlat.o CTRFlatWire.o CTRGouraud.o CTRGouraudWire.o CTRTextureFlat.o CTRTextureFlatWire.o CTRTextureGouraud.o CTRTextureGouraudAdd.o CTRTextureGouraudNoZ.o CTRTextureGouraudWire.o CZBuffer.o CTRTextureGouraudVertexAlpha2.o CTRTextureGouraudNoZ2.o CTRTextureLightMap2_M2.o CTRTextureLightMap2_M4.o CTRTextureLightMap2_M1.o CSoftwareDriver2.o CSoftwareTexture2.o CTRTextureGouraud2.o CTRGouraud2.o CTRGouraudAlpha2.o CTRGouraudAlphaNoZ2.o CTRTextureDetailMap2.o CTRTextureGouraudAdd2.o CTRTextureGouraudAddNoZ2.o CTRTextureWire2.o CTRTextureLightMap2_Add.o CTRTextureLightMapGouraud2_M4.o IBurningShader.o CTRTextureBlend.o CTRTextureGouraudAlpha.o CTRTextureGouraudAlphaNoZ.o CDepthBuffer.o IRRIOOBJ = CFileList.o CFileSystem.o CLimitReadFile.o CMemoryReadFile.o CReadFile.o CWriteFile.o CXMLReader.o CXMLWriter.o CZipReader.o CPakReader.o irrXML.o CAttributes.o @@ -30,7 +33,9 @@ JPEGLIBOBJ = jpeglib/jcapimin.o jpeglib/jcapistd.o jpeglib/jccoefct.o jpeglib/jc LIBPNGOBJ = libpng/png.o libpng/pngerror.o libpng/pngget.o libpng/pngmem.o libpng/pngpread.o libpng/pngread.o libpng/pngrio.o libpng/pngrtran.o libpng/pngrutil.o libpng/pngset.o libpng/pngtrans.o libpng/pngwio.o libpng/pngwrite.o libpng/pngwtran.o libpng/pngwutil.o # Next variable is for additional scene nodes etc. of customized Irrlicht versions EXTRAOBJ = -LINKOBJ = $(IRROBJ) $(IRRVIDEOOBJ) $(IRRSWRENDEROBJ) $(IRRIOOBJ) $(IRROTHEROBJ) $(IRRGUIOBJ) $(ZLIBOBJ) $(JPEGLIBOBJ) $(LIBPNGOBJ) $(EXTRAOBJ) +LINKOBJ := $(IRRMESHOBJ) $(IRROBJ) $(IRRPARTICLEOBJ) $(IRRANIMOBJ) \ + $(IRRVIDEOOBJ) $(IRRSWRENDEROBJ) $(IRRIOOBJ) $(IRROTHEROBJ) \ + $(IRRGUIOBJ) $(ZLIBOBJ) $(JPEGLIBOBJ) $(LIBPNGOBJ) $(EXTRAOBJ) ############### #Compiler flags @@ -99,7 +104,7 @@ install: -include $(LINKOBJ:.o=.d) -help: +help: @echo "Available targets for Irrlicht" @echo " sharedlib: Build shared library Irrlicht.so for Linux" @echo " staticlib: Build static library Irrlicht.a for Linux" @@ -110,7 +115,7 @@ help: @echo "" @echo " clean: Clean up directory" -# Cleans all temporary files and compilation results. +# Cleans all temporary files and compilation results. clean: $(RM) $(LINKOBJ) $(SHARED_LIB).$(VERSION) $(STATIC_LIB) $(LINKOBJ:.o=.d)