diff --git a/src/Client/GUI/CM2Mesh.cpp b/src/Client/GUI/CM2Mesh.cpp new file mode 100755 index 0000000..29a7ac3 --- /dev/null +++ b/src/Client/GUI/CM2Mesh.cpp @@ -0,0 +1,1384 @@ +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h +#include +#include "irrlicht/irrlicht.h" +#include "CM2Mesh.h" +#include "CBoneSceneNode.h" +namespace irr +{ +namespace scene +{ + + +//! constructor +CM2Mesh::CM2Mesh() +: SkinningBuffers(0), HasAnimation(0), PreparedForSkinning(0), + AnimationFrames(0.f), LastAnimatedFrame(0.f), + AnimateNormals(true), HardwareSkinning(0), InterpolationMode(EIM_LINEAR) +{ + #ifdef _DEBUG + setDebugName("CM2Mesh"); + #endif + + SkinningBuffers=&LocalBuffers; +} + + +//! destructor +CM2Mesh::~CM2Mesh() +{ + for (u32 i=0; idrop(); + } +} + + +//! returns the amount of frames in milliseconds. +//! If the amount is 1, it is a static (=non animated) mesh. +u32 CM2Mesh::getFrameCount() const +{ + return core::floor32(AnimationFrames); +} + + +//! returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail. Note, that some Meshes will ignore the detail level. +IMesh* CM2Mesh::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop) +{ + if (frame==-1) + return this; + animateMesh((f32)frame, 1.0f); + + skinMesh(); + return this; +} + + +//-------------------------------------------------------------------------- +// Keyframe Animation +//-------------------------------------------------------------------------- + + +//! Animates this mesh's joints based on frame input +//! blend: {0-old position, 1-New position} +void CM2Mesh::animateMesh(f32 frame, f32 blend) +{ + if ( !HasAnimation || LastAnimatedFrame==frame) + return; + + LastAnimatedFrame=frame; + SkinnedLastFrame=false; + + if (blend<=0.f) + return; //No need to animate + + for (u32 i=0; iAnimatedposition; + const core::vector3df oldScale = joint->Animatedscale; + const core::quaternion oldRotation = joint->Animatedrotation; + + core::vector3df position = oldPosition; + core::vector3df scale = oldScale; + core::quaternion rotation = oldRotation; + getFrameData(frame, joint, + position, joint->positionHint, + scale, joint->scaleHint, + rotation, joint->rotationHint); + + if (blend==1.0f) + { + //No blending needed + joint->Animatedposition = position; + joint->Animatedscale = scale; + joint->Animatedrotation = rotation; + } + else + { + //Blend animation + joint->Animatedposition = core::lerp(oldPosition, position, blend); + joint->Animatedscale = core::lerp(oldScale, scale, blend); + joint->Animatedrotation.slerp(oldRotation, rotation, blend); + } + + } + + //---------------- + buildAllAnimatedMatrices(); + //----------------- +} + + +void CM2Mesh::buildAllAnimatedMatrices(SJoint *joint, SJoint *parentJoint) +{ + + if (!joint) + { + for (u32 i=0; iUseAnimationFrom && + (joint->UseAnimationFrom->PositionKeys.size() || + joint->UseAnimationFrom->ScaleKeys.size() || + joint->UseAnimationFrom->RotationKeys.size() )) + { + joint->GlobalAnimatedMatrix= core::matrix4(); + joint->GlobalAnimatedMatrix.setTranslation(joint->LocalMatrix.getTranslation()); + + core::matrix4 tm; + tm.setTranslation(joint->Animatedposition); + joint->GlobalAnimatedMatrix*=tm; + + joint->GlobalAnimatedMatrix*=joint->Animatedrotation.getMatrix(); + + core::matrix4 ts; + ts.setScale(joint->Animatedscale); + joint->GlobalAnimatedMatrix*=ts; + } + else + { + joint->GlobalAnimatedMatrix=core::matrix4(); + } + if(parentJoint) + joint->GlobalAnimatedMatrix=parentJoint->GlobalAnimatedMatrix*joint->GlobalAnimatedMatrix; + for (u32 j=0; jChildren.size(); ++j) + { + buildAllAnimatedMatrices(joint->Children[j], joint); + } + } +} + + +void CM2Mesh::getFrameData(f32 frame, SJoint *joint, + core::vector3df &position, s32 &positionHint, + core::vector3df &scale, s32 &scaleHint, + core::quaternion &rotation, s32 &rotationHint) +{ + s32 foundPositionIndex = -1; + s32 foundScaleIndex = -1; + s32 foundRotationIndex = -1; + + if (joint->UseAnimationFrom) + { + const core::array &PositionKeys=joint->UseAnimationFrom->PositionKeys; + const core::array &ScaleKeys=joint->UseAnimationFrom->ScaleKeys; + const core::array &RotationKeys=joint->UseAnimationFrom->RotationKeys; + + if (PositionKeys.size()) + { + foundPositionIndex = -1; + + //Test the Hints... + if (positionHint>=0 && (u32)positionHint < PositionKeys.size()) + { + //check this hint + if (positionHint>0 && PositionKeys[positionHint].frame>=frame && PositionKeys[positionHint-1].frame=frame && + PositionKeys[positionHint+0].frame= frame) //Keys should to be sorted by frame + { + foundPositionIndex=i; + positionHint=i; + break; + } + } + } + + //Do interpolation... + if (foundPositionIndex!=-1) + { + if (InterpolationMode==EIM_CONSTANT || foundPositionIndex==0) + { + position = PositionKeys[foundPositionIndex].position; + } + else if (InterpolationMode==EIM_LINEAR) + { + const SPositionKey& KeyA = PositionKeys[foundPositionIndex]; + const SPositionKey& KeyB = PositionKeys[foundPositionIndex-1]; + + const f32 fd1 = frame - KeyA.frame; + const f32 fd2 = KeyB.frame - frame; + position = ((KeyB.position-KeyA.position)/(fd1+fd2))*fd1 + KeyA.position; + } + } + } + + //------------------------------------------------------------ + + if (ScaleKeys.size()) + { + foundScaleIndex = -1; + + //Test the Hints... + if (scaleHint>=0 && (u32)scaleHint < ScaleKeys.size()) + { + //check this hint + if (scaleHint>0 && ScaleKeys[scaleHint].frame>=frame && ScaleKeys[scaleHint-1].frame=frame && + ScaleKeys[scaleHint+0].frame= frame) //Keys should to be sorted by frame + { + foundScaleIndex=i; + scaleHint=i; + break; + } + } + } + + //Do interpolation... + if (foundScaleIndex!=-1) + { + if (InterpolationMode==EIM_CONSTANT || foundScaleIndex==0) + { + scale = ScaleKeys[foundScaleIndex].scale; + } + else if (InterpolationMode==EIM_LINEAR) + { + const SScaleKey& KeyA = ScaleKeys[foundScaleIndex]; + const SScaleKey& KeyB = ScaleKeys[foundScaleIndex-1]; + + const f32 fd1 = frame - KeyA.frame; + const f32 fd2 = KeyB.frame - frame; + scale = ((KeyB.scale-KeyA.scale)/(fd1+fd2))*fd1 + KeyA.scale; + } + } + } + + //------------------------------------------------------------- + + if (RotationKeys.size()) + { + foundRotationIndex = -1; + + //Test the Hints... + if (rotationHint>=0 && (u32)rotationHint < RotationKeys.size()) + { + //check this hint + if (rotationHint>0 && RotationKeys[rotationHint].frame>=frame && RotationKeys[rotationHint-1].frame=frame && + RotationKeys[rotationHint+0].frame= frame) //Keys should be sorted by frame + { + foundRotationIndex=i; + rotationHint=i; + break; + } + } + } + + //Do interpolation... + if (foundRotationIndex!=-1) + { + if (InterpolationMode==EIM_CONSTANT || foundRotationIndex==0) + { + rotation = RotationKeys[foundRotationIndex].rotation; + } + else if (InterpolationMode==EIM_LINEAR) + { + const SRotationKey& KeyA = RotationKeys[foundRotationIndex]; + const SRotationKey& KeyB = RotationKeys[foundRotationIndex-1]; + + const f32 fd1 = frame - KeyA.frame; + const f32 fd2 = KeyB.frame - frame; + const f32 t = fd1/(fd1+fd2); + + /* + f32 t = 0; + if (KeyA.frame!=KeyB.frame) + t = (frame-KeyA.frame) / (KeyB.frame - KeyA.frame); + */ + + rotation.slerp(KeyA.rotation, KeyB.rotation, t); + } + } + } + } +} + +//-------------------------------------------------------------------------- +// Software Skinning +//-------------------------------------------------------------------------- + +//! Preforms a software skin on this mesh based of joint positions +void CM2Mesh::skinMesh() +{ + if ( !HasAnimation || SkinnedLastFrame ) + return; + + SkinnedLastFrame=true; + if (!HardwareSkinning) + { + //Software skin.... + u32 i; + + //rigid animation + for (i=0; iAttachedMeshes.size(); ++j) + { + SSkinMeshBuffer* Buffer=(*SkinningBuffers)[ AllJoints[i]->AttachedMeshes[j] ]; + Buffer->Transformation=AllJoints[i]->GlobalAnimatedMatrix; + } + } + + //clear skinning helper array + for (i=0; isize(); ++i) + (*SkinningBuffers)[i]->setDirty(); + + } + updateBoundingBox(); +} + + +void CM2Mesh::SkinJoint(SJoint *joint, SJoint *parentJoint) +{ + if (joint->Weights.size()) + { + //Find this joints pull on vertices... + core::matrix4 jointVertexPull(core::matrix4::EM4CONST_NOTHING); + jointVertexPull.setbyproduct(joint->GlobalAnimatedMatrix, joint->GlobalInversedMatrix); + + core::vector3df thisVertexMove, thisNormalMove; + + core::array &buffersUsed=*SkinningBuffers; + + //Skin Vertices Positions and Normals... + for (u32 i=0; iWeights.size(); ++i) + { + SWeight& weight = joint->Weights[i]; + + // Pull this vertex... + jointVertexPull.transformVect(thisVertexMove, weight.StaticPos); + + if (AnimateNormals) + jointVertexPull.rotateVect(thisNormalMove, weight.StaticNormal); + + if (! (*(weight.Moved)) ) + { + *(weight.Moved) = true; + + buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Pos = thisVertexMove * weight.strength; + + if (AnimateNormals) + buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Normal = thisNormalMove * weight.strength; + } + else + { + buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Pos += thisVertexMove * weight.strength; + + if (AnimateNormals) + buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Normal += thisNormalMove * weight.strength; + } + buffersUsed[weight.buffer_id]->boundingBoxNeedsRecalculated(); + } + } + + //Skin all children + for (u32 j=0; jChildren.size(); ++j) + SkinJoint(joint->Children[j], joint); +} + + +E_ANIMATED_MESH_TYPE CM2Mesh::getMeshType() const +{ + return EAMT_SKINNED; +} + + +//! Gets joint count. +u32 CM2Mesh::getJointCount() const +{ + return AllJoints.size(); +} + + +//! Gets the name of a joint. +const c8* CM2Mesh::getJointName(u32 number) const +{ + if (number >= AllJoints.size()) + return 0; + return AllJoints[number]->Name.c_str(); +} + + +//! Gets a joint number from its name +s32 CM2Mesh::getJointNumber(const c8* name) const +{ + for (u32 i=0; iName == name) + return i; + } + + return -1; +} + + +//! returns amount of mesh buffers. +u32 CM2Mesh::getMeshBufferCount() const +{ + return LocalBuffers.size(); +} + + +//! returns pointer to a mesh buffer +IMeshBuffer* CM2Mesh::getMeshBuffer(u32 nr) const +{ + if (nr < LocalBuffers.size()) + return LocalBuffers[nr]; + else + return 0; +} + + +//! Returns pointer to a mesh buffer which fits a material +IMeshBuffer* CM2Mesh::getMeshBuffer(const video::SMaterial &material) const +{ + for (u32 i=0; igetMaterial() == material) + return LocalBuffers[i]; + } + return 0; +} + + +//! returns an axis aligned bounding box +const core::aabbox3d& CM2Mesh::getBoundingBox() const +{ + return BoundingBox; +} + + +//! set user axis aligned bounding box +void CM2Mesh::setBoundingBox( const core::aabbox3df& box) +{ + BoundingBox = box; +} + + +//! sets a flag of all contained materials to a new value +void CM2Mesh::setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) +{ + for (u32 i=0; iMaterial.setFlag(flag,newvalue); +} + +//! set the hardware mapping hint, for driver +void CM2Mesh::setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint, + E_BUFFER_TYPE buffer) +{ + for (u32 i=0; isetHardwareMappingHint(newMappingHint, buffer); +} + + +//! flags the meshbuffer as changed, reloads hardware buffers +void CM2Mesh::setDirty(E_BUFFER_TYPE buffer) +{ + for (u32 i=0; isetDirty(buffer); +} + + +//! uses animation from another mesh +bool CM2Mesh::useAnimationFrom(const ISkinnedMesh *mesh) +{ + bool unmatched=false; + + for(u32 i=0;iUseAnimationFrom=0; + + if (joint->Name=="") + unmatched=true; + else + { + for(u32 j=0;jgetAllJoints().size();++j) + { + SJoint *otherJoint=mesh->getAllJoints()[j]; + if (joint->Name==otherJoint->Name) + { + joint->UseAnimationFrom=otherJoint; + } + } + if (!joint->UseAnimationFrom) + unmatched=true; + } + } + + checkForAnimation(); + + return !unmatched; +} + + +//!Update Normals when Animating +//!False= Don't animate them, faster +//!True= Update normals (default) +void CM2Mesh::updateNormalsWhenAnimating(bool on) +{ + AnimateNormals = on; +} + + +//!Sets Interpolation Mode +void CM2Mesh::setInterpolationMode(E_INTERPOLATION_MODE mode) +{ + InterpolationMode = mode; +} + + +core::array &CM2Mesh::getMeshBuffers() +{ + return LocalBuffers; +} + + +core::array &CM2Mesh::getAllJoints() +{ + return AllJoints; +} + + +const core::array &CM2Mesh::getAllJoints() const +{ + return AllJoints; +} + + +//! (This feature is not implementated in irrlicht yet) +bool CM2Mesh::setHardwareSkinning(bool on) +{ + if (HardwareSkinning!=on) + { + + if (on) + { + + //set mesh to static pose... + for (u32 i=0; iWeights.size(); ++j) + { + const u16 buffer_id=joint->Weights[j].buffer_id; + const u32 vertex_id=joint->Weights[j].vertex_id; + LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos = joint->Weights[j].StaticPos; + LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal = joint->Weights[j].StaticNormal; + } + } + + + } + + HardwareSkinning=on; + } + return HardwareSkinning; +} + + +void CM2Mesh::CalculateGlobalMatrices(SJoint *joint,SJoint *parentJoint) +{ + if (!joint && parentJoint) // bit of protection from endless loops + return; + + //Go through the root bones + if (!joint) + { + for (u32 i=0; iLocalMatrix = joint->GlobalMatrix; + else + joint->LocalMatrix = joint->GlobalMatrix * parentJoint->GlobalInversedMatrix; + joint->Animatedposition=core::vector3df(0,0,0); + joint->LocalAnimatedMatrix=joint->LocalMatrix; + joint->GlobalAnimatedMatrix=joint->GlobalMatrix; + + if (joint->GlobalInversedMatrix.isIdentity())//might be pre calculated + { + joint->GlobalInversedMatrix = joint->GlobalMatrix; + joint->GlobalInversedMatrix.makeInverse(); // slow + } + + for (u32 j=0; jChildren.size(); ++j) + CalculateGlobalMatrices(joint->Children[j],joint); +} + + +void CM2Mesh::checkForAnimation() +{ + u32 i,j; + //Check for animation... + HasAnimation = false; + for(i=0;iUseAnimationFrom) + { + if (AllJoints[i]->UseAnimationFrom->PositionKeys.size() || + AllJoints[i]->UseAnimationFrom->ScaleKeys.size() || + AllJoints[i]->UseAnimationFrom->RotationKeys.size() ) + { + HasAnimation = true; + } + } + } + + //meshes with weights, are still counted as animated for ragdolls, etc + if (!HasAnimation) + { + for(i=0;iWeights.size()) + HasAnimation = true; + } + } + + if (HasAnimation) + { + //--- Find the length of the animation --- + AnimationFrames=0; + for(i=0;iUseAnimationFrom) + { + if (AllJoints[i]->UseAnimationFrom->PositionKeys.size()) + if (AllJoints[i]->UseAnimationFrom->PositionKeys.getLast().frame > AnimationFrames) + AnimationFrames=AllJoints[i]->UseAnimationFrom->PositionKeys.getLast().frame; + + if (AllJoints[i]->UseAnimationFrom->ScaleKeys.size()) + if (AllJoints[i]->UseAnimationFrom->ScaleKeys.getLast().frame > AnimationFrames) + AnimationFrames=AllJoints[i]->UseAnimationFrom->ScaleKeys.getLast().frame; + + if (AllJoints[i]->UseAnimationFrom->RotationKeys.size()) + if (AllJoints[i]->UseAnimationFrom->RotationKeys.getLast().frame > AnimationFrames) + AnimationFrames=AllJoints[i]->UseAnimationFrom->RotationKeys.getLast().frame; + } + } + } + + if (HasAnimation && !PreparedForSkinning) + { + PreparedForSkinning=true; + + //check for bugs: + for(i=0; i < AllJoints.size(); ++i) + { + SJoint *joint = AllJoints[i]; + for (j=0; jWeights.size(); ++j) + { + const u16 buffer_id=joint->Weights[j].buffer_id; + const u32 vertex_id=joint->Weights[j].vertex_id; + //check for invalid ids + if (buffer_id>=LocalBuffers.size()) + { + //printf("Skinned Mesh: Weight buffer id too large"); + joint->Weights[j].buffer_id = joint->Weights[j].vertex_id =0; + } + else if (vertex_id>=LocalBuffers[buffer_id]->getVertexCount()) + { + //printf("Skinned Mesh: Weight vertex id too large"); + joint->Weights[j].buffer_id = joint->Weights[j].vertex_id =0; + } + } + } + + //An array used in skinning + + for (i=0; iWeights.size(); ++j) + { + const u16 buffer_id=joint->Weights[j].buffer_id; + const u32 vertex_id=joint->Weights[j].vertex_id; + + joint->Weights[j].Moved = &Vertices_Moved[buffer_id] [vertex_id]; + joint->Weights[j].StaticPos = LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos; + joint->Weights[j].StaticNormal = LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal; + + } + } + + // normalize weights + normalizeWeights(); + } +} + + +//! called by loader after populating with mesh and bone data +void CM2Mesh::finalize() +{ + u32 i; + LastAnimatedFrame=-1; + SkinnedLastFrame=false; + + //calculate bounding box + + for (i=0; irecalculateBoundingBox(); + } + + if (AllJoints.size() || RootJoints.size()) + { + // populate AllJoints or RootJoints, depending on which is empty + if (!RootJoints.size()) + { + + for(u32 CheckingIdx=0; CheckingIdx < AllJoints.size(); ++CheckingIdx) + { + + bool foundParent=false; + for(i=0; i < AllJoints.size(); ++i) + { + for(u32 n=0; n < AllJoints[i]->Children.size(); ++n) + { + if (AllJoints[i]->Children[n] == AllJoints[CheckingIdx]) + foundParent=true; + } + } + + if (!foundParent) + RootJoints.push_back(AllJoints[CheckingIdx]); + } + } + else + { + AllJoints=RootJoints; + } + } + + for(i=0; i < AllJoints.size(); ++i) + { + AllJoints[i]->UseAnimationFrom=AllJoints[i]; + } + + //Set array sizes... + + for (i=0; i() ); + Vertices_Moved[i].set_used(LocalBuffers[i]->getVertexCount()); + } + + //Todo: optimise keys here... + + checkForAnimation(); + +if (HasAnimation) + { + //--- optimize and check keyframes --- + for(i=0;i &PositionKeys =AllJoints[i]->PositionKeys; + core::array &ScaleKeys = AllJoints[i]->ScaleKeys; + core::array &RotationKeys = AllJoints[i]->RotationKeys; + if (PositionKeys.size()>2) + { + for(u32 j=0;j1) + { + for(u32 j=0;j= PositionKeys[j+1].frame) //bad frame, unneed and may cause problems + { + PositionKeys.erase(j+1); + --j; + } + } + } + + if (ScaleKeys.size()>2) + { + for(u32 j=0;j1) + { + for(u32 j=0;j= ScaleKeys[j+1].frame) //bad frame, unneed and may cause problems + { + ScaleKeys.erase(j+1); + --j; + } + } + } + + if (RotationKeys.size()>2) + { + for(u32 j=0;j1) + { + for(u32 j=0;j= RotationKeys[j+1].frame) //bad frame, unneed and may cause problems + { + RotationKeys.erase(j+1); + --j; + } + } + } + + + //Fill empty keyframe areas + if (PositionKeys.size()) + { + SPositionKey *Key; + Key=&PositionKeys[0];//getFirst + if (Key->frame!=0) + { + PositionKeys.push_front(*Key); + Key=&PositionKeys[0];//getFirst + Key->frame=0; + } + + Key=&PositionKeys.getLast(); + if (Key->frame!=AnimationFrames) + { + PositionKeys.push_back(*Key); + Key=&PositionKeys.getLast(); + Key->frame=AnimationFrames; + } + } + + if (ScaleKeys.size()) + { + SScaleKey *Key; + Key=&ScaleKeys[0];//getFirst + if (Key->frame!=0) + { + ScaleKeys.push_front(*Key); + Key=&ScaleKeys[0];//getFirst + Key->frame=0; + } + + Key=&ScaleKeys.getLast(); + if (Key->frame!=AnimationFrames) + { + ScaleKeys.push_back(*Key); + Key=&ScaleKeys.getLast(); + Key->frame=AnimationFrames; + } + } + + if (RotationKeys.size()) + { + SRotationKey *Key; + Key=&RotationKeys[0];//getFirst + if (Key->frame!=0) + { + RotationKeys.push_front(*Key); + Key=&RotationKeys[0];//getFirst + Key->frame=0; + } + + Key=&RotationKeys.getLast(); + if (Key->frame!=AnimationFrames) + { + RotationKeys.push_back(*Key); + Key=&RotationKeys.getLast(); + Key->frame=AnimationFrames; + } + } + + } + } + + //Needed for animation and skinning... + + CalculateGlobalMatrices(0,0); + + //rigid animation for non animated meshes + for (i=0; iAttachedMeshes.size(); ++j) + { + SSkinMeshBuffer* Buffer=(*SkinningBuffers)[ AllJoints[i]->AttachedMeshes[j] ]; + Buffer->Transformation=AllJoints[i]->GlobalAnimatedMatrix; + } + } + + //calculate bounding box + if (LocalBuffers.empty()) + BoundingBox.reset(0,0,0); + else + { + irr::core::aabbox3df bb(LocalBuffers[0]->BoundingBox); + LocalBuffers[0]->Transformation.transformBoxEx(bb); + BoundingBox.reset(bb); + + for (u32 j=1; jBoundingBox; + LocalBuffers[j]->Transformation.transformBoxEx(bb); + + BoundingBox.addInternalBox(bb); + } + } +} + +void CM2Mesh::updateBoundingBox(void) +{ + if(!SkinningBuffers) + return; + core::array & buffer = *SkinningBuffers; + BoundingBox.reset(0,0,0); + + if (!buffer.empty()) + { + for (u32 j=0; jrecalculateBoundingBox(); + core::aabbox3df bb = buffer[j]->BoundingBox; + buffer[j]->Transformation.transformBoxEx(bb); + + BoundingBox.addInternalBox(bb); + } + } +} + + + +scene::SSkinMeshBuffer *CM2Mesh::createBuffer() +{ + scene::SSkinMeshBuffer *buffer=new scene::SSkinMeshBuffer(); + LocalBuffers.push_back(buffer); + return buffer; +} + + +CM2Mesh::SJoint *CM2Mesh::createJoint(SJoint *parent) +{ + SJoint *joint=new SJoint; + + AllJoints.push_back(joint); + if (!parent) + { + //Add root joints to array in finalize() + } + else + { + //Set parent (Be careful of the mesh loader also setting the parent) + parent->Children.push_back(joint); + } + + return joint; +} + + +CM2Mesh::SPositionKey *CM2Mesh::createPositionKey(SJoint *joint) +{ + if (!joint) + return 0; + + joint->PositionKeys.push_back(SPositionKey()); + return &joint->PositionKeys.getLast(); +} + + +CM2Mesh::SScaleKey *CM2Mesh::createScaleKey(SJoint *joint) +{ + if (!joint) + return 0; + + joint->ScaleKeys.push_back(SScaleKey()); + return &joint->ScaleKeys.getLast(); +} + + +CM2Mesh::SRotationKey *CM2Mesh::createRotationKey(SJoint *joint) +{ + if (!joint) + return 0; + + joint->RotationKeys.push_back(SRotationKey()); + return &joint->RotationKeys.getLast(); +} + + +CM2Mesh::SWeight *CM2Mesh::createWeight(SJoint *joint) +{ + if (!joint) + return 0; + + joint->Weights.push_back(SWeight()); + return &joint->Weights.getLast(); +} + + +bool CM2Mesh::isStatic() +{ + return !HasAnimation; +} + + +void CM2Mesh::normalizeWeights() +{ + // note: unsure if weights ids are going to be used. + + // Normalise the weights on bones.... + + u32 i,j; + core::array< core::array > Vertices_TotalWeight; + + for (i=0; i()); + Vertices_TotalWeight[i].set_used(LocalBuffers[i]->getVertexCount()); + } + + for (i=0; iWeights.size(); ++j) + { + if (joint->Weights[j].strength<=0)//Check for invalid weights + { + joint->Weights.erase(j); + --j; + } + else + { + Vertices_TotalWeight[ joint->Weights[j].buffer_id ] [ joint->Weights[j].vertex_id ] += joint->Weights[j].strength; + } + } + } + + for (i=0; iWeights.size(); ++j) + { + const f32 total = Vertices_TotalWeight[ joint->Weights[j].buffer_id ] [ joint->Weights[j].vertex_id ]; + if (total != 0 && total != 1) + joint->Weights[j].strength /= total; + } + } +} + + +void CM2Mesh::recoverJointsFromMesh(core::array &JointChildSceneNodes) +{ + for (u32 i=0;isetPosition( joint->LocalAnimatedMatrix.getTranslation() ); + node->setRotation( joint->LocalAnimatedMatrix.getRotationDegrees() ); + + //node->setScale( joint->LocalAnimatedMatrix.getScale() ); + + node->positionHint=joint->positionHint; + node->scaleHint=joint->scaleHint; + node->rotationHint=joint->rotationHint; + + //node->setAbsoluteTransformation(joint->GlobalMatrix); //not going to work + + //Note: This updateAbsolutePosition will not work well if joints are not nested like b3d + //node->updateAbsolutePosition(); + } +} + + +void CM2Mesh::transferJointsToMesh(const core::array &JointChildSceneNodes) +{ + for (u32 i=0; iLocalAnimatedMatrix.setTranslation(node->getPosition()); + joint->LocalAnimatedMatrix.setRotationDegrees(node->getRotation()); + + //joint->LocalAnimatedMatrix.setScale( node->getScale() ); + + joint->positionHint=node->positionHint; + joint->scaleHint=node->scaleHint; + joint->rotationHint=node->rotationHint; + + if (node->getSkinningSpace()==EBSS_GLOBAL) + joint->GlobalSkinningSpace=true; + else + joint->GlobalSkinningSpace=false; + } + //Remove cache, temp... + LastAnimatedFrame=-1; + SkinnedLastFrame=false; +} + + +void CM2Mesh::transferOnlyJointsHintsToMesh(const core::array &JointChildSceneNodes) +{ + for (u32 i=0;ipositionHint=node->positionHint; + joint->scaleHint=node->scaleHint; + joint->rotationHint=node->rotationHint; + } +} + + +void CM2Mesh::createJoints(core::array &JointChildSceneNodes, + IAnimatedMeshSceneNode* AnimatedMeshSceneNode, + ISceneManager* SceneManager) +{ + u32 i; + + //Create new joints + for (i=0;iName.c_str())); + } + + //Match up parents + for (i=0;iChildren.size();++n) + { + if (parentTest->Children[n]==joint) + { + parentID=j; + break; + } + } + } + } + + if (parentID!=-1) + node->setParent( JointChildSceneNodes[parentID] ); + else + node->setParent( AnimatedMeshSceneNode ); + + node->drop(); + } +} + + +void CM2Mesh::convertMeshToTangents() +{ + // now calculate tangents + for (u32 b=0; b < LocalBuffers.size(); ++b) + { + if (LocalBuffers[b]) + { + LocalBuffers[b]->MoveTo_Tangents(); + + const s32 idxCnt = LocalBuffers[b]->getIndexCount(); + + u16* idx = LocalBuffers[b]->getIndices(); + video::S3DVertexTangents* v = + (video::S3DVertexTangents*)LocalBuffers[b]->getVertices(); + + for (s32 i=0; igetBoundingBox(); - for (u32 i=1; igetBoundingBox()); - } - else - BoundingBox.reset(0.0f, 0.0f, 0.0f); - } - //! sets a flag of all contained materials to a new value virtual void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue); @@ -80,8 +61,10 @@ namespace scene //! flags the meshbuffer as changed, reloads hardware buffers virtual void setDirty(E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX); - - //! Returns the type of the animated mesh. + //! updates the bounding box + virtual void updateBoundingBox(void); + + //! Returns the type of the animated mesh. virtual E_ANIMATED_MESH_TYPE getMeshType() const; //! Gets joint count. @@ -159,9 +142,7 @@ private: void normalizeWeights(); - void buildAll_LocalAnimatedMatrices(); //public? - - void buildAll_GlobalAnimatedMatrices(SJoint *Joint=0, SJoint *ParentJoint=0); + void buildAllAnimatedMatrices(SJoint *Joint=0, SJoint *ParentJoint=0); //public? void getFrameData(f32 frame, SJoint *Node, core::vector3df &position, s32 &positionHint, @@ -192,8 +173,7 @@ private: f32 AnimationFrames; f32 LastAnimatedFrame; - f32 LastSkinnedFrame; - bool BoneControlUsed; + bool SkinnedLastFrame; bool AnimateNormals; diff --git a/src/Client/GUI/CM2MeshFileLoader.cpp b/src/Client/GUI/CM2MeshFileLoader.cpp index 5cc312f..6ec90ae 100644 --- a/src/Client/GUI/CM2MeshFileLoader.cpp +++ b/src/Client/GUI/CM2MeshFileLoader.cpp @@ -1,9 +1,8 @@ -// #define _DEBUG 1 +#define _DEBUG 1 #include #include "MemoryDataHolder.h" #include "MemoryInterface.h" #include "CM2MeshFileLoader.h" -#include "SSkinnedMesh.h" #include "common.h" namespace irr @@ -38,7 +37,7 @@ IAnimatedMesh* CM2MeshFileLoader::createMesh(io::IReadFile* file) if(!file) return 0; MeshFile = file; - AnimatedMesh = new scene::CSkinnedMesh(); + AnimatedMesh = new scene::CM2Mesh(); if ( load() ) { @@ -65,13 +64,6 @@ void CM2MeshFileLoader::ReadVertices() for(u32 i =0;iread(&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)); @@ -114,6 +106,7 @@ void CM2MeshFileLoader::ReadViewData(io::IReadFile* file) { file->read(&tempM2Submesh,sizeof(ModelViewSubmesh)-(header.version==0x100?16:0)); M2MSubmeshes.push_back(tempM2Submesh); + DEBUG(logdebug("Submesh %u nBone: %u ofsBone: %u",i,tempM2Submesh.nBone, tempM2Submesh.ofsBone)); // std::cout<< "Submesh " <seek(header.ofsTexLookup); - for(u32 i=0;iseek(header.ofsGlobalSequences); + for(u32 i=0;iread(&tempM2TexLookup,sizeof(u16)); - M2MTextureLookup.push_back(tempM2TexLookup); - DEBUG(logdebug("Texture %u Type %u",i,tempM2TexLookup)); + MeshFile->read(&tempGlobalSeq,sizeof(u32)); + M2MGlobalSequences.push_back(tempGlobalSeq); + 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 - TextureDefinition tempM2TexDef; - if(!M2MTextureDef.empty()) + //BoneLookupTable. This is global data + u16 tempBoneLookup; + if(!M2MBoneLookupTable.empty()) { - M2MTextureDef.clear(); + M2MBoneLookupTable.clear(); } - MeshFile->seek(header.ofsTextures); - for(u32 i=0;iseek(header.ofsBoneLookupTable); + for(u32 i=0;iread(&tempM2TexDef,sizeof(TextureDefinition)); - M2MTextureDef.push_back(tempM2TexDef); - DEBUG(logdebug("Texture %u Type %u",i,tempM2TexDef.texType)); + MeshFile->read(&tempBoneLookup,sizeof(u16)); + M2MBoneLookupTable.push_back(tempBoneLookup); + 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 - RenderFlags tempM2RF; - if(!M2MRenderFlags.empty()) + //SkeleBoneLookupTable. This is global data + u16 tempSkeleBoneLookup; + if(!M2MSkeleBoneLookupTable.empty()) { - M2MRenderFlags.clear(); + M2MSkeleBoneLookupTable.clear(); } - MeshFile->seek(header.ofsTexFlags); - for(u32 i=0;iseek(header.ofsSkelBoneLookup); + for(u32 i=0;iread(&tempM2RF,sizeof(RenderFlags)); - M2MRenderFlags.push_back(tempM2RF); - DEBUG(logdebug("Flag %u: (%u, %u)",i,tempM2RF.blending,tempM2RF.flags)); + MeshFile->read(&tempSkeleBoneLookup,sizeof(u16)); + M2MSkeleBoneLookupTable.push_back(tempSkeleBoneLookup); + DEBUG(logdebug("SkeleBoneLookupTable %u Value %u",i,tempSkeleBoneLookup)); } - DEBUG(logdebug("Read %u Renderflags",M2MRenderFlags.size())); - - if(!M2MTextureFiles.empty()) - M2MTextureFiles.clear(); - - std::string tempTexFileName=""; - M2MTextureFiles.reallocate(M2MTextureDef.size()); - for(u32 i=0; iseek(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)); + M2MAnimations.clear(); } -} + MeshFile->seek(header.ofsAnimations); + for(u32 i=0;iread(&tempAnimation,sizeof(Animation)); + M2MAnimations.push_back(tempAnimation); + DEBUG(logdebug("Animation %u Id %u Start %u End %u",i,tempAnimation.animationID,tempAnimation.start,tempAnimation.end)); + } + DEBUG(logdebug("Read %u Animations",M2MAnimations.size())); - -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(¤tView,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;iread(&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(¤tView, sizeof(ModelView)); -// -// //std::cout << "Skins "<0) -// M2MIndices.clear(); -// -// u16 tempM2Index; -// SkinFile->seek(currentView.ofsIndex); -// for(u32 i =0;iread(&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;iread(&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;iread(&tempM2Submesh,sizeof(ModelViewSubmesh)); -// M2MSubmeshes.push_back(tempM2Submesh); -// // std::cout<< "Submesh " <seek(currentView.ofsTex); -// for(u32 i=0;iread(&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 -Animation tempAnimation; -if(!M2MAnimations.empty()) -{ - M2MAnimations.clear(); -} -MeshFile->seek(header.ofsAnimations); -for(u32 i=0;iread(&tempAnimation,sizeof(Animation)); - M2MAnimations.push_back(tempAnimation); - //std::cout<read(&tempBone.rotation.header,sizeof(AnimBlockHead)); MeshFile->read(&tempBone.scaling.header,sizeof(AnimBlockHead)); 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); - //std::cout<seek(header.ofsTexLookup); + for(u32 i=0;igetAllJoints()[M2MBones[i].parentBone]; + MeshFile->read(&tempM2TexLookup,sizeof(u16)); + M2MTextureLookup.push_back(tempM2TexLookup); + DEBUG(logdebug("Texture %u Type %u",i,tempM2TexLookup)); } - Joint=AnimatedMesh->createJoint(ParentJoint); + DEBUG(logdebug("Read %u Texture lookup entries",M2MTextureLookup.size())); - - //std::cout << i << " "<GlobalMatrix.getTranslation().X<< " "<GlobalMatrix.getTranslation().Y<< " "<GlobalMatrix.getTranslation().Z<<'\n'; - //std::cout << i << " "<createPositionKey(Joint); - pos->frame=M2MBones[i].translation.timestamps[j]*.01f; - pos->position=core::vector3df(M2MBones[i].translation.values[j*3],M2MBones[i].translation.values[j*3+1],M2MBones[i].translation.values[j*3+2]); + M2MTextureDef.clear(); } -if(M2MBones[i].rotation.header.nValues>0) -{ - for(u32 j=0;jseek(header.ofsTextures); + for(u32 i=0;icreateRotationKey(Joint); - rot->frame=M2MBones[i].rotation.timestamps[j]*.01f; - 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]); - 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'; + 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;iread(&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; iseek(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)); } } -if(M2MBones[i].scaling.header.nValues>0){ - for(u32 j=0;jcreateScaleKey(Joint); - scale->frame=M2MBones[i].scaling.timestamps[j]*.01f; - 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<Animatedposition.X<<' '<Animatedposition.Y<<' '<Animatedposition.Z<<' '<<'\n'; -// 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; - //scaleMatrix.setScale( Joint->Animatedscale ); - core::matrix4 rotationMatrix;// = Joint->Animatedrotation.getMatrix(); - Joint->GlobalMatrix = positionMatrix * rotationMatrix * scaleMatrix;// +bool CM2MeshFileLoader::load() +{ +DEBUG(logdebug("Trying to open file %s",MeshFile->getFileName())); - if (ParentJoint) - { - core::matrix4 InverseParentGlobal; - ParentJoint->GlobalMatrix.getInverse(InverseParentGlobal); - Joint->LocalMatrix = InverseParentGlobal * Joint->GlobalMatrix; - } - else - Joint->LocalMatrix = Joint->GlobalMatrix; + +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(¤tView,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; + } } -*/ -//std::cout<getAllJoints()[1]->Children.size()<<" Children\n"; - - - - /////////////////////////// // EVERYTHING IS READ /////////////////////////// +/////////////////////////////////////// +// Animation related stuff // +/////////////////////////////////////// + +scene::CM2Mesh::SJoint* Joint; +for(u32 i=0;igetAllJoints()[M2MBones[i].parentBone]; + } + Joint=AnimatedMesh->createJoint(ParentJoint); + + if(M2MBones[i].translation.header.nValues>0) + { + for(u32 j=0;jcreatePositionKey(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]); + } + } + if(M2MBones[i].rotation.header.nValues>0) + { + for(u32 j=0;jcreateRotationKey(Joint); + 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]); + tempQ.normalize(); + rot->rotation=tempQ; + } + } + + if(M2MBones[i].scaling.header.nValues>0) + { + for(u32 j=0;jcreateScaleKey(Joint); + 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]); + } + } + + 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(); + + core::matrix4 scaleMatrix; + scaleMatrix.setScale( Joint->Animatedscale ); + + Joint->GlobalMatrix = positionMatrix * rotationMatrix * scaleMatrix; +} -//And M2MVertices are not usable like this. Thus we transform + + +//And M2MVertices are not usable like this. Thus we put it into an irrlicht S3DVertex if(M2Vertices.size()>0) M2Vertices.clear(); for(u32 i=0;iVertices_Standard.push_back(M2Vertices[j]); -// for(u32 k=0; k<4; k++) -// { - //std::cout << (u32)M2MVertices[j].bones[k] << " "; - /* ANIMATION NEED FIX !!! + for(u32 k=0; k<4; k++) + { 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->vertex_id=j-M2MSubmeshes[i].ofsVertex; + weight->vertex_id=MeshBuffer->Vertices_Standard.size()-1; weight->buffer_id=i; } - */ - //std::cout<buffer_id << " " << weight->vertex_id << " " << weight->strength <<"|"; -// } - // std::cout<<'\n'; + + } } - //std::cout << i << ": " << MeshBuffer->Vertices_Standard.size() <<" "<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;jgetVideoDriver()->findTexture(buf); if(!tex) { io::IReadFile* TexFile = io::IrrCreateIReadFileBasic(Device, buf); - // logdebug("Texture %s loading",M2MTextureFiles[M2MTextureLookup[M2MTextureUnit[j].textureIndex]].c_str()); if (!TexFile) { logerror("CM2MeshFileLoader: Texture file not found: %s", buf); continue; } -// logdebug("Texture %s loaded",M2MTextureFiles[M2MTextureLookup[M2MTextureUnit[j].textureIndex]].c_str()); tex = Device->getVideoDriver()->getTexture(TexFile); 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)); MeshBuffer->getMaterial().BackfaceCulling=(M2MRenderFlags[M2MTextureUnit[j].renderFlagsIndex].flags & 0x04)?false:true; - if(M2MRenderFlags[M2MTextureUnit[j].renderFlagsIndex].blending==1) - MeshBuffer->getMaterial().MaterialType=video::EMT_TRANSPARENT_ALPHA_CHANNEL; + switch(M2MRenderFlags[M2MTextureUnit[j].renderFlagsIndex].blending) + { + case 1: + case 2: + case 4: + MeshBuffer->getMaterial().MaterialType=video::EMT_TRANSPARENT_ALPHA_CHANNEL; + DEBUG(logdebug("Alpha Channel Transparency on")); + break; + } } } MeshBuffer->recalculateBoundingBox(); - MeshBuffer->setHardwareMappingHint(EHM_STATIC); + if(header.nAnimations==0 && header.nGlobalSequences == 0) + MeshBuffer->setHardwareMappingHint(EHM_STATIC); + else + MeshBuffer->setHardwareMappingHint(EHM_STREAM); - // Mesh->addMeshBuffer(MeshBuffer); - // Mesh->recalculateBoundingBox(); - //MeshBuffer->drop(); - //std::cout << "Mesh now has "<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(); M2MTriangles.clear(); M2Vertices.clear(); diff --git a/src/Client/GUI/CM2MeshFileLoader.h b/src/Client/GUI/CM2MeshFileLoader.h index 2a4f08e..587f63f 100644 --- a/src/Client/GUI/CM2MeshFileLoader.h +++ b/src/Client/GUI/CM2MeshFileLoader.h @@ -1,6 +1,6 @@ #include "irrlicht/irrlicht.h" #include "irrlicht/IMeshLoader.h" -#include "SSkinnedMesh.h" +#include "CM2Mesh.h" #include #include #include @@ -53,8 +53,8 @@ struct ModelHeader { u32 nTexFlags; u32 ofsTexFlags; - u32 nY; - u32 ofsY; //0x90 + u32 nBoneLookupTable; + u32 ofsBoneLookupTable; //0x90 u32 nTexLookup; u32 ofsTexLookup; @@ -127,7 +127,7 @@ struct ModelViewSubmesh { u16 nVertex; u16 ofsTris;//Starting Triangle index u16 nTris; - u16 unk1, unk2, unk3, unk4; + u16 nBone, ofsBone, unk3, unk4; core::vector3df v; float unkf[4]; }; @@ -220,14 +220,15 @@ private: bool load(); void ReadVertices(); void ReadTextureDefinitions(); + void ReadAnimationData(); void ReadViewData(io::IReadFile* file); IrrlichtDevice *Device; core::stringc Texdir; io::IReadFile *MeshFile, *SkinFile; - CSkinnedMesh *AnimatedMesh; - scene::CSkinnedMesh::SJoint *ParentJoint; + CM2Mesh *AnimatedMesh; + scene::CM2Mesh::SJoint *ParentJoint; @@ -246,8 +247,11 @@ private: core::array M2MTextureFiles; core::array M2MTextureUnit; core::array M2MRenderFlags; + core::array M2MGlobalSequences; core::array M2MAnimations; core::array M2MBones; + core::array M2MBoneLookupTable; + core::array M2MSkeleBoneLookupTable; //Used for the Mesh, thus m2_noM_* core::array M2Vertices; core::array M2Indices; diff --git a/src/Client/GUI/CMakeLists.txt b/src/Client/GUI/CMakeLists.txt index c224201..bf6590e 100644 --- a/src/Client/GUI/CMakeLists.txt +++ b/src/Client/GUI/CMakeLists.txt @@ -21,5 +21,5 @@ SceneLogin.cpp SceneWorld.cpp ShTlTerrainSceneNode.cpp SImage.cpp -SSkinnedMesh.cpp +CM2Mesh.cpp ) \ No newline at end of file diff --git a/src/Client/GUI/CWMOMeshFileLoader.cpp b/src/Client/GUI/CWMOMeshFileLoader.cpp index 8526512..d18baf7 100644 --- a/src/Client/GUI/CWMOMeshFileLoader.cpp +++ b/src/Client/GUI/CWMOMeshFileLoader.cpp @@ -3,7 +3,6 @@ #include "MemoryDataHolder.h" #include "MemoryInterface.h" #include "CWMOMeshFileLoader.h" -#include "SSkinnedMesh.h" #include "common.h" inline void flipcc(irr::u8 *fcc) @@ -52,7 +51,7 @@ IAnimatedMesh* CWMOMeshFileLoader::createMesh(io::IReadFile* file) return 0; MeshFile = file; std::string filename=MeshFile->getFileName(); - Mesh = new scene::CSkinnedMesh(); + Mesh = new scene::CM2Mesh(); if ( load(true) )//We try loading a root file first! { @@ -69,7 +68,7 @@ IAnimatedMesh* CWMOMeshFileLoader::createMesh(io::IReadFile* file) } load(false); } - Mesh->recalculateBoundingBox(); + Mesh->updateBoundingBox(); Device->getSceneManager()->getMeshManipulator()->flipSurfaces(Mesh); //Fix inverted surfaces after the rotation //Does this crash on windows? Device->getSceneManager()->getMeshManipulator()->recalculateNormals(Mesh,true);//just to be sure diff --git a/src/Client/GUI/CWMOMeshFileLoader.h b/src/Client/GUI/CWMOMeshFileLoader.h index 73c3981..55d6f3a 100644 --- a/src/Client/GUI/CWMOMeshFileLoader.h +++ b/src/Client/GUI/CWMOMeshFileLoader.h @@ -1,6 +1,6 @@ #include "irrlicht/irrlicht.h" #include "irrlicht/IMeshLoader.h" -#include "SSkinnedMesh.h" +#include "CM2Mesh.h" #include #include #include @@ -83,7 +83,7 @@ private: core::stringc Texdir; io::IReadFile* MeshFile; - CSkinnedMesh* Mesh; + CM2Mesh* Mesh; //Stuff from root file diff --git a/src/Client/GUI/DrawObject.cpp b/src/Client/GUI/DrawObject.cpp index f09d97b..8d0192d 100644 --- a/src/Client/GUI/DrawObject.cpp +++ b/src/Client/GUI/DrawObject.cpp @@ -193,7 +193,7 @@ void DrawObject::Draw(void) WorldPosition pos = ((WorldObject*)_obj)->GetPosition(); node->setPosition(WPToIrr(pos)); rotation.Y = O_TO_IRR(pos.o); - + rotation.X -=90; float s = _obj->GetFloatValue(OBJECT_FIELD_SCALE_X); if(s <= 0) s = 1; diff --git a/src/Client/GUI/SSkinnedMesh.cpp b/src/Client/GUI/SSkinnedMesh.cpp deleted file mode 100755 index ef061bd..0000000 --- a/src/Client/GUI/SSkinnedMesh.cpp +++ /dev/null @@ -1,1429 +0,0 @@ -// Copyright (C) 2002-2007 Nikolaus Gebhardt -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h -#include -#include "irrlicht/irrlicht.h" -#include "SSkinnedMesh.h" -#include "CBoneSceneNode.h" -namespace irr -{ -namespace scene -{ - - -//! constructor -CSkinnedMesh::CSkinnedMesh() -: SkinningBuffers(0), HasAnimation(0), PreparedForSkinning(0), - AnimationFrames(0.f), LastAnimatedFrame(0.f), LastSkinnedFrame(0.f), - BoneControlUsed(false), AnimateNormals(true), HardwareSkinning(0), InterpolationMode(EIM_LINEAR) -{ - #ifdef _DEBUG - setDebugName("CSkinnedMesh"); - #endif - - SkinningBuffers=&LocalBuffers; -} - - -//! destructor -CSkinnedMesh::~CSkinnedMesh() -{ - for (u32 i=0; idrop(); - } -} - - -//! returns the amount of frames in milliseconds. -//! If the amount is 1, it is a static (=non animated) mesh. -u32 CSkinnedMesh::getFrameCount() const -{ - return core::floor32(AnimationFrames); -} - - -//! returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail. Note, that some Meshes will ignore the detail level. -IMesh* CSkinnedMesh::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop) -{ - //animate(frame,startFrameLoop, endFrameLoop); - if (frame==-1) - return this; - - animateMesh((f32)frame, 1.0f); - buildAll_LocalAnimatedMatrices(); - buildAll_GlobalAnimatedMatrices(); - skinMesh(); - return this; -} - - -//-------------------------------------------------------------------------- -// Keyframe Animation -//-------------------------------------------------------------------------- - - -//! Animates this mesh's joints based on frame input -//! blend: {0-old position, 1-New position} -void CSkinnedMesh::animateMesh(f32 frame, f32 blend) -{ -// std::cout<<"Frame "<Animatedposition; - const core::vector3df oldScale = joint->Animatedscale; - const core::quaternion oldRotation = joint->Animatedrotation; - - core::vector3df position = oldPosition; - core::vector3df scale = oldScale; - core::quaternion rotation = oldRotation; - getFrameData(frame, joint, - position, joint->positionHint, - scale, joint->scaleHint, - rotation, joint->rotationHint); - - if (blend==1.0f) - { - //No blending needed - joint->Animatedposition = position; - joint->Animatedscale = scale; - joint->Animatedrotation = rotation; - } - else - { - //Blend animation - joint->Animatedposition = core::lerp(oldPosition, position, blend); - joint->Animatedscale = core::lerp(oldScale, scale, blend); - joint->Animatedrotation.slerp(oldRotation, rotation, blend); - } - - //Note: - //_LocalAnimatedMatrix needs to be built at some point, but this function may be called lots of times for - //one render (to play two animations at the same time) _LocalAnimatedMatrix only needs to be built once. - //a call to buildAllLocalAnimatedMatrices is needed before skinning the mesh, and before the user gets the joints to move - - //---------------- - // Temp! - buildAll_LocalAnimatedMatrices(); - //----------------- - } -} - - -void CSkinnedMesh::buildAll_LocalAnimatedMatrices() -{ - for (u32 i=0; iUseAnimationFrom && - (joint->UseAnimationFrom->PositionKeys.size() || - joint->UseAnimationFrom->ScaleKeys.size() || - joint->UseAnimationFrom->RotationKeys.size() )) - { - joint->LocalAnimatedMatrix=joint->Animatedrotation.getMatrix(); - - // --- joint->LocalAnimatedMatrix *= joint->Animatedrotation.getMatrix() --- - f32 *m1 = joint->LocalAnimatedMatrix.pointer(); - core::vector3df &Pos = joint->Animatedposition; - m1[0] += Pos.X*m1[3]; - m1[1] += Pos.Y*m1[3]; - m1[2] += Pos.Z*m1[3]; - m1[4] += Pos.X*m1[7]; - m1[5] += Pos.Y*m1[7]; - m1[6] += Pos.Z*m1[7]; - m1[8] += Pos.X*m1[11]; - m1[9] += Pos.Y*m1[11]; - m1[10] += Pos.Z*m1[11]; - m1[12] += Pos.X*m1[15]; - m1[13] += Pos.Y*m1[15]; - m1[14] += Pos.Z*m1[15]; - // ----------------------------------- - - joint->GlobalSkinningSpace=false; - - if (joint->ScaleKeys.size()) - { - /* - core::matrix4 scaleMatrix; - scaleMatrix.setScale(joint->Animatedscale); - joint->LocalAnimatedMatrix *= scaleMatrix; - */ - - // -------- joint->LocalAnimatedMatrix *= scaleMatrix ----------------- - f32 *m1 = joint->LocalAnimatedMatrix.pointer(); - m1[0] *= joint->Animatedscale.X; - m1[1] *= joint->Animatedscale.X; - m1[2] *= joint->Animatedscale.X; - m1[3] *= joint->Animatedscale.X; - m1[4] *= joint->Animatedscale.Y; - m1[5] *= joint->Animatedscale.Y; - m1[6] *= joint->Animatedscale.Y; - m1[7] *= joint->Animatedscale.Y; - m1[8] *= joint->Animatedscale.Z; - m1[9] *= joint->Animatedscale.Z; - m1[10] *= joint->Animatedscale.Z; - m1[11] *= joint->Animatedscale.Z; - m1[12] *= joint->Animatedscale.X; - // ----------------------------------- - - } - } - else - { - joint->LocalAnimatedMatrix=joint->LocalMatrix; - } - } -} - - -void CSkinnedMesh::buildAll_GlobalAnimatedMatrices(SJoint *joint, SJoint *parentJoint) -{ - if (!joint) - { - for (u32 i=0; iGlobalSkinningSpace) - joint->GlobalAnimatedMatrix = joint->LocalAnimatedMatrix; - else - joint->GlobalAnimatedMatrix = parentJoint->GlobalAnimatedMatrix * joint->LocalAnimatedMatrix; - - } - - for (u32 j=0; jChildren.size(); ++j) - buildAll_GlobalAnimatedMatrices(joint->Children[j], joint); -} - - -void CSkinnedMesh::getFrameData(f32 frame, SJoint *joint, - core::vector3df &position, s32 &positionHint, - core::vector3df &scale, s32 &scaleHint, - core::quaternion &rotation, s32 &rotationHint) -{ - s32 foundPositionIndex = -1; - s32 foundScaleIndex = -1; - s32 foundRotationIndex = -1; - - if (joint->UseAnimationFrom) - { - const core::array &PositionKeys=joint->UseAnimationFrom->PositionKeys; - const core::array &ScaleKeys=joint->UseAnimationFrom->ScaleKeys; - const core::array &RotationKeys=joint->UseAnimationFrom->RotationKeys; - - if (PositionKeys.size()) - { - foundPositionIndex = -1; - - //Test the Hints... - if (positionHint>=0 && (u32)positionHint < PositionKeys.size()) - { - //check this hint - if (positionHint>0 && PositionKeys[positionHint].frame>=frame && PositionKeys[positionHint-1].frame=frame && - PositionKeys[positionHint+0].frame= frame) //Keys should to be sorted by frame - { - foundPositionIndex=i; - positionHint=i; - break; - } - } - } - - //Do interpolation... - if (foundPositionIndex!=-1) - { - if (InterpolationMode==EIM_CONSTANT || foundPositionIndex==0) - { - position = PositionKeys[foundPositionIndex].position; - } - else if (InterpolationMode==EIM_LINEAR) - { - const SPositionKey& KeyA = PositionKeys[foundPositionIndex]; - const SPositionKey& KeyB = PositionKeys[foundPositionIndex-1]; - - const f32 fd1 = frame - KeyA.frame; - const f32 fd2 = KeyB.frame - frame; - position = ((KeyB.position-KeyA.position)/(fd1+fd2))*fd1 + KeyA.position; - } - } - } - - //------------------------------------------------------------ - - if (ScaleKeys.size()) - { - foundScaleIndex = -1; - - //Test the Hints... - if (scaleHint>=0 && (u32)scaleHint < ScaleKeys.size()) - { - //check this hint - if (scaleHint>0 && ScaleKeys[scaleHint].frame>=frame && ScaleKeys[scaleHint-1].frame=frame && - ScaleKeys[scaleHint+0].frame= frame) //Keys should to be sorted by frame - { - foundScaleIndex=i; - scaleHint=i; - break; - } - } - } - - //Do interpolation... - if (foundScaleIndex!=-1) - { - if (InterpolationMode==EIM_CONSTANT || foundScaleIndex==0) - { - scale = ScaleKeys[foundScaleIndex].scale; - } - else if (InterpolationMode==EIM_LINEAR) - { - const SScaleKey& KeyA = ScaleKeys[foundScaleIndex]; - const SScaleKey& KeyB = ScaleKeys[foundScaleIndex-1]; - - const f32 fd1 = frame - KeyA.frame; - const f32 fd2 = KeyB.frame - frame; - scale = ((KeyB.scale-KeyA.scale)/(fd1+fd2))*fd1 + KeyA.scale; - } - } - } - - //------------------------------------------------------------- - - if (RotationKeys.size()) - { - foundRotationIndex = -1; - - //Test the Hints... - if (rotationHint>=0 && (u32)rotationHint < RotationKeys.size()) - { - //check this hint - if (rotationHint>0 && RotationKeys[rotationHint].frame>=frame && RotationKeys[rotationHint-1].frame=frame && - RotationKeys[rotationHint+0].frame= frame) //Keys should be sorted by frame - { - foundRotationIndex=i; - rotationHint=i; - break; - } - } - } - - //Do interpolation... - if (foundRotationIndex!=-1) - { - if (InterpolationMode==EIM_CONSTANT || foundRotationIndex==0) - { - rotation = RotationKeys[foundRotationIndex].rotation; - } - else if (InterpolationMode==EIM_LINEAR) - { - const SRotationKey& KeyA = RotationKeys[foundRotationIndex]; - const SRotationKey& KeyB = RotationKeys[foundRotationIndex-1]; - - const f32 fd1 = frame - KeyA.frame; - const f32 fd2 = KeyB.frame - frame; - const f32 t = fd1/(fd1+fd2); - - /* - f32 t = 0; - if (KeyA.frame!=KeyB.frame) - t = (frame-KeyA.frame) / (KeyB.frame - KeyA.frame); - */ - - rotation.slerp(KeyA.rotation, KeyB.rotation, t); - } - } - } - } -} - -//-------------------------------------------------------------------------- -// Software Skinning -//-------------------------------------------------------------------------- - -//! Preforms a software skin on this mesh based of joint positions -void CSkinnedMesh::skinMesh() -{ - if ( !HasAnimation) - return; - - //---------------- - // Temp! - buildAll_GlobalAnimatedMatrices(); - //----------------- - - if (!HardwareSkinning) - { - //Software skin.... - u32 i; - - //rigid animation - for (i=0; iAttachedMeshes.size(); ++j) - { - SSkinMeshBuffer* Buffer=(*SkinningBuffers)[ AllJoints[i]->AttachedMeshes[j] ]; - Buffer->Transformation=AllJoints[i]->GlobalAnimatedMatrix; - } - } - - //clear skinning helper array - for (i=0; isize(); ++i) - (*SkinningBuffers)[i]->setDirty(); - - } -} - - -void CSkinnedMesh::SkinJoint(SJoint *joint, SJoint *parentJoint) -{ - if (joint->Weights.size()) - { - //Find this joints pull on vertices... - core::matrix4 jointVertexPull(core::matrix4::EM4CONST_NOTHING); - jointVertexPull.setbyproduct(joint->GlobalAnimatedMatrix, joint->GlobalInversedMatrix); - - core::vector3df thisVertexMove, thisNormalMove; - - core::array &buffersUsed=*SkinningBuffers; - - //Skin Vertices Positions and Normals... - for (u32 i=0; iWeights.size(); ++i) - { - SWeight& weight = joint->Weights[i]; - - // Pull this vertex... - jointVertexPull.transformVect(thisVertexMove, weight.StaticPos); - - if (AnimateNormals) - jointVertexPull.rotateVect(thisNormalMove, weight.StaticNormal); - - if (! (*(weight.Moved)) ) - { - *(weight.Moved) = true; - - buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Pos = thisVertexMove * weight.strength; - - if (AnimateNormals) - buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Normal = thisNormalMove * weight.strength; - - //*(weight._Pos) = thisVertexMove * weight.strength; - } - else - { - buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Pos += thisVertexMove * weight.strength; - - if (AnimateNormals) - buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Normal += thisNormalMove * weight.strength; - - //*(weight._Pos) += thisVertexMove * weight.strength; - } - } - } - - //Skin all children - for (u32 j=0; jChildren.size(); ++j) - SkinJoint(joint->Children[j], joint); -} - - -E_ANIMATED_MESH_TYPE CSkinnedMesh::getMeshType() const -{ - return EAMT_SKINNED; -} - - -//! Gets joint count. -u32 CSkinnedMesh::getJointCount() const -{ - return AllJoints.size(); -} - - -//! Gets the name of a joint. -const c8* CSkinnedMesh::getJointName(u32 number) const -{ - if (number >= AllJoints.size()) - return 0; - return AllJoints[number]->Name.c_str(); -} - - -//! Gets a joint number from its name -s32 CSkinnedMesh::getJointNumber(const c8* name) const -{ - for (u32 i=0; iName == name) - return i; - } - - return -1; -} - - -//! returns amount of mesh buffers. -u32 CSkinnedMesh::getMeshBufferCount() const -{ - return LocalBuffers.size(); -} - - -//! returns pointer to a mesh buffer -IMeshBuffer* CSkinnedMesh::getMeshBuffer(u32 nr) const -{ - if (nr < LocalBuffers.size()) - return LocalBuffers[nr]; - else - return 0; -} - - -//! Returns pointer to a mesh buffer which fits a material -IMeshBuffer* CSkinnedMesh::getMeshBuffer(const video::SMaterial &material) const -{ - for (u32 i=0; igetMaterial() == material) - return LocalBuffers[i]; - } - return 0; -} - - -//! returns an axis aligned bounding box -const core::aabbox3d& CSkinnedMesh::getBoundingBox() const -{ - return BoundingBox; -} - - -//! set user axis aligned bounding box -void CSkinnedMesh::setBoundingBox( const core::aabbox3df& box) -{ - BoundingBox = box; -} - - -//! sets a flag of all contained materials to a new value -void CSkinnedMesh::setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) -{ - for (u32 i=0; iMaterial.setFlag(flag,newvalue); -} - -//! set the hardware mapping hint, for driver -void CSkinnedMesh::setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint, - E_BUFFER_TYPE buffer) -{ - for (u32 i=0; isetHardwareMappingHint(newMappingHint, buffer); -} - - -//! flags the meshbuffer as changed, reloads hardware buffers -void CSkinnedMesh::setDirty(E_BUFFER_TYPE buffer) -{ - for (u32 i=0; isetDirty(buffer); -} - - -//! uses animation from another mesh -bool CSkinnedMesh::useAnimationFrom(const ISkinnedMesh *mesh) -{ - bool unmatched=false; - - for(u32 i=0;iUseAnimationFrom=0; - - if (joint->Name=="") - unmatched=true; - else - { - for(u32 j=0;jgetAllJoints().size();++j) - { - SJoint *otherJoint=mesh->getAllJoints()[j]; - if (joint->Name==otherJoint->Name) - { - joint->UseAnimationFrom=otherJoint; - } - } - if (!joint->UseAnimationFrom) - unmatched=true; - } - } - - checkForAnimation(); - - return !unmatched; -} - - -//!Update Normals when Animating -//!False= Don't animate them, faster -//!True= Update normals (default) -void CSkinnedMesh::updateNormalsWhenAnimating(bool on) -{ - AnimateNormals = on; -} - - -//!Sets Interpolation Mode -void CSkinnedMesh::setInterpolationMode(E_INTERPOLATION_MODE mode) -{ - InterpolationMode = mode; -} - - -core::array &CSkinnedMesh::getMeshBuffers() -{ - return LocalBuffers; -} - - -core::array &CSkinnedMesh::getAllJoints() -{ - return AllJoints; -} - - -const core::array &CSkinnedMesh::getAllJoints() const -{ - return AllJoints; -} - - -//! (This feature is not implementated in irrlicht yet) -bool CSkinnedMesh::setHardwareSkinning(bool on) -{ - if (HardwareSkinning!=on) - { - - if (on) - { - - //set mesh to static pose... - for (u32 i=0; iWeights.size(); ++j) - { - const u16 buffer_id=joint->Weights[j].buffer_id; - const u32 vertex_id=joint->Weights[j].vertex_id; - LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos = joint->Weights[j].StaticPos; - LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal = joint->Weights[j].StaticNormal; - } - } - - - } - - HardwareSkinning=on; - } - return HardwareSkinning; -} - - -void CSkinnedMesh::CalculateGlobalMatrices(SJoint *joint,SJoint *parentJoint) -{ - if (!joint && parentJoint) // bit of protection from endless loops - return; - - //Go through the root bones - if (!joint) - { - for (u32 i=0; iGlobalMatrix = joint->LocalMatrix; - else - joint->GlobalMatrix = parentJoint->GlobalMatrix * joint->LocalMatrix; - - joint->LocalAnimatedMatrix=joint->LocalMatrix; - joint->GlobalAnimatedMatrix=joint->GlobalMatrix; - - if (joint->GlobalInversedMatrix.isIdentity())//might be pre calculated - { - joint->GlobalInversedMatrix = joint->GlobalMatrix; - joint->GlobalInversedMatrix.makeInverse(); // slow - } - - for (u32 j=0; jChildren.size(); ++j) - CalculateGlobalMatrices(joint->Children[j],joint); -} - - -void CSkinnedMesh::checkForAnimation() -{ - u32 i,j; - //Check for animation... - HasAnimation = false; - for(i=0;iUseAnimationFrom) - { - if (AllJoints[i]->UseAnimationFrom->PositionKeys.size() || - AllJoints[i]->UseAnimationFrom->ScaleKeys.size() || - AllJoints[i]->UseAnimationFrom->RotationKeys.size() ) - { - HasAnimation = true; - } - } - } - - //meshes with weights, are still counted as animated for ragdolls, etc - if (!HasAnimation) - { - for(i=0;iWeights.size()) - HasAnimation = true; - } - } - - if (HasAnimation) - { - //--- Find the length of the animation --- - AnimationFrames=0; - for(i=0;iUseAnimationFrom) - { - if (AllJoints[i]->UseAnimationFrom->PositionKeys.size()) - if (AllJoints[i]->UseAnimationFrom->PositionKeys.getLast().frame > AnimationFrames) - AnimationFrames=AllJoints[i]->UseAnimationFrom->PositionKeys.getLast().frame; - - if (AllJoints[i]->UseAnimationFrom->ScaleKeys.size()) - if (AllJoints[i]->UseAnimationFrom->ScaleKeys.getLast().frame > AnimationFrames) - AnimationFrames=AllJoints[i]->UseAnimationFrom->ScaleKeys.getLast().frame; - - if (AllJoints[i]->UseAnimationFrom->RotationKeys.size()) - if (AllJoints[i]->UseAnimationFrom->RotationKeys.getLast().frame > AnimationFrames) - AnimationFrames=AllJoints[i]->UseAnimationFrom->RotationKeys.getLast().frame; - } - } - } - - if (HasAnimation && !PreparedForSkinning) - { - PreparedForSkinning=true; - - //check for bugs: - for(i=0; i < AllJoints.size(); ++i) - { - SJoint *joint = AllJoints[i]; - for (j=0; jWeights.size(); ++j) - { - const u16 buffer_id=joint->Weights[j].buffer_id; - const u32 vertex_id=joint->Weights[j].vertex_id; - //check for invalid ids - if (buffer_id>=LocalBuffers.size()) - { - printf("Skinned Mesh: Weight buffer id too large"); - joint->Weights[j].buffer_id = joint->Weights[j].vertex_id =0; - } - else if (vertex_id>=LocalBuffers[buffer_id]->getVertexCount()) - { - printf("Skinned Mesh: Weight vertex id too large"); - joint->Weights[j].buffer_id = joint->Weights[j].vertex_id =0; - } - } - } - - //An array used in skinning - - for (i=0; iWeights.size(); ++j) - { - const u16 buffer_id=joint->Weights[j].buffer_id; - const u32 vertex_id=joint->Weights[j].vertex_id; - - joint->Weights[j].Moved = &Vertices_Moved[buffer_id] [vertex_id]; - joint->Weights[j].StaticPos = LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos; - joint->Weights[j].StaticNormal = LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal; - - //joint->Weights[j]._Pos=&Buffers[buffer_id]->getVertex(vertex_id)->Pos; - } - } - - // normalize weights - normalizeWeights(); - } -} - - -//! called by loader after populating with mesh and bone data -void CSkinnedMesh::finalize() -{ - u32 i; - - LastAnimatedFrame=-1; - LastSkinnedFrame=-1; - - //calculate bounding box - - for (i=0; irecalculateBoundingBox(); - } - - // Get BoundingBox... - if (LocalBuffers.empty()) - BoundingBox.reset(0,0,0); - else - { - BoundingBox.reset(LocalBuffers[0]->BoundingBox.MaxEdge); - for (u32 j=0; jBoundingBox); - } - } - - //add 5% padding to bounding box - core::vector3df Padding=BoundingBox.getExtent()*0.05f; - BoundingBox.MinEdge-=Padding; - BoundingBox.MaxEdge+=Padding; - - - if (AllJoints.size() || RootJoints.size()) - { - // populate AllJoints or RootJoints, depending on which is empty - if (!RootJoints.size()) - { - - for(u32 CheckingIdx=0; CheckingIdx < AllJoints.size(); ++CheckingIdx) - { - - bool foundParent=false; - for(i=0; i < AllJoints.size(); ++i) - { - for(u32 n=0; n < AllJoints[i]->Children.size(); ++n) - { - if (AllJoints[i]->Children[n] == AllJoints[CheckingIdx]) - foundParent=true; - } - } - - if (!foundParent) - RootJoints.push_back(AllJoints[CheckingIdx]); - } - } - else - { - AllJoints=RootJoints; - } - } - - for(i=0; i < AllJoints.size(); ++i) - { - AllJoints[i]->UseAnimationFrom=AllJoints[i]; - } - - //Set array sizes... - - for (i=0; i() ); - Vertices_Moved[i].set_used(LocalBuffers[i]->getVertexCount()); - } - - //Todo: optimise keys here... - - checkForAnimation(); - -if (HasAnimation) - { - //--- optimize and check keyframes --- - for(i=0;i &PositionKeys =AllJoints[i]->PositionKeys; - core::array &ScaleKeys = AllJoints[i]->ScaleKeys; - core::array &RotationKeys = AllJoints[i]->RotationKeys; - - if (PositionKeys.size()>2) - { - for(u32 j=0;j1) - { - for(u32 j=0;j= PositionKeys[j+1].frame) //bad frame, unneed and may cause problems - { - PositionKeys.erase(j+1); - --j; - } - } - } - - if (ScaleKeys.size()>2) - { - for(u32 j=0;j1) - { - for(u32 j=0;j= ScaleKeys[j+1].frame) //bad frame, unneed and may cause problems - { - ScaleKeys.erase(j+1); - --j; - } - } - } - - if (RotationKeys.size()>2) - { - for(u32 j=0;j1) - { - for(u32 j=0;j= RotationKeys[j+1].frame) //bad frame, unneed and may cause problems - { - RotationKeys.erase(j+1); - --j; - } - } - } - - - //Fill empty keyframe areas - if (PositionKeys.size()) - { - SPositionKey *Key; - Key=&PositionKeys[0];//getFirst - if (Key->frame!=0) - { - PositionKeys.push_front(*Key); - Key=&PositionKeys[0];//getFirst - Key->frame=0; - } - - Key=&PositionKeys.getLast(); - if (Key->frame!=AnimationFrames) - { - PositionKeys.push_back(*Key); - Key=&PositionKeys.getLast(); - Key->frame=AnimationFrames; - } - } - - if (ScaleKeys.size()) - { - SScaleKey *Key; - Key=&ScaleKeys[0];//getFirst - if (Key->frame!=0) - { - ScaleKeys.push_front(*Key); - Key=&ScaleKeys[0];//getFirst - Key->frame=0; - } - - Key=&ScaleKeys.getLast(); - if (Key->frame!=AnimationFrames) - { - ScaleKeys.push_back(*Key); - Key=&ScaleKeys.getLast(); - Key->frame=AnimationFrames; - } - } - - if (RotationKeys.size()) - { - SRotationKey *Key; - Key=&RotationKeys[0];//getFirst - if (Key->frame!=0) - { - RotationKeys.push_front(*Key); - Key=&RotationKeys[0];//getFirst - Key->frame=0; - } - - Key=&RotationKeys.getLast(); - if (Key->frame!=AnimationFrames) - { - RotationKeys.push_back(*Key); - Key=&RotationKeys.getLast(); - Key->frame=AnimationFrames; - } - } - } - } - - //Needed for animation and skinning... - - CalculateGlobalMatrices(0,0); - - //animateMesh(0, 1); - //buildAll_LocalAnimatedMatrices(); - //buildAll_GlobalAnimatedMatrices(); - - //rigid animation for non animated meshes - for (i=0; iAttachedMeshes.size(); ++j) - { - SSkinMeshBuffer* Buffer=(*SkinningBuffers)[ AllJoints[i]->AttachedMeshes[j] ]; - Buffer->Transformation=AllJoints[i]->GlobalAnimatedMatrix; - } - } -} - - -scene::SSkinMeshBuffer *CSkinnedMesh::createBuffer() -{ - scene::SSkinMeshBuffer *buffer=new scene::SSkinMeshBuffer(); - LocalBuffers.push_back(buffer); - return buffer; -} - - -CSkinnedMesh::SJoint *CSkinnedMesh::createJoint(SJoint *parent) -{ - SJoint *joint=new SJoint; - - AllJoints.push_back(joint); - if (!parent) - { - //Add root joints to array in finalize() - } - else - { - //Set parent (Be careful of the mesh loader also setting the parent) - parent->Children.push_back(joint); - } - - return joint; -} - - -CSkinnedMesh::SPositionKey *CSkinnedMesh::createPositionKey(SJoint *joint) -{ - if (!joint) - return 0; - - joint->PositionKeys.push_back(SPositionKey()); - return &joint->PositionKeys.getLast(); -} - - -CSkinnedMesh::SScaleKey *CSkinnedMesh::createScaleKey(SJoint *joint) -{ - if (!joint) - return 0; - - joint->ScaleKeys.push_back(SScaleKey()); - return &joint->ScaleKeys.getLast(); -} - - -CSkinnedMesh::SRotationKey *CSkinnedMesh::createRotationKey(SJoint *joint) -{ - if (!joint) - return 0; - - joint->RotationKeys.push_back(SRotationKey()); - return &joint->RotationKeys.getLast(); -} - - -CSkinnedMesh::SWeight *CSkinnedMesh::createWeight(SJoint *joint) -{ - if (!joint) - return 0; - - joint->Weights.push_back(SWeight()); - return &joint->Weights.getLast(); -} - - -bool CSkinnedMesh::isStatic() -{ - return !HasAnimation; -} - - -void CSkinnedMesh::normalizeWeights() -{ - // note: unsure if weights ids are going to be used. - - // Normalise the weights on bones.... - - u32 i,j; - core::array< core::array > Vertices_TotalWeight; - - for (i=0; i()); - Vertices_TotalWeight[i].set_used(LocalBuffers[i]->getVertexCount()); - } - - for (i=0; iWeights.size(); ++j) - { - if (joint->Weights[j].strength<=0)//Check for invalid weights - { - joint->Weights.erase(j); - --j; - } - else - { - Vertices_TotalWeight[ joint->Weights[j].buffer_id ] [ joint->Weights[j].vertex_id ] += joint->Weights[j].strength; - } - } - } - - for (i=0; iWeights.size(); ++j) - { - const f32 total = Vertices_TotalWeight[ joint->Weights[j].buffer_id ] [ joint->Weights[j].vertex_id ]; - if (total != 0 && total != 1) - joint->Weights[j].strength /= total; - } - } -} - - -void CSkinnedMesh::recoverJointsFromMesh(core::array &JointChildSceneNodes) -{ - for (u32 i=0;isetPosition( joint->LocalAnimatedMatrix.getTranslation() ); - node->setRotation( joint->LocalAnimatedMatrix.getRotationDegrees() ); - - //node->setScale( joint->LocalAnimatedMatrix.getScale() ); - - node->positionHint=joint->positionHint; - node->scaleHint=joint->scaleHint; - node->rotationHint=joint->rotationHint; - - //node->setAbsoluteTransformation(joint->GlobalMatrix); //not going to work - - //Note: This updateAbsolutePosition will not work well if joints are not nested like b3d - //node->updateAbsolutePosition(); - } -} - - -void CSkinnedMesh::transferJointsToMesh(const core::array &JointChildSceneNodes) -{ - for (u32 i=0; iLocalAnimatedMatrix.setTranslation(node->getPosition()); - joint->LocalAnimatedMatrix.setRotationDegrees(node->getRotation()); - - //joint->LocalAnimatedMatrix.setScale( node->getScale() ); - - joint->positionHint=node->positionHint; - joint->scaleHint=node->scaleHint; - joint->rotationHint=node->rotationHint; - - if (node->getSkinningSpace()==EBSS_GLOBAL) - joint->GlobalSkinningSpace=true; - else - joint->GlobalSkinningSpace=false; - } - //Remove cache, temp... - LastAnimatedFrame=-1; - LastSkinnedFrame=-1; -} - - -void CSkinnedMesh::transferOnlyJointsHintsToMesh(const core::array &JointChildSceneNodes) -{ - for (u32 i=0;ipositionHint=node->positionHint; - joint->scaleHint=node->scaleHint; - joint->rotationHint=node->rotationHint; - } -} - - -void CSkinnedMesh::createJoints(core::array &JointChildSceneNodes, - IAnimatedMeshSceneNode* AnimatedMeshSceneNode, - ISceneManager* SceneManager) -{ - u32 i; - - //Create new joints - for (i=0;iName.c_str())); - } - - //Match up parents - for (i=0;iChildren.size();++n) - { - if (parentTest->Children[n]==joint) - { - parentID=j; - break; - } - } - } - } - - if (parentID!=-1) - node->setParent( JointChildSceneNodes[parentID] ); - else - node->setParent( AnimatedMeshSceneNode ); - - node->drop(); - } -} - - -void CSkinnedMesh::convertMeshToTangents() -{ - // now calculate tangents - for (u32 b=0; b < LocalBuffers.size(); ++b) - { - if (LocalBuffers[b]) - { - LocalBuffers[b]->MoveTo_Tangents(); - - const s32 idxCnt = LocalBuffers[b]->getIndexCount(); - - u16* idx = LocalBuffers[b]->getIndices(); - video::S3DVertexTangents* v = - (video::S3DVertexTangents*)LocalBuffers[b]->getVertices(); - - for (s32 i=0; igetSceneManager()->addAnimatedMeshSceneNode(m); - animModel->setAnimationSpeed(30); + animModel->setAnimationSpeed(1000); + animModel->setFrameLoop(3333,4333); Model = animModel; } Model->setMaterialFlag(video::EMF_LIGHTING, true); // Model->setMaterialFlag(video::EMF_BACK_FACE_CULLING, false); 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 // 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); - if (menu) - for(int item = 1; item < 6; ++item) - menu->setItemChecked(item, false); + for(int id = GUI_ID_DEBUG_BOUNDING_BOX; id <= GUI_ID_DEBUG_WIRE_OVERLAY; ++id) + ((IGUICheckBox*)Device->getGUIEnvironment()->getRootGUIElement()->getElementFromId(id,true))->setChecked(false); IGUIElement* toolboxWnd = Device->getGUIEnvironment()->getRootGUIElement()->getElementFromId(GUI_ID_DIALOG_ROOT_WINDOW, true); 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_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(22,142,130,156),t3,GUI_ID_LIGHT_VISIBLE,L"Visible"); env->addButton(core::rect(10,164,85,185), t3, GUI_ID_LIGHT_SET, L"Set"); + IGUITab* t4 = tab->addTab(L"Debug"); + env->addCheckBox(false, core::rect(22,48,130,68),t4,GUI_ID_DEBUG_BOUNDING_BOX,L"BBox"); + env->addCheckBox(false, core::rect(22,78,130,98),t4,GUI_ID_DEBUG_BUFFERS_BOUNDING_BOXES,L"Buffers BBoxes"); + env->addCheckBox(false, core::rect(22,108,130,128),t4,GUI_ID_DEBUG_HALF_TRANSPARENT,L"Half Transparent"); + env->addCheckBox(false, core::rect(22,138,130,158),t4,GUI_ID_DEBUG_NORMALS,L"Normals"); + env->addCheckBox(false, core::rect(22,168,130,188),t4,GUI_ID_DEBUG_SKELETON,L"Skeleton"); + env->addCheckBox(false, core::rect(22,198,130,218),t4,GUI_ID_DEBUG_WIRE_OVERLAY,L"Wire Overlay"); + env->addStaticText(L"Start:", core::rect(22,228,40,248), false, false, t4); + env->addEditBox(L"0", core::rect(40,248,130,268), true, t4, GUI_ID_FRAME_START); + env->addStaticText(L"End:", core::rect(22,268,40,288), false, false, t4); + env->addEditBox(L"0", core::rect(40,288,130,308), true, t4, GUI_ID_FRAME_END); + env->addButton(core::rect(10,318,85,338), t4, GUI_ID_FRAME_SET, L"Set"); + // bring irrlicht engine logo to front, because it // now may be below the newly created toolbox root->bringToFront(root->getElementFromId(666, true)); @@ -344,6 +367,38 @@ public: scene::ISceneManager* smgr = Device->getSceneManager(); 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: { // a menu item was clicked @@ -370,56 +425,6 @@ public: menu->setItemChecked(menu->getSelectedItem(), !menu->isItemChecked(menu->getSelectedItem())); SkyBox->setVisible(!SkyBox->isVisible()); 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 if (Model) Model->setMaterialType(video::EMT_SOLID); @@ -450,6 +455,7 @@ public: IGUIFileOpenDialog* dialog = (IGUIFileOpenDialog*)event.GUIEvent.Caller; loadModel(core::stringc(dialog->getFileName()).c_str()); + StartUpModelFile=core::stringc(dialog->getFileName()).c_str(); } break; @@ -577,6 +583,7 @@ public: env->addFileOpenDialog(L"Please select your game archive/directory"); break; case GUI_ID_LIGHT_SET: + { scene::ISceneNode* light; 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())); light->setPosition(lpos); 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; @@ -628,8 +641,23 @@ resizeable, which is quite useful for a mesh viewer. */ 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; printf("Please select the driver you want for this example:\n"\ @@ -650,7 +678,7 @@ int main(int argc, char* argv[]) case 'f': driverType = video::EDT_NULL; break; default: return 1; } - + // create device and exit if creation failed MyEventReceiver receiver; @@ -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"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->addItem(L"Solid", GUI_ID_MODEL_MATERIAL_SOLID); submenu->addItem(L"Transparent", GUI_ID_MODEL_MATERIAL_TRANSPARENT); @@ -813,7 +831,8 @@ int main(int argc, char* argv[]) // show about message box and load default model // if (argc==1) // showAboutText(); - loadModel(StartUpModelFile.c_str()); + if(StartUpModelFile.c_str()!="") + loadModel(StartUpModelFile.c_str()); // add skybox @@ -832,7 +851,7 @@ int main(int argc, char* argv[]) // where the mesh scene node is placed. 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]->setPosition(core::vector3df(0,0,-70)); 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)); - smgr->drawAll(); - video::SMaterial m2; - m2.Lighting = false; - driver->setMaterial(m2); - driver->draw3DLine(core::vector3df(0,0,0),core::vector3df(100,0,0),video::SColor(255,255,0,0)); - driver->draw3DLine(core::vector3df(0,0,0),core::vector3df(0,100,0),video::SColor(255,0,255,0)); - driver->draw3DLine(core::vector3df(0,0,0),core::vector3df(0,0,100),video::SColor(255,0,0,255)); + + video::SMaterial m; + m.Lighting = false; + driver->setMaterial(m); + driver->setTransform(video::ETS_WORLD, core::matrix4()); + 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(); driver->endScene(); @@ -872,8 +894,11 @@ int main(int argc, char* argv[]) str.append(core::stringw(driver->getFPS())); str += L" Tris: "; str.append(core::stringw(driver->getPrimitiveCountDrawn())); + str += L" Frame: "; + if(Model) + str.append(core::stringw(((scene::IAnimatedMeshSceneNode*)Model)->getFrameNr())); fpstext->setText(str.c_str()); - + scene::ICameraSceneNode* cam = Device->getSceneManager()->getActiveCamera(); str = L"Pos: "; str.append(core::stringw(cam->getPosition().X)); @@ -893,7 +918,8 @@ int main(int argc, char* argv[]) else Device->yield(); } - + + Device->drop(); return 0; }