Merge branch 'ryzom/ark-features' into main/gingo-test
[ryzomcore.git] / nel / src / 3d / mesh_morpher.cpp
blobd546bc97dd0319e54dda4485595ea57f8829ed88
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
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.
8 //
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/>.
17 #include "std3d.h"
19 #include "nel/3d/mesh_morpher.h"
20 #include "nel/3d/vertex_buffer.h"
21 #include "nel/3d/raw_skin.h"
24 using namespace std;
25 using namespace NLMISC;
27 #ifdef DEBUG_NEW
28 #define new DEBUG_NEW
29 #endif
31 namespace NL3D
34 // ***************************************************************************
35 void CBlendShape::serial (NLMISC::IStream &f)
37 /* ***********************************************
38 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
39 * It can be loaded/called through CAsyncFileManager for instance
40 * ***********************************************/
42 // version 1 : added tangent space support
43 sint ver = f.serialVersion (1);
45 f.serial (Name);
47 f.serialCont (deltaPos);
48 f.serialCont (deltaNorm);
49 f.serialCont (deltaUV);
50 f.serialCont (deltaCol);
52 if (ver >= 1) f.serialCont(deltaTgSpace);
54 f.serialCont (VertRefs);
57 // ***************************************************************************
58 CMeshMorpher::CMeshMorpher()
60 /* ***********************************************
61 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
62 * It can be loaded/called through CAsyncFileManager for instance
63 * ***********************************************/
65 _VBOri = NULL;
66 _VBDst = NULL;
68 _Vertices = NULL;
69 _Normals = NULL;
70 _TgSpace= NULL;
71 _SkinApplied= false;
74 // ***************************************************************************
75 void CMeshMorpher::init (CVertexBuffer *vbOri, CVertexBuffer *vbDst, bool hasTgSpace)
77 _VBOri = vbOri;
78 _VBDst = vbDst;
79 _UseTgSpace = hasTgSpace;
82 // ***************************************************************************
83 void CMeshMorpher::initSkinned (CVertexBuffer *vbOri,
84 CVertexBuffer *vbDst,
85 bool hasTgSpace,
86 std::vector<CVector> *vVertices,
87 std::vector<CVector> *vNormals,
88 std::vector<CVector> *vTgSpace, /* NULL if none */
89 bool bSkinApplied )
91 _VBOri = vbOri;
92 _VBDst = vbDst;
93 _UseTgSpace = hasTgSpace;
95 _Vertices = vVertices;
96 _Normals = vNormals;
97 _TgSpace = vTgSpace;
98 _SkinApplied = bSkinApplied;
101 // ***************************************************************************
102 void CMeshMorpher::update (std::vector<CAnimatedMorph> *pBSFactor)
104 uint32 i, j;
106 if (_VBOri == NULL)
107 return;
108 if (BlendShapes.empty())
109 return;
111 if (_VBOri->getNumVertices() != _VBDst->getNumVertices())
112 { // Because the original vertex buffer is not initialized by default
113 // we must init it here (if there are some blendshapes)
114 *_VBOri = *_VBDst;
117 // Does the flags are reserved ?
118 if (_Flags.size() != _VBOri->getNumVertices())
120 _Flags.resize (_VBOri->getNumVertices());
121 for (i = 0; i < _Flags.size(); ++i)
122 _Flags[i] = Modified; // Modified to update all
125 nlassert(_VBOri->getVertexFormat() == _VBDst->getVertexFormat());
127 // Cleaning with original vertex buffer
128 uint32 VBVertexSize = _VBOri->getVertexSize();
129 CVertexBufferRead srcvba;
130 _VBOri->lock (srcvba);
131 CVertexBufferReadWrite dstvba;
132 _VBDst->lock (dstvba);
133 const uint8 *pOri = (const uint8*)srcvba.getVertexCoordPointer ();
134 uint8 *pDst = (uint8*)dstvba.getVertexCoordPointer ();
136 for (i= 0; i < _Flags.size(); ++i)
137 if (_Flags[i] >= Modified)
139 _Flags[i] = OriginalVBDst;
141 for(j = 0; j < VBVertexSize; ++j)
142 pDst[j+i*VBVertexSize] = pOri[j+i*VBVertexSize];
145 uint tgSpaceStage = 0;
146 if (_UseTgSpace)
148 tgSpaceStage = _VBDst->getNumTexCoordUsed() - 1;
151 // Blending with blendshape
152 for (i = 0; i < BlendShapes.size(); ++i)
154 CBlendShape &rBS = BlendShapes[i];
155 float rFactor = pBSFactor->operator[](i).getFactor()/100.0f;
157 // todo hulud check it works
158 // if (rFactor > 0.0f)
159 if (rFactor != 0.0f)
160 for (j = 0; j < rBS.VertRefs.size(); ++j)
162 uint32 vp = rBS.VertRefs[j];
164 // Modify Pos/Norm/TgSpace.
165 //------------
166 if (_VBDst->getVertexFormat() & CVertexBuffer::PositionFlag)
167 if (!rBS.deltaPos.empty())
169 CVector *pV = dstvba.getVertexCoordPointer (vp);
170 *pV += rBS.deltaPos[j] * rFactor;
173 if (_VBDst->getVertexFormat() & CVertexBuffer::NormalFlag)
174 if (!rBS.deltaNorm.empty())
176 CVector *pV = dstvba.getNormalCoordPointer (vp);
177 *pV += rBS.deltaNorm[j] * rFactor;
180 if (_UseTgSpace)
181 if (!rBS.deltaTgSpace.empty())
183 CVector *pV = (CVector*)dstvba.getTexCoordPointer (vp, tgSpaceStage);
184 *pV += rBS.deltaTgSpace[j] * rFactor;
187 // Modify UV0 / Color
188 //------------
189 if (_VBDst->getVertexFormat() & CVertexBuffer::TexCoord0Flag)
190 if (!rBS.deltaUV.empty())
192 CUV *pUV = dstvba.getTexCoordPointer (vp);
193 *pUV += rBS.deltaUV[j] * rFactor;
196 if (_VBDst->getVertexFormat() & CVertexBuffer::PrimaryColorFlag)
197 if (!rBS.deltaCol.empty())
199 // todo hulud d3d vertex color RGBA / BGRA
200 CRGBA *pRGBA = (CRGBA*)dstvba.getColorPointer (vp);
201 CRGBAF rgbf(*pRGBA);
202 rgbf.R += rBS.deltaCol[j].R * rFactor;
203 rgbf.G += rBS.deltaCol[j].G * rFactor;
204 rgbf.B += rBS.deltaCol[j].B * rFactor;
205 rgbf.A += rBS.deltaCol[j].A * rFactor;
206 clamp(rgbf.R, 0.0f, 1.0f);
207 clamp(rgbf.G, 0.0f, 1.0f);
208 clamp(rgbf.B, 0.0f, 1.0f);
209 clamp(rgbf.A, 0.0f, 1.0f);
210 *pRGBA = rgbf;
213 // Modified
214 _Flags[vp] = Modified;
220 // ***************************************************************************
221 void CMeshMorpher::updateSkinned (std::vector<CAnimatedMorph> *pBSFactor)
223 uint32 i, j;
225 if (_VBOri == NULL)
226 return;
227 if (BlendShapes.empty())
228 return;
230 if (_VBOri->getNumVertices() != _VBDst->getNumVertices())
231 { // Because the original vertex buffer is not initialized by default
232 // we must init it here (if there are some blendshapes)
233 *_VBOri = *_VBDst;
236 // Does the flags are reserved ?
237 if (_Flags.size() != _VBOri->getNumVertices())
239 _Flags.resize (_VBOri->getNumVertices());
240 for (i = 0; i < _Flags.size(); ++i)
241 _Flags[i] = Modified; // Modified to update all
244 nlassert(_VBOri->getVertexFormat() == _VBDst->getVertexFormat());
246 uint tgSpaceStage;
247 uint tgSpaceOff = 0;
248 if (_UseTgSpace && _TgSpace)
250 tgSpaceStage = _VBDst->getNumTexCoordUsed() - 1;
251 tgSpaceOff = _VBDst->getTexCoordOff(tgSpaceStage);
254 // Cleaning with original vertex buffer
255 uint32 VBVertexSize = _VBOri->getVertexSize();
256 CVertexBufferRead srcvba;
257 _VBOri->lock (srcvba);
258 CVertexBufferReadWrite dstvba;
259 _VBDst->lock (dstvba);
260 const uint8 *pOri = (const uint8*)srcvba.getVertexCoordPointer ();
261 uint8 *pDst = (uint8*)dstvba.getVertexCoordPointer ();
263 for (i= 0; i < _Flags.size(); ++i)
264 if (_Flags[i] >= Modified)
266 for(j = 0; j < VBVertexSize; ++j)
267 pDst[j+i*VBVertexSize] = pOri[j+i*VBVertexSize];
269 if (_Vertices != NULL)
270 _Vertices->operator[](i) = ((CVector*)(pOri+i*VBVertexSize))[0];
272 if (_Normals != NULL)
273 _Normals->operator[](i) = ((CVector*)(pOri+i*VBVertexSize))[1];
275 if (_TgSpace != NULL)
276 (*_TgSpace)[i] = * (CVector*)(pOri + i * VBVertexSize + tgSpaceOff);
278 _Flags[i] = OriginalVBDst;
281 // Blending with blendshape
282 for (i = 0; i < BlendShapes.size(); ++i)
284 CBlendShape &rBS = BlendShapes[i];
285 float rFactor = pBSFactor->operator[](i).getFactor()/100.0f;
287 if (rFactor != 0.0f)
288 for (j = 0; j < rBS.VertRefs.size(); ++j)
290 uint32 vp = rBS.VertRefs[j];
292 // Modify Pos/Norm/TgSpace.
293 //------------
294 if (_Vertices != NULL)
295 if (!rBS.deltaPos.empty())
297 CVector *pV = &(_Vertices->operator[](vp));
298 *pV += rBS.deltaPos[j] * rFactor;
301 if (_Normals != NULL)
302 if (!rBS.deltaNorm.empty())
304 CVector *pV = &(_Normals->operator[](vp));
305 *pV += rBS.deltaNorm[j] * rFactor;
308 if (_UseTgSpace && _TgSpace != NULL)
309 if (!rBS.deltaTgSpace.empty())
311 CVector *pV = &((*_TgSpace)[vp]);
312 *pV += rBS.deltaTgSpace[j] * rFactor;
315 // Modify UV0 / Color
316 //------------
317 if (_VBDst->getVertexFormat() & CVertexBuffer::TexCoord0Flag)
318 if (!rBS.deltaUV.empty())
320 CUV *pUV = dstvba.getTexCoordPointer (vp);
321 *pUV += rBS.deltaUV[j] * rFactor;
324 if (_VBDst->getVertexFormat() & CVertexBuffer::PrimaryColorFlag)
325 if (!rBS.deltaCol.empty())
327 // todo hulud d3d vertex color RGBA / BGRA
328 CRGBA *pRGBA = (CRGBA*)dstvba.getColorPointer (vp);
329 CRGBAF rgbf(*pRGBA);
330 rgbf.R += rBS.deltaCol[j].R * rFactor;
331 rgbf.G += rBS.deltaCol[j].G * rFactor;
332 rgbf.B += rBS.deltaCol[j].B * rFactor;
333 rgbf.A += rBS.deltaCol[j].A * rFactor;
334 clamp(rgbf.R, 0.0f, 1.0f);
335 clamp(rgbf.G, 0.0f, 1.0f);
336 clamp(rgbf.B, 0.0f, 1.0f);
337 clamp(rgbf.A, 0.0f, 1.0f);
338 *pRGBA = rgbf;
341 // Modified
342 _Flags[vp] = Modified;
347 // ***************************************************************************
348 void CMeshMorpher::serial (NLMISC::IStream &f)
350 /* ***********************************************
351 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
352 * It can be loaded/called through CAsyncFileManager for instance
353 * ***********************************************/
355 (void)f.serialVersion (0);
357 f.serialCont (BlendShapes);
361 // ***************************************************************************
362 #define NL3D_RAWSKIN_NORMAL_OFF 12
363 #define NL3D_RAWSKIN_UV_OFF 24
364 #define NL3D_RAWSKIN_VERTEX_SIZE 32
366 void CMeshMorpher::updateRawSkin (CVertexBuffer *vbOri,
367 NLMISC::CObjectVector<CRawSkinVertex*, false> &vertexRemap,
368 std::vector<CAnimatedMorph> *pBSFactor)
370 uint32 i, j;
372 if (vbOri == NULL)
373 return;
374 if (BlendShapes.empty())
375 return;
377 nlassert(vbOri->getVertexFormat() == (CVertexBuffer::PositionFlag | CVertexBuffer::NormalFlag |CVertexBuffer::TexCoord0Flag) );
378 nlassert(NL3D_RAWSKIN_VERTEX_SIZE == vbOri->getVertexSize());
379 nlassert(NL3D_RAWSKIN_NORMAL_OFF == vbOri->getNormalOff());
380 nlassert(NL3D_RAWSKIN_UV_OFF == vbOri->getTexCoordOff(0));
382 // Cleaning with original vertex buffer
383 CVertexBufferRead srcvba;
384 vbOri->lock (srcvba);
385 const uint8 *pOri = (const uint8*)srcvba.getVertexCoordPointer ();
386 CRawSkinVertex **vRemap= vertexRemap.getPtr();
387 uint numVertices= vbOri->getNumVertices();
389 // Update only the vertices of this lod
390 for (i= 0; i < numVertices; ++i)
392 if(*vRemap)
394 (*vRemap)->Pos= *(CVector*)(pOri);
395 (*vRemap)->Normal= *(CVector*)(pOri + NL3D_RAWSKIN_NORMAL_OFF);
396 (*vRemap)->UV= *(CUV*)(pOri + NL3D_RAWSKIN_UV_OFF);
398 pOri+= NL3D_RAWSKIN_VERTEX_SIZE;
399 vRemap++;
402 // Blending with blendshape
403 for (i = 0; i < BlendShapes.size(); ++i)
405 CBlendShape &rBS = BlendShapes[i];
406 float rFactor = pBSFactor->operator[](i).getFactor();
408 if (rFactor != 0.0f)
410 rFactor*= 0.01f;
411 uint32 numVertices= (uint32)rBS.VertRefs.size();
412 // don't know why, but cases happen where deltaNorm not empty while deltaPos is
413 bool hasPos = !rBS.deltaPos.empty();
414 bool hasNorm = !rBS.deltaNorm.empty();
415 bool hasUV = !rBS.deltaUV.empty();
417 for (j = 0; j < numVertices; ++j)
419 // Get the vertex Index in the VBufferFinal
420 uint vid= rBS.VertRefs[j];
421 // Then get the RawSkin vertex to modify
422 CRawSkinVertex *rsVert= vertexRemap[vid];
424 // If exist in this Lod RawSkin, apply
425 if(rsVert)
427 if(hasPos)
428 rsVert->Pos+= rBS.deltaPos[j] * rFactor;
429 if(hasNorm)
430 rsVert->Normal+= rBS.deltaNorm[j] * rFactor;
431 if(hasUV)
432 rsVert->UV+= rBS.deltaUV[j] * rFactor;
442 } // NL3D