Update contrib.
2 * Copyright (c) 2003 Nokia Corporation and/or its subsidiary(-ies).
4 * This component and the accompanying materials are made available
5 * under the terms of the License "Eclipse Public License v1.0"
6 * which accompanies this distribution, and is available
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
9 * Initial Contributors:
10 * Nokia Corporation - initial contribution.
14 * Description: Mesh implementation
22 * \brief Mesh implementation
25 #ifndef M3G_CORE_INCLUDE
26 # error included by m3g_core.c; do not compile separately.
30 #include "m3g_memory.h"
32 /*----------------------------------------------------------------------
34 *--------------------------------------------------------------------*/
38 * \brief Destroys this Mesh object.
40 * \param obj Mesh object
42 static void m3gDestroyMesh(Object *obj)
45 Mesh *mesh = (Mesh *) obj;
46 M3G_VALIDATE_OBJECT(mesh);
48 for (i = 0; i < mesh->trianglePatchCount; ++i) {
49 M3G_ASSIGN_REF(mesh->indexBuffers[i], NULL);
50 M3G_ASSIGN_REF(mesh->appearances[i], NULL);
52 M3G_ASSIGN_REF(mesh->vertexBuffer, NULL);
55 Interface *m3g = M3G_INTERFACE(mesh);
56 m3gFree(m3g, mesh->indexBuffers);
57 m3gFree(m3g, mesh->appearances);
60 m3gIncStat(M3G_INTERFACE(obj), M3G_STAT_RENDERABLES, -1);
67 * \brief Insert a mesh into a rendering queue
69 static M3Gbool m3gQueueMesh(Mesh *mesh, const Matrix *toCamera,
70 RenderQueue *renderQueue)
74 /* Fetch the cumulative alpha factor for this node */
76 mesh->totalAlphaFactor =
77 (M3Gushort) m3gGetTotalAlphaFactor((Node*) mesh, renderQueue->root);
79 /* Insert each submesh into the rendering queue */
81 for (i = 0; i < mesh->trianglePatchCount; i++) {
82 if (mesh->appearances[i] != NULL) {
83 if (!m3gInsertDrawable(M3G_INTERFACE(mesh),
88 m3gGetAppearanceSortKey(mesh->appearances[i])))
97 * \brief Overloaded Node method.
99 * Setup mesh rendering by adding all submeshes to
102 * \param self Mesh object
103 * \param toCamera transform to camera
104 * \param alphaFactor total alpha factor
105 * \param caller caller node
106 * \param renderQueue RenderQueue
108 * \retval M3G_TRUE continue render setup
109 * \retval M3G_FALSE abort render setup
111 static M3Gbool m3gMeshSetupRender(Node *self,
114 RenderQueue *renderQueue)
116 Mesh *mesh = (Mesh *)self;
118 m3gIncStat(M3G_INTERFACE(self), M3G_STAT_RENDER_NODES, 1);
120 if ((self->enableBits & NODE_RENDER_BIT) != 0 &&
121 (self->scope & renderQueue->scope) != 0) {
123 /* Check view frustum culling */
125 # if defined(M3G_ENABLE_VF_CULLING)
127 m3gGetBoundingBox(mesh->vertexBuffer, &bbox);
128 m3gUpdateCullingMask(s, renderQueue->camera, &bbox);
129 if (s->cullMask == 0) {
130 m3gIncStat(M3G_INTERFACE(self),
131 M3G_STAT_RENDER_NODES_CULLED, 1);
136 /* No dice, let's render... */
138 return m3gQueueMesh(mesh, &s->toCamera, renderQueue);
145 * \brief Overloaded Node method.
147 * Renders one submesh.
149 * \param self Mesh object
150 * \param ctx current render context
151 * \param patchIndex submesh index
153 static void m3gMeshDoRender(Node *self,
155 const Matrix *toCamera,
158 Mesh *mesh = (Mesh *)self;
162 mesh->indexBuffers[patchIndex],
163 mesh->appearances[patchIndex],
165 mesh->totalAlphaFactor + 1,
171 * \brief Internal equivalent routine called
172 * by m3gMeshRayIntersect.
174 * \param mesh Mesh object
175 * \param vertices VertexBuffer object used in calculations
176 * \param mask pick scope mask
177 * \param ray pick ray
178 * \param ri RayIntersection object
179 * \param toGroup transform to originating group
180 * \retval M3G_TRUE continue pick
181 * \retval M3G_FALSE abort pick
183 static M3Gbool m3gMeshRayIntersectInternal( Mesh *mesh,
184 VertexBuffer *vertices,
190 Vec3 v0, v1, v2, tuv;
191 Vec4 transformed, p0, p1;
192 M3Gint indices[4] = { 0, 0, 0, 0 };
193 M3Gint i, j, k, cullMode;
194 Matrix t; /* Reused as texture transform */
196 if (vertices == NULL ||
197 mesh->appearances == NULL ||
198 mesh->indexBuffers == NULL ||
199 (((Node *)mesh)->scope & mask) == 0) {
203 if (vertices->vertices == NULL) {
204 m3gRaiseError(M3G_INTERFACE(mesh), M3G_INVALID_OPERATION);
218 m3gCopyMatrix(&t, toGroup);
219 M3G_BEGIN_PROFILE(M3G_INTERFACE(mesh), M3G_PROFILE_TRANSFORM_INVERT);
220 if (!m3gInvertMatrix(&t)) {
221 m3gRaiseError(M3G_INTERFACE(mesh), M3G_ARITHMETIC_ERROR);
224 M3G_END_PROFILE(M3G_INTERFACE(mesh), M3G_PROFILE_TRANSFORM_INVERT);
225 m3gTransformVec4(&t, &p0);
226 m3gTransformVec4(&t, &p1);
228 m3gScaleVec3((Vec3*) &p0, m3gRcp(p0.w));
229 m3gScaleVec3((Vec3*) &p1, m3gRcp(p1.w));
231 m3gSubVec4(&p1, &p0);
233 /* Quick bounding box test for Meshes */
234 if (m3gGetClass((Object *)mesh) == M3G_CLASS_MESH) {
236 m3gGetBoundingBox(vertices, &boundingBox);
238 if (!m3gIntersectBox((Vec3*) &p0, (Vec3*) &p1, &boundingBox)) {
243 /* Apply the inverse of the vertex scale and bias to the ray */
245 if (!IS_ZERO(vertices->vertexScale)) {
246 const Vec3 *bias = (const Vec3*) vertices->vertexBias;
247 M3Gfloat ooScale = m3gRcp(vertices->vertexScale);
248 m3gSubVec3((Vec3*) &p0, bias);
249 m3gScaleVec3((Vec3*) &p0, ooScale);
250 m3gScaleVec3((Vec3*) &p1, ooScale); /* direction vector -> no bias */
253 m3gRaiseError(M3G_INTERFACE(mesh), M3G_ARITHMETIC_ERROR);
257 /* Go through all submeshes */
258 for (i = 0; i < mesh->trianglePatchCount; i++) {
259 /* Do not pick submeshes with null appearance */
260 if (mesh->appearances[i] == NULL ||
261 mesh->indexBuffers[i] == NULL) continue;
263 /* Validate indices versus vertex buffer */
264 if (m3gGetMaxIndex(mesh->indexBuffers[i]) >= m3gGetNumVertices(vertices)) {
265 m3gRaiseError(M3G_INTERFACE(mesh), M3G_INVALID_OPERATION);
269 if (mesh->appearances[i]->polygonMode != NULL) {
270 cullMode = m3gGetWinding(mesh->appearances[i]->polygonMode) == M3G_WINDING_CCW ? 0 : 1;
271 switch(m3gGetCulling(mesh->appearances[i]->polygonMode)) {
272 case M3G_CULL_FRONT: cullMode ^= 1; break;
273 case M3G_CULL_NONE: cullMode = 2; break;
280 /* Go through all triangels */
281 for (j = 0; m3gGetIndices(mesh->indexBuffers[i], j, indices); j++) {
282 /* Ignore zero area triangles */
283 if ( indices[0] == indices[1] ||
284 indices[0] == indices[2] ||
285 indices[1] == indices[2]) continue;
287 m3gGetVertex(vertices, indices[0], &v0);
288 m3gGetVertex(vertices, indices[1], &v1);
289 m3gGetVertex(vertices, indices[2], &v2);
291 if (m3gIntersectTriangle((Vec3*)&p0, (Vec3*)&p1, &v0, &v1, &v2, &tuv, indices[3] ^ cullMode)) {
292 /* Check that we are going to fill this intersection */
293 if (tuv.x <= 0.f || tuv.x >= ri->tMin) continue;
295 /* Fill in to RayIntersection */
297 ri->distance = tuv.x;
298 ri->submeshIndex = i;
299 ri->intersected = (Node *)mesh;
302 if (m3gGetNormal(vertices, indices[0], &v0)) {
303 m3gGetNormal(vertices, indices[1], &v1);
304 m3gGetNormal(vertices, indices[2], &v2);
306 ri->normal[0] = m3gAdd(
307 m3gMul(v0.x, m3gSub(1.f, m3gAdd(tuv.y, tuv.z))),
310 m3gMul(v2.x, tuv.z)));
312 ri->normal[1] = m3gAdd(
313 m3gMul(v0.y, m3gSub(1.f, m3gAdd(tuv.y, tuv.z))),
316 m3gMul(v2.y, tuv.z)));
318 ri->normal[2] = m3gAdd(
319 m3gMul(v0.z, m3gSub(1.f, m3gAdd(tuv.y, tuv.z))),
322 m3gMul(v2.z, tuv.z)));
330 /* Fetch texture coordinates for each unit */
331 for (k = 0; k < M3G_NUM_TEXTURE_UNITS; k++) {
332 if (m3gGetTexCoord(vertices, indices[0], k, &v0)) {
333 m3gGetTexCoord(vertices, indices[1], k, &v1);
334 m3gGetTexCoord(vertices, indices[2], k, &v2);
336 /* Calculate transformed S and T */
337 transformed.x = m3gAdd(
338 m3gMul(v0.x, m3gSub(1.f, m3gAdd(tuv.y, tuv.z))),
341 m3gMul(v2.x, tuv.z)));
343 transformed.y = m3gAdd(
344 m3gMul(v0.y, m3gSub(1.f, m3gAdd(tuv.y, tuv.z))),
347 m3gMul(v2.y, tuv.z)));
352 /* Transform and * 1/w */
353 if (mesh->appearances[i]->texture[k] != NULL) {
354 m3gGetCompositeTransform((Transformable *)mesh->appearances[i]->texture[k], &t);
355 m3gTransformVec4(&t, &transformed);
356 m3gScaleVec4(&transformed, m3gRcp(transformed.w));
359 ri->textureS[k] = transformed.x;
360 ri->textureT[k] = transformed.y;
363 ri->textureS[k] = 0.f;
364 ri->textureT[k] = 0.f;
376 * \brief Overloaded Node method.
378 * Just forward call internal ray intersect.
380 * \param self Mesh object
381 * \param mask pick scope mask
382 * \param ray pick ray
383 * \param ri RayIntersection object
384 * \param toGroup transform to originating group
385 * \retval M3G_TRUE continue pick
386 * \retval M3G_FALSE abort pick
388 static M3Gbool m3gMeshRayIntersect( Node *self,
394 Mesh *mesh = (Mesh *)self;
395 return m3gMeshRayIntersectInternal(mesh, mesh->vertexBuffer, mask, ray, ri, toGroup);
400 * \brief Initializes a Mesh object. See specification
401 * for default values.
403 * \param m3g M3G interface
404 * \param mesh Mesh object
405 * \param hVertices VertexBuffer object
406 * \param hTriangles array of IndexBuffer objects
407 * \param hAppearances array of Appearance objects
408 * \param trianglePatchCount number of submeshes
409 * \param vfTable virtual function table
410 * \retval M3G_TRUE success
411 * \retval M3G_FALSE failed
413 static M3Gbool m3gInitMesh(Interface *m3g,
415 M3GVertexBuffer hVertices,
416 M3GIndexBuffer *hTriangles,
417 M3GAppearance *hAppearances,
418 M3Gint trianglePatchCount,
423 /* Out of memory if more than 65535 triangle patches */
424 if (trianglePatchCount > 65535) {
425 m3gRaiseError(m3g, M3G_OUT_OF_MEMORY);
429 for (i = 0; i < trianglePatchCount; i++) {
430 if (hTriangles[i] == NULL) {
431 m3gRaiseError(m3g, M3G_NULL_POINTER);
437 m3gAllocZ(m3g, sizeof(IndexBuffer *) * trianglePatchCount);
438 if (!mesh->indexBuffers) {
443 m3gAllocZ(m3g, sizeof(Appearance *) * trianglePatchCount);
444 if (!mesh->appearances) {
445 m3gFree(m3g, mesh->indexBuffers);
449 /* Mesh is derived from node */
450 m3gInitNode(m3g, &mesh->node, classID);
451 mesh->node.hasRenderables = M3G_TRUE;
452 mesh->node.dirtyBits |= NODE_BBOX_BIT;
454 for (i = 0; i < trianglePatchCount; i++) {
455 M3G_ASSIGN_REF(mesh->indexBuffers[i], hTriangles[i]);
458 if (hAppearances != NULL) {
459 for (i = 0; i < trianglePatchCount; i++) {
460 M3G_ASSIGN_REF(mesh->appearances[i], hAppearances[i]);
464 m3gZero(mesh->appearances, sizeof(Appearance *) * trianglePatchCount);
467 M3G_ASSIGN_REF(mesh->vertexBuffer, hVertices);
468 mesh->trianglePatchCount = (M3Gshort) trianglePatchCount;
470 m3gIncStat(M3G_INTERFACE(mesh), M3G_STAT_RENDERABLES, 1);
477 * \brief Overloaded Object3D method.
479 * \param self Mesh object
480 * \param references array of reference objects
481 * \return number of references
483 static M3Gint m3gMeshDoGetReferences(Object *self, Object **references)
485 Mesh *mesh = (Mesh *)self;
486 M3Gint i, num = m3gObjectDoGetReferences(self, references);
487 if (references != NULL)
488 references[num] = (Object *)mesh->vertexBuffer;
490 for (i = 0; i < mesh->trianglePatchCount; i++) {
491 if (mesh->indexBuffers[i] != NULL) {
492 if (references != NULL)
493 references[num] = (Object *)mesh->indexBuffers[i];
496 if (mesh->appearances[i] != NULL) {
497 if (references != NULL)
498 references[num] = (Object *)mesh->appearances[i];
507 * \brief Overloaded Object3D method.
509 static Object *m3gMeshFindID(Object *self, M3Gint userID)
512 Mesh *mesh = (Mesh *)self;
513 Object *found = m3gObjectFindID(self, userID);
516 found = m3gFindID((Object*) mesh->vertexBuffer, userID);
518 for (i = 0; !found && i < mesh->trianglePatchCount; ++i) {
519 if (mesh->indexBuffers[i] != NULL) {
520 found = m3gFindID((Object*) mesh->indexBuffers[i], userID);
522 if (!found && mesh->appearances[i] != NULL) {
523 found = m3gFindID((Object*) mesh->appearances[i], userID);
531 * \brief Overloaded Object3D method.
533 * \param originalObj original Mesh object
534 * \param cloneObj pointer to cloned Mesh object
535 * \param pairs array for all object-duplicate pairs
536 * \param numPairs number of pairs
538 static M3Gbool m3gMeshDuplicate(const Object *originalObj,
543 /* Create the clone if it doesn't exist; otherwise we'll be all
544 * set by the derived class(es) and can just call through to the
547 if (*cloneObj == NULL) {
548 Mesh *original = (Mesh *)originalObj;
549 Mesh *clone = (Mesh *)m3gCreateMesh(originalObj->interface,
550 original->vertexBuffer,
551 original->indexBuffers,
552 original->appearances,
553 original->trianglePatchCount);
554 *cloneObj = (Object *)clone;
555 if (*cloneObj == NULL) {
560 return m3gNodeDuplicate(originalObj, cloneObj, pairs, numPairs);
565 * \brief Overloaded Object3D method.
567 * \param self Mesh object
568 * \param time current world time
569 * \return minimum validity
571 static M3Gint m3gMeshApplyAnimation(Object *self, M3Gint time)
573 M3Gint validity, minValidity;
574 Mesh *mesh = (Mesh *)self;
576 M3G_VALIDATE_OBJECT(mesh);
578 minValidity = m3gObjectApplyAnimation(self, time);
580 vb = (Object *) mesh->vertexBuffer;
582 if (vb != NULL && minValidity > 0) {
583 validity = M3G_VFUNC(Object, vb, applyAnimation)(vb, time);
584 minValidity = M3G_MIN(validity, minValidity);
587 if (mesh->appearances != NULL) {
590 n = mesh->trianglePatchCount;
592 for (i = 0; i < n && minValidity > 0; ++i) {
593 app = (Object *) mesh->appearances[i];
595 validity = M3G_VFUNC(Object, app, applyAnimation)(app, time);
596 minValidity = M3G_MIN(validity, minValidity);
606 * \brief Overloaded Node method
608 static M3Gint m3gMeshGetBBox(Node *self, AABB *bbox)
610 Mesh *mesh = (Mesh *) self;
611 VertexBuffer *vb = mesh->vertexBuffer;
614 m3gGetBoundingBox(vb, bbox);
615 return VFC_BBOX_COST + VFC_NODE_OVERHEAD;
624 * \brief Overloaded Node method
626 static M3Gbool m3gMeshValidate(Node *self, M3Gbitmask stateBits, M3Gint scope)
628 Mesh *mesh = (Mesh *) self;
629 VertexBuffer *vb = mesh->vertexBuffer;
632 if ((scope & self->scope) != 0) {
633 if (stateBits & self->enableBits) {
635 /* Validate vertex buffer components */
637 for (i = 0; i < mesh->trianglePatchCount; ++i) {
638 Appearance *app = mesh->appearances[i];
640 if (!m3gValidateVertexBuffer(
641 vb, app, m3gGetMaxIndex(mesh->indexBuffers[i]))) {
642 m3gRaiseError(M3G_INTERFACE(mesh), M3G_INVALID_OPERATION);
648 /* Invalidate cached vertex stuff if source buffer changed */
650 M3Gint vbTimestamp = m3gGetTimestamp(vb);
651 if (mesh->vbTimestamp != vbTimestamp) {
652 m3gInvalidateNode(self, NODE_BBOX_BIT);
653 mesh->vbTimestamp = vbTimestamp;
657 return m3gNodeValidate(self, stateBits, scope);
666 * \brief Computes the estimated rendering cost for this Mesh node
668 static M3Gint m3gMeshRenderingCost(const Mesh *mesh)
670 /* Since we're using strips, just assume that each vertex
671 * generates a new triangle... */
674 mesh->vertexBuffer->vertexCount * (VFC_VERTEX_COST +
676 mesh->trianglePatchCount * VFC_RENDERCALL_OVERHEAD +
681 /*----------------------------------------------------------------------
682 * Virtual function table
683 *--------------------------------------------------------------------*/
685 static const NodeVFTable m3gvf_Mesh = {
688 m3gMeshApplyAnimation,
690 m3gNodeUpdateProperty,
691 m3gMeshDoGetReferences,
702 m3gNodeUpdateDuplicateReferences,
707 /*----------------------------------------------------------------------
708 * Public API functions
709 *--------------------------------------------------------------------*/
712 * \brief Creates a Mesh object.
714 * \param interface M3G interface
715 * \param hVertices VertexBuffer object
716 * \param hTriangles array of IndexBuffer objects
717 * \param hAppearances array of Appearance objects
718 * \param trianglePatchCount number of submeshes
719 * \retval Mesh new Mesh object
720 * \retval NULL Mesh creating failed
722 M3G_API M3GMesh m3gCreateMesh(M3GInterface interface,
723 M3GVertexBuffer hVertices,
724 M3GIndexBuffer *hTriangles,
725 M3GAppearance *hAppearances,
726 M3Gint trianglePatchCount)
728 Interface *m3g = (Interface *) interface;
729 M3G_VALIDATE_INTERFACE(m3g);
732 Mesh *mesh = m3gAllocZ(m3g, sizeof(Mesh));
735 if (!m3gInitMesh(m3g, mesh,
736 hVertices, hTriangles, hAppearances,
744 return (M3GMesh)mesh;
749 * \brief Sets submesh appearance.
751 * \param handle Mesh object
752 * \param appearanceIndex submesh index
753 * \param hAppearance Appearance object
755 M3G_API void m3gSetAppearance(M3GMesh handle,
756 M3Gint appearanceIndex,
757 M3GAppearance hAppearance)
759 Mesh *mesh = (Mesh *)handle;
760 M3G_VALIDATE_OBJECT(mesh);
762 if (appearanceIndex < 0 || appearanceIndex >= mesh->trianglePatchCount) {
763 m3gRaiseError(M3G_INTERFACE(mesh), M3G_INVALID_INDEX);
767 M3G_ASSIGN_REF(mesh->appearances[appearanceIndex], (Appearance *) hAppearance);
771 * \brief Gets submesh appearance.
773 * \param handle Mesh object
774 * \param idx submesh index
775 * \return Appearance object
777 M3G_API M3GAppearance m3gGetAppearance(M3GMesh handle,
780 Mesh *mesh = (Mesh *)handle;
781 M3G_VALIDATE_OBJECT(mesh);
783 if (idx < 0 || idx >= mesh->trianglePatchCount) {
784 m3gRaiseError(M3G_INTERFACE(mesh), M3G_INVALID_INDEX);
788 return mesh->appearances[idx];
792 * \brief Gets submesh index buffer.
794 * \param handle Mesh object
795 * \param idx submesh index
796 * \return IndexBuffer object
798 M3G_API M3GIndexBuffer m3gGetIndexBuffer(M3GMesh handle,
801 Mesh *mesh = (Mesh *)handle;
802 M3G_VALIDATE_OBJECT(mesh);
804 if (idx < 0 || idx >= mesh->trianglePatchCount) {
805 m3gRaiseError(M3G_INTERFACE(mesh), M3G_INVALID_INDEX);
809 return mesh->indexBuffers[idx];
813 * \brief Gets VertexBuffer.
815 * \param handle Mesh object
816 * \return VertexBuffer object
818 M3G_API M3GVertexBuffer m3gGetVertexBuffer(M3GMesh handle)
820 Mesh *mesh = (Mesh *)handle;
821 M3G_VALIDATE_OBJECT(mesh);
823 return mesh->vertexBuffer;
827 * \brief Gets submesh count.
829 * \param handle Mesh object
830 * \return submesh count
832 M3G_API M3Gint m3gGetSubmeshCount(M3GMesh handle)
834 Mesh *mesh = (Mesh *)handle;
835 M3G_VALIDATE_OBJECT(mesh);
837 return mesh->trianglePatchCount;