* M2 Animations Part 1: Animations work for 2.4.3

the viewer got a new debug tab, which allows to play around with debug settings and animations
This commit is contained in:
shlainn 2011-10-27 23:03:36 +02:00
parent f27b371b86
commit fedeb4d8fe
12 changed files with 1743 additions and 1882 deletions

1384
src/Client/GUI/CM2Mesh.cpp Executable file

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,5 @@
// Copyright (C) 2002-2007 Nikolaus Gebhardt #ifndef __M2_MESH_H_INCLUDED__
// This file is part of the "Irrlicht Engine". #define __M2_MESH_H_INCLUDED__
// For conditions of distribution and use, see copyright notice in irrlicht.h
//New skinned mesh
#ifndef __C_SKINNED_MESH_H_INCLUDED__
#define __C_SKINNED_MESH_H_INCLUDED__
#include "irrlicht/irrlicht.h" #include "irrlicht/irrlicht.h"
@ -17,15 +11,15 @@ namespace scene
class IAnimatedMeshSceneNode; class IAnimatedMeshSceneNode;
class IBoneSceneNode; class IBoneSceneNode;
class CSkinnedMesh: public ISkinnedMesh class CM2Mesh: public ISkinnedMesh
{ {
public: public:
//! constructor //! constructor
CSkinnedMesh(); CM2Mesh();
//! destructor //! destructor
virtual ~CSkinnedMesh(); virtual ~CM2Mesh();
//! returns the amount of frames. If the amount is 1, it is a static (=non animated) mesh. //! returns the amount of frames. If the amount is 1, it is a static (=non animated) mesh.
virtual u32 getFrameCount() const; virtual u32 getFrameCount() const;
@ -58,19 +52,6 @@ namespace scene
//! set user axis aligned bounding box //! set user axis aligned bounding box
virtual void setBoundingBox( const core::aabbox3df& box); virtual void setBoundingBox( const core::aabbox3df& box);
//! recalculates the bounding box
void recalculateBoundingBox()
{
if (LocalBuffers.size())
{
BoundingBox = LocalBuffers[0]->getBoundingBox();
for (u32 i=1; i<LocalBuffers.size(); ++i)
BoundingBox.addInternalBox(LocalBuffers[i]->getBoundingBox());
}
else
BoundingBox.reset(0.0f, 0.0f, 0.0f);
}
//! sets a flag of all contained materials to a new value //! sets a flag of all contained materials to a new value
virtual void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue); virtual void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue);
@ -80,6 +61,8 @@ namespace scene
//! flags the meshbuffer as changed, reloads hardware buffers //! flags the meshbuffer as changed, reloads hardware buffers
virtual void setDirty(E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX); virtual void setDirty(E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX);
//! updates the bounding box
virtual void updateBoundingBox(void);
//! Returns the type of the animated mesh. //! Returns the type of the animated mesh.
virtual E_ANIMATED_MESH_TYPE getMeshType() const; virtual E_ANIMATED_MESH_TYPE getMeshType() const;
@ -159,9 +142,7 @@ private:
void normalizeWeights(); void normalizeWeights();
void buildAll_LocalAnimatedMatrices(); //public? void buildAllAnimatedMatrices(SJoint *Joint=0, SJoint *ParentJoint=0); //public?
void buildAll_GlobalAnimatedMatrices(SJoint *Joint=0, SJoint *ParentJoint=0);
void getFrameData(f32 frame, SJoint *Node, void getFrameData(f32 frame, SJoint *Node,
core::vector3df &position, s32 &positionHint, core::vector3df &position, s32 &positionHint,
@ -192,8 +173,7 @@ private:
f32 AnimationFrames; f32 AnimationFrames;
f32 LastAnimatedFrame; f32 LastAnimatedFrame;
f32 LastSkinnedFrame; bool SkinnedLastFrame;
bool BoneControlUsed;
bool AnimateNormals; bool AnimateNormals;

View File

@ -1,9 +1,8 @@
// #define _DEBUG 1 #define _DEBUG 1
#include <iostream> #include <iostream>
#include "MemoryDataHolder.h" #include "MemoryDataHolder.h"
#include "MemoryInterface.h" #include "MemoryInterface.h"
#include "CM2MeshFileLoader.h" #include "CM2MeshFileLoader.h"
#include "SSkinnedMesh.h"
#include "common.h" #include "common.h"
namespace irr namespace irr
@ -38,7 +37,7 @@ IAnimatedMesh* CM2MeshFileLoader::createMesh(io::IReadFile* file)
if(!file) if(!file)
return 0; return 0;
MeshFile = file; MeshFile = file;
AnimatedMesh = new scene::CSkinnedMesh(); AnimatedMesh = new scene::CM2Mesh();
if ( load() ) if ( load() )
{ {
@ -65,13 +64,6 @@ void CM2MeshFileLoader::ReadVertices()
for(u32 i =0;i<header.nVertices;i++) for(u32 i =0;i<header.nVertices;i++)
{ {
MeshFile->read(&tempM2MVert,sizeof(ModelVertex)); MeshFile->read(&tempM2MVert,sizeof(ModelVertex));
tempYZ = tempM2MVert.pos.Y;
tempM2MVert.pos.Y=tempM2MVert.pos.Z;
tempM2MVert.pos.Z=tempYZ;
tempYZ = tempM2MVert.normal.Y;
tempM2MVert.normal.Y=tempM2MVert.normal.Z;
tempM2MVert.normal.Z=tempYZ;
M2MVertices.push_back(tempM2MVert); M2MVertices.push_back(tempM2MVert);
} }
DEBUG(logdebug("Read %u/%u Vertices",M2MVertices.size(),header.nVertices)); DEBUG(logdebug("Read %u/%u Vertices",M2MVertices.size(),header.nVertices));
@ -114,6 +106,7 @@ void CM2MeshFileLoader::ReadViewData(io::IReadFile* file)
{ {
file->read(&tempM2Submesh,sizeof(ModelViewSubmesh)-(header.version==0x100?16:0)); file->read(&tempM2Submesh,sizeof(ModelViewSubmesh)-(header.version==0x100?16:0));
M2MSubmeshes.push_back(tempM2Submesh); M2MSubmeshes.push_back(tempM2Submesh);
DEBUG(logdebug("Submesh %u nBone: %u ofsBone: %u",i,tempM2Submesh.nBone, tempM2Submesh.ofsBone));
// std::cout<< "Submesh " <<i<<" ID "<<tempM2Submesh.meshpartId<<" starts at V/T "<<tempM2Submesh.ofsVertex<<"/"<<tempM2Submesh.ofsTris<<" and has "<<tempM2Submesh.nVertex<<"/"<<tempM2Submesh.nTris<<" V/T\n"; // std::cout<< "Submesh " <<i<<" ID "<<tempM2Submesh.meshpartId<<" starts at V/T "<<tempM2Submesh.ofsVertex<<"/"<<tempM2Submesh.ofsTris<<" and has "<<tempM2Submesh.nVertex<<"/"<<tempM2Submesh.nTris<<" V/T\n";
} }
DEBUG(logdebug("Read %u/%u Submeshes",M2MSubmeshes.size(),currentView.nSub)); DEBUG(logdebug("Read %u/%u Submeshes",M2MSubmeshes.size(),currentView.nSub));
@ -135,215 +128,54 @@ void CM2MeshFileLoader::ReadViewData(io::IReadFile* file)
} }
void CM2MeshFileLoader::ReadTextureDefinitions() void CM2MeshFileLoader::ReadAnimationData()
{ {
//Texture Lookup table. This is global data
u16 tempM2TexLookup; //Global Sequences. This is global data
if(!M2MTextureLookup.empty()) u32 tempGlobalSeq;
if(!M2MGlobalSequences.empty())
{ {
M2MTextureLookup.clear(); M2MGlobalSequences.clear();
} }
MeshFile->seek(header.ofsTexLookup); MeshFile->seek(header.ofsGlobalSequences);
for(u32 i=0;i<header.nTexLookup;i++) for(u32 i=0;i<header.nGlobalSequences;i++)
{ {
MeshFile->read(&tempM2TexLookup,sizeof(u16)); MeshFile->read(&tempGlobalSeq,sizeof(u32));
M2MTextureLookup.push_back(tempM2TexLookup); M2MGlobalSequences.push_back(tempGlobalSeq);
DEBUG(logdebug("Texture %u Type %u",i,tempM2TexLookup)); DEBUG(logdebug("Global Sequence %u End %u",i,tempGlobalSeq));
} }
DEBUG(logdebug("Read %u Texture lookup entries",M2MTextureLookup.size())); DEBUG(logdebug("Read %u Global Sequence entries",M2MGlobalSequences.size()));
//Texture Definitions table. This is global data //BoneLookupTable. This is global data
TextureDefinition tempM2TexDef; u16 tempBoneLookup;
if(!M2MTextureDef.empty()) if(!M2MBoneLookupTable.empty())
{ {
M2MTextureDef.clear(); M2MBoneLookupTable.clear();
} }
MeshFile->seek(header.ofsTextures); MeshFile->seek(header.ofsBoneLookupTable);
for(u32 i=0;i<header.nTextures;i++) for(u32 i=0;i<header.nBoneLookupTable;i++)
{ {
MeshFile->read(&tempM2TexDef,sizeof(TextureDefinition)); MeshFile->read(&tempBoneLookup,sizeof(u16));
M2MTextureDef.push_back(tempM2TexDef); M2MBoneLookupTable.push_back(tempBoneLookup);
DEBUG(logdebug("Texture %u Type %u",i,tempM2TexDef.texType)); DEBUG(logdebug("BoneLookupTable %u Value %u",i,tempBoneLookup));
} }
DEBUG(logdebug("Read %u Texture Definition entries",M2MTextureDef.size())); DEBUG(logdebug("Read %u BoneLookupTable entries",M2MBoneLookupTable.size()));
//Render Flags table. This is global data //SkeleBoneLookupTable. This is global data
RenderFlags tempM2RF; u16 tempSkeleBoneLookup;
if(!M2MRenderFlags.empty()) if(!M2MSkeleBoneLookupTable.empty())
{ {
M2MRenderFlags.clear(); M2MSkeleBoneLookupTable.clear();
} }
MeshFile->seek(header.ofsTexFlags); MeshFile->seek(header.ofsSkelBoneLookup);
for(u32 i=0;i<header.nTexFlags;i++) for(u32 i=0;i<header.nSkelBoneLookup;i++)
{ {
MeshFile->read(&tempM2RF,sizeof(RenderFlags)); MeshFile->read(&tempSkeleBoneLookup,sizeof(u16));
M2MRenderFlags.push_back(tempM2RF); M2MSkeleBoneLookupTable.push_back(tempSkeleBoneLookup);
DEBUG(logdebug("Flag %u: (%u, %u)",i,tempM2RF.blending,tempM2RF.flags)); DEBUG(logdebug("SkeleBoneLookupTable %u Value %u",i,tempSkeleBoneLookup));
} }
DEBUG(logdebug("Read %u Renderflags",M2MRenderFlags.size())); DEBUG(logdebug("Read %u SkeleBoneLookupTable entries",M2MSkeleBoneLookupTable.size()));
if(!M2MTextureFiles.empty())
M2MTextureFiles.clear();
std::string tempTexFileName="";
M2MTextureFiles.reallocate(M2MTextureDef.size());
for(u32 i=0; i<M2MTextureDef.size(); i++)
{
tempTexFileName.resize(M2MTextureDef[i].texFileLen + 1);
MeshFile->seek(M2MTextureDef[i].texFileOfs);
MeshFile->read((void*)tempTexFileName.data(),M2MTextureDef[i].texFileLen);
M2MTextureFiles.push_back("");
M2MTextureFiles[i]=tempTexFileName.c_str();
DEBUG(logdebug("Texture: %u %u (%s/%s) @ %u(%u)",i,M2MTextureFiles.size(),M2MTextureFiles[i].c_str(),tempTexFileName.c_str(),M2MTextureDef[i].texFileOfs,M2MTextureDef[i].texFileLen));
}
}
bool CM2MeshFileLoader::load()
{
DEBUG(logdebug("Trying to open file %s",MeshFile->getFileName()));
MeshFile->read(&header,20);
DEBUG(logdebug("M2 Version %X",header.version));
switch(header.version)
{
case 0x100:
case 0x104://HACK
case 0x105://HACK
case 0x106://HACK
case 0x107://HACK
{
MeshFile->read((u8*)&header+20,sizeof(ModelHeader)-20);
ReadVertices();
MeshFile->seek(header.ofsViews);
MeshFile->read(&currentView,sizeof(ModelView));
ReadViewData(MeshFile);
ReadTextureDefinitions();
break;
}
case 0x108:
{
return 0;
break;
}
default:
{
logerror("M2: [%s] Wrong header %0X! File version doesn't match or file is not a M2 file.",MeshFile->getFileName(),header.version);
return 0;
}
}
//Vertices. Global data
// if(!M2MVertices.empty())
// M2MVertices.clear();
//
// ModelVertex tempM2MVert;
// f32 tempYZ;
// MeshFile->seek(header.ofsVertices);
//
// for(u32 i =0;i<header.nVertices;i++)
// {
// MeshFile->read(&tempM2MVert,sizeof(ModelVertex));
// tempYZ = tempM2MVert.pos.Y;
// tempM2MVert.pos.Y=tempM2MVert.pos.Z;
// tempM2MVert.pos.Z=tempYZ;
// tempYZ = tempM2MVert.normal.Y;
// tempM2MVert.normal.Y=tempM2MVert.normal.Z;
// tempM2MVert.normal.Z=tempYZ;
//
// M2MVertices.push_back(tempM2MVert);
// }
// DEBUG(logdebug("Read %u/%u Vertices",M2MVertices.size(),header.nVertices));
//Views (skins) == Sets of vertices. Usage yet unknown. Global data
// std::string SkinName = MeshFile->getFileName();
// SkinName = SkinName.substr(0, SkinName.length()-3) + "00.skin"; // FIX ME (and stuffextract) ! as we need more skins
// io::IReadFile* SkinFile = io::IrrCreateIReadFileBasic(Device, SkinName.c_str());
// if (!SkinFile)
// {
// logerror("Error! Skin file not found: %s", SkinName.c_str());
// return 0;
// }
//
// SkinFile->read(&currentView, sizeof(ModelView));
//
// //std::cout << "Skins "<<header.nViews<<" (views)\n";
//
// DEBUG(logdebug("Using View 0 for all further operations"));
// DEBUG(logdebug("This View has %u Submeshes",currentView.nSub));
//
// //Vertex indices of a specific view.Local to View 0
// if(M2MIndices.size()>0)
// M2MIndices.clear();
//
// u16 tempM2Index;
// SkinFile->seek(currentView.ofsIndex);
// for(u32 i =0;i<currentView.nIndex;i++)
// {
// SkinFile->read(&tempM2Index,sizeof(u16));
// M2MIndices.push_back(tempM2Index);
// }
// DEBUG(logdebug("Read %u/%u Indices",M2MIndices.size(),currentView.nIndex));
//
//
// //Triangles. Data Points point to the Vertex Indices, not the vertices themself. 3 Points = 1 Triangle, Local to View 0
// if(M2MTriangles.size()>0)
// M2MTriangles.clear();
//
// u16 tempM2Triangle;
// SkinFile->seek(currentView.ofsTris);
// for(u32 i =0;i<currentView.nTris;i++)
// {
// SkinFile->read(&tempM2Triangle,sizeof(u16));
// M2MTriangles.push_back(tempM2Triangle);
// }
// DEBUG(logdebug("Read %u/%u Triangles",M2MTriangles.size(),currentView.nTris));
// //Submeshes, Local to View 0
// if(M2MSubmeshes.size()>0)
// M2MSubmeshes.clear();
//
// ModelViewSubmesh tempM2Submesh;
// SkinFile->seek(currentView.ofsSub);
// for(u32 i =0;i<currentView.nSub;i++)
// {
// SkinFile->read(&tempM2Submesh,sizeof(ModelViewSubmesh));
// M2MSubmeshes.push_back(tempM2Submesh);
// // std::cout<< "Submesh " <<i<<" ID "<<tempM2Submesh.meshpartId<<" starts at V/T "<<tempM2Submesh.ofsVertex<<"/"<<tempM2Submesh.ofsTris<<" and has "<<tempM2Submesh.nVertex<<"/"<<tempM2Submesh.nTris<<" V/T\n";
// }
// DEBUG(logdebug("Read %u/%u Submeshes",M2MSubmeshes.size(),currentView.nSub));
//
// //Texture units. Local to view 0
// TextureUnit tempM2TexUnit;
// if(!M2MTextureUnit.empty())
// {
// M2MTextureUnit.clear();
// }
// SkinFile->seek(currentView.ofsTex);
// for(u32 i=0;i<currentView.nTex;i++)
// {
// SkinFile->read(&tempM2TexUnit,sizeof(TextureUnit));
// M2MTextureUnit.push_back(tempM2TexUnit);
// DEBUG(logdebug(" TexUnit %u: Submesh: %u %u Render Flag: %u TextureUnitNumber: %u %u TTU: %u",i,tempM2TexUnit.submeshIndex1,tempM2TexUnit.submeshIndex2, tempM2TexUnit.renderFlagsIndex, tempM2TexUnit.TextureUnitNumber, tempM2TexUnit.TextureUnitNumber2 ,tempM2TexUnit.textureIndex));
// }
// DEBUG(logdebug("Read %u Texture Unit entries for View 0",M2MTextureUnit.size()));
//
///////////////////////////////////////
// Animation related stuff //
///////////////////////////////////////
/* ANIMATION NEED FIX !!! - search this text to find all code blocks for animations
printf("Global Sequences: %u\n",header.nGlobalSequences);
//Ignored at the moment, as wolf.m2 has none
printf("Animations: %u\n",header.nAnimations);
//Animations. This is global data //Animations. This is global data
Animation tempAnimation; Animation tempAnimation;
if(!M2MAnimations.empty()) if(!M2MAnimations.empty())
@ -355,12 +187,10 @@ for(u32 i=0;i<header.nAnimations;i++)
{ {
MeshFile->read(&tempAnimation,sizeof(Animation)); MeshFile->read(&tempAnimation,sizeof(Animation));
M2MAnimations.push_back(tempAnimation); M2MAnimations.push_back(tempAnimation);
//std::cout<<tempAnimation.start<<" "<<tempAnimation.end<<"\n"; DEBUG(logdebug("Animation %u Id %u Start %u End %u",i,tempAnimation.animationID,tempAnimation.start,tempAnimation.end));
} }
DEBUG(logdebug("Read %u Animations",M2MAnimations.size())); DEBUG(logdebug("Read %u Animations",M2MAnimations.size()));
printf("Read %u Animations\n",M2MAnimations.size());
printf("Bones: %u\n",header.nBones);
//Bones. This is global data //Bones. This is global data
Bone tempBone; Bone tempBone;
if(!M2MBones.empty()) if(!M2MBones.empty())
@ -375,11 +205,8 @@ for(u32 i=0;i<header.nBones;i++)
MeshFile->read(&tempBone.rotation.header,sizeof(AnimBlockHead)); MeshFile->read(&tempBone.rotation.header,sizeof(AnimBlockHead));
MeshFile->read(&tempBone.scaling.header,sizeof(AnimBlockHead)); MeshFile->read(&tempBone.scaling.header,sizeof(AnimBlockHead));
MeshFile->read(&tempBone.PivotPoint,sizeof(core::vector3df)); MeshFile->read(&tempBone.PivotPoint,sizeof(core::vector3df));
tempYZ=tempBone.PivotPoint.Y;
tempBone.PivotPoint.Y=tempBone.PivotPoint.Z;
tempBone.PivotPoint.Z=tempYZ;
M2MBones.push_back(tempBone); M2MBones.push_back(tempBone);
//std::cout<<i<<":"<<tempBone.flags<<" "<<tempBone.parentBone<<" |"<<tempBone.translation.header.interpolationType<<" "<<tempBone.translation.header.nInterpolationRange<<" "<<tempBone.translation.header.nTimeStamp<<" "<<tempBone.translation.header.nValues<<"|"<<tempBone.rotation.header.interpolationType<<" "<<tempBone.rotation.header.nInterpolationRange<<" "<<tempBone.rotation.header.nTimeStamp<<" "<<tempBone.rotation.header.nValues<<"|"<<tempBone.scaling.header.interpolationType<<" "<<tempBone.scaling.header.nInterpolationRange<<" "<<tempBone.scaling.header.nTimeStamp<<" "<<tempBone.scaling.header.nValues<<"\n"; DEBUG(logdebug("Bone %u Parent %u PP %f %f %f",i,tempBone.parentBone,tempBone.PivotPoint.X,tempBone.PivotPoint.Y,tempBone.PivotPoint.Z));
} }
//Fill in values referenced in Bones. local to each bone //Fill in values referenced in Bones. local to each bone
InterpolationRange tempBoneIR; InterpolationRange tempBoneIR;
@ -476,12 +303,125 @@ for(u32 i=0; i<M2MBones.size(); i++)
DEBUG(logdebug("Read %u Bones",M2MBones.size())); DEBUG(logdebug("Read %u Bones",M2MBones.size()));
scene::CSkinnedMesh::SJoint* Joint;
}
void CM2MeshFileLoader::ReadTextureDefinitions()
{
//Texture Lookup table. This is global data
u16 tempM2TexLookup;
if(!M2MTextureLookup.empty())
{
M2MTextureLookup.clear();
}
MeshFile->seek(header.ofsTexLookup);
for(u32 i=0;i<header.nTexLookup;i++)
{
MeshFile->read(&tempM2TexLookup,sizeof(u16));
M2MTextureLookup.push_back(tempM2TexLookup);
DEBUG(logdebug("Texture %u Type %u",i,tempM2TexLookup));
}
DEBUG(logdebug("Read %u Texture lookup entries",M2MTextureLookup.size()));
//Texture Definitions table. This is global data
TextureDefinition tempM2TexDef;
if(!M2MTextureDef.empty())
{
M2MTextureDef.clear();
}
MeshFile->seek(header.ofsTextures);
for(u32 i=0;i<header.nTextures;i++)
{
MeshFile->read(&tempM2TexDef,sizeof(TextureDefinition));
M2MTextureDef.push_back(tempM2TexDef);
DEBUG(logdebug("Texture %u Type %u",i,tempM2TexDef.texType));
}
DEBUG(logdebug("Read %u Texture Definition entries",M2MTextureDef.size()));
//Render Flags table. This is global data
RenderFlags tempM2RF;
if(!M2MRenderFlags.empty())
{
M2MRenderFlags.clear();
}
MeshFile->seek(header.ofsTexFlags);
for(u32 i=0;i<header.nTexFlags;i++)
{
MeshFile->read(&tempM2RF,sizeof(RenderFlags));
M2MRenderFlags.push_back(tempM2RF);
DEBUG(logdebug("Flag %u: (%u, %u)",i,tempM2RF.blending,tempM2RF.flags));
}
DEBUG(logdebug("Read %u Renderflags",M2MRenderFlags.size()));
if(!M2MTextureFiles.empty())
M2MTextureFiles.clear();
std::string tempTexFileName="";
M2MTextureFiles.reallocate(M2MTextureDef.size());
for(u32 i=0; i<M2MTextureDef.size(); i++)
{
tempTexFileName.resize(M2MTextureDef[i].texFileLen + 1);
MeshFile->seek(M2MTextureDef[i].texFileOfs);
MeshFile->read((void*)tempTexFileName.data(),M2MTextureDef[i].texFileLen);
M2MTextureFiles.push_back("");
M2MTextureFiles[i]=tempTexFileName.c_str();
DEBUG(logdebug("Texture: %u %u (%s/%s) @ %u(%u)",i,M2MTextureFiles.size(),M2MTextureFiles[i].c_str(),tempTexFileName.c_str(),M2MTextureDef[i].texFileOfs,M2MTextureDef[i].texFileLen));
}
}
bool CM2MeshFileLoader::load()
{
DEBUG(logdebug("Trying to open file %s",MeshFile->getFileName()));
MeshFile->read(&header,20);
DEBUG(logdebug("M2 Version %X",header.version));
switch(header.version)
{
case 0x100:
case 0x104://HACK
case 0x105://HACK
case 0x106://HACK
case 0x107://HACK
{
MeshFile->read((u8*)&header+20,sizeof(ModelHeader)-20);
ReadVertices();
MeshFile->seek(header.ofsViews);
MeshFile->read(&currentView,sizeof(ModelView));
ReadViewData(MeshFile);
ReadTextureDefinitions();
ReadAnimationData();
break;
}
case 0x108:
{
return 0;
break;
}
default:
{
logerror("M2: [%s] Wrong header %0X! File version doesn't match or file is not a M2 file.",MeshFile->getFileName(),header.version);
return 0;
}
}
///////////////////////////
// EVERYTHING IS READ
///////////////////////////
///////////////////////////////////////
// Animation related stuff //
///////////////////////////////////////
scene::CM2Mesh::SJoint* Joint;
for(u32 i=0;i<M2MBones.size();i++) for(u32 i=0;i<M2MBones.size();i++)
{ {
if(M2MBones[i].parentBone == -1) if(M2MBones[i].parentBone == -1)
{ {
ParentJoint=(scene::CSkinnedMesh::SJoint*)0; ParentJoint=(scene::CM2Mesh::SJoint*)0;
} }
else else
{ {
@ -489,81 +429,63 @@ for(u32 i=0;i<M2MBones.size();i++)
} }
Joint=AnimatedMesh->createJoint(ParentJoint); Joint=AnimatedMesh->createJoint(ParentJoint);
if(M2MBones[i].translation.header.nValues>0)
//std::cout << i << " "<<Joint->GlobalMatrix.getTranslation().X<< " "<<Joint->GlobalMatrix.getTranslation().Y<< " "<<Joint->GlobalMatrix.getTranslation().Z<<'\n';
//std::cout << i << " "<<M2MBones[i].PivotPoint.X<< " "<<M2MBones[i].PivotPoint.Y<< " "<<M2MBones[i].PivotPoint.Z<<'\n';
/* for(u32 j=0;j<M2MBones[i].translation.header.nValues;j++)
{ {
scene::CSkinnedMesh::SPositionKey* pos=AnimatedMesh->createPositionKey(Joint); for(u32 j=0;j<M2MBones[i].translation.header.nValues;j++)
pos->frame=M2MBones[i].translation.timestamps[j]*.01f; {
scene::CM2Mesh::SPositionKey* pos=AnimatedMesh->createPositionKey(Joint);
pos->frame=M2MBones[i].translation.timestamps[j];
pos->position=core::vector3df(M2MBones[i].translation.values[j*3],M2MBones[i].translation.values[j*3+1],M2MBones[i].translation.values[j*3+2]); pos->position=core::vector3df(M2MBones[i].translation.values[j*3],M2MBones[i].translation.values[j*3+1],M2MBones[i].translation.values[j*3+2]);
} }
}
if(M2MBones[i].rotation.header.nValues>0) if(M2MBones[i].rotation.header.nValues>0)
{ {
for(u32 j=0;j<M2MBones[i].rotation.header.nValues;j++) for(u32 j=0;j<M2MBones[i].rotation.header.nValues;j++)
{ {
scene::CSkinnedMesh::SRotationKey* rot=AnimatedMesh->createRotationKey(Joint); scene::CM2Mesh::SRotationKey* rot=AnimatedMesh->createRotationKey(Joint);
rot->frame=M2MBones[i].rotation.timestamps[j]*.01f; rot->frame=M2MBones[i].rotation.timestamps[j];
core::quaternion tempQ=core::quaternion(M2MBones[i].rotation.values[j*4+0],M2MBones[i].rotation.values[j*4+1],M2MBones[i].rotation.values[j*4+2],M2MBones[i].rotation.values[j*4+3]); core::quaternion tempQ=core::quaternion(-M2MBones[i].rotation.values[j*4+0],-M2MBones[i].rotation.values[j*4+1],-M2MBones[i].rotation.values[j*4+2],M2MBones[i].rotation.values[j*4+3]);
tempQ.normalize();
rot->rotation=tempQ; rot->rotation=tempQ;
// std::cout <<" "<< M2MBones[i].rotation.values[j*4+0] <<" "<< M2MBones[i].rotation.values[j*4+1] <<" "<< M2MBones[i].rotation.values[j*4+2] <<" "<< M2MBones[i].rotation.values[j*4+3] <<'\n';
} }
} }
if(M2MBones[i].scaling.header.nValues>0){
if(M2MBones[i].scaling.header.nValues>0)
{
for(u32 j=0;j<M2MBones[i].scaling.header.nValues;j++) for(u32 j=0;j<M2MBones[i].scaling.header.nValues;j++)
{ {
scene::CSkinnedMesh::SScaleKey* scale=AnimatedMesh->createScaleKey(Joint); scene::CM2Mesh::SScaleKey* scale=AnimatedMesh->createScaleKey(Joint);
scale->frame=M2MBones[i].scaling.timestamps[j]*.01f; scale->frame=M2MBones[i].scaling.timestamps[j];
scale->scale=core::vector3df(M2MBones[i].scaling.values[j*3],M2MBones[i].scaling.values[j*3+1],M2MBones[i].scaling.values[j*3+2]); scale->scale=core::vector3df(M2MBones[i].scaling.values[j*3],M2MBones[i].scaling.values[j*3+1],M2MBones[i].scaling.values[j*3+2]);
} }
*/ }
// Joint->Animatedposition=M2MBones[i].PivotPoint;
// std::cout<<Joint->Animatedposition.X<<' '<<Joint->Animatedposition.Y<<' '<<Joint->Animatedposition.Z<<' '<<'\n'; Joint->Animatedposition=M2MBones[i].PivotPoint;
Joint->Animatedscale=core::vector3df(1.0f,1.0f,1.0f);
Joint->Animatedrotation=core::quaternion(0.0f,0.0f,0.0f,1.0f);
core::matrix4 positionMatrix;
positionMatrix.setTranslation( Joint->Animatedposition );
core::matrix4 rotationMatrix = Joint->Animatedrotation.getMatrix();
// Joint->Animatedscale=core::vector3df(1.0f,1.0f,1.0f);
//Joint->Animatedrotation=core::quaternion(0.0f,0.0f,0.0f,0.0f);
/* core::matrix4 positionMatrix; ANIMATION NEED FIX !!!
// positionMatrix.setTranslation( Joint->Animatedposition );
core::matrix4 scaleMatrix; core::matrix4 scaleMatrix;
//scaleMatrix.setScale( Joint->Animatedscale ); scaleMatrix.setScale( Joint->Animatedscale );
core::matrix4 rotationMatrix;// = Joint->Animatedrotation.getMatrix();
Joint->GlobalMatrix = positionMatrix * rotationMatrix * scaleMatrix;// Joint->GlobalMatrix = positionMatrix * rotationMatrix * scaleMatrix;
if (ParentJoint)
{
core::matrix4 InverseParentGlobal;
ParentJoint->GlobalMatrix.getInverse(InverseParentGlobal);
Joint->LocalMatrix = InverseParentGlobal * Joint->GlobalMatrix;
} }
else
Joint->LocalMatrix = Joint->GlobalMatrix;
}
*/
//std::cout<<AnimatedMesh->getAllJoints()[1]->Children.size()<<" Children\n";
/////////////////////////// //And M2MVertices are not usable like this. Thus we put it into an irrlicht S3DVertex
// EVERYTHING IS READ
///////////////////////////
//And M2MVertices are not usable like this. Thus we transform
if(M2Vertices.size()>0) if(M2Vertices.size()>0)
M2Vertices.clear(); M2Vertices.clear();
for(u32 i=0;i<M2MVertices.size();i++) for(u32 i=0;i<M2MVertices.size();i++)
{ {
//M2Vertices.push_back(video::S3DVertex(core::vector3df(M2MVertices[i].pos.X,M2MVertices[i].pos.Z,M2MVertices[i].pos.Y),core::vector3df(M2MVertices[i].normal.X,M2MVertices[i].normal.Z,M2MVertices[i].normal.Y), video::SColor(255,100,100,100),M2MVertices[i].texcoords));
//rotation happens when reading from file, so swapping Y and Z here is no longer necessary
M2Vertices.push_back(video::S3DVertex(core::vector3df(M2MVertices[i].pos.X,M2MVertices[i].pos.Y,M2MVertices[i].pos.Z),core::vector3df(M2MVertices[i].normal.X,M2MVertices[i].normal.Y,M2MVertices[i].normal.Z), video::SColor(255,100,100,100),M2MVertices[i].texcoords)); M2Vertices.push_back(video::S3DVertex(core::vector3df(M2MVertices[i].pos.X,M2MVertices[i].pos.Y,M2MVertices[i].pos.Z),core::vector3df(M2MVertices[i].normal.X,M2MVertices[i].normal.Y,M2MVertices[i].normal.Z), video::SColor(255,100,100,100),M2MVertices[i].texcoords));
} }
//Loop through the submeshes //Loop through the submeshes
@ -583,58 +505,36 @@ for(u32 i=0; i < currentView.nSub;i++)//
for(u32 j=M2MSubmeshes[i].ofsVertex;j<M2MSubmeshes[i].ofsVertex+M2MSubmeshes[i].nVertex;j++) for(u32 j=M2MSubmeshes[i].ofsVertex;j<M2MSubmeshes[i].ofsVertex+M2MSubmeshes[i].nVertex;j++)
{ {
MeshBuffer->Vertices_Standard.push_back(M2Vertices[j]); MeshBuffer->Vertices_Standard.push_back(M2Vertices[j]);
// for(u32 k=0; k<4; k++) for(u32 k=0; k<4; k++)
// { {
//std::cout << (u32)M2MVertices[j].bones[k] << " ";
/* ANIMATION NEED FIX !!!
if((M2MVertices[j].weights[k]/255.0f)>0.0f) if((M2MVertices[j].weights[k]/255.0f)>0.0f)
{ {
scene::CSkinnedMesh::SWeight* weight = AnimatedMesh->createWeight(AnimatedMesh->getAllJoints()[(u32)M2MVertices[j].bones[k]]); scene::CM2Mesh::SWeight* weight = AnimatedMesh->createWeight(AnimatedMesh->getAllJoints()[(u32)M2MVertices[j].bones[k]]);
weight->strength=M2MVertices[j].weights[k]/255.0f; weight->strength=M2MVertices[j].weights[k]/255.0f;
weight->vertex_id=j-M2MSubmeshes[i].ofsVertex; weight->vertex_id=MeshBuffer->Vertices_Standard.size()-1;
weight->buffer_id=i; weight->buffer_id=i;
} }
*/
//std::cout<<weight->buffer_id << " " << weight->vertex_id << " " << weight->strength <<"|"; }
// }
// std::cout<<'\n';
} }
//std::cout << i << ": " << MeshBuffer->Vertices_Standard.size() <<" "<<M2MSubmeshes[i].ofsVertex<<" "<<M2MSubmeshes[i].nVertex<< "\n";
MeshBuffer->recalculateBoundingBox(); MeshBuffer->recalculateBoundingBox();
//MeshBuffer->getMaterial().DiffuseColor.set(255,255-(u32)(255/(M2MSubmeshes.size()))*i,(u32)(255/(M2MSubmeshes.size()))*i,0);
//MeshBuffer->getMaterial().DiffuseColor.set(255,(M2MSubmeshes[i].meshpartId==0?0:255),(M2MSubmeshes[i].meshpartId==0?255:0),0);
for(u32 j=0;j<M2MTextureUnit.size();j++)//Loop through texture units for(u32 j=0;j<M2MTextureUnit.size();j++)//Loop through texture units
{ {
if(M2MTextureUnit[j].submeshIndex1==i && !M2MTextureFiles[M2MTextureLookup[M2MTextureUnit[j].textureIndex]].empty())//if a texture unit belongs to this submesh if(M2MTextureUnit[j].submeshIndex1==i && !M2MTextureFiles[M2MTextureLookup[M2MTextureUnit[j].textureIndex]].empty())//if a texture unit belongs to this submesh
{ {
// std::string TexName=Texdir.c_str();
// TexName+="/";
// if(i<M2MTextureUnit.size())
// TexName+=M2MTextureFiles[M2MTextureLookup[M2MTextureUnit[j].textureIndex]].c_str();
/* while(TexName.find('\\')<TexName.size())//Replace \ by /
{
TexName.replace(TexName.find('\\'),1,"/");
}
while(TexName.find(' ')<TexName.size())//Replace space by _
{
TexName.replace(TexName.find(' '),1,"_");
}
std::transform(TexName.begin(), TexName.end(), TexName.begin(), tolower);*/
char buf[1000]; char buf[1000];
MemoryDataHolder::MakeTextureFilename(buf,M2MTextureFiles[M2MTextureLookup[M2MTextureUnit[j].textureIndex]].c_str()); MemoryDataHolder::MakeTextureFilename(buf,M2MTextureFiles[M2MTextureLookup[M2MTextureUnit[j].textureIndex]].c_str());
video::ITexture* tex = Device->getVideoDriver()->findTexture(buf); video::ITexture* tex = Device->getVideoDriver()->findTexture(buf);
if(!tex) if(!tex)
{ {
io::IReadFile* TexFile = io::IrrCreateIReadFileBasic(Device, buf); io::IReadFile* TexFile = io::IrrCreateIReadFileBasic(Device, buf);
// logdebug("Texture %s loading",M2MTextureFiles[M2MTextureLookup[M2MTextureUnit[j].textureIndex]].c_str());
if (!TexFile) if (!TexFile)
{ {
logerror("CM2MeshFileLoader: Texture file not found: %s", buf); logerror("CM2MeshFileLoader: Texture file not found: %s", buf);
continue; continue;
} }
// logdebug("Texture %s loaded",M2MTextureFiles[M2MTextureLookup[M2MTextureUnit[j].textureIndex]].c_str());
tex = Device->getVideoDriver()->getTexture(TexFile); tex = Device->getVideoDriver()->getTexture(TexFile);
TexFile->drop(); TexFile->drop();
} }
@ -642,32 +542,28 @@ for(u32 i=0; i < currentView.nSub;i++)//
DEBUG(logdebug("Render Flags: %u %u",M2MRenderFlags[M2MTextureUnit[j].renderFlagsIndex].flags,M2MRenderFlags[M2MTextureUnit[j].renderFlagsIndex].blending)); DEBUG(logdebug("Render Flags: %u %u",M2MRenderFlags[M2MTextureUnit[j].renderFlagsIndex].flags,M2MRenderFlags[M2MTextureUnit[j].renderFlagsIndex].blending));
MeshBuffer->getMaterial().BackfaceCulling=(M2MRenderFlags[M2MTextureUnit[j].renderFlagsIndex].flags & 0x04)?false:true; MeshBuffer->getMaterial().BackfaceCulling=(M2MRenderFlags[M2MTextureUnit[j].renderFlagsIndex].flags & 0x04)?false:true;
if(M2MRenderFlags[M2MTextureUnit[j].renderFlagsIndex].blending==1) switch(M2MRenderFlags[M2MTextureUnit[j].renderFlagsIndex].blending)
{
case 1:
case 2:
case 4:
MeshBuffer->getMaterial().MaterialType=video::EMT_TRANSPARENT_ALPHA_CHANNEL; MeshBuffer->getMaterial().MaterialType=video::EMT_TRANSPARENT_ALPHA_CHANNEL;
DEBUG(logdebug("Alpha Channel Transparency on"));
break;
}
} }
} }
MeshBuffer->recalculateBoundingBox(); MeshBuffer->recalculateBoundingBox();
if(header.nAnimations==0 && header.nGlobalSequences == 0)
MeshBuffer->setHardwareMappingHint(EHM_STATIC); MeshBuffer->setHardwareMappingHint(EHM_STATIC);
else
MeshBuffer->setHardwareMappingHint(EHM_STREAM);
// Mesh->addMeshBuffer(MeshBuffer);
// Mesh->recalculateBoundingBox();
//MeshBuffer->drop();
//std::cout << "Mesh now has "<<Mesh->getMeshBufferCount()<<" Buffers\n";
} }
Device->getSceneManager()->getMeshManipulator()->flipSurfaces(AnimatedMesh); //Fix inverted surfaces after the rotation
// False.Genesis: commented out this problematic line.. was causing crashes for me, since 3.x client models
// SEEMS TO CRASH ONLY IN OPENGL-MODE ?! -- investigate!
//Device->getSceneManager()->getMeshManipulator()->recalculateNormals(AnimatedMesh,true);//just to be sure
AnimatedMesh->setInterpolationMode(scene::EIM_LINEAR);
// SkinFile->drop(); // SkinFile->drop();
M2MTriangles.clear(); M2MTriangles.clear();
M2Vertices.clear(); M2Vertices.clear();

View File

@ -1,6 +1,6 @@
#include "irrlicht/irrlicht.h" #include "irrlicht/irrlicht.h"
#include "irrlicht/IMeshLoader.h" #include "irrlicht/IMeshLoader.h"
#include "SSkinnedMesh.h" #include "CM2Mesh.h"
#include <string> #include <string>
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
@ -53,8 +53,8 @@ struct ModelHeader {
u32 nTexFlags; u32 nTexFlags;
u32 ofsTexFlags; u32 ofsTexFlags;
u32 nY; u32 nBoneLookupTable;
u32 ofsY; //0x90 u32 ofsBoneLookupTable; //0x90
u32 nTexLookup; u32 nTexLookup;
u32 ofsTexLookup; u32 ofsTexLookup;
@ -127,7 +127,7 @@ struct ModelViewSubmesh {
u16 nVertex; u16 nVertex;
u16 ofsTris;//Starting Triangle index u16 ofsTris;//Starting Triangle index
u16 nTris; u16 nTris;
u16 unk1, unk2, unk3, unk4; u16 nBone, ofsBone, unk3, unk4;
core::vector3df v; core::vector3df v;
float unkf[4]; float unkf[4];
}; };
@ -220,14 +220,15 @@ private:
bool load(); bool load();
void ReadVertices(); void ReadVertices();
void ReadTextureDefinitions(); void ReadTextureDefinitions();
void ReadAnimationData();
void ReadViewData(io::IReadFile* file); void ReadViewData(io::IReadFile* file);
IrrlichtDevice *Device; IrrlichtDevice *Device;
core::stringc Texdir; core::stringc Texdir;
io::IReadFile *MeshFile, *SkinFile; io::IReadFile *MeshFile, *SkinFile;
CSkinnedMesh *AnimatedMesh; CM2Mesh *AnimatedMesh;
scene::CSkinnedMesh::SJoint *ParentJoint; scene::CM2Mesh::SJoint *ParentJoint;
@ -246,8 +247,11 @@ private:
core::array<std::string> M2MTextureFiles; core::array<std::string> M2MTextureFiles;
core::array<TextureUnit> M2MTextureUnit; core::array<TextureUnit> M2MTextureUnit;
core::array<RenderFlags> M2MRenderFlags; core::array<RenderFlags> M2MRenderFlags;
core::array<u32> M2MGlobalSequences;
core::array<Animation> M2MAnimations; core::array<Animation> M2MAnimations;
core::array<Bone> M2MBones; core::array<Bone> M2MBones;
core::array<u16> M2MBoneLookupTable;
core::array<u16> M2MSkeleBoneLookupTable;
//Used for the Mesh, thus m2_noM_* //Used for the Mesh, thus m2_noM_*
core::array<video::S3DVertex> M2Vertices; core::array<video::S3DVertex> M2Vertices;
core::array<u16> M2Indices; core::array<u16> M2Indices;

View File

@ -21,5 +21,5 @@ SceneLogin.cpp
SceneWorld.cpp SceneWorld.cpp
ShTlTerrainSceneNode.cpp ShTlTerrainSceneNode.cpp
SImage.cpp SImage.cpp
SSkinnedMesh.cpp CM2Mesh.cpp
) )

