os/graphics/m3g/m3gcore11/src/m3g_skinnedmesh.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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