Index: ps/trunk/source/lib/sse.cpp =================================================================== --- ps/trunk/source/lib/sse.cpp (revision 24839) +++ ps/trunk/source/lib/sse.cpp (nonexistent) @@ -1,46 +0,0 @@ -/* Copyright (C) 2020 Wildfire Games. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "precompiled.h" - -#include "lib/sse.h" - -#if COMPILER_HAS_SSE -#include "lib/code_generation.h" -#include "lib/debug.h" -#include "lib/sysdep/arch.h" - -#if ARCH_X86_X64 -#include "lib/sysdep/arch/x86_x64/x86_x64.h" -#endif - -bool HostHasSSE() -{ -#if ARCH_X86_X64 - return x86_x64::Cap(x86_x64::CAP_SSE); -#elif ARCH_E2K - return true; -#else - return false; -#endif -} -#endif Property changes on: ps/trunk/source/lib/sse.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/lib/sse.h =================================================================== --- ps/trunk/source/lib/sse.h (revision 24839) +++ ps/trunk/source/lib/sse.h (nonexistent) @@ -1,32 +0,0 @@ -/* Copyright (C) 2020 Wildfire Games. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef INCLUDED_SSE -#define INCLUDED_SSE - -#include "lib/sysdep/compiler.h" - -#if COMPILER_HAS_SSE -extern bool HostHasSSE(); -#endif - -#endif // INCLUDED_SSE Property changes on: ps/trunk/source/lib/sse.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Index: ps/trunk/source/graphics/Color.cpp =================================================================== --- ps/trunk/source/graphics/Color.cpp (revision 24839) +++ ps/trunk/source/graphics/Color.cpp (revision 24840) @@ -1,145 +1,145 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #include "precompiled.h" #include "graphics/Color.h" #include "graphics/SColor.h" +#include "lib/sysdep/arch/x86_x64/simd.h" #include "maths/MathUtil.h" -#include "lib/sse.h" #include "ps/CLogger.h" #include "ps/CStr.h" #if COMPILER_HAS_SSE #include #endif static SColor4ub ConvertRGBColorTo4ubFallback(const RGBColor& src) { SColor4ub result; result.R = Clamp(static_cast(src.X * 255), 0, 255); result.G = Clamp(static_cast(src.Y * 255), 0, 255); result.B = Clamp(static_cast(src.Z * 255), 0, 255); result.A = 255; return result; } // on IA32, this is replaced by an SSE assembly version in ia32.cpp SColor4ub (*ConvertRGBColorTo4ub)(const RGBColor& src) = ConvertRGBColorTo4ubFallback; // Assembler-optimized function for color conversion #if COMPILER_HAS_SSE static SColor4ub ConvertRGBColorTo4ubSSE(const RGBColor& src) { const __m128 zero = _mm_setzero_ps(); const __m128 _255 = _mm_set_ss(255.0f); __m128 r = _mm_load_ss(&src.X); __m128 g = _mm_load_ss(&src.Y); __m128 b = _mm_load_ss(&src.Z); // C = min(255, 255*max(C, 0)) ( == Clamp(255*C, 0, 255) ) r = _mm_max_ss(r, zero); g = _mm_max_ss(g, zero); b = _mm_max_ss(b, zero); r = _mm_mul_ss(r, _255); g = _mm_mul_ss(g, _255); b = _mm_mul_ss(b, _255); r = _mm_min_ss(r, _255); g = _mm_min_ss(g, _255); b = _mm_min_ss(b, _255); // convert to integer and combine channels using bit logic int ri = _mm_cvtss_si32(r); int gi = _mm_cvtss_si32(g); int bi = _mm_cvtss_si32(b); return SColor4ub(ri, gi, bi, 0xFF); } #endif void ColorActivateFastImpl() { #if COMPILER_HAS_SSE if (HostHasSSE()) { ConvertRGBColorTo4ub = ConvertRGBColorTo4ubSSE; return; } #endif debug_printf("No SSE available. Slow fallback routines will be used.\n"); } /** * Important: This function does not modify the value if parsing fails. */ bool CColor::ParseString(const CStr8& value, int defaultAlpha) { const size_t NUM_VALS = 4; int values[NUM_VALS] = { 0, 0, 0, defaultAlpha }; std::stringstream stream; stream.str(value); // Parse each value size_t i; for (i = 0; i < NUM_VALS; ++i) { if (stream.eof()) break; stream >> values[i]; if ((stream.rdstate() & std::stringstream::failbit) != 0) { LOGWARNING("Unable to parse CColor parameters. Your input: '%s'", value.c_str()); return false; } if (values[i] < 0 || values[i] > 255) { LOGWARNING("Invalid value (<0 or >255) when parsing CColor parameters. Your input: '%s'", value.c_str()); return false; } } if (i < 3) { LOGWARNING("Not enough parameters when parsing as CColor. Your input: '%s'", value.c_str()); return false; } if (!stream.eof()) { LOGWARNING("Too many parameters when parsing as CColor. Your input: '%s'", value.c_str()); return false; } r = values[0] / 255.f; g = values[1] / 255.f; b = values[2] / 255.f; a = values[3] / 255.f; return true; } bool CColor::operator==(const CColor& color) const { return r == color.r && g == color.g && b == color.b && a == color.a; } Index: ps/trunk/source/graphics/ModelDef.cpp =================================================================== --- ps/trunk/source/graphics/ModelDef.cpp (revision 24839) +++ ps/trunk/source/graphics/ModelDef.cpp (revision 24840) @@ -1,495 +1,495 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ /* * Defines a raw 3d model. */ #include "precompiled.h" #include "ModelDef.h" #include "graphics/SkeletonAnimDef.h" -#include "lib/sse.h" +#include "lib/sysdep/arch/x86_x64/simd.h" #include "ps/FileIo.h" #include "maths/Vector4D.h" #if COMPILER_HAS_SSE # include #endif CVector3D CModelDef::SkinPoint(const SModelVertex& vtx, const CMatrix3D newPoseMatrices[]) { CVector3D result (0, 0, 0); for (int i = 0; i < SVertexBlend::SIZE && vtx.m_Blend.m_Bone[i] != 0xff; ++i) { result += newPoseMatrices[vtx.m_Blend.m_Bone[i]].Transform(vtx.m_Coords) * vtx.m_Blend.m_Weight[i]; } return result; } CVector3D CModelDef::SkinNormal(const SModelVertex& vtx, const CMatrix3D newPoseMatrices[]) { // 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 bone 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) { result += newPoseMatrices[vtx.m_Blend.m_Bone[i]].Rotate(vtx.m_Norm) * 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; } void(*CModelDef::SkinPointsAndNormals)( size_t numVertices, const VertexArrayIterator& Position, const VertexArrayIterator& Normal, const SModelVertex* vertices, const size_t* blendIndices, const CMatrix3D newPoseMatrices[]) {}; static void SkinPointsAndNormalsFallback( size_t numVertices, const VertexArrayIterator& Position, const VertexArrayIterator& Normal, const SModelVertex* vertices, const size_t* blendIndices, const CMatrix3D newPoseMatrices[]) { // To avoid some performance overhead, get the raw vertex array pointers char* PositionData = Position.GetData(); size_t PositionStride = Position.GetStride(); char* NormalData = Normal.GetData(); size_t NormalStride = Normal.GetStride(); for (size_t j = 0; j < numVertices; ++j) { const SModelVertex& vtx = vertices[j]; CVector3D pos = newPoseMatrices[blendIndices[j]].Transform(vtx.m_Coords); CVector3D norm = newPoseMatrices[blendIndices[j]].Rotate(vtx.m_Norm); // 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 norm.Normalize(); memcpy(PositionData + PositionStride*j, &pos.X, 3*sizeof(float)); memcpy(NormalData + NormalStride*j, &norm.X, 3*sizeof(float)); } } #if COMPILER_HAS_SSE static void SkinPointsAndNormalsSSE( size_t numVertices, const VertexArrayIterator& Position, const VertexArrayIterator& Normal, const SModelVertex* vertices, const size_t* blendIndices, const CMatrix3D newPoseMatrices[]) { // To avoid some performance overhead, get the raw vertex array pointers char* PositionData = Position.GetData(); size_t PositionStride = Position.GetStride(); char* NormalData = Normal.GetData(); size_t NormalStride = Normal.GetStride(); // Must be aligned correctly for SSE ASSERT((intptr_t)newPoseMatrices % 16 == 0); ASSERT((intptr_t)PositionData % 16 == 0); ASSERT((intptr_t)PositionStride % 16 == 0); ASSERT((intptr_t)NormalData % 16 == 0); ASSERT((intptr_t)NormalStride % 16 == 0); __m128 col0, col1, col2, col3, vec0, vec1, vec2; for (size_t j = 0; j < numVertices; ++j) { const SModelVertex& vtx = vertices[j]; const CMatrix3D& mtx = newPoseMatrices[blendIndices[j]]; // Loads matrix to xmm registers. col0 = _mm_load_ps(mtx._data); col1 = _mm_load_ps(mtx._data + 4); col2 = _mm_load_ps(mtx._data + 8); col3 = _mm_load_ps(mtx._data + 12); // Loads and computes vertex coordinates. vec0 = _mm_load1_ps(&vtx.m_Coords.X); // v0 = [x, x, x, x] vec0 = _mm_mul_ps(col0, vec0); // v0 = [_11*x, _21*x, _31*x, _41*x] vec1 = _mm_load1_ps(&vtx.m_Coords.Y); // v1 = [y, y, y, y] vec1 = _mm_mul_ps(col1, vec1); // v1 = [_12*y, _22*y, _32*y, _42*y] vec0 = _mm_add_ps(vec0, vec1); // v0 = [_11*x + _12*y, ...] vec1 = _mm_load1_ps(&vtx.m_Coords.Z); // v1 = [z, z, z, z] vec1 = _mm_mul_ps(col2, vec1); // v1 = [_13*z, _23*z, _33*z, _43*z] vec1 = _mm_add_ps(vec1, col3); // v1 = [_13*z + _14, ...] vec0 = _mm_add_ps(vec0, vec1); // v0 = [_11*x + _12*y + _13*z + _14, ...] _mm_store_ps((float*)(PositionData + PositionStride*j), vec0); // Loads and computes normal vectors. vec0 = _mm_load1_ps(&vtx.m_Norm.X); // v0 = [x, x, x, x] vec0 = _mm_mul_ps(col0, vec0); // v0 = [_11*x, _21*x, _31*x, _41*x] vec1 = _mm_load1_ps(&vtx.m_Norm.Y); // v1 = [y, y, y, y] vec1 = _mm_mul_ps(col1, vec1); // v1 = [_12*y, _22*y, _32*y, _42*y] vec0 = _mm_add_ps(vec0, vec1); // v0 = [_11*x + _12*y, ...] vec1 = _mm_load1_ps(&vtx.m_Norm.Z); // v1 = [z, z, z, z] vec1 = _mm_mul_ps(col2, vec1); // v1 = [_13*z, _23*z, _33*z, _43*z] vec0 = _mm_add_ps(vec0, vec1); // v0 = [_11*x + _12*y + _13*z, ...] // 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 { // Normalization. // vec1 = [x*x, y*y, z*z, ?*?] vec1 = _mm_mul_ps(vec0, vec0); // vec2 = [y*y, z*z, x*x, ?*?] vec2 = _mm_shuffle_ps(vec1, vec1, _MM_SHUFFLE(3, 0, 2, 1)); vec1 = _mm_add_ps(vec1, vec2); // vec2 = [z*z, x*x, y*y, ?*?] vec2 = _mm_shuffle_ps(vec2, vec2, _MM_SHUFFLE(3, 0, 2, 1)); vec1 = _mm_add_ps(vec1, vec2); // rsqrt(a) = 1 / sqrt(a) vec1 = _mm_rsqrt_ps(vec1); vec0 = _mm_mul_ps(vec0, vec1); } _mm_store_ps((float*)(NormalData + NormalStride*j), vec0); } } #endif void CModelDef::BlendBoneMatrices( CMatrix3D boneMatrices[]) { for (size_t i = 0; i < m_NumBlends; ++i) { const SVertexBlend& blend = m_pBlends[i]; CMatrix3D& boneMatrix = boneMatrices[m_NumBones + 1 + i]; // Note: there is a special case of joint influence, in which the vertex // is influenced by the bind-shape matrix instead of a particular bone, // which we indicate by setting the bone ID to the total number of bones. // It should be blended with the world space transform and we have already // set up this matrix in boneMatrices. // (see http://trac.wildfiregames.com/ticket/1012) boneMatrix.Blend(boneMatrices[blend.m_Bone[0]], blend.m_Weight[0]); for (size_t j = 1; j < SVertexBlend::SIZE && blend.m_Bone[j] != 0xFF; ++j) boneMatrix.AddBlend(boneMatrices[blend.m_Bone[j]], blend.m_Weight[j]); } } // CModelDef Constructor CModelDef::CModelDef() : m_NumVertices(0), m_NumUVsPerVertex(0), m_pVertices(0), m_NumFaces(0), m_pFaces(0), m_NumBones(0), m_Bones(0), m_InverseBindBoneMatrices(NULL), m_NumBlends(0), m_pBlends(0), m_pBlendIndices(0), m_Name(L"[not loaded]") { } // CModelDef Destructor CModelDef::~CModelDef() { for(RenderDataMap::iterator it = m_RenderData.begin(); it != m_RenderData.end(); ++it) delete it->second; delete[] m_pVertices; delete[] m_pFaces; delete[] m_Bones; delete[] m_InverseBindBoneMatrices; delete[] m_pBlends; delete[] m_pBlendIndices; } // FindPropPoint: find and return pointer to prop point matching given name; // return null if no match (case insensitive search) const SPropPoint* CModelDef::FindPropPoint(const char* name) const { for (size_t i = 0; i < m_PropPoints.size(); ++i) if (m_PropPoints[i].m_Name == name) return &m_PropPoints[i]; return 0; } // Load: read and return a new CModelDef initialised with data from given file CModelDef* CModelDef::Load(const VfsPath& filename, const VfsPath& name) { CFileUnpacker unpacker; // read everything in from file unpacker.Read(filename,"PSMD"); // check version if (unpacker.GetVersion() mdef (new CModelDef()); mdef->m_Name = name; // now unpack everything mdef->m_NumVertices = unpacker.UnpackSize(); // versions prior to 4 only support 1 UV set, 4 and later store it here if (unpacker.GetVersion() <= 3) { mdef->m_NumUVsPerVertex = 1; } else { mdef->m_NumUVsPerVertex = unpacker.UnpackSize(); } mdef->m_pVertices=new SModelVertex[mdef->m_NumVertices]; for (size_t i = 0; i < mdef->m_NumVertices; ++i) { unpacker.UnpackRaw(&mdef->m_pVertices[i].m_Coords, 12); unpacker.UnpackRaw(&mdef->m_pVertices[i].m_Norm, 12); for (size_t s = 0; s < mdef->m_NumUVsPerVertex; ++s) { float uv[2]; unpacker.UnpackRaw(&uv[0], 8); mdef->m_pVertices[i].m_UVs.push_back(uv[0]); mdef->m_pVertices[i].m_UVs.push_back(uv[1]); } unpacker.UnpackRaw(&mdef->m_pVertices[i].m_Blend, sizeof(SVertexBlend)); } mdef->m_NumFaces = unpacker.UnpackSize(); mdef->m_pFaces=new SModelFace[mdef->m_NumFaces]; unpacker.UnpackRaw(mdef->m_pFaces,sizeof(SModelFace)*mdef->m_NumFaces); mdef->m_NumBones = unpacker.UnpackSize(); if (mdef->m_NumBones) { mdef->m_Bones=new CBoneState[mdef->m_NumBones]; unpacker.UnpackRaw(mdef->m_Bones,mdef->m_NumBones*sizeof(CBoneState)); mdef->m_pBlendIndices = new size_t[mdef->m_NumVertices]; std::vector blends; for (size_t i = 0; i < mdef->m_NumVertices; i++) { const SVertexBlend &blend = mdef->m_pVertices[i].m_Blend; if (blend.m_Bone[1] == 0xFF) { mdef->m_pBlendIndices[i] = blend.m_Bone[0]; } else { // If there's already a vertex using the same blend as this, then // reuse its entry from blends; otherwise add the new one to blends size_t j; for (j = 0; j < blends.size(); j++) { if (blend == blends[j]) break; } if (j >= blends.size()) blends.push_back(blend); // This index is offset by one to allow the special case of a // weighted influence relative to the bind-shape rather than // a particular bone. See comment in BlendBoneMatrices. mdef->m_pBlendIndices[i] = mdef->m_NumBones + 1 + j; } } mdef->m_NumBlends = blends.size(); mdef->m_pBlends = new SVertexBlend[mdef->m_NumBlends]; std::copy(blends.begin(), blends.end(), mdef->m_pBlends); } if (unpacker.GetVersion() >= 2) { // versions >=2 also have prop point data size_t numPropPoints = unpacker.UnpackSize(); mdef->m_PropPoints.resize(numPropPoints); if (numPropPoints) { for (size_t i = 0; i < 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 don't include the default 'root' prop point, so add it here SPropPoint prop; prop.m_Name = "root"; prop.m_Transform.SetIdentity(); prop.m_BoneIndex = 0xFF; mdef->m_PropPoints.push_back(prop); } 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 { std::vector bindPose (mdef->m_NumBones); for (size_t 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 (size_t i = 0; i < mdef->m_NumVertices; ++i) { mdef->m_pVertices[i].m_Coords = SkinPoint(mdef->m_pVertices[i], &bindPose[0]); mdef->m_pVertices[i].m_Norm = SkinNormal(mdef->m_pVertices[i], &bindPose[0]); } } } // Compute the inverse bind-pose matrices, needed by the skinning code mdef->m_InverseBindBoneMatrices = new CMatrix3D[mdef->m_NumBones]; CBoneState* defpose = mdef->GetBones(); for (size_t i = 0; i < mdef->m_NumBones; ++i) { mdef->m_InverseBindBoneMatrices[i].SetIdentity(); mdef->m_InverseBindBoneMatrices[i].Translate(-defpose[i].m_Translation); mdef->m_InverseBindBoneMatrices[i].Rotate(defpose[i].m_Rotation.GetInverse()); } return mdef.release(); } // Save: write the given CModelDef to the given file void CModelDef::Save(const VfsPath& filename, const CModelDef* mdef) { CFilePacker packer(FILE_VERSION, "PSMD"); // pack everything up const size_t numVertices = mdef->GetNumVertices(); packer.PackSize(numVertices); packer.PackRaw(mdef->GetVertices(), sizeof(SModelVertex) * numVertices); const size_t numFaces = mdef->GetNumFaces(); packer.PackSize(numFaces); packer.PackRaw(mdef->GetFaces(), sizeof(SModelFace) * numFaces); const size_t numBones = mdef->m_NumBones; packer.PackSize(numBones); if (numBones) packer.PackRaw(mdef->m_Bones, sizeof(CBoneState) * numBones); const size_t numPropPoints = mdef->m_PropPoints.size(); packer.PackSize(numPropPoints); for (size_t i = 0; i < numPropPoints; i++) { packer.PackString(mdef->m_PropPoints[i].m_Name); packer.PackRaw(&mdef->m_PropPoints[i].m_Position.X, sizeof(mdef->m_PropPoints[i].m_Position)); packer.PackRaw(&mdef->m_PropPoints[i].m_Rotation.m_V.X, sizeof(mdef->m_PropPoints[i].m_Rotation)); packer.PackRaw(&mdef->m_PropPoints[i].m_BoneIndex, sizeof(mdef->m_PropPoints[i].m_BoneIndex)); } // flush everything out to file packer.Write(filename); } // SetRenderData: Set the render data object for the given key, void CModelDef::SetRenderData(const void* key, CModelDefRPrivate* data) { delete m_RenderData[key]; m_RenderData[key] = data; } // GetRenderData: Get the render data object for the given key, // or 0 if no such object exists. // Reference count of the render data object is automatically increased. CModelDefRPrivate* CModelDef::GetRenderData(const void* key) const { RenderDataMap::const_iterator it = m_RenderData.find(key); if (it != m_RenderData.end()) return it->second; return 0; } void ModelDefActivateFastImpl() { #if COMPILER_HAS_SSE if (HostHasSSE()) { CModelDef::SkinPointsAndNormals = SkinPointsAndNormalsSSE; return; } #endif CModelDef::SkinPointsAndNormals = SkinPointsAndNormalsFallback; } Index: ps/trunk/source/lib/sysdep/arch/x86_x64/simd.cpp =================================================================== --- ps/trunk/source/lib/sysdep/arch/x86_x64/simd.cpp (nonexistent) +++ ps/trunk/source/lib/sysdep/arch/x86_x64/simd.cpp (revision 24840) @@ -0,0 +1,46 @@ +/* Copyright (C) 2021 Wildfire Games. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "precompiled.h" + +#include "lib/sysdep/arch/x86_x64/simd.h" + +#if COMPILER_HAS_SSE +#include "lib/code_generation.h" +#include "lib/debug.h" +#include "lib/sysdep/arch.h" + +#if ARCH_X86_X64 +#include "lib/sysdep/arch/x86_x64/x86_x64.h" +#endif + +bool HostHasSSE() +{ +#if ARCH_X86_X64 + return x86_x64::Cap(x86_x64::CAP_SSE); +#elif ARCH_E2K + return true; +#else + return false; +#endif +} +#endif Property changes on: ps/trunk/source/lib/sysdep/arch/x86_x64/simd.cpp ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: ps/trunk/source/lib/sysdep/arch/x86_x64/simd.h =================================================================== --- ps/trunk/source/lib/sysdep/arch/x86_x64/simd.h (nonexistent) +++ ps/trunk/source/lib/sysdep/arch/x86_x64/simd.h (revision 24840) @@ -0,0 +1,32 @@ +/* Copyright (C) 2021 Wildfire Games. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef INCLUDED_SSE +#define INCLUDED_SSE + +#include "lib/sysdep/compiler.h" + +#if COMPILER_HAS_SSE +extern bool HostHasSSE(); +#endif + +#endif // INCLUDED_SSE Property changes on: ps/trunk/source/lib/sysdep/arch/x86_x64/simd.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property