View File

@ -3,7 +3,6 @@
#include "MemoryDataHolder.h" #include "MemoryDataHolder.h"
#include "MemoryInterface.h" #include "MemoryInterface.h"
#include "CWMOMeshFileLoader.h" #include "CWMOMeshFileLoader.h"
#include "SSkinnedMesh.h"
#include "common.h" #include "common.h"
inline void flipcc(irr::u8 *fcc) inline void flipcc(irr::u8 *fcc)
@ -52,7 +51,7 @@ IAnimatedMesh* CWMOMeshFileLoader::createMesh(io::IReadFile* file)
return 0; return 0;
MeshFile = file; MeshFile = file;
std::string filename=MeshFile->getFileName(); std::string filename=MeshFile->getFileName();
Mesh = new scene::CSkinnedMesh(); Mesh = new scene::CM2Mesh();
if ( load(true) )//We try loading a root file first! if ( load(true) )//We try loading a root file first!
{ {
@ -69,7 +68,7 @@ IAnimatedMesh* CWMOMeshFileLoader::createMesh(io::IReadFile* file)
} }
load(false); load(false);
} }
Mesh->recalculateBoundingBox(); Mesh->updateBoundingBox();
Device->getSceneManager()->getMeshManipulator()->flipSurfaces(Mesh); //Fix inverted surfaces after the rotation Device->getSceneManager()->getMeshManipulator()->flipSurfaces(Mesh); //Fix inverted surfaces after the rotation
//Does this crash on windows? //Does this crash on windows?
Device->getSceneManager()->getMeshManipulator()->recalculateNormals(Mesh,true);//just to be sure Device->getSceneManager()->getMeshManipulator()->recalculateNormals(Mesh,true);//just to be sure

