1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/graphics/m3g/m3gcore11/src/m3g_mesh.c Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,839 @@
1.4 +/*
1.5 +* Copyright (c) 2003 Nokia Corporation and/or its subsidiary(-ies).
1.6 +* All rights reserved.
1.7 +* This component and the accompanying materials are made available
1.8 +* under the terms of the License "Eclipse Public License v1.0"
1.9 +* which accompanies this distribution, and is available
1.10 +* at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.11 +*
1.12 +* Initial Contributors:
1.13 +* Nokia Corporation - initial contribution.
1.14 +*
1.15 +* Contributors:
1.16 +*
1.17 +* Description: Mesh implementation
1.18 +*
1.19 +*/
1.20 +
1.21 +
1.22 +/*!
1.23 + * \internal
1.24 + * \file
1.25 + * \brief Mesh implementation
1.26 + */
1.27 +
1.28 +#ifndef M3G_CORE_INCLUDE
1.29 +# error included by m3g_core.c; do not compile separately.
1.30 +#endif
1.31 +
1.32 +#include "m3g_mesh.h"
1.33 +#include "m3g_memory.h"
1.34 +
1.35 +/*----------------------------------------------------------------------
1.36 + * Internal functions
1.37 + *--------------------------------------------------------------------*/
1.38 +
1.39 +/*!
1.40 + * \internal
1.41 + * \brief Destroys this Mesh object.
1.42 + *
1.43 + * \param obj Mesh object
1.44 + */
1.45 +static void m3gDestroyMesh(Object *obj)
1.46 +{
1.47 + M3Gint i;
1.48 + Mesh *mesh = (Mesh *) obj;
1.49 + M3G_VALIDATE_OBJECT(mesh);
1.50 +
1.51 + for (i = 0; i < mesh->trianglePatchCount; ++i) {
1.52 + M3G_ASSIGN_REF(mesh->indexBuffers[i], NULL);
1.53 + M3G_ASSIGN_REF(mesh->appearances[i], NULL);
1.54 + }
1.55 + M3G_ASSIGN_REF(mesh->vertexBuffer, NULL);
1.56 +
1.57 + {
1.58 + Interface *m3g = M3G_INTERFACE(mesh);
1.59 + m3gFree(m3g, mesh->indexBuffers);
1.60 + m3gFree(m3g, mesh->appearances);
1.61 + }
1.62 +
1.63 + m3gIncStat(M3G_INTERFACE(obj), M3G_STAT_RENDERABLES, -1);
1.64 +
1.65 + m3gDestroyNode(obj);
1.66 +}
1.67 +
1.68 +/*!
1.69 + * \internal
1.70 + * \brief Insert a mesh into a rendering queue
1.71 + */
1.72 +static M3Gbool m3gQueueMesh(Mesh *mesh, const Matrix *toCamera,
1.73 + RenderQueue *renderQueue)
1.74 +{
1.75 + M3Gint i;
1.76 +
1.77 + /* Fetch the cumulative alpha factor for this node */
1.78 +
1.79 + mesh->totalAlphaFactor =
1.80 + (M3Gushort) m3gGetTotalAlphaFactor((Node*) mesh, renderQueue->root);
1.81 +
1.82 + /* Insert each submesh into the rendering queue */
1.83 +
1.84 + for (i = 0; i < mesh->trianglePatchCount; i++) {
1.85 + if (mesh->appearances[i] != NULL) {
1.86 + if (!m3gInsertDrawable(M3G_INTERFACE(mesh),
1.87 + renderQueue,
1.88 + (Node*) mesh,
1.89 + toCamera,
1.90 + i,
1.91 + m3gGetAppearanceSortKey(mesh->appearances[i])))
1.92 + return M3G_FALSE;
1.93 + }
1.94 + }
1.95 + return M3G_TRUE;
1.96 +}
1.97 +
1.98 +/*!
1.99 + * \internal
1.100 + * \brief Overloaded Node method.
1.101 + *
1.102 + * Setup mesh rendering by adding all submeshes to
1.103 + * the render queue.
1.104 + *
1.105 + * \param self Mesh object
1.106 + * \param toCamera transform to camera
1.107 + * \param alphaFactor total alpha factor
1.108 + * \param caller caller node
1.109 + * \param renderQueue RenderQueue
1.110 + *
1.111 + * \retval M3G_TRUE continue render setup
1.112 + * \retval M3G_FALSE abort render setup
1.113 + */
1.114 +static M3Gbool m3gMeshSetupRender(Node *self,
1.115 + const Node *caller,
1.116 + SetupRenderState *s,
1.117 + RenderQueue *renderQueue)
1.118 +{
1.119 + Mesh *mesh = (Mesh *)self;
1.120 + M3G_UNREF(caller);
1.121 + m3gIncStat(M3G_INTERFACE(self), M3G_STAT_RENDER_NODES, 1);
1.122 +
1.123 + if ((self->enableBits & NODE_RENDER_BIT) != 0 &&
1.124 + (self->scope & renderQueue->scope) != 0) {
1.125 +
1.126 + /* Check view frustum culling */
1.127 +
1.128 +# if defined(M3G_ENABLE_VF_CULLING)
1.129 + AABB bbox;
1.130 + m3gGetBoundingBox(mesh->vertexBuffer, &bbox);
1.131 + m3gUpdateCullingMask(s, renderQueue->camera, &bbox);
1.132 + if (s->cullMask == 0) {
1.133 + m3gIncStat(M3G_INTERFACE(self),
1.134 + M3G_STAT_RENDER_NODES_CULLED, 1);
1.135 + return M3G_TRUE;
1.136 + }
1.137 +# endif
1.138 +
1.139 + /* No dice, let's render... */
1.140 +
1.141 + return m3gQueueMesh(mesh, &s->toCamera, renderQueue);
1.142 + }
1.143 + return M3G_TRUE;
1.144 +}
1.145 +
1.146 +/*!
1.147 + * \internal
1.148 + * \brief Overloaded Node method.
1.149 + *
1.150 + * Renders one submesh.
1.151 + *
1.152 + * \param self Mesh object
1.153 + * \param ctx current render context
1.154 + * \param patchIndex submesh index
1.155 + */
1.156 +static void m3gMeshDoRender(Node *self,
1.157 + RenderContext *ctx,
1.158 + const Matrix *toCamera,
1.159 + M3Gint patchIndex)
1.160 +{
1.161 + Mesh *mesh = (Mesh *)self;
1.162 +
1.163 + m3gDrawMesh(ctx,
1.164 + mesh->vertexBuffer,
1.165 + mesh->indexBuffers[patchIndex],
1.166 + mesh->appearances[patchIndex],
1.167 + toCamera,
1.168 + mesh->totalAlphaFactor + 1,
1.169 + self->scope);
1.170 +}
1.171 +
1.172 +/*!
1.173 + * \internal
1.174 + * \brief Internal equivalent routine called
1.175 + * by m3gMeshRayIntersect.
1.176 + *
1.177 + * \param mesh Mesh object
1.178 + * \param vertices VertexBuffer object used in calculations
1.179 + * \param mask pick scope mask
1.180 + * \param ray pick ray
1.181 + * \param ri RayIntersection object
1.182 + * \param toGroup transform to originating group
1.183 + * \retval M3G_TRUE continue pick
1.184 + * \retval M3G_FALSE abort pick
1.185 + */
1.186 +static M3Gbool m3gMeshRayIntersectInternal( Mesh *mesh,
1.187 + VertexBuffer *vertices,
1.188 + M3Gint mask,
1.189 + M3Gfloat *ray,
1.190 + RayIntersection *ri,
1.191 + Matrix *toGroup)
1.192 +{
1.193 + Vec3 v0, v1, v2, tuv;
1.194 + Vec4 transformed, p0, p1;
1.195 + M3Gint indices[4] = { 0, 0, 0, 0 };
1.196 + M3Gint i, j, k, cullMode;
1.197 + Matrix t; /* Reused as texture transform */
1.198 +
1.199 + if (vertices == NULL ||
1.200 + mesh->appearances == NULL ||
1.201 + mesh->indexBuffers == NULL ||
1.202 + (((Node *)mesh)->scope & mask) == 0) {
1.203 + return M3G_TRUE;
1.204 + }
1.205 +
1.206 + if (vertices->vertices == NULL) {
1.207 + m3gRaiseError(M3G_INTERFACE(mesh), M3G_INVALID_OPERATION);
1.208 + return M3G_FALSE;
1.209 + }
1.210 +
1.211 + p0.x = ray[0];
1.212 + p0.y = ray[1];
1.213 + p0.z = ray[2];
1.214 + p0.w = 1.f;
1.215 +
1.216 + p1.x = ray[3];
1.217 + p1.y = ray[4];
1.218 + p1.z = ray[5];
1.219 + p1.w = 1.f;
1.220 +
1.221 + m3gCopyMatrix(&t, toGroup);
1.222 + M3G_BEGIN_PROFILE(M3G_INTERFACE(mesh), M3G_PROFILE_TRANSFORM_INVERT);
1.223 + if (!m3gInvertMatrix(&t)) {
1.224 + m3gRaiseError(M3G_INTERFACE(mesh), M3G_ARITHMETIC_ERROR);
1.225 + return M3G_FALSE;
1.226 + }
1.227 + M3G_END_PROFILE(M3G_INTERFACE(mesh), M3G_PROFILE_TRANSFORM_INVERT);
1.228 + m3gTransformVec4(&t, &p0);
1.229 + m3gTransformVec4(&t, &p1);
1.230 +
1.231 + m3gScaleVec3((Vec3*) &p0, m3gRcp(p0.w));
1.232 + m3gScaleVec3((Vec3*) &p1, m3gRcp(p1.w));
1.233 +
1.234 + m3gSubVec4(&p1, &p0);
1.235 +
1.236 + /* Quick bounding box test for Meshes */
1.237 + if (m3gGetClass((Object *)mesh) == M3G_CLASS_MESH) {
1.238 + AABB boundingBox;
1.239 + m3gGetBoundingBox(vertices, &boundingBox);
1.240 +
1.241 + if (!m3gIntersectBox((Vec3*) &p0, (Vec3*) &p1, &boundingBox)) {
1.242 + return M3G_TRUE;
1.243 + }
1.244 + }
1.245 +
1.246 + /* Apply the inverse of the vertex scale and bias to the ray */
1.247 +
1.248 + if (!IS_ZERO(vertices->vertexScale)) {
1.249 + const Vec3 *bias = (const Vec3*) vertices->vertexBias;
1.250 + M3Gfloat ooScale = m3gRcp(vertices->vertexScale);
1.251 + m3gSubVec3((Vec3*) &p0, bias);
1.252 + m3gScaleVec3((Vec3*) &p0, ooScale);
1.253 + m3gScaleVec3((Vec3*) &p1, ooScale); /* direction vector -> no bias */
1.254 + }
1.255 + else {
1.256 + m3gRaiseError(M3G_INTERFACE(mesh), M3G_ARITHMETIC_ERROR);
1.257 + return M3G_FALSE;
1.258 + }
1.259 +
1.260 + /* Go through all submeshes */
1.261 + for (i = 0; i < mesh->trianglePatchCount; i++) {
1.262 + /* Do not pick submeshes with null appearance */
1.263 + if (mesh->appearances[i] == NULL ||
1.264 + mesh->indexBuffers[i] == NULL) continue;
1.265 +
1.266 + /* Validate indices versus vertex buffer */
1.267 + if (m3gGetMaxIndex(mesh->indexBuffers[i]) >= m3gGetNumVertices(vertices)) {
1.268 + m3gRaiseError(M3G_INTERFACE(mesh), M3G_INVALID_OPERATION);
1.269 + return M3G_FALSE;
1.270 + }
1.271 +
1.272 + if (mesh->appearances[i]->polygonMode != NULL) {
1.273 + cullMode = m3gGetWinding(mesh->appearances[i]->polygonMode) == M3G_WINDING_CCW ? 0 : 1;
1.274 + switch(m3gGetCulling(mesh->appearances[i]->polygonMode)) {
1.275 + case M3G_CULL_FRONT: cullMode ^= 1; break;
1.276 + case M3G_CULL_NONE: cullMode = 2; break;
1.277 + }
1.278 + }
1.279 + else {
1.280 + cullMode = 0;
1.281 + }
1.282 +
1.283 + /* Go through all triangels */
1.284 + for (j = 0; m3gGetIndices(mesh->indexBuffers[i], j, indices); j++) {
1.285 + /* Ignore zero area triangles */
1.286 + if ( indices[0] == indices[1] ||
1.287 + indices[0] == indices[2] ||
1.288 + indices[1] == indices[2]) continue;
1.289 +
1.290 + m3gGetVertex(vertices, indices[0], &v0);
1.291 + m3gGetVertex(vertices, indices[1], &v1);
1.292 + m3gGetVertex(vertices, indices[2], &v2);
1.293 +
1.294 + if (m3gIntersectTriangle((Vec3*)&p0, (Vec3*)&p1, &v0, &v1, &v2, &tuv, indices[3] ^ cullMode)) {
1.295 + /* Check that we are going to fill this intersection */
1.296 + if (tuv.x <= 0.f || tuv.x >= ri->tMin) continue;
1.297 +
1.298 + /* Fill in to RayIntersection */
1.299 + ri->tMin = tuv.x;
1.300 + ri->distance = tuv.x;
1.301 + ri->submeshIndex = i;
1.302 + ri->intersected = (Node *)mesh;
1.303 +
1.304 + /* Fetch normal */
1.305 + if (m3gGetNormal(vertices, indices[0], &v0)) {
1.306 + m3gGetNormal(vertices, indices[1], &v1);
1.307 + m3gGetNormal(vertices, indices[2], &v2);
1.308 +
1.309 + ri->normal[0] = m3gAdd(
1.310 + m3gMul(v0.x, m3gSub(1.f, m3gAdd(tuv.y, tuv.z))),
1.311 + m3gAdd(
1.312 + m3gMul(v1.x, tuv.y),
1.313 + m3gMul(v2.x, tuv.z)));
1.314 +
1.315 + ri->normal[1] = m3gAdd(
1.316 + m3gMul(v0.y, m3gSub(1.f, m3gAdd(tuv.y, tuv.z))),
1.317 + m3gAdd(
1.318 + m3gMul(v1.y, tuv.y),
1.319 + m3gMul(v2.y, tuv.z)));
1.320 +
1.321 + ri->normal[2] = m3gAdd(
1.322 + m3gMul(v0.z, m3gSub(1.f, m3gAdd(tuv.y, tuv.z))),
1.323 + m3gAdd(
1.324 + m3gMul(v1.z, tuv.y),
1.325 + m3gMul(v2.z, tuv.z)));
1.326 + }
1.327 + else {
1.328 + ri->normal[0] = 0.f;
1.329 + ri->normal[1] = 0.f;
1.330 + ri->normal[2] = 1.f;
1.331 + }
1.332 +
1.333 + /* Fetch texture coordinates for each unit */
1.334 + for (k = 0; k < M3G_NUM_TEXTURE_UNITS; k++) {
1.335 + if (m3gGetTexCoord(vertices, indices[0], k, &v0)) {
1.336 + m3gGetTexCoord(vertices, indices[1], k, &v1);
1.337 + m3gGetTexCoord(vertices, indices[2], k, &v2);
1.338 +
1.339 + /* Calculate transformed S and T */
1.340 + transformed.x = m3gAdd(
1.341 + m3gMul(v0.x, m3gSub(1.f, m3gAdd(tuv.y, tuv.z))),
1.342 + m3gAdd(
1.343 + m3gMul(v1.x, tuv.y),
1.344 + m3gMul(v2.x, tuv.z)));
1.345 +
1.346 + transformed.y = m3gAdd(
1.347 + m3gMul(v0.y, m3gSub(1.f, m3gAdd(tuv.y, tuv.z))),
1.348 + m3gAdd(
1.349 + m3gMul(v1.y, tuv.y),
1.350 + m3gMul(v2.y, tuv.z)));
1.351 +
1.352 + transformed.z = 0;
1.353 + transformed.w = 1;
1.354 +
1.355 + /* Transform and * 1/w */
1.356 + if (mesh->appearances[i]->texture[k] != NULL) {
1.357 + m3gGetCompositeTransform((Transformable *)mesh->appearances[i]->texture[k], &t);
1.358 + m3gTransformVec4(&t, &transformed);
1.359 + m3gScaleVec4(&transformed, m3gRcp(transformed.w));
1.360 + }
1.361 +
1.362 + ri->textureS[k] = transformed.x;
1.363 + ri->textureT[k] = transformed.y;
1.364 + }
1.365 + else {
1.366 + ri->textureS[k] = 0.f;
1.367 + ri->textureT[k] = 0.f;
1.368 + }
1.369 + }
1.370 + }
1.371 + }
1.372 + }
1.373 +
1.374 + return M3G_TRUE;
1.375 +}
1.376 +
1.377 +/*!
1.378 + * \internal
1.379 + * \brief Overloaded Node method.
1.380 + *
1.381 + * Just forward call internal ray intersect.
1.382 + *
1.383 + * \param self Mesh object
1.384 + * \param mask pick scope mask
1.385 + * \param ray pick ray
1.386 + * \param ri RayIntersection object
1.387 + * \param toGroup transform to originating group
1.388 + * \retval M3G_TRUE continue pick
1.389 + * \retval M3G_FALSE abort pick
1.390 + */
1.391 +static M3Gbool m3gMeshRayIntersect( Node *self,
1.392 + M3Gint mask,
1.393 + M3Gfloat *ray,
1.394 + RayIntersection *ri,
1.395 + Matrix *toGroup)
1.396 +{
1.397 + Mesh *mesh = (Mesh *)self;
1.398 + return m3gMeshRayIntersectInternal(mesh, mesh->vertexBuffer, mask, ray, ri, toGroup);
1.399 +}
1.400 +
1.401 +/*!
1.402 + * \internal
1.403 + * \brief Initializes a Mesh object. See specification
1.404 + * for default values.
1.405 + *
1.406 + * \param m3g M3G interface
1.407 + * \param mesh Mesh object
1.408 + * \param hVertices VertexBuffer object
1.409 + * \param hTriangles array of IndexBuffer objects
1.410 + * \param hAppearances array of Appearance objects
1.411 + * \param trianglePatchCount number of submeshes
1.412 + * \param vfTable virtual function table
1.413 + * \retval M3G_TRUE success
1.414 + * \retval M3G_FALSE failed
1.415 + */
1.416 +static M3Gbool m3gInitMesh(Interface *m3g,
1.417 + Mesh *mesh,
1.418 + M3GVertexBuffer hVertices,
1.419 + M3GIndexBuffer *hTriangles,
1.420 + M3GAppearance *hAppearances,
1.421 + M3Gint trianglePatchCount,
1.422 + M3GClass classID)
1.423 +{
1.424 + M3Gint i;
1.425 +
1.426 + /* Out of memory if more than 65535 triangle patches */
1.427 + if (trianglePatchCount > 65535) {
1.428 + m3gRaiseError(m3g, M3G_OUT_OF_MEMORY);
1.429 + return M3G_FALSE;
1.430 + }
1.431 +
1.432 + for (i = 0; i < trianglePatchCount; i++) {
1.433 + if (hTriangles[i] == NULL) {
1.434 + m3gRaiseError(m3g, M3G_NULL_POINTER);
1.435 + return M3G_FALSE;
1.436 + }
1.437 + }
1.438 +
1.439 + mesh->indexBuffers =
1.440 + m3gAllocZ(m3g, sizeof(IndexBuffer *) * trianglePatchCount);
1.441 + if (!mesh->indexBuffers) {
1.442 + return M3G_FALSE;
1.443 + }
1.444 +
1.445 + mesh->appearances =
1.446 + m3gAllocZ(m3g, sizeof(Appearance *) * trianglePatchCount);
1.447 + if (!mesh->appearances) {
1.448 + m3gFree(m3g, mesh->indexBuffers);
1.449 + return M3G_FALSE;
1.450 + }
1.451 +
1.452 + /* Mesh is derived from node */
1.453 + m3gInitNode(m3g, &mesh->node, classID);
1.454 + mesh->node.hasRenderables = M3G_TRUE;
1.455 + mesh->node.dirtyBits |= NODE_BBOX_BIT;
1.456 +
1.457 + for (i = 0; i < trianglePatchCount; i++) {
1.458 + M3G_ASSIGN_REF(mesh->indexBuffers[i], hTriangles[i]);
1.459 + }
1.460 +
1.461 + if (hAppearances != NULL) {
1.462 + for (i = 0; i < trianglePatchCount; i++) {
1.463 + M3G_ASSIGN_REF(mesh->appearances[i], hAppearances[i]);
1.464 + }
1.465 + }
1.466 + else {
1.467 + m3gZero(mesh->appearances, sizeof(Appearance *) * trianglePatchCount);
1.468 + }
1.469 +
1.470 + M3G_ASSIGN_REF(mesh->vertexBuffer, hVertices);
1.471 + mesh->trianglePatchCount = (M3Gshort) trianglePatchCount;
1.472 +
1.473 + m3gIncStat(M3G_INTERFACE(mesh), M3G_STAT_RENDERABLES, 1);
1.474 +
1.475 + return M3G_TRUE;
1.476 +}
1.477 +
1.478 +/*!
1.479 + * \internal
1.480 + * \brief Overloaded Object3D method.
1.481 + *
1.482 + * \param self Mesh object
1.483 + * \param references array of reference objects
1.484 + * \return number of references
1.485 + */
1.486 +static M3Gint m3gMeshDoGetReferences(Object *self, Object **references)
1.487 +{
1.488 + Mesh *mesh = (Mesh *)self;
1.489 + M3Gint i, num = m3gObjectDoGetReferences(self, references);
1.490 + if (references != NULL)
1.491 + references[num] = (Object *)mesh->vertexBuffer;
1.492 + num++;
1.493 + for (i = 0; i < mesh->trianglePatchCount; i++) {
1.494 + if (mesh->indexBuffers[i] != NULL) {
1.495 + if (references != NULL)
1.496 + references[num] = (Object *)mesh->indexBuffers[i];
1.497 + num++;
1.498 + }
1.499 + if (mesh->appearances[i] != NULL) {
1.500 + if (references != NULL)
1.501 + references[num] = (Object *)mesh->appearances[i];
1.502 + num++;
1.503 + }
1.504 + }
1.505 + return num;
1.506 +}
1.507 +
1.508 +/*!
1.509 + * \internal
1.510 + * \brief Overloaded Object3D method.
1.511 + */
1.512 +static Object *m3gMeshFindID(Object *self, M3Gint userID)
1.513 +{
1.514 + int i;
1.515 + Mesh *mesh = (Mesh *)self;
1.516 + Object *found = m3gObjectFindID(self, userID);
1.517 +
1.518 + if (!found) {
1.519 + found = m3gFindID((Object*) mesh->vertexBuffer, userID);
1.520 + }
1.521 + for (i = 0; !found && i < mesh->trianglePatchCount; ++i) {
1.522 + if (mesh->indexBuffers[i] != NULL) {
1.523 + found = m3gFindID((Object*) mesh->indexBuffers[i], userID);
1.524 + }
1.525 + if (!found && mesh->appearances[i] != NULL) {
1.526 + found = m3gFindID((Object*) mesh->appearances[i], userID);
1.527 + }
1.528 + }
1.529 + return found;
1.530 +}
1.531 +
1.532 +/*!
1.533 + * \internal
1.534 + * \brief Overloaded Object3D method.
1.535 + *
1.536 + * \param originalObj original Mesh object
1.537 + * \param cloneObj pointer to cloned Mesh object
1.538 + * \param pairs array for all object-duplicate pairs
1.539 + * \param numPairs number of pairs
1.540 + */
1.541 +static M3Gbool m3gMeshDuplicate(const Object *originalObj,
1.542 + Object **cloneObj,
1.543 + Object **pairs,
1.544 + M3Gint *numPairs)
1.545 +{
1.546 + /* Create the clone if it doesn't exist; otherwise we'll be all
1.547 + * set by the derived class(es) and can just call through to the
1.548 + * base class */
1.549 +
1.550 + if (*cloneObj == NULL) {
1.551 + Mesh *original = (Mesh *)originalObj;
1.552 + Mesh *clone = (Mesh *)m3gCreateMesh(originalObj->interface,
1.553 + original->vertexBuffer,
1.554 + original->indexBuffers,
1.555 + original->appearances,
1.556 + original->trianglePatchCount);
1.557 + *cloneObj = (Object *)clone;
1.558 + if (*cloneObj == NULL) {
1.559 + return M3G_FALSE;
1.560 + }
1.561 + }
1.562 +
1.563 + return m3gNodeDuplicate(originalObj, cloneObj, pairs, numPairs);
1.564 +}
1.565 +
1.566 +/*!
1.567 + * \internal
1.568 + * \brief Overloaded Object3D method.
1.569 + *
1.570 + * \param self Mesh object
1.571 + * \param time current world time
1.572 + * \return minimum validity
1.573 + */
1.574 +static M3Gint m3gMeshApplyAnimation(Object *self, M3Gint time)
1.575 +{
1.576 + M3Gint validity, minValidity;
1.577 + Mesh *mesh = (Mesh *)self;
1.578 + Object *vb;
1.579 + M3G_VALIDATE_OBJECT(mesh);
1.580 +
1.581 + minValidity = m3gObjectApplyAnimation(self, time);
1.582 +
1.583 + vb = (Object *) mesh->vertexBuffer;
1.584 +
1.585 + if (vb != NULL && minValidity > 0) {
1.586 + validity = M3G_VFUNC(Object, vb, applyAnimation)(vb, time);
1.587 + minValidity = M3G_MIN(validity, minValidity);
1.588 + }
1.589 +
1.590 + if (mesh->appearances != NULL) {
1.591 + Object *app;
1.592 + M3Gint i, n;
1.593 + n = mesh->trianglePatchCount;
1.594 +
1.595 + for (i = 0; i < n && minValidity > 0; ++i) {
1.596 + app = (Object *) mesh->appearances[i];
1.597 + if (app != NULL) {
1.598 + validity = M3G_VFUNC(Object, app, applyAnimation)(app, time);
1.599 + minValidity = M3G_MIN(validity, minValidity);
1.600 + }
1.601 + }
1.602 + }
1.603 +
1.604 + return minValidity;
1.605 +}
1.606 +
1.607 +/*!
1.608 + * \internal
1.609 + * \brief Overloaded Node method
1.610 + */
1.611 +static M3Gint m3gMeshGetBBox(Node *self, AABB *bbox)
1.612 +{
1.613 + Mesh *mesh = (Mesh *) self;
1.614 + VertexBuffer *vb = mesh->vertexBuffer;
1.615 +
1.616 + if (vb->vertices) {
1.617 + m3gGetBoundingBox(vb, bbox);
1.618 + return VFC_BBOX_COST + VFC_NODE_OVERHEAD;
1.619 + }
1.620 + else {
1.621 + return 0;
1.622 + }
1.623 +}
1.624 +
1.625 +/*!
1.626 + * \internal
1.627 + * \brief Overloaded Node method
1.628 + */
1.629 +static M3Gbool m3gMeshValidate(Node *self, M3Gbitmask stateBits, M3Gint scope)
1.630 +{
1.631 + Mesh *mesh = (Mesh *) self;
1.632 + VertexBuffer *vb = mesh->vertexBuffer;
1.633 + int i;
1.634 +
1.635 + if ((scope & self->scope) != 0) {
1.636 + if (stateBits & self->enableBits) {
1.637 +
1.638 + /* Validate vertex buffer components */
1.639 +
1.640 + for (i = 0; i < mesh->trianglePatchCount; ++i) {
1.641 + Appearance *app = mesh->appearances[i];
1.642 + if (app) {
1.643 + if (!m3gValidateVertexBuffer(
1.644 + vb, app, m3gGetMaxIndex(mesh->indexBuffers[i]))) {
1.645 + m3gRaiseError(M3G_INTERFACE(mesh), M3G_INVALID_OPERATION);
1.646 + return M3G_FALSE;
1.647 + }
1.648 + }
1.649 + }
1.650 +
1.651 + /* Invalidate cached vertex stuff if source buffer changed */
1.652 + {
1.653 + M3Gint vbTimestamp = m3gGetTimestamp(vb);
1.654 + if (mesh->vbTimestamp != vbTimestamp) {
1.655 + m3gInvalidateNode(self, NODE_BBOX_BIT);
1.656 + mesh->vbTimestamp = vbTimestamp;
1.657 + }
1.658 + }
1.659 +
1.660 + return m3gNodeValidate(self, stateBits, scope);
1.661 + }
1.662 + }
1.663 + return M3G_TRUE;
1.664 +}
1.665 +
1.666 +#if 0
1.667 +/*!
1.668 + * \internal
1.669 + * \brief Computes the estimated rendering cost for this Mesh node
1.670 + */
1.671 +static M3Gint m3gMeshRenderingCost(const Mesh *mesh)
1.672 +{
1.673 + /* Since we're using strips, just assume that each vertex
1.674 + * generates a new triangle... */
1.675 +
1.676 + return
1.677 + mesh->vertexBuffer->vertexCount * (VFC_VERTEX_COST +
1.678 + VFC_TRIANGLE_COST) +
1.679 + mesh->trianglePatchCount * VFC_RENDERCALL_OVERHEAD +
1.680 + VFC_NODE_OVERHEAD;
1.681 +}
1.682 +#endif
1.683 +
1.684 +/*----------------------------------------------------------------------
1.685 + * Virtual function table
1.686 + *--------------------------------------------------------------------*/
1.687 +
1.688 +static const NodeVFTable m3gvf_Mesh = {
1.689 + {
1.690 + {
1.691 + m3gMeshApplyAnimation,
1.692 + m3gNodeIsCompatible,
1.693 + m3gNodeUpdateProperty,
1.694 + m3gMeshDoGetReferences,
1.695 + m3gMeshFindID,
1.696 + m3gMeshDuplicate,
1.697 + m3gDestroyMesh
1.698 + }
1.699 + },
1.700 + m3gNodeAlign,
1.701 + m3gMeshDoRender,
1.702 + m3gMeshGetBBox,
1.703 + m3gMeshRayIntersect,
1.704 + m3gMeshSetupRender,
1.705 + m3gNodeUpdateDuplicateReferences,
1.706 + m3gMeshValidate
1.707 +};
1.708 +
1.709 +
1.710 +/*----------------------------------------------------------------------
1.711 + * Public API functions
1.712 + *--------------------------------------------------------------------*/
1.713 +
1.714 +/*!
1.715 + * \brief Creates a Mesh object.
1.716 + *
1.717 + * \param interface M3G interface
1.718 + * \param hVertices VertexBuffer object
1.719 + * \param hTriangles array of IndexBuffer objects
1.720 + * \param hAppearances array of Appearance objects
1.721 + * \param trianglePatchCount number of submeshes
1.722 + * \retval Mesh new Mesh object
1.723 + * \retval NULL Mesh creating failed
1.724 + */
1.725 +M3G_API M3GMesh m3gCreateMesh(M3GInterface interface,
1.726 + M3GVertexBuffer hVertices,
1.727 + M3GIndexBuffer *hTriangles,
1.728 + M3GAppearance *hAppearances,
1.729 + M3Gint trianglePatchCount)
1.730 +{
1.731 + Interface *m3g = (Interface *) interface;
1.732 + M3G_VALIDATE_INTERFACE(m3g);
1.733 +
1.734 + {
1.735 + Mesh *mesh = m3gAllocZ(m3g, sizeof(Mesh));
1.736 +
1.737 + if (mesh != NULL) {
1.738 + if (!m3gInitMesh(m3g, mesh,
1.739 + hVertices, hTriangles, hAppearances,
1.740 + trianglePatchCount,
1.741 + M3G_CLASS_MESH)) {
1.742 + m3gFree(m3g, mesh);
1.743 + return NULL;
1.744 + }
1.745 + }
1.746 +
1.747 + return (M3GMesh)mesh;
1.748 + }
1.749 +}
1.750 +
1.751 +/*!
1.752 + * \brief Sets submesh appearance.
1.753 + *
1.754 + * \param handle Mesh object
1.755 + * \param appearanceIndex submesh index
1.756 + * \param hAppearance Appearance object
1.757 + */
1.758 +M3G_API void m3gSetAppearance(M3GMesh handle,
1.759 + M3Gint appearanceIndex,
1.760 + M3GAppearance hAppearance)
1.761 +{
1.762 + Mesh *mesh = (Mesh *)handle;
1.763 + M3G_VALIDATE_OBJECT(mesh);
1.764 +
1.765 + if (appearanceIndex < 0 || appearanceIndex >= mesh->trianglePatchCount) {
1.766 + m3gRaiseError(M3G_INTERFACE(mesh), M3G_INVALID_INDEX);
1.767 + return;
1.768 + }
1.769 +
1.770 + M3G_ASSIGN_REF(mesh->appearances[appearanceIndex], (Appearance *) hAppearance);
1.771 +}
1.772 +
1.773 +/*!
1.774 + * \brief Gets submesh appearance.
1.775 + *
1.776 + * \param handle Mesh object
1.777 + * \param idx submesh index
1.778 + * \return Appearance object
1.779 + */
1.780 +M3G_API M3GAppearance m3gGetAppearance(M3GMesh handle,
1.781 + M3Gint idx)
1.782 +{
1.783 + Mesh *mesh = (Mesh *)handle;
1.784 + M3G_VALIDATE_OBJECT(mesh);
1.785 +
1.786 + if (idx < 0 || idx >= mesh->trianglePatchCount) {
1.787 + m3gRaiseError(M3G_INTERFACE(mesh), M3G_INVALID_INDEX);
1.788 + return NULL;
1.789 + }
1.790 +
1.791 + return mesh->appearances[idx];
1.792 +}
1.793 +
1.794 +/*!
1.795 + * \brief Gets submesh index buffer.
1.796 + *
1.797 + * \param handle Mesh object
1.798 + * \param idx submesh index
1.799 + * \return IndexBuffer object
1.800 + */
1.801 +M3G_API M3GIndexBuffer m3gGetIndexBuffer(M3GMesh handle,
1.802 + M3Gint idx)
1.803 +{
1.804 + Mesh *mesh = (Mesh *)handle;
1.805 + M3G_VALIDATE_OBJECT(mesh);
1.806 +
1.807 + if (idx < 0 || idx >= mesh->trianglePatchCount) {
1.808 + m3gRaiseError(M3G_INTERFACE(mesh), M3G_INVALID_INDEX);
1.809 + return NULL;
1.810 + }
1.811 +
1.812 + return mesh->indexBuffers[idx];
1.813 +}
1.814 +
1.815 +/*!
1.816 + * \brief Gets VertexBuffer.
1.817 + *
1.818 + * \param handle Mesh object
1.819 + * \return VertexBuffer object
1.820 + */
1.821 +M3G_API M3GVertexBuffer m3gGetVertexBuffer(M3GMesh handle)
1.822 +{
1.823 + Mesh *mesh = (Mesh *)handle;
1.824 + M3G_VALIDATE_OBJECT(mesh);
1.825 +
1.826 + return mesh->vertexBuffer;
1.827 +}
1.828 +
1.829 +/*!
1.830 + * \brief Gets submesh count.
1.831 + *
1.832 + * \param handle Mesh object
1.833 + * \return submesh count
1.834 + */
1.835 +M3G_API M3Gint m3gGetSubmeshCount(M3GMesh handle)
1.836 +{
1.837 + Mesh *mesh = (Mesh *)handle;
1.838 + M3G_VALIDATE_OBJECT(mesh);
1.839 +
1.840 + return mesh->trianglePatchCount;
1.841 +}
1.842 +