mirror of
https://github.com/minetest/irrlicht.git
synced 2024-09-07 05:10:19 +02:00
git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@6000 dfc29bdd-3216-0410-991c-e03cc46cb475
631 lines
16 KiB
C++
631 lines
16 KiB
C++
// Copyright (C) 2002-2012 Thomas Alten
|
|
// This file is part of the "Irrlicht Engine".
|
|
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
|
|
|
#ifndef __C_ANIMATED_MESH_HALFLIFE_H_INCLUDED__
|
|
#define __C_ANIMATED_MESH_HALFLIFE_H_INCLUDED__
|
|
|
|
#include "IAnimatedMesh.h"
|
|
#include "ISceneManager.h"
|
|
#include "irrArray.h"
|
|
#include "irrString.h"
|
|
#include "IMeshLoader.h"
|
|
#include "SMesh.h"
|
|
#include "IReadFile.h"
|
|
|
|
namespace irr
|
|
{
|
|
namespace scene
|
|
{
|
|
|
|
|
|
// STUDIO MODELS, Copyright (c) 1998, Valve LLC. All rights reserved.
|
|
#define MAXSTUDIOTRIANGLES 20000 // TODO: tune this
|
|
#define MAXSTUDIOVERTS 2048 // TODO: tune this
|
|
#define MAXSTUDIOSEQUENCES 256 // total animation sequences
|
|
#define MAXSTUDIOSKINS 100 // total textures
|
|
#define MAXSTUDIOSRCBONES 512 // bones allowed at source movement
|
|
#define MAXSTUDIOBONES 128 // total bones actually used
|
|
#define MAXSTUDIOMODELS 32 // sub-models per model
|
|
#define MAXSTUDIOBODYPARTS 32
|
|
#define MAXSTUDIOGROUPS 4
|
|
#define MAXSTUDIOANIMATIONS 512 // per sequence
|
|
#define MAXSTUDIOMESHES 256
|
|
#define MAXSTUDIOEVENTS 1024
|
|
#define MAXSTUDIOPIVOTS 256
|
|
#define MAXSTUDIOCONTROLLERS 8
|
|
|
|
typedef f32 vec3_hl[3]; // x,y,z
|
|
typedef f32 vec4_hl[4]; // x,y,z,w
|
|
|
|
// byte-align structures
|
|
#include "irrpack.h"
|
|
|
|
struct SHalflifeHeader
|
|
{
|
|
c8 id[4];
|
|
s32 version;
|
|
|
|
c8 name[64];
|
|
s32 length;
|
|
|
|
vec3_hl eyeposition; // ideal eye position
|
|
vec3_hl min; // ideal movement hull size
|
|
vec3_hl max;
|
|
|
|
vec3_hl bbmin; // clipping bounding box
|
|
vec3_hl bbmax;
|
|
|
|
s32 flags;
|
|
|
|
u32 numbones; // bones
|
|
u32 boneindex;
|
|
|
|
u32 numbonecontrollers; // bone controllers
|
|
u32 bonecontrollerindex;
|
|
|
|
u32 numhitboxes; // complex bounding boxes
|
|
u32 hitboxindex;
|
|
|
|
u32 numseq; // animation sequences
|
|
u32 seqindex;
|
|
|
|
u32 numseqgroups; // demand loaded sequences
|
|
u32 seqgroupindex;
|
|
|
|
u32 numtextures; // raw textures
|
|
u32 textureindex;
|
|
u32 texturedataindex;
|
|
|
|
u32 numskinref; // replaceable textures
|
|
u32 numskinfamilies;
|
|
u32 skinindex;
|
|
|
|
u32 numbodyparts;
|
|
u32 bodypartindex;
|
|
|
|
u32 numattachments; // queryable attachable points
|
|
u32 attachmentindex;
|
|
|
|
s32 soundtable;
|
|
s32 soundindex;
|
|
s32 soundgroups;
|
|
s32 soundgroupindex;
|
|
|
|
s32 numtransitions; // animation node to animation node transition graph
|
|
s32 transitionindex;
|
|
} PACK_STRUCT;
|
|
|
|
// header for demand loaded sequence group data
|
|
struct studioseqhdr_t
|
|
{
|
|
s32 id;
|
|
s32 version;
|
|
|
|
c8 name[64];
|
|
s32 length;
|
|
} PACK_STRUCT;
|
|
|
|
// bones
|
|
struct SHalflifeBone
|
|
{
|
|
c8 name[32]; // bone name for symbolic links
|
|
s32 parent; // parent bone
|
|
s32 flags; // ??
|
|
s32 bonecontroller[6]; // bone controller index, -1 == none
|
|
f32 value[6]; // default DoF values
|
|
f32 scale[6]; // scale for delta DoF values
|
|
} PACK_STRUCT;
|
|
|
|
|
|
// bone controllers
|
|
struct SHalflifeBoneController
|
|
{
|
|
s32 bone; // -1 == 0
|
|
s32 type; // X, Y, Z, XR, YR, ZR, M
|
|
f32 start;
|
|
f32 end;
|
|
s32 rest; // byte index value at rest
|
|
s32 index; // 0-3 user set controller, 4 mouth
|
|
} PACK_STRUCT;
|
|
|
|
// intersection boxes
|
|
struct SHalflifeBBox
|
|
{
|
|
s32 bone;
|
|
s32 group; // intersection group
|
|
vec3_hl bbmin; // bounding box
|
|
vec3_hl bbmax;
|
|
} PACK_STRUCT;
|
|
|
|
#ifndef ZONE_H
|
|
// NOTE: this was a void*, but that crashes on 64bit.
|
|
// I have found no mdl format desc, so not sure what it's meant to be, but s32 at least works.
|
|
typedef s32 cache_user_t;
|
|
#endif
|
|
|
|
// demand loaded sequence groups
|
|
struct SHalflifeSequenceGroup
|
|
{
|
|
c8 label[32]; // textual name
|
|
c8 name[64]; // file name
|
|
cache_user_t cache; // cache index pointer
|
|
s32 data; // hack for group 0
|
|
} PACK_STRUCT;
|
|
|
|
// sequence descriptions
|
|
struct SHalflifeSequence
|
|
{
|
|
c8 label[32]; // sequence label
|
|
|
|
f32 fps; // frames per second
|
|
s32 flags; // looping/non-looping flags
|
|
|
|
s32 activity;
|
|
s32 actweight;
|
|
|
|
s32 numevents;
|
|
s32 eventindex;
|
|
|
|
s32 numframes; // number of frames per sequence
|
|
|
|
u32 numpivots; // number of foot pivots
|
|
u32 pivotindex;
|
|
|
|
s32 motiontype;
|
|
s32 motionbone;
|
|
vec3_hl linearmovement;
|
|
s32 automoveposindex;
|
|
s32 automoveangleindex;
|
|
|
|
vec3_hl bbmin; // per sequence bounding box
|
|
vec3_hl bbmax;
|
|
|
|
s32 numblends;
|
|
s32 animindex; // SHalflifeAnimOffset pointer relative to start of sequence group data
|
|
// [blend][bone][X, Y, Z, XR, YR, ZR]
|
|
|
|
s32 blendtype[2]; // X, Y, Z, XR, YR, ZR
|
|
f32 blendstart[2]; // starting value
|
|
f32 blendend[2]; // ending value
|
|
s32 blendparent;
|
|
|
|
s32 seqgroup; // sequence group for demand loading
|
|
|
|
s32 entrynode; // transition node at entry
|
|
s32 exitnode; // transition node at exit
|
|
s32 nodeflags; // transition rules
|
|
|
|
s32 nextseq; // auto advancing sequences
|
|
} PACK_STRUCT;
|
|
|
|
// events
|
|
struct mstudioevent_t
|
|
{
|
|
s32 frame;
|
|
s32 event;
|
|
s32 type;
|
|
c8 options[64];
|
|
} PACK_STRUCT;
|
|
|
|
|
|
// pivots
|
|
struct mstudiopivot_t
|
|
{
|
|
vec3_hl org; // pivot point
|
|
s32 start;
|
|
s32 end;
|
|
} PACK_STRUCT;
|
|
|
|
// attachment
|
|
struct SHalflifeAttachment
|
|
{
|
|
c8 name[32];
|
|
s32 type;
|
|
s32 bone;
|
|
vec3_hl org; // attachment point
|
|
vec3_hl vectors[3];
|
|
} PACK_STRUCT;
|
|
|
|
struct SHalflifeAnimOffset
|
|
{
|
|
u16 offset[6];
|
|
} PACK_STRUCT;
|
|
|
|
// animation frames
|
|
union SHalflifeAnimationFrame
|
|
{
|
|
struct {
|
|
u8 valid;
|
|
u8 total;
|
|
} PACK_STRUCT num;
|
|
s16 value;
|
|
} PACK_STRUCT;
|
|
|
|
|
|
// body part index
|
|
struct SHalflifeBody
|
|
{
|
|
c8 name[64];
|
|
u32 nummodels;
|
|
u32 base;
|
|
u32 modelindex; // index into models array
|
|
} PACK_STRUCT;
|
|
|
|
|
|
// skin info
|
|
struct SHalflifeTexture
|
|
{
|
|
c8 name[64];
|
|
s32 flags;
|
|
s32 width;
|
|
s32 height;
|
|
s32 index;
|
|
} PACK_STRUCT;
|
|
|
|
|
|
// skin families
|
|
// short index[skinfamilies][skinref]
|
|
|
|
// studio models
|
|
struct SHalflifeModel
|
|
{
|
|
c8 name[64];
|
|
s32 type;
|
|
|
|
f32 boundingradius;
|
|
|
|
u32 nummesh;
|
|
u32 meshindex;
|
|
|
|
u32 numverts; // number of unique vertices
|
|
u32 vertinfoindex; // vertex bone info
|
|
u32 vertindex; // vertex vec3_hl
|
|
u32 numnorms; // number of unique surface normals
|
|
u32 norminfoindex; // normal bone info
|
|
u32 normindex; // normal vec3_hl
|
|
|
|
u32 numgroups; // deformation groups
|
|
u32 groupindex;
|
|
} PACK_STRUCT;
|
|
|
|
|
|
// meshes
|
|
struct SHalflifeMesh
|
|
{
|
|
u32 numtris;
|
|
u32 triindex;
|
|
u32 skinref;
|
|
u32 numnorms; // per mesh normals
|
|
u32 normindex; // normal vec3_hl
|
|
} PACK_STRUCT;
|
|
|
|
// Default alignment
|
|
#include "irrunpack.h"
|
|
|
|
// lighting options
|
|
#define STUDIO_NF_FLATSHADE 0x0001
|
|
#define STUDIO_NF_CHROME 0x0002
|
|
#define STUDIO_NF_FULLBRIGHT 0x0004
|
|
|
|
// motion flags
|
|
#define STUDIO_X 0x0001
|
|
#define STUDIO_Y 0x0002
|
|
#define STUDIO_Z 0x0004
|
|
#define STUDIO_XR 0x0008
|
|
#define STUDIO_YR 0x0010
|
|
#define STUDIO_ZR 0x0020
|
|
#define STUDIO_LX 0x0040
|
|
#define STUDIO_LY 0x0080
|
|
#define STUDIO_LZ 0x0100
|
|
#define STUDIO_AX 0x0200
|
|
#define STUDIO_AY 0x0400
|
|
#define STUDIO_AZ 0x0800
|
|
#define STUDIO_AXR 0x1000
|
|
#define STUDIO_AYR 0x2000
|
|
#define STUDIO_AZR 0x4000
|
|
#define STUDIO_TYPES 0x7FFF
|
|
#define STUDIO_RLOOP 0x8000 // controller that wraps shortest distance
|
|
|
|
// sequence flags
|
|
#define STUDIO_LOOPING 0x0001
|
|
|
|
// bone flags
|
|
#define STUDIO_HAS_NORMALS 0x0001
|
|
#define STUDIO_HAS_VERTICES 0x0002
|
|
#define STUDIO_HAS_BBOX 0x0004
|
|
#define STUDIO_HAS_CHROME 0x0008 // if any of the textures have chrome on them
|
|
|
|
#define RAD_TO_STUDIO (32768.0/M_PI)
|
|
#define STUDIO_TO_RAD (M_PI/32768.0)
|
|
|
|
/*!
|
|
Textureatlas
|
|
Combine Source Images with arbitrary size and bithdepth to an Image with 2^n size
|
|
borders from the source images are copied around for allowing filtering ( bilinear, mipmap )
|
|
*/
|
|
struct STextureAtlas
|
|
{
|
|
STextureAtlas ()
|
|
{
|
|
release();
|
|
}
|
|
|
|
virtual ~STextureAtlas ()
|
|
{
|
|
release ();
|
|
}
|
|
|
|
void release ();
|
|
void addSource ( const c8 * name, video::IImage * image );
|
|
void create ( u32 pixelborder, video::E_TEXTURE_CLAMP texmode );
|
|
void getScale ( core::vector2df &scale );
|
|
void getTranslation ( const c8 * name, core::vector2di &pos );
|
|
|
|
struct TextureAtlasEntry
|
|
{
|
|
io::path name;
|
|
u32 width;
|
|
u32 height;
|
|
|
|
core::vector2di pos;
|
|
|
|
video::IImage * image;
|
|
|
|
bool operator < ( const TextureAtlasEntry & other )
|
|
{
|
|
return height > other.height;
|
|
}
|
|
};
|
|
|
|
|
|
core::array < TextureAtlasEntry > atlas;
|
|
video::IImage * Master;
|
|
};
|
|
|
|
|
|
//! Possible types of Animation Type
|
|
enum E_ANIMATION_TYPE
|
|
{
|
|
//! No Animation
|
|
EAMT_STILL,
|
|
//! From Start to End, then Stop ( Limited Line )
|
|
EAMT_WAYPOINT,
|
|
//! Linear Cycling Animation ( Sawtooth )
|
|
EAMT_LOOPING,
|
|
//! Linear bobbing ( Triangle )
|
|
EAMT_PINGPONG
|
|
};
|
|
|
|
//! Names for Animation Type
|
|
const c8* const MeshAnimationTypeNames[] =
|
|
{
|
|
"still",
|
|
"waypoint",
|
|
"looping",
|
|
"pingpong",
|
|
0
|
|
};
|
|
|
|
|
|
//! Data for holding named Animation Info
|
|
struct KeyFrameInterpolation
|
|
{
|
|
core::stringc Name; // Name of the current Animation/Bone
|
|
E_ANIMATION_TYPE AnimationType; // Type of Animation ( looping, usw..)
|
|
|
|
f32 CurrentFrame; // Current Frame
|
|
s32 NextFrame; // Frame which will be used next. For blending
|
|
|
|
s32 StartFrame; // Absolute Frame where the current animation start
|
|
s32 Frames; // Relative Frames how much Frames this animation have
|
|
s32 LoopingFrames; // How much of Frames sould be looped
|
|
s32 EndFrame; // Absolute Frame where the current animation ends End = start + frames - 1
|
|
|
|
f32 FramesPerSecond; // Speed in Frames/Seconds the animation is played
|
|
f32 RelativeSpeed; // Factor Original fps is modified
|
|
|
|
u32 BeginTime; // Animation started at this thime
|
|
u32 EndTime; // Animation end at this time
|
|
u32 LastTime; // Last Keyframe was done at this time
|
|
|
|
KeyFrameInterpolation ( const c8 * name = "", s32 start = 0, s32 frames = 0, s32 loopingframes = 0,
|
|
f32 fps = 0.f, f32 relativefps = 1.f )
|
|
: Name ( name ), AnimationType ( loopingframes ? EAMT_LOOPING : EAMT_WAYPOINT),
|
|
CurrentFrame ( (f32) start ), NextFrame ( start ), StartFrame ( start ),
|
|
Frames ( frames ), LoopingFrames ( loopingframes ), EndFrame ( start + frames - 1 ),
|
|
FramesPerSecond ( fps ), RelativeSpeed ( relativefps ),
|
|
BeginTime ( 0 ), EndTime ( 0 ), LastTime ( 0 )
|
|
{
|
|
}
|
|
|
|
// linear search
|
|
bool operator == ( const KeyFrameInterpolation & other ) const
|
|
{
|
|
return Name.equals_ignore_case ( other.Name );
|
|
}
|
|
|
|
};
|
|
|
|
|
|
//! a List holding named Animations
|
|
typedef core::array < KeyFrameInterpolation > IAnimationList;
|
|
|
|
//! a List holding named Skins
|
|
typedef core::array < core::stringc > ISkinList;
|
|
|
|
|
|
// Current Model per Body
|
|
struct SubModel
|
|
{
|
|
core::stringc name;
|
|
u32 startBuffer;
|
|
u32 endBuffer;
|
|
u32 state;
|
|
};
|
|
|
|
struct BodyPart
|
|
{
|
|
core::stringc name;
|
|
u32 defaultModel;
|
|
core::array < SubModel > model;
|
|
};
|
|
//! a List holding named Models and SubModels
|
|
typedef core::array < BodyPart > IBodyList;
|
|
|
|
|
|
class CAnimatedMeshHalfLife : public IAnimatedMesh
|
|
{
|
|
public:
|
|
|
|
//! constructor
|
|
CAnimatedMeshHalfLife();
|
|
|
|
//! destructor
|
|
virtual ~CAnimatedMeshHalfLife();
|
|
|
|
//! loads a Halflife mdl file
|
|
bool loadModelFile( io::IReadFile* file, ISceneManager * smgr );
|
|
|
|
//IAnimatedMesh
|
|
virtual u32 getFrameCount() const _IRR_OVERRIDE_;
|
|
virtual IMesh* getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop) _IRR_OVERRIDE_;
|
|
virtual const core::aabbox3d<f32>& getBoundingBox() const _IRR_OVERRIDE_;
|
|
virtual E_ANIMATED_MESH_TYPE getMeshType() const _IRR_OVERRIDE_;
|
|
void renderModel ( u32 param, video::IVideoDriver * driver, const core::matrix4 &absoluteTransformation);
|
|
|
|
//! returns amount of mesh buffers.
|
|
virtual u32 getMeshBufferCount() const _IRR_OVERRIDE_;
|
|
//! returns pointer to a mesh buffer
|
|
virtual IMeshBuffer* getMeshBuffer(u32 nr) const _IRR_OVERRIDE_;
|
|
//! Returns pointer to a mesh buffer which fits a material
|
|
virtual IMeshBuffer* getMeshBuffer( const video::SMaterial &material) const _IRR_OVERRIDE_;
|
|
|
|
virtual void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) _IRR_OVERRIDE_;
|
|
|
|
//! set the hardware mapping hint, for driver
|
|
virtual void setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint, E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX) _IRR_OVERRIDE_;
|
|
|
|
//! flags the meshbuffer as changed, reloads hardware buffers
|
|
virtual void setDirty(E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX) _IRR_OVERRIDE_;
|
|
|
|
//! set user axis aligned bounding box
|
|
virtual void setBoundingBox(const core::aabbox3df& box) _IRR_OVERRIDE_;
|
|
|
|
//! Gets the default animation speed of the animated mesh.
|
|
/** \return Amount of frames per second. If the amount is 0, it is a static, non animated mesh. */
|
|
virtual f32 getAnimationSpeed() const _IRR_OVERRIDE_
|
|
{
|
|
return FramesPerSecond;
|
|
}
|
|
|
|
//! Gets the frame count of the animated mesh.
|
|
/** \param fps Frames per second to play the animation with. If the amount is 0, it is not animated.
|
|
The actual speed is set in the scene node the mesh is instantiated in.*/
|
|
virtual void setAnimationSpeed(f32 fps) _IRR_OVERRIDE_
|
|
{
|
|
FramesPerSecond=fps;
|
|
}
|
|
|
|
//! Get the Animation List
|
|
IAnimationList* getAnimList () { return &AnimList; }
|
|
|
|
//! Return the named Body List of this Animated Mesh
|
|
IBodyList *getBodyList() { return &BodyList; }
|
|
|
|
private:
|
|
|
|
// KeyFrame Animation List
|
|
IAnimationList AnimList;
|
|
// Sum of all sequences
|
|
u32 FrameCount;
|
|
|
|
// Named meshes of the Body
|
|
IBodyList BodyList;
|
|
|
|
//! return a Mesh per frame
|
|
SMesh* MeshIPol;
|
|
|
|
ISceneManager *SceneManager;
|
|
|
|
SHalflifeHeader *Header;
|
|
SHalflifeHeader *TextureHeader;
|
|
bool OwnTexModel; // do we have a modelT.mdl ?
|
|
SHalflifeHeader *AnimationHeader[32]; // sequences named model01.mdl, model02.mdl
|
|
|
|
void initData ();
|
|
SHalflifeHeader * loadModel( io::IReadFile* file, const io::path &filename );
|
|
bool postLoadModel( const io::path &filename );
|
|
|
|
u32 SequenceIndex; // sequence index
|
|
f32 CurrentFrame; // Current Frame
|
|
f32 FramesPerSecond;
|
|
|
|
#define MOUTH_CONTROLLER 4
|
|
u8 BoneController[4 + 1 ]; // bone controllers + mouth position
|
|
u8 Blending[2]; // animation blending
|
|
|
|
vec4_hl BoneAdj;
|
|
f32 SetController( s32 controllerIndex, f32 value );
|
|
|
|
u32 SkinGroupSelection; // skin group selection
|
|
u32 SetSkin( u32 value );
|
|
|
|
void initModel();
|
|
void dumpModelInfo(u32 level) const;
|
|
|
|
void ExtractBbox(s32 sequence, core::aabbox3df &box) const;
|
|
|
|
void setUpBones ();
|
|
SHalflifeAnimOffset * getAnim( SHalflifeSequence *seq );
|
|
void slerpBones( vec4_hl q1[], vec3_hl pos1[], vec4_hl q2[], vec3_hl pos2[], f32 s );
|
|
void calcRotations ( vec3_hl *pos, vec4_hl *q, SHalflifeSequence *seq, SHalflifeAnimOffset *anim, f32 f );
|
|
|
|
void calcBoneAdj();
|
|
void calcBoneQuaternion(const s32 frame, const SHalflifeBone *bone, SHalflifeAnimOffset *anim, const u32 j, f32& angle1, f32& angle2) const;
|
|
void calcBonePosition(const s32 frame, f32 s, const SHalflifeBone *bone, SHalflifeAnimOffset *anim, f32 *pos ) const;
|
|
|
|
void buildVertices ();
|
|
|
|
io::path TextureBaseName;
|
|
|
|
#define HL_TEXTURE_ATLAS
|
|
|
|
#ifdef HL_TEXTURE_ATLAS
|
|
STextureAtlas TextureAtlas;
|
|
// video::ITexture *TextureMaster;
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
//! Meshloader capable of loading HalfLife Model files
|
|
class CHalflifeMDLMeshFileLoader : public IMeshLoader
|
|
{
|
|
public:
|
|
|
|
//! Constructor
|
|
CHalflifeMDLMeshFileLoader( scene::ISceneManager* smgr );
|
|
|
|
//! 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 io::path& filename) const _IRR_OVERRIDE_;
|
|
|
|
//! 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 IReferenceCounted::drop() for more information.
|
|
*/
|
|
virtual IAnimatedMesh* createMesh(io::IReadFile* file) _IRR_OVERRIDE_;
|
|
|
|
private:
|
|
scene::ISceneManager* SceneManager;
|
|
};
|
|
|
|
|
|
} // end namespace scene
|
|
} // end namespace irr
|
|
|
|
#endif
|
|
|