View File

@ -1,6 +1,6 @@
#include "irrlicht/irrlicht.h" #include "irrlicht/irrlicht.h"
#include "irrlicht/IMeshLoader.h" #include "irrlicht/IMeshLoader.h"
#include "SSkinnedMesh.h" #include "CM2Mesh.h"
#include <string> #include <string>
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
@ -83,7 +83,7 @@ private:
core::stringc Texdir; core::stringc Texdir;
io::IReadFile* MeshFile; io::IReadFile* MeshFile;
CSkinnedMesh* Mesh; CM2Mesh* Mesh;
//Stuff from root file //Stuff from root file

View File

@ -193,7 +193,7 @@ void DrawObject::Draw(void)
WorldPosition pos = ((WorldObject*)_obj)->GetPosition(); WorldPosition pos = ((WorldObject*)_obj)->GetPosition();
node->setPosition(WPToIrr(pos)); node->setPosition(WPToIrr(pos));
rotation.Y = O_TO_IRR(pos.o); rotation.Y = O_TO_IRR(pos.o);
rotation.X -=90;
float s = _obj->GetFloatValue(OBJECT_FIELD_SCALE_X); float s = _obj->GetFloatValue(OBJECT_FIELD_SCALE_X);
if(s <= 0) if(s <= 0)
s = 1; s = 1;

