-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathCrySkinBasisBuilder.cpp
168 lines (142 loc) · 4.75 KB
/
CrySkinBasisBuilder.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#include "stdafx.h"
#include "CrySkinRigidBasis.h"
#include "CrySkinBasisBuilder.h"
CrySkinBasisBuilder::CrySkinBasisBuilder (const ICrySkinSource* pGeometry, const Matrix44* pMatInvDef, unsigned numBoneInfos):
CrySkinBuilderBase0 (pGeometry),
m_pMatInvDef(pMatInvDef),
m_numBoneInfos (numBoneInfos),
m_nDestIntervalBegin (0),
m_nDestIntervalEnd (0),
m_numBones (0),
m_nFirstBone (0)
{
}
//////////////////////////////////////////////////////////////////////////
// sets the destination vertex interval to operate on. Initially, this is infinity.
// The destination vertex interval is the interval within which the destination vertex
// index must lie in order to be skinned. The base of the interval is considered
// vertex 0 in the produced skinner
void CrySkinBasisBuilder::setDestinationInterval (unsigned nBegin, unsigned nEnd)
{
if (nEnd > m_pGeometry->numExtTangents())
nEnd = m_pGeometry->numExtTangents();
if (nBegin < nEnd)
{
m_nDestIntervalBegin = nBegin;
m_nDestIntervalEnd = nEnd;
preprocess();
makeBoneBases ();
}
else
{
m_nDestIntervalBegin = 0;
m_nDestIntervalEnd = 0;
m_numBones = 0;
m_nFirstBone = 0;
}
}
// initializes the given rigid basis builder
void CrySkinBasisBuilder::initRigidBasisSkin (CrySkinRigidBasis* pSkin)
{
assert (sizeof(SPipTangentsA16)==0x30);
unsigned numAuxInts = 2 * (m_numBones-m_nFirstBone);
unsigned numBases = m_nDestIntervalEnd-m_nDestIntervalBegin;
pSkin->init (2 * numBases, numAuxInts, m_nFirstBone, m_numBones);
CrySkinStreams stream, streamBegin, streamEnd;
streamBegin.pAux = pSkin->m_arrAux.begin();
streamBegin.pVert = pSkin->m_arrVertices.begin();
stream = streamBegin;
streamEnd.pAux = streamBegin.pAux + numAuxInts;
streamEnd.pVert = streamBegin.pVert + 2 * numBases;
for (unsigned nBone = m_nFirstBone; nBone < m_numBones; ++nBone)
{
// for each bone, fill the three groups
// we fill the left and right vertices
fillGroup (stream, m_arrBoneBases[nBone].arrRight);
assert (stream.pAux <= streamEnd.pAux);
assert (stream.pVert <= streamEnd.pVert);
fillGroup (stream, m_arrBoneBases[nBone].arrLeft);
// only when we processed the last bone, we should have the pAux pointing to the end
assert (stream.pAux <= streamEnd.pAux);
assert (stream.pVert <= streamEnd.pVert);
}
}
void clipDenormal (float& x)
{
if (x > -1e-4 && x < 1e-4)
x = 0;
}
void clipDenormals(Vec3d& v)
{
clipDenormal(v.x);
clipDenormal(v.y);
clipDenormal(v.z);
}
// makes up the basis array
void CrySkinBasisBuilder::makeBoneBases ()
{
const unsigned* pExtToInt = m_pGeometry->getExtToIntMapEntries();
m_arrBoneBases.clear();
m_arrBoneBases.resize (m_numBones);
unsigned i;
// preallocate for push_back
for (i = 0; i < m_numBones; ++i)
m_arrBoneBases[i].reserve (m_nDestIntervalEnd / m_numBones);
for (i = m_nDestIntervalBegin; i < m_nDestIntervalEnd; ++i)
{
unsigned nGeomVert = pExtToInt[i];
TangData rBasis = m_pGeometry->getExtTangent (i);
clipDenormals(rBasis.binormal);
clipDenormals(rBasis.tangent);
const CryVertexBinding& rLink = m_pGeometry->getLink(nGeomVert);
unsigned nBone = rLink[0].BoneID;
assert (nBone < m_numBoneInfos);
CrySkinRigidBasisArray* pTargetArray;
if ((rBasis.tangent ^ rBasis.binormal)*rBasis.tnormal > 0)
pTargetArray = &m_arrBoneBases[nBone].arrRight;
else
pTargetArray = &m_arrBoneBases[nBone].arrLeft;
const Matrix44& matInvDef = m_pMatInvDef[nBone];
pTargetArray->push_back(CrySkinRigidBaseInfo (matInvDef,rBasis,i-m_nDestIntervalBegin));
}
}
//////////////////////////////////////////////////////////////////////////
// calculate the number of used bones and the skip-bone
void CrySkinBasisBuilder::preprocess()
{
unsigned numTangents = m_pGeometry->numExtTangents();
const unsigned* pExtToInt = m_pGeometry->getExtToIntMapEntries();
m_numBones = 0;
m_nFirstBone = 0;
bool bNotInited = true;
for (unsigned i = m_nDestIntervalBegin; i < min(m_nDestIntervalEnd,numTangents); ++i)
{
unsigned nGeomVert = pExtToInt[i];
const CryVertexBinding& rLink = m_pGeometry->getLink(nGeomVert);
unsigned nBone = rLink[0].BoneID;
if (bNotInited)
{
m_nFirstBone = nBone;
m_numBones = nBone+1;
bNotInited = false;
}
else
{
m_nFirstBone = min (m_nFirstBone, nBone);
m_numBones = max (nBone+1, m_numBones);
}
}
}
// fills the given bases to the simple stream
typedef std::vector< CrySkinRigidBaseInfo > CrySkinRigidBasisArray;
void CrySkinBasisBuilder::fillGroup (CrySkinStreams& streams, const CrySkinRigidBasisArray& arrBases)
{
// the group header is the number of vertices in the group
*streams.pAux++ = (CrySkinAuxInt)arrBases.size();
CrySkinRigidBasisArray::const_iterator it = arrBases.begin(), itEnd = it + arrBases.size();
for (; it != itEnd; ++it)
{
it->build(streams.pVert);
streams.pVert += 2;
}
}