Update contrib.
2 * Copyright (c) 2003 Nokia Corporation and/or its subsidiary(-ies).
4 * This component and the accompanying materials are made available
5 * under the terms of the License "Eclipse Public License v1.0"
6 * which accompanies this distribution, and is available
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
9 * Initial Contributors:
10 * Nokia Corporation - initial contribution.
14 * Description: SkinnedMesh implementation
22 * \brief SkinnedMesh implementation
25 #ifndef M3G_CORE_INCLUDE
26 # error included by m3g_core.c; do not compile separately.
29 #include "m3g_skinnedmesh.h"
30 #include "m3g_memory.h"
31 #include "m3g_animationtrack.h"
33 /*----------------------------------------------------------------------
35 *--------------------------------------------------------------------*/
41 /*! \internal \brief "At-rest" transformation from skinned mesh to bone */
44 /*! \internal \brief Cached animated transformation for positions */
45 M3Gshort baseMatrix[9];
47 M3Gshort baseExp, posExp, maxExp;
49 /*! \internal \brief Cached animated transformation for normals */
50 M3Gshort normalMatrix[9];
53 /*----------------------------------------------------------------------
55 *--------------------------------------------------------------------*/
59 * \brief Destroys this SkinnedMesh object.
61 * \param obj SkinnedMesh object
63 static void m3gDestroySkinnedMesh(Object *obj)
65 SkinnedMesh *mesh = (SkinnedMesh *) obj;
66 M3G_VALIDATE_OBJECT(mesh);
69 Interface *m3g = M3G_INTERFACE(mesh);
71 m3gDeleteVertexBuffer(mesh->morphedVB);
73 for (i = 0; i < mesh->bonesPerVertex; ++i) {
74 m3gFree(m3g, mesh->boneIndices[i]);
75 m3gFree(m3g, mesh->boneWeights[i]);
76 m3gFree(m3g, mesh->normalizedWeights[i]);
78 m3gFree(m3g, mesh->weightShifts);
80 for (i = 0; i < m3gArraySize(&mesh->bones); ++i) {
81 m3gFree(m3g, m3gGetArrayElement(&mesh->bones, i));
83 m3gDestroyArray(&mesh->bones, m3g);
85 if (mesh->skeleton != NULL) {
86 m3gSetParent((Node*) mesh->skeleton, NULL);
87 M3G_ASSIGN_REF(mesh->skeleton, NULL);
96 * \brief Get a bone index for a given node
98 * This finds an existing record if the bone has been added
99 * previously, or creates a new one if no record exists yet.
101 * \note Inline because only called from AddTransform.
103 static M3G_INLINE M3Gint m3gBoneIndex(SkinnedMesh *mesh, Node *node)
105 PointerArray *boneArray = &mesh->bones;
106 const int numBones = m3gArraySize(boneArray);
108 /* First look for an existing record in the array */
112 for (i = 0; i < numBones; ++i) {
113 Bone *b = m3gGetArrayElement(boneArray, i);
114 if (b->node == node) {
120 /* Not found; create a new one, append to the array, and set up
121 * the "at-rest" transformation for the bone. Note, however, that
122 * we can only store a maximum of 256 bones with byte indices! */
124 Interface *m3g = M3G_INTERFACE(mesh);
126 if (numBones >= 256) {
127 /* Out of available bone indices */
128 m3gRaiseError(m3g, M3G_OUT_OF_MEMORY);
133 Bone *bone = (Bone*) m3gAllocZ(m3g, sizeof(Bone));
134 if (!bone || !m3gGetTransformTo((Node*) mesh, node,
137 return -1; /* out of memory or singular transform */
141 idx = m3gArrayAppend(boneArray, bone, m3g);
144 return -1; /* out of memory */
153 * \brief Reallocate the per-vertex data if necessary.
155 * \note Inline because only called from AddTransform.
157 static M3G_INLINE M3Gbool m3gEnsureVertexCount(SkinnedMesh *mesh, M3Gint count)
159 /* Reallocate only if vertex count increased */
161 if (count > mesh->weightedVertexCount) {
163 Interface *m3g = M3G_INTERFACE(mesh);
167 /* Reallocate the weight shift array */
169 M3Gubyte *pNew = (M3Gubyte*) m3gAllocZ(m3g, count);
173 m3gCopy(pNew, mesh->weightShifts, mesh->weightedVertexCount);
174 m3gFree(m3g, mesh->weightShifts);
175 mesh->weightShifts = pNew;
178 /* Reallocate each of the bone index and weight arrays */
180 for (i = 0; i < mesh->bonesPerVertex; ++i) {
185 pNew = (M3Gubyte*) m3gAllocZ(m3g, count);
187 return M3G_FALSE; /* out of memory */
189 m3gCopy(pNew, mesh->boneWeights[i], mesh->weightedVertexCount);
190 m3gFree(m3g, mesh->boneWeights[i]);
191 mesh->boneWeights[i] = pNew;
193 pNew = (M3Gubyte*) m3gAllocZ(m3g, count);
195 return M3G_FALSE; /* out of memory */
197 m3gCopy(pNew, mesh->normalizedWeights[i],
198 mesh->weightedVertexCount);
199 m3gFree(m3g, mesh->normalizedWeights[i]);
200 mesh->normalizedWeights[i] = pNew;
203 pNew = (M3Gubyte*) m3gAllocZ(m3g, count);
205 return M3G_FALSE; /* out of memory */
207 m3gCopy(pNew, mesh->boneIndices[i], mesh->weightedVertexCount);
208 m3gFree(m3g, mesh->boneIndices[i]);
209 mesh->boneIndices[i] = pNew;
212 mesh->weightedVertexCount = count;
219 * \brief Reallocate the per-vertex data if necessary.
221 * \note Inline because only called from AddTransform.
223 static M3G_INLINE M3Gbool m3gEnsureBonesPerVertex(SkinnedMesh *mesh,
226 M3G_ASSERT(count <= M3G_MAX_VERTEX_TRANSFORMS);
228 /* Allocate only if per-vertex bone count increased */
230 if (count > mesh->bonesPerVertex) {
232 Interface *m3g = M3G_INTERFACE(mesh);
234 const M3Gint vertexCount = mesh->weightedVertexCount;
239 /* Allocate new arrays for bone indices and weights until
242 for (i = mesh->bonesPerVertex; i < count; ++i) {
243 pNew = (M3Gubyte*) m3gAllocZ(m3g, vertexCount);
245 goto AllocFailed; /* out of memory */
247 mesh->boneIndices[i] = pNew;
249 pNew = (M3Gubyte*) m3gAllocZ(m3g, vertexCount);
251 goto AllocFailed; /* out of memory */
253 mesh->boneWeights[i] = pNew;
255 pNew = (M3Gubyte*) m3gAllocZ(m3g, vertexCount);
257 goto AllocFailed; /* out of memory */
259 mesh->normalizedWeights[i] = pNew;
262 mesh->bonesPerVertex = count;
265 /* In case of failure, clean up to keep the bonesPerVertex
266 * counter in sync with the actual number of arrays
270 for (i = mesh->bonesPerVertex; i < count; ++i) {
271 m3gFree(m3g, mesh->boneIndices[i]);
272 m3gFree(m3g, mesh->boneWeights[i]);
273 m3gFree(m3g, mesh->normalizedWeights[i]);
275 mesh->boneIndices[i] = NULL;
276 mesh->boneWeights[i] = NULL;
277 mesh->normalizedWeights[i] = NULL;
286 * \brief Add a new bone influence to a vertex
288 * If the target vertex is already affected by
289 * M3G_MAX_VERTEX_TRANSFORMS bones, the one with the lowest weight is
292 static M3G_INLINE void m3gAddInfluence(SkinnedMesh *mesh,
297 M3Gint bonesPerVertex = mesh->bonesPerVertex;
298 M3Guint minWeight = weight;
299 M3Gint minWeightIndex = -1;
302 /* Shift the weight into the same scale with the other weights for
305 weight >>= mesh->weightShifts[vertexIndex];
307 /* Look for an existing weight for our bone, or find the index
308 * with the lowest weight if not found, and store it in
309 * minWeightIndex. Note that we're not separately tagging indices
310 * as used/unused; unused ones will merely have a weight of
313 for (i = 0; i < bonesPerVertex; ++i) {
315 /* If we find an existing weight for our bone, just add to
316 * that and break out. Otherwise, keep track of the minimum
317 * weight encountered so far. */
319 if (mesh->boneIndices[i][vertexIndex] == boneIndex) {
320 weight += mesh->boneWeights[i][vertexIndex];
325 M3Guint tempWeight = mesh->boneWeights[i][vertexIndex];
326 if (tempWeight < minWeight) {
327 minWeight = tempWeight;
333 /* Check whether our total weight exceeds the allocated range,
334 * shifting all existing weights down if necessary */
336 while (weight >= (1 << 8)) { /* byte range */
338 mesh->weightShifts[vertexIndex] += 1;
339 for (i = 0; i < bonesPerVertex; ++i) {
340 mesh->boneWeights[i][vertexIndex] >>= 1;
342 M3G_ASSERT(mesh->weightShifts[vertexIndex] <= 31);
345 /* Add the index and weight contribution of the new
346 * transformation, provided that the minimum weight found was
347 * indeed smaller than the one we're adding */
349 if (minWeightIndex >= 0) {
350 mesh->boneIndices[minWeightIndex][vertexIndex] = (M3Gubyte) boneIndex;
351 mesh->boneWeights[minWeightIndex][vertexIndex] = (M3Gubyte) weight;
353 /* Need an update of the normalizing scales, too, as well as
354 * the actual transformed vertices */
356 mesh->weightsDirty = M3G_TRUE;
357 m3gInvalidateNode((Node*) mesh, NODE_TRANSFORMS_BIT|NODE_BBOX_BIT);
363 * \brief Computes the normalization scales for vertex weights
365 static void m3gNormalizeWeights(SkinnedMesh *mesh)
367 const M3Gint bonesPerVertex = mesh->bonesPerVertex;
368 const M3Gint vertexCount = mesh->weightedVertexCount;
371 for (vi = 0; vi < vertexCount; ++vi) {
374 /* Sum up the 8-bit (possibly downshifted) weights */
377 for (k = 0; k < bonesPerVertex; ++k) {
378 sum += mesh->boneWeights[k][vi];
381 /* Compute an 8.24 reciprocal of the weights, then scale with
382 * that to normalize, and shift to 1.7 fixed point */
384 M3Guint s = (sum > 0 ? (1U << 24) / sum : 0);
387 for (k = 0; k < bonesPerVertex; ++k) {
388 M3Guint normalized = (s * mesh->boneWeights[k][vi]) >> 17;
389 M3G_ASSERT(m3gInRange((M3Gint)normalized, 0, 128));
391 mesh->normalizedWeights[k][vi] = (M3Gubyte) normalized;
394 /* NOTE there is a maximum of ½ rounding error per
395 * component, plus the rounding error from the reciprocal
396 * calculation, so the sum of weights will often not sum
397 * to 128 exactly! We therefore only assert against
398 * clearly out-of-range values here */
400 M3G_ASSERT(sum == 0 || m3gInRange((M3Gint) sum, 96, 128));
404 mesh->weightsDirty = M3G_FALSE;
409 * \brief Computes an optimal exponent value for a fixed point
412 * This scales the translation exponent up to optimally utilize the
413 * 32-bit intermediate precision if the matrix exponent is smaller.
415 static M3Gint m3gOptimalExponent(M3Gint matrixExp, M3Gint transExp)
417 M3Gint maxExp = matrixExp;
418 M3Gint shift = transExp - matrixExp;
421 /* The matrix part will always occupy less than half of the
422 * available range if shifted down by at least one bit, so we
423 * can shift the translation up by a maximum of 15 bits. If
424 * the matrix is shifted by more than 31 bits, it will always
425 * flush to zero, freeing the full 32-bit range for the
426 * translation alone. */
428 if (shift >= 32) { /* matrix will flush to zero */
431 else if (shift >= 16) { /* matrix always < half of the range */
435 shift -= 1; /* shift matrix by at least one bit */
438 maxExp = transExp - shift;
441 M3G_ASSERT(maxExp >= matrixExp && maxExp >= transExp - 16);
446 * \brief Fixed point vertex transformation
448 * \param mtx pointer to a 3x3 16-bit matrix
449 * \param mtxExp exponent for the matrix elements (upshift from int)
450 * \param trans pointer to 3-element 16-bit translation vector
451 * \param transExp exponent for the translation vector
452 * \param maxExp precalculated "optimal" exponent
453 * \param vx vertex X coordinate (16-bit range)
454 * \param vy vertex Y coordinate (16-bit range)
455 * \param vz vertex Z coordinate (16-bit range)
456 * \param out output vertex, 25 bits of precision
457 * \return exponent value for \c out
459 static M3Gint m3gFixedPointTransform(const M3Gshort *mtx, M3Gint mtxExp,
460 const M3Gshort *trans, M3Gint transExp,
462 M3Gint vx, M3Gint vy, M3Gint vz,
466 M3Gint ox = 0, oy = 0, oz = 0;
468 /* First put in the translation part, upscaled to the optimal
469 * range for this bone */
472 shift = maxExp - (transExp - 16);
473 M3G_ASSERT(shift >= 0);
475 ox += ((M3Gint) trans[0] << 16) >> shift;
476 oy += ((M3Gint) trans[1] << 16) >> shift;
477 oz += ((M3Gint) trans[2] << 16) >> shift;
481 /* Add the input multiplied with the base 3x3 matrix and shifted
482 * to the "maxExp" scale, provided that it has any effect on the
485 shift = maxExp - mtxExp;
486 M3G_ASSERT(shift >= 0);
489 # if defined(M3G_DEBUG)
490 M3Gint iMin = (-1 << 31) + (65535 * 32768 >> shift);
491 M3Gint iMax = (M3Gint)((1u << 31)-1) - (65535 * 32768 >> shift);
492 M3G_ASSERT(m3gInRange(ox, iMin, iMax));
493 M3G_ASSERT(m3gInRange(oy, iMin, iMax));
494 M3G_ASSERT(m3gInRange(oz, iMin, iMax));
495 # endif /* M3G_DEBUG */
497 ox += (mtx[0] * vx + mtx[3] * vy + mtx[6] * vz) >> shift;
498 oy += (mtx[1] * vx + mtx[4] * vy + mtx[7] * vz) >> shift;
499 oz += (mtx[2] * vx + mtx[5] * vy + mtx[8] * vz) >> shift;
502 /* Shift the output down to fit into 25 bits; we're dropping 7
503 * bits of precision here, so adjust the exponent accordingly */
513 * \brief Applies scale and bias to a vertex
515 * This is required for vertices that have no bones attached.
517 * \param mesh the SkinnedMesh object
518 * \param vx vertex X coordinate (16-bit range)
519 * \param vy vertex Y coordinate (16-bit range)
520 * \param vz vertex Z coordinate (16-bit range)
521 * \param upshift scaling value for the input coordinates and the
522 * translation component of the transformation
523 * \param vertex output vertex position
524 * \return exponent value for \c vertex
526 static M3Gint m3gScaleAndBiasVertex(const SkinnedMesh *mesh,
527 M3Gint vx, M3Gint vy, M3Gint vz,
534 M3G_ASSERT(m3gInRange(vx, -1 << 15, (1 << 15) - 1));
535 M3G_ASSERT(m3gInRange(vy, -1 << 15, (1 << 15) - 1));
536 M3G_ASSERT(m3gInRange(vz, -1 << 15, (1 << 15) - 1));
538 expo = m3gFixedPointTransform(mesh->scaleMatrix, mesh->scaleExp,
539 mesh->biasVector, mesh->biasExp + upshift,
541 vx << upshift, vy << upshift, vz << upshift,
544 /* Scale down from 25 to 16 bits, adjusting the exponent
547 vertex[0] = (M3Gshort)(temp[0] >> 9);
548 vertex[1] = (M3Gshort)(temp[1] >> 9);
549 vertex[2] = (M3Gshort)(temp[2] >> 9);
552 M3G_ASSERT(m3gInRange(expo, -127, 127));
558 * \brief Computes the blended position for a single vertex
560 * \param mesh the SkinnedMesh object
561 * \param vidx vertex index (for accessing bone data)
562 * \param vx vertex X coordinate (16-bit range)
563 * \param vy vertex Y coordinate (16-bit range)
564 * \param vz vertex Z coordinate (16-bit range)
565 * \param upshift scaling value for the input coordinates and the
566 * translation component of the transformation
567 * \param vertex output vertex position
568 * \return exponent value for \c vertex
570 static M3Gint m3gBlendVertex(const SkinnedMesh *mesh,
572 M3Gint vx, M3Gint vy, M3Gint vz,
576 const M3Gint boneCount = mesh->bonesPerVertex;
577 const PointerArray *boneArray = &mesh->bones;
580 M3Gint outExp = -128;
581 M3Gint sumWeights = 0;
583 M3Gint ox = 0, oy = 0, oz = 0;
589 M3G_ASSERT(m3gInRange(vx, -1 << 15, (1 << 15) - 1));
590 M3G_ASSERT(m3gInRange(vy, -1 << 15, (1 << 15) - 1));
591 M3G_ASSERT(m3gInRange(vz, -1 << 15, (1 << 15) - 1));
593 /* Loop over the bones and sum the contribution from each */
595 for (i = 0; i < boneCount; ++i) {
597 M3Gint weight = (M3Gint) mesh->normalizedWeights[i][vidx];
598 sumWeights += weight;
600 /* Skip bones with zero weights */
604 const Bone *bone = (const Bone *)
605 m3gGetArrayElement(boneArray, mesh->boneIndices[i][vidx]);
609 shift = m3gFixedPointTransform(bone->baseMatrix, bone->baseExp,
610 bone->posVec, bone->posExp + upshift,
615 shift = outExp - shift;
630 /* Apply the vertex weights: 1.7 * 25.0 -> 26.7, but since
631 * the weights are positive and sum to 1, we should stay
632 * within the 32-bit range */
636 M3G_ASSERT(m3gInRange(temp[0], -1 << 24, (1 << 24) - 1));
637 M3G_ASSERT(m3gInRange(temp[1], -1 << 24, (1 << 24) - 1));
638 M3G_ASSERT(m3gInRange(temp[2], -1 << 24, (1 << 24) - 1));
640 ox += (weight * temp[0]) >> shift;
641 oy += (weight * temp[1]) >> shift;
642 oz += (weight * temp[2]) >> shift;
647 /* Before returning, we still need to check for the special case
648 * of all-zero weights, and shift the values from the post-scaling
649 * 32-bit precision back into the 16-bit range; we're essentially
650 * dropping the (25 - 16) bits of the blended result, so the
651 * exponent must change accordingly */
653 if (sumWeights > 0) {
654 vertex[0] = (M3Gshort)(ox >> 16);
655 vertex[1] = (M3Gshort)(oy >> 16);
656 vertex[2] = (M3Gshort)(oz >> 16);
657 outExp = outExp - upshift + 9;
659 M3G_ASSERT(m3gInRange(outExp, -127, 127));
666 return m3gScaleAndBiasVertex(mesh, vx, vy, vz, upshift, vertex);
672 * \brief Computes the blended normal vector for a single vertex
674 * \param mesh the SkinnedMesh object
675 * \param vidx vertex index (for accessing bone data)
676 * \param nx normal X coordinate (16-bit range)
677 * \param ny normal Y coordinate (16-bit range)
678 * \param nz normal Z coordinate (16-bit range)
679 * \param upshift scaling for input coordinates to increase precision
680 * \param normal output normal vector (8-bit range!)
681 * \return a shift value for the output vertex (scale from integer)
683 static void m3gBlendNormal(const SkinnedMesh *mesh,
685 M3Gint nx, M3Gint ny, M3Gint nz,
689 const M3Gint boneCount = mesh->bonesPerVertex;
690 const PointerArray *boneArray = &mesh->bones;
693 M3Gint outExp = -128;
694 M3Gint sumWeights = 0;
696 M3Gint ox = 0, oy = 0, oz = 0;
702 M3G_ASSERT(m3gInRange(nx, -1 << 15, (1 << 15) - 1));
703 M3G_ASSERT(m3gInRange(ny, -1 << 15, (1 << 15) - 1));
704 M3G_ASSERT(m3gInRange(nz, -1 << 15, (1 << 15) - 1));
706 /* Loop over the bones and sum the contribution from each */
708 for (i = 0; i < boneCount; ++i) {
710 M3Gint weight = (M3Gint) mesh->normalizedWeights[i][vidx];
711 sumWeights += weight;
713 /* Skip bones with zero weights */
717 const Bone *bone = (const Bone *)
718 m3gGetArrayElement(boneArray, mesh->boneIndices[i][vidx]);
722 shift = m3gFixedPointTransform(bone->normalMatrix, 0,
728 shift = outExp - shift;
743 /* Apply the vertex weights: 1.7 * 25.0 -> 26.7, but since
744 * the weights are positive and sum to 1, we should stay
745 * within the 32-bit range */
749 M3G_ASSERT(m3gInRange(temp[0], -1 << 24, (1 << 24) - 1));
750 M3G_ASSERT(m3gInRange(temp[1], -1 << 24, (1 << 24) - 1));
751 M3G_ASSERT(m3gInRange(temp[2], -1 << 24, (1 << 24) - 1));
753 ox += (weight * temp[0]) >> shift;
754 oy += (weight * temp[1]) >> shift;
755 oz += (weight * temp[2]) >> shift;
760 /* Before returning, we still need to check for the special case
761 * of all-zero weights, and shift the values from the post-scaling
762 * 32-bit precision down into the 8-bit range */
764 if (sumWeights > 0) {
765 normal[0] = (M3Gbyte)(ox >> 24);
766 normal[1] = (M3Gbyte)(oy >> 24);
767 normal[2] = (M3Gbyte)(oz >> 24);
770 normal[0] = (M3Gbyte)(ox >> 8);
771 normal[1] = (M3Gbyte)(oy >> 8);
772 normal[2] = (M3Gbyte)(oz >> 8);
778 * \brief Updates internal vertex buffer
780 * \param mesh SkinnedMesh object
782 * \retval M3G_TRUE VertexBuffer is up to date
783 * \retval M3G_FALSE Failed to update VertexBuffer, out of memory exception raised
785 static M3Gbool m3gSkinnedMeshUpdateVB(SkinnedMesh *mesh)
788 M3G_ASSERT(mesh->mesh.vertexBuffer != NULL);
789 M3G_ASSERT(mesh->morphedVB != NULL);
791 /* Source vertex buffer array configuration changed since last
794 vbTimestamp = m3gGetTimestamp(mesh->mesh.vertexBuffer);
796 if (mesh->vbTimestamp != vbTimestamp) {
797 Interface *m3g = M3G_INTERFACE(mesh);
799 M3Gint vcount = m3gGetVertexCount(mesh->mesh.vertexBuffer);
801 /* Must ensure that our internal morphing buffer matches the
802 * configuration of the source buffer, with dedicated arrays
803 * for the morphed positions and normals */
805 if (!m3gMakeModifiedVertexBuffer(mesh->morphedVB,
806 mesh->mesh.vertexBuffer,
807 M3G_POSITION_BIT|M3G_NORMAL_BIT,
809 return M3G_FALSE; /* out of memory */
812 /* We always have the vertex positions as shorts, but the
813 * array may not be actually initialized yet, so we must check
814 * whether to create a copy or not */
816 if (mesh->mesh.vertexBuffer->vertices) {
817 array = m3gCreateVertexArray(m3g, vcount, 3, M3G_SHORT);
821 m3gSetVertexArray(mesh->morphedVB, array, 1.f, NULL, 0);
824 /* Normals (always bytes) only exist if in the original VB */
826 if (mesh->mesh.vertexBuffer->normals) {
827 array = m3gCreateVertexArray(m3g, vcount, 3, M3G_BYTE);
831 m3gSetNormalArray(mesh->morphedVB, array);
834 mesh->vbTimestamp = vbTimestamp;
837 /* The default color must always be updated, because it can be
838 * animated (doesn't affect timestamp) */
840 mesh->morphedVB->defaultColor = mesh->mesh.vertexBuffer->defaultColor;
847 * \brief Gets the transformation(s) for a single bone record
849 * Also stores the normal transformation matrix if needed.
851 * \param mesh pointer to the mesh object
852 * \param bone pointer to the bone record
853 * \param hasNormals flag indicating whether the normals transformation
854 * should be computed and cached in the bone record
855 * \param mtx matrix to store the vertex transformation in
857 static M3G_INLINE M3Gbool m3gGetBoneTransformInternal(SkinnedMesh *mesh,
862 const VertexBuffer *vb = mesh->mesh.vertexBuffer;
864 /* Get the vertex transformation and concatenate it with the
865 * at-rest matrix and the vertex scale and bias transformations.
866 * The resulting 3x4 transformation matrix is then split into a
867 * fixed point 3x3 matrix and translation vector */
869 if (!m3gGetTransformTo(bone->node, (Node*) mesh, mtx)) {
870 return M3G_FALSE; /* no path or singular transform */
872 m3gMulMatrix(mtx, &bone->toBone);
874 /* If normals are enabled, compute and store the inverse transpose
875 * matrix for transforming normals at this stage */
879 if (!m3gInverseTranspose(&t, mtx)) {
880 m3gRaiseError(M3G_INTERFACE(mesh), M3G_ARITHMETIC_ERROR);
881 return M3G_FALSE; /* singular transform */
883 m3gGetFixedPoint3x3Basis(&t, bone->normalMatrix);
886 /* Apply the vertex bias and scale to the transformation */
889 mtx, vb->vertexBias[0], vb->vertexBias[1], vb->vertexBias[2]);
890 m3gScaleMatrix(mtx, vb->vertexScale, vb->vertexScale, vb->vertexScale);
897 * \brief Compute and cache the bone transformations for morphing
899 * \param mesh the SkinnedMesh object
900 * \param posShift vertex position value "gain"
902 static M3Gbool m3gPreComputeTransformations(SkinnedMesh *mesh,
906 M3Gint boneCount = m3gArraySize(&mesh->bones);
908 Matrix *tBone = NULL;
910 /* First, just compute the floating point transformation matrices
911 * for the bones, caching them in a temp array */
914 tBone = m3gAllocTemp(M3G_INTERFACE(mesh), boneCount * sizeof(Matrix));
916 return M3G_FALSE; /* out of memory */
918 for (i = 0; i < boneCount; ++i) {
919 Bone *bone = m3gGetArrayElement(&mesh->bones, i);
920 if (!m3gGetBoneTransformInternal(mesh, bone, hasNormals, &tBone[i])) {
926 /* Find the value range of the bone translations, and offset the
927 * bones to center output vertex values (roughly) around the
930 const VertexBuffer *vb = mesh->mesh.vertexBuffer;
931 M3Gfloat min[3], max[3], bias[3];
935 /* Find the minimum and maximum values; start with the plain
936 * vertex bias for non-weighted bones */
938 min[0] = max[0] = vb->vertexBias[0];
939 min[1] = max[1] = vb->vertexBias[1];
940 min[2] = max[2] = vb->vertexBias[2];
942 for (i = 0; i < boneCount; ++i) {
943 m3gGetMatrixColumn(&tBone[i], 3, &t);
944 min[0] = M3G_MIN(min[0], t.x);
945 max[0] = M3G_MAX(max[0], t.x);
946 min[1] = M3G_MIN(min[1], t.y);
947 max[1] = M3G_MAX(max[1], t.y);
948 min[2] = M3G_MIN(min[2], t.z);
949 max[2] = M3G_MAX(max[2], t.z);
952 /* Divide to get the mean translation, store in the
953 * destination VB, and invert for de-biasing the bones */
955 for (i = 0; i < 3; ++i) {
956 bias[i] = m3gMul(0.5f, m3gAdd(min[i], max[i]));
957 mesh->morphedVB->vertexBias[i] = bias[i];
958 bias[i] = m3gNegate(bias[i]);
961 /* Offset bones by the (now inverted) bias vector, and store
962 * the fixed point matrix & vector parts in the bone record;
963 * also set the maximum bone exponent into the mesh */
966 for (i = 0; i < boneCount; ++i) {
967 Bone *bone = m3gGetArrayElement(&mesh->bones, i);
968 m3gPreTranslateMatrix(&tBone[i], bias[0], bias[1], bias[2]); /*lint !e613 tBone not null if boneCount > 0 */
970 bone->baseExp = (M3Gshort)
971 m3gGetFixedPoint3x3Basis(&tBone[i], bone->baseMatrix); /*lint !e613 tBone not null if boneCount > 0 */
972 bone->posExp = (M3Gshort)
973 m3gGetFixedPointTranslation(&tBone[i], bone->posVec); /*lint !e613 tBone not null if boneCount > 0 */
974 bone->maxExp = (M3Gshort)
975 m3gOptimalExponent(bone->baseExp, bone->posExp + posShift);
977 maxExp = M3G_MAX(maxExp, bone->maxExp);
980 /* Make a fixed-point matrix for applying the scale and bias as
981 * well, for vertices not attached to any bone (this is not the
982 * optimal way to store the information, but we can just reuse
983 * existing code this way) */
986 m3gTranslationMatrix(&sb,
987 m3gAdd(bias[0], vb->vertexBias[0]),
988 m3gAdd(bias[1], vb->vertexBias[1]),
989 m3gAdd(bias[2], vb->vertexBias[2]));
991 vb->vertexScale, vb->vertexScale, vb->vertexScale);
993 mesh->scaleExp = (M3Gshort)
994 m3gGetFixedPoint3x3Basis(&sb, mesh->scaleMatrix);
995 mesh->biasExp = (M3Gshort)
996 m3gGetFixedPointTranslation(&sb, mesh->biasVector);
997 mesh->scaleBiasExp = (M3Gshort)
998 m3gOptimalExponent(mesh->scaleExp, mesh->biasExp + posShift);
1000 maxExp = M3G_MAX(mesh->scaleBiasExp, maxExp);
1003 /* Compute the maximum post-blending exponent and store it as the
1004 * morphed vertex buffer scale -- this is dependent on the
1005 * implementations of m3gBlendVertex, m3gScaleAndBiasVertex, and
1006 * m3gFixedPointTransform! */
1008 maxExp = maxExp + 16 - posShift;
1009 M3G_ASSERT(m3gInRange(maxExp, -127, 127));
1010 *(M3Gint*)&mesh->morphedVB->vertexScale = (maxExp + 127) << 23;
1011 mesh->maxExp = (M3Gshort) maxExp;
1014 if (boneCount > 0) {
1015 m3gFreeTemp(M3G_INTERFACE(mesh));
1023 * \brief Computes derived data required for bounding volumes and skinning
1025 static M3Gbool m3gSkinnedMeshPreMorph(SkinnedMesh *mesh)
1027 const VertexBuffer *srcVB = mesh->mesh.vertexBuffer;
1028 M3Gint posShift = 0, normalShift = 0;
1030 /* Compute upscaling shift values for positions and normals so
1031 * that we can maximize precision even for absurdly small
1034 M3Gint minVal, maxVal;
1036 if (srcVB->normals) {
1037 m3gGetArrayValueRange(srcVB->normals, &minVal, &maxVal);
1038 maxVal = M3G_MAX(-minVal, maxVal);
1039 M3G_ASSERT(maxVal >= 0);
1041 while ((maxVal << normalShift) < (1 << 14)) {
1047 m3gGetArrayValueRange(srcVB->vertices, &minVal, &maxVal);
1048 maxVal = M3G_MAX(-minVal, maxVal);
1049 M3G_ASSERT(maxVal >= 0);
1051 while ((maxVal << posShift) < (1 << 14)) {
1056 mesh->posShift = (M3Gshort) posShift;
1057 mesh->normalShift = (M3Gshort) normalShift;
1060 /* Now that we can compute the optimized exponents for the
1061 * transformations based on the position upshift value, let's
1062 * resolve the bone transformations; this will also cache the
1063 * maximum bone exponent in mesh->maxExp */
1065 if (!m3gPreComputeTransformations(mesh,
1067 srcVB->normals != NULL)) {
1068 return M3G_FALSE; /* invalid transform */
1076 * \brief Does the actual vertex morphing into the internal vertex buffer
1078 * \param mesh SkinnedMesh object
1079 * \retval M3G_TRUE skinning ok
1080 * \retval M3G_FALSE skinning failed, exception raised
1082 static void m3gSkinnedMeshMorph(SkinnedMesh *mesh)
1084 const VertexBuffer *srcVB = mesh->mesh.vertexBuffer;
1085 const void *srcPositions;
1086 const void *srcNormals = NULL;
1087 VertexBuffer *dstVB = mesh->morphedVB;
1088 M3Gshort *dstPositions;
1089 M3Gbyte *dstNormals = NULL;
1090 M3Gint vertexCount = mesh->weightedVertexCount;
1091 M3Gint maxExp = mesh->maxExp;
1092 M3Gint posShift = mesh->posShift, normShift = mesh->normalShift;
1095 M3G_ASSERT(!((Node*) mesh)->dirtyBits);
1097 /* Let's update the vertex weights if we need to */
1099 if (mesh->weightsDirty) {
1100 m3gNormalizeWeights(mesh);
1103 /* Get pointers to source and destination position and normal
1104 * data; the latter will always be shorts and bytes,
1105 * respectively, while the former can be either */
1107 srcPositions = m3gMapVertexArrayReadOnly(srcVB->vertices);
1108 dstPositions = (M3Gshort*) m3gMapVertexArray(dstVB->vertices);
1109 if (srcVB->normals) {
1110 srcNormals = m3gMapVertexArrayReadOnly(srcVB->normals);
1111 dstNormals = (M3Gbyte*) m3gMapVertexArray(dstVB->normals);
1114 /* Transform the vertices that are affected by bones */
1116 M3Gshort *dst = dstPositions;
1118 if (srcVB->vertices->elementType == GL_BYTE) {
1119 const M3Gbyte *src = (const M3Gbyte*) srcPositions;
1120 for (i = 0; i < vertexCount; ++i) {
1122 maxExp - m3gBlendVertex(mesh, i,
1123 src[0], src[1], src[2],
1137 src += 4; /* byte data always padded to 32 bits */
1141 const M3Gshort *src = (const M3Gshort*) srcPositions;
1142 for (i = 0; i < vertexCount; ++i) {
1144 maxExp - m3gBlendVertex(mesh, i,
1145 src[0], src[1], src[2],
1164 /* Transform the normals (if enabled). Normals will be
1165 * normalized when rendering, so no need to keep track of
1169 M3Gbyte *dst = dstNormals;
1171 if (srcVB->normals->elementType == GL_BYTE) {
1172 const M3Gbyte *src = (const M3Gbyte*) srcNormals;
1173 for (i = 0; i < vertexCount; ++i) {
1174 m3gBlendNormal(mesh, i,
1175 src[0], src[1], src[2],
1178 src += 4; /* byte data padded to 32 bits */
1183 const M3Gshort *src = (const M3Gshort*) srcNormals;
1184 for (i = 0; i < vertexCount; ++i) {
1185 m3gBlendNormal(mesh, i,
1186 src[0], src[1], src[2],
1195 /* Finally, handle the remaining vertices, which have no bones
1196 * attached; these just need to have the scale and bias
1199 vertexCount = m3gGetNumVertices(srcVB);
1200 if (i < vertexCount) {
1202 M3Gint startIndex = i;
1203 M3Gshort *dstPos = dstPositions + startIndex * 3;
1206 if (srcVB->vertices->elementType == GL_BYTE) {
1207 const M3Gbyte *src = ((const M3Gbyte*) srcPositions) + startIndex * 4;
1208 for (i = startIndex ; i < vertexCount; ++i) {
1210 maxExp - m3gScaleAndBiasVertex(mesh,
1211 src[0], src[1], src[2],
1214 *dstPos++ = (M3Gshort)(temp[0] >> shift);
1215 *dstPos++ = (M3Gshort)(temp[1] >> shift);
1216 *dstPos++ = (M3Gshort)(temp[2] >> shift);
1217 src += 4; /* byte data, padded to 32 bits */
1221 const M3Gshort *src = ((const M3Gshort*) srcPositions) + startIndex * 3;
1222 for (i = startIndex ; i < vertexCount; ++i) {
1224 maxExp - m3gScaleAndBiasVertex(mesh,
1225 src[0], src[1], src[2],
1228 *dstPos++ = (M3Gshort)(temp[0] >> shift);
1229 *dstPos++ = (M3Gshort)(temp[1] >> shift);
1230 *dstPos++ = (M3Gshort)(temp[2] >> shift);
1235 /* Byte normals can just use a memcopy, as we don't have
1236 * to scale them at all; shorts will require a conversion,
1237 * after prescaling with the normal upshift to avoid
1238 * underflowing to zero */
1241 M3Gbyte *dstNorm = dstNormals + startIndex * 4;
1242 if (srcVB->normals->elementType == GL_BYTE) {
1243 const M3Gbyte *src =
1244 ((const M3Gbyte*) srcNormals) + startIndex * 4;
1245 m3gCopy(dstNorm, src, (vertexCount - startIndex) * 4);
1248 const M3Gshort *src =
1249 ((const M3Gshort*) srcNormals) + startIndex * 3;
1250 for (i = startIndex ; i < vertexCount; ++i) {
1251 *dstNorm++ = (M3Gbyte)((*src++ << normShift) >> 8);
1252 *dstNorm++ = (M3Gbyte)((*src++ << normShift) >> 8);
1253 *dstNorm++ = (M3Gbyte)((*src++ << normShift) >> 8);
1254 ++dstNorm; /* again, padding for byte values */
1260 /* All done! Clean up and exit */
1262 m3gUnmapVertexArray(srcVB->vertices);
1263 m3gUnmapVertexArray(dstVB->vertices);
1265 m3gUnmapVertexArray(srcVB->normals);
1266 m3gUnmapVertexArray(dstVB->normals);
1272 * \brief Overloaded Node method.
1274 * Setup skinned mesh render. Call mesh render setup,
1275 * do skinning calculations and traverse into the skeleton or the parent
1277 * \param self SkinnedMesh object
1278 * \param toCamera transform to camera
1279 * \param alphaFactor total alpha factor
1280 * \param caller caller node
1281 * \param renderQueue RenderQueue
1283 * \retval M3G_TRUE continue render setup
1284 * \retval M3G_FALSE abort render setup
1286 static M3Gbool m3gSkinnedMeshSetupRender(Node *self,
1288 SetupRenderState *s,
1289 RenderQueue *renderQueue)
1291 SkinnedMesh *mesh = (SkinnedMesh *)self;
1292 Node *skeleton = (Node*) mesh->skeleton;
1293 M3Gbool enabled, success = M3G_TRUE;
1294 m3gIncStat(M3G_INTERFACE(self), M3G_STAT_RENDER_NODES, 1);
1296 /* Optimize the rendering-enable checking for top-down traversal */
1298 enabled = (self->enableBits & NODE_RENDER_BIT) != 0;
1299 if (caller != self->parent) {
1300 enabled = m3gHasEnabledPath(self, renderQueue->root);
1301 s->cullMask = CULLMASK_ALL;
1304 /* Handle self and the skeleton if enabled */
1308 /* Traverse into the skeleton unless coming from there */
1310 if (skeleton != caller) {
1311 SetupRenderState cs;
1312 cs.cullMask = s->cullMask;
1314 M3G_BEGIN_PROFILE(M3G_INTERFACE(self), M3G_PROFILE_SETUP_TRANSFORMS);
1315 m3gGetCompositeNodeTransform(skeleton, &cs.toCamera);
1316 m3gPreMultiplyMatrix(&cs.toCamera, &s->toCamera);
1317 M3G_END_PROFILE(M3G_INTERFACE(self), M3G_PROFILE_SETUP_TRANSFORMS);
1319 success = M3G_VFUNC(Node, skeleton, setupRender)(skeleton,
1325 /* Handle self if in scope */
1327 if ((self->scope & renderQueue->scope) != 0) {
1329 /* Try view frustum culling */
1331 # if defined(M3G_ENABLE_VF_CULLING)
1332 m3gUpdateCullingMask(s, renderQueue->camera, &mesh->bbox);
1335 if (s->cullMask == 0) {
1336 m3gIncStat(M3G_INTERFACE(self),
1337 M3G_STAT_RENDER_NODES_CULLED, 1);
1340 success &= m3gQueueMesh((Mesh*) self, &s->toCamera, renderQueue);
1343 M3G_BEGIN_PROFILE(M3G_INTERFACE(self), M3G_PROFILE_SKIN);
1344 m3gSkinnedMeshMorph(mesh);
1345 M3G_END_PROFILE(M3G_INTERFACE(self), M3G_PROFILE_SKIN);
1351 /* Traverse into the parent node unless coming from there. Again,
1352 * discard the old traversal state at this point, as we're not
1355 if (success && self != renderQueue->root) {
1356 Node *parent = self->parent;
1357 if (parent != NULL && parent != caller) {
1360 M3G_BEGIN_PROFILE(M3G_INTERFACE(self), M3G_PROFILE_SETUP_TRANSFORMS);
1361 if (!m3gGetInverseNodeTransform(self, &t)) {
1364 m3gMulMatrix(&s->toCamera, &t);
1365 M3G_END_PROFILE(M3G_INTERFACE(self), M3G_PROFILE_SETUP_TRANSFORMS);
1367 success = M3G_VFUNC(Node, parent, setupRender)(parent,
1379 * \brief Overloaded Node method.
1381 * Renders one skinned submesh.
1383 * \param self SkinnedMesh object
1384 * \param ctx current render context
1385 * \param patchIndex submesh index
1387 static void m3gSkinnedMeshDoRender(Node *self,
1389 const Matrix *toCamera,
1392 SkinnedMesh *mesh = (SkinnedMesh *)self;
1393 IndexBuffer *indexBuffer = mesh->mesh.indexBuffers[patchIndex];
1394 Appearance *appearance = mesh->mesh.appearances[patchIndex];
1396 if (indexBuffer == NULL || appearance == NULL)
1404 mesh->mesh.totalAlphaFactor + 1,
1405 mesh->mesh.node.scope);
1410 * \brief Overloaded Node method.
1412 * Do skinning calculations and forward to Mesh internal ray intersect.
1414 * \param self SkinnedMesh object
1415 * \param mask pick scope mask
1416 * \param ray pick ray
1417 * \param ri RayIntersection object
1418 * \param toGroup transform to originating group
1419 * \retval M3G_TRUE continue pick
1420 * \retval M3G_FALSE abort pick
1422 static M3Gbool m3gSkinnedMeshRayIntersect( Node *self,
1425 RayIntersection *ri,
1428 SkinnedMesh *mesh = (SkinnedMesh *)self;
1429 M3G_BEGIN_PROFILE(M3G_INTERFACE(self), M3G_PROFILE_SKIN);
1431 if ((((Node *)mesh)->scope & mask) == 0) {
1435 if (!m3gSkinnedMeshPreMorph(mesh)) {
1438 m3gSkinnedMeshMorph(mesh);
1439 M3G_END_PROFILE(M3G_INTERFACE(self), M3G_PROFILE_SKIN);
1440 return m3gMeshRayIntersectInternal( &mesh->mesh,
1450 * \brief Overloaded Object3D method.
1452 * \param self SkinnedMesh object
1453 * \param time current world time
1454 * \return minimum validity
1456 static M3Gint m3gSkinnedMeshApplyAnimation(Object *self, M3Gint time)
1458 SkinnedMesh *mesh = (SkinnedMesh *)self;
1460 M3Gint validity = m3gMeshApplyAnimation((Object*) &mesh->mesh, time);
1464 M3G_VFUNC(Object, mesh->skeleton, applyAnimation)(
1465 (Object *)mesh->skeleton, time);
1466 return (validity < validity2 ? validity : validity2);
1473 * \brief Overloaded Object3D method.
1475 * \param self SkinnedMesh object
1476 * \param references array of reference objects
1477 * \return number of references
1479 static M3Gint m3gSkinnedMeshDoGetReferences(Object *self, Object **references)
1481 SkinnedMesh *smesh = (SkinnedMesh *)self;
1482 M3Gint num = m3gMeshDoGetReferences(self, references);
1483 if (smesh->skeleton != NULL)
1485 if (references != NULL)
1486 references[num] = (Object *)smesh->skeleton;
1494 * \brief Overloaded Object3D method.
1496 static Object *m3gSkinnedMeshFindID(Object *self, M3Gint userID)
1498 SkinnedMesh *smesh = (SkinnedMesh *)self;
1499 Object *found = m3gMeshFindID(self, userID);
1501 if (!found && smesh->skeleton != NULL) {
1502 found = m3gFindID((Object*) smesh->skeleton, userID);
1509 * \brief Overloaded Object3D method.
1511 * \param originalObj original SkinnedMesh object
1512 * \param cloneObj pointer to cloned SkinnedMesh object
1513 * \param pairs array for all object-duplicate pairs
1514 * \param numPairs number of pairs
1516 static M3Gbool m3gSkinnedMeshDuplicate(const Object *originalObj,
1522 SkinnedMesh *original = (SkinnedMesh *)originalObj;
1523 Group *skeleton = NULL;
1525 M3G_ASSERT(*cloneObj == NULL); /* no derived classes */
1527 /* Duplicate the skeleton group first, as this is a prerequisite
1528 * for creating the clone SkinnedMesh. If this fails, we must
1529 * manually delete the skeleton, as no record of it will be stored
1530 * anywhere else; we also need to hold a reference until ownership
1531 * of the skeleton transfers to the clone SkinnedMesh. */
1533 if (!M3G_VFUNC(Object, original->skeleton, duplicate)(
1534 (Object*) original->skeleton,
1535 (Object**) &skeleton, pairs, numPairs)) {
1536 m3gDeleteObject((Object*) skeleton);
1539 m3gAddRef((Object*) skeleton); /* don't leave this floating */
1541 /* Create the actual clone object */
1543 clone = (SkinnedMesh*)
1544 m3gCreateSkinnedMesh(originalObj->interface,
1545 original->mesh.vertexBuffer,
1546 original->mesh.indexBuffers,
1547 original->mesh.appearances,
1548 original->mesh.trianglePatchCount,
1550 m3gDeleteRef((Object*) skeleton); /* ownership transferred to clone */
1554 *cloneObj = (Object *)clone;
1556 /* Duplicate base class data; we're OK for normal deletion at this
1557 * point, so can just leave it up to the caller on failure */
1559 if (!m3gMeshDuplicate(originalObj, cloneObj, pairs, numPairs)) {
1563 /* Duplicate the rest of our own data */
1565 if (!m3gEnsureVertexCount(clone, original->weightedVertexCount) ||
1566 !m3gEnsureBonesPerVertex(clone, original->bonesPerVertex)) {
1567 return M3G_FALSE; /* out of memory */
1570 for (i = 0; i < clone->bonesPerVertex; i++) {
1571 m3gCopy(clone->boneIndices[i], original->boneIndices[i],
1572 clone->weightedVertexCount);
1573 m3gCopy(clone->boneWeights[i], original->boneWeights[i],
1574 clone->weightedVertexCount);
1575 m3gCopy(clone->normalizedWeights[i], original->normalizedWeights[i],
1576 clone->weightedVertexCount);
1578 clone->weightsDirty = original->weightsDirty;
1579 m3gCopy(clone->weightShifts, original->weightShifts,
1580 clone->weightedVertexCount);
1582 for (i = 0; i < m3gArraySize(&original->bones); i++) {
1583 Bone *cloneBone = (Bone*) m3gAllocZ(originalObj->interface,
1586 return M3G_FALSE; /* out of memory */
1588 /* this line looks odd, but really just copies the *contents*
1589 * of the bone structure... */
1590 *cloneBone = *(Bone*)m3gGetArrayElement(&original->bones, i);
1592 if (m3gArrayAppend(&clone->bones, cloneBone, originalObj->interface) < 0) {
1593 m3gFree(originalObj->interface, cloneBone);
1594 return M3G_FALSE; /* out of memory */
1603 * \brief Overloaded Node method
1605 static M3Gint m3gSkinnedMeshGetBBox(Node *self, AABB *bbox)
1607 SkinnedMesh *mesh = (SkinnedMesh*) self;
1608 Node *skeleton = (Node*) mesh->skeleton;
1610 /* First update our local bounding box if necessary */
1612 if (self->dirtyBits & NODE_BBOX_BIT) {
1614 /* Compute an estimated bounding box from the morphed vertex
1615 * buffer scale and bias (from PreComputeTransformations).
1616 * The morphed vertex array is always scaled to utilize most
1617 * of the 16-bit short range, so we just use that as the
1620 const GLfloat scale = mesh->morphedVB->vertexScale;
1621 const GLfloat *bias = mesh->morphedVB->vertexBias;
1624 for (i = 0; i < 3; ++i) {
1625 mesh->bbox.min[i] = m3gMadd(scale, -1 << 15, bias[i]);
1626 mesh->bbox.max[i] = m3gMadd(scale, (1 << 15) - 1, bias[i]);
1632 /* Mix in the skeleton bounding box if we need to -- but only into
1633 * the output bbox, as we're handling the local mesh bbox
1634 * specially in SetupRender! */
1636 if (skeleton->hasRenderables && skeleton->enableBits) {
1638 if (m3gGetNodeBBox(skeleton, &skeletonBBox)) {
1640 m3gGetCompositeNodeTransform(self, &t);
1641 m3gTransformAABB(&skeletonBBox, &t);
1642 m3gFitAABB(bbox, &skeletonBBox, bbox);
1645 return m3gArraySize(&mesh->bones) * VFC_NODE_OVERHEAD;
1650 * \brief Overloaded Node method
1652 static M3Gbool m3gSkinnedMeshValidate(Node *self, M3Gbitmask stateBits, M3Gint scope)
1654 SkinnedMesh *mesh = (SkinnedMesh*) self;
1655 Interface *m3g = M3G_INTERFACE(mesh);
1656 Node *skeleton = (Node*) mesh->skeleton;
1657 const VertexBuffer *srcVB = mesh->mesh.vertexBuffer;
1658 M3Gint vertexCount = mesh->weightedVertexCount;
1660 if ((scope & self->scope) != 0) {
1661 if (stateBits & self->enableBits) {
1663 /* Check for invalid SkinnedMesh state */
1665 if (srcVB->vertices == NULL || vertexCount > srcVB->vertexCount) {
1666 m3gRaiseError(m3g, M3G_INVALID_OPERATION);
1669 if (!m3gSkinnedMeshUpdateVB(mesh)) { /* Memory allocation failed */
1673 /* Validate the skeleton */
1675 if (!m3gValidateNode(skeleton, stateBits, scope)) {
1679 /* Validate our local state */
1681 if ((self->dirtyBits & NODE_TRANSFORMS_BIT) != 0 ||
1682 m3gGetTimestamp(srcVB) != mesh->mesh.vbTimestamp) {
1683 if (!m3gSkinnedMeshPreMorph((SkinnedMesh*) self)) {
1687 if (self->dirtyBits & NODE_BBOX_BIT) {
1688 M3G_BEGIN_PROFILE(M3G_INTERFACE(self), M3G_PROFILE_VFC_UPDATE);
1689 m3gGetNodeBBox(self, &mesh->bbox);
1690 M3G_END_PROFILE(M3G_INTERFACE(self), M3G_PROFILE_VFC_UPDATE);
1693 return m3gMeshValidate(self, stateBits, scope);
1701 * \brief Overloaded Object3D method.
1703 * \param self SkinnedMesh object
1704 * \param pairs array for all object-duplicate pairs
1705 * \param numPairs number of pairs
1707 static void m3gSkinnedMeshUpdateDuplicateReferences(Node *self, Object **pairs, M3Gint numPairs)
1709 SkinnedMesh *skinned = (SkinnedMesh *)self;
1710 SkinnedMesh *duplicate = (SkinnedMesh *)m3gGetDuplicatedInstance(self, pairs, numPairs);
1713 m3gNodeUpdateDuplicateReferences(self, pairs, numPairs);
1715 n = m3gArraySize(&duplicate->bones);
1716 for (i = 0; i < n; i++) {
1717 Bone *bone = (Bone*) m3gGetArrayElement(&duplicate->bones, i);
1718 Node *boneDuplicate = m3gGetDuplicatedInstance(bone->node, pairs, numPairs);
1719 if (boneDuplicate != NULL) {
1720 bone->node = boneDuplicate;
1724 M3G_VFUNC(Node, skinned->skeleton, updateDuplicateReferences)(
1725 (Node *)skinned->skeleton, pairs, numPairs);
1730 * \brief Initializes a SkinnedMesh object. See specification
1731 * for default values.
1733 * \param m3g M3G interface
1734 * \param mesh SkinnedMesh object
1735 * \param hVertices VertexBuffer object
1736 * \param hTriangles array of IndexBuffer objects
1737 * \param hAppearances array of Appearance objects
1738 * \param trianglePatchCount number of submeshes
1739 * \param hSkeleton Group containing the skeleton
1740 * \retval M3G_TRUE success
1741 * \retval M3G_FALSE failure
1743 static M3Gbool m3gInitSkinnedMesh(Interface *m3g,
1745 M3GVertexBuffer hVertices,
1746 M3GIndexBuffer *hTriangles,
1747 M3GAppearance *hAppearances,
1748 M3Gint trianglePatchCount,
1751 /* SkinnedMesh is derived from Mesh */
1752 if (!m3gInitMesh(m3g, &mesh->mesh,
1753 hVertices, hTriangles, hAppearances,
1755 M3G_CLASS_SKINNED_MESH))
1760 /* Make sure our mesh gets blended even if no bones are added */
1761 ((Node*)mesh)->dirtyBits |= NODE_TRANSFORMS_BIT;
1763 /* Set default values, see RI SkinnedMesh.java for reference */
1764 m3gSetParent(&((Group *)hSkeleton)->node, &mesh->mesh.node);
1765 M3G_ASSIGN_REF(mesh->skeleton, (Group *)hSkeleton);
1767 m3gInitArray(&mesh->bones);
1769 mesh->morphedVB = (VertexBuffer *)m3gCreateVertexBuffer(m3g);
1770 if (mesh->morphedVB == NULL
1771 || m3gSkinnedMeshUpdateVB(mesh) == M3G_FALSE) {
1773 /* We're sufficiently initialized at this point that the
1774 * destructor can be called for cleaning up */
1776 m3gDestroySkinnedMesh((Object *)mesh);
1782 /*----------------------------------------------------------------------
1783 * Virtual function table
1784 *--------------------------------------------------------------------*/
1786 static const NodeVFTable m3gvf_SkinnedMesh = {
1789 m3gSkinnedMeshApplyAnimation,
1790 m3gNodeIsCompatible,
1791 m3gNodeUpdateProperty,
1792 m3gSkinnedMeshDoGetReferences,
1793 m3gSkinnedMeshFindID,
1794 m3gSkinnedMeshDuplicate,
1795 m3gDestroySkinnedMesh
1799 m3gSkinnedMeshDoRender,
1800 m3gSkinnedMeshGetBBox,
1801 m3gSkinnedMeshRayIntersect,
1802 m3gSkinnedMeshSetupRender,
1803 m3gSkinnedMeshUpdateDuplicateReferences,
1804 m3gSkinnedMeshValidate
1808 /*----------------------------------------------------------------------
1809 * Public API functions
1810 *--------------------------------------------------------------------*/
1813 * \brief Creates a SkinnedMesh object.
1815 * \param interface M3G interface
1816 * \param hVertices VertexBuffer object
1817 * \param hTriangles array of IndexBuffer objects
1818 * \param hAppearances array of Appearance objects
1819 * \param trianglePatchCount number of submeshes
1820 * \param hSkeleton Group containing the skeleton
1821 * \retval SkinnedMesh new SkinnedMesh object
1822 * \retval NULL SkinnedMesh creating failed
1824 M3G_API M3GSkinnedMesh m3gCreateSkinnedMesh(M3GInterface interface,
1825 M3GVertexBuffer hVertices,
1826 M3GIndexBuffer *hTriangles,
1827 M3GAppearance *hAppearances,
1828 M3Gint trianglePatchCount,
1831 Interface *m3g = (Interface *) interface;
1832 M3G_VALIDATE_INTERFACE(m3g);
1834 SkinnedMesh *mesh = NULL;
1835 Group *skeleton = (Group *) hSkeleton;
1836 if (skeleton == NULL) {
1837 m3gRaiseError(m3g, M3G_NULL_POINTER);
1840 if (skeleton->node.parent != NULL ||
1841 M3G_CLASS(skeleton) == M3G_CLASS_WORLD) {
1842 m3gRaiseError(m3g, M3G_INVALID_VALUE);
1846 mesh = m3gAllocZ(m3g, sizeof(SkinnedMesh));
1848 if (!m3gInitSkinnedMesh(m3g, mesh,
1849 hVertices, hTriangles, hAppearances,
1856 return (M3GSkinnedMesh)mesh;
1861 * \brief Add new weighted transformation (bone) to range of vertices
1864 * \param handle SkinnedMesh object
1865 * \param hNode bone to transform the vertices with
1866 * \param weight weight of the bone
1867 * \param firstVertex index to the first affected vertex
1868 * \param numVertices number of affected vertices
1870 M3G_API void m3gAddTransform(M3GSkinnedMesh handle,
1873 M3Gint firstVertex, M3Gint numVertices)
1875 SkinnedMesh *mesh = (SkinnedMesh *)handle;
1876 Node *boneNode = (Node *)hNode;
1877 Interface *m3g = M3G_INTERFACE(mesh);
1879 M3Gint lastVertex = firstVertex + numVertices;
1880 M3G_VALIDATE_OBJECT(mesh);
1882 /* Check for errors */
1885 m3gRaiseError(m3g, M3G_NULL_POINTER);
1888 M3G_VALIDATE_OBJECT(boneNode);
1889 if (!m3gIsChildOf((const Node*) mesh, boneNode)
1890 || numVertices <= 0 || weight <= 0) {
1891 m3gRaiseError(m3g, M3G_INVALID_VALUE);
1894 if (firstVertex < 0 || lastVertex > 65535) {
1895 m3gRaiseError(m3g, M3G_INVALID_INDEX);
1899 /* Make sure we have enough per-vertex data */
1901 if (!m3gEnsureVertexCount(mesh, lastVertex)) {
1902 return; /* out of memory */
1905 /* Check whether we may need to increase the number of bone
1906 * entries per vertex, or whether we're already maxed out */
1908 if (mesh->bonesPerVertex < M3G_MAX_VERTEX_TRANSFORMS) {
1910 /* Scan the input vertex range to find the maximum number of
1911 * transforms per vertex (with non-zero weights) already in
1912 * use, then make sure we can fit one more */
1914 int numBones = mesh->bonesPerVertex;
1918 for (vertex = firstVertex; vertex < lastVertex; ++vertex) {
1920 for (k = numBones; k > 0; --k) {
1921 if (mesh->boneWeights[k-1][vertex] > 0) {
1922 maxBones = M3G_MAX(maxBones, k);
1927 if (!m3gEnsureBonesPerVertex(mesh, maxBones + 1)) {
1928 return; /* out of memory */
1932 /* Get a bone record for the bone node, and add the bone influence
1933 * to all affected vertices */
1937 M3Gint boneIndex = m3gBoneIndex(mesh, boneNode);
1938 if (boneIndex < 0) {
1939 return; /* out of memory */
1942 for (i = firstVertex; i < lastVertex; i++) {
1943 m3gAddInfluence(mesh, i, boneIndex, weight);
1947 /* Update the bone flag for the bone node and its parents up to
1948 * the SkinnedMesh node */
1950 while (boneNode != (Node*) mesh) { /* boneNode must be a child of ours */
1951 M3G_ASSERT(boneNode);
1952 boneNode->hasBones = M3G_TRUE;
1953 boneNode = boneNode->parent;
1958 * \brief Getter for skeleton.
1960 * \param handle SkinnedMesh object
1961 * \return Group object
1963 M3G_API M3GGroup m3gGetSkeleton(M3GSkinnedMesh handle)
1965 SkinnedMesh *mesh = (SkinnedMesh *)handle;
1966 M3G_VALIDATE_OBJECT(mesh);
1968 return mesh->skeleton;
1972 * \brief Getter for bone transform.
1974 * \param handle SkinnedMesh object
1976 * \param transform Transform
1978 M3G_API void m3gGetBoneTransform(M3GSkinnedMesh handle,
1980 M3GMatrix *transform)
1982 SkinnedMesh *mesh = (SkinnedMesh *)handle;
1983 Node *node = (Node *)hBone;
1987 M3G_VALIDATE_OBJECT(mesh);
1988 M3G_VALIDATE_OBJECT(node);
1990 if (!m3gIsChildOf((Node*) mesh->skeleton, node)) {
1991 m3gRaiseError(M3G_INTERFACE(mesh), M3G_INVALID_VALUE);
1995 boneCount = m3gArraySize(&mesh->bones);
1997 for (i = 0; i < boneCount; ++i) {
1998 Bone *bone = m3gGetArrayElement(&mesh->bones, i);
2000 if (bone->node == node) {
2001 m3gCopyMatrix(transform, &bone->toBone);
2008 * \brief Getter for bone vertices.
2010 * \param handle SkinnedMesh object
2012 * \param indices Influenced indices
2013 * \param weights Weights
2014 * \return Number of influenced vertices
2016 M3G_API M3Gint m3gGetBoneVertices(M3GSkinnedMesh handle,
2018 M3Gint *indices, M3Gfloat *weights)
2020 SkinnedMesh *mesh = (SkinnedMesh *)handle;
2021 Node *node = (Node *)hBone;
2022 M3Gint boneIndex, boneCount, count = 0;
2024 M3G_VALIDATE_OBJECT(mesh);
2025 M3G_VALIDATE_OBJECT(node);
2027 /* Check for errors */
2029 if (!m3gIsChildOf((Node*) mesh->skeleton, node)) {
2030 m3gRaiseError(M3G_INTERFACE(mesh), M3G_INVALID_VALUE);
2034 /* Find the bone index corresponding to our bone node */
2036 boneCount = m3gArraySize(&mesh->bones);
2038 for (boneIndex = 0; boneIndex < boneCount; ++boneIndex) {
2039 Bone *bone = m3gGetArrayElement(&mesh->bones, boneIndex);
2040 if (bone->node == node) {
2045 /* Loop over the vertices, outputting index-weight pairs for each
2046 * vertex influenced by the bone */
2048 if (boneIndex < boneCount) {
2051 for (i = 0; i < mesh->weightedVertexCount; ++i) {
2052 for (j = 0; j < mesh->bonesPerVertex; ++j) {
2053 if (mesh->boneIndices[j][i] == boneIndex && mesh->boneWeights[j][i] > 0) {
2054 if (indices != NULL && weights != NULL) {
2056 for (k = 0; k < mesh->bonesPerVertex; ++k) {
2057 sum += mesh->boneWeights[k][i];
2061 weights[count] = ((M3Gfloat) mesh->boneWeights[j][i]) / sum;