File diff suppressed because it is too large Load Diff

View File

@ -90,6 +90,7 @@ namespace scene
private: private:
//! Internal members used by CSkinnedMesh //! Internal members used by CSkinnedMesh
friend class CSkinnedMesh; friend class CSkinnedMesh;
friend class CM2Mesh;
bool *Moved; bool *Moved;
core::vector3df StaticPos; core::vector3df StaticPos;
core::vector3df StaticNormal; core::vector3df StaticNormal;
@ -162,6 +163,7 @@ namespace scene
private: private:
//! Internal members used by CSkinnedMesh //! Internal members used by CSkinnedMesh
friend class CSkinnedMesh; friend class CSkinnedMesh;
friend class CM2Mesh;
SJoint *UseAnimationFrom; SJoint *UseAnimationFrom;
bool LocalAnimatedMatrix_Animated; bool LocalAnimatedMatrix_Animated;

View File

@ -9,8 +9,7 @@ ${PROJECT_SOURCE_DIR}/src/Client/GUI/SImage.cpp
${PROJECT_SOURCE_DIR}/src/Client/GUI/MemoryInterface.cpp ${PROJECT_SOURCE_DIR}/src/Client/GUI/MemoryInterface.cpp
${PROJECT_SOURCE_DIR}/src/Client/GUI/CMDHMemoryReadFile.cpp ${PROJECT_SOURCE_DIR}/src/Client/GUI/CMDHMemoryReadFile.cpp
${PROJECT_SOURCE_DIR}/src/Client/GUI/CBoneSceneNode.cpp ${PROJECT_SOURCE_DIR}/src/Client/GUI/CBoneSceneNode.cpp
${PROJECT_SOURCE_DIR}/src/Client/GUI/SSkinnedMesh.cpp ${PROJECT_SOURCE_DIR}/src/Client/GUI/CM2Mesh.cpp
) )
# Link the executable to the libraries. # Link the executable to the libraries.

