os/graphics/m3g/m3gcore11/src/m3g_group.c
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     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: Group implementation
    15 *
    16 */
    17 
    18 
    19 /*!
    20  * \internal
    21  * \file
    22  * \brief Group 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_group.h"
    30 #include "m3g_memory.h"
    31 
    32 /*----------------------------------------------------------------------
    33  * Internal functions
    34  *--------------------------------------------------------------------*/
    35 
    36 /*!
    37  * \internal
    38  * \brief Links a new child into the child list of this node.
    39  *
    40  * This assumes that all error checking has been done prior to calling
    41  * the function, and the operation is a valid one.
    42  *
    43  * \param child Node object
    44  * \param group Group object
    45  */
    46 static void m3gLinkChild(Node *child, Group *group)
    47 {
    48     M3G_VALIDATE_OBJECT(child);
    49     M3G_VALIDATE_OBJECT(group);
    50     
    51 	if (group->firstChild == NULL) {
    52 		group->firstChild = child;
    53 		child->left = child;
    54 		child->right = child;
    55 	}
    56 	else {
    57         Node *linkChild = group->firstChild;
    58         
    59 		child->left = linkChild->left;
    60 		linkChild->left->right = child;
    61         
    62 		child->right = linkChild;
    63 		linkChild->left = child;
    64 	}
    65     m3gSetParent(child, (Node *) group);    
    66 }
    67 
    68 /*!
    69  * \internal
    70  * \brief Removes a child from the child list of this node.
    71  *
    72  * This assumes that all error checking has been done prior to calling
    73  * the function, and the operation is a valid one.
    74  *
    75  * \param child Node object
    76  * \param group Group object
    77  */
    78 static void m3gDetachChild(Node *child, Group *group)
    79 {
    80 	Node *n;
    81     M3G_VALIDATE_OBJECT(child);
    82     M3G_VALIDATE_OBJECT(group);
    83 
    84     n = group->firstChild;
    85     
    86 	do {
    87 		if (n == child) {
    88             M3G_VALIDATE_OBJECT(child->right);
    89             M3G_VALIDATE_OBJECT(child->left);
    90             
    91 			n->right->left = n->left;
    92 			n->left->right = n->right;
    93 
    94 			if (group->firstChild == n) {
    95 				group->firstChild = (n->right != n) ? n->right : NULL;
    96 			}
    97             
    98             n->left = NULL;
    99             n->right = NULL;
   100             m3gSetParent(n, NULL);
   101 			return;
   102 		}
   103         n = n->right;
   104 	} while (n != group->firstChild);
   105 }
   106 
   107 /*!
   108  * \internal
   109  * \brief Destroys this Group object.
   110  *
   111  * \param obj Group object
   112  */
   113 static void m3gDestroyGroup(Object *obj)
   114 {
   115     /* Release child references so they can be deleted */
   116     
   117 	Group *group = (Group *) obj;
   118 	while (group->firstChild != NULL) {
   119         m3gDetachChild(group->firstChild, group);
   120 	}
   121 #   if defined(M3G_ENABLE_VF_CULLING)
   122     if (group->bbox) {
   123         m3gFree(M3G_INTERFACE(group), group->bbox);
   124         m3gIncStat(M3G_INTERFACE(group), M3G_STAT_BOUNDING_BOXES, -1);
   125     }
   126 #   endif
   127     m3gDestroyNode(obj);
   128 }
   129 
   130 /*!
   131  * \internal
   132  * \brief Overloaded Node method.
   133  *
   134  * \param self Group object
   135  * \param refNode alignment reference Node object
   136  *
   137  * \retval M3G_TRUE continue align
   138  * \retval M3G_FALSE abort align
   139  */
   140 static M3Gbool m3gGroupAlign(Node *self, const Node *refNode)
   141 {
   142 	Group *group = (Group *)self;
   143 	Node *child = group->firstChild;
   144 
   145     if (!m3gNodeAlign(self, refNode)) {
   146         return M3G_FALSE;
   147     }
   148 
   149     if (child) {
   150         do {
   151             if (!M3G_VFUNC(Node, child, align)(child, refNode)) {
   152                 return M3G_FALSE;
   153             }
   154             child = child->right;
   155         } while (child != group->firstChild);
   156 	}
   157 
   158     return M3G_TRUE;
   159 }
   160 
   161 /*!
   162  * \internal
   163  * \brief Overloaded Node method.
   164  *
   165  * Setup group rendering by calling child
   166  * nodes' render setup.
   167  *
   168  * \param self Group object
   169  * \param toCamera transform to camera
   170  * \param alphaFactor total alpha factor
   171  * \param caller caller node
   172  * \param renderQueue RenderQueue
   173  *
   174  * \retval M3G_TRUE continue render setup
   175  * \retval M3G_FALSE abort render setup
   176  */
   177 static M3Gbool m3gGroupSetupRender(Node *self,
   178                                    const Node *caller,
   179                                    SetupRenderState *s,
   180                                    RenderQueue *renderQueue)
   181 {
   182 	Group *group = (Group *)self;
   183     M3Gbool enabled, success = M3G_TRUE;
   184 
   185     /* Check whether we're going up or down, and optimize the
   186      * rendering-enabled and visibility checking based on that */
   187 
   188     enabled = (self->enableBits & NODE_RENDER_BIT) != 0;
   189     if (caller != self->parent) {
   190         enabled = m3gHasEnabledPath(self, renderQueue->root);
   191         s->cullMask = CULLMASK_ALL;
   192     }
   193     M3G_ASSERT(!self->dirtyBits || !enabled);
   194     
   195 	/* First do the child nodes, unless disabled (inheritable, so
   196      * children would be, too) */
   197     
   198     if (enabled && (group->numNonCullables > 0 || group->numRenderables > 0)) {
   199         
   200         Node *child = group->firstChild;
   201         if (child) {
   202 
   203             /* Check the bounding box if we have one */
   204             
   205 #           if defined(M3G_ENABLE_VF_CULLING)
   206             if (group->bbox) {
   207                 m3gValidateAABB(group->bbox);
   208                 m3gUpdateCullingMask(s, renderQueue->camera, group->bbox);
   209             }
   210 #           endif
   211             
   212             /* If we're not culled, or if we carry lights, we really
   213              * need to recurse into each child node */
   214             
   215             if (s->cullMask || group->numNonCullables > 0) {
   216                 do {
   217                     if (child != caller) {
   218                         SetupRenderState cs;
   219                         cs.cullMask = s->cullMask;
   220                         
   221                         M3G_BEGIN_PROFILE(M3G_INTERFACE(group),
   222                                           M3G_PROFILE_SETUP_TRANSFORMS);
   223                         m3gGetCompositeNodeTransform(child, &cs.toCamera);
   224                         m3gPreMultiplyMatrix(&cs.toCamera, &s->toCamera);
   225                         M3G_END_PROFILE(M3G_INTERFACE(group),
   226                                         M3G_PROFILE_SETUP_TRANSFORMS);
   227                         
   228                         if (!M3G_VFUNC(Node, child, setupRender)(
   229                                 child, self, &cs, renderQueue)) {
   230                             return M3G_FALSE;
   231                         }
   232                     }
   233                     child = child->right;
   234                 } while (child != group->firstChild);
   235             }
   236             else {
   237                 M3GInterface m3g = M3G_INTERFACE(group);
   238                 M3Gint n = group->numRenderables;
   239                 m3gIncStat(m3g, M3G_STAT_RENDER_NODES, n);
   240                 m3gIncStat(m3g, M3G_STAT_RENDER_NODES_CULLED, n);
   241             }
   242         }
   243     }
   244 
   245 	/* Then do the parent node if we're going up the tree.  Again, we
   246      * can discard the old traversal state at this point. */
   247     
   248 	if (self != renderQueue->root) {
   249 	    Node *parent = self->parent;
   250 	    
   251 	    if (parent != caller && parent != NULL) {
   252             Matrix t;
   253 
   254             M3G_BEGIN_PROFILE(M3G_INTERFACE(self), M3G_PROFILE_SETUP_TRANSFORMS);
   255             if (!m3gGetInverseNodeTransform(self, &t)) {
   256                 return M3G_FALSE;
   257             }
   258 			m3gMulMatrix(&s->toCamera, &t);
   259             M3G_END_PROFILE(M3G_INTERFACE(self), M3G_PROFILE_SETUP_TRANSFORMS);
   260 
   261             success = M3G_VFUNC(Node, parent, setupRender)(parent,
   262                                                            self,
   263                                                            s,
   264                                                            renderQueue);
   265 	    }
   266 	}
   267 
   268     return success;
   269 }
   270 
   271 /*!
   272  * \internal
   273  * \brief Overloaded Object3D method.
   274  *
   275  * \param self Group object
   276  * \param time current world time
   277  * \return minimum validity
   278  */
   279 static M3Gint m3gGroupApplyAnimation(Object *self, M3Gint time)
   280 {
   281     M3Gint validity, minValidity;
   282 	Node *child;
   283     Group *group = (Group *)self;
   284     M3G_VALIDATE_OBJECT(group);
   285 
   286     minValidity = m3gObjectApplyAnimation(self, time);
   287     
   288     child = group->firstChild;
   289     if (child && minValidity > 0) {
   290         do {
   291             validity = M3G_VFUNC(Object, child, applyAnimation)(
   292                 (Object *)child, time);
   293             minValidity = validity < minValidity ? validity : minValidity;
   294             child = child->right;
   295         } while (minValidity > 0 && child != group->firstChild);
   296     }
   297     return minValidity;
   298 }
   299 
   300 /*!
   301  * \internal
   302  * \brief Overloaded Node method.
   303  *
   304  * Call child nodes' ray intersect.
   305  *
   306  * \param self      Group object
   307  * \param mask      pick scope mask
   308  * \param ray       pick ray
   309  * \param ri        RayIntersection object
   310  * \param toGroup   transform to originating group
   311  * \retval          M3G_TRUE    continue pick
   312  * \retval          M3G_FALSE   abort pick
   313  */
   314 static M3Gbool m3gGroupRayIntersect(Node *self,
   315                                     M3Gint mask,
   316                                     M3Gfloat *ray,
   317                                     RayIntersection *ri,
   318                                     Matrix *toGroup)
   319 {
   320     Group *group = (Group *)self;
   321     Node *child;
   322     Matrix t, nt;
   323 
   324     m3gIdentityMatrix(&t);
   325     m3gIdentityMatrix(&nt);
   326 
   327     child = group->firstChild;
   328     if (child) {
   329         do {
   330             if (m3gHasPickablePath(child, ri->root)) {
   331                 m3gCopyMatrix(&t, toGroup);
   332                 m3gGetCompositeNodeTransform(child, &nt);
   333                 m3gRightMulMatrix(&t, &nt);
   334                 
   335                 if (!M3G_VFUNC(Node, child, rayIntersect)(
   336                         child, mask, ray, ri, &t)) {
   337                     return M3G_FALSE;
   338                 }
   339             }    
   340             child = child->right;
   341         } while (child != group->firstChild);
   342     }
   343 
   344     return M3G_TRUE;
   345 }
   346 
   347 /*!
   348  * \internal
   349  * \brief Initializes pick traversing.
   350  *
   351  * \param ri        RayIntersection object
   352  * \param root      Root node for the traversing
   353  * \param camera    Camera object used in pick (2D pick only)
   354  * \param x         viewport x (2D pick only)
   355  * \param y         viewport y (2D pick only)
   356  */
   357 static void m3gInitPick(RayIntersection *ri, Node *root, Camera *camera, M3Gfloat x, M3Gfloat y)
   358 {
   359     m3gZero(ri, sizeof(*ri));
   360 
   361     ri->root = root;
   362     ri->camera = camera;
   363     ri->x = x;
   364     ri->y = y;
   365     ri->tMin = M3G_MAX_POSITIVE_FLOAT;
   366 }
   367 
   368 /*!
   369  * \internal
   370  * \brief Fills Java side RayIntersection result.
   371  *
   372  * \param ri        RayIntersection object
   373  * \param ray       Ray used in pick
   374  * \param result    Java side float array
   375  */
   376 static void m3gFillPickResult(RayIntersection *ri, M3Gfloat *ray, M3Gfloat *result)
   377 {
   378     if (ri->intersected != NULL) {
   379         Vec3 n;
   380 
   381         /* Fill in the values */
   382         result[0] = ri->distance;
   383         result[1] = (M3Gfloat)ri->submeshIndex;
   384         result[2] = ri->textureS[0];
   385         result[3] = ri->textureS[1];
   386         result[4] = ri->textureT[0];
   387         result[5] = ri->textureT[1];
   388 
   389         /* Normalize normal */
   390         n.x = ri->normal[0];
   391         n.y = ri->normal[1];
   392         n.z = ri->normal[2];
   393         m3gNormalizeVec3(&n);
   394 
   395         result[6] = n.x;
   396         result[7] = n.y;
   397         result[8] = n.z;
   398 
   399         result[9] = ray[0];
   400         result[10] = ray[1];
   401         result[11] = ray[2];
   402         result[12] = m3gSub(ray[3], ray[0]);
   403         result[13] = m3gSub(ray[4], ray[1]);
   404         result[14] = m3gSub(ray[5], ray[2]);
   405     }
   406 }
   407 
   408 /*!
   409  * \internal
   410  * \brief Overloaded Object3D method.
   411  *
   412  * \param self Group object
   413  * \param references array of reference objects
   414  * \return number of references
   415  */
   416 static M3Gint m3gGroupDoGetReferences(Object *self, Object **references)
   417 {
   418     Group *group = (Group *)self;
   419     M3Gint num = m3gObjectDoGetReferences(self, references);
   420     Node *child = group->firstChild;
   421     if (child) {
   422         do {
   423             if (references != NULL)
   424                 references[num] = (Object *)child;
   425             child = child->right;
   426             num++;
   427         } while (child != group->firstChild);
   428     }
   429     return num;
   430 }
   431 
   432 /*!
   433  * \internal
   434  * \brief Overloaded Object3D method.
   435  *
   436  * \param self Group object
   437  * \param references array of reference objects
   438  * \return number of references
   439  */
   440 static Object *m3gGroupFindID(Object *self, M3Gint userID)
   441 {
   442     Group *group = (Group *)self;
   443     Object *found = m3gObjectFindID(self, userID);
   444     
   445     Node *child = group->firstChild;
   446     if (child && !found) {
   447         do {
   448             found = m3gFindID((Object*) child, userID);
   449             child = child->right;
   450         } while (!found && child != group->firstChild);
   451     }
   452     return found;
   453 }
   454 
   455 /*!
   456  * \internal
   457  * \brief Overloaded Object3D method.
   458  *
   459  * \param originalObj original Group object
   460  * \param cloneObj pointer to cloned Group object
   461  * \param pairs array for all object-duplicate pairs
   462  * \param numPairs number of pairs
   463  */
   464 static M3Gbool m3gGroupDuplicate(const Object *originalObj,
   465                                  Object **cloneObj,
   466                                  Object **pairs,
   467                                  M3Gint *numPairs)
   468 {
   469     Node *child;
   470     Group *original = (Group *)originalObj;
   471     Group *clone;
   472 
   473     /* Create the clone object, unless already created in a derived
   474      * class function */
   475     
   476     if (*cloneObj == NULL) {
   477         clone = (Group *)m3gCreateGroup(originalObj->interface);
   478         if (!clone) {
   479             return M3G_FALSE; /* out of memory */
   480         }
   481         *cloneObj = (Object *)clone;
   482     }
   483     else {
   484         clone = (Group *)*cloneObj;
   485     }
   486 
   487     /* Call base class function to duplicate base class data */
   488     
   489     if (!m3gNodeDuplicate(originalObj, cloneObj, pairs, numPairs)) {
   490         return M3G_FALSE; /* out of memory; caller will delete us */
   491     }
   492 
   493     /* Duplicate child nodes. */
   494     
   495     child = original->firstChild;
   496     if (child) {
   497         do {
   498             Node *temp = NULL;
   499             if (!M3G_VFUNC(Object, child, duplicate)(
   500                     (Object *)child, (Object**)&temp, pairs, numPairs)) {
   501                 m3gDeleteObject((Object*) temp); /* we have the only reference */
   502                 return M3G_FALSE;
   503             }
   504             m3gAddChild(clone, temp);
   505             child = child->right;
   506         } while (child != original->firstChild);
   507     }
   508     
   509     return M3G_TRUE;
   510 }
   511 
   512 /*!
   513  * \internal
   514  * \brief Overloaded Node method
   515  */
   516 static M3Gint m3gGroupGetBBox(Node *self, AABB *bbox)
   517 {
   518     Group *group = (Group*) self;
   519     
   520     /* Quick exit for empty volumes */
   521     
   522     if (!group->firstChild || !self->hasRenderables) {
   523         return 0;
   524     }
   525 
   526     /* Assume our existing bbox is ok, but compute a new one if it
   527      * isn't */
   528     
   529     if (group->bbox && !(self->dirtyBits & NODE_BBOX_BIT)) {
   530         *bbox = *group->bbox;
   531     }
   532     else {
   533 
   534         /* Compute local bounding box by recursively merging the
   535          * bounding boxes of all renderable child nodes */
   536     
   537         Node *child = group->firstChild;
   538         M3Gint groupYield = 0;
   539         
   540         do {
   541             if (child->hasRenderables && child->enableBits) {
   542                 
   543                 /* Get the transformation for the child node, then
   544                  * update our existing state with its bounding box */
   545                 
   546                 AABB childBBox;
   547                 M3Gint childYield;
   548                 Matrix t;
   549                 
   550                 childYield = m3gGetNodeBBox(child, &childBBox);
   551                 if (childYield > 0) {
   552                     m3gGetCompositeNodeTransform(child, &t);
   553                     m3gTransformAABB(&childBBox, &t);
   554                     
   555                     if (groupYield) {
   556                         m3gFitAABB(bbox, &childBBox, bbox);
   557                     }
   558                     else {
   559                         *bbox = childBBox;
   560                     }
   561                     groupYield += childYield;
   562                 }
   563             }
   564             child = child->right;
   565         } while (child != group->firstChild);
   566         
   567         /* Store the updated bbox locally if we have one, or return
   568          * the combined child yield factor if we don't */
   569         
   570         if (group->bbox) {
   571             *group->bbox = *bbox;
   572         }
   573         else {
   574             return (groupYield > 0) ? groupYield + VFC_NODE_OVERHEAD : 0;
   575         }
   576     }
   577     return VFC_BBOX_COST + VFC_NODE_OVERHEAD;
   578 }
   579 
   580 /*!
   581  * \internal
   582  * \brief Overloaded Node method
   583  */
   584 static M3Gbool m3gGroupValidate(Node *self, M3Gbitmask stateBits, M3Gint scope)
   585 {
   586     Group *group = (Group*) self;
   587 
   588     if (stateBits & self->enableBits) {
   589         
   590         /* First validate child nodes to ensure we don't skip anything,
   591          * and allow children to invalidate our state */
   592     
   593         Node *child = group->firstChild;
   594         if (child) {
   595             do {
   596                 if (!m3gValidateNode(child, stateBits, scope)) {
   597                     return M3G_FALSE;
   598                 }
   599                 child = child->right;
   600             } while (child != group->firstChild);
   601         }
   602 
   603         /* Re-evaluate our local bounding box if necessary */
   604 
   605         if (self->hasRenderables && self->dirtyBits & NODE_BBOX_BIT) {
   606             AABB bbox;
   607             M3Gint yield;
   608             M3G_BEGIN_PROFILE(M3G_INTERFACE(self), M3G_PROFILE_VFC_UPDATE);
   609             
   610             yield = m3gGetNodeBBox(self, &bbox);
   611         
   612             /* Think about adding a bounding box if we don't yet have one,
   613              * or removing the current one if it doesn't seem worth it */
   614 
   615             if (!group->bbox) {
   616                 if (yield > (3*VFC_BBOX_COST) >> 1) {
   617                     group->bbox = m3gAlloc(M3G_INTERFACE(group),
   618                                            sizeof(*group->bbox));
   619                     if (group->bbox) {
   620                         m3gIncStat(M3G_INTERFACE(group),
   621                                    M3G_STAT_BOUNDING_BOXES, 1);
   622                         *group->bbox = bbox;
   623                     }
   624                     else {
   625                         return M3G_FALSE;
   626                     }
   627                 }
   628             }
   629             else if (yield <= VFC_BBOX_COST) {
   630                 m3gFree(M3G_INTERFACE(group), group->bbox);
   631                 group->bbox = NULL;
   632                 m3gIncStat(M3G_INTERFACE(group), M3G_STAT_BOUNDING_BOXES, -1);
   633             }
   634             M3G_END_PROFILE(M3G_INTERFACE(self), M3G_PROFILE_VFC_UPDATE);
   635         }
   636         return m3gNodeValidate(self, stateBits, scope);
   637     }
   638     return M3G_TRUE;
   639 }
   640 
   641 /*!
   642  * \internal
   643  * \brief Overloaded Node method.
   644  *
   645  * \param self Group object
   646  * \param pairs array for all object-duplicate pairs
   647  * \param numPairs number of pairs
   648  */
   649 static void m3gGroupUpdateDuplicateReferences(Node *self, Object **pairs, M3Gint numPairs)
   650 {
   651     Group *group = (Group *)self;
   652     Node *child = group->firstChild;
   653     
   654     m3gNodeUpdateDuplicateReferences(self, pairs, numPairs);
   655     
   656     if (child) {
   657         do {
   658             M3G_VFUNC(Node, child, updateDuplicateReferences)(
   659                 child, pairs, numPairs);
   660             child = child->right;
   661         } while (child != group->firstChild);
   662     }
   663 }
   664 
   665 /*!
   666  * \internal
   667  * \brief Initializes a Group object. See specification
   668  * for default values.
   669  *
   670  * \param m3g           M3G interface
   671  * \param group         Group object
   672  * \param vfTable       virtual function table
   673  */
   674 static void m3gInitGroup(Interface *m3g, Group *group, M3GClass classID)
   675 {
   676 	/* Group is derived from Node */
   677 	m3gInitNode(m3g, &group->node, classID);
   678 }
   679 
   680 /*----------------------------------------------------------------------
   681  * Virtual function table
   682  *--------------------------------------------------------------------*/
   683 
   684 static const NodeVFTable m3gvf_Group = {
   685     {
   686         {
   687             m3gGroupApplyAnimation,
   688             m3gNodeIsCompatible,
   689             m3gNodeUpdateProperty,
   690             m3gGroupDoGetReferences,
   691             m3gGroupFindID,
   692             m3gGroupDuplicate,
   693             m3gDestroyGroup
   694         }
   695     },
   696     m3gGroupAlign,
   697     NULL, /* pure virtual m3gNodeDoRender */
   698     m3gGroupGetBBox,
   699     m3gGroupRayIntersect,
   700     m3gGroupSetupRender,
   701     m3gGroupUpdateDuplicateReferences,
   702     m3gGroupValidate
   703 };
   704 
   705 
   706 /*----------------------------------------------------------------------
   707  * Public API functions
   708  *--------------------------------------------------------------------*/
   709 
   710 /*!
   711  * \brief Creates a Group object.
   712  *
   713  * \param interface     M3G interface
   714  * \retval Group new Group object
   715  * \retval NULL Group creating failed
   716  */
   717 M3G_API M3GGroup m3gCreateGroup(M3GInterface interface)
   718 {
   719     Interface *m3g = (Interface *) interface;
   720     M3G_VALIDATE_INTERFACE(m3g);
   721 
   722 	{
   723 		Group *group =  m3gAllocZ(m3g, sizeof(Group));
   724 	
   725         if (group != NULL) {
   726     		m3gInitGroup(m3g, group, M3G_CLASS_GROUP);
   727         }
   728 
   729 		return (M3GGroup) group;
   730 	}
   731 }
   732 
   733 /*!
   734  * \brief Adds a node to this group.
   735  *
   736  * \param handle        Group object
   737  * \param hNode         Node object
   738  */
   739 M3G_API void m3gAddChild(M3GGroup handle, M3GNode hNode)
   740 {
   741     Group *group = (Group *) handle;
   742 	Node *child = (Node *) hNode;
   743     
   744     M3G_VALIDATE_OBJECT(group);
   745 
   746     if (child == NULL) {
   747         m3gRaiseError(M3G_INTERFACE(group), M3G_NULL_POINTER);
   748         return;
   749     }
   750 
   751     if (child == (Node *)group   ||
   752         (child->parent != NULL && child->parent != (Node *)group) ||
   753         m3gIsChildOf(child, (Node *)group) ||
   754         m3gGetClass((Object *) child) == M3G_CLASS_WORLD) {
   755         m3gRaiseError(M3G_INTERFACE(group), M3G_INVALID_VALUE);
   756         return;
   757     }
   758 
   759     if (child->parent == NULL) {
   760         m3gLinkChild(child, group);
   761     }
   762 }
   763 
   764 /*!
   765  * \brief Removes a node from this group.
   766  *
   767  * \param handle        Group object
   768  * \param hNode         Node object
   769  */
   770 M3G_API void m3gRemoveChild(M3GGroup handle, M3GNode hNode)
   771 {
   772     Group *group = (Group *) handle;
   773 	Node *child = (Node *)hNode;
   774     M3G_VALIDATE_OBJECT(group);
   775 
   776     if (child == NULL) {
   777         return;
   778     }
   779 
   780     if (child->hasBones == M3G_TRUE) {
   781         m3gRaiseError(M3G_INTERFACE(group), M3G_INVALID_VALUE);
   782         return;
   783     }
   784     
   785     if (group->firstChild == NULL) {
   786         return;
   787     }
   788 
   789     m3gDetachChild(child, group);
   790 }
   791 
   792 /*!
   793  * \brief Performs 3D pick.
   794  *
   795  * \param handle        Group object
   796  * \param mask          pick scope mask
   797  * \param ray           pick ray
   798  * \arg ray[0]          origin X
   799  * \arg ray[1]          origin Y
   800  * \arg ray[2]          origin Z
   801  * \arg ray[3]          direction X
   802  * \arg ray[4]          direction Y
   803  * \arg ray[5]          direction Z
   804  * \param result        java side RayIntersection result
   805  * \arg result[0]       distance
   806  * \arg result[1]       submesh index
   807  * \arg result[2]       textureS[0]
   808  * \arg result[3]       textureS[1]
   809  * \arg result[4]       textureT[0]
   810  * \arg result[5]       textureT[1]
   811  * \arg result[6]       normal X
   812  * \arg result[7]       normal Y
   813  * \arg result[8]       normal Z
   814  * \arg result[9]       ray ox
   815  * \arg result[10]      ray oy
   816  * \arg result[11]      ray oz
   817  * \arg result[12]      ray dx
   818  * \arg result[13]      ray dy
   819  * \arg result[14]      ray dz
   820  * \return              intersected Node object
   821  */
   822 
   823 #ifdef M3G_ENABLE_PROFILING
   824 static M3GNode m3gPick3DInternal(M3GGroup handle,
   825                           M3Gint mask,
   826                           M3Gfloat *ray,
   827                           M3Gfloat *result);
   828 
   829 M3G_API M3GNode m3gPick3D(M3GGroup handle,
   830                           M3Gint mask,
   831                           M3Gfloat *ray,
   832                           M3Gfloat *result)
   833 {
   834     M3GNode pickResult;
   835     M3G_BEGIN_PROFILE(M3G_INTERFACE(handle), M3G_PROFILE_PICK);
   836     pickResult = m3gPick3DInternal(handle, mask, ray, result);
   837     M3G_END_PROFILE(M3G_INTERFACE(handle), M3G_PROFILE_PICK);
   838     return pickResult;
   839 }
   840 
   841 static M3GNode m3gPick3DInternal(M3GGroup handle,
   842                           M3Gint mask,
   843                           M3Gfloat *ray,
   844                           M3Gfloat *result)
   845 #else
   846 M3G_API M3GNode m3gPick3D(M3GGroup handle,
   847                           M3Gint mask,
   848                           M3Gfloat *ray,
   849                           M3Gfloat *result)
   850 
   851 #endif
   852 {
   853     RayIntersection ri;
   854     Matrix toGroup;
   855     Group *group = (Group *) handle;
   856     M3G_VALIDATE_OBJECT(group);
   857 
   858     M3G_LOG1(M3G_LOG_STAGES, "Picking group 0x%08X\n", (unsigned) group);
   859     
   860     /* Check for errors */
   861     if (ray[3] == 0 && ray[4] == 0 && ray[5] == 0) {
   862         m3gRaiseError(M3G_INTERFACE(group), M3G_INVALID_VALUE);
   863         return NULL;
   864     }
   865     if (!m3gValidateNode((Node*) group, NODE_PICK_BIT, mask)) {
   866         return NULL;
   867     }
   868         
   869     m3gInitPick(&ri, (Node *)group, NULL, 0, 0);
   870     m3gIdentityMatrix(&toGroup);
   871 
   872     ray[3] = m3gAdd(ray[3], ray[0]);
   873     ray[4] = m3gAdd(ray[4], ray[1]);
   874     ray[5] = m3gAdd(ray[5], ray[2]);
   875 
   876     M3G_VFUNC(Node, group, rayIntersect)(   (Node *)group,
   877                                             mask,
   878                                             ray,
   879                                             &ri,
   880                                             &toGroup);
   881     m3gFillPickResult(&ri, ray, result);
   882     return ri.intersected;
   883 }
   884 
   885 /*!
   886  * \brief Performs 2D pick.
   887  *
   888  * \param handle        Group object
   889  * \param mask          pick scope mask
   890  * \param x             viewport x
   891  * \param y             viewport y
   892  * \param hCamera       Camera object
   893  * \param result        java side RayIntersection result, see m3gPick3D
   894  * \return              intersected Node object
   895  */
   896 
   897 #ifdef M3G_ENABLE_PROFILING
   898 static M3GNode m3gPick2DInternal(M3GGroup handle,
   899                           M3Gint mask,
   900                           M3Gfloat x, M3Gfloat y,
   901                           M3GCamera hCamera,
   902                           M3Gfloat *result);
   903 
   904 M3G_API M3GNode m3gPick2D(M3GGroup handle,
   905                           M3Gint mask,
   906                           M3Gfloat x, M3Gfloat y,
   907                           M3GCamera hCamera,
   908                           M3Gfloat *result)
   909 {
   910     M3GNode pickResult;
   911     M3G_BEGIN_PROFILE(M3G_INTERFACE(handle), M3G_PROFILE_PICK);
   912     pickResult = m3gPick2DInternal(handle, mask, x, y, hCamera, result);
   913     M3G_END_PROFILE(M3G_INTERFACE(handle), M3G_PROFILE_PICK);
   914     return pickResult;
   915 }
   916 
   917 static M3GNode m3gPick2DInternal(M3GGroup handle,
   918                           M3Gint mask,
   919                           M3Gfloat x, M3Gfloat y,
   920                           M3GCamera hCamera,
   921                           M3Gfloat *result)
   922 #else
   923 M3G_API M3GNode m3gPick2D(M3GGroup handle,
   924                           M3Gint mask,
   925                           M3Gfloat x, M3Gfloat y,
   926                           M3GCamera hCamera,
   927                           M3Gfloat *result)
   928 #endif
   929 {
   930     Vec4 farp, nearp;
   931     RayIntersection ri;
   932     Matrix toGroup;
   933     M3Gfloat ray[6 + 2];    /* Extra floats to store near and far plane z */
   934     Node *root;
   935     Group *group = (Group *) handle;    
   936 
   937     M3G_LOG2(M3G_LOG_STAGES, "Picking group 0x%08X via camera 0x%08X\n",
   938              (unsigned) group, (unsigned) hCamera);
   939     
   940     M3G_VALIDATE_OBJECT(group);
   941 
   942     if (hCamera == 0) {
   943         m3gRaiseError(M3G_INTERFACE(group), M3G_NULL_POINTER);
   944         return NULL;
   945     }
   946 
   947     root = m3gGetRoot((Node *)hCamera);
   948 
   949     if (root != m3gGetRoot(&group->node)) {
   950         m3gRaiseError(M3G_INTERFACE(group), M3G_INVALID_OPERATION);
   951         return NULL;
   952     }
   953     if (!m3gValidateNode(root, NODE_PICK_BIT, mask)) {
   954         return NULL;
   955     }
   956 
   957     farp.x = m3gSub(m3gMul(2, x), 1.f);
   958     farp.y = m3gSub(1.f, m3gMul(2, y));
   959     farp.z = 1.f;
   960     farp.w = 1.f;
   961 
   962     nearp.x = farp.x;
   963     nearp.y = farp.y;
   964     nearp.z = -1.f;
   965     nearp.w =  1.f;
   966 
   967     m3gCopyMatrix(&toGroup, m3gProjectionMatrix((Camera *)hCamera));
   968 
   969     M3G_BEGIN_PROFILE(M3G_INTERFACE(group), M3G_PROFILE_TRANSFORM_INVERT);
   970     if (!m3gInvertMatrix(&toGroup)) {
   971         m3gRaiseError(M3G_INTERFACE(group), M3G_ARITHMETIC_ERROR);
   972         return NULL;
   973     }
   974     M3G_END_PROFILE(M3G_INTERFACE(group), M3G_PROFILE_TRANSFORM_INVERT);
   975 
   976     m3gTransformVec4(&toGroup, &nearp);
   977     m3gTransformVec4(&toGroup, &farp);
   978 
   979     m3gScaleVec4(&nearp, m3gRcp(nearp.w));
   980     m3gScaleVec4(&farp, m3gRcp(farp.w));
   981 
   982     /* Store near and far plane z for sprite picking */
   983     ray[6] = nearp.z;
   984     ray[7] = farp.z;
   985 
   986     if (!m3gGetTransformTo((M3GNode) hCamera, (Node *) group, &toGroup)) {
   987         return NULL;
   988     }
   989 
   990     m3gTransformVec4(&toGroup, &nearp);
   991     m3gTransformVec4(&toGroup, &farp);
   992 
   993     m3gScaleVec4(&nearp, m3gRcp(nearp.w));
   994     m3gScaleVec4(&farp, m3gRcp(farp.w));
   995 
   996     ray[0] = nearp.x;
   997     ray[1] = nearp.y;
   998     ray[2] = nearp.z;
   999     ray[3] = farp.x;
  1000     ray[4] = farp.y;
  1001     ray[5] = farp.z;
  1002 
  1003 
  1004     m3gInitPick(&ri, (Node *)group, (Camera *)hCamera, x, y);
  1005     m3gIdentityMatrix(&toGroup);
  1006 
  1007     M3G_VFUNC(Node, group, rayIntersect)((Node *)group, mask, ray, &ri, &toGroup);
  1008 
  1009     m3gFillPickResult(&ri, ray, result);
  1010     return ri.intersected;
  1011 }
  1012 
  1013 /*!
  1014  * \brief Gets a child.
  1015  *
  1016  * \param handle        Group object
  1017  * \param idx           child index
  1018  * \return              Node object
  1019  */
  1020 M3G_API M3GNode m3gGetChild(M3GGroup handle, M3Gint idx)
  1021 {
  1022     Node *n;
  1023     Group *group = (Group *) handle;
  1024     M3G_VALIDATE_OBJECT(group);
  1025 
  1026     if (idx < 0) {
  1027         goto InvalidIndex;
  1028     }
  1029 
  1030 	n = group->firstChild;
  1031 
  1032     while (idx-- > 0) {
  1033         n = n->right;
  1034         if (n == group->firstChild) {
  1035             goto InvalidIndex;
  1036         }
  1037     }
  1038     return n;
  1039 
  1040     InvalidIndex:
  1041     m3gRaiseError(M3G_INTERFACE(group), M3G_INVALID_INDEX);
  1042     return NULL;
  1043 }
  1044 
  1045 /*!
  1046  * \brief Gets children count.
  1047  *
  1048  * \param handle        Group object
  1049  * \return              children count
  1050  */
  1051 M3G_API M3Gint m3gGetChildCount(M3GGroup handle)
  1052 {
  1053     Group *group = (Group *) handle;
  1054     M3G_VALIDATE_OBJECT(group);
  1055     {
  1056         M3Gint count = 0;
  1057         const Node *child = group->firstChild;
  1058         if (child) {
  1059             do {
  1060                 ++count;
  1061                 child = child->right;
  1062             } while (child != group->firstChild);
  1063         }
  1064         return count;
  1065     }
  1066 }
  1067