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/mesh_morpher.h"
20 #include "nel/3d/vertex_buffer.h"
21 #include "nel/3d/raw_skin.h"
25 using namespace NLMISC
;
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);
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 * ***********************************************/
74 // ***************************************************************************
75 void CMeshMorpher::init (CVertexBuffer
*vbOri
, CVertexBuffer
*vbDst
, bool hasTgSpace
)
79 _UseTgSpace
= hasTgSpace
;
82 // ***************************************************************************
83 void CMeshMorpher::initSkinned (CVertexBuffer
*vbOri
,
86 std::vector
<CVector
> *vVertices
,
87 std::vector
<CVector
> *vNormals
,
88 std::vector
<CVector
> *vTgSpace
, /* NULL if none */
93 _UseTgSpace
= hasTgSpace
;
95 _Vertices
= vVertices
;
98 _SkinApplied
= bSkinApplied
;
101 // ***************************************************************************
102 void CMeshMorpher::update (std::vector
<CAnimatedMorph
> *pBSFactor
)
108 if (BlendShapes
.empty())
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)
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;
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)
160 for (j
= 0; j
< rBS
.VertRefs
.size(); ++j
)
162 uint32 vp
= rBS
.VertRefs
[j
];
164 // Modify Pos/Norm/TgSpace.
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
;
181 if (!rBS
.deltaTgSpace
.empty())
183 CVector
*pV
= (CVector
*)dstvba
.getTexCoordPointer (vp
, tgSpaceStage
);
184 *pV
+= rBS
.deltaTgSpace
[j
] * rFactor
;
187 // Modify UV0 / Color
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
);
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
);
214 _Flags
[vp
] = Modified
;
220 // ***************************************************************************
221 void CMeshMorpher::updateSkinned (std::vector
<CAnimatedMorph
> *pBSFactor
)
227 if (BlendShapes
.empty())
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)
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());
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
;
288 for (j
= 0; j
< rBS
.VertRefs
.size(); ++j
)
290 uint32 vp
= rBS
.VertRefs
[j
];
292 // Modify Pos/Norm/TgSpace.
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
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
);
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
);
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
)
374 if (BlendShapes
.empty())
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
)
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
;
402 // Blending with blendshape
403 for (i
= 0; i
< BlendShapes
.size(); ++i
)
405 CBlendShape
&rBS
= BlendShapes
[i
];
406 float rFactor
= pBSFactor
->operator[](i
).getFactor();
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
428 rsVert
->Pos
+= rBS
.deltaPos
[j
] * rFactor
;
430 rsVert
->Normal
+= rBS
.deltaNorm
[j
] * rFactor
;
432 rsVert
->UV
+= rBS
.deltaUV
[j
] * rFactor
;