Changeset View
Changeset View
Standalone View
Standalone View
source/graphics/ModelDef.cpp
/* Copyright (C) 2022 Wildfire Games. | /* Copyright (C) 2023 Wildfire Games. | ||||
* This file is part of 0 A.D. | * This file is part of 0 A.D. | ||||
* | * | ||||
* 0 A.D. is free software: you can redistribute it and/or modify | * 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 | * it under the terms of the GNU General Public License as published by | ||||
* the Free Software Foundation, either version 2 of the License, or | * the Free Software Foundation, either version 2 of the License, or | ||||
* (at your option) any later version. | * (at your option) any later version. | ||||
* | * | ||||
* 0 A.D. is distributed in the hope that it will be useful, | * 0 A.D. is distributed in the hope that it will be useful, | ||||
▲ Show 20 Lines • Show All 112 Lines • ▼ Show 20 Lines | CVector3D CModelDef::SkinNormal(const SModelVertex& vtx, | ||||
// (It's fairly common to only have one influence, so it seems sensible to | // (It's fairly common to only have one influence, so it seems sensible to | ||||
// optimise that case a bit.) | // optimise that case a bit.) | ||||
if (vtx.m_Blend.m_Bone[1] != 0xff) // if more than one influence | if (vtx.m_Blend.m_Bone[1] != 0xff) // if more than one influence | ||||
result.Normalize(); | result.Normalize(); | ||||
return result; | return result; | ||||
} | } | ||||
void(*CModelDef::SkinPointsAndNormals)( | void CModelDef::SkinPointsAndNormals( | ||||
size_t numVertices, | |||||
const VertexArrayIterator<CVector3D>& Position, | |||||
const VertexArrayIterator<CVector3D>& Normal, | |||||
const SModelVertex* vertices, | |||||
const size_t* blendIndices, | |||||
const CMatrix3D newPoseMatrices[]) {}; | |||||
static void SkinPointsAndNormalsFallback( | |||||
size_t numVertices, | size_t numVertices, | ||||
const VertexArrayIterator<CVector3D>& Position, | const VertexArrayIterator<CVector3D>& Position, | ||||
const VertexArrayIterator<CVector3D>& Normal, | const VertexArrayIterator<CVector3D>& Normal, | ||||
const SModelVertex* vertices, | const SModelVertex* vertices, | ||||
const size_t* blendIndices, | const size_t* blendIndices, | ||||
const CMatrix3D newPoseMatrices[]) | const CMatrix3D newPoseMatrices[]) | ||||
vladislavbelov: Might want to change to `PS::span` in the future. | |||||
{ | { | ||||
// To avoid some performance overhead, get the raw vertex array pointers | // To avoid some performance overhead, get the raw vertex array pointers | ||||
char* PositionData = Position.GetData(); | char* PositionData = Position.GetData(); | ||||
size_t PositionStride = Position.GetStride(); | size_t PositionStride = Position.GetStride(); | ||||
char* NormalData = Normal.GetData(); | char* NormalData = Normal.GetData(); | ||||
size_t NormalStride = Normal.GetStride(); | size_t NormalStride = Normal.GetStride(); | ||||
#if !COMPILER_HAS_SSE | |||||
for (size_t j = 0; j < numVertices; ++j) | for (size_t j = 0; j < numVertices; ++j) | ||||
{ | { | ||||
const SModelVertex& vtx = vertices[j]; | const SModelVertex& vtx = vertices[j]; | ||||
CVector3D pos = newPoseMatrices[blendIndices[j]].Transform(vtx.m_Coords); | CVector3D pos = newPoseMatrices[blendIndices[j]].Transform(vtx.m_Coords); | ||||
CVector3D norm = newPoseMatrices[blendIndices[j]].Rotate(vtx.m_Norm); | CVector3D norm = newPoseMatrices[blendIndices[j]].Rotate(vtx.m_Norm); | ||||
// If there was more than one influence, the result is probably not going | // 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 | // to be of unit length (since it's a weighted sum of several independent | ||||
// unit vectors), so we need to normalise it. | // unit vectors), so we need to normalise it. | ||||
// (It's fairly common to only have one influence, so it seems sensible to | // (It's fairly common to only have one influence, so it seems sensible to | ||||
// optimise that case a bit.) | // optimise that case a bit.) | ||||
if (vtx.m_Blend.m_Bone[1] != 0xff) // if more than one influence | if (vtx.m_Blend.m_Bone[1] != 0xff) // if more than one influence | ||||
norm.Normalize(); | norm.Normalize(); | ||||
memcpy(PositionData + PositionStride*j, &pos.X, 3*sizeof(float)); | memcpy(PositionData + PositionStride*j, &pos.X, 3*sizeof(float)); | ||||
memcpy(NormalData + NormalStride*j, &norm.X, 3*sizeof(float)); | memcpy(NormalData + NormalStride*j, &norm.X, 3*sizeof(float)); | ||||
} | } | ||||
} | |||||
#if COMPILER_HAS_SSE | #else | ||||
static void SkinPointsAndNormalsSSE( | |||||
size_t numVertices, | |||||
const VertexArrayIterator<CVector3D>& Position, | |||||
const VertexArrayIterator<CVector3D>& 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 | // Must be aligned correctly for SSE | ||||
ASSERT((intptr_t)newPoseMatrices % 16 == 0); | ASSERT((intptr_t)newPoseMatrices % 16 == 0); | ||||
ASSERT((intptr_t)PositionData % 16 == 0); | ASSERT((intptr_t)PositionData % 16 == 0); | ||||
ASSERT((intptr_t)PositionStride % 16 == 0); | ASSERT((intptr_t)PositionStride % 16 == 0); | ||||
ASSERT((intptr_t)NormalData % 16 == 0); | ASSERT((intptr_t)NormalData % 16 == 0); | ||||
ASSERT((intptr_t)NormalStride % 16 == 0); | ASSERT((intptr_t)NormalStride % 16 == 0); | ||||
Show All 16 Lines | for (size_t j = 0; j < numVertices; ++j) | ||||
vec0 = _mm_mul_ps(col0, vec0); // v0 = [_11*x, _21*x, _31*x, _41*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_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] | 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, ...] | 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_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_mul_ps(col2, vec1); // v1 = [_13*z, _23*z, _33*z, _43*z] | ||||
vec1 = _mm_add_ps(vec1, col3); // v1 = [_13*z + _14, ...] | vec1 = _mm_add_ps(vec1, col3); // v1 = [_13*z + _14, ...] | ||||
vec0 = _mm_add_ps(vec0, vec1); // v0 = [_11*x + _12*y + _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); | _mm_store_ps(reinterpret_cast<float*>(PositionData + PositionStride * j), vec0); | ||||
// Loads and computes normal vectors. | // Loads and computes normal vectors. | ||||
vec0 = _mm_load1_ps(&vtx.m_Norm.X); // v0 = [x, x, x, x] | 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] | 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_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] | 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, ...] | 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_load1_ps(&vtx.m_Norm.Z); // v1 = [z, z, z, z] | ||||
Show All 15 Lines | if (vtx.m_Blend.m_Bone[1] != 0xff) // if more than one influence | ||||
vec1 = _mm_add_ps(vec1, vec2); | vec1 = _mm_add_ps(vec1, vec2); | ||||
// vec2 = [z*z, x*x, y*y, ?*?] | // vec2 = [z*z, x*x, y*y, ?*?] | ||||
vec2 = _mm_shuffle_ps(vec2, vec2, _MM_SHUFFLE(3, 0, 2, 1)); | vec2 = _mm_shuffle_ps(vec2, vec2, _MM_SHUFFLE(3, 0, 2, 1)); | ||||
vec1 = _mm_add_ps(vec1, vec2); | vec1 = _mm_add_ps(vec1, vec2); | ||||
// rsqrt(a) = 1 / sqrt(a) | // rsqrt(a) = 1 / sqrt(a) | ||||
vec1 = _mm_rsqrt_ps(vec1); | vec1 = _mm_rsqrt_ps(vec1); | ||||
vec0 = _mm_mul_ps(vec0, vec1); | vec0 = _mm_mul_ps(vec0, vec1); | ||||
} | } | ||||
_mm_store_ps((float*)(NormalData + NormalStride*j), vec0); | _mm_store_ps(reinterpret_cast<float*>(NormalData + NormalStride * j), vec0); | ||||
} | |||||
} | } | ||||
#endif | #endif | ||||
} | |||||
void CModelDef::BlendBoneMatrices( | void CModelDef::BlendBoneMatrices( | ||||
CMatrix3D boneMatrices[]) | CMatrix3D boneMatrices[]) | ||||
{ | { | ||||
for (size_t i = 0; i < m_NumBlends; ++i) | for (size_t i = 0; i < m_NumBlends; ++i) | ||||
{ | { | ||||
const SVertexBlend& blend = m_pBlends[i]; | const SVertexBlend& blend = m_pBlends[i]; | ||||
CMatrix3D& boneMatrix = boneMatrices[m_NumBones + 1 + i]; | CMatrix3D& boneMatrix = boneMatrices[m_NumBones + 1 + i]; | ||||
▲ Show 20 Lines • Show All 253 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
RenderDataMap::const_iterator it = m_RenderData.find(key); | RenderDataMap::const_iterator it = m_RenderData.find(key); | ||||
if (it != m_RenderData.end()) | if (it != m_RenderData.end()) | ||||
return it->second; | return it->second; | ||||
return 0; | return 0; | ||||
} | } | ||||
void ModelDefActivateFastImpl() | |||||
{ | |||||
#if COMPILER_HAS_SSE | |||||
if (HostHasSSE()) | |||||
{ | |||||
CModelDef::SkinPointsAndNormals = SkinPointsAndNormalsSSE; | |||||
return; | |||||
} | |||||
#endif | |||||
CModelDef::SkinPointsAndNormals = SkinPointsAndNormalsFallback; | |||||
} |
Wildfire Games · Phabricator
Might want to change to PS::span in the future.