1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "nel/3d/skeleton_shape.h"
20 #include "nel/3d/skeleton_model.h"
21 #include "nel/3d/scene.h"
22 #include "nel/misc/bsphere.h"
25 using namespace NLMISC
;
35 // ***************************************************************************
36 void CSkeletonShape::CLod::serial(NLMISC::IStream
&f
)
38 (void)f
.serialVersion(0);
41 f
.serialCont(ActiveBones
);
45 // ***************************************************************************
46 CSkeletonShape::CSkeletonShape()
48 // By default for now....
49 // Temp. Have a huge BBox, so clip badly.
50 _BBox
.setCenter(CVector(0,0,1.5));
51 _BBox
.setSize(CVector(3,3,3));
55 // ***************************************************************************
56 sint32
CSkeletonShape::getBoneIdByName(const std::string
&name
) const
58 std::map
<std::string
, uint32
>::const_iterator it
= _BoneMap
.find(name
);
59 if(it
==_BoneMap
.end())
66 // ***************************************************************************
67 void CSkeletonShape::build(const std::vector
<CBoneBase
> &bones
)
75 for(i
=0;i
<_Bones
.size();i
++)
78 _BoneMap
[_Bones
[i
].Name
]= i
;
79 // validate distances.
80 _Bones
[i
].LodDisableDistance
= max(0.f
, _Bones
[i
].LodDisableDistance
);
83 sint32 fatherId
= _Bones
[i
].FatherId
;
84 // if father exist and is not "always enabled"
85 if(fatherId
>=0 && _Bones
[fatherId
].LodDisableDistance
!=0)
87 float fatherDist
= _Bones
[fatherId
].LodDisableDistance
;
88 // I must disable me at least before my father (never after).
89 if(_Bones
[i
].LodDisableDistance
==0)
90 _Bones
[i
].LodDisableDistance
= fatherDist
;
92 _Bones
[i
].LodDisableDistance
= min(_Bones
[i
].LodDisableDistance
, fatherDist
);
96 // build Lod Information.
100 // build all distances used.
102 for(i
=0;i
<_Bones
.size();i
++)
104 float dist
= _Bones
[i
].LodDisableDistance
;
105 // if lod enabled for this bone, add a new distance, or do nothing
107 distSet
.insert(dist
);
110 // create a lod for each distance used + 1 (the "dist==0" distance).
111 _Lods
.resize(distSet
.size() + 1);
112 // create the default lod: all bones activated.
114 _Lods
[0].ActiveBones
.resize(_Bones
.size(), 0xFF);
116 // For each lods not 0th.
117 set
<float>::iterator it
= distSet
.begin();
118 for(uint j
=1; j
<_Lods
.size(); j
++, it
++)
121 // set the distance of activation
122 _Lods
[j
].Distance
= lodDist
;
123 // resize and default to all enabled.
124 _Lods
[j
].ActiveBones
.resize(_Bones
.size(), 0xFF);
126 // Search what lod are to be disabled at this distance.
127 for(i
=0;i
<_Bones
.size();i
++)
129 float dist
= _Bones
[i
].LodDisableDistance
;
130 // if the dist of the lod is greater (or equal) to the disableDist of the bone,
131 // and if the bone is not "always enabled", disable the bone
132 if(lodDist
>=dist
&& dist
!=0 )
133 _Lods
[j
].ActiveBones
[i
]= 0;
141 // ***************************************************************************
142 void CSkeletonShape::retrieve(std::vector
<CBoneBase
> &bones
) const
148 // ***************************************************************************
149 CTransformShape
*CSkeletonShape::createInstance(CScene
&scene
)
151 // Create a CSkeletonModel, an instance of a mesh.
152 //===============================================
153 CSkeletonModel
*sm
= (CSkeletonModel
*)scene
.createModel(NL3D::SkeletonModelId
);
158 sm
->Bones
.reserve(_Bones
.size());
159 for(sint i
=0;i
<(sint
)_Bones
.size();i
++)
161 // Append a new bone.
162 sm
->Bones
.push_back( CBone(&_Bones
[i
]) );
164 // Must set the Animatable father of the bone (the skeleton model!).
165 sm
->Bones
[i
].setFather(sm
, CSkeletonModel::OwnerBit
);
168 // Must create and init skeleton bone usage to 0.
169 sm
->initBoneUsages();
171 // For skinning: setup skeleton in Skin LoadBalancing group
172 sm
->setLoadBalancingGroup("Skin");
177 // ***************************************************************************
178 void CSkeletonShape::serial(NLMISC::IStream
&f
)
184 sint ver
= f
.serialVersion(1);
186 f
.serialCont(_Bones
);
187 f
.serialCont(_BoneMap
);
193 // create a skeleton shape with bones activated all the time
195 // create the default lod: all bones activated.
197 _Lods
[0].ActiveBones
.resize(_Bones
.size(), 0xFF);
201 // ***************************************************************************
203 float CSkeletonShape::getNumTriangles (float distance
)
210 // ***************************************************************************
211 bool CSkeletonShape::clip(const std::vector
<CPlane
> &pyramid
, const CMatrix
&worldMatrix
)
213 // Speed Clip: clip just the sphere.
214 CBSphere
localSphere(_BBox
.getCenter(), _BBox
.getRadius());
215 CBSphere worldSphere
;
217 // transform the sphere in WorldMatrix (with nearly good scale info).
218 localSphere
.applyTransform(worldMatrix
, worldSphere
);
220 // if out of only plane, entirely out.
221 for(sint i
=0;i
<(sint
)pyramid
.size();i
++)
223 // We are sure that pyramid has normalized plane normals.
224 // if SpherMax OUT return false.
225 float d
= pyramid
[i
]*worldSphere
.Center
;
226 if(d
>worldSphere
.Radius
)
234 // ***************************************************************************
235 void CSkeletonShape::getAABBox(NLMISC::CAABBox
&bbox
) const
241 // ***************************************************************************
242 uint
CSkeletonShape::getLodForDistance(float dist
) const
245 uint end
= (uint
)_Lods
.size();
246 // find lower_bound by dichotomy
249 uint pivot
= (end
+start
)/2;
250 // return the lower_bound, ie return first start with _Lods[pivot].Distance<=dist
251 if(_Lods
[pivot
].Distance
<= dist
)