aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/irrlicht-1.8/source/Irrlicht/CAnimatedMeshHalfLife.h
blob: 693cd8d1f5a767752a551e0a7505505f77af7ff6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
// 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
		virtual bool loadModelFile( io::IReadFile* file, ISceneManager * smgr );

		//IAnimatedMesh
		virtual u32 getFrameCount() const;
		virtual IMesh* getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop);
		virtual const core::aabbox3d<f32>& getBoundingBox() const;
		virtual E_ANIMATED_MESH_TYPE getMeshType() const;
		virtual void renderModel ( u32 param, video::IVideoDriver * driver, const core::matrix4 &absoluteTransformation);

		//! 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
		virtual IMeshBuffer* getMeshBuffer( const video::SMaterial &material) const;

		virtual void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue);

		//! set the hardware mapping hint, for driver
		virtual void setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint, E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX);

		//! flags the meshbuffer as changed, reloads hardware buffers
		virtual void setDirty(E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX);

		//! set user axis aligned bounding box
		virtual void setBoundingBox(const core::aabbox3df& box);

		//! 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
		{
			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)
		{
			FramesPerSecond=fps;
		}

		//! Get the Animation List
		virtual IAnimationList* getAnimList () { return &AnimList; }

		//! Return the named Body List of this Animated Mesh
		virtual 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;

		//! 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);

	private:
		scene::ISceneManager* SceneManager;
	};


} // end namespace scene
} // end namespace irr

#endif