m3g/m3gcore11/src/m3g_morphingmesh.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: MorphingMesh implementation
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 /*!
       
    20  * \internal
       
    21  * \file
       
    22  * \brief MorphingMesh implementation
       
    23  *
       
    24  */
       
    25 
       
    26 #ifndef M3G_CORE_INCLUDE
       
    27 #   error included by m3g_core.c; do not compile separately.
       
    28 #endif
       
    29 
       
    30 #include "m3g_morphingmesh.h"
       
    31 #include "m3g_memory.h"
       
    32 #include "m3g_animationtrack.h"
       
    33 
       
    34 #define WEIGHT_SHIFT        ( 8 )
       
    35 #define WEIGHT_SCALE        ( 1 << WEIGHT_SHIFT )
       
    36 #define WEIGHT_ROUND_PLUS   ( WEIGHT_SCALE / 4 )
       
    37 #define WEIGHT_ROUND_MINUS  ( 0 )
       
    38 
       
    39 /*!
       
    40  * \internal
       
    41  * \brief offsetof macro
       
    42  */
       
    43 #include <stddef.h>
       
    44 
       
    45 static M3Gbool m3gMorph(MorphingMesh *momesh);
       
    46 static M3Gbool m3gCreateClones(VertexBuffer *vertices, VertexBuffer *morphed);
       
    47 static void m3gDeleteClones(VertexBuffer *morphed);
       
    48 
       
    49 /*----------------------------------------------------------------------
       
    50  * Internal functions
       
    51  *--------------------------------------------------------------------*/
       
    52 
       
    53 /*!
       
    54  * \internal
       
    55  * \brief Destroys this MorphingMesh object.
       
    56  *
       
    57  * \param obj MorphingMesh object
       
    58  */
       
    59 static void m3gDestroyMorphingMesh(Object *obj)
       
    60 {
       
    61     M3Gint i;
       
    62     MorphingMesh *momesh = (MorphingMesh *) obj;
       
    63     M3G_VALIDATE_OBJECT(momesh);
       
    64 
       
    65     for (i = 0; i < momesh->numTargets; i++) {
       
    66         M3G_ASSIGN_REF(momesh->targets[i], NULL);
       
    67     }
       
    68 
       
    69     M3G_ASSIGN_REF(momesh->morphed, NULL);
       
    70 
       
    71     {
       
    72         Interface *m3g = M3G_INTERFACE(momesh); 
       
    73         m3gFree(m3g, momesh->targets);
       
    74         m3gFree(m3g, momesh->weights);
       
    75         m3gFree(m3g, momesh->floatWeights);
       
    76     }
       
    77 
       
    78     m3gDestroyMesh(obj);
       
    79 }
       
    80 
       
    81 /*!
       
    82  * \internal
       
    83  * \brief Overloaded Node method.
       
    84  *
       
    85  * Setup morphing mesh render. Morph and call Mesh
       
    86  * render setup.
       
    87  *
       
    88  * \param self MorphingMesh object
       
    89  * \param toCamera transform to camera
       
    90  * \param alphaFactor total alpha factor
       
    91  * \param caller caller node
       
    92  * \param renderQueue RenderQueue
       
    93  *
       
    94  * \retval M3G_TRUE continue render setup
       
    95  * \retval M3G_FALSE abort render setup
       
    96  */
       
    97 static M3Gbool m3gMorphingMeshSetupRender(Node *self,
       
    98                                           const Node *caller,
       
    99                                           SetupRenderState *s,
       
   100                                           RenderQueue *renderQueue)
       
   101 {
       
   102     MorphingMesh *momesh = (MorphingMesh *)self;
       
   103     M3G_UNREF(caller);
       
   104     m3gIncStat(M3G_INTERFACE(self), M3G_STAT_RENDER_NODES, 1);
       
   105     
       
   106     momesh->dirtyState = M3G_TRUE;
       
   107 
       
   108     if ((self->enableBits & NODE_RENDER_BIT) != 0 &&
       
   109         (self->scope & renderQueue->scope) != 0) {
       
   110 
       
   111         /* Try view frustum culling */
       
   112 
       
   113 #       if defined(M3G_ENABLE_VF_CULLING)
       
   114         m3gUpdateCullingMask(s, renderQueue->camera, &momesh->bbox);
       
   115         if (s->cullMask == 0) {
       
   116             m3gIncStat(M3G_INTERFACE(self),
       
   117                        M3G_STAT_RENDER_NODES_CULLED, 1);
       
   118             return M3G_TRUE;
       
   119         }
       
   120 #       endif
       
   121         
       
   122         /* No dice, must morph & render */
       
   123         
       
   124         M3G_BEGIN_PROFILE(M3G_INTERFACE(momesh), M3G_PROFILE_MORPH);
       
   125         if (!m3gMorph(momesh)) {
       
   126             return M3G_FALSE;
       
   127         }
       
   128         M3G_END_PROFILE(M3G_INTERFACE(momesh), M3G_PROFILE_MORPH);
       
   129 
       
   130         return m3gQueueMesh((Mesh*) self, &s->toCamera, renderQueue);
       
   131     }
       
   132     return M3G_TRUE;
       
   133 }
       
   134 
       
   135 /*!
       
   136  * \internal
       
   137  * \brief Overloaded Node method.
       
   138  *
       
   139  * Renders one submesh.
       
   140  *
       
   141  * \param self MorphingMesh object
       
   142  * \param ctx current render context
       
   143  * \param patchIndex submesh index
       
   144  */
       
   145 static void m3gMorphingMeshDoRender(Node *self,
       
   146                                     RenderContext *ctx,
       
   147                                     const Matrix *toCamera,
       
   148                                     M3Gint patchIndex)
       
   149 {
       
   150     MorphingMesh *momesh = (MorphingMesh *)self;
       
   151     Mesh *mesh = (Mesh *)self;
       
   152 
       
   153     m3gDrawMesh(ctx,
       
   154                 momesh->morphed,
       
   155                 mesh->indexBuffers[patchIndex],
       
   156                 mesh->appearances[patchIndex],
       
   157                 toCamera,
       
   158                 mesh->totalAlphaFactor + 1,
       
   159                 self->scope);
       
   160 }
       
   161 
       
   162 /*!
       
   163  * \internal
       
   164  * \brief Overloaded Node method.
       
   165  *
       
   166  * Morph and forward call Mesh internal ray intersect.
       
   167  *
       
   168  * \param self      MorphingMesh object
       
   169  * \param mask      pick scope mask
       
   170  * \param ray       pick ray
       
   171  * \param ri        RayIntersection object
       
   172  * \param toGroup   transform to originating group
       
   173  * \retval          M3G_TRUE    continue pick
       
   174  * \retval          M3G_FALSE   abort pick
       
   175  */
       
   176 static M3Gbool m3gMorphingMeshRayIntersect( Node *self,
       
   177                                             M3Gint mask,
       
   178                                             M3Gfloat *ray,
       
   179                                             RayIntersection *ri,
       
   180                                             Matrix *toGroup)
       
   181 {
       
   182     MorphingMesh *momesh = (MorphingMesh *)self;
       
   183     M3G_BEGIN_PROFILE(M3G_INTERFACE(momesh), M3G_PROFILE_MORPH);
       
   184     if (!m3gMorph(momesh)) {
       
   185         return M3G_FALSE;
       
   186     }
       
   187     M3G_END_PROFILE(M3G_INTERFACE(momesh), M3G_PROFILE_MORPH);
       
   188     return m3gMeshRayIntersectInternal(&momesh->mesh, momesh->morphed, mask, ray, ri, toGroup);
       
   189 }
       
   190 
       
   191 /*!
       
   192  * \internal
       
   193  * \brief Morphes short type vertex arrays.
       
   194  *
       
   195  * \param momesh        MorphingMesh object
       
   196  * \param dsta          destination VertexArray object
       
   197  * \param base          base VertexArray object
       
   198  * \param arrayOffset   offset to VertexArray object inside Mesh object
       
   199  * \retval M3G_TRUE     morph ok
       
   200  * \retval M3G_FALSE    morph failed, exception raised
       
   201  */
       
   202 static M3Gbool m3gMorphShorts(MorphingMesh *momesh, VertexArray *dsta, VertexArray *base, M3Gint arrayOffset)
       
   203 {
       
   204     M3Gint i;
       
   205     M3Gint sum, sw;
       
   206     M3Gshort *dst, *src;
       
   207     M3Gshort j, numMsTargets = 0;
       
   208     M3Gshort **srct = m3gAllocTemp(M3G_INTERFACE(momesh), sizeof(M3Gshort *) * momesh->numTargets * 2);
       
   209     M3Gshort *msTargets = (M3Gshort *) (srct + momesh->numTargets);
       
   210 
       
   211     if (msTargets == NULL) {
       
   212         return M3G_FALSE;
       
   213     }
       
   214 
       
   215     /* Check that target arrays are in same format */
       
   216     for (j = 0; j < momesh->numTargets; j++) {
       
   217         VertexArray **va;
       
   218         va = (VertexArray **)(((M3Gbyte *)momesh->targets[j]) + arrayOffset);
       
   219         if (!m3gIsCompatible(*va, base)) {
       
   220             /* Unmap all arrays */
       
   221             for (j = 0; j < numMsTargets; j++) {
       
   222                 m3gUnmapVertexArray(*(VertexArray **)(((M3Gbyte *)momesh->targets[msTargets[j]]) + arrayOffset));
       
   223             }
       
   224             m3gFreeTemp(M3G_INTERFACE(momesh));
       
   225             m3gRaiseError(M3G_INTERFACE(momesh), M3G_INVALID_OPERATION);
       
   226             return M3G_FALSE;
       
   227         }
       
   228         /* Use only most significant targets*/
       
   229         if (momesh->weights[j] != 0) {
       
   230             msTargets[numMsTargets] = j;
       
   231             srct[numMsTargets] = (M3Gshort *) m3gMapVertexArrayReadOnly(*va);
       
   232             numMsTargets++;
       
   233         }
       
   234     }
       
   235 
       
   236     dst = (M3Gshort *) m3gMapVertexArray(dsta);
       
   237     src = (M3Gshort *) m3gMapVertexArrayReadOnly(base);
       
   238     sw = momesh->sumWeights;
       
   239 
       
   240     for (i = 0; i < base->vertexCount * base->elementSize; i++) {
       
   241         sum = src[i] * sw;
       
   242         for (j = 0; j < numMsTargets; j++) {
       
   243             sum += srct[j][i] * momesh->weights[msTargets[j]];
       
   244         }
       
   245         /* Round */
       
   246         if (sum >= 0) {
       
   247             sum += WEIGHT_ROUND_PLUS;
       
   248         }
       
   249         else {
       
   250             sum -= WEIGHT_ROUND_MINUS;
       
   251         }
       
   252         dst[i] = (M3Gshort)(sum >> WEIGHT_SHIFT);
       
   253     }
       
   254 
       
   255     /* Unmap all arrays */
       
   256     for (j = 0; j < numMsTargets; j++) {
       
   257         m3gUnmapVertexArray(*(VertexArray **)(((M3Gbyte *)momesh->targets[msTargets[j]]) + arrayOffset));
       
   258     }
       
   259 
       
   260     m3gUnmapVertexArray(base);
       
   261     m3gUnmapVertexArray(dsta);
       
   262     
       
   263     m3gFreeTemp(M3G_INTERFACE(momesh));
       
   264     return M3G_TRUE;
       
   265 }
       
   266 
       
   267 /*!
       
   268  * \internal
       
   269  * \brief Morphes byte type vertex arrays.
       
   270  *
       
   271  * \param momesh        MorphingMesh object
       
   272  * \param dsta          destination VertexArray object
       
   273  * \param base          base VertexArray object
       
   274  * \param arrayOffset   offset to VertexArray object inside Mesh object
       
   275  * \retval M3G_TRUE     morph ok
       
   276  * \retval M3G_FALSE    morph failed, exception raised
       
   277  */
       
   278 static M3Gbool m3gMorphBytes(MorphingMesh *momesh, VertexArray *dsta, VertexArray *base, M3Gint arrayOffset)
       
   279 {
       
   280     M3Gint i;
       
   281     M3Gint sum, sw;
       
   282     M3Gbyte *dst, *src;
       
   283     M3Gint skip;
       
   284     M3Gshort j, numMsTargets = 0;
       
   285     M3Gbyte **srct = m3gAllocTemp(M3G_INTERFACE(momesh), sizeof(M3Gbyte *) * momesh->numTargets * 2);
       
   286     M3Gshort *msTargets = (M3Gshort *) (srct + momesh->numTargets);
       
   287 
       
   288     if (msTargets == NULL) {
       
   289         return M3G_FALSE;
       
   290     }
       
   291 
       
   292     /* Check that target arrays are in same format */
       
   293     for (j = 0; j < momesh->numTargets; j++) {
       
   294         VertexArray **va;
       
   295         va = (VertexArray **)(((M3Gbyte *)momesh->targets[j]) + arrayOffset);
       
   296         if (!m3gIsCompatible(*va, base)) {
       
   297             /* Unmap all arrays */
       
   298             for (j = 0; j < numMsTargets; j++) {
       
   299                 m3gUnmapVertexArray(*(VertexArray **)(((M3Gbyte *)momesh->targets[msTargets[j]]) + arrayOffset));
       
   300             }
       
   301             m3gFreeTemp(M3G_INTERFACE(momesh));
       
   302             m3gRaiseError(M3G_INTERFACE(momesh), M3G_INVALID_OPERATION);
       
   303             return M3G_FALSE;
       
   304         }
       
   305         /* Use only most significant targets*/
       
   306         if (momesh->weights[j] != 0) {
       
   307             msTargets[numMsTargets] = j;
       
   308             srct[numMsTargets] = (M3Gbyte *) m3gMapVertexArrayReadOnly(*va);
       
   309             numMsTargets++;
       
   310         }
       
   311     }
       
   312 
       
   313     dst = (M3Gbyte *) m3gMapVertexArray(dsta);
       
   314     src = (M3Gbyte *) m3gMapVertexArrayReadOnly(base);
       
   315     sw = momesh->sumWeights;
       
   316     skip = base->elementSize;
       
   317 
       
   318     for (i = 0; i < base->vertexCount * base->stride; i++) {
       
   319         if ((i & 3) >= skip) continue;
       
   320         sum = src[i] * sw;
       
   321         for (j = 0; j < numMsTargets; j++) {
       
   322             sum += srct[j][i] * momesh->weights[msTargets[j]];
       
   323         }
       
   324         /* Round */
       
   325         if (sum >= 0) {
       
   326             sum += WEIGHT_ROUND_PLUS;
       
   327         }
       
   328         else {
       
   329             sum -= WEIGHT_ROUND_MINUS;
       
   330         }
       
   331         dst[i] = (M3Gbyte)(sum >> WEIGHT_SHIFT);
       
   332     }
       
   333 
       
   334     /* Unmap all arrays */
       
   335     for (j = 0; j < numMsTargets; j++) {
       
   336         m3gUnmapVertexArray(*(VertexArray **)(((M3Gbyte *)momesh->targets[msTargets[j]]) + arrayOffset));
       
   337     }
       
   338 
       
   339     m3gUnmapVertexArray(base);
       
   340     m3gUnmapVertexArray(dsta);
       
   341 
       
   342     m3gFreeTemp(M3G_INTERFACE(momesh));
       
   343     return M3G_TRUE;
       
   344 }
       
   345 
       
   346 /*!
       
   347  * \internal
       
   348  * \brief Morphes byte type color vertex arrays.
       
   349  *
       
   350  * \param momesh        MorphingMesh object
       
   351  * \param dsta          destination VertexArray object
       
   352  * \param base          base VertexArray object
       
   353  * \param arrayOffset   offset to VertexArray object inside Mesh object
       
   354  * \retval M3G_TRUE     morph ok
       
   355  * \retval M3G_FALSE    morph failed, exception raised
       
   356  */
       
   357 static M3Gbool m3gMorphColorBytes(MorphingMesh *momesh, VertexArray *dsta, VertexArray *base, M3Gint arrayOffset)
       
   358 {
       
   359     M3Gint i;
       
   360     M3Gint sum, sw;
       
   361     M3Gubyte *dst, *src;
       
   362     M3Gint skip;
       
   363     M3Gshort j, numMsTargets = 0;
       
   364     M3Gubyte **srct = m3gAllocTemp(M3G_INTERFACE(momesh), sizeof(M3Gubyte *) * momesh->numTargets * 2);
       
   365     M3Gshort *msTargets = (M3Gshort *) (srct + momesh->numTargets);
       
   366 
       
   367 
       
   368     if (msTargets == NULL) {
       
   369         return M3G_FALSE;
       
   370     }
       
   371 
       
   372     /* Check that target arrays are in same format */
       
   373     for (j = 0; j < momesh->numTargets; j++) {
       
   374         VertexArray **va;
       
   375         va = (VertexArray **)(((M3Gbyte *)momesh->targets[j]) + arrayOffset);
       
   376         if (!m3gIsCompatible(*va, base)) {
       
   377             /* Unmap all arrays */
       
   378             for (j = 0; j < numMsTargets; j++) {
       
   379                 m3gUnmapVertexArray(*(VertexArray **)(((M3Gbyte *)momesh->targets[msTargets[j]]) + arrayOffset));
       
   380             }
       
   381             m3gFreeTemp(M3G_INTERFACE(momesh));
       
   382             m3gRaiseError(M3G_INTERFACE(momesh), M3G_INVALID_OPERATION);
       
   383             return M3G_FALSE;
       
   384         }
       
   385         /* Use only most significant targets*/
       
   386         if (momesh->weights[j] != 0) {
       
   387             msTargets[numMsTargets] = j;
       
   388             srct[numMsTargets] = (M3Gubyte *) m3gMapVertexArrayReadOnly(*va);
       
   389             numMsTargets++;
       
   390         }
       
   391     }
       
   392 
       
   393     dst = (M3Gubyte *) m3gMapVertexArray(dsta);
       
   394     src = (M3Gubyte *) m3gMapVertexArray(base);
       
   395     sw = momesh->sumWeights;
       
   396     skip = base->elementSize;
       
   397 
       
   398     for (i = 0; i < base->vertexCount * base->stride; i++) {
       
   399         if ((i & 3) >= skip) continue;
       
   400         sum = src[i] * sw;
       
   401         for (j = 0; j < numMsTargets; j++) {
       
   402             sum += srct[j][i] * momesh->weights[msTargets[j]];
       
   403         }
       
   404 
       
   405         /* Round */
       
   406         sum += WEIGHT_ROUND_PLUS;
       
   407         /* Clamp */
       
   408         if (sum > 255 * WEIGHT_SCALE) sum = 255 * WEIGHT_SCALE;
       
   409 
       
   410         dst[i] = (M3Gubyte) (sum >> WEIGHT_SHIFT);
       
   411     }
       
   412 
       
   413     /* Unmap all arrays */
       
   414     for (j = 0; j < numMsTargets; j++) {
       
   415         m3gUnmapVertexArray(*(VertexArray **)(((M3Gbyte *)momesh->targets[msTargets[j]]) + arrayOffset));
       
   416     }
       
   417 
       
   418     m3gUnmapVertexArray(base);
       
   419     m3gUnmapVertexArray(dsta);
       
   420     
       
   421     m3gFreeTemp(M3G_INTERFACE(momesh));
       
   422     return M3G_TRUE;
       
   423 }
       
   424 
       
   425 /*!
       
   426  * \internal
       
   427  * \brief Morphes all MorphingMesh vertex arrays. That
       
   428  * is positions, normals, texture coordinates and colors.
       
   429  *
       
   430  * \param momesh        MorphingMesh object
       
   431  * \retval M3G_TRUE     morph ok
       
   432  * \retval M3G_FALSE    morph failed, exception raised
       
   433  */
       
   434 static M3Gbool m3gMorph(MorphingMesh *momesh)
       
   435 {
       
   436     M3Gint i, j;
       
   437     M3Gint nullValues;
       
   438 
       
   439     if (momesh->cloneArrayMask != m3gGetArrayMask(momesh->base)) {
       
   440         if (!m3gCreateClones(momesh->base, momesh->morphed)) {
       
   441             return M3G_FALSE;
       
   442         }
       
   443         momesh->cloneArrayMask = m3gGetArrayMask(momesh->base);
       
   444         momesh->dirtyState = M3G_TRUE;
       
   445     }
       
   446 
       
   447     if (momesh->dirtyState == M3G_FALSE) return M3G_TRUE;
       
   448 
       
   449     if (momesh->base->vertices != NULL) {
       
   450         nullValues = 0;
       
   451         for (i = 0; i < momesh->numTargets; i++) {
       
   452             if (momesh->targets[i]->vertices == NULL) {
       
   453                 nullValues++;
       
   454             }           
       
   455         }
       
   456 
       
   457         if (nullValues != momesh->numTargets && nullValues != 0) {
       
   458             m3gRaiseError(M3G_INTERFACE(momesh), M3G_INVALID_OPERATION);
       
   459             return M3G_FALSE;
       
   460         }
       
   461 
       
   462         if (nullValues == 0) {
       
   463             if (momesh->base->vertices->elementType == M3G_GLTYPE(M3G_SHORT)) {
       
   464                 if (!m3gMorphShorts( momesh,
       
   465                                      momesh->morphed->vertices,
       
   466                                      momesh->base->vertices,
       
   467                                      offsetof(VertexBuffer, vertices) )) return M3G_FALSE;
       
   468             }
       
   469             else {
       
   470                 if (!m3gMorphBytes(  momesh,
       
   471                                      momesh->morphed->vertices,
       
   472                                      momesh->base->vertices,
       
   473                                      offsetof(VertexBuffer, vertices) )) return M3G_FALSE;
       
   474             }
       
   475         }
       
   476         else {
       
   477             m3gCopy(m3gMapVertexArray(momesh->morphed->vertices),
       
   478                     m3gMapVertexArrayReadOnly(momesh->base->vertices),
       
   479                     momesh->base->vertices->stride * momesh->base->vertices->vertexCount );
       
   480             m3gUnmapVertexArray(momesh->base->vertices);
       
   481             m3gUnmapVertexArray(momesh->morphed->vertices);
       
   482         }
       
   483     }
       
   484     else {
       
   485         for (i = 0; i < momesh->numTargets; i++) {
       
   486             if (momesh->targets[i]->vertices != NULL) {
       
   487                 m3gRaiseError(M3G_INTERFACE(momesh), M3G_INVALID_OPERATION);
       
   488                 return M3G_FALSE;
       
   489             }           
       
   490         }
       
   491     }
       
   492 
       
   493     if (momesh->base->normals != NULL) {
       
   494         nullValues = 0;
       
   495         for (i = 0; i < momesh->numTargets; i++) {
       
   496             if (momesh->targets[i]->normals == NULL) {
       
   497                 nullValues++;
       
   498             }           
       
   499         }
       
   500 
       
   501         if (nullValues != momesh->numTargets && nullValues != 0) {
       
   502             m3gRaiseError(M3G_INTERFACE(momesh), M3G_INVALID_OPERATION);
       
   503             return M3G_FALSE;
       
   504         }
       
   505 
       
   506         if (nullValues == 0) {
       
   507             if (momesh->base->normals->elementType == M3G_GLTYPE(M3G_SHORT)) {
       
   508                 if (!m3gMorphShorts( momesh,
       
   509                                      momesh->morphed->normals,
       
   510                                      momesh->base->normals,
       
   511                                      offsetof(VertexBuffer, normals) )) return M3G_FALSE;
       
   512             }
       
   513             else {
       
   514                 if (!m3gMorphBytes(  momesh,
       
   515                                      momesh->morphed->normals,
       
   516                                      momesh->base->normals,
       
   517                                      offsetof(VertexBuffer, normals) )) return M3G_FALSE;
       
   518             }
       
   519         }
       
   520         else {
       
   521             m3gCopy(m3gMapVertexArray(momesh->morphed->normals),
       
   522                     m3gMapVertexArrayReadOnly(momesh->base->normals),
       
   523                     momesh->base->normals->stride * momesh->base->normals->vertexCount );
       
   524             m3gUnmapVertexArray(momesh->base->normals);
       
   525             m3gUnmapVertexArray(momesh->morphed->normals);
       
   526         }
       
   527     }
       
   528     else {
       
   529         for (i = 0; i < momesh->numTargets; i++) {
       
   530             if (momesh->targets[i]->normals != NULL) {
       
   531                 m3gRaiseError(M3G_INTERFACE(momesh), M3G_INVALID_OPERATION);
       
   532                 return M3G_FALSE;
       
   533             }           
       
   534         }
       
   535     }
       
   536     
       
   537     if (momesh->base->colors != NULL) {
       
   538         nullValues = 0;
       
   539         for (i = 0; i < momesh->numTargets; i++) {
       
   540             if (momesh->targets[i]->colors == NULL) {
       
   541                 nullValues++;
       
   542             }           
       
   543         }
       
   544         
       
   545         if (nullValues != momesh->numTargets && nullValues != 0) {
       
   546             m3gRaiseError(M3G_INTERFACE(momesh), M3G_INVALID_OPERATION);
       
   547             return M3G_FALSE;
       
   548         }
       
   549 
       
   550         if (nullValues == 0) {
       
   551             /* Only byte colors are supported */
       
   552             if (!m3gMorphColorBytes( momesh,
       
   553                                      momesh->morphed->colors,
       
   554                                      momesh->base->colors,
       
   555                                      offsetof(VertexBuffer, colors) )) return M3G_FALSE;
       
   556         }
       
   557         else {
       
   558             m3gCopy(m3gMapVertexArray(momesh->morphed->colors),
       
   559                     m3gMapVertexArrayReadOnly(momesh->base->colors),
       
   560                     momesh->base->colors->stride * momesh->base->colors->vertexCount );
       
   561             m3gUnmapVertexArray(momesh->base->colors);
       
   562             m3gUnmapVertexArray(momesh->morphed->colors);
       
   563         }
       
   564     }
       
   565     else {
       
   566         /* Morph default color */   
       
   567         M3Gint r, g, b, a;
       
   568         
       
   569         for (i = 0; i < momesh->numTargets; i++) {
       
   570             if (momesh->targets[i]->colors != NULL) {
       
   571                 m3gRaiseError(M3G_INTERFACE(momesh), M3G_INVALID_OPERATION);
       
   572                 return M3G_FALSE;
       
   573             }           
       
   574         }
       
   575 
       
   576         r = momesh->base->defaultColor.r * momesh->sumWeights;
       
   577         g = momesh->base->defaultColor.g * momesh->sumWeights;
       
   578         b = momesh->base->defaultColor.b * momesh->sumWeights;
       
   579         a = momesh->base->defaultColor.a * momesh->sumWeights;
       
   580 
       
   581         for (i = 0; i < momesh->numTargets; i++) {
       
   582             r += momesh->targets[i]->defaultColor.r * momesh->weights[i];
       
   583             g += momesh->targets[i]->defaultColor.g * momesh->weights[i];
       
   584             b += momesh->targets[i]->defaultColor.b * momesh->weights[i];
       
   585             a += momesh->targets[i]->defaultColor.a * momesh->weights[i];
       
   586         }       
       
   587 
       
   588         /* Clamp values*/
       
   589         if (r < 0) r = 0;
       
   590         if (g < 0) g = 0;
       
   591         if (b < 0) b = 0;
       
   592         if (a < 0) a = 0;
       
   593 
       
   594         if (r > 255 * WEIGHT_SCALE) r = 255 * WEIGHT_SCALE;
       
   595         if (g > 255 * WEIGHT_SCALE) g = 255 * WEIGHT_SCALE;
       
   596         if (b > 255 * WEIGHT_SCALE) b = 255 * WEIGHT_SCALE;
       
   597         if (a > 255 * WEIGHT_SCALE) a = 255 * WEIGHT_SCALE;
       
   598 
       
   599         momesh->morphed->defaultColor.r = (GLubyte) (r >> WEIGHT_SHIFT);
       
   600         momesh->morphed->defaultColor.g = (GLubyte) (g >> WEIGHT_SHIFT);
       
   601         momesh->morphed->defaultColor.b = (GLubyte) (b >> WEIGHT_SHIFT);
       
   602         momesh->morphed->defaultColor.a = (GLubyte) (a >> WEIGHT_SHIFT);
       
   603     }
       
   604 
       
   605     for (i = 0; i < M3G_NUM_TEXTURE_UNITS; i++) {
       
   606         if (momesh->base->texCoords[i] != NULL) {
       
   607             nullValues = 0;
       
   608             for (j = 0; j < momesh->numTargets; j++) {
       
   609                 if (momesh->targets[j]->texCoords[i] == NULL) {
       
   610                     nullValues++;
       
   611                 }           
       
   612             }
       
   613 
       
   614             if (nullValues != momesh->numTargets && nullValues != 0) {
       
   615                 m3gRaiseError(M3G_INTERFACE(momesh), M3G_INVALID_OPERATION);
       
   616                 return M3G_FALSE;
       
   617             }
       
   618     
       
   619             if (nullValues == 0) {
       
   620                 if (momesh->base->texCoords[i]->elementType == M3G_GLTYPE(M3G_SHORT)) {
       
   621                     if (!m3gMorphShorts( momesh,
       
   622                                          momesh->morphed->texCoords[i],
       
   623                                          momesh->base->texCoords[i],
       
   624                                          offsetof(VertexBuffer, texCoords) + i * sizeof(VertexBuffer *) )) return M3G_FALSE;
       
   625                 }
       
   626                 else {
       
   627                     if (!m3gMorphBytes(  momesh,
       
   628                                          momesh->morphed->texCoords[i],
       
   629                                          momesh->base->texCoords[i],
       
   630                                          offsetof(VertexBuffer, texCoords) + i * sizeof(VertexBuffer *) )) return M3G_FALSE;
       
   631                 }
       
   632             }
       
   633             else {
       
   634                 m3gCopy(m3gMapVertexArray(momesh->morphed->texCoords[i]),
       
   635                         m3gMapVertexArrayReadOnly(momesh->base->texCoords[i]),
       
   636                         momesh->base->texCoords[i]->stride * momesh->base->texCoords[i]->vertexCount );
       
   637                 m3gUnmapVertexArray(momesh->base->texCoords[i]);
       
   638                 m3gUnmapVertexArray(momesh->morphed->texCoords[i]);
       
   639             }
       
   640         }
       
   641         else {
       
   642             for (j = 0; j < momesh->numTargets; j++) {
       
   643                 if (momesh->targets[j]->texCoords[i] != NULL) {
       
   644                     m3gRaiseError(M3G_INTERFACE(momesh), M3G_INVALID_OPERATION);
       
   645                     return M3G_FALSE;
       
   646                 }           
       
   647             }
       
   648         }
       
   649     }
       
   650 
       
   651     momesh->dirtyState = M3G_FALSE;
       
   652     return M3G_TRUE;
       
   653 }
       
   654 
       
   655 /*!
       
   656  * \internal
       
   657  * \brief Overloaded Object3D method.
       
   658  *
       
   659  * \param property      animation property
       
   660  * \retval M3G_TRUE     property supported
       
   661  * \retval M3G_FALSE    property not supported
       
   662  */
       
   663 static M3Gbool m3gMorphingMeshIsCompatible(M3Gint property)
       
   664 {
       
   665     switch (property) {
       
   666     case M3G_ANIM_MORPH_WEIGHTS:
       
   667         return M3G_TRUE;
       
   668     default:
       
   669         return m3gNodeIsCompatible(property);
       
   670     }
       
   671 }
       
   672 
       
   673 /*!
       
   674  * \internal
       
   675  * \brief Overloaded Node method
       
   676  */
       
   677 static M3Gint m3gMorphingMeshGetBBox(Node *self, AABB *bbox)
       
   678 {
       
   679     MorphingMesh *m = (MorphingMesh*) self;
       
   680     
       
   681     if (m->base->vertices) {
       
   682         if (self->dirtyBits & NODE_BBOX_BIT) {
       
   683 
       
   684             /* Blend target and base mesh bounding boxes to estimate the
       
   685              * real bounding box of the morphed mesh */
       
   686         
       
   687             M3Gint i;
       
   688             M3Gint vMin, vMax;
       
   689             M3Gfloat sumWeights = (M3Gfloat)m->sumWeights / WEIGHT_SCALE;
       
   690 
       
   691             /* Get base mesh bounding box */
       
   692 
       
   693             m3gGetArrayValueRange(m->base->vertices, &vMin, &vMax);
       
   694             if (sumWeights < 0) {
       
   695                 M3Gint t = vMin;
       
   696                 vMin = vMax;
       
   697                 vMax = t;
       
   698             }
       
   699             
       
   700             for (i = 0; i < 3; ++i) {
       
   701                 bbox->min[i] = (M3Gfloat) vMin;
       
   702                 bbox->max[i] = (M3Gfloat) vMax;
       
   703             }
       
   704             
       
   705             /* Blend with target bounding boxes */
       
   706             
       
   707             for (i = 0; i < m->numTargets; i++) {
       
   708                 if (m->targets[i]->vertices) {
       
   709                     M3Gfloat w = m->floatWeights[i];
       
   710 
       
   711                     m3gGetArrayValueRange(m->targets[i]->vertices,
       
   712                                           &vMin, &vMax);
       
   713                     if (w < 0) {
       
   714                         M3Gint t = vMin;
       
   715                         vMin = vMax;
       
   716                         vMax = t;
       
   717                     }
       
   718                     
       
   719                     bbox->min[0] = m3gMadd((M3Gfloat) vMin, w, bbox->min[0]);
       
   720                     bbox->min[1] = m3gMadd((M3Gfloat) vMin, w, bbox->min[1]);
       
   721                     bbox->min[2] = m3gMadd((M3Gfloat) vMin, w, bbox->min[2]);
       
   722                     bbox->max[0] = m3gMadd((M3Gfloat) vMax, w, bbox->max[0]);
       
   723                     bbox->max[1] = m3gMadd((M3Gfloat) vMax, w, bbox->max[1]);
       
   724                     bbox->max[2] = m3gMadd((M3Gfloat) vMax, w, bbox->max[2]);
       
   725                 }
       
   726             }
       
   727 
       
   728             /* Apply scale and bias, and flip the min-max values if
       
   729              * the scale is negative */
       
   730             {
       
   731                 const VertexBuffer *vb = m->base;
       
   732                 for (i = 0; i < 3; ++i) {
       
   733                     
       
   734                     bbox->min[i] = m3gMadd(bbox->min[i], vb->vertexScale,
       
   735                                            vb->vertexBias[i]);
       
   736                     bbox->max[i] = m3gMadd(bbox->max[i], vb->vertexScale,
       
   737                                            vb->vertexBias[i]);
       
   738                     
       
   739                     if (bbox->min[i] > bbox->max[i]) {
       
   740                         M3Gfloat t = bbox->min[i];
       
   741                         bbox->min[i] = bbox->max[i];
       
   742                         bbox->max[i] = t;
       
   743                     }
       
   744                 }
       
   745             }
       
   746             
       
   747             m->bbox = *bbox;
       
   748         }
       
   749         else {
       
   750             *bbox = m->bbox;
       
   751         }
       
   752 
       
   753         /* Estimate a cost of 6 times normal bbox check, as we're
       
   754          * dynamically computing the box every time... */
       
   755         
       
   756         return 6 * VFC_BBOX_COST + VFC_NODE_OVERHEAD;
       
   757     }
       
   758     return 0; /* no vertices, nothing to render */
       
   759 }
       
   760 
       
   761 /*!
       
   762  * \internal
       
   763  * \brief Overloaded Object3D method.
       
   764  *
       
   765  * \param self          MorphingMesh object
       
   766  * \param property      animation property
       
   767  * \param valueSize     size of value array
       
   768  * \param value         value array
       
   769  */
       
   770 static void m3gMorphingMeshUpdateProperty(Object *self,
       
   771                                           M3Gint property,
       
   772                                           M3Gint valueSize,
       
   773                                           const M3Gfloat *value)
       
   774 {
       
   775     M3Gint i;
       
   776     MorphingMesh *mMesh = (MorphingMesh *)self;
       
   777     M3G_VALIDATE_OBJECT(mMesh);
       
   778     M3G_ASSERT_PTR(value);
       
   779     
       
   780     switch (property) {
       
   781     case M3G_ANIM_MORPH_WEIGHTS:
       
   782         mMesh->sumWeights = WEIGHT_SCALE;
       
   783         mMesh->dirtyState = M3G_TRUE;
       
   784 
       
   785         for (i = 0; i < mMesh->numTargets; i++) {
       
   786             /* Value array can have less or more elements than
       
   787                numTargets is. If less, weights after the last
       
   788                element are set to 0. If more, weights after
       
   789                numTargets are ignored. */
       
   790             if (i < valueSize) {
       
   791                 mMesh->floatWeights[i] = value[i];
       
   792                 mMesh->weights[i] = m3gRoundToInt(m3gMul(value[i], WEIGHT_SCALE));
       
   793                 mMesh->sumWeights -= mMesh->weights[i];
       
   794             }
       
   795             else
       
   796                 mMesh->weights[i] = 0;
       
   797         }
       
   798         m3gInvalidateNode((Node*)self, NODE_BBOX_BIT);
       
   799         break;
       
   800     default:
       
   801         m3gNodeUpdateProperty(self, property, valueSize, value);
       
   802     }
       
   803 }
       
   804 
       
   805 /*!
       
   806  * \internal
       
   807  * \brief Deletes all internal vertex arrays.
       
   808  *
       
   809  * \param morphed       VertexBuffer object that contains
       
   810  *                      the internal arrays.
       
   811  */
       
   812 static void m3gDeleteClones(VertexBuffer *morphed)
       
   813 {
       
   814     M3Gint i;
       
   815 
       
   816     M3G_ASSIGN_REF(morphed->vertices, NULL);
       
   817     M3G_ASSIGN_REF(morphed->normals, NULL);
       
   818     M3G_ASSIGN_REF(morphed->colors, NULL);
       
   819 
       
   820     for (i = 0; i < M3G_NUM_TEXTURE_UNITS; i++) {
       
   821         M3G_ASSIGN_REF(morphed->texCoords[i], NULL);
       
   822     }
       
   823 }
       
   824 
       
   825 /*!
       
   826  * \internal
       
   827  * \brief Creates all internal vertex arrays.
       
   828  *
       
   829  * \param vertices      VertexBuffer object that contains
       
   830  *                      the original arrays.
       
   831  * \param morphed       VertexBuffer object that contains
       
   832  *                      the internal arrays.
       
   833  * \retval M3G_TRUE     clones created
       
   834  * \retval M3G_FALSE    clone creation failed
       
   835  */
       
   836 static M3Gbool m3gCreateClones(VertexBuffer *vertices, VertexBuffer *morphed)
       
   837 {
       
   838     M3Gint i, refCount;
       
   839 
       
   840     /* Delete old clone arrays */
       
   841     m3gDeleteClones(morphed);
       
   842 
       
   843     /* Clone all attributes but arrays, reference count and animtracks. Because
       
   844        morphed is an internal buffer it cannot have those attributes copied.
       
   845        If they would be copied it would cause a memory leak when morphed array
       
   846        is destroyed. */
       
   847     refCount = morphed->object.refCount;
       
   848     m3gCopy(morphed, vertices, sizeof(VertexBuffer));
       
   849     morphed->object.refCount = refCount;
       
   850     morphed->object.animTracks = NULL;
       
   851     morphed->vertices = NULL;
       
   852     morphed->normals = NULL;
       
   853     morphed->colors = NULL;
       
   854     for (i = 0; i < M3G_NUM_TEXTURE_UNITS; i++) {
       
   855         morphed->texCoords[i] = NULL;
       
   856     }
       
   857 
       
   858     if (vertices->vertices != NULL) {
       
   859         M3G_ASSIGN_REF(morphed->vertices, m3gCloneVertexArray(vertices->vertices));
       
   860         if (morphed->vertices == NULL) {
       
   861             return M3G_FALSE;
       
   862         }
       
   863     }
       
   864 
       
   865     if (vertices->normals != NULL) {
       
   866         M3G_ASSIGN_REF(morphed->normals, m3gCloneVertexArray(vertices->normals));
       
   867         if (morphed->normals == NULL) {
       
   868             return M3G_FALSE;
       
   869         }
       
   870     }
       
   871 
       
   872     if (vertices->colors != NULL) {
       
   873         M3G_ASSIGN_REF(morphed->colors, m3gCloneVertexArray(vertices->colors));
       
   874         if (morphed->colors == NULL) {
       
   875             return M3G_FALSE;
       
   876         }
       
   877     }
       
   878 
       
   879     for (i = 0; i < M3G_NUM_TEXTURE_UNITS; i++) {
       
   880         if (vertices->texCoords[i] != NULL) {
       
   881             M3G_ASSIGN_REF(morphed->texCoords[i], m3gCloneVertexArray(vertices->texCoords[i]));
       
   882             if (morphed->texCoords[i] == NULL) {
       
   883                 return M3G_FALSE;
       
   884             }
       
   885         }   
       
   886     }
       
   887 
       
   888     return M3G_TRUE;
       
   889 }
       
   890 
       
   891 /*!
       
   892  * \internal
       
   893  * \brief Overloaded Object3D method.
       
   894  *
       
   895  * \param self MorphingMesh object
       
   896  * \param references array of reference objects
       
   897  * \return number of references
       
   898  */
       
   899 static M3Gint m3gMorphingMeshDoGetReferences(Object *self, Object **references)
       
   900 {
       
   901     MorphingMesh *mmesh = (MorphingMesh *)self;
       
   902     M3Gint i, num = m3gMeshDoGetReferences(self, references);
       
   903     for (i = 0; i < mmesh->numTargets; i++) {
       
   904         if (mmesh->targets[i] != NULL) {
       
   905             if (references != NULL)
       
   906                 references[num] = (Object *)mmesh->targets[i];
       
   907             num++;
       
   908         }
       
   909     }
       
   910     return num;
       
   911 }
       
   912 
       
   913 /*!
       
   914  * \internal
       
   915  * \brief Overloaded Object3D method.
       
   916  */
       
   917 static Object *m3gMorphingMeshFindID(Object *self, M3Gint userID)
       
   918 {
       
   919     int i;
       
   920     MorphingMesh *mmesh = (MorphingMesh *)self;
       
   921     Object *found = m3gMeshFindID(self, userID);
       
   922     
       
   923     for (i = 0; !found && i < mmesh->numTargets; ++i) {
       
   924         if (mmesh->targets[i] != NULL) {
       
   925             found = m3gFindID((Object*) mmesh->targets[i], userID);
       
   926         }
       
   927     }
       
   928     return found;
       
   929 }
       
   930 
       
   931 /*!
       
   932  * \internal
       
   933  * \brief Overloaded Object3D method.
       
   934  *
       
   935  * \param originalObj original MorphingMesh object
       
   936  * \param cloneObj pointer to cloned Mesh object
       
   937  * \param pairs array for all object-duplicate pairs
       
   938  * \param numPairs number of pairs
       
   939  */
       
   940 static M3Gbool m3gMorphingMeshDuplicate(const Object *originalObj,
       
   941                                         Object **cloneObj,
       
   942                                         Object **pairs,
       
   943                                         M3Gint *numPairs)
       
   944 {
       
   945     MorphingMesh *original = (MorphingMesh *)originalObj;
       
   946     MorphingMesh *clone;
       
   947     M3G_ASSERT(*cloneObj == NULL); /* no derived classes */
       
   948 
       
   949     /* Create the clone object */
       
   950     
       
   951     clone = (MorphingMesh*) m3gCreateMorphingMesh(originalObj->interface,
       
   952                                                   original->mesh.vertexBuffer,
       
   953                                                   original->targets,
       
   954                                                   original->mesh.indexBuffers,
       
   955                                                   original->mesh.appearances,
       
   956                                                   original->mesh.trianglePatchCount,
       
   957                                                   original->numTargets);
       
   958     if (!clone) {
       
   959         return M3G_FALSE;
       
   960     }
       
   961     *cloneObj = (Object *)clone;
       
   962 
       
   963     /* Duplicate base class data and if that succeeds, our own */
       
   964     
       
   965     if (m3gMeshDuplicate(originalObj, cloneObj, pairs, numPairs)) {
       
   966         m3gSetWeights(clone, original->floatWeights, original->numTargets);
       
   967         return M3G_TRUE;
       
   968     }
       
   969     else {
       
   970         return M3G_FALSE;
       
   971     }
       
   972 }
       
   973 
       
   974 /*!
       
   975  * \internal
       
   976  * \brief Overloaded Node method
       
   977  */
       
   978 static M3Gbool m3gMorphingMeshValidate(Node *self, M3Gbitmask stateBits, M3Gint scope)
       
   979 {
       
   980     MorphingMesh *mesh = (MorphingMesh*) self;
       
   981     AABB bbox;
       
   982     int i;
       
   983     M3G_BEGIN_PROFILE(M3G_INTERFACE(self), M3G_PROFILE_VFC_UPDATE);
       
   984 
       
   985     /* Always compute a new bounding box for morphing meshes --
       
   986      * otherwise we would have to maintain timestamps for all source
       
   987      * vertex buffers */
       
   988     
       
   989     m3gMorphingMeshGetBBox(self, &bbox);
       
   990 
       
   991     /* Invalidate enclosing bounding boxes if new box is larger */
       
   992     
       
   993     for (i = 0; i < 3; ++i) {
       
   994         if (bbox.min[i] < mesh->bbox.min[i] ||
       
   995             bbox.max[i] > mesh->bbox.max[i]) {
       
   996             m3gInvalidateNode(self, NODE_BBOX_BIT);
       
   997             break;
       
   998         }
       
   999     }
       
  1000     mesh->bbox = bbox;
       
  1001     
       
  1002     M3G_END_PROFILE(M3G_INTERFACE(self), M3G_PROFILE_VFC_UPDATE);
       
  1003     return m3gMeshValidate(self, stateBits, scope);
       
  1004 }
       
  1005 
       
  1006 /*!
       
  1007  * \internal
       
  1008  * \brief Initializes a MorphingMesh object. See specification
       
  1009  * for default values.
       
  1010  *
       
  1011  * \param m3g                   M3G interface
       
  1012  * \param momesh                MorphingMesh object
       
  1013  * \param hVertices             VertexBuffer object
       
  1014  * \param hTargets              array of morph target VertexBuffer objects
       
  1015  * \param hTriangles            array of IndexBuffer objects
       
  1016  * \param hAppearances          array of Appearance objects
       
  1017  * \param trianglePatchCount    number of submeshes
       
  1018  * \param targetCount           number of morph targets
       
  1019  * \retval                      M3G_TRUE success
       
  1020  * \retval                      M3G_FALSE failed
       
  1021  */
       
  1022 static M3Gbool m3gInitMorphingMesh( Interface *m3g,
       
  1023                                     MorphingMesh *momesh,
       
  1024                                     M3GVertexBuffer hVertices,
       
  1025                                     M3GVertexBuffer *hTargets,
       
  1026                                     M3GIndexBuffer *hTriangles,
       
  1027                                     M3GAppearance *hAppearances,
       
  1028                                     M3Gint trianglePatchCount,
       
  1029                                     M3Gint targetCount )
       
  1030 {
       
  1031     M3Gint i;
       
  1032 
       
  1033     VertexBuffer *morphed;
       
  1034 
       
  1035     /* Check target validities */
       
  1036     for (i = 0; i < targetCount; i++) {
       
  1037         if (hTargets[i] == NULL) {
       
  1038             m3gRaiseError(m3g, M3G_NULL_POINTER);
       
  1039             return M3G_FALSE;
       
  1040         }
       
  1041     }
       
  1042 
       
  1043     /* Create morphed vertex buffer */
       
  1044     morphed = (VertexBuffer *)m3gCreateVertexBuffer(m3g);
       
  1045     if (morphed == NULL) {
       
  1046         return M3G_FALSE;
       
  1047     }
       
  1048 
       
  1049     M3G_ASSIGN_REF(momesh->morphed, morphed);
       
  1050 
       
  1051     /* Create initial vertex array clones */
       
  1052     if (!m3gCreateClones(hVertices, morphed)) {
       
  1053         M3G_ASSIGN_REF(momesh->morphed, NULL);
       
  1054         return M3G_FALSE;
       
  1055     }
       
  1056 
       
  1057     /* MorphingMesh is derived from Mesh */
       
  1058     if (!m3gInitMesh(m3g, &momesh->mesh,
       
  1059                      hVertices, hTriangles, hAppearances,
       
  1060                      trianglePatchCount,
       
  1061                      M3G_CLASS_MORPHING_MESH)) {
       
  1062         M3G_ASSIGN_REF(momesh->morphed, NULL);
       
  1063         return M3G_FALSE;        
       
  1064     }
       
  1065 
       
  1066     momesh->targets = m3gAllocZ(m3g, sizeof(VertexBuffer *) * targetCount);
       
  1067     momesh->weights = m3gAllocZ(m3g, sizeof(M3Gint) * targetCount);
       
  1068     momesh->floatWeights = m3gAllocZ(m3g, sizeof(M3Gfloat) * targetCount);
       
  1069 
       
  1070     /* Check for errors */
       
  1071     if (!momesh->targets || !momesh->weights || !momesh->floatWeights) {
       
  1072         m3gDestroyMesh((Object *) &momesh->mesh); /* already init'd above */
       
  1073         m3gFree(m3g, momesh->targets);
       
  1074         m3gFree(m3g, momesh->weights);
       
  1075         m3gFree(m3g, momesh->floatWeights);
       
  1076         M3G_ASSIGN_REF(momesh->morphed, NULL);
       
  1077         return M3G_FALSE;    
       
  1078     }
       
  1079 
       
  1080     /* Assign references */
       
  1081     for (i = 0; i < targetCount; i++) {
       
  1082         M3G_ASSIGN_REF(momesh->targets[i], hTargets[i]);
       
  1083     }
       
  1084     
       
  1085     momesh->base = hVertices;
       
  1086     momesh->numTargets = targetCount;
       
  1087     momesh->sumWeights = WEIGHT_SCALE;
       
  1088     momesh->dirtyState = M3G_TRUE;
       
  1089     momesh->cloneArrayMask = m3gGetArrayMask(hVertices);
       
  1090 
       
  1091     return M3G_TRUE;
       
  1092 }
       
  1093 
       
  1094 /*----------------------------------------------------------------------
       
  1095  * Public API functions
       
  1096  *--------------------------------------------------------------------*/
       
  1097 
       
  1098 static const NodeVFTable m3gvf_MorphingMesh = {
       
  1099     {
       
  1100         {
       
  1101             m3gMeshApplyAnimation,
       
  1102             m3gMorphingMeshIsCompatible,
       
  1103             m3gMorphingMeshUpdateProperty,
       
  1104             m3gMorphingMeshDoGetReferences,
       
  1105             m3gMorphingMeshFindID,
       
  1106             m3gMorphingMeshDuplicate,
       
  1107             m3gDestroyMorphingMesh
       
  1108         }
       
  1109     },
       
  1110     m3gNodeAlign,
       
  1111     m3gMorphingMeshDoRender,
       
  1112     m3gMorphingMeshGetBBox,
       
  1113     m3gMorphingMeshRayIntersect,
       
  1114     m3gMorphingMeshSetupRender,
       
  1115     m3gNodeUpdateDuplicateReferences,
       
  1116     m3gMorphingMeshValidate
       
  1117 };
       
  1118 
       
  1119 
       
  1120 /*----------------------------------------------------------------------
       
  1121  * Public API functions
       
  1122  *--------------------------------------------------------------------*/
       
  1123 
       
  1124 /*!
       
  1125  * \brief Creates a MorphingMesh object.
       
  1126  *
       
  1127  * \param interface             M3G interface
       
  1128  * \param hVertices             VertexBuffer object
       
  1129  * \param hTargets              array of morph target VertexBuffer objects
       
  1130  * \param hTriangles            array of IndexBuffer objects
       
  1131  * \param hAppearances          array of Appearance objects
       
  1132  * \param trianglePatchCount    number of submeshes
       
  1133  * \param targetCount           number of morph targets
       
  1134  * \retval Mesh new MorphingMesh object
       
  1135  * \retval NULL MorphingMesh creating failed
       
  1136  */
       
  1137 M3G_API M3GMorphingMesh m3gCreateMorphingMesh(M3GInterface interface,
       
  1138                                               M3GVertexBuffer hVertices,
       
  1139                                               M3GVertexBuffer *hTargets,
       
  1140                                               M3GIndexBuffer *hTriangles,
       
  1141                                               M3GAppearance *hAppearances,
       
  1142                                               M3Gint trianglePatchCount,
       
  1143                                               M3Gint targetCount)
       
  1144 {
       
  1145     Interface *m3g = (Interface *) interface;
       
  1146     M3G_VALIDATE_INTERFACE(m3g);
       
  1147 
       
  1148     {
       
  1149         MorphingMesh *momesh = m3gAllocZ(m3g, sizeof(MorphingMesh));
       
  1150     
       
  1151         if (momesh != NULL) {
       
  1152             if (!m3gInitMorphingMesh(   m3g,
       
  1153                                         momesh,
       
  1154                                         hVertices, hTargets,
       
  1155                                         hTriangles, hAppearances,
       
  1156                                         trianglePatchCount, targetCount)) {
       
  1157                 m3gFree(m3g, momesh);
       
  1158                 return NULL;
       
  1159             }
       
  1160         }
       
  1161 
       
  1162         return (M3GMorphingMesh)momesh;
       
  1163     }
       
  1164 }
       
  1165 
       
  1166 /*!
       
  1167  * \brief Set morph weights.
       
  1168  *
       
  1169  * \param handle                MorphingMesh object
       
  1170  * \param weights               array of weights
       
  1171  * \param numWeights            number of weights in array
       
  1172  */
       
  1173 M3G_API void m3gSetWeights(M3GMorphingMesh handle,
       
  1174                            M3Gfloat *weights,
       
  1175                            M3Gint numWeights)
       
  1176 {
       
  1177     MorphingMesh *momesh = (MorphingMesh *)handle;
       
  1178     M3G_VALIDATE_OBJECT(momesh);
       
  1179     
       
  1180     if (numWeights >= momesh->numTargets) {
       
  1181         M3Gint i;
       
  1182         momesh->dirtyState = M3G_TRUE;
       
  1183         momesh->sumWeights = WEIGHT_SCALE;
       
  1184         for (i = 0; i < momesh->numTargets; i++) {
       
  1185             momesh->floatWeights[i] = weights[i];
       
  1186             momesh->weights[i] = m3gRoundToInt(m3gMul(weights[i], WEIGHT_SCALE));
       
  1187             momesh->sumWeights -= momesh->weights[i];
       
  1188         }
       
  1189         m3gInvalidateNode((Node*)momesh, NODE_BBOX_BIT);
       
  1190     }
       
  1191     else {
       
  1192         m3gRaiseError(M3G_INTERFACE(momesh), M3G_INVALID_VALUE);
       
  1193     }
       
  1194 }
       
  1195 
       
  1196 /*!
       
  1197  * \brief Get morph weights.
       
  1198  *
       
  1199  * \param handle                MorphingMesh object
       
  1200  * \param weights               array of weights to fill in
       
  1201  * \param numWeights            max number of weights in array
       
  1202  */
       
  1203 M3G_API void m3gGetWeights(M3GMorphingMesh handle,
       
  1204                            M3Gfloat *weights,
       
  1205                            M3Gint numWeights)
       
  1206 {
       
  1207     MorphingMesh *momesh = (MorphingMesh *)handle;
       
  1208     M3G_VALIDATE_OBJECT(momesh);
       
  1209     
       
  1210     if (numWeights >= momesh->numTargets) {
       
  1211         M3Gint i;
       
  1212         for (i = 0; i < momesh->numTargets; i++) {
       
  1213             weights[i] = momesh->floatWeights[i];
       
  1214         }
       
  1215     }
       
  1216     else {
       
  1217         m3gRaiseError(M3G_INTERFACE(momesh), M3G_INVALID_VALUE);
       
  1218     }
       
  1219 }
       
  1220 
       
  1221 /*!
       
  1222  * \brief Get morph target.
       
  1223  *
       
  1224  * \param handle                MorphingMesh object
       
  1225  * \param idx                   target index
       
  1226  * \return                      VertexBuffer object
       
  1227  */
       
  1228 M3G_API M3GVertexBuffer m3gGetMorphTarget(M3GMorphingMesh handle, M3Gint idx)
       
  1229 {
       
  1230     MorphingMesh *momesh = (MorphingMesh *)handle;
       
  1231     M3G_VALIDATE_OBJECT(momesh);
       
  1232 
       
  1233     if (idx < 0 || idx >= momesh->numTargets) {
       
  1234         m3gRaiseError(M3G_INTERFACE(momesh), M3G_INVALID_INDEX);
       
  1235         return NULL;
       
  1236     }
       
  1237 
       
  1238     return momesh->targets[idx];
       
  1239 }
       
  1240 
       
  1241 /*!
       
  1242  * \brief Get morph target count.
       
  1243  *
       
  1244  * \param handle                MorphingMesh object
       
  1245  * \return                      number of morph targets
       
  1246  */
       
  1247 M3G_API M3Gint m3gGetMorphTargetCount(M3GMorphingMesh handle)
       
  1248 {
       
  1249     MorphingMesh *momesh = (MorphingMesh *)handle;
       
  1250     M3G_VALIDATE_OBJECT(momesh);
       
  1251 
       
  1252     return momesh->numTargets;
       
  1253 }
       
  1254