diff --git a/binaries/data/mods/_test.minimal/art/textures/terrain/types/whiteness.dds b/binaries/data/mods/_test.minimal/art/textures/terrain/types/whiteness.dds new file mode 100644 index 0000000000..e411424429 --- /dev/null +++ b/binaries/data/mods/_test.minimal/art/textures/terrain/types/whiteness.dds @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:51512ce9e0d3893ae5457780f103c67860216ff7fa3c4f8976b511f359970260 +size 136 diff --git a/source/collada/Converter.cpp b/source/collada/Converter.cpp index 4d7b13bd2b..24005e2aaa 100644 --- a/source/collada/Converter.cpp +++ b/source/collada/Converter.cpp @@ -55,7 +55,6 @@ struct BoneTransform { float translation[3]; float orientation[4]; - FMMatrix44 matrix; // not output in the PMD, but useful for calculating bone transforms }; @@ -146,11 +145,7 @@ public: FCDGeometryPolygons* polys = GetPolysFromGeometry((FCDGeometry*)baseTarget); // Make sure it doesn't use more bones per vertex than the game can handle -// SkinReduceInfluences(skin, maxInfluences, 0.001f); - - // XXX The game is broken if there's >1 influence per vertex. Until - // that's fixed, just limit it to 1 and put up with the ugly blending... - SkinReduceInfluences(skin, 1, 0.001f); + SkinReduceInfluences(skin, maxInfluences, 0.001f); // Convert the bone influences into VertexBlend structures for the PMD @@ -207,8 +202,7 @@ public: BoneTransform b = { { parts.t.x, parts.t.y, parts.t.z }, - { parts.q.x, parts.q.y, parts.q.z, parts.q.w }, - bindPose + { parts.q.x, parts.q.y, parts.q.z, parts.q.w } }; int boneId = StdSkeletons::FindStandardBoneID(joint->joint->GetName()); @@ -231,7 +225,7 @@ public: assert(normal.size() == vertices*3); assert(texcoord.size() == vertices*2); - TransformVertices(position, normal, blends, bones, transform); + TransformVertices(position, normal, bones, transform); WritePMD(output, vertices, bones.size(), &position[0], &normal[0], &texcoord[0], &blends[0], &bones[0]); } @@ -257,7 +251,7 @@ public: if (boneCount) assert(boneWeights && boneTransforms); output("PSMD", 4); // magic number - write(output, 2); // version number + write(output, 3); // version number write(output, (uint32)( 4 + 13*4*vertexCount + // vertices 4 + 6*vertexCount/3 + // faces @@ -364,52 +358,17 @@ public: } } - static void TransformVertices(FloatList& position, FloatList& normal, std::vector& blends, std::vector& bones, const FMMatrix44& transform) + static void TransformVertices(FloatList& position, FloatList& normal, std::vector& bones, const FMMatrix44& transform) { for (size_t vtxId = 0; vtxId < position.size()/3; ++vtxId) { - // Skinned vertices need to be transformed by the inverse of their - // rest states: - - float zero16[16] = {0}; - FMMatrix44 bindPoseTransform (zero16); - - // Calculate the weighted sum of influence matrices - for (size_t j = 0; j < maxInfluences; ++j) - { - // Ignore unused bone influences - if (blends[vtxId].bones[j] == 0xff) - continue; - - float weight = blends[vtxId].weights[j]; - const BoneTransform& b = bones[blends[vtxId].bones[j]]; - - // The transformation matrix could be reconstructed with: - /* - FMMatrix44 R = QuatToMatrix(b.orientation[0], b.orientation[1], b.orientation[2], b.orientation[3]); - FMMatrix44 T = FMMatrix44::TranslationMatrix(FMVector3(b.translation, 0)); - FMMatrix44 boneMatrix = T * R; - */ - // but since we generated orientation/translation from a matrix, - // just use that matrix directly: - FMMatrix44 boneMatrix = b.matrix; - - bindPoseTransform = bindPoseTransform + weight * boneMatrix; - } - FMVector3 pos (&position[vtxId*3], 0); FMVector3 norm (&normal[vtxId*3], 0); - // Apply the scene-node transforms first + // Apply the scene-node transforms pos = transform.TransformCoordinate(pos); norm = transform.TransformVector(norm).Normalize(); - // Apply the inverse bind pose transform, so the model will display - // correctly after it's been transform back again - FMMatrix44 bindPoseTransformInverse = bindPoseTransform.Inverted(); - pos = bindPoseTransformInverse.TransformCoordinate(pos); - norm = bindPoseTransformInverse.TransformVector(norm); - // Switch from Max's coordinate system into the game's: std::swap(pos.y, pos.z); diff --git a/source/graphics/Model.cpp b/source/graphics/Model.cpp index b074ddd727..8415dae985 100644 --- a/source/graphics/Model.cpp +++ b/source/graphics/Model.cpp @@ -27,9 +27,9 @@ ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // Constructor CModel::CModel() - : m_Parent(0), m_Flags(0), m_Anim(0), m_AnimTime(0), - m_BoneMatrices(0), m_InvTranspBoneMatrices(0), - m_PositionValid(false), m_InvTranspValid(false), m_ShadingColor(1,1,1,1) + : m_Parent(NULL), m_Flags(0), m_Anim(NULL), m_AnimTime(0), + m_BoneMatrices(NULL), m_InverseBindBoneMatrices(NULL), + m_PositionValid(false), m_ShadingColor(1,1,1,1) { } @@ -62,8 +62,9 @@ CModel::~CModel() void CModel::ReleaseData() { delete[] m_BoneMatrices; - delete[] m_InvTranspBoneMatrices; - for (size_t i=0;im_Parent = 0; delete m_Props[i].m_Model; } @@ -84,19 +85,24 @@ bool CModel::InitModel(CModelDefPtr modeldef) m_pModelDef = modeldef; - size_t numBones=modeldef->GetNumBones(); - if (numBones != 0) { + size_t numBones = modeldef->GetNumBones(); + if (numBones != 0) + { // allocate matrices for bone transformations - m_BoneMatrices=new CMatrix3D[numBones]; - m_InvTranspBoneMatrices=new CMatrix3D[numBones]; + m_BoneMatrices = new CMatrix3D[numBones]; + m_InverseBindBoneMatrices = new CMatrix3D[numBones]; + // store default pose until animation assigned - CBoneState* defpose=modeldef->GetBones(); - for (uint i=0;iGetBones(); + for (size_t i = 0; i < numBones; ++i) + { + m_BoneMatrices[i].SetIdentity(); + m_BoneMatrices[i].Rotate(defpose[i].m_Rotation); + m_BoneMatrices[i].Translate(defpose[i].m_Translation); + + m_InverseBindBoneMatrices[i].SetIdentity(); + m_InverseBindBoneMatrices[i].Translate(-defpose[i].m_Translation); + m_InverseBindBoneMatrices[i].Rotate(defpose[i].m_Rotation.GetInverse()); } } @@ -106,33 +112,6 @@ bool CModel::InitModel(CModelDefPtr modeldef) } -///////////////////////////////////////////////////////////////////////////////////////////////////////////// -// SkinPoint: skin the given point using the given blend and matrix data -static CVector3D SkinPoint(const CVector3D& pos, const SVertexBlend& blend, - const CMatrix3D* bonestates) -{ - CVector3D result,tmp; - - // must have at least one valid bone if we're using SkinPoint - if (blend.m_Bone[0] == 0xff) - { - ONCE( debug_warn("SkinPoint called for vertex with no bone weights") ); - return CVector3D(0, 0, 0); - } - - const CMatrix3D& m = bonestates[blend.m_Bone[0]]; - m.Transform(pos, result); - result *= blend.m_Weight[0]; - - for (int i = 1; i < SVertexBlend::SIZE && blend.m_Bone[i] != 0xff; i++) { - const CMatrix3D& m = bonestates[blend.m_Bone[i]]; - m.Transform(pos, tmp); - result += tmp*blend.m_Weight[i]; - } - - return result; -} - ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // CalcBound: calculate the world space bounds of this model void CModel::CalcBounds() @@ -203,10 +182,10 @@ void CModel::CalcAnimatedObjectBound(CSkeletonAnimDef* anim,CBound& result) ValidatePosition(); // extend bounds by vertex positions at the frame - for (size_t i=0;iGetFrameTime(); } @@ -322,7 +301,6 @@ void CModel::ValidatePosition() } m_PositionValid = true; - m_InvTranspValid = false; // re-position and validate all props for (size_t j = 0; j < m_Props.size(); ++j) @@ -341,24 +319,6 @@ void CModel::ValidatePosition() } -///////////////////////////////////////////////////////////////////////////////////////////////////////////// -// CalcInvTranspBoneMatrices -void CModel::CalcInvTranspBoneMatrices() -{ - debug_assert(m_BoneMatrices); - - PROFILE( "invert transpose bone matrices" ); - - CMatrix3D tmp; - for(size_t i = 0; i < m_pModelDef->GetNumBones(); ++i) - { - m_BoneMatrices[i].GetInverse(tmp); - tmp.GetTranspose(m_InvTranspBoneMatrices[i]); - } - - m_InvTranspValid = true; -} - ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // SetAnimation: set the given animation as the current animation on this model; // return false on error, else true diff --git a/source/graphics/Model.h b/source/graphics/Model.h index 258e57ccea..31f3a1bad6 100644 --- a/source/graphics/Model.h +++ b/source/graphics/Model.h @@ -101,24 +101,26 @@ public: void CalcAnimatedObjectBound(CSkeletonAnimDef* anim,CBound& result); /** - * SetTransform: Set transform of this object. + * Set transform of this object. * * @note In order to ensure that all child props are updated properly, * you must call ValidatePosition(). */ void SetTransform(const CMatrix3D& transform); + /** + * Return whether this is a skinned/skeletal model. If it is, Get*BoneMatrices() + * will return valid non-NULL arrays. + */ + bool IsSkinned() { return (m_BoneMatrices != NULL); } + // return the models bone matrices - const CMatrix3D* GetBoneMatrices() { + const CMatrix3D* GetAnimatedBoneMatrices() { debug_assert(m_PositionValid); return m_BoneMatrices; } - // return the models inverted transposed bone matrices for normal transformation - const CMatrix3D* GetInvTranspBoneMatrices() { - debug_assert(m_PositionValid); - if (!m_InvTranspValid) - CalcInvTranspBoneMatrices(); - return m_InvTranspBoneMatrices; + const CMatrix3D* GetInverseBindBoneMatrices() { + return m_InverseBindBoneMatrices; } // load raw animation frame animation from given file, and build a @@ -137,7 +139,7 @@ public: CModel* Clone() const; /** - * ValidatePosition: Ensure that both the transformation and the bone + * Ensure that both the transformation and the bone * matrices are correct for this model and all its props. */ void ValidatePosition(); @@ -147,19 +149,13 @@ private: void ReleaseData(); /** - * InvalidatePosition: Mark this model's position and bone matrices, + * Mark this model's position and bone matrices, * and all props' positions as invalid. */ void InvalidatePosition(); /** - * CalcInvTranspBoneMatrices: Calc inverse transpose bone matrices - * from bone matrices. - */ - void CalcInvTranspBoneMatrices(); - - /** - * m_Parent: If non-null, m_Parent points to the model that we + * If non-null, m_Parent points to the model that we * are attached to. */ CModel* m_Parent; @@ -186,23 +182,16 @@ private: float m_AnimTime; // current state of all bones on this model; null if associated modeldef isn't skeletal CMatrix3D* m_BoneMatrices; - // inverse of the transpose of the above matrices - CMatrix3D* m_InvTranspBoneMatrices; + // inverse matrices for the bind pose's bones; null if not skeletal + CMatrix3D* m_InverseBindBoneMatrices; // list of current props on model std::vector m_Props; /** - * m_PositionValid: true if both transform and and bone matrices - * are valid. + * true if both transform and and bone matrices are valid. */ bool m_PositionValid; - /** - * m_InvTranspValid: true if m_InvTranspBoneMatrices match the current - * m_BoneMatrices - */ - bool m_InvTranspValid; - // modulating color CColor m_ShadingColor; }; diff --git a/source/graphics/ModelDef.cpp b/source/graphics/ModelDef.cpp index 3939c299f6..edaca38cd5 100644 --- a/source/graphics/ModelDef.cpp +++ b/source/graphics/ModelDef.cpp @@ -9,9 +9,73 @@ #include "precompiled.h" #include "ModelDef.h" +#include "graphics/SkeletonAnimDef.h" #include "ps/FilePacker.h" #include "ps/FileUnpacker.h" +#include "maths/Vector4D.h" +CVector3D CModelDef::SkinPoint(const SModelVertex& vtx, + const CMatrix3D newPoseMatrices[], + const CMatrix3D inverseBindMatrices[]) +{ + CVector3D result (0, 0, 0); + + for (int i = 0; i < SVertexBlend::SIZE && vtx.m_Blend.m_Bone[i] != 0xff; ++i) + { + CVector3D bindSpace = inverseBindMatrices[vtx.m_Blend.m_Bone[i]].Transform(vtx.m_Coords); + CVector3D worldSpace = newPoseMatrices[vtx.m_Blend.m_Bone[i]].Transform(bindSpace); + result += worldSpace * vtx.m_Blend.m_Weight[i]; + } + + return result; +} + +CVector3D CModelDef::SkinNormal(const SModelVertex& vtx, + const CMatrix3D newPoseMatrices[], + const CMatrix3D inverseBindMatrices[]) +{ + // To be correct, the normal vectors apparently need to be multiplied by the + // inverse of the transpose. Unfortunately inverses are slow. + // If a matrix is orthogonal, M * M^T = I and so the inverse of the transpose + // is the original matrix. But that's not entirely relevant here, because + // the cone matrices include translation components and so they're not + // orthogonal. + // But that's okay because we have + // M = T * R + // and want to find + // n' = (M^T^-1) * n + // = (T * R)^T^-1 * n + // = (R^T * T^T)^-1 * n + // = (T^T^-1 * R^T^-1) * n + // R is indeed orthogonal so R^T^-1 = R. T isn't orthogonal at all. + // But n is only a 3-vector, and from the forms of T and R (which have + // lots of zeroes) I can convince myself that replacing T with T^T^-1 has no + // effect on anything but the fourth component of M^T^-1 - and the fourth + // component is discarded since it has no effect on n', and so we can happily + // use n' = M*n. + // + // (This isn't very good as a proof, but it's better than assuming M is + // orthogonal when it's clearly not.) + + CVector3D result (0, 0, 0); + + for (int i = 0; i < SVertexBlend::SIZE && vtx.m_Blend.m_Bone[i] != 0xff; ++i) + { + CVector3D bindSpace = inverseBindMatrices[vtx.m_Blend.m_Bone[i]].Rotate(vtx.m_Norm); + CVector3D worldSpace = newPoseMatrices[vtx.m_Blend.m_Bone[i]].Rotate(bindSpace); + result += worldSpace * vtx.m_Blend.m_Weight[i]; + } + + // If there was more than one influence, the result is probably not going + // to be of unit length (since it's a weighted sum of several independent + // unit vectors), so we need to normalise it. + // (It's fairly common to only have one influence, so it seems sensible to + // optimise that case a bit.) + if (vtx.m_Blend.m_Bone[1] != 0xff) // if more than one influence + result.Normalize(); + + return result; +} /////////////////////////////////////////////////////////////////////////////// // CModelDef Constructor @@ -38,11 +102,10 @@ CModelDef::~CModelDef() // return null if no match (case insensitive search) SPropPoint* CModelDef::FindPropPoint(const char* name) const { - for (uint i=0;i mdef (new CModelDef); mdef->m_Name = filename; - try { - // now unpack everything - unpacker.UnpackRaw(&mdef->m_NumVertices,sizeof(mdef->m_NumVertices)); - mdef->m_pVertices=new SModelVertex[mdef->m_NumVertices]; - unpacker.UnpackRaw(mdef->m_pVertices,sizeof(SModelVertex)*mdef->m_NumVertices); - - unpacker.UnpackRaw(&mdef->m_NumFaces,sizeof(mdef->m_NumFaces)); - mdef->m_pFaces=new SModelFace[mdef->m_NumFaces]; - unpacker.UnpackRaw(mdef->m_pFaces,sizeof(SModelFace)*mdef->m_NumFaces); - - unpacker.UnpackRaw(&mdef->m_NumBones,sizeof(mdef->m_NumBones)); - if (mdef->m_NumBones) { - mdef->m_Bones=new CBoneState[mdef->m_NumBones]; - unpacker.UnpackRaw(mdef->m_Bones,mdef->m_NumBones*sizeof(CBoneState)); - } - - if (unpacker.GetVersion()>=2) { - // versions >=2 also have prop point data - unpacker.UnpackRaw(&mdef->m_NumPropPoints,sizeof(mdef->m_NumPropPoints)); - if (mdef->m_NumPropPoints) { - mdef->m_PropPoints=new SPropPoint[mdef->m_NumPropPoints]; - for (u32 i=0;im_NumPropPoints;i++) { - unpacker.UnpackString(mdef->m_PropPoints[i].m_Name); - unpacker.UnpackRaw(&mdef->m_PropPoints[i].m_Position.X,sizeof(mdef->m_PropPoints[i].m_Position)); - unpacker.UnpackRaw(&mdef->m_PropPoints[i].m_Rotation.m_V.X,sizeof(mdef->m_PropPoints[i].m_Rotation)); - unpacker.UnpackRaw(&mdef->m_PropPoints[i].m_BoneIndex,sizeof(mdef->m_PropPoints[i].m_BoneIndex)); - - // build prop point transform - mdef->m_PropPoints[i].m_Transform.SetIdentity(); - mdef->m_PropPoints[i].m_Transform.Rotate(mdef->m_PropPoints[i].m_Rotation); - mdef->m_PropPoints[i].m_Transform.Translate(mdef->m_PropPoints[i].m_Position); - } - } - } - } catch (PSERROR_File_UnexpectedEOF&) { - delete mdef; - throw; + // now unpack everything + unpacker.UnpackRaw(&mdef->m_NumVertices,sizeof(mdef->m_NumVertices)); + mdef->m_pVertices=new SModelVertex[mdef->m_NumVertices]; + unpacker.UnpackRaw(mdef->m_pVertices,sizeof(SModelVertex)*mdef->m_NumVertices); + + unpacker.UnpackRaw(&mdef->m_NumFaces,sizeof(mdef->m_NumFaces)); + mdef->m_pFaces=new SModelFace[mdef->m_NumFaces]; + unpacker.UnpackRaw(mdef->m_pFaces,sizeof(SModelFace)*mdef->m_NumFaces); + + unpacker.UnpackRaw(&mdef->m_NumBones,sizeof(mdef->m_NumBones)); + if (mdef->m_NumBones) + { + mdef->m_Bones=new CBoneState[mdef->m_NumBones]; + unpacker.UnpackRaw(mdef->m_Bones,mdef->m_NumBones*sizeof(CBoneState)); } - return mdef; + if (unpacker.GetVersion() >= 2) + { + // versions >=2 also have prop point data + unpacker.UnpackRaw(&mdef->m_NumPropPoints,sizeof(mdef->m_NumPropPoints)); + if (mdef->m_NumPropPoints) { + mdef->m_PropPoints=new SPropPoint[mdef->m_NumPropPoints]; + for (u32 i=0;im_NumPropPoints;i++) { + unpacker.UnpackString(mdef->m_PropPoints[i].m_Name); + unpacker.UnpackRaw(&mdef->m_PropPoints[i].m_Position.X,sizeof(mdef->m_PropPoints[i].m_Position)); + unpacker.UnpackRaw(&mdef->m_PropPoints[i].m_Rotation.m_V.X,sizeof(mdef->m_PropPoints[i].m_Rotation)); + unpacker.UnpackRaw(&mdef->m_PropPoints[i].m_BoneIndex,sizeof(mdef->m_PropPoints[i].m_BoneIndex)); + + // build prop point transform + mdef->m_PropPoints[i].m_Transform.SetIdentity(); + mdef->m_PropPoints[i].m_Transform.Rotate(mdef->m_PropPoints[i].m_Rotation); + mdef->m_PropPoints[i].m_Transform.Translate(mdef->m_PropPoints[i].m_Position); + } + } + } + + if (unpacker.GetVersion() <= 2) + { + // Versions <=2 store the vertexes relative to the bind pose. That + // isn't useful when you want to do correct skinning, so later versions + // store them in world space. So, fix the old models by skinning each + // vertex: + + if (mdef->m_NumBones) // only do skinned models + { + CMatrix3D identity; + identity.SetIdentity(); + std::vector identityBones (mdef->m_NumBones, identity); + + std::vector bindPose (mdef->m_NumBones); + + for (u32 i = 0; i < mdef->m_NumBones; ++i) + { + bindPose[i].SetIdentity(); + bindPose[i].Rotate(mdef->m_Bones[i].m_Rotation); + bindPose[i].Translate(mdef->m_Bones[i].m_Translation); + } + + for (u32 i = 0; i < mdef->m_NumVertices; ++i) + { + mdef->m_pVertices[i].m_Coords = SkinPoint(mdef->m_pVertices[i], &bindPose[0], &identityBones[0]); + mdef->m_pVertices[i].m_Norm = SkinNormal(mdef->m_pVertices[i], &bindPose[0], &identityBones[0]); + } + } + } + + return mdef.release(); } /////////////////////////////////////////////////////////////////////////////// @@ -137,7 +227,6 @@ void CModelDef::Save(const char* filename,const CModelDef* mdef) packer.Write(filename); } - /////////////////////////////////////////////////////////////////////////////// // SetRenderData: Set the render data object for the given key, void CModelDef::SetRenderData(const void* key, CModelDefRPrivate* data) diff --git a/source/graphics/ModelDef.h b/source/graphics/ModelDef.h index be7ecdb80e..9c7c16b713 100644 --- a/source/graphics/ModelDef.h +++ b/source/graphics/ModelDef.h @@ -11,13 +11,12 @@ #include "ps/CStr.h" #include "maths/Vector3D.h" -#include "MeshManager.h" -#include "SkeletonAnimDef.h" +#include "maths/Quaternion.h" #include -#include class CMeshManager; class CModelDef; +class CBoneState; /////////////////////////////////////////////////////////////////////////////// // SPropPoint: structure describing a prop point @@ -89,7 +88,7 @@ class CModelDef friend class CMeshManager; public: // current file version given to saved animations - enum { FILE_VERSION = 2 }; + enum { FILE_VERSION = 3 }; // supported file read version - files with a version less than this will be rejected enum { FILE_READ_VERSION = 1 }; @@ -101,7 +100,7 @@ public: virtual ~CModelDef(); // model I/O functions - static void Save(const char* filename,const CModelDef* mdef); + static void Save(const char* filename,const CModelDef* mdef); public: // accessor: get vertex data @@ -116,7 +115,6 @@ public: size_t GetNumBones() const { return (size_t)m_NumBones; } CBoneState* GetBones() const { return m_Bones; } - // accessor: get prop data int GetNumPropPoints() const { return m_NumPropPoints; } SPropPoint* GetPropPoints() const { return m_PropPoints; } @@ -126,7 +124,23 @@ public: SPropPoint* FindPropPoint(const char* name) const; /** - * SetRenderData: Register renderer private data. Use the key to + * Transform the given vertex's position from the bind pose into the new pose. + * + * @return new world-space vertex coordinates + */ + static CVector3D SkinPoint(const SModelVertex& vtx, + const CMatrix3D newPoseMatrices[], const CMatrix3D inverseBindMatrices[]); + + /** + * Transform the given vertex's normal from the bind pose into the new pose. + * + * @return new world-space vertex normal + */ + static CVector3D SkinNormal(const SModelVertex& vtx, + const CMatrix3D newPoseMatrices[], const CMatrix3D inverseBindMatrices[]); + + /** + * Register renderer private data. Use the key to * distinguish between private data used by different render paths. * The private data will be managed by this CModelDef object: * It will be deleted when CModelDef is destructed or when private diff --git a/source/gui/MiniMap.cpp b/source/gui/MiniMap.cpp index 87fcc8b83e..2aa8097569 100644 --- a/source/gui/MiniMap.cpp +++ b/source/gui/MiniMap.cpp @@ -2,18 +2,17 @@ #include +#include "MiniMap.h" + #include "graphics/GameView.h" #include "graphics/MiniPatch.h" -#include "graphics/Model.h" #include "graphics/Terrain.h" #include "graphics/TextureEntry.h" #include "graphics/TextureManager.h" #include "graphics/Unit.h" #include "graphics/UnitManager.h" -#include "gui/MiniMap.h" #include "lib/ogl.h" #include "lib/sdl.h" -#include "maths/Bound.h" #include "ps/Game.h" #include "ps/Interact.h" #include "network/NetMessage.h" diff --git a/source/gui/MiniMap.h b/source/gui/MiniMap.h index 2c6b932d1a..6db6efb217 100644 --- a/source/gui/MiniMap.h +++ b/source/gui/MiniMap.h @@ -2,9 +2,10 @@ #define __H_MINIMAP_H__ #include "gui/GUI.h" -#include "ps/Vector2D.h" -#include "maths/Vector3D.h" -#include "graphics/Camera.h" + +class CVector2D; +class CVector3D; +class CCamera; class CTerrain; class CUnitManager; diff --git a/source/lib/res/graphics/tex_dds.cpp b/source/lib/res/graphics/tex_dds.cpp index 292a36ad96..97c4fa12ea 100644 --- a/source/lib/res/graphics/tex_dds.cpp +++ b/source/lib/res/graphics/tex_dds.cpp @@ -517,16 +517,28 @@ static LibError decode_sd(const DDSURFACEDESC2* sd, uint* w_, uint* h_, // image dimensions const u32 h = read_le32(&sd->dwHeight); const u32 w = read_le32(&sd->dwWidth); - // .. not padded to S3TC block size - if(w % 4 || h % 4) - WARN_RETURN(ERR::TEX_INVALID_SIZE); // pixel format uint bpp, flags; RETURN_ERR(decode_pf(&sd->ddpfPixelFormat, &bpp, &flags)); + // if the image is not aligned with the S3TC block size, it is stored + // with extra pixels on the bottom left to fill up the space, so we need + // to account for those when calculating how big it should be + u32 stored_h, stored_w; + if(flags & TEX_DXT) + { + stored_h = round_up(h, 4); + stored_w = round_up(w, 4); + } + else + { + stored_h = h; + stored_w = w; + } + // verify pitch or linear size, if given - const size_t pitch = w*bpp/8; + const size_t pitch = stored_w*bpp/8; const u32 sd_pitch_or_size = read_le32(&sd->dwPitchOrLinearSize); if(sd_flags & DDSD_PITCH) { @@ -535,7 +547,7 @@ static LibError decode_sd(const DDSURFACEDESC2* sd, uint* w_, uint* h_, } if(sd_flags & DDSD_LINEARSIZE) { - if(sd_pitch_or_size != pitch*h) + if(sd_pitch_or_size != pitch*stored_h) WARN_RETURN(ERR::CORRUPTED); } // note: both flags set would be invalid; no need to check for that, diff --git a/source/maths/Matrix3D.cpp b/source/maths/Matrix3D.cpp index 00c77bd692..eff279d52d 100644 --- a/source/maths/Matrix3D.cpp +++ b/source/maths/Matrix3D.cpp @@ -13,6 +13,7 @@ #include "Matrix3D.h" #include "Quaternion.h" +#include "Vector4D.h" CMatrix3D::CMatrix3D () { @@ -262,8 +263,10 @@ void CMatrix3D::Scale (float x_scale, float y_scale, float z_scale) //Returns the transpose of the matrix. For orthonormal //matrices, this is the same is the inverse matrix -void CMatrix3D::GetTranspose(CMatrix3D& result) const +CMatrix3D CMatrix3D::GetTranspose() const { + CMatrix3D result; + result._11 = _11; result._21 = _12; result._31 = _13; @@ -283,6 +286,8 @@ void CMatrix3D::GetTranspose(CMatrix3D& result) const result._24 = _42; result._34 = _43; result._44 = _44; + + return result; } @@ -474,6 +479,13 @@ void CMatrix3D::GetInverse(CMatrix3D& dst) const } } +CMatrix3D CMatrix3D::GetInverse() const +{ + CMatrix3D r; + GetInverse(r); + return r; +} + void CMatrix3D::Rotate(const CQuaternion& quat) { CMatrix3D rotationMatrix=quat.ToMatrix(); diff --git a/source/maths/Matrix3D.h b/source/maths/Matrix3D.h index 3916ac88e0..5b9e197fe1 100644 --- a/source/maths/Matrix3D.h +++ b/source/maths/Matrix3D.h @@ -1,10 +1,8 @@ #ifndef __MATRIX3D_H #define __MATRIX3D_H -#include -#include "Vector3D.h" -#include "Vector4D.h" - +class CVector3D; +class CVector4D; class CQuaternion; ///////////////////////////////////////////////////////////////////////// @@ -97,8 +95,11 @@ public: // calculate the inverse of this matrix, store in dst void GetInverse(CMatrix3D& dst) const; + // return the inverse of this matrix + CMatrix3D GetInverse() const; + // calculate the transpose of this matrix, store in dst - void GetTranspose(CMatrix3D& dst) const; + CMatrix3D GetTranspose() const; // return the translation component of this matrix CVector3D GetTranslation() const; diff --git a/source/maths/Quaternion.cpp b/source/maths/Quaternion.cpp index 63ecb1cd55..3024e69e03 100644 --- a/source/maths/Quaternion.cpp +++ b/source/maths/Quaternion.cpp @@ -130,26 +130,21 @@ CMatrix3D CQuaternion::ToMatrix () const void CQuaternion::ToMatrix(CMatrix3D& result) const { - float x2, y2, z2; float wx, wy, wz, xx, xy, xz, yy, yz, zz; // calculate coefficients - x2 = m_V.X + m_V.X; - y2 = m_V.Y + m_V.Y; - z2 = m_V.Z + m_V.Z; - - xx = m_V.X * x2; - xy = m_V.X * y2; - xz = m_V.X * z2; + xx = m_V.X * m_V.X * 2.f; + xy = m_V.X * m_V.Y * 2.f; + xz = m_V.X * m_V.Z * 2.f; - yy = m_V.Y * y2; - yz = m_V.Y * z2; + yy = m_V.Y * m_V.Y * 2.f; + yz = m_V.Y * m_V.Z * 2.f; - zz = m_V.Z * z2; + zz = m_V.Z * m_V.Z * 2.f; - wx = m_W * x2; - wy = m_W * y2; - wz = m_W * z2; + wx = m_W * m_V.X * 2.f; + wy = m_W * m_V.Y * 2.f; + wz = m_W * m_V.Z * 2.f; result._11 = 1.0f - (yy + zz); result._12 = xy - wz; @@ -277,6 +272,8 @@ CVector3D CQuaternion::Rotate(const CVector3D& vec) const CQuaternion CQuaternion::GetInverse() const { - float lensqrd = SQR(m_V.X) + SQR(m_V.Y) + SQR(m_V.Z) + SQR(m_W); - return CQuaternion(-m_V.X/lensqrd, -m_V.Y/lensqrd, -m_V.Z/lensqrd, m_W/lensqrd); + // (x,y,z,w)^-1 = (-x/l^2, -y/l^2, -z/l^2, w/l^2) where l^2=x^2+y^2+z^2+w^2 + // Since we're only using quaternions for rotation, they should always have unit + // length, so assume l=1 + return CQuaternion(-m_V.X, -m_V.Y, -m_V.Z, m_W); } diff --git a/source/maths/Quaternion.h b/source/maths/Quaternion.h index d1dc936819..4a09667ea1 100644 --- a/source/maths/Quaternion.h +++ b/source/maths/Quaternion.h @@ -22,39 +22,39 @@ public: CQuaternion(); CQuaternion(float x, float y, float z, float w); - //quaternion addition + // Quaternion addition CQuaternion operator + (const CQuaternion &quat) const; - //quaternion addition/assignment + // Quaternion addition/assignment CQuaternion &operator += (const CQuaternion &quat); - //quaternion multiplication + // Quaternion multiplication CQuaternion operator * (const CQuaternion &quat) const; - //quaternion multiplication/assignment + // Quaternion multiplication/assignment CQuaternion &operator *= (const CQuaternion &quat); void FromEulerAngles (float x, float y, float z); CVector3D ToEulerAngles(); - //convert the quaternion to matrix + // Convert the quaternion to matrix CMatrix3D ToMatrix() const; void ToMatrix(CMatrix3D& result) const; - //sphere interpolation + // Sphere interpolation void Slerp(const CQuaternion& from, const CQuaternion& to, float ratio); - // create a quaternion from axis/angle representation of a rotation + // Create a quaternion from axis/angle representation of a rotation void FromAxisAngle(const CVector3D& axis, float angle); - // convert the quaternion to axis/angle representation of a rotation + // Convert the quaternion to axis/angle representation of a rotation void ToAxisAngle(CVector3D& axis, float& angle); - // normalize this quaternion + // Normalize this quaternion void Normalize(); - // rotate a vector by this quaternion + // Rotate a vector by this quaternion. Assumes the quaternion is normalised. CVector3D Rotate(const CVector3D& vec) const; - // calculate q^-1 + // Calculate q^-1. Assumes the quaternion is normalised. CQuaternion GetInverse() const; }; diff --git a/source/maths/tests/test_Matrix3d.h b/source/maths/tests/test_Matrix3d.h index 8d16c73440..c21d1a61db 100644 --- a/source/maths/tests/test_Matrix3d.h +++ b/source/maths/tests/test_Matrix3d.h @@ -49,8 +49,8 @@ public: q.ToMatrix(m); CQuaternion q2 = m.GetRotation(); - // I hope there's a good reason why they're sometimes negated, and - // it's not just a bug... + // Quaternions (x,y,z,w) and (-x,-y,-z,-w) are equivalent when + // interpreted as rotations, so it doesn't matter which we get const bool ok_oneway = feq(q2.m_W, q.m_W) && feq(q2.m_V.X, q.m_V.X) && diff --git a/source/renderer/InstancingModelRenderer.cpp b/source/renderer/InstancingModelRenderer.cpp index 976ada7547..bf00ba2762 100644 --- a/source/renderer/InstancingModelRenderer.cpp +++ b/source/renderer/InstancingModelRenderer.cpp @@ -132,7 +132,7 @@ void* InstancingModelRenderer::CreateModelData(CModel* model) CModelDefPtr mdef = model->GetModelDef(); IModelDef* imodeldef = (IModelDef*)mdef->GetRenderData(m); - debug_assert(!model->GetBoneMatrices()); + debug_assert(!model->IsSkinned()); if (!imodeldef) { diff --git a/source/renderer/ModelRenderer.cpp b/source/renderer/ModelRenderer.cpp index 804aeeb957..da58d596ea 100644 --- a/source/renderer/ModelRenderer.cpp +++ b/source/renderer/ModelRenderer.cpp @@ -31,58 +31,6 @@ #define LOG_CATEGORY "graphics" -///////////////////////////////////////////////////////////////////////////////////////////////////////////// -// SkinPoint: skin the vertex position using it's blend data and given bone matrices -static void SkinPoint(const SModelVertex& vertex,const CMatrix3D* matrices,CVector3D& result) -{ - CVector3D tmp; - const SVertexBlend& blend=vertex.m_Blend; - - // must have at least one valid bone if we're using SkinPoint - if (blend.m_Bone[0] == 0xff) - { - // (CModel should have already complained about this) - result = CVector3D(0, 0, 0); - return; - } - - const CMatrix3D& m=matrices[blend.m_Bone[0]]; - m.Transform(vertex.m_Coords,result); - result*=blend.m_Weight[0]; - - for (u32 i=1; iGetNumVertices(); SModelVertex* vertices=mdef->GetVertices(); - const CMatrix3D* bonematrices = model->GetBoneMatrices(); - if (bonematrices) + if (model->IsSkinned()) { // boned model - calculate skinned vertex positions/normals PROFILE( "skinning bones" ); - const CMatrix3D* invtranspbonematrices; - - // Analytic geometry tells us that normal vectors need to be - // multiplied by the inverse of the transpose. However, calculating - // the inverse is slow, and analytic geometry also tells us that - // for orthogonal matrices, the inverse is equal to the transpose, - // so the inverse of the transpose is, in fact, the original matrix. - // - // The "fast normals" code assumes that bone transformation contain - // no "weird" transformations like shears or non-uniform scaling - // (actually, the entire code assumes no scaling) and thus gets - // around the slow calculation of the inverse. - if (g_Renderer.m_FastNormals) - invtranspbonematrices = bonematrices; - else - invtranspbonematrices = model->GetInvTranspBoneMatrices(); // Avoid the noisy warnings that occur inside SkinPoint/SkinNormal in // some broken situations @@ -144,8 +75,8 @@ void ModelRenderer::BuildPositionAndNormals( for (size_t j=0; jGetAnimatedBoneMatrices(), model->GetInverseBindBoneMatrices()); + Normal[j] = CModelDef::SkinNormal(vertices[j], model->GetAnimatedBoneMatrices(), model->GetInverseBindBoneMatrices()); } } else diff --git a/source/renderer/Renderer.cpp b/source/renderer/Renderer.cpp index e7160461bf..00b06e13eb 100644 --- a/source/renderer/Renderer.cpp +++ b/source/renderer/Renderer.cpp @@ -353,7 +353,6 @@ CRenderer::CRenderer() m_ClearColor[0]=m_ClearColor[1]=m_ClearColor[2]=m_ClearColor[3]=0; m_SortAllTransparent = false; - m_FastNormals = true; m_DisplayFrustum = false; m_DisableCopyShadow = false; m_FastPlayerColor = true; @@ -1747,7 +1746,6 @@ void CRenderer::ScriptingInit() AddProperty(L"renderpath", &CRenderer::JSI_GetRenderPath, &CRenderer::JSI_SetRenderPath); AddProperty(L"useDepthTexture", &CRenderer::JSI_GetUseDepthTexture, &CRenderer::JSI_SetUseDepthTexture); AddProperty(L"sortAllTransparent", &CRenderer::m_SortAllTransparent); - AddProperty(L"fastNormals", &CRenderer::m_FastNormals); AddProperty(L"displayFrustum", &CRenderer::m_DisplayFrustum); AddProperty(L"shadowZBias", &CRenderer::m_ShadowZBias); AddProperty(L"disableCopyShadow", &CRenderer::m_DisableCopyShadow); diff --git a/source/renderer/Renderer.h b/source/renderer/Renderer.h index 62d81c210a..d30027c3b2 100644 --- a/source/renderer/Renderer.h +++ b/source/renderer/Renderer.h @@ -431,13 +431,6 @@ protected: */ bool m_SortAllTransparent; - /** - * m_FastNormals: Use faster normal transformation in the - * software transform by multiplying with the bone matrix itself - * instead of the transpose of the inverse. - */ - bool m_FastNormals; - /** * m_DisplayFrustum: Render the cull frustum and other data that may be interesting * to evaluate culling and shadow map calculations diff --git a/source/tools/atlas/AtlasUI/ActorViewer/ActorViewer.cpp b/source/tools/atlas/AtlasUI/ActorViewer/ActorViewer.cpp index 94c03daf21..b0722636a0 100644 --- a/source/tools/atlas/AtlasUI/ActorViewer/ActorViewer.cpp +++ b/source/tools/atlas/AtlasUI/ActorViewer/ActorViewer.cpp @@ -166,7 +166,7 @@ static void SendToGame(const AtlasMessage::sEnvironmentSettings& settings) ActorViewer::ActorViewer(wxWindow* parent) : wxFrame(parent, wxID_ANY, _("Actor Viewer"), wxDefaultPosition, wxSize(800, 600)), m_CurrentSpeed(0.f), m_BackgroundColour(wxColour(255, 255, 255)), - m_ToggledWalking(true), m_ToggledWireframe(false), m_ToggledGround(true), + m_ToggledWalking(false), m_ToggledWireframe(false), m_ToggledGround(true), m_ToggledShadows(true), m_ToggledStats(false), m_ObjectSettings(m_ObjectSelection, AtlasMessage::eRenderView::ACTOR) { diff --git a/source/tools/atlas/GameInterface/ActorViewer.cpp b/source/tools/atlas/GameInterface/ActorViewer.cpp index b35279d2a1..07d04eb80e 100644 --- a/source/tools/atlas/GameInterface/ActorViewer.cpp +++ b/source/tools/atlas/GameInterface/ActorViewer.cpp @@ -51,7 +51,7 @@ ActorViewer::ActorViewer() : m(*new ActorViewerImpl()) { m.Unit = NULL; - m.WalkEnabled = true; + m.WalkEnabled = false; m.Background = SColor4ub(255, 255, 255, 255); // Set up the renderer diff --git a/source/tools/atlas/GameInterface/Handlers/CameraCtrlHandlers.cpp b/source/tools/atlas/GameInterface/Handlers/CameraCtrlHandlers.cpp index 539b7e294a..294568a02b 100644 --- a/source/tools/atlas/GameInterface/Handlers/CameraCtrlHandlers.cpp +++ b/source/tools/atlas/GameInterface/Handlers/CameraCtrlHandlers.cpp @@ -168,7 +168,7 @@ MESSAGEHANDLER(LookAt) 0, 0, 0, 1 ); - M.GetTranspose(camera.m_Orientation); + camera.m_Orientation = M.GetTranspose(); camera.m_Orientation.Translate(-eye); camera.UpdateFrustum();