m3g/m3gcore11/src/m3g_skinnedmesh.c
changeset 0 5d03bc08d59c
equal deleted inserted replaced
-1:000000000000 0:5d03bc08d59c
       
     1 /*
       
     2 * Copyright (c) 2003 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     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".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: SkinnedMesh implementation
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 /*!
       
    20  * \internal
       
    21  * \file
       
    22  * \brief SkinnedMesh implementation
       
    23  */
       
    24 
       
    25 #ifndef M3G_CORE_INCLUDE
       
    26 #   error included by m3g_core.c; do not compile separately.
       
    27 #endif
       
    28 
       
    29 #include "m3g_skinnedmesh.h"
       
    30 #include "m3g_memory.h"
       
    31 #include "m3g_animationtrack.h"
       
    32 
       
    33 /*----------------------------------------------------------------------
       
    34  * Internal structures
       
    35  *--------------------------------------------------------------------*/
       
    36 
       
    37 struct BoneRecord
       
    38 {
       
    39     Node *node;
       
    40 
       
    41     /*! \internal \brief "At-rest" transformation from skinned mesh to bone */
       
    42     Matrix toBone;
       
    43 
       
    44     /*! \internal \brief Cached animated transformation for positions */
       
    45     M3Gshort baseMatrix[9];
       
    46     M3Gshort posVec[3];
       
    47     M3Gshort baseExp, posExp, maxExp;
       
    48 
       
    49     /*! \internal \brief Cached animated transformation for normals */
       
    50     M3Gshort normalMatrix[9];
       
    51 };
       
    52 
       
    53 /*----------------------------------------------------------------------
       
    54  * Internal functions
       
    55  *--------------------------------------------------------------------*/
       
    56 
       
    57 /*!
       
    58  * \internal
       
    59  * \brief Destroys this SkinnedMesh object.
       
    60  *
       
    61  * \param obj SkinnedMesh object
       
    62  */
       
    63 static void m3gDestroySkinnedMesh(Object *obj)
       
    64 {
       
    65     SkinnedMesh *mesh = (SkinnedMesh *) obj;
       
    66     M3G_VALIDATE_OBJECT(mesh);
       
    67     {
       
    68         int i;
       
    69         Interface *m3g = M3G_INTERFACE(mesh);
       
    70         
       
    71         m3gDeleteVertexBuffer(mesh->morphedVB);
       
    72 
       
    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]);
       
    77         }
       
    78         m3gFree(m3g, mesh->weightShifts);
       
    79         
       
    80         for (i = 0; i < m3gArraySize(&mesh->bones); ++i) {
       
    81             m3gFree(m3g, m3gGetArrayElement(&mesh->bones, i));
       
    82         }
       
    83         m3gDestroyArray(&mesh->bones, m3g);
       
    84         
       
    85         if (mesh->skeleton != NULL) {
       
    86             m3gSetParent((Node*) mesh->skeleton, NULL);
       
    87             M3G_ASSIGN_REF(mesh->skeleton, NULL);
       
    88         }
       
    89     }
       
    90     m3gDestroyMesh(obj);
       
    91 }
       
    92 
       
    93 
       
    94 /*!
       
    95  * \internal
       
    96  * \brief Get a bone index for a given node
       
    97  *
       
    98  * This finds an existing record if the bone has been added
       
    99  * previously, or creates a new one if no record exists yet.
       
   100  *
       
   101  * \note Inline because only called from AddTransform.
       
   102  */
       
   103 static M3G_INLINE M3Gint m3gBoneIndex(SkinnedMesh *mesh, Node *node)
       
   104 {
       
   105     PointerArray *boneArray = &mesh->bones;
       
   106     const int numBones = m3gArraySize(boneArray);
       
   107     
       
   108     /* First look for an existing record in the array */
       
   109     {
       
   110         int i;
       
   111         
       
   112         for (i = 0; i < numBones; ++i) {
       
   113             Bone *b = m3gGetArrayElement(boneArray, i);
       
   114             if (b->node == node) {
       
   115                 return i;
       
   116             }
       
   117         }
       
   118     }
       
   119 
       
   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! */
       
   123     {
       
   124         Interface *m3g = M3G_INTERFACE(mesh);
       
   125         
       
   126         if (numBones >= 256) {
       
   127             /* Out of available bone indices */
       
   128             m3gRaiseError(m3g, M3G_OUT_OF_MEMORY);
       
   129             return -1;
       
   130         }
       
   131         else {
       
   132             M3Gint idx;
       
   133             Bone *bone = (Bone*) m3gAllocZ(m3g, sizeof(Bone));
       
   134             if (!bone || !m3gGetTransformTo((Node*) mesh, node,
       
   135                                             &bone->toBone)) {
       
   136                 m3gFree(m3g, bone);
       
   137                 return -1; /* out of memory or singular transform */
       
   138             }
       
   139             bone->node = node;
       
   140 
       
   141             idx = m3gArrayAppend(boneArray, bone, m3g);
       
   142             if (idx < 0) {
       
   143                 m3gFree(m3g, bone);
       
   144                 return -1; /* out of memory */
       
   145             }
       
   146             return idx;
       
   147         }
       
   148     }
       
   149 }
       
   150 
       
   151 /*!
       
   152  * \internal
       
   153  * \brief Reallocate the per-vertex data if necessary.
       
   154  *
       
   155  * \note Inline because only called from AddTransform.
       
   156  */
       
   157 static M3G_INLINE M3Gbool m3gEnsureVertexCount(SkinnedMesh *mesh, M3Gint count)
       
   158 {
       
   159     /* Reallocate only if vertex count increased */
       
   160     
       
   161     if (count > mesh->weightedVertexCount) {
       
   162         
       
   163         Interface *m3g = M3G_INTERFACE(mesh);
       
   164 
       
   165         int i;
       
   166 
       
   167         /* Reallocate the weight shift array */
       
   168         {
       
   169             M3Gubyte *pNew = (M3Gubyte*) m3gAllocZ(m3g, count);
       
   170             if (!pNew) {
       
   171                 return M3G_FALSE;
       
   172             }
       
   173             m3gCopy(pNew, mesh->weightShifts, mesh->weightedVertexCount);
       
   174             m3gFree(m3g, mesh->weightShifts);
       
   175             mesh->weightShifts = pNew;
       
   176         }
       
   177 
       
   178         /* Reallocate each of the bone index and weight arrays */
       
   179         
       
   180         for (i = 0; i < mesh->bonesPerVertex; ++i) {
       
   181             
       
   182             M3Gubyte *pNew;
       
   183             
       
   184             /* Weights */
       
   185             pNew = (M3Gubyte*) m3gAllocZ(m3g, count);
       
   186             if (!pNew) {
       
   187                 return M3G_FALSE; /* out of memory */
       
   188             }
       
   189             m3gCopy(pNew, mesh->boneWeights[i], mesh->weightedVertexCount);
       
   190             m3gFree(m3g, mesh->boneWeights[i]);
       
   191             mesh->boneWeights[i] = pNew;
       
   192             
       
   193             pNew = (M3Gubyte*) m3gAllocZ(m3g, count);
       
   194             if (!pNew) {
       
   195                 return M3G_FALSE; /* out of memory */
       
   196             }
       
   197             m3gCopy(pNew, mesh->normalizedWeights[i],
       
   198                     mesh->weightedVertexCount);
       
   199             m3gFree(m3g, mesh->normalizedWeights[i]);
       
   200             mesh->normalizedWeights[i] = pNew;
       
   201 
       
   202             /* Indices */
       
   203             pNew = (M3Gubyte*) m3gAllocZ(m3g, count);
       
   204             if (!pNew) {
       
   205                 return M3G_FALSE; /* out of memory */
       
   206             }
       
   207             m3gCopy(pNew, mesh->boneIndices[i], mesh->weightedVertexCount);
       
   208             m3gFree(m3g, mesh->boneIndices[i]);
       
   209             mesh->boneIndices[i] = pNew;
       
   210         }
       
   211 
       
   212         mesh->weightedVertexCount = count;
       
   213     }
       
   214     return M3G_TRUE;
       
   215 }
       
   216     
       
   217 /*!
       
   218  * \internal
       
   219  * \brief Reallocate the per-vertex data if necessary.
       
   220  *
       
   221  * \note Inline because only called from AddTransform.
       
   222  */
       
   223 static M3G_INLINE M3Gbool m3gEnsureBonesPerVertex(SkinnedMesh *mesh,
       
   224                                                   M3Gint count)
       
   225 {
       
   226     M3G_ASSERT(count <= M3G_MAX_VERTEX_TRANSFORMS);
       
   227 
       
   228     /* Allocate only if per-vertex bone count increased */
       
   229     
       
   230     if (count > mesh->bonesPerVertex) {
       
   231         
       
   232         Interface *m3g = M3G_INTERFACE(mesh);
       
   233         
       
   234         const M3Gint vertexCount = mesh->weightedVertexCount;
       
   235         M3Gubyte *pNew;
       
   236         
       
   237         int i;
       
   238 
       
   239         /* Allocate new arrays for bone indices and weights until
       
   240          * we're satisfied */
       
   241         
       
   242         for (i = mesh->bonesPerVertex; i < count; ++i) {
       
   243             pNew = (M3Gubyte*) m3gAllocZ(m3g, vertexCount);
       
   244             if (!pNew) {
       
   245                 goto AllocFailed; /* out of memory */
       
   246             }
       
   247             mesh->boneIndices[i] = pNew;
       
   248             
       
   249             pNew = (M3Gubyte*) m3gAllocZ(m3g, vertexCount);
       
   250             if (!pNew) {
       
   251                 goto AllocFailed; /* out of memory */
       
   252             }
       
   253             mesh->boneWeights[i] = pNew;
       
   254             
       
   255             pNew = (M3Gubyte*) m3gAllocZ(m3g, vertexCount);
       
   256             if (!pNew) {
       
   257                 goto AllocFailed; /* out of memory */
       
   258             }
       
   259             mesh->normalizedWeights[i] = pNew;
       
   260         }
       
   261 
       
   262         mesh->bonesPerVertex = count;
       
   263         return M3G_TRUE;
       
   264 
       
   265         /* In case of failure, clean up to keep the bonesPerVertex
       
   266          * counter in sync with the actual number of arrays
       
   267          * allocated */
       
   268     
       
   269     AllocFailed:
       
   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]);
       
   274 
       
   275             mesh->boneIndices[i] = NULL;
       
   276             mesh->boneWeights[i] = NULL;
       
   277             mesh->normalizedWeights[i] = NULL;
       
   278         }
       
   279         return M3G_FALSE;
       
   280     }
       
   281     return M3G_TRUE;
       
   282 }
       
   283     
       
   284 /*!
       
   285  * \internal
       
   286  * \brief Add a new bone influence to a vertex
       
   287  *
       
   288  * If the target vertex is already affected by
       
   289  * M3G_MAX_VERTEX_TRANSFORMS bones, the one with the lowest weight is
       
   290  * discarded.
       
   291  */
       
   292 static M3G_INLINE void m3gAddInfluence(SkinnedMesh *mesh,
       
   293                                        M3Gint vertexIndex,
       
   294                                        M3Gint boneIndex,
       
   295                                        M3Gint weight) 
       
   296 {
       
   297     M3Gint bonesPerVertex = mesh->bonesPerVertex;
       
   298     M3Guint minWeight = weight;
       
   299     M3Gint minWeightIndex = -1;
       
   300     int i;
       
   301 
       
   302     /* Shift the weight into the same scale with the other weights for
       
   303      * this vertex. */
       
   304 
       
   305     weight >>= mesh->weightShifts[vertexIndex];
       
   306 
       
   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
       
   311      * zero. */
       
   312         
       
   313     for (i = 0; i < bonesPerVertex; ++i) {
       
   314 
       
   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. */
       
   318         
       
   319         if (mesh->boneIndices[i][vertexIndex] == boneIndex) {
       
   320             weight += mesh->boneWeights[i][vertexIndex];
       
   321             minWeightIndex = i;
       
   322             break;
       
   323         }
       
   324         else {
       
   325             M3Guint tempWeight = mesh->boneWeights[i][vertexIndex];
       
   326             if (tempWeight < minWeight) {
       
   327                 minWeight = tempWeight;
       
   328                 minWeightIndex = i;
       
   329             }
       
   330         }
       
   331     }
       
   332 
       
   333     /* Check whether our total weight exceeds the allocated range,
       
   334      * shifting all existing weights down if necessary */
       
   335 
       
   336     while (weight >= (1 << 8)) { /* byte range */
       
   337         weight >>= 1;
       
   338         mesh->weightShifts[vertexIndex] += 1;
       
   339         for (i = 0; i < bonesPerVertex; ++i) {
       
   340             mesh->boneWeights[i][vertexIndex] >>= 1;
       
   341         }
       
   342         M3G_ASSERT(mesh->weightShifts[vertexIndex] <= 31);
       
   343     }
       
   344 
       
   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 */
       
   348         
       
   349     if (minWeightIndex >= 0) {
       
   350         mesh->boneIndices[minWeightIndex][vertexIndex] = (M3Gubyte) boneIndex;
       
   351         mesh->boneWeights[minWeightIndex][vertexIndex] = (M3Gubyte) weight;
       
   352 
       
   353         /* Need an update of the normalizing scales, too, as well as
       
   354          * the actual transformed vertices */
       
   355         
       
   356         mesh->weightsDirty = M3G_TRUE;
       
   357         m3gInvalidateNode((Node*) mesh, NODE_TRANSFORMS_BIT|NODE_BBOX_BIT);
       
   358     }
       
   359 }
       
   360 
       
   361 /*!
       
   362  * \internal
       
   363  * \brief Computes the normalization scales for vertex weights
       
   364  */
       
   365 static void m3gNormalizeWeights(SkinnedMesh *mesh)
       
   366 {
       
   367     const M3Gint bonesPerVertex = mesh->bonesPerVertex;
       
   368     const M3Gint vertexCount = mesh->weightedVertexCount;
       
   369     M3Gint vi;
       
   370 
       
   371     for (vi = 0; vi < vertexCount; ++vi) {
       
   372         M3Gint k;
       
   373         
       
   374         /* Sum up the 8-bit (possibly downshifted) weights */
       
   375         
       
   376         M3Guint sum = 0;
       
   377         for (k = 0; k < bonesPerVertex; ++k) {
       
   378             sum += mesh->boneWeights[k][vi];
       
   379         }
       
   380 
       
   381         /* Compute an 8.24 reciprocal of the weights, then scale with
       
   382          * that to normalize, and shift to 1.7 fixed point */
       
   383         {
       
   384             M3Guint s = (sum > 0 ? (1U << 24) / sum : 0);
       
   385 
       
   386             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));
       
   390                 sum += normalized;
       
   391                 mesh->normalizedWeights[k][vi] = (M3Gubyte) normalized;
       
   392             }
       
   393             
       
   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 */
       
   399             
       
   400             M3G_ASSERT(sum == 0 || m3gInRange((M3Gint) sum, 96, 128));
       
   401         }
       
   402     }
       
   403 
       
   404     mesh->weightsDirty = M3G_FALSE;
       
   405 }
       
   406 
       
   407 /*!
       
   408  * \internal
       
   409  * \brief Computes an optimal exponent value for a fixed point
       
   410  * transformation
       
   411  *
       
   412  * This scales the translation exponent up to optimally utilize the
       
   413  * 32-bit intermediate precision if the matrix exponent is smaller.
       
   414  */
       
   415 static M3Gint m3gOptimalExponent(M3Gint matrixExp, M3Gint transExp)
       
   416 {
       
   417     M3Gint maxExp = matrixExp;
       
   418     M3Gint shift = transExp - matrixExp;
       
   419     if (shift > 0) {
       
   420 
       
   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. */
       
   427 
       
   428         if (shift >= 32) {      /* matrix will flush to zero */
       
   429             shift = 16;
       
   430         }
       
   431         else if (shift >= 16) { /* matrix always < half of the range */
       
   432             shift = 15;
       
   433         }
       
   434         else {
       
   435             shift -= 1;     /* shift matrix by at least one bit */
       
   436         }
       
   437         
       
   438         maxExp = transExp - shift;
       
   439     }
       
   440     
       
   441     M3G_ASSERT(maxExp >= matrixExp && maxExp >= transExp - 16);
       
   442     return maxExp;
       
   443 }
       
   444 
       
   445 /*
       
   446  * \brief Fixed point vertex transformation
       
   447  *
       
   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
       
   458  */
       
   459 static M3Gint m3gFixedPointTransform(const M3Gshort *mtx, M3Gint mtxExp,
       
   460                                      const M3Gshort *trans, M3Gint transExp,
       
   461                                      M3Gint maxExp,
       
   462                                      M3Gint vx, M3Gint vy, M3Gint vz,
       
   463                                      M3Gint *out)
       
   464 {
       
   465     M3Gint shift;
       
   466     M3Gint ox = 0, oy = 0, oz = 0;
       
   467     
       
   468     /* First put in the translation part, upscaled to the optimal
       
   469      * range for this bone */
       
   470 
       
   471     if (trans) {
       
   472         shift = maxExp - (transExp - 16);
       
   473         M3G_ASSERT(shift >= 0);
       
   474         if (shift < 32) {
       
   475             ox += ((M3Gint) trans[0] << 16) >> shift;
       
   476             oy += ((M3Gint) trans[1] << 16) >> shift;
       
   477             oz += ((M3Gint) trans[2] << 16) >> shift;
       
   478         }
       
   479     }
       
   480         
       
   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
       
   483      * outcome */
       
   484     
       
   485     shift = maxExp - mtxExp;
       
   486     M3G_ASSERT(shift >= 0);
       
   487     if (shift < 32) {
       
   488         
       
   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 */
       
   496         
       
   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;
       
   500     }
       
   501 
       
   502     /* Shift the output down to fit into 25 bits; we're dropping 7
       
   503      * bits of precision here, so adjust the exponent accordingly */
       
   504 
       
   505     out[0] = ox >> 7;
       
   506     out[1] = oy >> 7;
       
   507     out[2] = oz >> 7;
       
   508     return maxExp + 7;
       
   509 }
       
   510 
       
   511 /*!
       
   512  * \internal
       
   513  * \brief Applies scale and bias to a vertex
       
   514  *
       
   515  * This is required for vertices that have no bones attached.
       
   516  * 
       
   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
       
   525  */
       
   526 static M3Gint m3gScaleAndBiasVertex(const SkinnedMesh *mesh,
       
   527                                     M3Gint vx, M3Gint vy, M3Gint vz,
       
   528                                     M3Gint upshift,
       
   529                                     M3Gshort *vertex)
       
   530 {
       
   531     M3Gint temp[3];
       
   532     M3Gint expo;
       
   533 
       
   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));
       
   537     
       
   538     expo = m3gFixedPointTransform(mesh->scaleMatrix, mesh->scaleExp,
       
   539                                   mesh->biasVector, mesh->biasExp + upshift,
       
   540                                   mesh->scaleBiasExp,
       
   541                                   vx << upshift, vy << upshift, vz << upshift,
       
   542                                   temp) - upshift;
       
   543 
       
   544     /* Scale down from 25 to 16 bits, adjusting the exponent
       
   545      * accordingly */
       
   546     
       
   547     vertex[0] = (M3Gshort)(temp[0] >> 9);
       
   548     vertex[1] = (M3Gshort)(temp[1] >> 9);
       
   549     vertex[2] = (M3Gshort)(temp[2] >> 9);
       
   550     expo += 9;
       
   551     
       
   552     M3G_ASSERT(m3gInRange(expo, -127, 127));
       
   553     return expo;
       
   554 }
       
   555 
       
   556 /*!
       
   557  * \internal
       
   558  * \brief Computes the blended position for a single vertex
       
   559  *
       
   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
       
   569  */
       
   570 static M3Gint m3gBlendVertex(const SkinnedMesh *mesh,
       
   571                              M3Gint vidx,
       
   572                              M3Gint vx, M3Gint vy, M3Gint vz,
       
   573                              M3Gint upshift,
       
   574                              M3Gshort *vertex)
       
   575 {
       
   576     const M3Gint boneCount = mesh->bonesPerVertex;
       
   577     const PointerArray *boneArray = &mesh->bones;
       
   578     M3Gint i;
       
   579     
       
   580     M3Gint outExp = -128;
       
   581     M3Gint sumWeights = 0;
       
   582     
       
   583     M3Gint ox = 0, oy = 0, oz = 0;
       
   584     
       
   585     vx <<= upshift;
       
   586     vy <<= upshift;
       
   587     vz <<= upshift;
       
   588 
       
   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));
       
   592 
       
   593     /* Loop over the bones and sum the contribution from each */
       
   594     
       
   595     for (i = 0; i < boneCount; ++i) {
       
   596         
       
   597         M3Gint weight = (M3Gint) mesh->normalizedWeights[i][vidx];
       
   598         sumWeights += weight;
       
   599 
       
   600         /* Skip bones with zero weights */
       
   601         
       
   602         if (weight > 0) {
       
   603             
       
   604             const Bone *bone = (const Bone *)
       
   605                 m3gGetArrayElement(boneArray, mesh->boneIndices[i][vidx]);
       
   606             M3Gint temp[3];
       
   607             M3Gint shift;
       
   608 
       
   609             shift = m3gFixedPointTransform(bone->baseMatrix, bone->baseExp,
       
   610                                            bone->posVec, bone->posExp + upshift,
       
   611                                            bone->maxExp,
       
   612                                            vx, vy, vz,
       
   613                                            temp);
       
   614 
       
   615             shift = outExp - shift;
       
   616             if (shift < 0) {
       
   617                 shift = -shift;
       
   618                 if (shift < 31) {
       
   619                     ox >>= shift;
       
   620                     oy >>= shift;
       
   621                     oz >>= shift;
       
   622                 }
       
   623                 else {
       
   624                     ox = oy = oz = 0;
       
   625                 }
       
   626                 outExp += shift;
       
   627                 shift = 0;
       
   628             }
       
   629 
       
   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 */
       
   633             
       
   634             if (shift < 31) {
       
   635                 
       
   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));
       
   639                 
       
   640                 ox += (weight * temp[0]) >> shift;
       
   641                 oy += (weight * temp[1]) >> shift;
       
   642                 oz += (weight * temp[2]) >> shift;
       
   643             }
       
   644         }
       
   645     }
       
   646 
       
   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 */
       
   652 
       
   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;
       
   658 
       
   659         M3G_ASSERT(m3gInRange(outExp, -127, 127));
       
   660         return outExp;
       
   661     }
       
   662     else {
       
   663         vx >>= upshift;
       
   664         vy >>= upshift;
       
   665         vz >>= upshift;
       
   666         return m3gScaleAndBiasVertex(mesh, vx, vy, vz, upshift, vertex);
       
   667     }
       
   668 }
       
   669 
       
   670 /*!
       
   671  * \internal
       
   672  * \brief Computes the blended normal vector for a single vertex
       
   673  *
       
   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)
       
   682  */
       
   683 static void m3gBlendNormal(const SkinnedMesh *mesh,
       
   684                            M3Gint vidx,
       
   685                            M3Gint nx, M3Gint ny, M3Gint nz,
       
   686                            M3Gint upshift,
       
   687                            M3Gbyte *normal)
       
   688 {
       
   689     const M3Gint boneCount = mesh->bonesPerVertex;
       
   690     const PointerArray *boneArray = &mesh->bones;
       
   691     M3Gint i;
       
   692     
       
   693     M3Gint outExp = -128;
       
   694     M3Gint sumWeights = 0;
       
   695     
       
   696     M3Gint ox = 0, oy = 0, oz = 0;
       
   697 
       
   698     nx <<= upshift;
       
   699     ny <<= upshift;
       
   700     nz <<= upshift;
       
   701     
       
   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));
       
   705 
       
   706     /* Loop over the bones and sum the contribution from each */
       
   707     
       
   708     for (i = 0; i < boneCount; ++i) {
       
   709         
       
   710         M3Gint weight = (M3Gint) mesh->normalizedWeights[i][vidx];
       
   711         sumWeights += weight;
       
   712 
       
   713         /* Skip bones with zero weights */
       
   714         
       
   715         if (weight > 0) {
       
   716             
       
   717             const Bone *bone = (const Bone *)
       
   718                 m3gGetArrayElement(boneArray, mesh->boneIndices[i][vidx]);
       
   719             M3Gint temp[3];
       
   720             M3Gint shift;
       
   721 
       
   722             shift = m3gFixedPointTransform(bone->normalMatrix, 0,
       
   723                                            NULL, 0,
       
   724                                            0,
       
   725                                            nx, ny, nz,
       
   726                                            temp);
       
   727 
       
   728             shift = outExp - shift;
       
   729             if (shift < 0) {
       
   730                 shift = -shift;
       
   731                 if (shift < 31) {
       
   732                     ox >>= shift;
       
   733                     oy >>= shift;
       
   734                     oz >>= shift;
       
   735                 }
       
   736                 else {
       
   737                     ox = oy = oz = 0;
       
   738                 }
       
   739                 outExp += shift;
       
   740                 shift = 0;
       
   741             }
       
   742 
       
   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 */
       
   746             
       
   747             if (shift < 31) {
       
   748                 
       
   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));
       
   752                 
       
   753                 ox += (weight * temp[0]) >> shift;
       
   754                 oy += (weight * temp[1]) >> shift;
       
   755                 oz += (weight * temp[2]) >> shift;
       
   756             }
       
   757         }
       
   758     }
       
   759 
       
   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 */
       
   763 
       
   764     if (sumWeights > 0) {
       
   765         normal[0] = (M3Gbyte)(ox >> 24);
       
   766         normal[1] = (M3Gbyte)(oy >> 24);
       
   767         normal[2] = (M3Gbyte)(oz >> 24);
       
   768     }
       
   769     else {
       
   770         normal[0] = (M3Gbyte)(ox >> 8);
       
   771         normal[1] = (M3Gbyte)(oy >> 8);
       
   772         normal[2] = (M3Gbyte)(oz >> 8);
       
   773     }
       
   774 }
       
   775 
       
   776 /*!
       
   777  * \internal
       
   778  * \brief Updates internal vertex buffer
       
   779  *
       
   780  * \param mesh SkinnedMesh object
       
   781  *
       
   782  * \retval M3G_TRUE VertexBuffer is up to date
       
   783  * \retval M3G_FALSE Failed to update VertexBuffer, out of memory exception raised
       
   784  */
       
   785 static M3Gbool m3gSkinnedMeshUpdateVB(SkinnedMesh *mesh)
       
   786 {
       
   787     M3Gint vbTimestamp;
       
   788     M3G_ASSERT(mesh->mesh.vertexBuffer != NULL);
       
   789     M3G_ASSERT(mesh->morphedVB != NULL);
       
   790     
       
   791     /* Source vertex buffer array configuration changed since last
       
   792      * update? */
       
   793 
       
   794     vbTimestamp = m3gGetTimestamp(mesh->mesh.vertexBuffer);
       
   795     
       
   796     if (mesh->vbTimestamp != vbTimestamp) {
       
   797         Interface *m3g = M3G_INTERFACE(mesh);
       
   798         VertexArray *array;
       
   799         M3Gint vcount = m3gGetVertexCount(mesh->mesh.vertexBuffer);
       
   800 
       
   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 */
       
   804         
       
   805         if (!m3gMakeModifiedVertexBuffer(mesh->morphedVB,
       
   806                                          mesh->mesh.vertexBuffer,
       
   807                                          M3G_POSITION_BIT|M3G_NORMAL_BIT,
       
   808                                          M3G_FALSE)) {
       
   809             return M3G_FALSE; /* out of memory */
       
   810         }
       
   811 
       
   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 */
       
   815 
       
   816         if (mesh->mesh.vertexBuffer->vertices) {
       
   817             array = m3gCreateVertexArray(m3g, vcount, 3, M3G_SHORT);
       
   818             if (!array) {
       
   819                 return M3G_FALSE;
       
   820             }
       
   821             m3gSetVertexArray(mesh->morphedVB, array, 1.f, NULL, 0);
       
   822         }
       
   823 
       
   824         /* Normals (always bytes) only exist if in the original VB */
       
   825         
       
   826         if (mesh->mesh.vertexBuffer->normals) {
       
   827             array = m3gCreateVertexArray(m3g, vcount, 3, M3G_BYTE);
       
   828             if (!array) {
       
   829                 return M3G_FALSE;
       
   830             }
       
   831             m3gSetNormalArray(mesh->morphedVB, array);
       
   832         }
       
   833     
       
   834         mesh->vbTimestamp = vbTimestamp;
       
   835     }
       
   836     
       
   837     /* The default color must always be updated, because it can be
       
   838      * animated (doesn't affect timestamp) */
       
   839     
       
   840     mesh->morphedVB->defaultColor = mesh->mesh.vertexBuffer->defaultColor;
       
   841     return M3G_TRUE;
       
   842 }
       
   843 
       
   844 
       
   845 /*!
       
   846  * \internal
       
   847  * \brief Gets the transformation(s) for a single bone record
       
   848  *
       
   849  * Also stores the normal transformation matrix if needed.
       
   850  *
       
   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
       
   856  */
       
   857 static M3G_INLINE M3Gbool m3gGetBoneTransformInternal(SkinnedMesh *mesh,
       
   858                                               Bone *bone,
       
   859                                               M3Gbool hasNormals,
       
   860                                               Matrix *mtx)
       
   861 {
       
   862     const VertexBuffer *vb = mesh->mesh.vertexBuffer;
       
   863 
       
   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 */
       
   868     
       
   869     if (!m3gGetTransformTo(bone->node, (Node*) mesh, mtx)) {
       
   870         return M3G_FALSE; /* no path or singular transform */
       
   871     }
       
   872     m3gMulMatrix(mtx, &bone->toBone);
       
   873 
       
   874     /* If normals are enabled, compute and store the inverse transpose
       
   875      * matrix for transforming normals at this stage */
       
   876     
       
   877     if (hasNormals) {
       
   878         Matrix t;
       
   879         if (!m3gInverseTranspose(&t, mtx)) {
       
   880             m3gRaiseError(M3G_INTERFACE(mesh), M3G_ARITHMETIC_ERROR);
       
   881             return M3G_FALSE; /* singular transform */
       
   882         }
       
   883         m3gGetFixedPoint3x3Basis(&t, bone->normalMatrix);
       
   884     }
       
   885 
       
   886     /* Apply the vertex bias and scale to the transformation */
       
   887     
       
   888     m3gTranslateMatrix(
       
   889         mtx, vb->vertexBias[0], vb->vertexBias[1], vb->vertexBias[2]);
       
   890     m3gScaleMatrix(mtx, vb->vertexScale, vb->vertexScale, vb->vertexScale);
       
   891     
       
   892     return M3G_TRUE;
       
   893 }
       
   894 
       
   895 /*!
       
   896  * \internal
       
   897  * \brief Compute and cache the bone transformations for morphing
       
   898  *
       
   899  * \param mesh     the SkinnedMesh object
       
   900  * \param posShift vertex position value "gain"
       
   901  */
       
   902 static M3Gbool m3gPreComputeTransformations(SkinnedMesh *mesh,
       
   903                                             M3Gint posShift,
       
   904                                             M3Gbool hasNormals)
       
   905 {
       
   906     M3Gint boneCount = m3gArraySize(&mesh->bones);
       
   907     M3Gint i;
       
   908     Matrix *tBone = NULL;
       
   909 
       
   910     /* First, just compute the floating point transformation matrices
       
   911      * for the bones, caching them in a temp array */
       
   912 
       
   913     if (boneCount > 0) {
       
   914         tBone = m3gAllocTemp(M3G_INTERFACE(mesh), boneCount * sizeof(Matrix));
       
   915         if (!tBone) {
       
   916             return M3G_FALSE; /* out of memory */
       
   917         }    
       
   918         for (i = 0; i < boneCount; ++i) {
       
   919             Bone *bone = m3gGetArrayElement(&mesh->bones, i);
       
   920             if (!m3gGetBoneTransformInternal(mesh, bone, hasNormals, &tBone[i])) {
       
   921                 return M3G_FALSE;
       
   922             }
       
   923         }
       
   924     }
       
   925 
       
   926     /* Find the value range of the bone translations, and offset the
       
   927      * bones to center output vertex values (roughly) around the
       
   928      * origin */
       
   929     {
       
   930         const VertexBuffer *vb = mesh->mesh.vertexBuffer;
       
   931         M3Gfloat min[3], max[3], bias[3];
       
   932         M3Gint maxExp;
       
   933         Vec4 t;
       
   934 
       
   935         /* Find the minimum and maximum values; start with the plain
       
   936          * vertex bias for non-weighted bones */
       
   937         
       
   938         min[0] = max[0] = vb->vertexBias[0];
       
   939         min[1] = max[1] = vb->vertexBias[1];
       
   940         min[2] = max[2] = vb->vertexBias[2];
       
   941         
       
   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);
       
   950         }
       
   951         
       
   952         /* Divide to get the mean translation, store in the
       
   953          * destination VB, and invert for de-biasing the bones */
       
   954         
       
   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]);
       
   959         }
       
   960         
       
   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 */
       
   964 
       
   965         maxExp = -128;
       
   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 */
       
   969             
       
   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);
       
   976 
       
   977             maxExp = M3G_MAX(maxExp, bone->maxExp);
       
   978         }
       
   979 
       
   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) */
       
   984         {
       
   985             Matrix sb;
       
   986             m3gTranslationMatrix(&sb,
       
   987                                  m3gAdd(bias[0], vb->vertexBias[0]),
       
   988                                  m3gAdd(bias[1], vb->vertexBias[1]),
       
   989                                  m3gAdd(bias[2], vb->vertexBias[2]));
       
   990             m3gScaleMatrix(&sb,
       
   991                            vb->vertexScale, vb->vertexScale, vb->vertexScale);
       
   992             
       
   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);
       
   999         
       
  1000             maxExp = M3G_MAX(mesh->scaleBiasExp, maxExp);
       
  1001         }
       
  1002 
       
  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! */
       
  1007 
       
  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;
       
  1012     }
       
  1013     
       
  1014     if (boneCount > 0) {
       
  1015         m3gFreeTemp(M3G_INTERFACE(mesh));
       
  1016     }
       
  1017     
       
  1018     return M3G_TRUE;
       
  1019 }
       
  1020 
       
  1021 /*!
       
  1022  * \internal
       
  1023  * \brief Computes derived data required for bounding volumes and skinning
       
  1024  */
       
  1025 static M3Gbool m3gSkinnedMeshPreMorph(SkinnedMesh *mesh)
       
  1026 {
       
  1027     const VertexBuffer *srcVB = mesh->mesh.vertexBuffer;
       
  1028     M3Gint posShift = 0, normalShift = 0;
       
  1029     
       
  1030     /* Compute upscaling shift values for positions and normals so
       
  1031      * that we can maximize precision even for absurdly small
       
  1032      * vertex values */
       
  1033     {
       
  1034         M3Gint minVal, maxVal;
       
  1035         
       
  1036         if (srcVB->normals) {
       
  1037             m3gGetArrayValueRange(srcVB->normals, &minVal, &maxVal);
       
  1038             maxVal = M3G_MAX(-minVal, maxVal);
       
  1039             M3G_ASSERT(maxVal >= 0);
       
  1040             if (maxVal) {
       
  1041                 while ((maxVal << normalShift) < (1 << 14)) {
       
  1042                     ++normalShift;
       
  1043                 }
       
  1044             }
       
  1045         }
       
  1046             
       
  1047         m3gGetArrayValueRange(srcVB->vertices, &minVal, &maxVal);
       
  1048         maxVal = M3G_MAX(-minVal, maxVal);
       
  1049         M3G_ASSERT(maxVal >= 0);
       
  1050         if (maxVal) {
       
  1051             while ((maxVal << posShift) < (1 << 14)) {
       
  1052                 ++posShift;
       
  1053             }
       
  1054         }
       
  1055         
       
  1056         mesh->posShift    = (M3Gshort) posShift;
       
  1057         mesh->normalShift = (M3Gshort) normalShift;
       
  1058     }
       
  1059 
       
  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 */
       
  1064 
       
  1065     if (!m3gPreComputeTransformations(mesh,
       
  1066                                       posShift,
       
  1067                                       srcVB->normals != NULL)) { 
       
  1068         return M3G_FALSE; /* invalid transform */
       
  1069     }
       
  1070     
       
  1071     return M3G_TRUE;
       
  1072 }
       
  1073 
       
  1074 /*!
       
  1075  * \internal
       
  1076  * \brief Does the actual vertex morphing into the internal vertex buffer
       
  1077  *
       
  1078  * \param mesh   SkinnedMesh object
       
  1079  * \retval M3G_TRUE     skinning ok
       
  1080  * \retval M3G_FALSE    skinning failed, exception raised
       
  1081  */
       
  1082 static void m3gSkinnedMeshMorph(SkinnedMesh *mesh)
       
  1083 {
       
  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;
       
  1093     M3Gint i;
       
  1094 
       
  1095     M3G_ASSERT(!((Node*) mesh)->dirtyBits);
       
  1096     
       
  1097     /* Let's update the vertex weights if we need to */
       
  1098         
       
  1099     if (mesh->weightsDirty) {
       
  1100         m3gNormalizeWeights(mesh);
       
  1101     }
       
  1102 
       
  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 */
       
  1106         
       
  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);
       
  1112     }
       
  1113         
       
  1114     /* Transform the vertices that are affected by bones */
       
  1115     {
       
  1116         M3Gshort *dst = dstPositions;
       
  1117             
       
  1118         if (srcVB->vertices->elementType == GL_BYTE) {
       
  1119             const M3Gbyte *src = (const M3Gbyte*) srcPositions;
       
  1120             for (i = 0; i < vertexCount; ++i) {
       
  1121                 M3Gint shift =
       
  1122                     maxExp - m3gBlendVertex(mesh, i,
       
  1123                                             src[0], src[1], src[2],
       
  1124                                             posShift,
       
  1125                                             dst);
       
  1126                 if (shift > 31) {
       
  1127                     *dst++ = 0;
       
  1128                     *dst++ = 0;
       
  1129                     *dst++ = 0;
       
  1130                 }
       
  1131                 else {
       
  1132                     *dst++ >>= shift;
       
  1133                     *dst++ >>= shift;
       
  1134                     *dst++ >>= shift;
       
  1135                 }
       
  1136             
       
  1137                 src += 4; /* byte data always padded to 32 bits */
       
  1138             }
       
  1139         }
       
  1140         else {
       
  1141             const M3Gshort *src = (const M3Gshort*) srcPositions;
       
  1142             for (i = 0; i < vertexCount; ++i) {
       
  1143                 M3Gint shift =
       
  1144                     maxExp - m3gBlendVertex(mesh, i,
       
  1145                                             src[0], src[1], src[2],
       
  1146                                             posShift,
       
  1147                                             dst);
       
  1148                 if (shift > 31) {
       
  1149                     *dst++ = 0;
       
  1150                     *dst++ = 0;
       
  1151                     *dst++ = 0;
       
  1152                 }
       
  1153                 else {
       
  1154                     *dst++ >>= shift;
       
  1155                     *dst++ >>= shift;
       
  1156                     *dst++ >>= shift;
       
  1157                 }
       
  1158                 
       
  1159                 src += 3;
       
  1160             }
       
  1161         }
       
  1162     }
       
  1163 
       
  1164     /* Transform the normals (if enabled).  Normals will be
       
  1165      * normalized when rendering, so no need to keep track of
       
  1166      * scales here */
       
  1167         
       
  1168     if (srcNormals) {
       
  1169         M3Gbyte *dst = dstNormals;
       
  1170             
       
  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],
       
  1176                                normShift,
       
  1177                                dst);
       
  1178                 src += 4; /* byte data padded to 32 bits */
       
  1179                 dst += 4; 
       
  1180             }
       
  1181         }
       
  1182         else {
       
  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],
       
  1187                                normShift,
       
  1188                                dst);
       
  1189                 src += 3;
       
  1190                 dst += 4; 
       
  1191             }
       
  1192         }
       
  1193     }
       
  1194 
       
  1195     /* Finally, handle the remaining vertices, which have no bones
       
  1196      * attached; these just need to have the scale and bias
       
  1197      * applied */
       
  1198 
       
  1199     vertexCount = m3gGetNumVertices(srcVB);
       
  1200     if (i < vertexCount) {
       
  1201             
       
  1202         M3Gint startIndex = i;
       
  1203         M3Gshort *dstPos = dstPositions + startIndex * 3;
       
  1204         M3Gshort temp[3];
       
  1205             
       
  1206         if (srcVB->vertices->elementType == GL_BYTE) {
       
  1207             const M3Gbyte *src = ((const M3Gbyte*) srcPositions) + startIndex * 4;
       
  1208             for (i = startIndex ; i < vertexCount; ++i) {
       
  1209                 M3Gint shift =
       
  1210                     maxExp - m3gScaleAndBiasVertex(mesh,
       
  1211                                                    src[0], src[1], src[2],
       
  1212                                                    posShift,
       
  1213                                                    temp);
       
  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 */
       
  1218             }
       
  1219         }
       
  1220         else {
       
  1221             const M3Gshort *src = ((const M3Gshort*) srcPositions) + startIndex * 3;
       
  1222             for (i = startIndex ; i < vertexCount; ++i) {
       
  1223                 M3Gint shift =
       
  1224                     maxExp - m3gScaleAndBiasVertex(mesh,
       
  1225                                                    src[0], src[1], src[2],
       
  1226                                                    posShift,
       
  1227                                                    temp);
       
  1228                 *dstPos++ = (M3Gshort)(temp[0] >> shift);
       
  1229                 *dstPos++ = (M3Gshort)(temp[1] >> shift);
       
  1230                 *dstPos++ = (M3Gshort)(temp[2] >> shift);                    
       
  1231                 src += 3;
       
  1232             }
       
  1233         }
       
  1234             
       
  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 */
       
  1239                 
       
  1240         if (srcNormals) {
       
  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);
       
  1246             }
       
  1247             else {
       
  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 */
       
  1255                 }
       
  1256             }
       
  1257         }
       
  1258     }
       
  1259         
       
  1260     /* All done! Clean up and exit */
       
  1261 
       
  1262     m3gUnmapVertexArray(srcVB->vertices);
       
  1263     m3gUnmapVertexArray(dstVB->vertices);
       
  1264     if (srcNormals) {
       
  1265         m3gUnmapVertexArray(srcVB->normals);
       
  1266         m3gUnmapVertexArray(dstVB->normals);
       
  1267     }
       
  1268 }
       
  1269 
       
  1270 /*!
       
  1271  * \internal
       
  1272  * \brief Overloaded Node method.
       
  1273  *
       
  1274  * Setup skinned mesh render. Call mesh render setup,
       
  1275  * do skinning calculations and traverse into the skeleton or the parent
       
  1276  *
       
  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
       
  1282  *
       
  1283  * \retval M3G_TRUE continue render setup
       
  1284  * \retval M3G_FALSE abort render setup
       
  1285  */
       
  1286 static M3Gbool m3gSkinnedMeshSetupRender(Node *self,
       
  1287                                          const Node *caller,
       
  1288                                          SetupRenderState *s,
       
  1289                                          RenderQueue *renderQueue)
       
  1290 {
       
  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);
       
  1295     
       
  1296     /* Optimize the rendering-enable checking for top-down traversal */
       
  1297 
       
  1298     enabled = (self->enableBits & NODE_RENDER_BIT) != 0;
       
  1299     if (caller != self->parent) {
       
  1300         enabled = m3gHasEnabledPath(self, renderQueue->root);
       
  1301         s->cullMask = CULLMASK_ALL;
       
  1302     }
       
  1303 
       
  1304     /* Handle self and the skeleton if enabled */
       
  1305 
       
  1306     if (enabled) {
       
  1307         
       
  1308         /* Traverse into the skeleton unless coming from there */
       
  1309     
       
  1310         if (skeleton != caller) {
       
  1311             SetupRenderState cs;
       
  1312             cs.cullMask = s->cullMask;
       
  1313         
       
  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);
       
  1318         
       
  1319             success = M3G_VFUNC(Node, skeleton, setupRender)(skeleton,
       
  1320                                                              self,
       
  1321                                                              &cs,
       
  1322                                                              renderQueue);
       
  1323         }
       
  1324 
       
  1325         /* Handle self if in scope */
       
  1326         
       
  1327         if ((self->scope & renderQueue->scope) != 0) {
       
  1328 
       
  1329             /* Try view frustum culling */
       
  1330 
       
  1331 #           if defined(M3G_ENABLE_VF_CULLING)
       
  1332             m3gUpdateCullingMask(s, renderQueue->camera, &mesh->bbox);
       
  1333 #           endif
       
  1334 
       
  1335             if (s->cullMask == 0) {
       
  1336                 m3gIncStat(M3G_INTERFACE(self),
       
  1337                            M3G_STAT_RENDER_NODES_CULLED, 1);
       
  1338             }
       
  1339             else {
       
  1340                 success &= m3gQueueMesh((Mesh*) self, &s->toCamera, renderQueue);
       
  1341                 
       
  1342                 if (success) {
       
  1343                     M3G_BEGIN_PROFILE(M3G_INTERFACE(self), M3G_PROFILE_SKIN);
       
  1344                     m3gSkinnedMeshMorph(mesh);
       
  1345                     M3G_END_PROFILE(M3G_INTERFACE(self), M3G_PROFILE_SKIN);
       
  1346                 }
       
  1347             }
       
  1348         }
       
  1349     }
       
  1350 
       
  1351     /* Traverse into the parent node unless coming from there.  Again,
       
  1352      * discard the old traversal state at this point, as we're not
       
  1353      * coming back. */
       
  1354     
       
  1355     if (success && self != renderQueue->root) {
       
  1356         Node *parent = self->parent;
       
  1357         if (parent != NULL && parent != caller) {
       
  1358             Matrix t;
       
  1359             
       
  1360             M3G_BEGIN_PROFILE(M3G_INTERFACE(self), M3G_PROFILE_SETUP_TRANSFORMS);
       
  1361             if (!m3gGetInverseNodeTransform(self, &t)) {
       
  1362                 return M3G_FALSE;
       
  1363             }
       
  1364             m3gMulMatrix(&s->toCamera, &t);
       
  1365             M3G_END_PROFILE(M3G_INTERFACE(self), M3G_PROFILE_SETUP_TRANSFORMS);
       
  1366 
       
  1367             success = M3G_VFUNC(Node, parent, setupRender)(parent,
       
  1368                                                            self,
       
  1369                                                            s,
       
  1370                                                            renderQueue);
       
  1371         }
       
  1372     }
       
  1373 
       
  1374     return success;
       
  1375 }
       
  1376 
       
  1377 /*!
       
  1378  * \internal
       
  1379  * \brief Overloaded Node method.
       
  1380  *
       
  1381  * Renders one skinned submesh.
       
  1382  *
       
  1383  * \param self SkinnedMesh object
       
  1384  * \param ctx current render context
       
  1385  * \param patchIndex submesh index
       
  1386  */
       
  1387 static void m3gSkinnedMeshDoRender(Node *self,
       
  1388                                    RenderContext *ctx,
       
  1389                                    const Matrix *toCamera,
       
  1390                                    int patchIndex)
       
  1391 {
       
  1392     SkinnedMesh *mesh = (SkinnedMesh *)self;
       
  1393     IndexBuffer *indexBuffer = mesh->mesh.indexBuffers[patchIndex];
       
  1394     Appearance *appearance = mesh->mesh.appearances[patchIndex];
       
  1395 
       
  1396     if (indexBuffer == NULL || appearance == NULL)
       
  1397         return;
       
  1398 
       
  1399     m3gDrawMesh(ctx,
       
  1400                 mesh->morphedVB,
       
  1401                 indexBuffer,
       
  1402                 appearance,
       
  1403                 toCamera,
       
  1404                 mesh->mesh.totalAlphaFactor + 1,
       
  1405                 mesh->mesh.node.scope);
       
  1406 }
       
  1407 
       
  1408 /*!
       
  1409  * \internal
       
  1410  * \brief Overloaded Node method.
       
  1411  *
       
  1412  * Do skinning calculations and forward to Mesh internal ray intersect.
       
  1413  *
       
  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
       
  1421  */
       
  1422 static M3Gbool m3gSkinnedMeshRayIntersect(  Node *self,
       
  1423                                             M3Gint mask,
       
  1424                                             M3Gfloat *ray,
       
  1425                                             RayIntersection *ri,
       
  1426                                             Matrix *toGroup)
       
  1427 {
       
  1428     SkinnedMesh *mesh = (SkinnedMesh *)self;
       
  1429     M3G_BEGIN_PROFILE(M3G_INTERFACE(self), M3G_PROFILE_SKIN);
       
  1430 
       
  1431     if ((((Node *)mesh)->scope & mask) == 0) {
       
  1432         return M3G_TRUE;
       
  1433     }
       
  1434 
       
  1435     if (!m3gSkinnedMeshPreMorph(mesh)) {
       
  1436         return M3G_FALSE;
       
  1437     }
       
  1438     m3gSkinnedMeshMorph(mesh);
       
  1439     M3G_END_PROFILE(M3G_INTERFACE(self), M3G_PROFILE_SKIN);
       
  1440     return m3gMeshRayIntersectInternal( &mesh->mesh,
       
  1441                                         mesh->morphedVB,
       
  1442                                         mask,
       
  1443                                         ray,
       
  1444                                         ri,
       
  1445                                         toGroup);
       
  1446 }
       
  1447 
       
  1448 /*!
       
  1449  * \internal
       
  1450  * \brief Overloaded Object3D method.
       
  1451  *
       
  1452  * \param self SkinnedMesh object
       
  1453  * \param time current world time
       
  1454  * \return minimum validity
       
  1455  */
       
  1456 static M3Gint m3gSkinnedMeshApplyAnimation(Object *self, M3Gint time)
       
  1457 {
       
  1458     SkinnedMesh *mesh = (SkinnedMesh *)self;
       
  1459     
       
  1460     M3Gint validity = m3gMeshApplyAnimation((Object*) &mesh->mesh, time);
       
  1461     
       
  1462     if (validity > 0) {
       
  1463         M3Gint validity2 =
       
  1464             M3G_VFUNC(Object, mesh->skeleton, applyAnimation)(
       
  1465                 (Object *)mesh->skeleton, time);
       
  1466         return (validity < validity2 ? validity : validity2);
       
  1467     }
       
  1468     return 0;
       
  1469 }
       
  1470 
       
  1471 /*!
       
  1472  * \internal
       
  1473  * \brief Overloaded Object3D method.
       
  1474  *
       
  1475  * \param self SkinnedMesh object
       
  1476  * \param references array of reference objects
       
  1477  * \return number of references
       
  1478  */
       
  1479 static M3Gint m3gSkinnedMeshDoGetReferences(Object *self, Object **references)
       
  1480 {
       
  1481     SkinnedMesh *smesh = (SkinnedMesh *)self;
       
  1482     M3Gint num = m3gMeshDoGetReferences(self, references);
       
  1483     if (smesh->skeleton != NULL)
       
  1484     {
       
  1485         if (references != NULL)
       
  1486             references[num] = (Object *)smesh->skeleton;
       
  1487         num++;
       
  1488     }
       
  1489     return num;
       
  1490 }
       
  1491 
       
  1492 /*!
       
  1493  * \internal
       
  1494  * \brief Overloaded Object3D method.
       
  1495  */
       
  1496 static Object *m3gSkinnedMeshFindID(Object *self, M3Gint userID)
       
  1497 {
       
  1498     SkinnedMesh *smesh = (SkinnedMesh *)self;
       
  1499     Object *found = m3gMeshFindID(self, userID);
       
  1500     
       
  1501     if (!found && smesh->skeleton != NULL) {
       
  1502         found = m3gFindID((Object*) smesh->skeleton, userID);
       
  1503     }
       
  1504     return found;
       
  1505 }
       
  1506 
       
  1507 /*!
       
  1508  * \internal
       
  1509  * \brief Overloaded Object3D method.
       
  1510  *
       
  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
       
  1515  */
       
  1516 static M3Gbool m3gSkinnedMeshDuplicate(const Object *originalObj,
       
  1517                                        Object **cloneObj,
       
  1518                                        Object **pairs,
       
  1519                                        M3Gint *numPairs)
       
  1520 {
       
  1521     M3Gint i;
       
  1522     SkinnedMesh *original = (SkinnedMesh *)originalObj;
       
  1523     Group *skeleton = NULL;
       
  1524     SkinnedMesh *clone;
       
  1525     M3G_ASSERT(*cloneObj == NULL); /* no derived classes */
       
  1526     
       
  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. */
       
  1532     
       
  1533     if (!M3G_VFUNC(Object, original->skeleton, duplicate)(
       
  1534             (Object*) original->skeleton,
       
  1535             (Object**) &skeleton, pairs, numPairs)) {
       
  1536         m3gDeleteObject((Object*) skeleton);
       
  1537         return M3G_FALSE;
       
  1538     }
       
  1539     m3gAddRef((Object*) skeleton); /* don't leave this floating */
       
  1540 
       
  1541     /* Create the actual clone object */
       
  1542     
       
  1543     clone = (SkinnedMesh*)
       
  1544         m3gCreateSkinnedMesh(originalObj->interface,
       
  1545                              original->mesh.vertexBuffer,
       
  1546                              original->mesh.indexBuffers,
       
  1547                              original->mesh.appearances,
       
  1548                              original->mesh.trianglePatchCount,
       
  1549                              skeleton);    
       
  1550     m3gDeleteRef((Object*) skeleton); /* ownership transferred to clone */
       
  1551     if (!clone) {
       
  1552         return M3G_FALSE;
       
  1553     }
       
  1554     *cloneObj = (Object *)clone;
       
  1555 
       
  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 */
       
  1558     
       
  1559     if (!m3gMeshDuplicate(originalObj, cloneObj, pairs, numPairs)) {
       
  1560         return M3G_FALSE;
       
  1561     }
       
  1562 
       
  1563     /* Duplicate the rest of our own data */
       
  1564 
       
  1565     if (!m3gEnsureVertexCount(clone, original->weightedVertexCount) ||
       
  1566         !m3gEnsureBonesPerVertex(clone, original->bonesPerVertex)) {
       
  1567         return M3G_FALSE; /* out of memory */
       
  1568     }
       
  1569     
       
  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);
       
  1577     }
       
  1578     clone->weightsDirty = original->weightsDirty;
       
  1579     m3gCopy(clone->weightShifts, original->weightShifts,
       
  1580             clone->weightedVertexCount);
       
  1581 
       
  1582     for (i = 0; i < m3gArraySize(&original->bones); i++) {
       
  1583         Bone *cloneBone = (Bone*) m3gAllocZ(originalObj->interface,
       
  1584                                             sizeof(Bone));
       
  1585         if (!cloneBone) {
       
  1586             return M3G_FALSE; /* out of memory */
       
  1587         }
       
  1588         /* this line looks odd, but really just copies the *contents*
       
  1589          * of the bone structure... */
       
  1590         *cloneBone = *(Bone*)m3gGetArrayElement(&original->bones, i);
       
  1591 
       
  1592         if (m3gArrayAppend(&clone->bones, cloneBone, originalObj->interface) < 0) {
       
  1593             m3gFree(originalObj->interface, cloneBone);
       
  1594             return M3G_FALSE; /* out of memory */
       
  1595         }
       
  1596     }
       
  1597     
       
  1598     return M3G_TRUE;
       
  1599 }
       
  1600 
       
  1601 /*!
       
  1602  * \internal
       
  1603  * \brief Overloaded Node method
       
  1604  */
       
  1605 static M3Gint m3gSkinnedMeshGetBBox(Node *self, AABB *bbox)
       
  1606 {
       
  1607     SkinnedMesh *mesh = (SkinnedMesh*) self;
       
  1608     Node *skeleton = (Node*) mesh->skeleton;
       
  1609 
       
  1610     /* First update our local bounding box if necessary */
       
  1611     
       
  1612     if (self->dirtyBits & NODE_BBOX_BIT) {
       
  1613         
       
  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
       
  1618          * extents. */
       
  1619         {
       
  1620             const GLfloat scale = mesh->morphedVB->vertexScale;
       
  1621             const GLfloat *bias = mesh->morphedVB->vertexBias;
       
  1622             int i;
       
  1623             
       
  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]);
       
  1627             }
       
  1628         }
       
  1629     }
       
  1630     *bbox = mesh->bbox;
       
  1631     
       
  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! */
       
  1635         
       
  1636     if (skeleton->hasRenderables && skeleton->enableBits) {
       
  1637         AABB skeletonBBox;
       
  1638         if (m3gGetNodeBBox(skeleton, &skeletonBBox)) {
       
  1639             Matrix t;
       
  1640             m3gGetCompositeNodeTransform(self, &t);
       
  1641             m3gTransformAABB(&skeletonBBox, &t);
       
  1642             m3gFitAABB(bbox, &skeletonBBox, bbox);
       
  1643         }
       
  1644     }    
       
  1645     return m3gArraySize(&mesh->bones) * VFC_NODE_OVERHEAD;
       
  1646 }
       
  1647 
       
  1648 /*!
       
  1649  * \internal
       
  1650  * \brief Overloaded Node method
       
  1651  */
       
  1652 static M3Gbool m3gSkinnedMeshValidate(Node *self, M3Gbitmask stateBits, M3Gint scope)
       
  1653 {
       
  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;
       
  1659 
       
  1660     if ((scope & self->scope) != 0) {
       
  1661         if (stateBits & self->enableBits) {
       
  1662             
       
  1663             /* Check for invalid SkinnedMesh state */
       
  1664         
       
  1665             if (srcVB->vertices == NULL || vertexCount > srcVB->vertexCount) {
       
  1666                 m3gRaiseError(m3g, M3G_INVALID_OPERATION);
       
  1667                 return M3G_FALSE;
       
  1668             }
       
  1669             if (!m3gSkinnedMeshUpdateVB(mesh)) { /* Memory allocation failed */
       
  1670                 return M3G_FALSE;
       
  1671             }
       
  1672         
       
  1673             /* Validate the skeleton */
       
  1674         
       
  1675             if (!m3gValidateNode(skeleton, stateBits, scope)) {
       
  1676                 return M3G_FALSE;
       
  1677             }
       
  1678     
       
  1679             /* Validate our local state */
       
  1680     
       
  1681             if ((self->dirtyBits & NODE_TRANSFORMS_BIT) != 0 || 
       
  1682                 m3gGetTimestamp(srcVB) != mesh->mesh.vbTimestamp) {
       
  1683                 if (!m3gSkinnedMeshPreMorph((SkinnedMesh*) self)) {
       
  1684                     return M3G_FALSE;
       
  1685                 }
       
  1686             }
       
  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);
       
  1691             }
       
  1692     
       
  1693             return m3gMeshValidate(self, stateBits, scope);
       
  1694         }
       
  1695     }
       
  1696     return M3G_TRUE;
       
  1697 }
       
  1698 
       
  1699 /*!
       
  1700  * \internal
       
  1701  * \brief Overloaded Object3D method.
       
  1702  *
       
  1703  * \param self SkinnedMesh object
       
  1704  * \param pairs array for all object-duplicate pairs
       
  1705  * \param numPairs number of pairs
       
  1706  */
       
  1707 static void m3gSkinnedMeshUpdateDuplicateReferences(Node *self, Object **pairs, M3Gint numPairs)
       
  1708 {
       
  1709     SkinnedMesh *skinned = (SkinnedMesh *)self;
       
  1710     SkinnedMesh *duplicate = (SkinnedMesh *)m3gGetDuplicatedInstance(self, pairs, numPairs);
       
  1711     M3Gint i, n;
       
  1712     
       
  1713     m3gNodeUpdateDuplicateReferences(self, pairs, numPairs);
       
  1714     
       
  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;
       
  1721         }
       
  1722     }
       
  1723     
       
  1724     M3G_VFUNC(Node, skinned->skeleton, updateDuplicateReferences)(
       
  1725         (Node *)skinned->skeleton, pairs, numPairs);
       
  1726 }
       
  1727 
       
  1728 /*!
       
  1729  * \internal
       
  1730  * \brief Initializes a SkinnedMesh object. See specification
       
  1731  * for default values.
       
  1732  *
       
  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
       
  1742  */
       
  1743 static M3Gbool m3gInitSkinnedMesh(Interface *m3g,
       
  1744                                   SkinnedMesh *mesh,
       
  1745                                   M3GVertexBuffer hVertices,
       
  1746                                   M3GIndexBuffer *hTriangles,
       
  1747                                   M3GAppearance *hAppearances,
       
  1748                                   M3Gint trianglePatchCount,
       
  1749                                   M3GGroup hSkeleton)
       
  1750 {
       
  1751     /* SkinnedMesh is derived from Mesh */
       
  1752     if (!m3gInitMesh(m3g, &mesh->mesh,
       
  1753                      hVertices, hTriangles, hAppearances,
       
  1754                      trianglePatchCount,
       
  1755                      M3G_CLASS_SKINNED_MESH))
       
  1756     {
       
  1757         return M3G_FALSE;
       
  1758     }
       
  1759 
       
  1760     /* Make sure our mesh gets blended even if no bones are added */    
       
  1761     ((Node*)mesh)->dirtyBits |= NODE_TRANSFORMS_BIT;
       
  1762         
       
  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);
       
  1766 
       
  1767     m3gInitArray(&mesh->bones);
       
  1768     
       
  1769     mesh->morphedVB = (VertexBuffer *)m3gCreateVertexBuffer(m3g);
       
  1770     if (mesh->morphedVB == NULL
       
  1771         || m3gSkinnedMeshUpdateVB(mesh) == M3G_FALSE) {
       
  1772         
       
  1773         /* We're sufficiently initialized at this point that the
       
  1774          * destructor can be called for cleaning up */
       
  1775         
       
  1776         m3gDestroySkinnedMesh((Object *)mesh);
       
  1777         return M3G_FALSE;
       
  1778     }
       
  1779     return M3G_TRUE;
       
  1780 }
       
  1781 
       
  1782 /*----------------------------------------------------------------------
       
  1783  * Virtual function table
       
  1784  *--------------------------------------------------------------------*/
       
  1785 
       
  1786 static const NodeVFTable m3gvf_SkinnedMesh = {
       
  1787     {
       
  1788         {
       
  1789             m3gSkinnedMeshApplyAnimation,
       
  1790             m3gNodeIsCompatible,
       
  1791             m3gNodeUpdateProperty,
       
  1792             m3gSkinnedMeshDoGetReferences,
       
  1793             m3gSkinnedMeshFindID,
       
  1794             m3gSkinnedMeshDuplicate,
       
  1795             m3gDestroySkinnedMesh
       
  1796         }
       
  1797     },
       
  1798     m3gNodeAlign,
       
  1799     m3gSkinnedMeshDoRender,
       
  1800     m3gSkinnedMeshGetBBox,
       
  1801     m3gSkinnedMeshRayIntersect,
       
  1802     m3gSkinnedMeshSetupRender,
       
  1803     m3gSkinnedMeshUpdateDuplicateReferences,
       
  1804     m3gSkinnedMeshValidate
       
  1805 };
       
  1806 
       
  1807 
       
  1808 /*----------------------------------------------------------------------
       
  1809  * Public API functions
       
  1810  *--------------------------------------------------------------------*/
       
  1811 
       
  1812 /*!
       
  1813  * \brief Creates a SkinnedMesh object.
       
  1814  *
       
  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
       
  1823  */
       
  1824 M3G_API M3GSkinnedMesh m3gCreateSkinnedMesh(M3GInterface interface,
       
  1825                                             M3GVertexBuffer hVertices,
       
  1826                                             M3GIndexBuffer *hTriangles,
       
  1827                                             M3GAppearance *hAppearances,
       
  1828                                             M3Gint trianglePatchCount,
       
  1829                                             M3GGroup hSkeleton)
       
  1830 {
       
  1831     Interface *m3g = (Interface *) interface;
       
  1832     M3G_VALIDATE_INTERFACE(m3g);
       
  1833     {
       
  1834         SkinnedMesh *mesh = NULL;
       
  1835         Group *skeleton = (Group *) hSkeleton;
       
  1836         if (skeleton == NULL) {
       
  1837             m3gRaiseError(m3g, M3G_NULL_POINTER);
       
  1838             return NULL;
       
  1839         }
       
  1840         if (skeleton->node.parent != NULL ||
       
  1841             M3G_CLASS(skeleton) == M3G_CLASS_WORLD) {
       
  1842             m3gRaiseError(m3g, M3G_INVALID_VALUE);
       
  1843             return NULL;
       
  1844         }
       
  1845         
       
  1846         mesh = m3gAllocZ(m3g, sizeof(SkinnedMesh));
       
  1847         if (mesh) {
       
  1848             if (!m3gInitSkinnedMesh(m3g, mesh,
       
  1849                                     hVertices, hTriangles, hAppearances,
       
  1850                                     trianglePatchCount,
       
  1851                                     hSkeleton)) {
       
  1852                 m3gFree(m3g, mesh);
       
  1853                 return NULL;
       
  1854             }
       
  1855         }
       
  1856         return (M3GSkinnedMesh)mesh;
       
  1857     }
       
  1858 }
       
  1859 
       
  1860 /*!
       
  1861  * \brief Add new weighted transformation (bone) to range of vertices
       
  1862  *
       
  1863  * 
       
  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
       
  1869  */
       
  1870 M3G_API void m3gAddTransform(M3GSkinnedMesh handle,
       
  1871                              M3GNode hNode,
       
  1872                              M3Gint weight,
       
  1873                              M3Gint firstVertex, M3Gint numVertices)
       
  1874 {
       
  1875     SkinnedMesh *mesh = (SkinnedMesh *)handle;
       
  1876     Node *boneNode = (Node *)hNode;
       
  1877     Interface *m3g = M3G_INTERFACE(mesh);
       
  1878     
       
  1879     M3Gint lastVertex = firstVertex + numVertices;
       
  1880     M3G_VALIDATE_OBJECT(mesh);
       
  1881 
       
  1882     /* Check for errors */
       
  1883     
       
  1884     if (!boneNode) {
       
  1885         m3gRaiseError(m3g, M3G_NULL_POINTER);
       
  1886         return;
       
  1887     }
       
  1888     M3G_VALIDATE_OBJECT(boneNode);
       
  1889     if (!m3gIsChildOf((const Node*) mesh, boneNode)
       
  1890         || numVertices <= 0 || weight <= 0) {
       
  1891         m3gRaiseError(m3g, M3G_INVALID_VALUE);
       
  1892         return;
       
  1893     }
       
  1894     if (firstVertex < 0 || lastVertex > 65535) {
       
  1895         m3gRaiseError(m3g, M3G_INVALID_INDEX);
       
  1896         return;
       
  1897     }
       
  1898 
       
  1899     /* Make sure we have enough per-vertex data */
       
  1900     
       
  1901     if (!m3gEnsureVertexCount(mesh, lastVertex)) {
       
  1902         return; /* out of memory */
       
  1903     }
       
  1904     
       
  1905     /* Check whether we may need to increase the number of bone
       
  1906      * entries per vertex, or whether we're already maxed out */
       
  1907     
       
  1908     if (mesh->bonesPerVertex < M3G_MAX_VERTEX_TRANSFORMS) {
       
  1909 
       
  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 */
       
  1913         
       
  1914         int numBones = mesh->bonesPerVertex;
       
  1915         int maxBones = 0;
       
  1916         
       
  1917         int vertex;
       
  1918         for (vertex = firstVertex; vertex < lastVertex; ++vertex) {
       
  1919             int k;
       
  1920             for (k = numBones; k > 0; --k) {
       
  1921                 if (mesh->boneWeights[k-1][vertex] > 0) {
       
  1922                     maxBones = M3G_MAX(maxBones,  k);
       
  1923                     break;
       
  1924                 }
       
  1925             }
       
  1926         }
       
  1927         if (!m3gEnsureBonesPerVertex(mesh, maxBones + 1)) {
       
  1928             return; /* out of memory */
       
  1929         }
       
  1930     }
       
  1931     
       
  1932     /* Get a bone record for the bone node, and add the bone influence
       
  1933      * to all affected vertices */
       
  1934     {
       
  1935         int i;
       
  1936         
       
  1937         M3Gint boneIndex = m3gBoneIndex(mesh, boneNode);
       
  1938         if (boneIndex < 0) {
       
  1939             return; /* out of memory */
       
  1940         }
       
  1941         
       
  1942         for (i = firstVertex; i < lastVertex; i++) {
       
  1943             m3gAddInfluence(mesh, i, boneIndex, weight);
       
  1944         }
       
  1945     }
       
  1946     
       
  1947     /* Update the bone flag for the bone node and its parents up to
       
  1948      * the SkinnedMesh node */
       
  1949     
       
  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;
       
  1954     }
       
  1955 }
       
  1956 
       
  1957 /*!
       
  1958  * \brief Getter for skeleton.
       
  1959  *
       
  1960  * \param handle                SkinnedMesh object
       
  1961  * \return                      Group object
       
  1962  */
       
  1963 M3G_API M3GGroup m3gGetSkeleton(M3GSkinnedMesh handle)
       
  1964 {
       
  1965     SkinnedMesh *mesh = (SkinnedMesh *)handle;
       
  1966     M3G_VALIDATE_OBJECT(mesh);
       
  1967 
       
  1968     return mesh->skeleton;
       
  1969 }
       
  1970 
       
  1971 /*!
       
  1972  * \brief Getter for bone transform.
       
  1973  *
       
  1974  * \param handle                SkinnedMesh object
       
  1975  * \param hBone                 Bone
       
  1976  * \param transform             Transform
       
  1977  */
       
  1978 M3G_API void m3gGetBoneTransform(M3GSkinnedMesh handle,
       
  1979                                  M3GNode hBone,
       
  1980                                  M3GMatrix *transform)
       
  1981 {
       
  1982     SkinnedMesh *mesh = (SkinnedMesh *)handle;
       
  1983     Node *node = (Node *)hBone;
       
  1984     M3Gint i;
       
  1985     M3Gint boneCount;
       
  1986 
       
  1987     M3G_VALIDATE_OBJECT(mesh);
       
  1988     M3G_VALIDATE_OBJECT(node);
       
  1989 
       
  1990     if (!m3gIsChildOf((Node*) mesh->skeleton, node)) {
       
  1991         m3gRaiseError(M3G_INTERFACE(mesh), M3G_INVALID_VALUE);
       
  1992         return;
       
  1993     }   
       
  1994     
       
  1995     boneCount = m3gArraySize(&mesh->bones);
       
  1996 
       
  1997     for (i = 0; i < boneCount; ++i) {
       
  1998         Bone *bone = m3gGetArrayElement(&mesh->bones, i);
       
  1999 
       
  2000         if (bone->node == node) {
       
  2001             m3gCopyMatrix(transform, &bone->toBone);
       
  2002             break;
       
  2003         }
       
  2004     }
       
  2005 }
       
  2006 
       
  2007 /*!
       
  2008  * \brief Getter for bone vertices.
       
  2009  *
       
  2010  * \param handle                SkinnedMesh object
       
  2011  * \param hBone                 Bone
       
  2012  * \param indices               Influenced indices
       
  2013  * \param weights               Weights
       
  2014  * \return                      Number of influenced vertices
       
  2015  */
       
  2016 M3G_API M3Gint m3gGetBoneVertices(M3GSkinnedMesh handle,
       
  2017                                   M3GNode hBone,
       
  2018                                   M3Gint *indices, M3Gfloat *weights)
       
  2019 {
       
  2020     SkinnedMesh *mesh = (SkinnedMesh *)handle;
       
  2021     Node *node = (Node *)hBone;
       
  2022     M3Gint boneIndex, boneCount, count = 0;
       
  2023 
       
  2024     M3G_VALIDATE_OBJECT(mesh);
       
  2025     M3G_VALIDATE_OBJECT(node);
       
  2026 
       
  2027     /* Check for errors */
       
  2028 
       
  2029     if (!m3gIsChildOf((Node*) mesh->skeleton, node)) {
       
  2030         m3gRaiseError(M3G_INTERFACE(mesh), M3G_INVALID_VALUE);
       
  2031         return 0;
       
  2032     }   
       
  2033         
       
  2034     /* Find the bone index corresponding to our bone node */
       
  2035     
       
  2036     boneCount = m3gArraySize(&mesh->bones);
       
  2037 
       
  2038     for (boneIndex = 0; boneIndex < boneCount; ++boneIndex) {
       
  2039         Bone *bone = m3gGetArrayElement(&mesh->bones, boneIndex);
       
  2040         if (bone->node == node) {
       
  2041             break;
       
  2042         }
       
  2043     }
       
  2044 
       
  2045     /* Loop over the vertices, outputting index-weight pairs for each
       
  2046      * vertex influenced by the bone */
       
  2047 
       
  2048     if (boneIndex < boneCount) {
       
  2049         M3Gint i, j;
       
  2050 
       
  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) {
       
  2055                         M3Gint k, sum = 0;
       
  2056                         for (k = 0; k < mesh->bonesPerVertex; ++k) {
       
  2057                             sum += mesh->boneWeights[k][i];
       
  2058                         }
       
  2059                         indices[count] = i;
       
  2060                         if (sum != 0) {
       
  2061                             weights[count] = ((M3Gfloat) mesh->boneWeights[j][i]) / sum;
       
  2062                         }
       
  2063                         else {
       
  2064                             weights[count] = 0;
       
  2065                         }
       
  2066                     }
       
  2067                     ++count;
       
  2068                 }
       
  2069             }                    
       
  2070         }
       
  2071     }
       
  2072     return count;
       
  2073 }
       
  2074