Commit 816d5655 authored by engineer_apple's avatar engineer_apple

- added Halflife 1 Model Loader

- added Halflife 1 Texture Loader
- slightly changed usage of getMesh ( doesn't effect existing implementation)

git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@3335 dfc29bdd-3216-0410-991c-e03cc46cb475
parent ccfcd68a
...@@ -11,6 +11,84 @@ Changes in 1.7.1 (05.07.2010) TA ...@@ -11,6 +11,84 @@ Changes in 1.7.1 (05.07.2010) TA
changed the light billboards to use the light color. ( green light, green particle, red light red particle ) changed the light billboards to use the light color. ( green light, green particle, red light red particle )
allow to disable the bump/parallax on the earth like in the room ( with transparency ) allow to disable the bump/parallax on the earth like in the room ( with transparency )
- added DDS Image files, DXT2, DXT3, DXT4, DXT5, based on code from nvidia and Randy Reddig - added DDS Image files, DXT2, DXT3, DXT4, DXT5, based on code from nvidia and Randy Reddig
- added a Halflife 1 Model Loader. ( bases on code by Fabio Concas )
-> Load all Textures ( can even optimize it to texture atlas ), all bone animation, all submodels.
-> But to make use of the values ( named animation, mouth animation ) the Interface for IAnimatedMeshSceneNode
has to be reonde. I don't want to blow up the Interface again...
TODO:
->can handle float frames numbers, the interface for getMesh should be reworked
I already have working implementations for MD2, MD3 and MDL to use float blendning instead
of using some kind of fix point..
This is my idea of a new getMesh interface for IAnimatedMesh
//! Returns the IMesh interface for a frame.
/** \param frameA: Frame number as zero based index.
The Blend Factor is in the fractional part of frameA
The Mesh will be calculated as
frame = integer(frameA) * (1-fractional(frameA )) + frameB * fractional(frameA)
FrameNr KeyFrameA KeyFrameB
40.0 1 0
40.1 0.9 0.1
40.5 0.5 0.5
40.9 0.1 0.9
41.0 0 1
\param frameB: Frame number as zero based index. The other KeyFrame which is blended with FrameA.
\param userParam: for Example Level of detail, or something else
*/
virtual IMesh* getMesh(f32 frameA, s32 frameB = 0,s32 param = 0) = 0;
Should be discussed. handles all situations ( forward/reverse animation ) because the direction
vector is A->B
For now i used the (unused, always 255) detail level parameter and set a blend percentage as
s32 frameNr = (s32) getFrameNr();
s32 frameBlend = (s32) (core::fract ( getFrameNr() ) * 1000.f);
return Mesh->getMesh(frameNr, frameBlend, StartFrame, EndFrame);
So no interface is affected.
TODO:
I also added structures (suggestion) for Keyframe Interpolation which are currently not used here
mainly to unifiy get and set named animations/bones from different model files with a unique function call.
It would also effect the Handling of IAnimatedMeshSceneNode. This Topic should be discussed.
My goal is to get as many information from the original model file like key/bone animation, skin info, shaders
sub models, attachement points etc in a public interface
and to reduce the interface like setMD2Anim, setMD3Animn, setBoneAnim into one slim line function call
for setting and getting.
The callback interface also should be more generalized and event based.
(Halflife for example can notify if your left foot animation touches ground, or tirggers sound or whatever)
Maybe we use the gui event system for that
I included a 357kb Yodan.mdl and the copyright info file from Doug Hillyer to the media directory
used in example 7. collision as 4th model..
it's not easy to unify different model types and that's why it's not finished;-)
-> TODO: Quaternion Rotation is done private hand made and should be done with irrlicht quaterions
- added Halflife 1 Texture Loader
Valve uses WAL archive types like quake2. textures are inside model files
I reworked the existing ImageloaderWAL and added named Halflife textures to wal2 ( they have not extension )
and an LMP (palette/texture) loader into the same file ( all using 32bit now )
- coreutil.h
added void splitFilenam, splits a path into components
- irstring.h
added parameter make_lower to substring ( copy just lower case )
string<T> subString(u32 begin, s32 length, bool make_lower = false ) const
- ColorConverter
added
//! converts a 8 bit palettized or non palettized image (A8) into R8G8B8
static void convert8BitTo24Bit(const u8* in, s16* out, s32 width, s32 height, const s32* palette, s32 linepad = 0, bool flip=false);
//! converts a 8 bit palettized or non palettized image (A8) into A8R8G8B8
static void convert8BitTo32Bit(const u8* in, u8* out, s32 width, s32 height, const u8* palette, s32 linepad = 0, bool flip=false);
-------------------------------------- --------------------------------------
...@@ -573,7 +651,7 @@ Changes in 1.6 (23.09.2009) ...@@ -573,7 +651,7 @@ Changes in 1.6 (23.09.2009)
There exists a known list of ArchiveLoaders, which know how to produce a Archive. There exists a known list of ArchiveLoaders, which know how to produce a Archive.
The Loaders and the Archives can be attached/detached on runtime. The Loaders and the Archives can be attached/detached on runtime.
The FileNames are now stored as core::string<c16>. where c16 is toggled between char/wchar The FileNames are now stored as io::path. where c16 is toggled between char/wchar
with the #define flag _IRR_WCHAR_FILESYSTEM, to supported unicode backends (default:off) with the #define flag _IRR_WCHAR_FILESYSTEM, to supported unicode backends (default:off)
Replaced most (const c8* filename) to string references. Replaced most (const c8* filename) to string references.
......
...@@ -164,14 +164,15 @@ int main() ...@@ -164,14 +164,15 @@ int main()
selection is being performed. */ selection is being performed. */
scene::IAnimatedMeshSceneNode* node = 0; scene::IAnimatedMeshSceneNode* node = 0;
video::SMaterial material;
// Add an MD2 node, which uses vertex-based animation. // Add an MD2 node, which uses vertex-based animation.
node = smgr->addAnimatedMeshSceneNode(smgr->getMesh("../../media/faerie.md2"), node = smgr->addAnimatedMeshSceneNode(smgr->getMesh("../../media/faerie.md2"),
0, IDFlag_IsPickable | IDFlag_IsHighlightable); 0, IDFlag_IsPickable | IDFlag_IsHighlightable);
node->setPosition(core::vector3df(-70,-15,-120)); // Put its feet on the floor. node->setPosition(core::vector3df(-70,-15,-140)); // Put its feet on the floor.
node->setScale(core::vector3df(2, 2, 2)); // Make it appear realistically scaled node->setScale(core::vector3df(2, 2, 2)); // Make it appear realistically scaled
node->setMD2Animation(scene::EMAT_POINT); node->setMD2Animation(scene::EMAT_POINT);
node->setAnimationSpeed(20.f); node->setAnimationSpeed(20.f);
video::SMaterial material;
material.setTexture(0, driver->getTexture("../../media/faerie2.bmp")); material.setTexture(0, driver->getTexture("../../media/faerie2.bmp"));
material.Lighting = true; material.Lighting = true;
material.NormalizeNormals = true; material.NormalizeNormals = true;
...@@ -183,24 +184,38 @@ int main() ...@@ -183,24 +184,38 @@ int main()
node->setTriangleSelector(selector); node->setTriangleSelector(selector);
selector->drop(); // We're done with this selector, so drop it now. selector->drop(); // We're done with this selector, so drop it now.
// And this B3D file uses skinned skeletal animation.
node = smgr->addAnimatedMeshSceneNode(smgr->getMesh("../../media/ninja.b3d"),
0, IDFlag_IsPickable | IDFlag_IsHighlightable);
node->setScale(core::vector3df(10, 10, 10));
node->setPosition(core::vector3df(-70,-66,-80));
node->setRotation(core::vector3df(0,90,0));
node->setAnimationSpeed(10.f);
node->getMaterial(0).NormalizeNormals = true;
node->getMaterial(0).Lighting = true;
// Just do the same as we did above.
selector = smgr->createTriangleSelector(node);
node->setTriangleSelector(selector);
selector->drop();
// This X files uses skeletal animation, but without skinning. // This X files uses skeletal animation, but without skinning.
node = smgr->addAnimatedMeshSceneNode(smgr->getMesh("../../media/dwarf.x"), node = smgr->addAnimatedMeshSceneNode(smgr->getMesh("../../media/dwarf.x"),
0, IDFlag_IsPickable | IDFlag_IsHighlightable); 0, IDFlag_IsPickable | IDFlag_IsHighlightable);
node->setPosition(core::vector3df(-70,-66,0)); // Put its feet on the floor. node->setPosition(core::vector3df(-70,-66,-30)); // Put its feet on the floor.
node->setRotation(core::vector3df(0,-90,0)); // And turn it towards the camera. node->setRotation(core::vector3df(0,-90,0)); // And turn it towards the camera.
node->setAnimationSpeed(20.f); node->setAnimationSpeed(20.f);
node->getMaterial(0).Lighting = true;
selector = smgr->createTriangleSelector(node); selector = smgr->createTriangleSelector(node);
node->setTriangleSelector(selector); node->setTriangleSelector(selector);
selector->drop(); selector->drop();
// And this B3D file uses skinned skeletal animation.
node = smgr->addAnimatedMeshSceneNode(smgr->getMesh("../../media/ninja.b3d"), // And this mdl file uses skinned skeletal animation.
node = smgr->addAnimatedMeshSceneNode(smgr->getMesh("../../media/yodan.mdl"),
0, IDFlag_IsPickable | IDFlag_IsHighlightable); 0, IDFlag_IsPickable | IDFlag_IsHighlightable);
node->setScale(core::vector3df(10, 10, 10)); node->setPosition(core::vector3df(-70,-25,20));
node->setPosition(core::vector3df(-70,-66,-60)); node->getMaterial(0).Lighting = true;
node->setRotation(core::vector3df(0,90,0));
node->setAnimationSpeed(10.f);
node->getMaterial(0).NormalizeNormals = true;
// Just do the same as we did above. // Just do the same as we did above.
selector = smgr->createTriangleSelector(node); selector = smgr->createTriangleSelector(node);
node->setTriangleSelector(selector); node->setTriangleSelector(selector);
...@@ -310,3 +325,4 @@ int main() ...@@ -310,3 +325,4 @@ int main()
/* /*
**/ **/
...@@ -25,7 +25,7 @@ using namespace irr; ...@@ -25,7 +25,7 @@ using namespace irr;
int main() int main()
{ {
// ask if user would like shadows // ask if user would like shadows
/*
char i; char i;
printf("Please press 'y' if you want to use realtime shadows.\n"); printf("Please press 'y' if you want to use realtime shadows.\n");
...@@ -37,6 +37,9 @@ int main() ...@@ -37,6 +37,9 @@ int main()
video::E_DRIVER_TYPE driverType=driverChoiceConsole(); video::E_DRIVER_TYPE driverType=driverChoiceConsole();
if (driverType==video::EDT_COUNT) if (driverType==video::EDT_COUNT)
return 1; return 1;
*/
video::E_DRIVER_TYPE driverType = video::EDT_DIRECT3D9; // video::EDT_BURNINGSVIDEO; // video::EDT_OPENGL; //video::EDT_BURNINGSVIDEO;
bool shadows = true;
/* /*
Create device and exit if creation failed. We make the stencil flag Create device and exit if creation failed. We make the stencil flag
......
...@@ -47,10 +47,105 @@ namespace scene ...@@ -47,10 +47,105 @@ namespace scene
can be loaded directly by Irrlicht */ can be loaded directly by Irrlicht */
EAMT_OCT, EAMT_OCT,
//! Halflife MDL model file
EAMT_MDL_HALFLIFE,
//! generic skinned mesh //! generic skinned mesh
EAMT_SKINNED EAMT_SKINNED
}; };
//! 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),
StartFrame ( start ), CurrentFrame ( (f32) start ), NextFrame ( start ),
Frames ( frames ), EndFrame ( start + frames - 1 ),
FramesPerSecond ( fps ), RelativeSpeed ( relativefps ),
LoopingFrames ( loopingframes ),
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;
//! Interface for an animated mesh. //! Interface for an animated mesh.
/** There are already simple implementations of this interface available so /** There are already simple implementations of this interface available so
you don't have to implement this interface on your own if you need to: you don't have to implement this interface on your own if you need to:
......
...@@ -260,12 +260,12 @@ B3D, MS3D or X meshes */ ...@@ -260,12 +260,12 @@ B3D, MS3D or X meshes */
//! Define _IRR_COMPILE_WITH_IRR_MESH_LOADER_ if you want to load Irrlicht Engine .irrmesh files //! Define _IRR_COMPILE_WITH_IRR_MESH_LOADER_ if you want to load Irrlicht Engine .irrmesh files
#define _IRR_COMPILE_WITH_IRR_MESH_LOADER_ #define _IRR_COMPILE_WITH_IRR_MESH_LOADER_
//! Define _IRR_COMPILE_WITH_HALFLIFE_LOADER_ if you want to load Halflife animated files
#define _IRR_COMPILE_WITH_HALFLIFE_LOADER_
//! Define _IRR_COMPILE_WITH_MD2_LOADER_ if you want to load Quake 2 animated files //! Define _IRR_COMPILE_WITH_MD2_LOADER_ if you want to load Quake 2 animated files
#define _IRR_COMPILE_WITH_MD2_LOADER_ #define _IRR_COMPILE_WITH_MD2_LOADER_
//! Define _IRR_COMPILE_WITH_MD3_LOADER_ if you want to load Quake 3 animated files //! Define _IRR_COMPILE_WITH_MD3_LOADER_ if you want to load Quake 3 animated files
#define _IRR_COMPILE_WITH_MD3_LOADER_ #define _IRR_COMPILE_WITH_MD3_LOADER_
//! Define _IRR_COMPILE_WITH_3DS_LOADER_ if you want to load 3D Studio Max files //! Define _IRR_COMPILE_WITH_3DS_LOADER_ if you want to load 3D Studio Max files
#define _IRR_COMPILE_WITH_3DS_LOADER_ #define _IRR_COMPILE_WITH_3DS_LOADER_
//! Define _IRR_COMPILE_WITH_COLLADA_LOADER_ if you want to load Collada files //! Define _IRR_COMPILE_WITH_COLLADA_LOADER_ if you want to load Collada files
...@@ -321,6 +321,8 @@ B3D, MS3D or X meshes */ ...@@ -321,6 +321,8 @@ B3D, MS3D or X meshes */
#define _IRR_COMPILE_WITH_TGA_LOADER_ #define _IRR_COMPILE_WITH_TGA_LOADER_
//! Define _IRR_COMPILE_WITH_WAL_LOADER_ if you want to load .wal files //! Define _IRR_COMPILE_WITH_WAL_LOADER_ if you want to load .wal files
#define _IRR_COMPILE_WITH_WAL_LOADER_ #define _IRR_COMPILE_WITH_WAL_LOADER_
//! Define _IRR_COMPILE_WITH_LMP_LOADER_ if you want to load .lmp files
#define _IRR_COMPILE_WITH_LMP_LOADER_
//! Define _IRR_COMPILE_WITH_RGB_LOADER_ if you want to load Silicon Graphics .rgb/.rgba/.sgi/.int/.inta/.bw files //! Define _IRR_COMPILE_WITH_RGB_LOADER_ if you want to load Silicon Graphics .rgb/.rgba/.sgi/.int/.inta/.bw files
#define _IRR_COMPILE_WITH_RGB_LOADER_ #define _IRR_COMPILE_WITH_RGB_LOADER_
......
...@@ -33,6 +33,16 @@ namespace scene ...@@ -33,6 +33,16 @@ namespace scene
MeshBuffers[i]->drop(); MeshBuffers[i]->drop();
} }
//! clean mesh
virtual void clear()
{
for (u32 i=0; i<MeshBuffers.size(); ++i)
MeshBuffers[i]->drop();
MeshBuffers.clear();
BoundingBox.reset ( 0.f, 0.f, 0.f );
}
//! returns amount of mesh buffers. //! returns amount of mesh buffers.
virtual u32 getMeshBufferCount() const virtual u32 getMeshBufferCount() const
{ {
......
...@@ -138,6 +138,39 @@ inline s32 isInSameDirectory ( const io::path& path, const io::path& file ) ...@@ -138,6 +138,39 @@ inline s32 isInSameDirectory ( const io::path& path, const io::path& file )
return subB - subA; return subB - subA;
} }
// splits a path into components
static inline void splitFilename( const io::path &name, io::path *path,io::path* filename, io::path* extension,bool make_lower = false )
{
s32 i = name.size();
s32 extpos = i;
// search for path separator or beginning
while ( i >= 0 )
{
if ( name[i] == '.' )
{
extpos = i;
if ( extension )
*extension = name.subString ( extpos + 1, name.size() - (extpos + 1), make_lower );
}
else
if ( name[i] == '/' || name[i] == '\\' )
{
if ( filename )
*filename = name.subString ( i + 1, extpos - (i + 1), make_lower );
if ( path )
{
*path = name.subString ( 0, i + 1, make_lower );
path->replace ( '\\', '/' );
}
return;
}
i -= 1;
}
if ( filename )
*filename = name.subString ( 0, extpos, make_lower );
}
//! some standard function ( to remove dependencies ) //! some standard function ( to remove dependencies )
#undef isdigit #undef isdigit
......
...@@ -884,25 +884,35 @@ public: ...@@ -884,25 +884,35 @@ public:
//! Returns a substring //! Returns a substring
/** \param begin: Start of substring. /** \param begin: Start of substring.
\param length: Length of substring. */ \param length: Length of substring.
string<T,TAlloc> subString(u32 begin, s32 length) const \param make_lower, copy only lower case */
string<T> subString(u32 begin, s32 length, bool make_lower = false ) const
{ {
// if start after string // if start after string
// or no proper substring length // or no proper substring length
if ((length <= 0) || (begin>=size())) if ((length <= 0) || (begin>=size()))
return string<T,TAlloc>(""); return string<T>("");
// clamp length to maximal value // clamp length to maximal value
if ((length+begin) > size()) if ((length+begin) > size())
length = size()-begin; length = size()-begin;
string<T,TAlloc> o; string<T> o;
o.reserve(length+1); o.reserve(length+1);
for (s32 i=0; i<length; ++i) s32 i;
o.array[i] = array[i+begin]; if ( !make_lower )
{
for (i=0; i<length; ++i)
o.array[i] = array[i+begin];
}
else
{
for (i=0; i<length; ++i)
o.array[i] = locale_lower ( array[i+begin] );
}
o.array[length] = 0; o.array[length] = 0;
o.used = o.allocated; o.used = length + 1;
return o; return o;
} }
......
Boba Fett Model for Half-Life
Copyright © 1999 Doug Hillyer
Author: Doug "CHaoSMaN" Hillyer--All modeling and textures
E-Mail: dhillyer@bigfoot.com
ICQ: 707847 (Don't contact through ICQ without a good reason)
Webpage: http:// *UNDER CONSTRUCTION* E-mail me if you'll host my page.
Model Name: Boba Fett
Version: 1.0
Relaese Date: 3/24/99
Total Size: 448KB
Polygons: 700
Vertices: 379
Texture Size: 159KB (I'll take it down under 150KB in the next release)
Team Colors: No. Maybe in a future release if I figure out how to change the palette.
Animations: Standard DM Player Animations--I'm too lazy to make my own
Build Time: 30+ Hours?
Programs Used: 3D Studio MAX R2.5, Character Studio R2, Surface Suite 1.1, Photoshop 5
Knows bugs:
Top of jet pack goes though his head in some animations. Not much I can do about it. No chrome texture. If anyone knows how to do this, let me know and I'll add it. Multiplayer BMP thinks it has team colors and doesn't display correctly.
Description:
Here is one less model on the Cold Fusion Wish List (http://www.planethalflife.com/coldfusion/)! After more that 30 hours of modeling and texturing it's finaly done. Each and every polygon hand-built by me, except for the arms, which belong to the gordon model. I saw no reason to remodel something that was already made. All textures made to match the latest version of Boba Fett. The modifier stack in 3DSMAX had at least 40 modifiers and froze my computer numerous time. It's a little bit bulky at 700 polygons, but I can't do it with much less and still have all of the details that I want. I hope that everyone likes it. Please send me any comments or suggestions you may have.
If there is something wronge with the design or model, then let me know so that I can fix it in an upcoming release.
I'm also taking requests or suggestions for models.
Remember, this model is Copyrighted by me, Doug Hillyer. If you want to use this model or need one custom built for a MOD, then contact me.
Enjoy!
Installation:
Put all files (bobafett.mdl, bobafett.bmp) in half-life\valve\models\player\bobafett directory
\ No newline at end of file
File added
// Copyright (C) 2002-2009 Nikolaus Gebhardt / Fabio Concas / Thomas Alten
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_HALFLIFE_LOADER_
#include "CAnimatedMeshHalfLife.h"
#include "os.h"
#include "CColorConverter.h"
#include "CImage.h"
#include "coreutil.h"
#include "SMeshBuffer.h"
#include "IVideoDriver.h"
#include "IFileSystem.h"
namespace irr
{
namespace scene
{
using namespace video;
void AngleQuaternion( const vec3_hl angles, vec4_hl quaternion )
{
f32 angle;
f32 sr, sp, sy, cr, cp, cy;
// FIXME: rescale the inputs to 1/2 angle
angle = angles[2] * 0.5f;
sy = sin(angle);
cy = cos(angle);
angle = angles[1] * 0.5f;
sp = sin(angle);
cp = cos(angle);
angle = angles[0] * 0.5f;
sr = sin(angle);
cr = cos(angle);
quaternion[0] = sr*cp*cy-cr*sp*sy; // X
quaternion[1] = cr*sp*cy+sr*cp*sy; // Y
quaternion[2] = cr*cp*sy-sr*sp*cy; // Z
quaternion[3] = cr*cp*cy+sr*sp*sy; // W
}
void QuaternionMatrix( const vec4_hl quaternion, f32 (*matrix)[4] )
{
matrix[0][0] = 1.f - 2.f * quaternion[1] * quaternion[1] - 2.f * quaternion[2] * quaternion[2];
matrix[1][0] = 2.f * quaternion[0] * quaternion[1] + 2.f * quaternion[3] * quaternion[2];
matrix[2][0] = 2.f * quaternion[0] * quaternion[2] - 2.f * quaternion[3] * quaternion[1];
matrix[0][1] = 2.f * quaternion[0] * quaternion[1] - 2.f * quaternion[3] * quaternion[2];
matrix[1][1] = 1.f - 2.f * quaternion[0] * quaternion[0] - 2.f * quaternion[2] * quaternion[2];
matrix[2][1] = 2.f * quaternion[1] * quaternion[2] + 2.f * quaternion[3] * quaternion[0];
matrix[0][2] = 2.f * quaternion[0] * quaternion[2] + 2.f * quaternion[3] * quaternion[1];
matrix[1][2] = 2.f * quaternion[1] * quaternion[2] - 2.f * quaternion[3] * quaternion[0];
matrix[2][2] = 1.f - 2.f * quaternion[0] * quaternion[0] - 2.f * quaternion[1] * quaternion[1];
}
void QuaternionSlerp( const vec4_hl p, vec4_hl q, f32 t, vec4_hl qt )
{
s32 i;
f32 omega, cosom, sinom, sclp, sclq;
// decide if one of the quaternions is backwards
f32 a = 0;
f32 b = 0;
for (i = 0; i < 4; i++) {
a += (p[i]-q[i])*(p[i]-q[i]);
b += (p[i]+q[i])*(p[i]+q[i]);
}
if (a > b) {
for (i = 0; i < 4; i++) {
q[i] = -q[i];
}
}
cosom = p[0]*q[0] + p[1]*q[1] + p[2]*q[2] + p[3]*q[3];
if ((1.f + cosom) > 0.00000001) {
if ((1.f - cosom) > 0.00000001) {
omega = acos( cosom );
sinom = sin( omega );
sclp = sin( (1.f - t)*omega) / sinom;
sclq = sin( t*omega ) / sinom;
}
else {
sclp = 1.f - t;
sclq = t;
}
for (i = 0; i < 4; i++) {
qt[i] = sclp * p[i] + sclq * q[i];
}
}
else {
qt[0] = -p[1];
qt[1] = p[0];
qt[2] = -p[3];
qt[3] = p[2];
sclp = sin( (1.f - t) * 0.5f * core::PI);
sclq = sin( t * 0.5f * core::PI);
for (i = 0; i < 3; i++) {
qt[i] = sclp * p[i] + sclq * qt[i];
}
}
}
void R_ConcatTransforms (const f32 in1[3][4], const f32 in2[3][4], f32 out[3][4])
{
out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0];
out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + in1[0][2] * in2[2][1];
out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + in1[0][2] * in2[2][2];
out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] + in1[0][2] * in2[2][3] + in1[0][3];
out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + in1[1][2] * in2[2][0];
out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + in1[1][2] * in2[2][1];
out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + in1[1][2] * in2[2][2];
out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] + in1[1][2] * in2[2][3] + in1[1][3];
out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + in1[2][2] * in2[2][0];
out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + in1[2][2] * in2[2][1];
out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + in1[2][2] * in2[2][2];
out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + in1[2][2] * in2[2][3] + in1[2][3];
}
#define EQUAL_EPSILON 0.001
s32 VectorCompare (vec3_hl v1, vec3_hl v2)
{
s32 i;
for (i=0 ; i<3 ; i++)
if (fabs(v1[i]-v2[i]) > EQUAL_EPSILON)
return false;
return true;
}
#define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2])
inline void VectorTransform (const vec3_hl in1, const f32 in2[3][4], vec3_hl out)
{
out[0] = DotProduct(in1, in2[0]) + in2[0][3];
out[1] = DotProduct(in1, in2[1]) + in2[1][3];
out[2] = DotProduct(in1, in2[2]) + in2[2][3];
}
inline void VectorTransform2 (core::vector3df &out, const vec3_hl in1, const f32 in2[3][4])
{
out.X = DotProduct(in1, in2[0]) + in2[0][3];
out.Z = DotProduct(in1, in2[1]) + in2[1][3];
out.Y = DotProduct(in1, in2[2]) + in2[2][3];
}
static f32 BoneTransform[MAXSTUDIOBONES][3][4]; // bone transformation matrix
void getBoneVector ( core::vector3df &out, u32 index )
{
out.X = BoneTransform[index][0][3];
out.Z = BoneTransform[index][1][3];
out.Y = BoneTransform[index][2][3];
}
void getBoneBox ( core::aabbox3df &box, u32 index, f32 size = 0.5f )
{
box.MinEdge.X = BoneTransform[index][0][3] - size;
box.MinEdge.Z = BoneTransform[index][1][3] - size;
box.MinEdge.Y = BoneTransform[index][2][3] - size;
size *= 2.f;
box.MaxEdge.X = box.MinEdge.X + size;
box.MaxEdge.Y = box.MinEdge.Y + size;
box.MaxEdge.Z = box.MinEdge.Z + size;
}
void getTransformedBoneVector ( core::vector3df &out, u32 index, const vec3_hl in)
{
out.X = DotProduct(in, BoneTransform[index][0]) + BoneTransform[index][0][3];
out.Z = DotProduct(in, BoneTransform[index][1]) + BoneTransform[index][1][3];
out.Y = DotProduct(in, BoneTransform[index][2]) + BoneTransform[index][2][3];
}
//! Constructor
CHalflifeMDLMeshFileLoader::CHalflifeMDLMeshFileLoader( scene::ISceneManager* smgr )
{
#ifdef _DEBUG
setDebugName("CHalflifeMDLMeshFileLoader");
#endif
SceneManager = smgr;
}
//! returns true if the file maybe is able to be loaded by this class
//! based on the file extension (e.g. ".bsp")
bool CHalflifeMDLMeshFileLoader::isALoadableFileExtension(const io::path& filename) const
{
return core::hasFileExtension ( filename, "mdl" );
}
//! 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.
IAnimatedMesh* CHalflifeMDLMeshFileLoader::createMesh(io::IReadFile* file)
{
CAnimatedMeshHalfLife* msh = new CAnimatedMeshHalfLife();
if (msh)
{
if ( msh->loadModelFile ( file, SceneManager ) )
return msh;
msh->drop();
}
return 0;
}
//! Constructor
CAnimatedMeshHalfLife::CAnimatedMeshHalfLife()
{
#ifdef _DEBUG
setDebugName("CAnimatedMeshHalfLife");
#endif
initData ();
}
/*!
loads a complete model
*/
bool CAnimatedMeshHalfLife::loadModelFile( io::IReadFile* file,ISceneManager * smgr )
{
if (!file)
return false;
bool r = false;
SceneManager = smgr;
if ( loadModel ( file, file->getFileName() ) )
{
if ( postLoadModel ( file->getFileName() ) )
{
initModel ();
//dumpModelInfo ( 1 );
r = true;
}
}
return r;
}
//! Destructor
CAnimatedMeshHalfLife::~CAnimatedMeshHalfLife()
{
freeModel ();
}
//! Returns the amount of frames in milliseconds. If the amount is 1, it is a static (=non animated) mesh.
u32 CAnimatedMeshHalfLife::getFrameCount() const
{
return FrameCount;
}
//! set the hardware mapping hint, for driver
void CAnimatedMeshHalfLife::setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint,E_BUFFER_TYPE buffer)
{
}
//! flags the meshbuffer as changed, reloads hardware buffers
void CAnimatedMeshHalfLife::setDirty(E_BUFFER_TYPE buffer)
{
}
static vec3_hl TransformedVerts[MAXSTUDIOVERTS]; // transformed vertices
static vec3_hl TransformedNormals[MAXSTUDIOVERTS]; // light surface normals
/*!
*/
void CAnimatedMeshHalfLife::initModel ()
{
// init Sequences to Animation
KeyFrameInterpolation ipol;
ipol.Name.reserve ( 64 );
u32 i;
AnimList.clear();
FrameCount = 0;
SHalflifeSequence *seq = (SHalflifeSequence*) ((u8*) Header + Header->seqindex);
for ( i = 0; i < Header->numseq; i++)
{
ipol.Name = seq[i].label;
ipol.StartFrame = FrameCount;
ipol.Frames = core::max_ ( 1, seq[i].numframes - 1 );
ipol.EndFrame = ipol.StartFrame + ipol.Frames - 1;
ipol.FramesPerSecond = seq[i].fps;
ipol.AnimationType = seq[i].flags & STUDIO_LOOPING ? EAMT_LOOPING : EAMT_WAYPOINT;
AnimList.push_back ( ipol );
FrameCount += ipol.Frames;
}
// initBoneControllers
/*
SHalflifeBoneController *bonecontroller = (SHalflifeBoneController *)((u8*) Header + Header->bonecontrollerindex);
for ( i = 0; i < Header->numbonecontrollers; i++)
{
printf ( "BoneController%d index:%d%s range:%f - %f\n",
i,
bonecontroller[i].index, bonecontroller[i].index == MOUTH_CONTROLLER ? " (Mouth)": "",
bonecontroller[i].start,bonecontroller[i].end
);
}
// initSkins
for (i = 0; i < TextureHeader->numskinfamilies; i++)
{
printf ( "Skin%d\n", i + 1);
}
*/
// initBodyparts
u32 meshBuffer = 0;
BodyList.clear();
SHalflifeBody *body = (SHalflifeBody *) ((u8*) Header + Header->bodypartindex);
for ( i = 0; i < Header->numbodyparts; ++i)
{
BodyPart part;
part.name = body[i].name;
part.defaultModel = core::max_ ( 0, (s32) body[i].base - 1 );
SHalflifeModel * model = (SHalflifeModel *)((u8*) Header + body[i].modelindex);
for ( u32 g = 0; g < body[i].nummodels; ++g)
{
SubModel sub;
sub.name = model[g].name;
sub.startBuffer = meshBuffer;
sub.endBuffer = sub.startBuffer + model[g].nummesh;
sub.state = g == part.defaultModel;
part.model.push_back ( sub );
meshBuffer += model[g].nummesh;
}
BodyList.push_back ( part );
}
SequenceIndex = 0;
CurrentFrame = 0.f;
SetController (0, 0.f);
SetController (1, 0.f);
SetController (2, 0.f);
SetController (3, 0.f);
SetController (MOUTH_CONTROLLER, 0.f);
SetSkin (0);
// init Meshbuffers
io::path store;
const SHalflifeTexture *tex = (SHalflifeTexture *) ((u8*) TextureHeader + TextureHeader->textureindex);
const u16 *skinref = (u16 *)((u8*)TextureHeader + TextureHeader->skinindex);
if (SkinGroupSelection != 0 && SkinGroupSelection < TextureHeader->numskinfamilies)
skinref += (SkinGroupSelection * TextureHeader->numskinref);
io::path fname;
io::path ext;
core::vector2df tex_scale;
core::vector2di tex_trans ( 0, 0 );
#ifdef HL_TEXTURE_ATLAS
TextureAtlas.getScale ( tex_scale );
#endif
for ( u32 bodypart=0 ; bodypart < Header->numbodyparts ; ++bodypart)
{
const SHalflifeBody *body = (SHalflifeBody *)((u8*) Header + Header->bodypartindex) + bodypart;
for ( u32 modelnr = 0; modelnr < body->nummodels; ++modelnr )
{
const SHalflifeModel *model = (SHalflifeModel *)((u8*) Header + body->modelindex) + modelnr;
const vec3_hl *studioverts = (vec3_hl *)((u8*)Header + model->vertindex);
const vec3_hl *studionorms = (vec3_hl *)((u8*)Header + model->normindex);
for (i = 0; i < model->nummesh; ++i)
{
const SHalflifeMesh *mesh = (SHalflifeMesh *)((u8*)Header + model->meshindex) + i;
const SHalflifeTexture *currentex = &tex[skinref[mesh->skinref]];
#ifdef HL_TEXTURE_ATLAS
TextureAtlas.getTranslation ( currentex->name, tex_trans );
#else
tex_scale.X = 1.f/(f32)currentex->width;
tex_scale.Y = 1.f/(f32)currentex->height;
#endif
SMeshBuffer * buffer = new SMeshBuffer();
// count index vertex size indexcount = mesh->numtris * 3
u32 indexCount = 0;
u32 vertexCount = 0;
const s16 *tricmd = (s16*)((u8*)Header + mesh->triindex);
s32 c;
while (c = *(tricmd++))
{
if (c < 0)
c = -c;
indexCount += ( c - 2 ) * 3;
vertexCount += c;
tricmd += ( 4 * c );
}
// indices
buffer->Indices.set_used ( indexCount );
buffer->Vertices.set_used ( vertexCount );
// fill in static indices and vertex
u16 *index = buffer->Indices.pointer();
video::S3DVertex * v = buffer->Vertices.pointer();
// blow up gl_triangle_fan/gl_triangle_strip to indexed triangle list
E_PRIMITIVE_TYPE type;
vertexCount = 0;
indexCount = 0;
tricmd = (s16*)((u8*)Header + mesh->triindex);
while (c = *(tricmd++))
{
if (c < 0)
{
// triangle fan
c = -c;
type = EPT_TRIANGLE_FAN;
}
else
{
type = EPT_TRIANGLE_STRIP;
}
for ( s32 g = 0; g < c; ++g, v += 1, tricmd += 4 )
{
// fill vertex
#if 0
const f32 *av = studioverts[tricmd[0]];
v->Pos.X = av[0];
v->Pos.Z = av[1];
v->Pos.Y = av[2];
av = studionorms[tricmd[1]];
v->Normal.X = av[0];
v->Normal.Z = av[1];
v->Normal.Y = av[2];
#endif
v->Normal.X = 0.f;
v->Normal.Z = 0.f;
v->Normal.Y = 1.f;
v->TCoords.X = (tex_trans.X + tricmd[2])*tex_scale.X;
v->TCoords.Y = (tex_trans.Y + tricmd[3])*tex_scale.Y;
v->Color.color = 0xFFFFFFFF;
// fill index
if ( g < c - 2 )
{
if ( type == EPT_TRIANGLE_FAN )
{
index[indexCount+0] = vertexCount;
index[indexCount+1] = vertexCount+g+1;
index[indexCount+2] = vertexCount+g+2;
}
else
{
if ( g & 1 )
{
index[indexCount+0] = vertexCount+g+1;
index[indexCount+1] = vertexCount+g+0;
index[indexCount+2] = vertexCount+g+2;
}
else
{
index[indexCount+0] = vertexCount+g+0;
index[indexCount+1] = vertexCount+g+1;
index[indexCount+2] = vertexCount+g+2;
}
}
indexCount += 3;
}
}
vertexCount += c;
}
// material
video::SMaterial &m = buffer->getMaterial();
m.MaterialType = video::EMT_SOLID;
m.BackfaceCulling = true;
if ( currentex->flags & STUDIO_NF_CHROME )
{
// don't know what to do with chrome here
}
#ifdef HL_TEXTURE_ATLAS
store = TextureBaseName + "atlas";
#else
core::splitFilename ( currentex->name, 0, &fname, &ext );
store = TextureBaseName + fname;
#endif
m.TextureLayer[0].Texture = SceneManager->getVideoDriver()->getTexture ( store );
m.Lighting = false;
MeshIPol.addMeshBuffer ( buffer );
buffer->drop ();
} // mesh
} // model
} // body part
}
/*!
*/
void CAnimatedMeshHalfLife::buildVertices ()
{
/*
const u16 *skinref = (u16 *)((u8*)TextureHeader + TextureHeader->skinindex);
if (SkinGroupSelection != 0 && SkinGroupSelection < TextureHeader->numskinfamilies)
skinref += (SkinGroupSelection * TextureHeader->numskinref);
*/
u32 i;
s32 c,g;
const s16 *tricmd;
u32 meshBufferNr = 0;
for ( u32 bodypart = 0 ; bodypart < Header->numbodyparts; ++bodypart)
{
const SHalflifeBody *body = (SHalflifeBody *)((u8*) Header + Header->bodypartindex) + bodypart;
for ( u32 modelnr = 0; modelnr < body->nummodels; ++modelnr )
{
const SHalflifeModel *model = (SHalflifeModel *)((u8*) Header + body->modelindex) + modelnr;
const u8 *vertbone = ((u8*)Header + model->vertinfoindex);
const u8 *normbone = ((u8*)Header + model->norminfoindex);
const vec3_hl *studioverts = (vec3_hl *)((u8*)Header + model->vertindex);
const vec3_hl *studionorms = (vec3_hl *)((u8*)Header + model->normindex);
for ( i = 0; i < model->numverts; i++)
{
VectorTransform ( studioverts[i], BoneTransform[vertbone[i]], TransformedVerts[i] );
}
/*
for ( i = 0; i < model->numnorms; i++)
{
VectorTransform ( studionorms[i], BoneTransform[normbone[i]], TransformedNormals[i] );
}
*/
for (i = 0; i < model->nummesh; i++)
{
const SHalflifeMesh *mesh = (SHalflifeMesh *)((u8*)Header + model->meshindex) + i;
IMeshBuffer * buffer = MeshIPol.getMeshBuffer ( meshBufferNr++ );
video::S3DVertex* v = (video::S3DVertex* ) buffer->getVertices();
tricmd = (s16*)((u8*)Header + mesh->triindex);
while (c = *(tricmd++))
{
if (c < 0)
c = -c;
for ( g = 0; g < c; ++g, v += 1, tricmd += 4 )
{
// fill vertex
const f32 *av = TransformedVerts[tricmd[0]];
v->Pos.X = av[0];
v->Pos.Z = av[1];
v->Pos.Y = av[2];
/*
av = TransformedNormals[tricmd[1]];
v->Normal.X = av[0];
v->Normal.Z = av[1];
v->Normal.Y = av[2];
//v->Normal.normalize();
*/
}
} // tricmd
} // nummesh
} // model
} // bodypart
}
/*!
render Bones
*/
void CAnimatedMeshHalfLife::renderModel ( u32 param, IVideoDriver * driver, const core::matrix4 &absoluteTransformation)
{
SHalflifeBone *bone = (SHalflifeBone *) ((u8 *) Header + Header->boneindex);
video::SColor blue ( 0xFF000080 );
video::SColor red ( 0xFF800000 );
video::SColor yellow ( 0xFF808000 );
video::SColor cyan ( 0xFF008080 );
core::aabbox3df box;
u32 i;
for ( i = 0; i < Header->numbones; i++)
{
if (bone[i].parent >= 0)
{
getBoneVector ( box.MinEdge, bone[i].parent );
getBoneVector ( box.MaxEdge, i );
driver->draw3DLine ( box.MinEdge, box.MaxEdge, blue );
// draw parent bone node
if (bone[bone[i].parent].parent >=0 )
{
getBoneBox ( box, bone[i].parent );
driver->draw3DBox ( box, blue );
}
getBoneBox ( box, i );
driver->draw3DBox ( box, blue );
}
else
{
// draw parent bone node
getBoneBox ( box, i, 1.f );
driver->draw3DBox ( box , red );
}
}
// attachements
SHalfelifeAttachment *attach = (SHalfelifeAttachment *) ((u8*) Header + Header->attachmentindex);
core::vector3df v[8];
for ( i = 0; i < Header->numattachments; i++)
{
getTransformedBoneVector ( v[0],attach[i].bone,attach[i].org );
getTransformedBoneVector ( v[1],attach[i].bone,attach[i].vectors[0] );
getTransformedBoneVector ( v[2],attach[i].bone,attach[i].vectors[1] );
getTransformedBoneVector ( v[3],attach[i].bone,attach[i].vectors[2] );
driver->draw3DLine ( v[0], v[1], cyan );
driver->draw3DLine ( v[0], v[2], cyan );
driver->draw3DLine ( v[0], v[3], cyan );
}
// hit boxes
SHalflifeBBox *hitbox = (SHalflifeBBox *) ((u8*) Header + Header->hitboxindex);
f32 *bbmin,*bbmax;
vec3_hl v2[8];
for (i = 0; i < Header->numhitboxes; i++)
{
bbmin = hitbox[i].bbmin;
bbmax = hitbox[i].bbmax;
v2[0][0] = bbmin[0];
v2[0][1] = bbmax[1];
v2[0][2] = bbmin[2];
v2[1][0] = bbmin[0];
v2[1][1] = bbmin[1];
v2[1][2] = bbmin[2];
v2[2][0] = bbmax[0];
v2[2][1] = bbmax[1];
v2[2][2] = bbmin[2];
v2[3][0] = bbmax[0];
v2[3][1] = bbmin[1];
v2[3][2] = bbmin[2];
v2[4][0] = bbmax[0];
v2[4][1] = bbmax[1];
v2[4][2] = bbmax[2];
v2[5][0] = bbmax[0];
v2[5][1] = bbmin[1];
v2[5][2] = bbmax[2];
v2[6][0] = bbmin[0];
v2[6][1] = bbmax[1];
v2[6][2] = bbmax[2];
v2[7][0] = bbmin[0];
v2[7][1] = bbmin[1];
v2[7][2] = bbmax[2];
for ( u32 g = 0; g < 8; ++g )
getTransformedBoneVector ( v[g],hitbox[i].bone,v2[g] );
driver->draw3DLine(v[0], v[1], yellow);
driver->draw3DLine(v[1], v[3], yellow);
driver->draw3DLine(v[3], v[2], yellow);
driver->draw3DLine(v[2], v[0], yellow);
driver->draw3DLine(v[4], v[5], yellow);
driver->draw3DLine(v[5], v[7], yellow);
driver->draw3DLine(v[7], v[6], yellow);
driver->draw3DLine(v[6], v[4], yellow);
driver->draw3DLine(v[0], v[6], yellow);
driver->draw3DLine(v[1], v[7], yellow);
driver->draw3DLine(v[3], v[5], yellow);
driver->draw3DLine(v[2], v[4], yellow);
}
}
//! Returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail.
IMesh* CAnimatedMeshHalfLife::getMesh(s32 frameInt, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop)
{
f32 frame = frameInt + (detailLevel * 0.001f);
u32 frameA = core::floor32 ( frame );
f32 blend = core::fract ( frame );
u32 i;
SHalflifeSequence *seq = (SHalflifeSequence*) ((u8*) Header + Header->seqindex);
// find SequenceIndex from summed list
u32 frameCount = 0;
for ( i = 0; i < Header->numseq; i++)
{
u32 val = core::max_ ( 1, seq[i].numframes - 1 );
if ( frameCount + val > frameA )
{
SequenceIndex = i;
CurrentFrame = frame - frameCount;
break;
}
frameCount += val;
}
seq += SequenceIndex;
//SetBodyPart ( 1, 1 );
setUpBones ();
buildVertices();
MeshIPol.BoundingBox.MinEdge.X = seq->bbmin[0];
MeshIPol.BoundingBox.MinEdge.Z = seq->bbmin[1];
MeshIPol.BoundingBox.MinEdge.Y = seq->bbmin[2];
MeshIPol.BoundingBox.MaxEdge.X = seq->bbmax[0];
MeshIPol.BoundingBox.MaxEdge.Z = seq->bbmax[1];
MeshIPol.BoundingBox.MaxEdge.Y = seq->bbmax[2];
return &MeshIPol;
}
/*!
*/
void CAnimatedMeshHalfLife::initData ()
{
u32 i;
Header = 0;
TextureHeader = 0;
OwnTexModel = false;
for ( i = 0; i < 32; ++i )
AnimationHeader[i] = 0;
SequenceIndex = 0;
CurrentFrame = 0.f;
for ( i = 0; i < 5; ++i )
BoneController[i] = 0;
for ( i = 0; i < 2; ++i )
Blending[i] = 0;
SkinGroupSelection = 0;
AnimList.clear();
FrameCount = 0;
MeshIPol.clear();
#ifdef HL_TEXTURE_ATLAS
TextureAtlas.release();
#endif
}
/*!
*/
void CAnimatedMeshHalfLife::freeModel ()
{
delete [] (u8*) Header;
if (OwnTexModel )
delete [] (u8*) TextureHeader;
for ( u32 i = 0; i < 32; ++i )
delete [] (u8*) AnimationHeader[i];
}
/*!
*/
void STextureAtlas::release ()
{
for (u32 i = 0; i < atlas.size(); i++)
{
if ( atlas[i].image )
{
atlas[i].image->drop ();
atlas[i].image = 0;
}
}
Master = 0;
}
/*!
*/
void STextureAtlas::addSource ( const c8 * name, video::IImage * image )
{
TextureAtlasEntry entry;
entry.name = name;
entry.image = image;
entry.width = image->getDimension().Width;
entry.height = image->getDimension().Height;
entry.pos.X = 0;
entry.pos.Y = 0;
atlas.push_back ( entry );
}
/*!
*/
void STextureAtlas::getScale ( core::vector2df & scale )
{
for ( u32 i = atlas.size() - 1; i >= 0; --i)
{
if ( atlas[i].name == "_merged_" )
{
scale.X = 1.f / atlas[i].width;
scale.Y = 1.f / atlas[i].height;
return;
}
}
scale.X = 1.f;
scale.Y = 1.f;
}
/*!
*/
void STextureAtlas::getTranslation ( const c8 * name, core::vector2di &pos )
{
u32 i = 0;
for ( u32 i = 0; i < atlas.size(); ++i)
{
if ( atlas[i].name == name )
{
pos = atlas[i].pos;
return;
}
}
}
/*!
*/
void STextureAtlas::create ( u32 border, E_TEXTURE_CLAMP texmode)
{
u32 i = 0;
u32 w = 0;
u32 w2;
u32 h2;
u32 h;
u32 wsum;
u32 hsum = 0;
ECOLOR_FORMAT format = ECF_R8G8B8;
const s32 frame = core::s32_max ( 0, (border - 1 ) / 2 );
// sort for biggest coming first
atlas.sort();
// split size
wsum = frame;
for (i = 0; i < atlas.size(); i++)
{
// make space
w2 = atlas[i].width + border;
// align
w2 = (w2 + 1) & ~1;
wsum += w2;
}
u32 splitsize = 256;
if ( wsum > 512 )
splitsize = 512;
wsum = frame;
hsum = frame;
w = frame;
h = 0;
for (i = 0; i < atlas.size(); i++)
{
if ( atlas[i].image->getColorFormat() == ECF_A8R8G8B8 )
{
format = ECF_A8R8G8B8;
}
// make space
w2 = atlas[i].width + border;
h2 = atlas[i].height + border;
// align
w2 = (w2 + 1) & ~1;
h2 = (h2 + 1) & ~1;
h = core::s32_max ( h, h2 );
if ( w + w2 >= splitsize )
{
hsum += h;
wsum = core::s32_max ( wsum, w );
h = h2;
w = frame;
}
atlas[i].pos.X = w;
atlas[i].pos.Y = hsum;
w += w2;
}
hsum += h;
wsum = core::s32_max ( wsum, w );
// build image
core::dimension2d<u32> dim = core::dimension2d<u32>( wsum, hsum ).getOptimalSize();
IImage* master = new CImage( format, dim );
master->fill ( 0 );
video::SColor col[2];
static const u8 wrap[][4] =
{
{1, 0 }, // ETC_REPEAT
{0, 1 }, // ETC_CLAMP
{0, 1 }, // ETC_CLAMP_TO_EDGE
{0, 1 } // ETC_MIRROR
};
s32 a,b;
for (i = 0; i < atlas.size(); i++)
{
atlas[i].image->copyTo ( master, atlas[i].pos );
// clamp/wrap ( copy edges, filtering needs it )
for ( b = 0; b < frame; ++b )
{
for ( a = 0 - b; a <= (s32) atlas[i].width + b; ++a )
{
col[0] = atlas[i].image->getPixel ( core::s32_clamp ( a, 0, atlas[i].width - 1 ), 0 );
col[1] = atlas[i].image->getPixel ( core::s32_clamp ( a, 0, atlas[i].width - 1 ), atlas[i].height - 1 );
master->setPixel ( atlas[i].pos.X + a, atlas[i].pos.Y + ( b + 1 ) * -1, col[wrap[texmode][0]] );
master->setPixel ( atlas[i].pos.X + a, atlas[i].pos.Y + atlas[i].height - 1 + ( b + 1 ) * 1, col[wrap[texmode][1]] );
}
for ( a = -1 - b; a <= (s32) atlas[i].height + b; ++a )
{
col[0] = atlas[i].image->getPixel ( 0, core::s32_clamp ( a, 0, atlas[i].height - 1 ) );
col[1] = atlas[i].image->getPixel ( atlas[i].width - 1, core::s32_clamp ( a, 0, atlas[i].height - 1 ) );
master->setPixel ( atlas[i].pos.X + ( b + 1 ) * -1, atlas[i].pos.Y + a, col[wrap[texmode][0]] );
master->setPixel ( atlas[i].pos.X + atlas[i].width + b, atlas[i].pos.Y + a, col[wrap[texmode][1]] );
}
}
}
addSource ( "_merged_", master );
Master = master;
}
/*!
*/
SHalflifeHeader * CAnimatedMeshHalfLife::loadModel( io::IReadFile* file, const io::path &filename )
{
bool closefile = false;
if ( 0 == file )
{
file = SceneManager->getFileSystem()->createAndOpenFile ( filename );
closefile = true;
}
if ( 0 == file )
return 0;
u8 * pin = new u8 [ file->getSize() ];
file->read ( pin, file->getSize() );
SHalflifeHeader * header = (SHalflifeHeader*) pin;
const bool idst = 0 == strncmp ( header->id, "IDST", 4);
const bool idsq = 0 == strncmp ( header->id, "IDSQ", 4);
if ( (!idst && !idsq) || (idsq && !Header) )
{
os::Printer::log("MDL Halflife Loader: Wrong file header", file->getFileName(), ELL_WARNING);
if ( closefile )
{
file->drop();
file = 0;
}
delete [] pin;
return false;
}
// don't know the real header.. idsg might be different
if (header->textureindex && idst )
{
io::path fname;
io::path ext;
io::path path;
io::path store;
core::splitFilename ( file->getFileName(), &path, &fname, &ext );
TextureBaseName = path + fname + "_";
SHalflifeTexture *tex = (SHalflifeTexture *)(pin + header->textureindex);
u32 i;
u32 *palette = new u32[256];
for (i = 0; i < header->numtextures; i++)
{
const u8 *src = pin + tex[i].index;
// convert rgb to argb palette
{
const u8 *pal = src + tex[i].width * tex[i].height;
for( u32 g=0; g<256; ++g )
{
palette[g] = 0xFF000000 | pal[0] << 16 | pal[1] << 8 | pal[2];
pal += 3;
}
}
IImage* image = new CImage( ECF_R8G8B8, core::dimension2d<u32> ( tex[i].width, tex[i].height ) );
CColorConverter::convert8BitTo24Bit(src, (u8*)image->lock(), tex[i].width, tex[i].height, (u8*) palette, 0, false);
image->unlock();
#if 0
core::splitFilename ( tex[i].name, 0, &fname, 0 );
io::path store = io::path ( "c:/h2/convert/" ) + fname + ".bmp";
SceneManager->getVideoDriver()->writeImageToFile ( image, store );
#endif
#ifdef HL_TEXTURE_ATLAS
TextureAtlas.addSource ( tex[i].name, image );
#else
core::splitFilename ( tex[i].name, 0, &fname, &ext );
store = TextureBaseName + fname;
SceneManager->getVideoDriver()->addTexture ( store, image );
image->drop();
#endif
}
delete [] palette;
#ifdef HL_TEXTURE_ATLAS
TextureAtlas.create ( 2 * 2 + 1, ETC_CLAMP );
store = TextureBaseName + "atlas";
SceneManager->getVideoDriver()->addTexture ( store, TextureAtlas.Master );
#if 0
core::splitFilename ( store, 0, &fname, 0 );
store = io::path ( "c:/h2/convert/" ) + fname + ".bmp";
SceneManager->getVideoDriver()->writeImageToFile ( TextureAtlas.Master, store );
#endif
TextureAtlas.release ();
#endif
}
if (!Header)
Header = header;
if ( closefile )
{
file->drop();
file = 0;
}
return header;
}
/*!
*/
f32 CAnimatedMeshHalfLife::SetController( s32 controllerIndex, f32 value )
{
if (!Header)
return 0.f;
SHalflifeBoneController *bonecontroller = (SHalflifeBoneController *)((u8*) Header + Header->bonecontrollerindex);
// find first controller that matches the index
u32 i;
for (i = 0; i < Header->numbonecontrollers; i++, bonecontroller++)
{
if (bonecontroller->index == controllerIndex)
break;
}
if (i >= Header->numbonecontrollers)
return value;
// wrap 0..360 if it's a rotational controller
if (bonecontroller->type & (STUDIO_XR | STUDIO_YR | STUDIO_ZR))
{
// ugly hack, invert value if end < start
if (bonecontroller->end < bonecontroller->start)
value = -value;
// does the controller not wrap?
if (bonecontroller->start + 359.f >= bonecontroller->end)
{
if (value > ((bonecontroller->start + bonecontroller->end) / 2.f) + 180.f)
value = value - 360.f;
if (value < ((bonecontroller->start + bonecontroller->end) / 2.f) - 180.f)
value = value + 360.f;
}
else
{
if (value > 360.f)
value = value - (s32)(value / 360.f) * 360.f;
else if (value < 0.f)
value = value + (s32)((value / -360.f) + 1) * 360.f;
}
}
s32 range = controllerIndex == MOUTH_CONTROLLER ? 64 : 255;
s32 setting = (s32) ( (f32) range * (value - bonecontroller->start) / (bonecontroller->end - bonecontroller->start));
if (setting < 0) setting = 0;
if (setting > range) setting = range;
BoneController[controllerIndex] = setting;
return setting * (1.f / (f32) range ) * (bonecontroller->end - bonecontroller->start) + bonecontroller->start;
}
/*!
*/
u32 CAnimatedMeshHalfLife::SetSkin( u32 value )
{
if (value < Header->numskinfamilies)
SkinGroupSelection = value;
return SkinGroupSelection;
}
/*!
*/
bool CAnimatedMeshHalfLife::postLoadModel( const io::path &filename )
{
io::path path;
io::path texname;
io::path submodel;
core::splitFilename ( filename ,&path, &texname, 0 );
// preload textures
if (Header->numtextures == 0)
{
submodel = path + texname + "T.mdl";
TextureHeader = loadModel( 0, submodel );
if (!TextureHeader)
return false;
OwnTexModel = true;
}
else
{
TextureHeader = Header;
OwnTexModel = false;
}
u32 i;
// preload animations
if (Header->numseqgroups > 1)
{
c8 seq[8];
for ( i = 1; i < Header->numseqgroups; i++)
{
snprintf( seq, 8, "%02d.mdl", i );
submodel = path + texname + seq;
AnimationHeader[i] = loadModel( 0, submodel );
if (!AnimationHeader[i])
return false;
}
}
return true;
}
/*!
*/
void CAnimatedMeshHalfLife::dumpModelInfo ( u32 level )
{
u8 *phdr = (u8*) Header;
SHalflifeHeader * hdr = Header;
u32 i;
if ( level == 0 )
{
printf (
"Bones: %d\n"
"Bone Controllers: %d\n"
"Hit Boxes: %d\n"
"Sequences: %d\n"
"Sequence Groups: %d\n",
hdr->numbones,
hdr->numbonecontrollers,
hdr->numhitboxes,
hdr->numseq,
hdr->numseqgroups
);
printf (
"Textures: %d\n"
"Skin Families: %d\n"
"Bodyparts: %d\n"
"Attachments: %d\n"
"Transitions: %d\n",
hdr->numtextures,
hdr->numskinfamilies,
hdr->numbodyparts,
hdr->numattachments,
hdr->numtransitions);
return;
}
printf("id: %c%c%c%c\n", phdr[0], phdr[1], phdr[2], phdr[3]);
printf("version: %d\n", hdr->version);
printf("name: \"%s\"\n", hdr->name);
printf("length: %d\n\n", hdr->length);
printf("eyeposition: %f %f %f\n", hdr->eyeposition[0], hdr->eyeposition[1], hdr->eyeposition[2]);
printf("min: %f %f %f\n", hdr->min[0], hdr->min[1], hdr->min[2]);
printf("max: %f %f %f\n", hdr->max[0], hdr->max[1], hdr->max[2]);
printf("bbmin: %f %f %f\n", hdr->bbmin[0], hdr->bbmin[1], hdr->bbmin[2]);
printf("bbmax: %f %f %f\n", hdr->bbmax[0], hdr->bbmax[1], hdr->bbmax[2]);
printf("flags: %d\n\n", hdr->flags);
printf("numbones: %d\n", hdr->numbones);
for (i = 0; i < hdr->numbones; i++)
{
SHalflifeBone *bone = (SHalflifeBone *) (phdr + hdr->boneindex);
printf("bone %d.name: \"%s\"\n", i + 1, bone[i].name);
printf("bone %d.parent: %d\n", i + 1, bone[i].parent);
printf("bone %d.flags: %d\n", i + 1, bone[i].flags);
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]);
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]);
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]);
}
printf("\nnumbonecontrollers: %d\n", hdr->numbonecontrollers);
SHalflifeBoneController *bonecontrollers = (SHalflifeBoneController *) (phdr + hdr->bonecontrollerindex);
for (i = 0; i < hdr->numbonecontrollers; i++)
{
printf("bonecontroller %d.bone: %d\n", i + 1, bonecontrollers[i].bone);
printf("bonecontroller %d.type: %d\n", i + 1, bonecontrollers[i].type);
printf("bonecontroller %d.start: %f\n", i + 1, bonecontrollers[i].start);
printf("bonecontroller %d.end: %f\n", i + 1, bonecontrollers[i].end);
printf("bonecontroller %d.rest: %d\n", i + 1, bonecontrollers[i].rest);
printf("bonecontroller %d.index: %d\n", i + 1, bonecontrollers[i].index);
}
printf("\nnumhitboxes: %d\n", hdr->numhitboxes);
SHalflifeBBox *box = (SHalflifeBBox *) (phdr + hdr->hitboxindex);
for (i = 0; i < hdr->numhitboxes; i++)
{
printf("hitbox %d.bone: %d\n", i + 1, box[i].bone);
printf("hitbox %d.group: %d\n", i + 1, box[i].group);
printf("hitbox %d.bbmin: %f %f %f\n", i + 1, box[i].bbmin[0], box[i].bbmin[1], box[i].bbmin[2]);
printf("hitbox %d.bbmax: %f %f %f\n", i + 1, box[i].bbmax[0], box[i].bbmax[1], box[i].bbmax[2]);
}
printf("\nnumseq: %d\n", hdr->numseq);
SHalflifeSequence *seq = (SHalflifeSequence *) (phdr + hdr->seqindex);
for (i = 0; i < hdr->numseq; i++)
{
printf("seqdesc %d.label: \"%s\"\n", i + 1, seq[i].label);
printf("seqdesc %d.fps: %f\n", i + 1, seq[i].fps);
printf("seqdesc %d.flags: %d\n", i + 1, seq[i].flags);
printf("<...>\n");
}
printf("\nnumseqgroups: %d\n", hdr->numseqgroups);
for (i = 0; i < hdr->numseqgroups; i++)
{
SHalflifeSequenceGroup *group = (SHalflifeSequenceGroup *) (phdr + hdr->seqgroupindex);
printf("\nseqgroup %d.label: \"%s\"\n", i + 1, group[i].label);
printf("\nseqgroup %d.namel: \"%s\"\n", i + 1, group[i].name);
printf("\nseqgroup %d.data: %d\n", i + 1, group[i].data);
}
printf("\nnumskinref: %d\n", hdr->numskinref);
printf("numskinfamilies: %d\n", hdr->numskinfamilies);
printf("\nnumbodyparts: %d\n", hdr->numbodyparts);
SHalflifeBody *pbodyparts = (SHalflifeBody*) ((u8*) hdr + hdr->bodypartindex);
for (i = 0; i < hdr->numbodyparts; i++)
{
printf("bodypart %d.name: \"%s\"\n", i + 1, pbodyparts[i].name);
printf("bodypart %d.nummodels: %d\n", i + 1, pbodyparts[i].nummodels);
printf("bodypart %d.base: %d\n", i + 1, pbodyparts[i].base);
printf("bodypart %d.modelindex: %d\n", i + 1, pbodyparts[i].modelindex);
}
printf("\nnumattachments: %d\n", hdr->numattachments);
for (i = 0; i < hdr->numattachments; i++)
{
SHalfelifeAttachment *attach = (SHalfelifeAttachment *) ((u8*) hdr + hdr->attachmentindex);
printf("attachment %d.name: \"%s\"\n", i + 1, attach[i].name);
}
hdr = TextureHeader;
printf("\nnumtextures: %d\n", hdr->numtextures);
printf("textureindex: %d\n", hdr->textureindex);
printf("texturedataindex: %d\n", hdr->texturedataindex);
SHalflifeTexture *ptextures = (SHalflifeTexture *) ((u8*) hdr + hdr->textureindex);
for (i = 0; i < hdr->numtextures; i++)
{
printf("texture %d.name: \"%s\"\n", i + 1, ptextures[i].name);
printf("texture %d.flags: %d\n", i + 1, ptextures[i].flags);
printf("texture %d.width: %d\n", i + 1, ptextures[i].width);
printf("texture %d.height: %d\n", i + 1, ptextures[i].height);
printf("texture %d.index: %d\n", i + 1, ptextures[i].index);
}
}
/*!
*/
void CAnimatedMeshHalfLife::ExtractBbox( s32 sequence, core::aabbox3df &box )
{
SHalflifeSequence *seq = (SHalflifeSequence *)((u8*)Header + Header->seqindex) + sequence;
box.MinEdge.X = seq[0].bbmin[0];
box.MinEdge.Y = seq[0].bbmin[1];
box.MinEdge.Z = seq[0].bbmin[2];
box.MaxEdge.X = seq[0].bbmax[0];
box.MaxEdge.Y = seq[0].bbmax[1];
box.MaxEdge.Z = seq[0].bbmax[2];
}
/*!
*/
void CAnimatedMeshHalfLife::calcBoneAdj()
{
u32 j;
s32 i;
f32 value;
SHalflifeBoneController *bonecontroller;
bonecontroller = (SHalflifeBoneController *)((u8*) Header + Header->bonecontrollerindex);
for (j = 0; j < Header->numbonecontrollers; j++)
{
i = bonecontroller[j].index;
f32 range = i <= 3 ? 255.f : 64.f;
// check for 360% wrapping
if (bonecontroller[j].type & STUDIO_RLOOP)
{
value = BoneController[i] * (360.f/256.f) + bonecontroller[j].start;
}
else
{
value = BoneController[i] / range;
if (value < 0.f) value = 0.f;
if (value > 1.f) value = 1.f;
value = (1.f - value) * bonecontroller[j].start + value * bonecontroller[j].end;
}
switch(bonecontroller[j].type & STUDIO_TYPES)
{
case STUDIO_XR:
case STUDIO_YR:
case STUDIO_ZR:
BoneAdj[j] = value * (core::PI / 180.f);
break;
case STUDIO_X:
case STUDIO_Y:
case STUDIO_Z:
BoneAdj[j] = value;
break;
}
}
}
/*!
*/
void CAnimatedMeshHalfLife::calcBoneQuaternion( s32 frame, f32 s, SHalflifeBone *bone, SHalflifeAnimOffset *anim, f32 *q ) const
{
s32 j, k;
vec4_hl q1, q2;
vec3_hl angle1, angle2;
SHalfelifeAnimationFrame *animvalue;
for (j = 0; j < 3; j++)
{
if (anim->offset[j+3] == 0)
{
angle2[j] = angle1[j] = bone->value[j+3]; // default;
}
else
{
animvalue = (SHalfelifeAnimationFrame *)((u8*)anim + anim->offset[j+3]);
k = frame;
while (animvalue->num.total <= k)
{
k -= animvalue->num.total;
animvalue += animvalue->num.valid + 1;
}
// Bah, missing blend!
if (animvalue->num.valid > k)
{
angle1[j] = animvalue[k+1].value;
if (animvalue->num.valid > k + 1)
{
angle2[j] = animvalue[k+2].value;
}
else
{
if (animvalue->num.total > k + 1)
angle2[j] = angle1[j];
else
angle2[j] = animvalue[animvalue->num.valid+2].value;
}
}
else
{
angle1[j] = animvalue[animvalue->num.valid].value;
if (animvalue->num.total > k + 1)
{
angle2[j] = angle1[j];
}
else
{
angle2[j] = animvalue[animvalue->num.valid + 2].value;
}
}
angle1[j] = bone->value[j+3] + angle1[j] * bone->scale[j+3];
angle2[j] = bone->value[j+3] + angle2[j] * bone->scale[j+3];
}
if (bone->bonecontroller[j+3] != -1)
{
angle1[j] += BoneAdj[bone->bonecontroller[j+3]];
angle2[j] += BoneAdj[bone->bonecontroller[j+3]];
}
}
if (!VectorCompare( angle1, angle2 ))
{
AngleQuaternion( angle1, q1 );
AngleQuaternion( angle2, q2 );
QuaternionSlerp( q1, q2, s, q );
}
else
{
AngleQuaternion( angle1, q );
}
}
/*!
*/
void CAnimatedMeshHalfLife::calcBonePosition( s32 frame, f32 s, SHalflifeBone *bone, SHalflifeAnimOffset *anim, f32 *pos ) const
{
s32 j, k;
SHalfelifeAnimationFrame *animvalue;
for (j = 0; j < 3; j++)
{
pos[j] = bone->value[j]; // default;
if (anim->offset[j] != 0)
{
animvalue = (SHalfelifeAnimationFrame *)((u8*)anim + anim->offset[j]);
k = frame;
// find span of values that includes the frame we want
while (animvalue->num.total <= k)
{
k -= animvalue->num.total;
animvalue += animvalue->num.valid + 1;
}
// if we're inside the span
if (animvalue->num.valid > k)
{
// and there's more data in the span
if (animvalue->num.valid > k + 1)
{
pos[j] += (animvalue[k+1].value * (1.f - s) + s * animvalue[k+2].value) * bone->scale[j];
}
else
{
pos[j] += animvalue[k+1].value * bone->scale[j];
}
}
else
{
// are we at the end of the repeating values section and there's another section with data?
if (animvalue->num.total <= k + 1)
{
pos[j] += (animvalue[animvalue->num.valid].value * (1.f - s) + s * animvalue[animvalue->num.valid + 2].value) * bone->scale[j];
}
else
{
pos[j] += animvalue[animvalue->num.valid].value * bone->scale[j];
}
}
}
if (bone->bonecontroller[j] != -1)
{
pos[j] += BoneAdj[bone->bonecontroller[j]];
}
}
}
/*!
*/
void CAnimatedMeshHalfLife::calcRotations ( vec3_hl *pos, vec4_hl *q, SHalflifeSequence *seq, SHalflifeAnimOffset *anim, f32 f )
{
s32 frame;
SHalflifeBone *bone;
f32 s;
frame = (s32)f;
s = (f - frame);
// add in programatic controllers
calcBoneAdj( );
bone = (SHalflifeBone *)((u8 *)Header + Header->boneindex);
for ( u32 i = 0; i < Header->numbones; i++, bone++, anim++)
{
calcBoneQuaternion( frame, s, bone, anim, q[i] );
calcBonePosition( frame, s, bone, anim, pos[i] );
}
if (seq->motiontype & STUDIO_X)
pos[seq->motionbone][0] = 0.f;
if (seq->motiontype & STUDIO_Y)
pos[seq->motionbone][1] = 0.f;
if (seq->motiontype & STUDIO_Z)
pos[seq->motionbone][2] = 0.f;
}
/*!
*/
SHalflifeAnimOffset * CAnimatedMeshHalfLife::getAnim( SHalflifeSequence *seq )
{
SHalflifeSequenceGroup *seqgroup;
seqgroup = (SHalflifeSequenceGroup *)((u8*)Header + Header->seqgroupindex) + seq->seqgroup;
if (seq->seqgroup == 0)
{
return (SHalflifeAnimOffset *)((u8*)Header + seqgroup->data + seq->animindex);
}
return (SHalflifeAnimOffset *)((u8*)AnimationHeader[seq->seqgroup] + seq->animindex);
}
/*!
*/
void CAnimatedMeshHalfLife::slerpBones( vec4_hl q1[], vec3_hl pos1[], vec4_hl q2[], vec3_hl pos2[], f32 s )
{
vec4_hl q3;
f32 s1;
if (s < 0) s = 0;
else if (s > 1.f) s = 1.f;
s1 = 1.f - s;
for ( u32 i = 0; i < Header->numbones; i++)
{
QuaternionSlerp( q1[i], q2[i], s, q3 );
q1[i][0] = q3[0];
q1[i][1] = q3[1];
q1[i][2] = q3[2];
q1[i][3] = q3[3];
pos1[i][0] = pos1[i][0] * s1 + pos2[i][0] * s;
pos1[i][1] = pos1[i][1] * s1 + pos2[i][1] * s;
pos1[i][2] = pos1[i][2] * s1 + pos2[i][2] * s;
}
}
/*!
*/
void CAnimatedMeshHalfLife::setUpBones ()
{
SHalflifeBone *bone;
SHalflifeSequence *seq;
SHalflifeAnimOffset *anim;
static vec3_hl pos[MAXSTUDIOBONES];
f32 bonematrix[3][4];
static vec4_hl q[MAXSTUDIOBONES];
static vec3_hl pos2[MAXSTUDIOBONES];
static vec4_hl q2[MAXSTUDIOBONES];
static vec3_hl pos3[MAXSTUDIOBONES];
static vec4_hl q3[MAXSTUDIOBONES];
static vec3_hl pos4[MAXSTUDIOBONES];
static vec4_hl q4[MAXSTUDIOBONES];
if (SequenceIndex >= Header->numseq)
SequenceIndex = 0;
seq = (SHalflifeSequence *)((u8*) Header + Header->seqindex) + SequenceIndex;
anim = getAnim( seq );
calcRotations( pos, q, seq, anim, CurrentFrame );
if (seq->numblends > 1)
{
f32 s;
anim += Header->numbones;
calcRotations( pos2, q2, seq, anim, CurrentFrame );
s = Blending[0] / 255.f;
slerpBones( q, pos, q2, pos2, s );
if (seq->numblends == 4)
{
anim += Header->numbones;
calcRotations( pos3, q3, seq, anim, CurrentFrame );
anim += Header->numbones;
calcRotations( pos4, q4, seq, anim, CurrentFrame );
s = Blending[0] / 255.f;
slerpBones( q3, pos3, q4, pos4, s );
s = Blending[1] / 255.f;
slerpBones( q, pos, q3, pos3, s );
}
}
bone = (SHalflifeBone *)((u8*) Header + Header->boneindex);
for (u32 i = 0; i < Header->numbones; i++)
{
QuaternionMatrix( q[i], bonematrix );
bonematrix[0][3] = pos[i][0];
bonematrix[1][3] = pos[i][1];
bonematrix[2][3] = pos[i][2];
if (bone[i].parent == -1) {
memcpy(BoneTransform[i], bonematrix, sizeof(f32) * 12);
}
else {
R_ConcatTransforms (BoneTransform[bone[i].parent], bonematrix, BoneTransform[i]);
}
}
}
//! Returns an axis aligned bounding box
const core::aabbox3d<f32>& CAnimatedMeshHalfLife::getBoundingBox() const
{
return MeshIPol.BoundingBox;
}
//! Returns the type of the animated mesh.
E_ANIMATED_MESH_TYPE CAnimatedMeshHalfLife::getMeshType() const
{
return EAMT_MDL_HALFLIFE;
}
//! returns amount of mesh buffers.
u32 CAnimatedMeshHalfLife::getMeshBufferCount() const
{
return MeshIPol.getMeshBufferCount();
}
//! returns pointer to a mesh buffer
IMeshBuffer* CAnimatedMeshHalfLife::getMeshBuffer(u32 nr) const
{
return MeshIPol.getMeshBuffer ( nr );
}
//! Returns pointer to a mesh buffer which fits a material
/** \param material: material to search for
\return Returns the pointer to the mesh buffer or
NULL if there is no such mesh buffer. */
IMeshBuffer* CAnimatedMeshHalfLife::getMeshBuffer( const video::SMaterial &material) const
{
return MeshIPol.getMeshBuffer ( material );
}
void CAnimatedMeshHalfLife::setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue)
{
MeshIPol.setMaterialFlag ( flag, newvalue );
}
//! set user axis aligned bounding box
void CAnimatedMeshHalfLife::setBoundingBox(const core::aabbox3df& box)
{
return;
}
} // end namespace scene
} // end namespace irr
#endif // _IRR_COMPILE_WITH_MD3_LOADER_
// Copyright (C) 2002-2010 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
{
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
# pragma pack( push, packing )
# pragma pack( 1 )
# define PACK_STRUCT
#elif defined( __GNUC__ )
# define PACK_STRUCT __attribute__((packed))
#else
# error compiler not supported
#endif
// 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
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;
};
// header for demand loaded sequence group data
typedef struct
{
s32 id;
s32 version;
c8 name[64];
s32 length;
} studioseqhdr_t;
// 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
};
// 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
};
// intersection boxes
struct SHalflifeBBox
{
s32 bone;
s32 group; // intersection group
vec3_hl bbmin; // bounding box
vec3_hl bbmax;
};
#ifndef ZONE_H
typedef void *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
};
// 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
};
// events
typedef struct
{
s32 frame;
s32 event;
s32 type;
c8 options[64];
} mstudioevent_t;
// pivots
typedef struct
{
vec3_hl org; // pivot point
s32 start;
s32 end;
} mstudiopivot_t;
// attachment
struct SHalfelifeAttachment
{
c8 name[32];
s32 type;
s32 bone;
vec3_hl org; // attachment point
vec3_hl vectors[3];
};
struct SHalflifeAnimOffset
{
u16 offset[6];
};
// animation frames
union SHalfelifeAnimationFrame
{
struct {
u8 valid;
u8 total;
} num;
s16 value;
};
// body part index
struct SHalflifeBody
{
c8 name[64];
u32 nummodels;
u32 base;
u32 modelindex; // index into models array
};
// skin info
struct SHalflifeTexture
{
c8 name[64];
s32 flags;
s32 width;
s32 height;
s32 index;
};
// 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;
};
// meshes
typedef struct
{
u32 numtris;
u32 triindex;
u32 skinref;
u32 numnorms; // per mesh normals
u32 normindex; // normal vec3_hl
} SHalflifeMesh;
// 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)
// Default alignment
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
# pragma pack( pop, packing )
#endif
#undef PACK_STRUCT
/*!
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;
};
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);
//! 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 ();
void freeModel ();
SHalflifeHeader * loadModel( io::IReadFile* file, const io::path &filename );
bool postLoadModel( const io::path &filename );
u32 SequenceIndex; // sequence index
f32 CurrentFrame; // Current Frame
#define MOUTH_CONTROLLER 4
u8 BoneController[4 + 1 ]; // bone controllers + mouth position
u8 Blending[2]; // animation blending
f32 SetController( s32 controllerIndex, f32 value );
u32 SkinGroupSelection; // skin group selection
u32 SetSkin( u32 value );
void initModel ();
void dumpModelInfo ( u32 level);
void ExtractBbox( s32 sequence, core::aabbox3df &box );
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 );
vec4_hl BoneAdj;
void calcBoneAdj();
void calcBoneQuaternion( s32 frame, f32 s, SHalflifeBone *bone, SHalflifeAnimOffset *anim, f32 *q ) const;
void calcBonePosition( s32 frame, f32 s, 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
...@@ -199,7 +199,9 @@ IMesh * CAnimatedMeshSceneNode::getMeshForCurrentFrame() ...@@ -199,7 +199,9 @@ IMesh * CAnimatedMeshSceneNode::getMeshForCurrentFrame()
{ {
if(Mesh->getMeshType() != EAMT_SKINNED) if(Mesh->getMeshType() != EAMT_SKINNED)
{ {
return Mesh->getMesh((s32)getFrameNr(), 255, StartFrame, EndFrame); s32 frameNr = (s32) getFrameNr();
s32 frameBlend = (s32) (core::fract ( getFrameNr() ) * 1000.f);
return Mesh->getMesh(frameNr, frameBlend, StartFrame, EndFrame);
} }
else else
{ {
......
...@@ -112,6 +112,93 @@ void CColorConverter::convert8BitTo16Bit(const u8* in, s16* out, s32 width, s32 ...@@ -112,6 +112,93 @@ void CColorConverter::convert8BitTo16Bit(const u8* in, s16* out, s32 width, s32
} }
} }
//! converts a 8 bit palettized or non palettized image (A8) into R8G8B8
void CColorConverter::convert8BitTo24Bit(const u8* in, u8* out, s32 width, s32 height, const u8* palette, s32 linepad, bool flip)
{
if (!in || !out )
return;
const s32 lineWidth = 3 * width;
if (flip)
out += lineWidth * height;
for (s32 y=0; y<height; ++y)
{
if (flip)
out -= lineWidth; // one line back
for (s32 x=0; x< lineWidth; x += 3)
{
if ( palette )
{
#ifdef __BIG_ENDIAN__
out[x+0] = palette[ (in[0] << 2 ) + 0];
out[x+1] = palette[ (in[0] << 2 ) + 1];
out[x+2] = palette[ (in[0] << 2 ) + 2];
#else
out[x+0] = palette[ (in[0] << 2 ) + 2];
out[x+1] = palette[ (in[0] << 2 ) + 1];
out[x+2] = palette[ (in[0] << 2 ) + 0];
#endif
}
else
{
out[x+0] = in[0];
out[x+1] = in[0];
out[x+2] = in[0];
}
++in;
}
if (!flip)
out += lineWidth;
in += linepad;
}
}
//! converts a 8 bit palettized or non palettized image (A8) into R8G8B8
void CColorConverter::convert8BitTo32Bit(const u8* in, u8* out, s32 width, s32 height, const u8* palette, s32 linepad, bool flip)
{
if (!in || !out )
return;
const u32 lineWidth = 4 * width;
if (flip)
out += lineWidth * height;
u32 x;
register u32 c;
for (u32 y=0; y < (u32) height; ++y)
{
if (flip)
out -= lineWidth; // one line back
if ( palette )
{
for (x=0; x < (u32) width; x += 1)
{
c = in[x];
((u32*)out)[x] = ((u32*)palette)[ c ];
}
}
else
{
for (x=0; x < (u32) width; x += 1)
{
c = in[x];
#ifdef __BIG_ENDIAN__
((u32*)out)[x] = c << 24 | c << 16 | c << 8 | 0x000000FF;
#else
((u32*)out)[x] = 0xFF000000 | c << 16 | c << 8 | c;
#endif
}
}
if (!flip)
out += lineWidth;
in += width + linepad;
}
}
//! converts 16bit data to 16bit data //! converts 16bit data to 16bit data
......
...@@ -26,6 +26,12 @@ public: ...@@ -26,6 +26,12 @@ public:
//! converts a 8 bit palettized image to A1R5G5B5 //! converts a 8 bit palettized image to A1R5G5B5
static void convert8BitTo16Bit(const u8* in, s16* out, s32 width, s32 height, const s32* palette, s32 linepad=0, bool flip=false); static void convert8BitTo16Bit(const u8* in, s16* out, s32 width, s32 height, const s32* palette, s32 linepad=0, bool flip=false);
//! converts a 8 bit palettized or non palettized image (A8) into R8G8B8
static void convert8BitTo24Bit(const u8* in, u8* out, s32 width, s32 height, const u8* palette, s32 linepad = 0, bool flip=false);
//! converts a 8 bit palettized or non palettized image (A8) into A8R8G8B8
static void convert8BitTo32Bit(const u8* in, u8* out, s32 width, s32 height, const u8* palette, s32 linepad = 0, bool flip=false);
//! converts R8G8B8 16 bit data to A1R5G5B5 data //! converts R8G8B8 16 bit data to A1R5G5B5 data
static void convert16BitTo16Bit(const s16* in, s16* out, s32 width, s32 height, s32 linepad=0, bool flip=false); static void convert16BitTo16Bit(const s16* in, s16* out, s32 width, s32 height, s32 linepad=0, bool flip=false);
......
...@@ -122,7 +122,7 @@ void CStencilBuffer::setSize(const core::dimension2d<u32>& size) ...@@ -122,7 +122,7 @@ void CStencilBuffer::setSize(const core::dimension2d<u32>& size)
if (Buffer) if (Buffer)
delete [] Buffer; delete [] Buffer;
Pitch = size.Width * sizeof ( u8 ); Pitch = size.Width * sizeof ( u32 );
TotalSize = Pitch * size.Height; TotalSize = Pitch * size.Height;
Buffer = new u8[TotalSize]; Buffer = new u8[TotalSize];
clear (); clear ();
......
...@@ -18,6 +18,9 @@ namespace irr ...@@ -18,6 +18,9 @@ namespace irr
namespace video namespace video
{ {
// old implementation
#if 0
// May or may not be fully implemented // May or may not be fully implemented
#define TRY_LOADING_PALETTE_FROM_FILE 0 #define TRY_LOADING_PALETTE_FROM_FILE 0
...@@ -141,6 +144,302 @@ IImageLoader* createImageLoaderWAL() ...@@ -141,6 +144,302 @@ IImageLoader* createImageLoaderWAL()
return new irr::video::CImageLoaderWAL(); return new irr::video::CImageLoaderWAL();
} }
#endif
// Palette quake2 colormap.h, 768 byte, last is transparent
static const u32 colormap_h[256] = {
0xFF000000,0xFF0F0F0F,0xFF1F1F1F,0xFF2F2F2F,0xFF3F3F3F,0xFF4B4B4B,0xFF5B5B5B,0xFF6B6B6B,
0xFF7B7B7B,0xFF8B8B8B,0xFF9B9B9B,0xFFABABAB,0xFFBBBBBB,0xFFCBCBCB,0xFFDBDBDB,0xFFEBEBEB,
0xFF0F0B07,0xFF170F0B,0xFF1F170B,0xFF271B0F,0xFF2F2313,0xFF372B17,0xFF3F2F17,0xFF4B371B,
0xFF533B1B,0xFF5B431F,0xFF634B1F,0xFF6B531F,0xFF73571F,0xFF7B5F23,0xFF836723,0xFF8F6F23,
0xFF0B0B0F,0xFF13131B,0xFF1B1B27,0xFF272733,0xFF2F2F3F,0xFF37374B,0xFF3F3F57,0xFF474767,
0xFF4F4F73,0xFF5B5B7F,0xFF63638B,0xFF6B6B97,0xFF7373A3,0xFF7B7BAF,0xFF8383BB,0xFF8B8BCB,
0xFF000000,0xFF070700,0xFF0B0B00,0xFF131300,0xFF1B1B00,0xFF232300,0xFF2B2B07,0xFF2F2F07,
0xFF373707,0xFF3F3F07,0xFF474707,0xFF4B4B0B,0xFF53530B,0xFF5B5B0B,0xFF63630B,0xFF6B6B0F,
0xFF070000,0xFF0F0000,0xFF170000,0xFF1F0000,0xFF270000,0xFF2F0000,0xFF370000,0xFF3F0000,
0xFF470000,0xFF4F0000,0xFF570000,0xFF5F0000,0xFF670000,0xFF6F0000,0xFF770000,0xFF7F0000,
0xFF131300,0xFF1B1B00,0xFF232300,0xFF2F2B00,0xFF372F00,0xFF433700,0xFF4B3B07,0xFF574307,
0xFF5F4707,0xFF6B4B0B,0xFF77530F,0xFF835713,0xFF8B5B13,0xFF975F1B,0xFFA3631F,0xFFAF6723,
0xFF231307,0xFF2F170B,0xFF3B1F0F,0xFF4B2313,0xFF572B17,0xFF632F1F,0xFF733723,0xFF7F3B2B,
0xFF8F4333,0xFF9F4F33,0xFFAF632F,0xFFBF772F,0xFFCF8F2B,0xFFDFAB27,0xFFEFCB1F,0xFFFFF31B,
0xFF0B0700,0xFF1B1300,0xFF2B230F,0xFF372B13,0xFF47331B,0xFF533723,0xFF633F2B,0xFF6F4733,
0xFF7F533F,0xFF8B5F47,0xFF9B6B53,0xFFA77B5F,0xFFB7876B,0xFFC3937B,0xFFD3A38B,0xFFE3B397,
0xFFAB8BA3,0xFF9F7F97,0xFF937387,0xFF8B677B,0xFF7F5B6F,0xFF775363,0xFF6B4B57,0xFF5F3F4B,
0xFF573743,0xFF4B2F37,0xFF43272F,0xFF371F23,0xFF2B171B,0xFF231313,0xFF170B0B,0xFF0F0707,
0xFFBB739F,0xFFAF6B8F,0xFFA35F83,0xFF975777,0xFF8B4F6B,0xFF7F4B5F,0xFF734353,0xFF6B3B4B,
0xFF5F333F,0xFF532B37,0xFF47232B,0xFF3B1F23,0xFF2F171B,0xFF231313,0xFF170B0B,0xFF0F0707,
0xFFDBC3BB,0xFFCBB3A7,0xFFBFA39B,0xFFAF978B,0xFFA3877B,0xFF977B6F,0xFF876F5F,0xFF7B6353,
0xFF6B5747,0xFF5F4B3B,0xFF533F33,0xFF433327,0xFF372B1F,0xFF271F17,0xFF1B130F,0xFF0F0B07,
0xFF6F837B,0xFF677B6F,0xFF5F7367,0xFF576B5F,0xFF4F6357,0xFF475B4F,0xFF3F5347,0xFF374B3F,
0xFF2F4337,0xFF2B3B2F,0xFF233327,0xFF1F2B1F,0xFF172317,0xFF0F1B13,0xFF0B130B,0xFF070B07,
0xFFFFF31B,0xFFEFDF17,0xFFDBCB13,0xFFCBB70F,0xFFBBA70F,0xFFAB970B,0xFF9B8307,0xFF8B7307,
0xFF7B6307,0xFF6B5300,0xFF5B4700,0xFF4B3700,0xFF3B2B00,0xFF2B1F00,0xFF1B0F00,0xFF0B0700,
0xFF0000FF,0xFF0B0BEF,0xFF1313DF,0xFF1B1BCF,0xFF2323BF,0xFF2B2BAF,0xFF2F2F9F,0xFF2F2F8F,
0xFF2F2F7F,0xFF2F2F6F,0xFF2F2F5F,0xFF2B2B4F,0xFF23233F,0xFF1B1B2F,0xFF13131F,0xFF0B0B0F,
0xFF2B0000,0xFF3B0000,0xFF4B0700,0xFF5F0700,0xFF6F0F00,0xFF7F1707,0xFF931F07,0xFFA3270B,
0xFFB7330F,0xFFC34B1B,0xFFCF632B,0xFFDB7F3B,0xFFE3974F,0xFFE7AB5F,0xFFEFBF77,0xFFF7D38B,
0xFFA77B3B,0xFFB79B37,0xFFC7C337,0xFFE7E357,0xFF7FBFFF,0xFFABE7FF,0xFFD7FFFF,0xFF670000,
0xFF8B0000,0xFFB30000,0xFFD70000,0xFFFF0000,0xFFFFF393,0xFFFFF7C7,0xFFFFFFFF,0x009F5B53
};
// Palette quake2 demo pics/colormap.pcx, last is transparent
static const u32 colormap_pcx[256] = {
0xFF000000,0xFF0F0F0F,0xFF1F1F1F,0xFF2F2F2F,0xFF3F3F3F,0xFF4B4B4B,0xFF5B5B5B,0xFF6B6B6B,
0xFF7B7B7B,0xFF8B8B8B,0xFF9B9B9B,0xFFABABAB,0xFFBBBBBB,0xFFCBCBCB,0xFFDBDBDB,0xFFEBEBEB,
0xFF634B23,0xFF5B431F,0xFF533F1F,0xFF4F3B1B,0xFF47371B,0xFF3F2F17,0xFF3B2B17,0xFF332713,
0xFF2F2313,0xFF2B1F13,0xFF271B0F,0xFF23170F,0xFF1B130B,0xFF170F0B,0xFF130F07,0xFF0F0B07,
0xFF5F5F6F,0xFF5B5B67,0xFF5B535F,0xFF574F5B,0xFF534B53,0xFF4F474B,0xFF473F43,0xFF3F3B3B,
0xFF3B3737,0xFF332F2F,0xFF2F2B2B,0xFF272727,0xFF232323,0xFF1B1B1B,0xFF171717,0xFF131313,
0xFF8F7753,0xFF7B6343,0xFF735B3B,0xFF674F2F,0xFFCF974B,0xFFA77B3B,0xFF8B672F,0xFF6F5327,
0xFFEB9F27,0xFFCB8B23,0xFFAF771F,0xFF93631B,0xFF774F17,0xFF5B3B0F,0xFF3F270B,0xFF231707,
0xFFA73B2B,0xFF9F2F23,0xFF972B1B,0xFF8B2713,0xFF7F1F0F,0xFF73170B,0xFF671707,0xFF571300,
0xFF4B0F00,0xFF430F00,0xFF3B0F00,0xFF330B00,0xFF2B0B00,0xFF230B00,0xFF1B0700,0xFF130700,
0xFF7B5F4B,0xFF735743,0xFF6B533F,0xFF674F3B,0xFF5F4737,0xFF574333,0xFF533F2F,0xFF4B372B,
0xFF433327,0xFF3F2F23,0xFF37271B,0xFF2F2317,0xFF271B13,0xFF1F170F,0xFF170F0B,0xFF0F0B07,
0xFF6F3B17,0xFF5F3717,0xFF532F17,0xFF432B17,0xFF372313,0xFF271B0F,0xFF1B130B,0xFF0F0B07,
0xFFB35B4F,0xFFBF7B6F,0xFFCB9B93,0xFFD7BBB7,0xFFCBD7DF,0xFFB3C7D3,0xFF9FB7C3,0xFF87A7B7,
0xFF7397A7,0xFF5B879B,0xFF47778B,0xFF2F677F,0xFF17536F,0xFF134B67,0xFF0F435B,0xFF0B3F53,
0xFF07374B,0xFF072F3F,0xFF072733,0xFF001F2B,0xFF00171F,0xFF000F13,0xFF00070B,0xFF000000,
0xFF8B5757,0xFF834F4F,0xFF7B4747,0xFF734343,0xFF6B3B3B,0xFF633333,0xFF5B2F2F,0xFF572B2B,
0xFF4B2323,0xFF3F1F1F,0xFF331B1B,0xFF2B1313,0xFF1F0F0F,0xFF130B0B,0xFF0B0707,0xFF000000,
0xFF979F7B,0xFF8F9773,0xFF878B6B,0xFF7F8363,0xFF777B5F,0xFF737357,0xFF6B6B4F,0xFF636347,
0xFF5B5B43,0xFF4F4F3B,0xFF434333,0xFF37372B,0xFF2F2F23,0xFF23231B,0xFF171713,0xFF0F0F0B,
0xFF9F4B3F,0xFF934337,0xFF8B3B2F,0xFF7F3727,0xFF772F23,0xFF6B2B1B,0xFF632317,0xFF571F13,
0xFF4F1B0F,0xFF43170B,0xFF37130B,0xFF2B0F07,0xFF1F0B07,0xFF170700,0xFF0B0000,0xFF000000,
0xFF777BCF,0xFF6F73C3,0xFF676BB7,0xFF6363A7,0xFF5B5B9B,0xFF53578F,0xFF4B4F7F,0xFF474773,
0xFF3F3F67,0xFF373757,0xFF2F2F4B,0xFF27273F,0xFF231F2F,0xFF1B1723,0xFF130F17,0xFF0B0707,
0xFF9BAB7B,0xFF8F9F6F,0xFF879763,0xFF7B8B57,0xFF73834B,0xFF677743,0xFF5F6F3B,0xFF576733,
0xFF4B5B27,0xFF3F4F1B,0xFF374313,0xFF2F3B0B,0xFF232F07,0xFF1B2300,0xFF131700,0xFF0B0F00,
0xFF00FF00,0xFF23E70F,0xFF3FD31B,0xFF53BB27,0xFF5FA72F,0xFF5F8F33,0xFF5F7B33,0xFFFFFFFF,
0xFFFFFFD3,0xFFFFFFA7,0xFFFFFF7F,0xFFFFFF53,0xFFFFFF27,0xFFFFEB1F,0xFFFFD717,0xFFFFBF0F,
0xFFFFAB07,0xFFFF9300,0xFFEF7F00,0xFFE36B00,0xFFD35700,0xFFC74700,0xFFB73B00,0xFFAB2B00,
0xFF9B1F00,0xFF8F1700,0xFF7F0F00,0xFF730700,0xFF5F0000,0xFF470000,0xFF2F0000,0xFF1B0000,
0xFFEF0000,0xFF3737FF,0xFFFF0000,0xFF0000FF,0xFF2B2B23,0xFF1B1B17,0xFF13130F,0xFFEB977F,
0xFFC37353,0xFF9F5733,0xFF7B3F1B,0xFFEBD3C7,0xFFC7AB9B,0xFFA78B77,0xFF876B57,0x009F5B53
};
#if 0
// palette halflife gfx/palette.lmp only 1 entry difference.. transparent = 0,0,255
static const u32 palette_lmp[256] = {
0xFF000000,0xFF0F0F0F,0xFF1F1F1F,0xFF2F2F2F,0xFF3F3F3F,0xFF4B4B4B,0xFF5B5B5B,0xFF6B6B6B,
0xFF7B7B7B,0xFF8B8B8B,0xFF9B9B9B,0xFFABABAB,0xFFBBBBBB,0xFFCBCBCB,0xFFDBDBDB,0xFFEBEBEB,
0xFF0F0B07,0xFF170F0B,0xFF1F170B,0xFF271B0F,0xFF2F2313,0xFF372B17,0xFF3F2F17,0xFF4B371B,
0xFF533B1B,0xFF5B431F,0xFF634B1F,0xFF6B531F,0xFF73571F,0xFF7B5F23,0xFF836723,0xFF8F6F23,
0xFF0B0B0F,0xFF13131B,0xFF1B1B27,0xFF272733,0xFF2F2F3F,0xFF37374B,0xFF3F3F57,0xFF474767,
0xFF4F4F73,0xFF5B5B7F,0xFF63638B,0xFF6B6B97,0xFF7373A3,0xFF7B7BAF,0xFF8383BB,0xFF8B8BCB,
0xFF000000,0xFF070700,0xFF0B0B00,0xFF131300,0xFF1B1B00,0xFF232300,0xFF2B2B07,0xFF2F2F07,
0xFF373707,0xFF3F3F07,0xFF474707,0xFF4B4B0B,0xFF53530B,0xFF5B5B0B,0xFF63630B,0xFF6B6B0F,
0xFF070000,0xFF0F0000,0xFF170000,0xFF1F0000,0xFF270000,0xFF2F0000,0xFF370000,0xFF3F0000,
0xFF470000,0xFF4F0000,0xFF570000,0xFF5F0000,0xFF670000,0xFF6F0000,0xFF770000,0xFF7F0000,
0xFF131300,0xFF1B1B00,0xFF232300,0xFF2F2B00,0xFF372F00,0xFF433700,0xFF4B3B07,0xFF574307,
0xFF5F4707,0xFF6B4B0B,0xFF77530F,0xFF835713,0xFF8B5B13,0xFF975F1B,0xFFA3631F,0xFFAF6723,
0xFF231307,0xFF2F170B,0xFF3B1F0F,0xFF4B2313,0xFF572B17,0xFF632F1F,0xFF733723,0xFF7F3B2B,
0xFF8F4333,0xFF9F4F33,0xFFAF632F,0xFFBF772F,0xFFCF8F2B,0xFFDFAB27,0xFFEFCB1F,0xFFFFF31B,
0xFF0B0700,0xFF1B1300,0xFF2B230F,0xFF372B13,0xFF47331B,0xFF533723,0xFF633F2B,0xFF6F4733,
0xFF7F533F,0xFF8B5F47,0xFF9B6B53,0xFFA77B5F,0xFFB7876B,0xFFC3937B,0xFFD3A38B,0xFFE3B397,
0xFFAB8BA3,0xFF9F7F97,0xFF937387,0xFF8B677B,0xFF7F5B6F,0xFF775363,0xFF6B4B57,0xFF5F3F4B,
0xFF573743,0xFF4B2F37,0xFF43272F,0xFF371F23,0xFF2B171B,0xFF231313,0xFF170B0B,0xFF0F0707,
0xFFBB739F,0xFFAF6B8F,0xFFA35F83,0xFF975777,0xFF8B4F6B,0xFF7F4B5F,0xFF734353,0xFF6B3B4B,
0xFF5F333F,0xFF532B37,0xFF47232B,0xFF3B1F23,0xFF2F171B,0xFF231313,0xFF170B0B,0xFF0F0707,
0xFFDBC3BB,0xFFCBB3A7,0xFFBFA39B,0xFFAF978B,0xFFA3877B,0xFF977B6F,0xFF876F5F,0xFF7B6353,
0xFF6B5747,0xFF5F4B3B,0xFF533F33,0xFF433327,0xFF372B1F,0xFF271F17,0xFF1B130F,0xFF0F0B07,
0xFF6F837B,0xFF677B6F,0xFF5F7367,0xFF576B5F,0xFF4F6357,0xFF475B4F,0xFF3F5347,0xFF374B3F,
0xFF2F4337,0xFF2B3B2F,0xFF233327,0xFF1F2B1F,0xFF172317,0xFF0F1B13,0xFF0B130B,0xFF070B07,
0xFFFFF31B,0xFFEFDF17,0xFFDBCB13,0xFFCBB70F,0xFFBBA70F,0xFFAB970B,0xFF9B8307,0xFF8B7307,
0xFF7B6307,0xFF6B5300,0xFF5B4700,0xFF4B3700,0xFF3B2B00,0xFF2B1F00,0xFF1B0F00,0xFF0B0700,
0xFF0000FF,0xFF0B0BEF,0xFF1313DF,0xFF1B1BCF,0xFF2323BF,0xFF2B2BAF,0xFF2F2F9F,0xFF2F2F8F,
0xFF2F2F7F,0xFF2F2F6F,0xFF2F2F5F,0xFF2B2B4F,0xFF23233F,0xFF1B1B2F,0xFF13131F,0xFF0B0B0F,
0xFF2B0000,0xFF3B0000,0xFF4B0700,0xFF5F0700,0xFF6F0F00,0xFF7F1707,0xFF931F07,0xFFA3270B,
0xFFB7330F,0xFFC34B1B,0xFFCF632B,0xFFDB7F3B,0xFFE3974F,0xFFE7AB5F,0xFFEFBF77,0xFFF7D38B,
0xFFA77B3B,0xFFB79B37,0xFFC7C337,0xFFE7E357,0xFF00FF00,0xFFABE7FF,0xFFD7FFFF,0xFF670000,
0xFF8B0000,0xFFB30000,0xFFD70000,0xFFFF0000,0xFFFFF393,0xFFFFF7C7,0xFFFFFFFF,0xFF9F5B53
};
#endif
bool CImageLoaderLMP::isALoadableFileExtension(const io::path& filename) const
{
return core::hasFileExtension ( filename, "lmp" );
}
bool CImageLoaderLMP::isALoadableFileFormat(irr::io::IReadFile* file) const
{
return false;
}
/*!
Quake1, Quake2, Hallife lmp texture
*/
IImage* CImageLoaderLMP::loadImage(irr::io::IReadFile* file) const
{
SLMPHeader header;
file->seek(0);
file->read(&header, sizeof(header));
// maybe palette file
u32 rawtexsize = header.width * header.height;
if ( rawtexsize + sizeof ( header ) != file->getSize() )
return 0;
u8 *rawtex = new u8 [ rawtexsize ];
file->read(rawtex, rawtexsize);
IImage* image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(header.width, header.height));
CColorConverter::convert8BitTo32Bit(rawtex, (u8*)image->lock(), header.width, header.height, (u8*) colormap_h, 0, false);
image->unlock();
delete [] rawtex;
return image;
}
/*!
Halflife
*/
bool CImageLoaderWAL2::isALoadableFileExtension(const io::path& filename) const
{
// embedded in Wad(WAD3 format). originally it has no extension
return core::hasFileExtension ( filename, "wal2" );
}
bool CImageLoaderWAL2::isALoadableFileFormat(irr::io::IReadFile* file) const
{
return false;
}
/*
Halflite Texture WAD
*/
IImage* CImageLoaderWAL2::loadImage(irr::io::IReadFile* file) const
{
miptex_halflife header;
file->seek(0);
file->read(&header, sizeof(header));
#ifdef __BIG_ENDIAN__
header.width = os::Byteswap::byteswap(header.width);
header.height = os::Byteswap::byteswap(header.height);
#endif
// palette
//u32 paletteofs = header.mipmap[0] + ((rawtexsize * 85) >> 6) + 2;
u32 *pal = new u32 [ 192 + 256 ];
u8 *s = (u8*) pal;
file->seek ( file->getSize() - 768 - 2 );
file->read ( s, 768 );
u32 i;
for ( i = 0; i < 256; ++i, s+= 3 )
{
pal [ 192 + i ] = 0xFF000000 | s[0] << 16 | s[1] << 8 | s[2];
}
ECOLOR_FORMAT format = ECF_R8G8B8;
// transparency in filename;-) funny. rgb:0x0000FF is colorkey
if ( file->getFileName().findFirst ( '{' ) >= 0 )
{
format = ECF_A8R8G8B8;
pal [ 192 + 255 ] &= 0x00FFFFFF;
}
u32 rawtexsize = header.width * header.height;
u8 *rawtex = new u8 [ rawtexsize ];
file->seek ( header.mipmap[0] );
file->read(rawtex, rawtexsize);
IImage* image = new CImage(format, core::dimension2d<u32>(header.width, header.height));
switch ( format )
{
case ECF_R8G8B8:
CColorConverter::convert8BitTo24Bit(rawtex, (u8*)image->lock(), header.width, header.height, (u8*) pal + 768, 0, false);
break;
case ECF_A8R8G8B8:
CColorConverter::convert8BitTo32Bit(rawtex, (u8*)image->lock(), header.width, header.height, (u8*) pal + 768, 0, false);
break;
}
image->unlock();
delete [] rawtex;
delete [] pal;
return image;
}
bool CImageLoaderWAL::isALoadableFileExtension(const io::path& filename) const
{
return core::hasFileExtension ( filename, "wal" );
}
bool CImageLoaderWAL::isALoadableFileFormat(irr::io::IReadFile* file) const
{
return false;
}
/*!
quake2
*/
IImage* CImageLoaderWAL::loadImage(irr::io::IReadFile* file) const
{
miptex_quake2 header;
file->seek(0);
file->read(&header, sizeof(header));
#ifdef __BIG_ENDIAN__
header.width = os::Byteswap::byteswap(header.width);
header.height = os::Byteswap::byteswap(header.height);
#endif
u32 rawtexsize = header.width * header.height;
u8 *rawtex = new u8 [ rawtexsize ];
file->seek ( header.mipmap[0] );
file->read(rawtex, rawtexsize);
IImage* image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(header.width, header.height));
CColorConverter::convert8BitTo32Bit(rawtex, (u8*)image->lock(), header.width, header.height, (u8*) colormap_pcx, 0, false);
image->unlock();
delete [] rawtex;
return image;
}
IImageLoader* createImageLoaderHalfLife()
{
return new irr::video::CImageLoaderWAL2();
}
IImageLoader* createImageLoaderWAL()
{
return new irr::video::CImageLoaderWAL();
}
IImageLoader* createImageLoaderLMP()
{
return new irr::video::CImageLoaderLMP();
}
} }
} }
......
...@@ -17,6 +17,7 @@ namespace irr ...@@ -17,6 +17,7 @@ namespace irr
{ {
namespace video namespace video
{ {
#if 0
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__) #if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
# pragma pack( push, packing ) # pragma pack( push, packing )
...@@ -62,6 +63,80 @@ private: ...@@ -62,6 +63,80 @@ private:
static s32 DefaultPaletteQ2[256]; static s32 DefaultPaletteQ2[256];
}; };
#endif
//! An Irrlicht image loader for Quake1,2 engine lmp textures/palette
class CImageLoaderLMP : public irr::video::IImageLoader
{
public:
virtual bool isALoadableFileExtension(const io::path& filename) const;
virtual bool isALoadableFileFormat(irr::io::IReadFile* file) const;
virtual irr::video::IImage* loadImage(irr::io::IReadFile* file) const;
};
//! An Irrlicht image loader for quake2 wal engine textures
class CImageLoaderWAL : public irr::video::IImageLoader
{
public:
virtual bool isALoadableFileExtension(const io::path& filename) const;
virtual bool isALoadableFileFormat(irr::io::IReadFile* file) const;
virtual irr::video::IImage* loadImage(irr::io::IReadFile* file) const;
};
//! An Irrlicht image loader for Halife 1 engine textures
class CImageLoaderWAL2 : public irr::video::IImageLoader
{
public:
virtual bool isALoadableFileExtension(const io::path& filename) const;
virtual bool isALoadableFileFormat(irr::io::IReadFile* file) const;
virtual irr::video::IImage* loadImage(irr::io::IReadFile* file) const;
};
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
# pragma pack( push, packing )
# pragma pack( 1 )
# define PACK_STRUCT
#elif defined( __GNUC__ )
# define PACK_STRUCT __attribute__((packed))
#else
# error compiler not supported
#endif
struct SLMPHeader {
u32 width; // width
u32 height; // height
// variably sized
} PACK_STRUCT;
// Halfelife wad3 type 67 file
struct miptex_halflife
{
c8 name[16];
u32 width, height;
u32 mipmap[4]; // four mip maps stored
} PACK_STRUCT;
//quake2 texture
struct miptex_quake2
{
c8 name[32];
u32 width;
u32 height;
u32 mipmap[4]; // four mip maps stored
c8 animname[32]; // next frame in animation chain
s32 flags;
s32 contents;
s32 value;
};
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
# pragma pack( pop, packing )
#endif
#undef PACK_STRUCT
} }
} }
......
...@@ -45,6 +45,12 @@ IImageLoader* createImageLoaderPNG(); ...@@ -45,6 +45,12 @@ IImageLoader* createImageLoaderPNG();
//! creates a loader which is able to load WAL images //! creates a loader which is able to load WAL images
IImageLoader* createImageLoaderWAL(); IImageLoader* createImageLoaderWAL();
//! creates a loader which is able to load halflife images
IImageLoader* createImageLoaderHalfLife();
//! creates a loader which is able to load lmp images
IImageLoader* createImageLoaderLMP();
//! creates a loader which is able to load ppm/pgm/pbm images //! creates a loader which is able to load ppm/pgm/pbm images
IImageLoader* createImageLoaderPPM(); IImageLoader* createImageLoaderPPM();
...@@ -123,6 +129,13 @@ CNullDriver::CNullDriver(io::IFileSystem* io, const core::dimension2d<u32>& scre ...@@ -123,6 +129,13 @@ CNullDriver::CNullDriver(io::IFileSystem* io, const core::dimension2d<u32>& scre
#ifdef _IRR_COMPILE_WITH_WAL_LOADER_ #ifdef _IRR_COMPILE_WITH_WAL_LOADER_
SurfaceLoader.push_back(video::createImageLoaderWAL()); SurfaceLoader.push_back(video::createImageLoaderWAL());
#endif #endif
#ifdef _IRR_COMPILE_WITH_LMP_LOADER_
SurfaceLoader.push_back(video::createImageLoaderLMP());
#endif
#ifdef _IRR_COMPILE_WITH_HALFLIFE_LOADER_
SurfaceLoader.push_back(video::createImageLoaderHalfLife());
#endif
#ifdef _IRR_COMPILE_WITH_PPM_LOADER_ #ifdef _IRR_COMPILE_WITH_PPM_LOADER_
SurfaceLoader.push_back(video::createImageLoaderPPM()); SurfaceLoader.push_back(video::createImageLoaderPPM());
#endif #endif
......
...@@ -29,6 +29,10 @@ ...@@ -29,6 +29,10 @@
#include "CMD2MeshFileLoader.h" #include "CMD2MeshFileLoader.h"
#endif #endif
#ifdef _IRR_COMPILE_WITH_HALFLIFE_LOADER_
#include "CAnimatedMeshHalfLife.h"
#endif
#ifdef _IRR_COMPILE_WITH_MS3D_LOADER_ #ifdef _IRR_COMPILE_WITH_MS3D_LOADER_
#include "CMS3DMeshFileLoader.h" #include "CMS3DMeshFileLoader.h"
#endif #endif
...@@ -222,6 +226,9 @@ CSceneManager::CSceneManager(video::IVideoDriver* driver, io::IFileSystem* fs, ...@@ -222,6 +226,9 @@ CSceneManager::CSceneManager(video::IVideoDriver* driver, io::IFileSystem* fs,
#ifdef _IRR_COMPILE_WITH_MS3D_LOADER_ #ifdef _IRR_COMPILE_WITH_MS3D_LOADER_
MeshLoaderList.push_back(new CMS3DMeshFileLoader(Driver)); MeshLoaderList.push_back(new CMS3DMeshFileLoader(Driver));
#endif #endif
#ifdef _IRR_COMPILE_WITH_HALFLIFE_LOADER_
MeshLoaderList.push_back(new CHalflifeMDLMeshFileLoader( this ));
#endif
#ifdef _IRR_COMPILE_WITH_3DS_LOADER_ #ifdef _IRR_COMPILE_WITH_3DS_LOADER_
MeshLoaderList.push_back(new C3DSMeshFileLoader(this, FileSystem)); MeshLoaderList.push_back(new C3DSMeshFileLoader(this, FileSystem));
#endif #endif
......
...@@ -331,8 +331,9 @@ void CShadowVolumeSceneNode::render() ...@@ -331,8 +331,9 @@ void CShadowVolumeSceneNode::render()
driver->setTransform(video::ETS_WORLD, Parent->getAbsoluteTransformation()); driver->setTransform(video::ETS_WORLD, Parent->getAbsoluteTransformation());
for (u32 i=0; i<ShadowVolumesUsed; ++i) for (u32 i=0; i<ShadowVolumesUsed; ++i)
driver->drawStencilShadowVolume(ShadowVolumes[i].pointer(), {
ShadowVolumes[i].size(), UseZFailMethod); driver->drawStencilShadowVolume(ShadowVolumes[i].pointer(),ShadowVolumes[i].size(), UseZFailMethod);
}
} }
......
...@@ -348,9 +348,12 @@ CBurningVideoDriver::CBurningVideoDriver(const irr::SIrrlichtCreationParameters& ...@@ -348,9 +348,12 @@ CBurningVideoDriver::CBurningVideoDriver(const irr::SIrrlichtCreationParameters&
BackBuffer->fill(SColor(0)); BackBuffer->fill(SColor(0));
// create z buffer // create z buffer
DepthBuffer = video::createDepthBuffer(BackBuffer->getDimension()); if ( params.ZBufferBits )
DepthBuffer = video::createDepthBuffer(BackBuffer->getDimension());
// create stencil buffer // create stencil buffer
StencilBuffer = video::createStencilBuffer(BackBuffer->getDimension()); if ( params.Stencilbuffer )
StencilBuffer = video::createStencilBuffer(BackBuffer->getDimension());
} }
// create triangle renderers // create triangle renderers
...@@ -607,6 +610,7 @@ bool CBurningVideoDriver::queryFeature(E_VIDEO_DRIVER_FEATURE feature) const ...@@ -607,6 +610,7 @@ bool CBurningVideoDriver::queryFeature(E_VIDEO_DRIVER_FEATURE feature) const
case EVDF_MIP_MAP: case EVDF_MIP_MAP:
return true; return true;
#endif #endif
case EVDF_STENCIL_BUFFER:
case EVDF_RENDER_TO_TARGET: case EVDF_RENDER_TO_TARGET:
case EVDF_MULTITEXTURE: case EVDF_MULTITEXTURE:
case EVDF_HARDWARE_TL: case EVDF_HARDWARE_TL:
......
...@@ -1395,6 +1395,14 @@ ...@@ -1395,6 +1395,14 @@
RelativePath="C3DSMeshFileLoader.h" RelativePath="C3DSMeshFileLoader.h"
> >
</File> </File>
<File
RelativePath=".\CAnimatedMeshHalfLife.cpp"
>
</File>
<File
RelativePath=".\CAnimatedMeshHalfLife.h"
>
</File>
<File <File
RelativePath="CAnimatedMeshMD2.cpp" RelativePath="CAnimatedMeshMD2.cpp"
> >
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment