diff options
author | David Walter Seikel | 2016-03-28 22:28:34 +1000 |
---|---|---|
committer | David Walter Seikel | 2016-03-28 22:28:34 +1000 |
commit | 7028cbe09c688437910a25623098762bf0fa592d (patch) | |
tree | 10b5af58277d9880380c2251f109325542c4e6eb /src/others/irrlicht-1.8.1/source/Irrlicht/CAnimatedMeshHalfLife.cpp | |
parent | Move lemon to the src/others directory. (diff) | |
download | SledjHamr-7028cbe09c688437910a25623098762bf0fa592d.zip SledjHamr-7028cbe09c688437910a25623098762bf0fa592d.tar.gz SledjHamr-7028cbe09c688437910a25623098762bf0fa592d.tar.bz2 SledjHamr-7028cbe09c688437910a25623098762bf0fa592d.tar.xz |
Move Irrlicht to src/others.
Diffstat (limited to 'src/others/irrlicht-1.8.1/source/Irrlicht/CAnimatedMeshHalfLife.cpp')
-rw-r--r-- | src/others/irrlicht-1.8.1/source/Irrlicht/CAnimatedMeshHalfLife.cpp | 1695 |
1 files changed, 1695 insertions, 0 deletions
diff --git a/src/others/irrlicht-1.8.1/source/Irrlicht/CAnimatedMeshHalfLife.cpp b/src/others/irrlicht-1.8.1/source/Irrlicht/CAnimatedMeshHalfLife.cpp new file mode 100644 index 0000000..6531e1a --- /dev/null +++ b/src/others/irrlicht-1.8.1/source/Irrlicht/CAnimatedMeshHalfLife.cpp | |||
@@ -0,0 +1,1695 @@ | |||
1 | // Copyright (C) 2002-2012 Nikolaus Gebhardt / Fabio Concas / Thomas Alten | ||
2 | // This file is part of the "Irrlicht Engine". | ||
3 | // For conditions of distribution and use, see copyright notice in irrlicht.h | ||
4 | |||
5 | #include "IrrCompileConfig.h" | ||
6 | #ifdef _IRR_COMPILE_WITH_HALFLIFE_LOADER_ | ||
7 | |||
8 | #include "CAnimatedMeshHalfLife.h" | ||
9 | #include "os.h" | ||
10 | #include "CColorConverter.h" | ||
11 | #include "CImage.h" | ||
12 | #include "coreutil.h" | ||
13 | #include "SMeshBuffer.h" | ||
14 | #include "IVideoDriver.h" | ||
15 | #include "IFileSystem.h" | ||
16 | |||
17 | namespace irr | ||
18 | { | ||
19 | namespace scene | ||
20 | { | ||
21 | |||
22 | using namespace video; | ||
23 | |||
24 | void AngleQuaternion(const core::vector3df& angles, vec4_hl quaternion) | ||
25 | { | ||
26 | f32 angle; | ||
27 | f32 sr, sp, sy, cr, cp, cy; | ||
28 | |||
29 | // FIXME: rescale the inputs to 1/2 angle | ||
30 | angle = angles.Z * 0.5f; | ||
31 | sy = sin(angle); | ||
32 | cy = cos(angle); | ||
33 | angle = angles.Y * 0.5f; | ||
34 | sp = sin(angle); | ||
35 | cp = cos(angle); | ||
36 | angle = angles.X * 0.5f; | ||
37 | sr = sin(angle); | ||
38 | cr = cos(angle); | ||
39 | |||
40 | quaternion[0] = sr*cp*cy-cr*sp*sy; // X | ||
41 | quaternion[1] = cr*sp*cy+sr*cp*sy; // Y | ||
42 | quaternion[2] = cr*cp*sy-sr*sp*cy; // Z | ||
43 | quaternion[3] = cr*cp*cy+sr*sp*sy; // W | ||
44 | } | ||
45 | |||
46 | void QuaternionMatrix( const vec4_hl quaternion, f32 (*matrix)[4] ) | ||
47 | { | ||
48 | matrix[0][0] = 1.f - 2.f * quaternion[1] * quaternion[1] - 2.f * quaternion[2] * quaternion[2]; | ||
49 | matrix[1][0] = 2.f * quaternion[0] * quaternion[1] + 2.f * quaternion[3] * quaternion[2]; | ||
50 | matrix[2][0] = 2.f * quaternion[0] * quaternion[2] - 2.f * quaternion[3] * quaternion[1]; | ||
51 | |||
52 | matrix[0][1] = 2.f * quaternion[0] * quaternion[1] - 2.f * quaternion[3] * quaternion[2]; | ||
53 | matrix[1][1] = 1.f - 2.f * quaternion[0] * quaternion[0] - 2.f * quaternion[2] * quaternion[2]; | ||
54 | matrix[2][1] = 2.f * quaternion[1] * quaternion[2] + 2.f * quaternion[3] * quaternion[0]; | ||
55 | |||
56 | matrix[0][2] = 2.f * quaternion[0] * quaternion[2] + 2.f * quaternion[3] * quaternion[1]; | ||
57 | matrix[1][2] = 2.f * quaternion[1] * quaternion[2] - 2.f * quaternion[3] * quaternion[0]; | ||
58 | matrix[2][2] = 1.f - 2.f * quaternion[0] * quaternion[0] - 2.f * quaternion[1] * quaternion[1]; | ||
59 | } | ||
60 | |||
61 | void QuaternionSlerp( const vec4_hl p, vec4_hl q, f32 t, vec4_hl qt ) | ||
62 | { | ||
63 | s32 i; | ||
64 | f32 omega, cosom, sinom, sclp, sclq; | ||
65 | |||
66 | // decide if one of the quaternions is backwards | ||
67 | f32 a = 0; | ||
68 | f32 b = 0; | ||
69 | for (i = 0; i < 4; i++) { | ||
70 | a += (p[i]-q[i])*(p[i]-q[i]); | ||
71 | b += (p[i]+q[i])*(p[i]+q[i]); | ||
72 | } | ||
73 | if (a > b) { | ||
74 | for (i = 0; i < 4; i++) { | ||
75 | q[i] = -q[i]; | ||
76 | } | ||
77 | } | ||
78 | |||
79 | cosom = p[0]*q[0] + p[1]*q[1] + p[2]*q[2] + p[3]*q[3]; | ||
80 | |||
81 | if ((1.f + cosom) > 0.00000001) { | ||
82 | if ((1.f - cosom) > 0.00000001) { | ||
83 | omega = acos( cosom ); | ||
84 | sinom = sin( omega ); | ||
85 | sclp = sin( (1.f - t)*omega) / sinom; | ||
86 | sclq = sin( t*omega ) / sinom; | ||
87 | } | ||
88 | else { | ||
89 | sclp = 1.f - t; | ||
90 | sclq = t; | ||
91 | } | ||
92 | for (i = 0; i < 4; i++) { | ||
93 | qt[i] = sclp * p[i] + sclq * q[i]; | ||
94 | } | ||
95 | } | ||
96 | else { | ||
97 | qt[0] = -p[1]; | ||
98 | qt[1] = p[0]; | ||
99 | qt[2] = -p[3]; | ||
100 | qt[3] = p[2]; | ||
101 | sclp = sin( (1.f - t) * 0.5f * core::PI); | ||
102 | sclq = sin( t * 0.5f * core::PI); | ||
103 | for (i = 0; i < 3; i++) { | ||
104 | qt[i] = sclp * p[i] + sclq * qt[i]; | ||
105 | } | ||
106 | } | ||
107 | } | ||
108 | |||
109 | void R_ConcatTransforms (const f32 in1[3][4], const f32 in2[3][4], f32 out[3][4]) | ||
110 | { | ||
111 | out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0]; | ||
112 | out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + in1[0][2] * in2[2][1]; | ||
113 | out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + in1[0][2] * in2[2][2]; | ||
114 | out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] + in1[0][2] * in2[2][3] + in1[0][3]; | ||
115 | out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + in1[1][2] * in2[2][0]; | ||
116 | out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + in1[1][2] * in2[2][1]; | ||
117 | out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + in1[1][2] * in2[2][2]; | ||
118 | out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] + in1[1][2] * in2[2][3] + in1[1][3]; | ||
119 | out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + in1[2][2] * in2[2][0]; | ||
120 | out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + in1[2][2] * in2[2][1]; | ||
121 | out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + in1[2][2] * in2[2][2]; | ||
122 | out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + in1[2][2] * in2[2][3] + in1[2][3]; | ||
123 | } | ||
124 | |||
125 | #define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]) | ||
126 | |||
127 | inline void VectorTransform(const vec3_hl in1, const f32 in2[3][4], core::vector3df& out) | ||
128 | { | ||
129 | out.X = DotProduct(in1, in2[0]) + in2[0][3]; | ||
130 | out.Z = DotProduct(in1, in2[1]) + in2[1][3]; | ||
131 | out.Y = DotProduct(in1, in2[2]) + in2[2][3]; | ||
132 | } | ||
133 | |||
134 | static f32 BoneTransform[MAXSTUDIOBONES][3][4]; // bone transformation matrix | ||
135 | |||
136 | void getBoneVector ( core::vector3df &out, u32 index ) | ||
137 | { | ||
138 | out.X = BoneTransform[index][0][3]; | ||
139 | out.Z = BoneTransform[index][1][3]; | ||
140 | out.Y = BoneTransform[index][2][3]; | ||
141 | } | ||
142 | |||
143 | void getBoneBox ( core::aabbox3df &box, u32 index, f32 size = 0.5f ) | ||
144 | { | ||
145 | box.MinEdge.X = BoneTransform[index][0][3] - size; | ||
146 | box.MinEdge.Z = BoneTransform[index][1][3] - size; | ||
147 | box.MinEdge.Y = BoneTransform[index][2][3] - size; | ||
148 | |||
149 | size *= 2.f; | ||
150 | box.MaxEdge.X = box.MinEdge.X + size; | ||
151 | box.MaxEdge.Y = box.MinEdge.Y + size; | ||
152 | box.MaxEdge.Z = box.MinEdge.Z + size; | ||
153 | } | ||
154 | |||
155 | void getTransformedBoneVector ( core::vector3df &out, u32 index, const vec3_hl in) | ||
156 | { | ||
157 | out.X = DotProduct(in, BoneTransform[index][0]) + BoneTransform[index][0][3]; | ||
158 | out.Z = DotProduct(in, BoneTransform[index][1]) + BoneTransform[index][1][3]; | ||
159 | out.Y = DotProduct(in, BoneTransform[index][2]) + BoneTransform[index][2][3]; | ||
160 | |||
161 | } | ||
162 | |||
163 | |||
164 | //! Constructor | ||
165 | CHalflifeMDLMeshFileLoader::CHalflifeMDLMeshFileLoader( | ||
166 | scene::ISceneManager* smgr) : SceneManager(smgr) | ||
167 | { | ||
168 | #ifdef _DEBUG | ||
169 | setDebugName("CHalflifeMDLMeshFileLoader"); | ||
170 | #endif | ||
171 | } | ||
172 | |||
173 | |||
174 | //! returns true if the file maybe is able to be loaded by this class | ||
175 | //! based on the file extension (e.g. ".bsp") | ||
176 | bool CHalflifeMDLMeshFileLoader::isALoadableFileExtension(const io::path& filename) const | ||
177 | { | ||
178 | return core::hasFileExtension(filename, "mdl"); | ||
179 | } | ||
180 | |||
181 | |||
182 | //! creates/loads an animated mesh from the file. | ||
183 | //! \return Pointer to the created mesh. Returns 0 if loading failed. | ||
184 | //! If you no longer need the mesh, you should call IAnimatedMesh::drop(). | ||
185 | //! See IReferenceCounted::drop() for more information. | ||
186 | IAnimatedMesh* CHalflifeMDLMeshFileLoader::createMesh(io::IReadFile* file) | ||
187 | { | ||
188 | CAnimatedMeshHalfLife* msh = new CAnimatedMeshHalfLife(); | ||
189 | if (msh) | ||
190 | { | ||
191 | if (msh->loadModelFile(file, SceneManager)) | ||
192 | return msh; | ||
193 | msh->drop(); | ||
194 | } | ||
195 | |||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | |||
200 | //! Constructor | ||
201 | CAnimatedMeshHalfLife::CAnimatedMeshHalfLife() | ||
202 | : FrameCount(0), MeshIPol(0), SceneManager(0), Header(0), TextureHeader(0), | ||
203 | OwnTexModel(false), SequenceIndex(0), CurrentFrame(0), FramesPerSecond(25.f), | ||
204 | SkinGroupSelection(0) | ||
205 | #ifdef HL_TEXTURE_ATLAS | ||
206 | , TextureMaster(0) | ||
207 | #endif | ||
208 | { | ||
209 | #ifdef _DEBUG | ||
210 | setDebugName("CAnimatedMeshHalfLife"); | ||
211 | #endif | ||
212 | initData(); | ||
213 | } | ||
214 | |||
215 | /*! | ||
216 | loads a complete model | ||
217 | */ | ||
218 | bool CAnimatedMeshHalfLife::loadModelFile(io::IReadFile* file, | ||
219 | ISceneManager* smgr) | ||
220 | { | ||
221 | if (!file) | ||
222 | return false; | ||
223 | |||
224 | SceneManager = smgr; | ||
225 | |||
226 | if ( loadModel(file, file->getFileName()) ) | ||
227 | { | ||
228 | if ( postLoadModel ( file->getFileName() ) ) | ||
229 | { | ||
230 | initModel (); | ||
231 | //dumpModelInfo ( 1 ); | ||
232 | return true; | ||
233 | } | ||
234 | } | ||
235 | return false; | ||
236 | } | ||
237 | |||
238 | |||
239 | //! Destructor | ||
240 | CAnimatedMeshHalfLife::~CAnimatedMeshHalfLife() | ||
241 | { | ||
242 | delete [] (u8*) Header; | ||
243 | if (OwnTexModel) | ||
244 | delete [] (u8*) TextureHeader; | ||
245 | |||
246 | for (u32 i = 0; i < 32; ++i) | ||
247 | delete [] (u8*) AnimationHeader[i]; | ||
248 | |||
249 | if (MeshIPol) | ||
250 | MeshIPol->drop(); | ||
251 | } | ||
252 | |||
253 | |||
254 | //! Returns the amount of frames in milliseconds. If the amount is 1, it is a static (=non animated) mesh. | ||
255 | u32 CAnimatedMeshHalfLife::getFrameCount() const | ||
256 | { | ||
257 | return FrameCount; | ||
258 | } | ||
259 | |||
260 | |||
261 | //! set the hardware mapping hint, for driver | ||
262 | void CAnimatedMeshHalfLife::setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint,E_BUFFER_TYPE buffer) | ||
263 | { | ||
264 | } | ||
265 | |||
266 | |||
267 | //! flags the meshbuffer as changed, reloads hardware buffers | ||
268 | void CAnimatedMeshHalfLife::setDirty(E_BUFFER_TYPE buffer) | ||
269 | { | ||
270 | } | ||
271 | |||
272 | |||
273 | static core::vector3df TransformedVerts[MAXSTUDIOVERTS]; // transformed vertices | ||
274 | //static core::vector3df TransformedNormals[MAXSTUDIOVERTS]; // light surface normals | ||
275 | |||
276 | |||
277 | /*! | ||
278 | */ | ||
279 | void CAnimatedMeshHalfLife::initModel() | ||
280 | { | ||
281 | // init Sequences to Animation | ||
282 | KeyFrameInterpolation ipol; | ||
283 | ipol.Name.reserve ( 64 ); | ||
284 | u32 i; | ||
285 | |||
286 | AnimList.clear(); | ||
287 | FrameCount = 0; | ||
288 | |||
289 | SHalflifeSequence *seq = (SHalflifeSequence*) ((u8*) Header + Header->seqindex); | ||
290 | for ( i = 0; i < Header->numseq; i++) | ||
291 | { | ||
292 | ipol.Name = seq[i].label; | ||
293 | ipol.StartFrame = FrameCount; | ||
294 | ipol.Frames = core::max_ ( 1, seq[i].numframes - 1 ); | ||
295 | ipol.EndFrame = ipol.StartFrame + ipol.Frames - 1; | ||
296 | ipol.FramesPerSecond = seq[i].fps; | ||
297 | ipol.AnimationType = seq[i].flags & STUDIO_LOOPING ? EAMT_LOOPING : EAMT_WAYPOINT; | ||
298 | AnimList.push_back ( ipol ); | ||
299 | |||
300 | FrameCount += ipol.Frames; | ||
301 | } | ||
302 | |||
303 | // initBoneControllers | ||
304 | /* | ||
305 | SHalflifeBoneController *bonecontroller = (SHalflifeBoneController *)((u8*) Header + Header->bonecontrollerindex); | ||
306 | for ( i = 0; i < Header->numbonecontrollers; i++) | ||
307 | { | ||
308 | printf ( "BoneController%d index:%d%s range:%f - %f\n", | ||
309 | i, | ||
310 | bonecontroller[i].index, bonecontroller[i].index == MOUTH_CONTROLLER ? " (Mouth)": "", | ||
311 | bonecontroller[i].start,bonecontroller[i].end | ||
312 | ); | ||
313 | } | ||
314 | |||
315 | // initSkins | ||
316 | for (i = 0; i < TextureHeader->numskinfamilies; i++) | ||
317 | { | ||
318 | printf ( "Skin%d\n", i + 1); | ||
319 | } | ||
320 | */ | ||
321 | |||
322 | // initBodyparts | ||
323 | u32 meshBuffer = 0; | ||
324 | BodyList.clear(); | ||
325 | SHalflifeBody *body = (SHalflifeBody *) ((u8*) Header + Header->bodypartindex); | ||
326 | for (i=0; i < Header->numbodyparts; ++i) | ||
327 | { | ||
328 | BodyPart part; | ||
329 | part.name = body[i].name; | ||
330 | part.defaultModel = core::max_ ( 0, (s32) body[i].base - 1 ); | ||
331 | |||
332 | SHalflifeModel * model = (SHalflifeModel *)((u8*) Header + body[i].modelindex); | ||
333 | for ( u32 g = 0; g < body[i].nummodels; ++g) | ||
334 | { | ||
335 | SubModel sub; | ||
336 | sub.name = model[g].name; | ||
337 | sub.startBuffer = meshBuffer; | ||
338 | sub.endBuffer = sub.startBuffer + model[g].nummesh; | ||
339 | sub.state = g == part.defaultModel; | ||
340 | part.model.push_back ( sub ); | ||
341 | meshBuffer += model[g].nummesh; | ||
342 | } | ||
343 | BodyList.push_back ( part ); | ||
344 | } | ||
345 | |||
346 | SequenceIndex = 0; | ||
347 | CurrentFrame = 0.f; | ||
348 | |||
349 | SetController(0, 0.f); | ||
350 | SetController(1, 0.f); | ||
351 | SetController(2, 0.f); | ||
352 | SetController(3, 0.f); | ||
353 | SetController(MOUTH_CONTROLLER, 0.f); | ||
354 | |||
355 | SetSkin (0); | ||
356 | |||
357 | // init Meshbuffers | ||
358 | const SHalflifeTexture *tex = (SHalflifeTexture *) ((u8*) TextureHeader + TextureHeader->textureindex); | ||
359 | const u16 *skinref = (u16 *)((u8*)TextureHeader + TextureHeader->skinindex); | ||
360 | if ((SkinGroupSelection != 0) && (SkinGroupSelection < TextureHeader->numskinfamilies)) | ||
361 | skinref += (SkinGroupSelection * TextureHeader->numskinref); | ||
362 | |||
363 | core::vector2df tex_scale; | ||
364 | core::vector2di tex_trans ( 0, 0 ); | ||
365 | |||
366 | #ifdef HL_TEXTURE_ATLAS | ||
367 | TextureAtlas.getScale(tex_scale); | ||
368 | #endif | ||
369 | |||
370 | for (u32 bodypart=0 ; bodypart < Header->numbodyparts ; ++bodypart) | ||
371 | { | ||
372 | const SHalflifeBody *body = (SHalflifeBody *)((u8*) Header + Header->bodypartindex) + bodypart; | ||
373 | |||
374 | for (u32 modelnr = 0; modelnr < body->nummodels; ++modelnr) | ||
375 | { | ||
376 | const SHalflifeModel *model = (SHalflifeModel *)((u8*) Header + body->modelindex) + modelnr; | ||
377 | #if 0 | ||
378 | const vec3_hl *studioverts = (vec3_hl *)((u8*)Header + model->vertindex); | ||
379 | const vec3_hl *studionorms = (vec3_hl *)((u8*)Header + model->normindex); | ||
380 | #endif | ||
381 | for (i = 0; i < model->nummesh; ++i) | ||
382 | { | ||
383 | const SHalflifeMesh *mesh = (SHalflifeMesh *)((u8*)Header + model->meshindex) + i; | ||
384 | const SHalflifeTexture *currentex = &tex[skinref[mesh->skinref]]; | ||
385 | |||
386 | #ifdef HL_TEXTURE_ATLAS | ||
387 | TextureAtlas.getTranslation ( currentex->name, tex_trans ); | ||
388 | #else | ||
389 | tex_scale.X = 1.f/(f32)currentex->width; | ||
390 | tex_scale.Y = 1.f/(f32)currentex->height; | ||
391 | #endif | ||
392 | |||
393 | SMeshBuffer * buffer = new SMeshBuffer(); | ||
394 | |||
395 | // count index vertex size indexcount = mesh->numtris * 3 | ||
396 | u32 indexCount = 0; | ||
397 | u32 vertexCount = 0; | ||
398 | |||
399 | const s16 *tricmd = (s16*)((u8*)Header + mesh->triindex); | ||
400 | s32 c; | ||
401 | while ( (c = *(tricmd++)) ) | ||
402 | { | ||
403 | if (c < 0) | ||
404 | c = -c; | ||
405 | |||
406 | indexCount += ( c - 2 ) * 3; | ||
407 | vertexCount += c; | ||
408 | tricmd += ( 4 * c ); | ||
409 | } | ||
410 | |||
411 | // indices | ||
412 | buffer->Indices.set_used ( indexCount ); | ||
413 | buffer->Vertices.set_used ( vertexCount ); | ||
414 | |||
415 | // fill in static indices and vertex | ||
416 | u16 *index = buffer->Indices.pointer(); | ||
417 | video::S3DVertex * v = buffer->Vertices.pointer(); | ||
418 | |||
419 | // blow up gl_triangle_fan/gl_triangle_strip to indexed triangle list | ||
420 | E_PRIMITIVE_TYPE type; | ||
421 | vertexCount = 0; | ||
422 | indexCount = 0; | ||
423 | tricmd = (s16*)((u8*)Header + mesh->triindex); | ||
424 | while ( (c = *(tricmd++)) ) | ||
425 | { | ||
426 | if (c < 0) | ||
427 | { | ||
428 | // triangle fan | ||
429 | c = -c; | ||
430 | type = EPT_TRIANGLE_FAN; | ||
431 | } | ||
432 | else | ||
433 | { | ||
434 | type = EPT_TRIANGLE_STRIP; | ||
435 | } | ||
436 | |||
437 | for ( s32 g = 0; g < c; ++g, v += 1, tricmd += 4 ) | ||
438 | { | ||
439 | // fill vertex | ||
440 | #if 0 | ||
441 | const f32 *av = studioverts[tricmd[0]]; | ||
442 | v->Pos.X = av[0]; | ||
443 | v->Pos.Z = av[1]; | ||
444 | v->Pos.Y = av[2]; | ||
445 | |||
446 | av = studionorms[tricmd[1]]; | ||
447 | v->Normal.X = av[0]; | ||
448 | v->Normal.Z = av[1]; | ||
449 | v->Normal.Y = av[2]; | ||
450 | |||
451 | #endif | ||
452 | v->Normal.X = 0.f; | ||
453 | v->Normal.Z = 0.f; | ||
454 | v->Normal.Y = 1.f; | ||
455 | |||
456 | v->TCoords.X = (tex_trans.X + tricmd[2])*tex_scale.X; | ||
457 | v->TCoords.Y = (tex_trans.Y + tricmd[3])*tex_scale.Y; | ||
458 | |||
459 | v->Color.color = 0xFFFFFFFF; | ||
460 | |||
461 | // fill index | ||
462 | if ( g < c - 2 ) | ||
463 | { | ||
464 | if ( type == EPT_TRIANGLE_FAN ) | ||
465 | { | ||
466 | index[indexCount+0] = vertexCount; | ||
467 | index[indexCount+1] = vertexCount+g+1; | ||
468 | index[indexCount+2] = vertexCount+g+2; | ||
469 | } | ||
470 | else | ||
471 | { | ||
472 | if ( g & 1 ) | ||
473 | { | ||
474 | index[indexCount+0] = vertexCount+g+1; | ||
475 | index[indexCount+1] = vertexCount+g+0; | ||
476 | index[indexCount+2] = vertexCount+g+2; | ||
477 | } | ||
478 | else | ||
479 | { | ||
480 | index[indexCount+0] = vertexCount+g+0; | ||
481 | index[indexCount+1] = vertexCount+g+1; | ||
482 | index[indexCount+2] = vertexCount+g+2; | ||
483 | } | ||
484 | } | ||
485 | |||
486 | indexCount += 3; | ||
487 | } | ||
488 | } | ||
489 | |||
490 | vertexCount += c; | ||
491 | } | ||
492 | |||
493 | // material | ||
494 | video::SMaterial &m = buffer->getMaterial(); | ||
495 | |||
496 | m.MaterialType = video::EMT_SOLID; | ||
497 | m.BackfaceCulling = true; | ||
498 | |||
499 | if ( currentex->flags & STUDIO_NF_CHROME ) | ||
500 | { | ||
501 | // don't know what to do with chrome here | ||
502 | } | ||
503 | |||
504 | #ifdef HL_TEXTURE_ATLAS | ||
505 | io::path store = TextureBaseName + "atlas"; | ||
506 | #else | ||
507 | io::path fname; | ||
508 | io::path ext; | ||
509 | core::splitFilename ( currentex->name, 0, &fname, &ext ); | ||
510 | io::path store = TextureBaseName + fname; | ||
511 | #endif | ||
512 | m.TextureLayer[0].Texture = SceneManager->getVideoDriver()->getTexture ( store ); | ||
513 | m.Lighting = false; | ||
514 | |||
515 | MeshIPol->addMeshBuffer(buffer); | ||
516 | buffer->recalculateBoundingBox(); | ||
517 | buffer->drop(); | ||
518 | } // mesh | ||
519 | MeshIPol->recalculateBoundingBox(); | ||
520 | } // model | ||
521 | } // body part | ||
522 | } | ||
523 | |||
524 | |||
525 | /*! | ||
526 | */ | ||
527 | void CAnimatedMeshHalfLife::buildVertices() | ||
528 | { | ||
529 | /* | ||
530 | const u16 *skinref = (u16 *)((u8*)TextureHeader + TextureHeader->skinindex); | ||
531 | if (SkinGroupSelection != 0 && SkinGroupSelection < TextureHeader->numskinfamilies) | ||
532 | skinref += (SkinGroupSelection * TextureHeader->numskinref); | ||
533 | */ | ||
534 | u32 i; | ||
535 | s32 c,g; | ||
536 | const s16 *tricmd; | ||
537 | |||
538 | u32 meshBufferNr = 0; | ||
539 | for ( u32 bodypart = 0 ; bodypart < Header->numbodyparts; ++bodypart) | ||
540 | { | ||
541 | const SHalflifeBody *body = (SHalflifeBody *)((u8*) Header + Header->bodypartindex) + bodypart; | ||
542 | |||
543 | for ( u32 modelnr = 0; modelnr < body->nummodels; ++modelnr ) | ||
544 | { | ||
545 | const SHalflifeModel *model = (SHalflifeModel *)((u8*) Header + body->modelindex) + modelnr; | ||
546 | |||
547 | const u8 *vertbone = ((u8*)Header + model->vertinfoindex); | ||
548 | |||
549 | const vec3_hl *studioverts = (vec3_hl *)((u8*)Header + model->vertindex); | ||
550 | |||
551 | for ( i = 0; i < model->numverts; i++) | ||
552 | { | ||
553 | VectorTransform ( studioverts[i], BoneTransform[vertbone[i]], TransformedVerts[i] ); | ||
554 | } | ||
555 | /* | ||
556 | const u8 *normbone = ((u8*)Header + model->norminfoindex); | ||
557 | const vec3_hl *studionorms = (vec3_hl *)((u8*)Header + model->normindex); | ||
558 | for ( i = 0; i < model->numnorms; i++) | ||
559 | { | ||
560 | VectorTransform ( studionorms[i], BoneTransform[normbone[i]], TransformedNormals[i] ); | ||
561 | } | ||
562 | */ | ||
563 | for (i = 0; i < model->nummesh; i++) | ||
564 | { | ||
565 | const SHalflifeMesh *mesh = (SHalflifeMesh *)((u8*)Header + model->meshindex) + i; | ||
566 | |||
567 | IMeshBuffer * buffer = MeshIPol->getMeshBuffer ( meshBufferNr++ ); | ||
568 | video::S3DVertex* v = (video::S3DVertex* ) buffer->getVertices(); | ||
569 | |||
570 | tricmd = (s16*)((u8*)Header + mesh->triindex); | ||
571 | while ( (c = *(tricmd++)) ) | ||
572 | { | ||
573 | if (c < 0) | ||
574 | c = -c; | ||
575 | |||
576 | for ( g = 0; g < c; ++g, v += 1, tricmd += 4 ) | ||
577 | { | ||
578 | // fill vertex | ||
579 | const core::vector3df& av = TransformedVerts[tricmd[0]]; | ||
580 | v->Pos = av; | ||
581 | /* | ||
582 | const core::vector3df& an = TransformedNormals[tricmd[1]]; | ||
583 | v->Normal = an; | ||
584 | //v->Normal.normalize(); | ||
585 | */ | ||
586 | } | ||
587 | } // tricmd | ||
588 | } // nummesh | ||
589 | } // model | ||
590 | } // bodypart | ||
591 | } | ||
592 | |||
593 | |||
594 | /*! | ||
595 | render Bones | ||
596 | */ | ||
597 | void CAnimatedMeshHalfLife::renderModel(u32 param, IVideoDriver * driver, const core::matrix4 &absoluteTransformation) | ||
598 | { | ||
599 | SHalflifeBone *bone = (SHalflifeBone *) ((u8 *) Header + Header->boneindex); | ||
600 | |||
601 | video::SColor blue(0xFF000080); | ||
602 | video::SColor red(0xFF800000); | ||
603 | video::SColor yellow(0xFF808000); | ||
604 | video::SColor cyan(0xFF008080); | ||
605 | |||
606 | core::aabbox3df box; | ||
607 | |||
608 | u32 i; | ||
609 | for ( i = 0; i < Header->numbones; i++) | ||
610 | { | ||
611 | if (bone[i].parent >= 0) | ||
612 | { | ||
613 | getBoneVector ( box.MinEdge, bone[i].parent ); | ||
614 | getBoneVector ( box.MaxEdge, i ); | ||
615 | driver->draw3DLine ( box.MinEdge, box.MaxEdge, blue ); | ||
616 | |||
617 | // draw parent bone node | ||
618 | if (bone[bone[i].parent].parent >=0 ) | ||
619 | { | ||
620 | getBoneBox ( box, bone[i].parent ); | ||
621 | driver->draw3DBox ( box, blue ); | ||
622 | } | ||
623 | getBoneBox ( box, i ); | ||
624 | driver->draw3DBox ( box, blue ); | ||
625 | } | ||
626 | else | ||
627 | { | ||
628 | // draw parent bone node | ||
629 | getBoneBox ( box, i, 1.f ); | ||
630 | driver->draw3DBox ( box , red ); | ||
631 | } | ||
632 | } | ||
633 | |||
634 | // attachements | ||
635 | SHalflifeAttachment *attach = (SHalflifeAttachment *) ((u8*) Header + Header->attachmentindex); | ||
636 | core::vector3df v[8]; | ||
637 | for ( i = 0; i < Header->numattachments; i++) | ||
638 | { | ||
639 | getTransformedBoneVector ( v[0],attach[i].bone,attach[i].org ); | ||
640 | getTransformedBoneVector ( v[1],attach[i].bone,attach[i].vectors[0] ); | ||
641 | getTransformedBoneVector ( v[2],attach[i].bone,attach[i].vectors[1] ); | ||
642 | getTransformedBoneVector ( v[3],attach[i].bone,attach[i].vectors[2] ); | ||
643 | driver->draw3DLine ( v[0], v[1], cyan ); | ||
644 | driver->draw3DLine ( v[0], v[2], cyan ); | ||
645 | driver->draw3DLine ( v[0], v[3], cyan ); | ||
646 | } | ||
647 | |||
648 | // hit boxes | ||
649 | SHalflifeBBox *hitbox = (SHalflifeBBox *) ((u8*) Header + Header->hitboxindex); | ||
650 | f32 *bbmin,*bbmax; | ||
651 | vec3_hl v2[8]; | ||
652 | for (i = 0; i < Header->numhitboxes; i++) | ||
653 | { | ||
654 | bbmin = hitbox[i].bbmin; | ||
655 | bbmax = hitbox[i].bbmax; | ||
656 | |||
657 | v2[0][0] = bbmin[0]; | ||
658 | v2[0][1] = bbmax[1]; | ||
659 | v2[0][2] = bbmin[2]; | ||
660 | |||
661 | v2[1][0] = bbmin[0]; | ||
662 | v2[1][1] = bbmin[1]; | ||
663 | v2[1][2] = bbmin[2]; | ||
664 | |||
665 | v2[2][0] = bbmax[0]; | ||
666 | v2[2][1] = bbmax[1]; | ||
667 | v2[2][2] = bbmin[2]; | ||
668 | |||
669 | v2[3][0] = bbmax[0]; | ||
670 | v2[3][1] = bbmin[1]; | ||
671 | v2[3][2] = bbmin[2]; | ||
672 | |||
673 | v2[4][0] = bbmax[0]; | ||
674 | v2[4][1] = bbmax[1]; | ||
675 | v2[4][2] = bbmax[2]; | ||
676 | |||
677 | v2[5][0] = bbmax[0]; | ||
678 | v2[5][1] = bbmin[1]; | ||
679 | v2[5][2] = bbmax[2]; | ||
680 | |||
681 | v2[6][0] = bbmin[0]; | ||
682 | v2[6][1] = bbmax[1]; | ||
683 | v2[6][2] = bbmax[2]; | ||
684 | |||
685 | v2[7][0] = bbmin[0]; | ||
686 | v2[7][1] = bbmin[1]; | ||
687 | v2[7][2] = bbmax[2]; | ||
688 | |||
689 | for ( u32 g = 0; g < 8; ++g ) | ||
690 | getTransformedBoneVector ( v[g],hitbox[i].bone,v2[g] ); | ||
691 | |||
692 | driver->draw3DLine(v[0], v[1], yellow); | ||
693 | driver->draw3DLine(v[1], v[3], yellow); | ||
694 | driver->draw3DLine(v[3], v[2], yellow); | ||
695 | driver->draw3DLine(v[2], v[0], yellow); | ||
696 | |||
697 | driver->draw3DLine(v[4], v[5], yellow); | ||
698 | driver->draw3DLine(v[5], v[7], yellow); | ||
699 | driver->draw3DLine(v[7], v[6], yellow); | ||
700 | driver->draw3DLine(v[6], v[4], yellow); | ||
701 | |||
702 | driver->draw3DLine(v[0], v[6], yellow); | ||
703 | driver->draw3DLine(v[1], v[7], yellow); | ||
704 | driver->draw3DLine(v[3], v[5], yellow); | ||
705 | driver->draw3DLine(v[2], v[4], yellow); | ||
706 | } | ||
707 | } | ||
708 | |||
709 | |||
710 | //! Returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail. | ||
711 | IMesh* CAnimatedMeshHalfLife::getMesh(s32 frameInt, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop) | ||
712 | { | ||
713 | f32 frame = frameInt + (detailLevel * 0.001f); | ||
714 | u32 frameA = core::floor32 ( frame ); | ||
715 | // f32 blend = core::fract ( frame ); | ||
716 | |||
717 | SHalflifeSequence *seq = (SHalflifeSequence*) ((u8*) Header + Header->seqindex); | ||
718 | |||
719 | // find SequenceIndex from summed list | ||
720 | u32 frameCount = 0; | ||
721 | for (u32 i = 0; i < Header->numseq; ++i) | ||
722 | { | ||
723 | u32 val = core::max_ ( 1, seq[i].numframes - 1 ); | ||
724 | if ( frameCount + val > frameA ) | ||
725 | { | ||
726 | SequenceIndex = i; | ||
727 | CurrentFrame = frame - frameCount; | ||
728 | break; | ||
729 | } | ||
730 | frameCount += val; | ||
731 | } | ||
732 | |||
733 | seq += SequenceIndex; | ||
734 | |||
735 | //SetBodyPart ( 1, 1 ); | ||
736 | setUpBones (); | ||
737 | buildVertices(); | ||
738 | |||
739 | MeshIPol->BoundingBox.MinEdge.X = seq->bbmin[0]; | ||
740 | MeshIPol->BoundingBox.MinEdge.Z = seq->bbmin[1]; | ||
741 | MeshIPol->BoundingBox.MinEdge.Y = seq->bbmin[2]; | ||
742 | |||
743 | MeshIPol->BoundingBox.MaxEdge.X = seq->bbmax[0]; | ||
744 | MeshIPol->BoundingBox.MaxEdge.Z = seq->bbmax[1]; | ||
745 | MeshIPol->BoundingBox.MaxEdge.Y = seq->bbmax[2]; | ||
746 | |||
747 | return MeshIPol; | ||
748 | } | ||
749 | |||
750 | |||
751 | /*! | ||
752 | */ | ||
753 | void CAnimatedMeshHalfLife::initData () | ||
754 | { | ||
755 | u32 i; | ||
756 | |||
757 | Header = 0; | ||
758 | TextureHeader = 0; | ||
759 | OwnTexModel = false; | ||
760 | |||
761 | for ( i = 0; i < 32; ++i ) | ||
762 | AnimationHeader[i] = 0; | ||
763 | |||
764 | SequenceIndex = 0; | ||
765 | CurrentFrame = 0.f; | ||
766 | |||
767 | for ( i = 0; i < 5; ++i ) | ||
768 | BoneController[i] = 0; | ||
769 | |||
770 | for ( i = 0; i < 2; ++i ) | ||
771 | Blending[i] = 0; | ||
772 | |||
773 | SkinGroupSelection = 0; | ||
774 | |||
775 | AnimList.clear(); | ||
776 | FrameCount = 0; | ||
777 | |||
778 | if (!MeshIPol) | ||
779 | MeshIPol = new SMesh(); | ||
780 | MeshIPol->clear(); | ||
781 | |||
782 | #ifdef HL_TEXTURE_ATLAS | ||
783 | TextureAtlas.release(); | ||
784 | #endif | ||
785 | } | ||
786 | |||
787 | |||
788 | /*! | ||
789 | */ | ||
790 | void STextureAtlas::release() | ||
791 | { | ||
792 | for (u32 i = 0; i < atlas.size(); i++) | ||
793 | { | ||
794 | if ( atlas[i].image ) | ||
795 | { | ||
796 | atlas[i].image->drop(); | ||
797 | atlas[i].image = 0; | ||
798 | } | ||
799 | } | ||
800 | Master = 0; | ||
801 | } | ||
802 | |||
803 | |||
804 | /*! | ||
805 | */ | ||
806 | void STextureAtlas::addSource ( const c8 * name, video::IImage * image ) | ||
807 | { | ||
808 | TextureAtlasEntry entry; | ||
809 | entry.name = name; | ||
810 | entry.image = image; | ||
811 | entry.width = image->getDimension().Width; | ||
812 | entry.height = image->getDimension().Height; | ||
813 | entry.pos.X = 0; | ||
814 | entry.pos.Y = 0; | ||
815 | atlas.push_back ( entry ); | ||
816 | } | ||
817 | |||
818 | |||
819 | /*! | ||
820 | */ | ||
821 | void STextureAtlas::getScale(core::vector2df& scale) | ||
822 | { | ||
823 | for (s32 i = static_cast<s32>(atlas.size()) - 1; i >= 0; --i) | ||
824 | { | ||
825 | if ( atlas[i].name == "_merged_" ) | ||
826 | { | ||
827 | scale.X = 1.f / atlas[i].width; | ||
828 | scale.Y = 1.f / atlas[i].height; | ||
829 | return; | ||
830 | } | ||
831 | } | ||
832 | scale.X = 1.f; | ||
833 | scale.Y = 1.f; | ||
834 | } | ||
835 | |||
836 | |||
837 | /*! | ||
838 | */ | ||
839 | void STextureAtlas::getTranslation(const c8* name, core::vector2di& pos) | ||
840 | { | ||
841 | for ( u32 i = 0; i < atlas.size(); ++i) | ||
842 | { | ||
843 | if ( atlas[i].name == name ) | ||
844 | { | ||
845 | pos = atlas[i].pos; | ||
846 | return; | ||
847 | } | ||
848 | } | ||
849 | } | ||
850 | |||
851 | |||
852 | /*! | ||
853 | */ | ||
854 | void STextureAtlas::create(u32 border, E_TEXTURE_CLAMP texmode) | ||
855 | { | ||
856 | u32 i = 0; | ||
857 | u32 w = 0; | ||
858 | u32 w2; | ||
859 | u32 h2; | ||
860 | u32 h; | ||
861 | u32 wsum; | ||
862 | u32 hsum = 0; | ||
863 | ECOLOR_FORMAT format = ECF_R8G8B8; | ||
864 | |||
865 | const s32 frame = core::s32_max ( 0, (border - 1 ) / 2 ); | ||
866 | |||
867 | // sort for biggest coming first | ||
868 | atlas.sort(); | ||
869 | |||
870 | // split size | ||
871 | wsum = frame; | ||
872 | for (i = 0; i < atlas.size(); i++) | ||
873 | { | ||
874 | // make space | ||
875 | w2 = atlas[i].width + border; | ||
876 | |||
877 | // align | ||
878 | w2 = (w2 + 1) & ~1; | ||
879 | wsum += w2; | ||
880 | } | ||
881 | u32 splitsize = 256; | ||
882 | if ( wsum > 512 ) | ||
883 | splitsize = 512; | ||
884 | |||
885 | wsum = frame; | ||
886 | hsum = frame; | ||
887 | w = frame; | ||
888 | h = 0; | ||
889 | for (i = 0; i < atlas.size(); i++) | ||
890 | { | ||
891 | if ( atlas[i].image->getColorFormat() == ECF_A8R8G8B8 ) | ||
892 | { | ||
893 | format = ECF_A8R8G8B8; | ||
894 | } | ||
895 | |||
896 | // make space | ||
897 | w2 = atlas[i].width + border; | ||
898 | h2 = atlas[i].height + border; | ||
899 | |||
900 | // align | ||
901 | w2 = (w2 + 1) & ~1; | ||
902 | h2 = (h2 + 1) & ~1; | ||
903 | |||
904 | h = core::s32_max ( h, h2 ); | ||
905 | |||
906 | if ( w + w2 >= splitsize ) | ||
907 | { | ||
908 | hsum += h; | ||
909 | wsum = core::s32_max ( wsum, w ); | ||
910 | h = h2; | ||
911 | w = frame; | ||
912 | } | ||
913 | |||
914 | atlas[i].pos.X = w; | ||
915 | atlas[i].pos.Y = hsum; | ||
916 | |||
917 | w += w2; | ||
918 | |||
919 | } | ||
920 | hsum += h; | ||
921 | wsum = core::s32_max ( wsum, w ); | ||
922 | |||
923 | // build image | ||
924 | core::dimension2d<u32> dim = core::dimension2d<u32>( wsum, hsum ).getOptimalSize(); | ||
925 | IImage* master = new CImage(format, dim); | ||
926 | master->fill(0); | ||
927 | |||
928 | video::SColor col[2]; | ||
929 | |||
930 | static const u8 wrap[][4] = | ||
931 | { | ||
932 | {1, 0}, // ETC_REPEAT | ||
933 | {0, 1}, // ETC_CLAMP | ||
934 | {0, 1}, // ETC_CLAMP_TO_EDGE | ||
935 | {0, 1} // ETC_MIRROR | ||
936 | }; | ||
937 | |||
938 | s32 a,b; | ||
939 | for (i = 0; i < atlas.size(); i++) | ||
940 | { | ||
941 | atlas[i].image->copyTo ( master, atlas[i].pos ); | ||
942 | |||
943 | // clamp/wrap ( copy edges, filtering needs it ) | ||
944 | |||
945 | for ( b = 0; b < frame; ++b ) | ||
946 | { | ||
947 | for ( a = 0 - b; a <= (s32) atlas[i].width + b; ++a ) | ||
948 | { | ||
949 | col[0] = atlas[i].image->getPixel ( core::s32_clamp ( a, 0, atlas[i].width - 1 ), 0 ); | ||
950 | col[1] = atlas[i].image->getPixel ( core::s32_clamp ( a, 0, atlas[i].width - 1 ), atlas[i].height - 1 ); | ||
951 | |||
952 | master->setPixel ( atlas[i].pos.X + a, atlas[i].pos.Y + ( b + 1 ) * -1, col[wrap[texmode][0]] ); | ||
953 | master->setPixel ( atlas[i].pos.X + a, atlas[i].pos.Y + atlas[i].height - 1 + ( b + 1 ) * 1, col[wrap[texmode][1]] ); | ||
954 | } | ||
955 | |||
956 | for ( a = -1 - b; a <= (s32) atlas[i].height + b; ++a ) | ||
957 | { | ||
958 | col[0] = atlas[i].image->getPixel ( 0, core::s32_clamp ( a, 0, atlas[i].height - 1 ) ); | ||
959 | col[1] = atlas[i].image->getPixel ( atlas[i].width - 1, core::s32_clamp ( a, 0, atlas[i].height - 1 ) ); | ||
960 | |||
961 | master->setPixel ( atlas[i].pos.X + ( b + 1 ) * -1, atlas[i].pos.Y + a, col[wrap[texmode][0]] ); | ||
962 | master->setPixel ( atlas[i].pos.X + atlas[i].width + b, atlas[i].pos.Y + a, col[wrap[texmode][1]] ); | ||
963 | } | ||
964 | } | ||
965 | } | ||
966 | |||
967 | addSource ( "_merged_", master ); | ||
968 | Master = master; | ||
969 | } | ||
970 | |||
971 | |||
972 | /*! | ||
973 | */ | ||
974 | SHalflifeHeader* CAnimatedMeshHalfLife::loadModel(io::IReadFile* file, const io::path& filename) | ||
975 | { | ||
976 | bool closefile = false; | ||
977 | |||
978 | // if secondary files are needed, open here and mark for closing | ||
979 | if ( 0 == file ) | ||
980 | { | ||
981 | file = SceneManager->getFileSystem()->createAndOpenFile(filename); | ||
982 | closefile = true; | ||
983 | } | ||
984 | |||
985 | if ( 0 == file ) | ||
986 | return 0; | ||
987 | |||
988 | // read into memory | ||
989 | u8* pin = new u8[file->getSize()]; | ||
990 | file->read(pin, file->getSize()); | ||
991 | |||
992 | SHalflifeHeader* header = (SHalflifeHeader*) pin; | ||
993 | |||
994 | const bool idst = (0 == strncmp(header->id, "IDST", 4)); | ||
995 | const bool idsq = (0 == strncmp(header->id, "IDSQ", 4)); | ||
996 | |||
997 | if ( (!idst && !idsq) || (idsq && !Header) ) | ||
998 | { | ||
999 | os::Printer::log("MDL Halflife Loader: Wrong file header", file->getFileName(), ELL_WARNING); | ||
1000 | if ( closefile ) | ||
1001 | { | ||
1002 | file->drop(); | ||
1003 | file = 0; | ||
1004 | } | ||
1005 | delete [] pin; | ||
1006 | return 0; | ||
1007 | } | ||
1008 | |||
1009 | // don't know the real header.. idsg might be different | ||
1010 | if (header->textureindex && idst ) | ||
1011 | { | ||
1012 | io::path path; | ||
1013 | io::path fname; | ||
1014 | io::path ext; | ||
1015 | |||
1016 | core::splitFilename(file->getFileName(), &path, &fname, &ext); | ||
1017 | TextureBaseName = path + fname + "_"; | ||
1018 | |||
1019 | SHalflifeTexture *tex = (SHalflifeTexture *)(pin + header->textureindex); | ||
1020 | u32 *palette = new u32[256]; | ||
1021 | for (u32 i = 0; i < header->numtextures; ++i) | ||
1022 | { | ||
1023 | const u8 *src = pin + tex[i].index; | ||
1024 | |||
1025 | // convert rgb to argb palette | ||
1026 | { | ||
1027 | const u8 *pal = src + tex[i].width * tex[i].height; | ||
1028 | for( u32 g=0; g<256; ++g ) | ||
1029 | { | ||
1030 | palette[g] = 0xFF000000 | pal[0] << 16 | pal[1] << 8 | pal[2]; | ||
1031 | pal += 3; | ||
1032 | } | ||
1033 | } | ||
1034 | |||
1035 | IImage* image = SceneManager->getVideoDriver()->createImage(ECF_R8G8B8, core::dimension2d<u32>(tex[i].width, tex[i].height)); | ||
1036 | |||
1037 | CColorConverter::convert8BitTo24Bit(src, (u8*)image->lock(), tex[i].width, tex[i].height, (u8*) palette, 0, false); | ||
1038 | image->unlock(); | ||
1039 | |||
1040 | #ifdef HL_TEXTURE_ATLAS | ||
1041 | TextureAtlas.addSource ( tex[i].name, image ); | ||
1042 | #else | ||
1043 | core::splitFilename ( tex[i].name, 0, &fname, &ext ); | ||
1044 | SceneManager->getVideoDriver()->addTexture ( TextureBaseName + fname, image ); | ||
1045 | image->drop(); | ||
1046 | #endif | ||
1047 | } | ||
1048 | delete [] palette; | ||
1049 | |||
1050 | #ifdef HL_TEXTURE_ATLAS | ||
1051 | TextureAtlas.create ( 2 * 2 + 1, ETC_CLAMP ); | ||
1052 | SceneManager->getVideoDriver()->addTexture ( TextureBaseName + "atlas", TextureAtlas.Master ); | ||
1053 | TextureAtlas.release(); | ||
1054 | #endif | ||
1055 | } | ||
1056 | |||
1057 | if (!Header) | ||
1058 | Header = header; | ||
1059 | |||
1060 | if ( closefile ) | ||
1061 | { | ||
1062 | file->drop(); | ||
1063 | file = 0; | ||
1064 | } | ||
1065 | |||
1066 | return header; | ||
1067 | } | ||
1068 | |||
1069 | |||
1070 | /*! | ||
1071 | */ | ||
1072 | f32 CAnimatedMeshHalfLife::SetController( s32 controllerIndex, f32 value ) | ||
1073 | { | ||
1074 | if (!Header) | ||
1075 | return 0.f; | ||
1076 | |||
1077 | SHalflifeBoneController *bonecontroller = (SHalflifeBoneController *)((u8*) Header + Header->bonecontrollerindex); | ||
1078 | |||
1079 | // find first controller that matches the index | ||
1080 | u32 i; | ||
1081 | for (i = 0; i < Header->numbonecontrollers; i++, bonecontroller++) | ||
1082 | { | ||
1083 | if (bonecontroller->index == controllerIndex) | ||
1084 | break; | ||
1085 | } | ||
1086 | if (i >= Header->numbonecontrollers) | ||
1087 | return value; | ||
1088 | |||
1089 | // wrap 0..360 if it's a rotational controller | ||
1090 | if (bonecontroller->type & (STUDIO_XR | STUDIO_YR | STUDIO_ZR)) | ||
1091 | { | ||
1092 | // ugly hack, invert value if end < start | ||
1093 | if (bonecontroller->end < bonecontroller->start) | ||
1094 | value = -value; | ||
1095 | |||
1096 | // does the controller not wrap? | ||
1097 | if (bonecontroller->start + 359.f >= bonecontroller->end) | ||
1098 | { | ||
1099 | if (value > ((bonecontroller->start + bonecontroller->end) / 2.f) + 180.f) | ||
1100 | value = value - 360.f; | ||
1101 | if (value < ((bonecontroller->start + bonecontroller->end) / 2.f) - 180.f) | ||
1102 | value = value + 360.f; | ||
1103 | } | ||
1104 | else | ||
1105 | { | ||
1106 | if (value > 360.f) | ||
1107 | value = value - (s32)(value / 360.f) * 360.f; | ||
1108 | else if (value < 0.f) | ||
1109 | value = value + (s32)((value / -360.f) + 1) * 360.f; | ||
1110 | } | ||
1111 | } | ||
1112 | |||
1113 | s32 range = controllerIndex == MOUTH_CONTROLLER ? 64 : 255; | ||
1114 | |||
1115 | s32 setting = (s32) ( (f32) range * (value - bonecontroller->start) / (bonecontroller->end - bonecontroller->start)); | ||
1116 | |||
1117 | if (setting < 0) setting = 0; | ||
1118 | if (setting > range) setting = range; | ||
1119 | |||
1120 | BoneController[controllerIndex] = setting; | ||
1121 | |||
1122 | return setting * (1.f / (f32) range ) * (bonecontroller->end - bonecontroller->start) + bonecontroller->start; | ||
1123 | } | ||
1124 | |||
1125 | |||
1126 | /*! | ||
1127 | */ | ||
1128 | u32 CAnimatedMeshHalfLife::SetSkin( u32 value ) | ||
1129 | { | ||
1130 | if (value < Header->numskinfamilies) | ||
1131 | SkinGroupSelection = value; | ||
1132 | |||
1133 | return SkinGroupSelection; | ||
1134 | } | ||
1135 | |||
1136 | |||
1137 | /*! | ||
1138 | */ | ||
1139 | bool CAnimatedMeshHalfLife::postLoadModel( const io::path &filename ) | ||
1140 | { | ||
1141 | io::path path; | ||
1142 | io::path texname; | ||
1143 | io::path submodel; | ||
1144 | |||
1145 | core::splitFilename ( filename ,&path, &texname, 0 ); | ||
1146 | |||
1147 | // preload textures | ||
1148 | // if no textures are stored in main file, use texfile | ||
1149 | if (Header->numtextures == 0) | ||
1150 | { | ||
1151 | submodel = path + texname + "T.mdl"; | ||
1152 | TextureHeader = loadModel(0, submodel); | ||
1153 | if (!TextureHeader) | ||
1154 | return false; | ||
1155 | OwnTexModel = true; | ||
1156 | } | ||
1157 | else | ||
1158 | { | ||
1159 | TextureHeader = Header; | ||
1160 | OwnTexModel = false; | ||
1161 | } | ||
1162 | |||
1163 | // preload animations | ||
1164 | if (Header->numseqgroups > 1) | ||
1165 | { | ||
1166 | c8 seq[8]; | ||
1167 | for (u32 i = 1; i < Header->numseqgroups; i++) | ||
1168 | { | ||
1169 | snprintf( seq, 8, "%02d.mdl", i ); | ||
1170 | submodel = path + texname + seq; | ||
1171 | |||
1172 | AnimationHeader[i] = loadModel(0, submodel); | ||
1173 | if (!AnimationHeader[i]) | ||
1174 | return false; | ||
1175 | } | ||
1176 | } | ||
1177 | |||
1178 | return true; | ||
1179 | } | ||
1180 | |||
1181 | |||
1182 | /*! | ||
1183 | */ | ||
1184 | void CAnimatedMeshHalfLife::dumpModelInfo(u32 level) const | ||
1185 | { | ||
1186 | const u8 *phdr = (const u8*) Header; | ||
1187 | const SHalflifeHeader * hdr = Header; | ||
1188 | u32 i; | ||
1189 | |||
1190 | if (level == 0) | ||
1191 | { | ||
1192 | printf ( | ||
1193 | "Bones: %d\n" | ||
1194 | "Bone Controllers: %d\n" | ||
1195 | "Hit Boxes: %d\n" | ||
1196 | "Sequences: %d\n" | ||
1197 | "Sequence Groups: %d\n", | ||
1198 | hdr->numbones, | ||
1199 | hdr->numbonecontrollers, | ||
1200 | hdr->numhitboxes, | ||
1201 | hdr->numseq, | ||
1202 | hdr->numseqgroups | ||
1203 | ); | ||
1204 | printf ( | ||
1205 | "Textures: %d\n" | ||
1206 | "Skin Families: %d\n" | ||
1207 | "Bodyparts: %d\n" | ||
1208 | "Attachments: %d\n" | ||
1209 | "Transitions: %d\n", | ||
1210 | hdr->numtextures, | ||
1211 | hdr->numskinfamilies, | ||
1212 | hdr->numbodyparts, | ||
1213 | hdr->numattachments, | ||
1214 | hdr->numtransitions); | ||
1215 | return; | ||
1216 | } | ||
1217 | |||
1218 | printf("id: %c%c%c%c\n", phdr[0], phdr[1], phdr[2], phdr[3]); | ||
1219 | printf("version: %d\n", hdr->version); | ||
1220 | printf("name: \"%s\"\n", hdr->name); | ||
1221 | printf("length: %d\n\n", hdr->length); | ||
1222 | |||
1223 | printf("eyeposition: %f %f %f\n", hdr->eyeposition[0], hdr->eyeposition[1], hdr->eyeposition[2]); | ||
1224 | printf("min: %f %f %f\n", hdr->min[0], hdr->min[1], hdr->min[2]); | ||
1225 | printf("max: %f %f %f\n", hdr->max[0], hdr->max[1], hdr->max[2]); | ||
1226 | printf("bbmin: %f %f %f\n", hdr->bbmin[0], hdr->bbmin[1], hdr->bbmin[2]); | ||
1227 | printf("bbmax: %f %f %f\n", hdr->bbmax[0], hdr->bbmax[1], hdr->bbmax[2]); | ||
1228 | |||
1229 | printf("flags: %d\n\n", hdr->flags); | ||
1230 | |||
1231 | printf("numbones: %d\n", hdr->numbones); | ||
1232 | for (i = 0; i < hdr->numbones; i++) | ||
1233 | { | ||
1234 | const SHalflifeBone *bone = (const SHalflifeBone *) (phdr + hdr->boneindex); | ||
1235 | printf("bone %d.name: \"%s\"\n", i + 1, bone[i].name); | ||
1236 | printf("bone %d.parent: %d\n", i + 1, bone[i].parent); | ||
1237 | printf("bone %d.flags: %d\n", i + 1, bone[i].flags); | ||
1238 | printf("bone %d.bonecontroller: %d %d %d %d %d %d\n", i + 1, bone[i].bonecontroller[0], bone[i].bonecontroller[1], bone[i].bonecontroller[2], bone[i].bonecontroller[3], bone[i].bonecontroller[4], bone[i].bonecontroller[5]); | ||
1239 | printf("bone %d.value: %f %f %f %f %f %f\n", i + 1, bone[i].value[0], bone[i].value[1], bone[i].value[2], bone[i].value[3], bone[i].value[4], bone[i].value[5]); | ||
1240 | printf("bone %d.scale: %f %f %f %f %f %f\n", i + 1, bone[i].scale[0], bone[i].scale[1], bone[i].scale[2], bone[i].scale[3], bone[i].scale[4], bone[i].scale[5]); | ||
1241 | } | ||
1242 | |||
1243 | printf("\nnumbonecontrollers: %d\n", hdr->numbonecontrollers); | ||
1244 | const SHalflifeBoneController *bonecontrollers = (const SHalflifeBoneController *) (phdr + hdr->bonecontrollerindex); | ||
1245 | for (i = 0; i < hdr->numbonecontrollers; i++) | ||
1246 | { | ||
1247 | printf("bonecontroller %d.bone: %d\n", i + 1, bonecontrollers[i].bone); | ||
1248 | printf("bonecontroller %d.type: %d\n", i + 1, bonecontrollers[i].type); | ||
1249 | printf("bonecontroller %d.start: %f\n", i + 1, bonecontrollers[i].start); | ||
1250 | printf("bonecontroller %d.end: %f\n", i + 1, bonecontrollers[i].end); | ||
1251 | printf("bonecontroller %d.rest: %d\n", i + 1, bonecontrollers[i].rest); | ||
1252 | printf("bonecontroller %d.index: %d\n", i + 1, bonecontrollers[i].index); | ||
1253 | } | ||
1254 | |||
1255 | printf("\nnumhitboxes: %d\n", hdr->numhitboxes); | ||
1256 | const SHalflifeBBox *box = (const SHalflifeBBox *) (phdr + hdr->hitboxindex); | ||
1257 | for (i = 0; i < hdr->numhitboxes; i++) | ||
1258 | { | ||
1259 | printf("hitbox %d.bone: %d\n", i + 1, box[i].bone); | ||
1260 | printf("hitbox %d.group: %d\n", i + 1, box[i].group); | ||
1261 | printf("hitbox %d.bbmin: %f %f %f\n", i + 1, box[i].bbmin[0], box[i].bbmin[1], box[i].bbmin[2]); | ||
1262 | printf("hitbox %d.bbmax: %f %f %f\n", i + 1, box[i].bbmax[0], box[i].bbmax[1], box[i].bbmax[2]); | ||
1263 | } | ||
1264 | |||
1265 | printf("\nnumseq: %d\n", hdr->numseq); | ||
1266 | const SHalflifeSequence *seq = (const SHalflifeSequence *) (phdr + hdr->seqindex); | ||
1267 | for (i = 0; i < hdr->numseq; i++) | ||
1268 | { | ||
1269 | printf("seqdesc %d.label: \"%s\"\n", i + 1, seq[i].label); | ||
1270 | printf("seqdesc %d.fps: %f\n", i + 1, seq[i].fps); | ||
1271 | printf("seqdesc %d.flags: %d\n", i + 1, seq[i].flags); | ||
1272 | printf("<...>\n"); | ||
1273 | } | ||
1274 | |||
1275 | printf("\nnumseqgroups: %d\n", hdr->numseqgroups); | ||
1276 | for (i = 0; i < hdr->numseqgroups; i++) | ||
1277 | { | ||
1278 | const SHalflifeSequenceGroup *group = (const SHalflifeSequenceGroup *) (phdr + hdr->seqgroupindex); | ||
1279 | printf("\nseqgroup %d.label: \"%s\"\n", i + 1, group[i].label); | ||
1280 | printf("\nseqgroup %d.namel: \"%s\"\n", i + 1, group[i].name); | ||
1281 | printf("\nseqgroup %d.data: %d\n", i + 1, group[i].data); | ||
1282 | } | ||
1283 | |||
1284 | printf("\nnumskinref: %d\n", hdr->numskinref); | ||
1285 | printf("numskinfamilies: %d\n", hdr->numskinfamilies); | ||
1286 | |||
1287 | printf("\nnumbodyparts: %d\n", hdr->numbodyparts); | ||
1288 | const SHalflifeBody *pbodyparts = (const SHalflifeBody*) ((const u8*) hdr + hdr->bodypartindex); | ||
1289 | for (i = 0; i < hdr->numbodyparts; i++) | ||
1290 | { | ||
1291 | printf("bodypart %d.name: \"%s\"\n", i + 1, pbodyparts[i].name); | ||
1292 | printf("bodypart %d.nummodels: %d\n", i + 1, pbodyparts[i].nummodels); | ||
1293 | printf("bodypart %d.base: %d\n", i + 1, pbodyparts[i].base); | ||
1294 | printf("bodypart %d.modelindex: %d\n", i + 1, pbodyparts[i].modelindex); | ||
1295 | } | ||
1296 | |||
1297 | printf("\nnumattachments: %d\n", hdr->numattachments); | ||
1298 | for (i = 0; i < hdr->numattachments; i++) | ||
1299 | { | ||
1300 | const SHalflifeAttachment *attach = (const SHalflifeAttachment *) ((const u8*) hdr + hdr->attachmentindex); | ||
1301 | printf("attachment %d.name: \"%s\"\n", i + 1, attach[i].name); | ||
1302 | } | ||
1303 | |||
1304 | hdr = TextureHeader; | ||
1305 | printf("\nnumtextures: %d\n", hdr->numtextures); | ||
1306 | printf("textureindex: %d\n", hdr->textureindex); | ||
1307 | printf("texturedataindex: %d\n", hdr->texturedataindex); | ||
1308 | const SHalflifeTexture *ptextures = (const SHalflifeTexture *) ((const u8*) hdr + hdr->textureindex); | ||
1309 | for (i = 0; i < hdr->numtextures; i++) | ||
1310 | { | ||
1311 | printf("texture %d.name: \"%s\"\n", i + 1, ptextures[i].name); | ||
1312 | printf("texture %d.flags: %d\n", i + 1, ptextures[i].flags); | ||
1313 | printf("texture %d.width: %d\n", i + 1, ptextures[i].width); | ||
1314 | printf("texture %d.height: %d\n", i + 1, ptextures[i].height); | ||
1315 | printf("texture %d.index: %d\n", i + 1, ptextures[i].index); | ||
1316 | } | ||
1317 | } | ||
1318 | |||
1319 | |||
1320 | /*! | ||
1321 | */ | ||
1322 | void CAnimatedMeshHalfLife::ExtractBbox(s32 sequence, core::aabbox3df &box) const | ||
1323 | { | ||
1324 | const SHalflifeSequence *seq = (const SHalflifeSequence *)((const u8*)Header + Header->seqindex) + sequence; | ||
1325 | |||
1326 | box.MinEdge.X = seq[0].bbmin[0]; | ||
1327 | box.MinEdge.Y = seq[0].bbmin[1]; | ||
1328 | box.MinEdge.Z = seq[0].bbmin[2]; | ||
1329 | |||
1330 | box.MaxEdge.X = seq[0].bbmax[0]; | ||
1331 | box.MaxEdge.Y = seq[0].bbmax[1]; | ||
1332 | box.MaxEdge.Z = seq[0].bbmax[2]; | ||
1333 | } | ||
1334 | |||
1335 | |||
1336 | /*! | ||
1337 | */ | ||
1338 | void CAnimatedMeshHalfLife::calcBoneAdj() | ||
1339 | { | ||
1340 | const SHalflifeBoneController *bonecontroller = | ||
1341 | (const SHalflifeBoneController *)((const u8*) Header + Header->bonecontrollerindex); | ||
1342 | |||
1343 | for (u32 j = 0; j < Header->numbonecontrollers; j++) | ||
1344 | { | ||
1345 | const s32 i = bonecontroller[j].index; | ||
1346 | // check for 360% wrapping | ||
1347 | f32 value; | ||
1348 | if (bonecontroller[j].type & STUDIO_RLOOP) | ||
1349 | { | ||
1350 | value = BoneController[i] * (360.f/256.f) + bonecontroller[j].start; | ||
1351 | } | ||
1352 | else | ||
1353 | { | ||
1354 | const f32 range = i <= 3 ? 255.f : 64.f; | ||
1355 | value = core::clamp(BoneController[i] / range,0.f,1.f); | ||
1356 | value = (1.f - value) * bonecontroller[j].start + value * bonecontroller[j].end; | ||
1357 | } | ||
1358 | |||
1359 | switch(bonecontroller[j].type & STUDIO_TYPES) | ||
1360 | { | ||
1361 | case STUDIO_XR: | ||
1362 | case STUDIO_YR: | ||
1363 | case STUDIO_ZR: | ||
1364 | BoneAdj[j] = value * core::DEGTORAD; | ||
1365 | break; | ||
1366 | case STUDIO_X: | ||
1367 | case STUDIO_Y: | ||
1368 | case STUDIO_Z: | ||
1369 | BoneAdj[j] = value; | ||
1370 | break; | ||
1371 | } | ||
1372 | } | ||
1373 | } | ||
1374 | |||
1375 | |||
1376 | /*! | ||
1377 | */ | ||
1378 | void CAnimatedMeshHalfLife::calcBoneQuaternion(const s32 frame, const SHalflifeBone * const bone, | ||
1379 | SHalflifeAnimOffset *anim, const u32 j, f32& angle1, f32& angle2) const | ||
1380 | { | ||
1381 | // three vector components | ||
1382 | if (anim->offset[j+3] == 0) | ||
1383 | { | ||
1384 | angle2 = angle1 = bone->value[j+3]; // default | ||
1385 | } | ||
1386 | else | ||
1387 | { | ||
1388 | SHalflifeAnimationFrame *animvalue = (SHalflifeAnimationFrame *)((u8*)anim + anim->offset[j+3]); | ||
1389 | s32 k = frame; | ||
1390 | while (animvalue->num.total <= k) | ||
1391 | { | ||
1392 | k -= animvalue->num.total; | ||
1393 | animvalue += animvalue->num.valid + 1; | ||
1394 | } | ||
1395 | // Bah, missing blend! | ||
1396 | if (animvalue->num.valid > k) | ||
1397 | { | ||
1398 | angle1 = animvalue[k+1].value; | ||
1399 | |||
1400 | if (animvalue->num.valid > k + 1) | ||
1401 | { | ||
1402 | angle2 = animvalue[k+2].value; | ||
1403 | } | ||
1404 | else | ||
1405 | { | ||
1406 | if (animvalue->num.total > k + 1) | ||
1407 | angle2 = angle1; | ||
1408 | else | ||
1409 | angle2 = animvalue[animvalue->num.valid+2].value; | ||
1410 | } | ||
1411 | } | ||
1412 | else | ||
1413 | { | ||
1414 | angle1 = animvalue[animvalue->num.valid].value; | ||
1415 | if (animvalue->num.total > k + 1) | ||
1416 | { | ||
1417 | angle2 = angle1; | ||
1418 | } | ||
1419 | else | ||
1420 | { | ||
1421 | angle2 = animvalue[animvalue->num.valid + 2].value; | ||
1422 | } | ||
1423 | } | ||
1424 | angle1 = bone->value[j+3] + angle1 * bone->scale[j+3]; | ||
1425 | angle2 = bone->value[j+3] + angle2 * bone->scale[j+3]; | ||
1426 | } | ||
1427 | |||
1428 | if (bone->bonecontroller[j+3] != -1) | ||
1429 | { | ||
1430 | angle1 += BoneAdj[bone->bonecontroller[j+3]]; | ||
1431 | angle2 += BoneAdj[bone->bonecontroller[j+3]]; | ||
1432 | } | ||
1433 | } | ||
1434 | |||
1435 | |||
1436 | /*! | ||
1437 | */ | ||
1438 | void CAnimatedMeshHalfLife::calcBonePosition(const s32 frame, f32 s, | ||
1439 | const SHalflifeBone * const bone, SHalflifeAnimOffset *anim, f32 *pos) const | ||
1440 | { | ||
1441 | for (s32 j = 0; j < 3; ++j) | ||
1442 | { | ||
1443 | pos[j] = bone->value[j]; // default; | ||
1444 | if (anim->offset[j] != 0) | ||
1445 | { | ||
1446 | SHalflifeAnimationFrame *animvalue = (SHalflifeAnimationFrame *)((u8*)anim + anim->offset[j]); | ||
1447 | |||
1448 | s32 k = frame; | ||
1449 | // find span of values that includes the frame we want | ||
1450 | while (animvalue->num.total <= k) | ||
1451 | { | ||
1452 | k -= animvalue->num.total; | ||
1453 | animvalue += animvalue->num.valid + 1; | ||
1454 | } | ||
1455 | // if we're inside the span | ||
1456 | if (animvalue->num.valid > k) | ||
1457 | { | ||
1458 | // and there's more data in the span | ||
1459 | if (animvalue->num.valid > k + 1) | ||
1460 | { | ||
1461 | pos[j] += (animvalue[k+1].value * (1.f - s) + s * animvalue[k+2].value) * bone->scale[j]; | ||
1462 | } | ||
1463 | else | ||
1464 | { | ||
1465 | pos[j] += animvalue[k+1].value * bone->scale[j]; | ||
1466 | } | ||
1467 | } | ||
1468 | else | ||
1469 | { | ||
1470 | // are we at the end of the repeating values section and there's another section with data? | ||
1471 | if (animvalue->num.total <= k + 1) | ||
1472 | { | ||
1473 | pos[j] += (animvalue[animvalue->num.valid].value * (1.f - s) + s * animvalue[animvalue->num.valid + 2].value) * bone->scale[j]; | ||
1474 | } | ||
1475 | else | ||
1476 | { | ||
1477 | pos[j] += animvalue[animvalue->num.valid].value * bone->scale[j]; | ||
1478 | } | ||
1479 | } | ||
1480 | } | ||
1481 | if (bone->bonecontroller[j] != -1) | ||
1482 | { | ||
1483 | pos[j] += BoneAdj[bone->bonecontroller[j]]; | ||
1484 | } | ||
1485 | } | ||
1486 | } | ||
1487 | |||
1488 | |||
1489 | /*! | ||
1490 | */ | ||
1491 | void CAnimatedMeshHalfLife::calcRotations(vec3_hl *pos, vec4_hl *q, | ||
1492 | SHalflifeSequence *seq, SHalflifeAnimOffset *anim, f32 f) | ||
1493 | { | ||
1494 | s32 frame = (s32)f; | ||
1495 | f32 s = (f - frame); | ||
1496 | |||
1497 | // add in programatic controllers | ||
1498 | calcBoneAdj(); | ||
1499 | |||
1500 | SHalflifeBone *bone = (SHalflifeBone *)((u8 *)Header + Header->boneindex); | ||
1501 | for ( u32 i = 0; i < Header->numbones; i++, bone++, anim++) | ||
1502 | { | ||
1503 | core::vector3df angle1, angle2; | ||
1504 | calcBoneQuaternion(frame, bone, anim, 0, angle1.X, angle2.X); | ||
1505 | calcBoneQuaternion(frame, bone, anim, 1, angle1.Y, angle2.Y); | ||
1506 | calcBoneQuaternion(frame, bone, anim, 2, angle1.Z, angle2.Z); | ||
1507 | |||
1508 | if (!angle1.equals(angle2)) | ||
1509 | { | ||
1510 | vec4_hl q1, q2; | ||
1511 | AngleQuaternion( angle1, q1 ); | ||
1512 | AngleQuaternion( angle2, q2 ); | ||
1513 | QuaternionSlerp( q1, q2, s, q[i] ); | ||
1514 | } | ||
1515 | else | ||
1516 | { | ||
1517 | AngleQuaternion( angle1, q[i] ); | ||
1518 | } | ||
1519 | |||
1520 | calcBonePosition(frame, s, bone, anim, pos[i]); | ||
1521 | } | ||
1522 | |||
1523 | if (seq->motiontype & STUDIO_X) | ||
1524 | pos[seq->motionbone][0] = 0.f; | ||
1525 | if (seq->motiontype & STUDIO_Y) | ||
1526 | pos[seq->motionbone][1] = 0.f; | ||
1527 | if (seq->motiontype & STUDIO_Z) | ||
1528 | pos[seq->motionbone][2] = 0.f; | ||
1529 | } | ||
1530 | |||
1531 | |||
1532 | /*! | ||
1533 | */ | ||
1534 | SHalflifeAnimOffset * CAnimatedMeshHalfLife::getAnim( SHalflifeSequence *seq ) | ||
1535 | { | ||
1536 | SHalflifeSequenceGroup *seqgroup = (SHalflifeSequenceGroup *)((u8*)Header + Header->seqgroupindex) + seq->seqgroup; | ||
1537 | |||
1538 | if (seq->seqgroup == 0) | ||
1539 | { | ||
1540 | return (SHalflifeAnimOffset *)((u8*)Header + seqgroup->data + seq->animindex); | ||
1541 | } | ||
1542 | |||
1543 | return (SHalflifeAnimOffset *)((u8*)AnimationHeader[seq->seqgroup] + seq->animindex); | ||
1544 | } | ||
1545 | |||
1546 | |||
1547 | /*! | ||
1548 | */ | ||
1549 | void CAnimatedMeshHalfLife::slerpBones(vec4_hl q1[], vec3_hl pos1[], vec4_hl q2[], vec3_hl pos2[], f32 s) | ||
1550 | { | ||
1551 | if (s < 0) | ||
1552 | s = 0; | ||
1553 | else if (s > 1.f) | ||
1554 | s = 1.f; | ||
1555 | |||
1556 | f32 s1 = 1.f - s; | ||
1557 | |||
1558 | for ( u32 i = 0; i < Header->numbones; i++) | ||
1559 | { | ||
1560 | vec4_hl q3; | ||
1561 | QuaternionSlerp( q1[i], q2[i], s, q3 ); | ||
1562 | q1[i][0] = q3[0]; | ||
1563 | q1[i][1] = q3[1]; | ||
1564 | q1[i][2] = q3[2]; | ||
1565 | q1[i][3] = q3[3]; | ||
1566 | pos1[i][0] = pos1[i][0] * s1 + pos2[i][0] * s; | ||
1567 | pos1[i][1] = pos1[i][1] * s1 + pos2[i][1] * s; | ||
1568 | pos1[i][2] = pos1[i][2] * s1 + pos2[i][2] * s; | ||
1569 | } | ||
1570 | } | ||
1571 | |||
1572 | |||
1573 | /*! | ||
1574 | */ | ||
1575 | void CAnimatedMeshHalfLife::setUpBones() | ||
1576 | { | ||
1577 | static vec3_hl pos[MAXSTUDIOBONES]; | ||
1578 | f32 bonematrix[3][4]; | ||
1579 | static vec4_hl q[MAXSTUDIOBONES]; | ||
1580 | |||
1581 | static vec3_hl pos2[MAXSTUDIOBONES]; | ||
1582 | static vec4_hl q2[MAXSTUDIOBONES]; | ||
1583 | static vec3_hl pos3[MAXSTUDIOBONES]; | ||
1584 | static vec4_hl q3[MAXSTUDIOBONES]; | ||
1585 | static vec3_hl pos4[MAXSTUDIOBONES]; | ||
1586 | static vec4_hl q4[MAXSTUDIOBONES]; | ||
1587 | |||
1588 | if (SequenceIndex >= Header->numseq) | ||
1589 | SequenceIndex = 0; | ||
1590 | |||
1591 | SHalflifeSequence *seq = (SHalflifeSequence *)((u8*) Header + Header->seqindex) + SequenceIndex; | ||
1592 | |||
1593 | SHalflifeAnimOffset *anim = getAnim(seq); | ||
1594 | calcRotations(pos, q, seq, anim, CurrentFrame); | ||
1595 | |||
1596 | if (seq->numblends > 1) | ||
1597 | { | ||
1598 | anim += Header->numbones; | ||
1599 | calcRotations( pos2, q2, seq, anim, CurrentFrame ); | ||
1600 | f32 s = Blending[0] / 255.f; | ||
1601 | |||
1602 | slerpBones( q, pos, q2, pos2, s ); | ||
1603 | |||
1604 | if (seq->numblends == 4) | ||
1605 | { | ||
1606 | anim += Header->numbones; | ||
1607 | calcRotations( pos3, q3, seq, anim, CurrentFrame ); | ||
1608 | |||
1609 | anim += Header->numbones; | ||
1610 | calcRotations( pos4, q4, seq, anim, CurrentFrame ); | ||
1611 | |||
1612 | s = Blending[0] / 255.f; | ||
1613 | slerpBones( q3, pos3, q4, pos4, s ); | ||
1614 | |||
1615 | s = Blending[1] / 255.f; | ||
1616 | slerpBones( q, pos, q3, pos3, s ); | ||
1617 | } | ||
1618 | } | ||
1619 | |||
1620 | SHalflifeBone *bone = (SHalflifeBone *)((u8*) Header + Header->boneindex); | ||
1621 | |||
1622 | for (u32 i = 0; i < Header->numbones; i++) | ||
1623 | { | ||
1624 | QuaternionMatrix( q[i], bonematrix ); | ||
1625 | |||
1626 | bonematrix[0][3] = pos[i][0]; | ||
1627 | bonematrix[1][3] = pos[i][1]; | ||
1628 | bonematrix[2][3] = pos[i][2]; | ||
1629 | |||
1630 | if (bone[i].parent == -1) { | ||
1631 | memcpy(BoneTransform[i], bonematrix, sizeof(f32) * 12); | ||
1632 | } | ||
1633 | else { | ||
1634 | R_ConcatTransforms (BoneTransform[bone[i].parent], bonematrix, BoneTransform[i]); | ||
1635 | } | ||
1636 | } | ||
1637 | } | ||
1638 | |||
1639 | |||
1640 | //! Returns an axis aligned bounding box | ||
1641 | const core::aabbox3d<f32>& CAnimatedMeshHalfLife::getBoundingBox() const | ||
1642 | { | ||
1643 | return MeshIPol->BoundingBox; | ||
1644 | } | ||
1645 | |||
1646 | |||
1647 | //! Returns the type of the animated mesh. | ||
1648 | E_ANIMATED_MESH_TYPE CAnimatedMeshHalfLife::getMeshType() const | ||
1649 | { | ||
1650 | return EAMT_MDL_HALFLIFE; | ||
1651 | } | ||
1652 | |||
1653 | |||
1654 | //! returns amount of mesh buffers. | ||
1655 | u32 CAnimatedMeshHalfLife::getMeshBufferCount() const | ||
1656 | { | ||
1657 | return MeshIPol->getMeshBufferCount(); | ||
1658 | } | ||
1659 | |||
1660 | |||
1661 | //! returns pointer to a mesh buffer | ||
1662 | IMeshBuffer* CAnimatedMeshHalfLife::getMeshBuffer(u32 nr) const | ||
1663 | { | ||
1664 | return MeshIPol->getMeshBuffer(nr); | ||
1665 | } | ||
1666 | |||
1667 | |||
1668 | //! Returns pointer to a mesh buffer which fits a material | ||
1669 | /** \param material: material to search for | ||
1670 | \return Returns the pointer to the mesh buffer or | ||
1671 | NULL if there is no such mesh buffer. */ | ||
1672 | IMeshBuffer* CAnimatedMeshHalfLife::getMeshBuffer(const video::SMaterial &material) const | ||
1673 | { | ||
1674 | return MeshIPol->getMeshBuffer(material); | ||
1675 | } | ||
1676 | |||
1677 | |||
1678 | void CAnimatedMeshHalfLife::setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) | ||
1679 | { | ||
1680 | MeshIPol->setMaterialFlag ( flag, newvalue ); | ||
1681 | } | ||
1682 | |||
1683 | |||
1684 | //! set user axis aligned bounding box | ||
1685 | void CAnimatedMeshHalfLife::setBoundingBox(const core::aabbox3df& box) | ||
1686 | { | ||
1687 | MeshIPol->setBoundingBox(box); | ||
1688 | } | ||
1689 | |||
1690 | |||
1691 | } // end namespace scene | ||
1692 | } // end namespace irr | ||
1693 | |||
1694 | #endif // _IRR_COMPILE_WITH_MD3_LOADER_ | ||
1695 | |||