View File

@ -19,6 +19,7 @@ tutorial, we use a lot stuff from the gui namespace.
#include "GUI/CM2MeshFileLoader.h" #include "GUI/CM2MeshFileLoader.h"
#include "GUI/CWMOMeshFileLoader.h" #include "GUI/CWMOMeshFileLoader.h"
#include "GUI/CImageLoaderBLP.h" #include "GUI/CImageLoaderBLP.h"
#include "MemoryDataHolder.h"
using namespace irr; using namespace irr;
@ -33,7 +34,7 @@ using namespace gui;
Some global variables used later on Some global variables used later on
*/ */
IrrlichtDevice *Device = 0; IrrlichtDevice *Device = 0;
core::stringc StartUpModelFile = "../../../bin/data/model/draeneifemale.m2"; core::stringc StartUpModelFile = "";
core::stringw MessageText; core::stringw MessageText;
core::stringw Caption; core::stringw Caption;
scene::ISceneNode* Model = 0; scene::ISceneNode* Model = 0;
@ -87,6 +88,11 @@ enum
GUI_ID_QUIT, GUI_ID_QUIT,
GUI_ID_TREE_VIEW, GUI_ID_TREE_VIEW,
GUI_ID_FRAME_START,
GUI_ID_FRAME_END,
GUI_ID_FRAME_SET,
// And some magic numbers // And some magic numbers
MAX_FRAMERATE = 1000, MAX_FRAMERATE = 1000,
DEFAULT_FRAMERATE = 30, DEFAULT_FRAMERATE = 30,
@ -193,19 +199,18 @@ void loadModel(const c8* fn)
else else
{ {
scene::IAnimatedMeshSceneNode* animModel = Device->getSceneManager()->addAnimatedMeshSceneNode(m); scene::IAnimatedMeshSceneNode* animModel = Device->getSceneManager()->addAnimatedMeshSceneNode(m);
animModel->setAnimationSpeed(30); animModel->setAnimationSpeed(1000);
animModel->setFrameLoop(3333,4333);
Model = animModel; Model = animModel;
} }
Model->setMaterialFlag(video::EMF_LIGHTING, true); Model->setMaterialFlag(video::EMF_LIGHTING, true);
// Model->setMaterialFlag(video::EMF_BACK_FACE_CULLING, false); // Model->setMaterialFlag(video::EMF_BACK_FACE_CULLING, false);
Model->setDebugDataVisible(scene::EDS_OFF); Model->setDebugDataVisible(scene::EDS_OFF);
Model->setRotation(core::vector3df(-90,0,0));
// we need to uncheck the menu entries. would be cool to fake a menu event, but // we need to uncheck the menu entries. would be cool to fake a menu event, but
// that's not so simple. so we do it brute force // that's not so simple. so we do it brute force
gui::IGUIContextMenu* menu = (gui::IGUIContextMenu*)Device->getGUIEnvironment()->getRootGUIElement()->getElementFromId(GUI_ID_TOGGLE_DEBUG_INFO, true); for(int id = GUI_ID_DEBUG_BOUNDING_BOX; id <= GUI_ID_DEBUG_WIRE_OVERLAY; ++id)
if (menu) ((IGUICheckBox*)Device->getGUIEnvironment()->getRootGUIElement()->getElementFromId(id,true))->setChecked(false);
for(int item = 1; item < 6; ++item)
menu->setItemChecked(item, false);
IGUIElement* toolboxWnd = Device->getGUIEnvironment()->getRootGUIElement()->getElementFromId(GUI_ID_DIALOG_ROOT_WINDOW, true); IGUIElement* toolboxWnd = Device->getGUIEnvironment()->getRootGUIElement()->getElementFromId(GUI_ID_DIALOG_ROOT_WINDOW, true);
if ( toolboxWnd ) if ( toolboxWnd )
{ {
@ -213,6 +218,11 @@ void loadModel(const c8* fn)
toolboxWnd->getElementFromId(GUI_ID_Y_SCALE, true)->setText(L"1.0"); toolboxWnd->getElementFromId(GUI_ID_Y_SCALE, true)->setText(L"1.0");
toolboxWnd->getElementFromId(GUI_ID_Z_SCALE, true)->setText(L"1.0"); toolboxWnd->getElementFromId(GUI_ID_Z_SCALE, true)->setText(L"1.0");
} }
FILE* f = fopen("./viewer_last.txt","w");
fwrite(filename.c_str(),1,filename.size(),f);
fclose(f);
} }
@ -292,6 +302,19 @@ void createToolBox()
env->addCheckBox(true, core::rect<s32>(22,142,130,156),t3,GUI_ID_LIGHT_VISIBLE,L"Visible"); env->addCheckBox(true, core::rect<s32>(22,142,130,156),t3,GUI_ID_LIGHT_VISIBLE,L"Visible");
env->addButton(core::rect<s32>(10,164,85,185), t3, GUI_ID_LIGHT_SET, L"Set"); env->addButton(core::rect<s32>(10,164,85,185), t3, GUI_ID_LIGHT_SET, L"Set");
IGUITab* t4 = tab->addTab(L"Debug");
env->addCheckBox(false, core::rect<s32>(22,48,130,68),t4,GUI_ID_DEBUG_BOUNDING_BOX,L"BBox");
env->addCheckBox(false, core::rect<s32>(22,78,130,98),t4,GUI_ID_DEBUG_BUFFERS_BOUNDING_BOXES,L"Buffers BBoxes");
env->addCheckBox(false, core::rect<s32>(22,108,130,128),t4,GUI_ID_DEBUG_HALF_TRANSPARENT,L"Half Transparent");
env->addCheckBox(false, core::rect<s32>(22,138,130,158),t4,GUI_ID_DEBUG_NORMALS,L"Normals");
env->addCheckBox(false, core::rect<s32>(22,168,130,188),t4,GUI_ID_DEBUG_SKELETON,L"Skeleton");
env->addCheckBox(false, core::rect<s32>(22,198,130,218),t4,GUI_ID_DEBUG_WIRE_OVERLAY,L"Wire Overlay");
env->addStaticText(L"Start:", core::rect<s32>(22,228,40,248), false, false, t4);
env->addEditBox(L"0", core::rect<s32>(40,248,130,268), true, t4, GUI_ID_FRAME_START);
env->addStaticText(L"End:", core::rect<s32>(22,268,40,288), false, false, t4);
env->addEditBox(L"0", core::rect<s32>(40,288,130,308), true, t4, GUI_ID_FRAME_END);
env->addButton(core::rect<s32>(10,318,85,338), t4, GUI_ID_FRAME_SET, L"Set");
// bring irrlicht engine logo to front, because it // bring irrlicht engine logo to front, because it
// now may be below the newly created toolbox // now may be below the newly created toolbox
root->bringToFront(root->getElementFromId(666, true)); root->bringToFront(root->getElementFromId(666, true));
@ -344,6 +367,38 @@ public:
scene::ISceneManager* smgr = Device->getSceneManager(); scene::ISceneManager* smgr = Device->getSceneManager();
switch(event.GUIEvent.EventType) switch(event.GUIEvent.EventType)
{ {
case EGET_CHECKBOX_CHANGED:
{
s32 pos = ((IGUICheckBox*)event.GUIEvent.Caller)->getID();
switch (pos)
{
case GUI_ID_DEBUG_BOUNDING_BOX: // View -> Debug Information
if (Model)
Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_BBOX));
break;
case GUI_ID_DEBUG_NORMALS: // View -> Debug Information
if (Model)
Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_NORMALS));
break;
case GUI_ID_DEBUG_SKELETON: // View -> Debug Information
if (Model)
Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_SKELETON));
break;
case GUI_ID_DEBUG_WIRE_OVERLAY: // View -> Debug Information
if (Model)
Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_MESH_WIRE_OVERLAY));
break;
case GUI_ID_DEBUG_HALF_TRANSPARENT: // View -> Debug Information
if (Model)
Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_HALF_TRANSPARENCY));
break;
case GUI_ID_DEBUG_BUFFERS_BOUNDING_BOXES: // View -> Debug Information
if (Model)
Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_BBOX_BUFFERS));
break;
}
break;
}
case EGET_MENU_ITEM_SELECTED: case EGET_MENU_ITEM_SELECTED:
{ {
// a menu item was clicked // a menu item was clicked
@ -370,56 +425,6 @@ public:
menu->setItemChecked(menu->getSelectedItem(), !menu->isItemChecked(menu->getSelectedItem())); menu->setItemChecked(menu->getSelectedItem(), !menu->isItemChecked(menu->getSelectedItem()));
SkyBox->setVisible(!SkyBox->isVisible()); SkyBox->setVisible(!SkyBox->isVisible());
break; break;
case GUI_ID_DEBUG_OFF: // View -> Debug Information
menu->setItemChecked(menu->getSelectedItem()+1, false);
menu->setItemChecked(menu->getSelectedItem()+2, false);
menu->setItemChecked(menu->getSelectedItem()+3, false);
menu->setItemChecked(menu->getSelectedItem()+4, false);
menu->setItemChecked(menu->getSelectedItem()+5, false);
menu->setItemChecked(menu->getSelectedItem()+6, false);
if (Model)
Model->setDebugDataVisible(scene::EDS_OFF);
break;
case GUI_ID_DEBUG_BOUNDING_BOX: // View -> Debug Information
menu->setItemChecked(menu->getSelectedItem(), !menu->isItemChecked(menu->getSelectedItem()));
if (Model)
Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_BBOX));
break;
case GUI_ID_DEBUG_NORMALS: // View -> Debug Information
menu->setItemChecked(menu->getSelectedItem(), !menu->isItemChecked(menu->getSelectedItem()));
if (Model)
Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_NORMALS));
break;
case GUI_ID_DEBUG_SKELETON: // View -> Debug Information
menu->setItemChecked(menu->getSelectedItem(), !menu->isItemChecked(menu->getSelectedItem()));
if (Model)
Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_SKELETON));
break;
case GUI_ID_DEBUG_WIRE_OVERLAY: // View -> Debug Information
menu->setItemChecked(menu->getSelectedItem(), !menu->isItemChecked(menu->getSelectedItem()));
if (Model)
Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_MESH_WIRE_OVERLAY));
break;
case GUI_ID_DEBUG_HALF_TRANSPARENT: // View -> Debug Information
menu->setItemChecked(menu->getSelectedItem(), !menu->isItemChecked(menu->getSelectedItem()));
if (Model)
Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_HALF_TRANSPARENCY));
break;
case GUI_ID_DEBUG_BUFFERS_BOUNDING_BOXES: // View -> Debug Information
menu->setItemChecked(menu->getSelectedItem(), !menu->isItemChecked(menu->getSelectedItem()));
if (Model)
Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_BBOX_BUFFERS));
break;
case GUI_ID_DEBUG_ALL: // View -> Debug Information
menu->setItemChecked(menu->getSelectedItem()-1, true);
menu->setItemChecked(menu->getSelectedItem()-2, true);
menu->setItemChecked(menu->getSelectedItem()-3, true);
menu->setItemChecked(menu->getSelectedItem()-4, true);
menu->setItemChecked(menu->getSelectedItem()-5, true);
menu->setItemChecked(menu->getSelectedItem()-6, true);
if (Model)
Model->setDebugDataVisible(scene::EDS_FULL);
break;
case GUI_ID_MODEL_MATERIAL_SOLID: // View -> Material -> Solid case GUI_ID_MODEL_MATERIAL_SOLID: // View -> Material -> Solid
if (Model) if (Model)
Model->setMaterialType(video::EMT_SOLID); Model->setMaterialType(video::EMT_SOLID);
@ -450,6 +455,7 @@ public:
IGUIFileOpenDialog* dialog = IGUIFileOpenDialog* dialog =
(IGUIFileOpenDialog*)event.GUIEvent.Caller; (IGUIFileOpenDialog*)event.GUIEvent.Caller;
loadModel(core::stringc(dialog->getFileName()).c_str()); loadModel(core::stringc(dialog->getFileName()).c_str());
StartUpModelFile=core::stringc(dialog->getFileName()).c_str();
} }
break; break;
@ -577,6 +583,7 @@ public:
env->addFileOpenDialog(L"Please select your game archive/directory"); env->addFileOpenDialog(L"Please select your game archive/directory");
break; break;
case GUI_ID_LIGHT_SET: case GUI_ID_LIGHT_SET:
{
scene::ISceneNode* light; scene::ISceneNode* light;
s32 pos=((IGUIComboBox*)env->getRootGUIElement()->getElementFromId(GUI_ID_LIGHT_BOX,true))->getSelected(); s32 pos=((IGUIComboBox*)env->getRootGUIElement()->getElementFromId(GUI_ID_LIGHT_BOX,true))->getSelected();
@ -600,9 +607,15 @@ public:
atof(core::stringc(env->getRootGUIElement()->getElementFromId(GUI_ID_LIGHT_Z_SCALE,true)->getText()).c_str())); atof(core::stringc(env->getRootGUIElement()->getElementFromId(GUI_ID_LIGHT_Z_SCALE,true)->getText()).c_str()));
light->setPosition(lpos); light->setPosition(lpos);
light->setVisible(((IGUICheckBox*)(env->getRootGUIElement()->getElementFromId(GUI_ID_LIGHT_VISIBLE,true)))->isChecked()); light->setVisible(((IGUICheckBox*)(env->getRootGUIElement()->getElementFromId(GUI_ID_LIGHT_VISIBLE,true)))->isChecked());
}
break;
case GUI_ID_FRAME_SET:
{
if(Model)
((scene::IAnimatedMeshSceneNode*)Model)->setFrameLoop(atoi(core::stringc(env->getRootGUIElement()->getElementFromId(GUI_ID_FRAME_START,true)->getText()).c_str()),
atoi(core::stringc(env->getRootGUIElement()->getElementFromId(GUI_ID_FRAME_END,true)->getText()).c_str()));
}
break; break;
} }
break; break;
@ -628,8 +641,23 @@ resizeable, which is quite useful for a mesh viewer.
*/ */
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
// ask user for driver //config hacks
log_setloglevel(3);
log_prepare("viewerlog.txt","w");
MemoryDataHolder::SetUseMPQ("enUS");
FILE* f;
f = fopen("./viewer_last.txt","r");
if(f!=NULL)
{
log("Loading last used mesh");
c8 buffer[255];
fseek(f,0,SEEK_SET);
fread(&buffer,1,255,f);
StartUpModelFile = buffer;
fclose(f);
}
// ask user for driver
video::E_DRIVER_TYPE driverType = video::EDT_DIRECT3D8; video::E_DRIVER_TYPE driverType = video::EDT_DIRECT3D8;
printf("Please select the driver you want for this example:\n"\ printf("Please select the driver you want for this example:\n"\
@ -719,16 +747,6 @@ int main(int argc, char* argv[])
submenu->addItem(L"toggle model debug information", GUI_ID_TOGGLE_DEBUG_INFO, true, true); submenu->addItem(L"toggle model debug information", GUI_ID_TOGGLE_DEBUG_INFO, true, true);
submenu->addItem(L"model material", -1, true, true ); submenu->addItem(L"model material", -1, true, true );
submenu = submenu->getSubMenu(1);
submenu->addItem(L"Off", GUI_ID_DEBUG_OFF);
submenu->addItem(L"Bounding Box", GUI_ID_DEBUG_BOUNDING_BOX);
submenu->addItem(L"Normals", GUI_ID_DEBUG_NORMALS);
submenu->addItem(L"Skeleton", GUI_ID_DEBUG_SKELETON);
submenu->addItem(L"Wire overlay", GUI_ID_DEBUG_WIRE_OVERLAY);
submenu->addItem(L"Half-Transparent", GUI_ID_DEBUG_HALF_TRANSPARENT);
submenu->addItem(L"Buffers bounding boxes", GUI_ID_DEBUG_BUFFERS_BOUNDING_BOXES);
submenu->addItem(L"All", GUI_ID_DEBUG_ALL);
submenu = menu->getSubMenu(1)->getSubMenu(2); submenu = menu->getSubMenu(1)->getSubMenu(2);
submenu->addItem(L"Solid", GUI_ID_MODEL_MATERIAL_SOLID); submenu->addItem(L"Solid", GUI_ID_MODEL_MATERIAL_SOLID);
submenu->addItem(L"Transparent", GUI_ID_MODEL_MATERIAL_TRANSPARENT); submenu->addItem(L"Transparent", GUI_ID_MODEL_MATERIAL_TRANSPARENT);
@ -813,6 +831,7 @@ int main(int argc, char* argv[])
// show about message box and load default model // show about message box and load default model
// if (argc==1) // if (argc==1)
// showAboutText(); // showAboutText();
if(StartUpModelFile.c_str()!="")
loadModel(StartUpModelFile.c_str()); loadModel(StartUpModelFile.c_str());
// add skybox // add skybox
@ -832,7 +851,7 @@ int main(int argc, char* argv[])
// where the mesh scene node is placed. // where the mesh scene node is placed.
Camera[0]->setTarget(core::vector3df(0,0,0)); Camera[0]->setTarget(core::vector3df(0,0,0));
Camera[1] = smgr->addCameraSceneNodeFPS(); Camera[1] = smgr->addCameraSceneNodeFPS(0,50.0f,0.1f);
Camera[1]->setFarValue(20000.f); Camera[1]->setFarValue(20000.f);
Camera[1]->setPosition(core::vector3df(0,0,-70)); Camera[1]->setPosition(core::vector3df(0,0,-70));
Camera[1]->setTarget(core::vector3df(0,0,0)); Camera[1]->setTarget(core::vector3df(0,0,0));
@ -856,14 +875,17 @@ int main(int argc, char* argv[])
{ {
driver->beginScene(true, true, video::SColor(150,50,50,50)); driver->beginScene(true, true, video::SColor(150,50,50,50));
smgr->drawAll(); smgr->drawAll();
video::SMaterial m2;
m2.Lighting = false; video::SMaterial m;
driver->setMaterial(m2); m.Lighting = false;
driver->draw3DLine(core::vector3df(0,0,0),core::vector3df(100,0,0),video::SColor(255,255,0,0)); driver->setMaterial(m);
driver->draw3DLine(core::vector3df(0,0,0),core::vector3df(0,100,0),video::SColor(255,0,255,0)); driver->setTransform(video::ETS_WORLD, core::matrix4());
driver->draw3DLine(core::vector3df(0,0,0),core::vector3df(0,0,100),video::SColor(255,0,0,255)); driver->draw3DLine(core::vector3df(-1,-1,-1),core::vector3df(10,-1,-1),video::SColor(255,255,0,0));
driver->draw3DLine(core::vector3df(-1,-1,-1),core::vector3df(-1,10,-1),video::SColor(255,0,255,0));
driver->draw3DLine(core::vector3df(-1,-1,-1),core::vector3df(-1,-1,10),video::SColor(255,0,0,255));
driver->draw3DLine(core::vector3df(-1,-1,-1),core::vector3df(0,0,0),video::SColor(255,255,0,255));
env->drawAll(); env->drawAll();
driver->endScene(); driver->endScene();
@ -872,6 +894,9 @@ int main(int argc, char* argv[])
str.append(core::stringw(driver->getFPS())); str.append(core::stringw(driver->getFPS()));
str += L" Tris: "; str += L" Tris: ";
str.append(core::stringw(driver->getPrimitiveCountDrawn())); str.append(core::stringw(driver->getPrimitiveCountDrawn()));
str += L" Frame: ";
if(Model)
str.append(core::stringw(((scene::IAnimatedMeshSceneNode*)Model)->getFrameNr()));
fpstext->setText(str.c_str()); fpstext->setText(str.c_str());
scene::ICameraSceneNode* cam = Device->getSceneManager()->getActiveCamera(); scene::ICameraSceneNode* cam = Device->getSceneManager()->getActiveCamera();
@ -894,6 +919,7 @@ int main(int argc, char* argv[])
Device->yield(); Device->yield();
} }
Device->drop(); Device->drop();
return 0; return 0;
} }