os/graphics/m3g/m3gcore11/src/m3g_mesh.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.
sl@0
     1
/*
sl@0
     2
* Copyright (c) 2003 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     3
* All rights reserved.
sl@0
     4
* This component and the accompanying materials are made available
sl@0
     5
* under the terms of the License "Eclipse Public License v1.0"
sl@0
     6
* which accompanies this distribution, and is available
sl@0
     7
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     8
*
sl@0
     9
* Initial Contributors:
sl@0
    10
* Nokia Corporation - initial contribution.
sl@0
    11
*
sl@0
    12
* Contributors:
sl@0
    13
*
sl@0
    14
* Description: Mesh implementation
sl@0
    15
*
sl@0
    16
*/
sl@0
    17
sl@0
    18
sl@0
    19
/*!
sl@0
    20
 * \internal
sl@0
    21
 * \file
sl@0
    22
 * \brief Mesh implementation
sl@0
    23
 */
sl@0
    24
sl@0
    25
#ifndef M3G_CORE_INCLUDE
sl@0
    26
#   error included by m3g_core.c; do not compile separately.
sl@0
    27
#endif
sl@0
    28
sl@0
    29
#include "m3g_mesh.h"
sl@0
    30
#include "m3g_memory.h"
sl@0
    31
sl@0
    32
/*----------------------------------------------------------------------
sl@0
    33
 * Internal functions
sl@0
    34
 *--------------------------------------------------------------------*/
sl@0
    35
sl@0
    36
/*!
sl@0
    37
 * \internal
sl@0
    38
 * \brief Destroys this Mesh object.
sl@0
    39
 *
sl@0
    40
 * \param obj Mesh object
sl@0
    41
 */
sl@0
    42
static void m3gDestroyMesh(Object *obj)
sl@0
    43
{
sl@0
    44
    M3Gint i;
sl@0
    45
    Mesh *mesh = (Mesh *) obj;
sl@0
    46
    M3G_VALIDATE_OBJECT(mesh);
sl@0
    47
sl@0
    48
    for (i = 0; i < mesh->trianglePatchCount; ++i) {
sl@0
    49
        M3G_ASSIGN_REF(mesh->indexBuffers[i], NULL);
sl@0
    50
        M3G_ASSIGN_REF(mesh->appearances[i], NULL);
sl@0
    51
    }
sl@0
    52
    M3G_ASSIGN_REF(mesh->vertexBuffer, NULL);
sl@0
    53
sl@0
    54
	{
sl@0
    55
		Interface *m3g = M3G_INTERFACE(mesh);
sl@0
    56
		m3gFree(m3g, mesh->indexBuffers);
sl@0
    57
		m3gFree(m3g, mesh->appearances);
sl@0
    58
	}
sl@0
    59
sl@0
    60
    m3gIncStat(M3G_INTERFACE(obj), M3G_STAT_RENDERABLES, -1);
sl@0
    61
    
sl@0
    62
    m3gDestroyNode(obj);
sl@0
    63
}
sl@0
    64
sl@0
    65
/*!
sl@0
    66
 * \internal
sl@0
    67
 * \brief Insert a mesh into a rendering queue
sl@0
    68
 */
sl@0
    69
static M3Gbool m3gQueueMesh(Mesh *mesh, const Matrix *toCamera,
sl@0
    70
                            RenderQueue *renderQueue)
sl@0
    71
{
sl@0
    72
    M3Gint i;
sl@0
    73
sl@0
    74
    /* Fetch the cumulative alpha factor for this node */
sl@0
    75
    
sl@0
    76
    mesh->totalAlphaFactor =
sl@0
    77
        (M3Gushort) m3gGetTotalAlphaFactor((Node*) mesh, renderQueue->root);
sl@0
    78
        
sl@0
    79
    /* Insert each submesh into the rendering queue */
sl@0
    80
            
sl@0
    81
    for (i = 0; i < mesh->trianglePatchCount; i++) {
sl@0
    82
        if (mesh->appearances[i] != NULL) {
sl@0
    83
            if (!m3gInsertDrawable(M3G_INTERFACE(mesh),
sl@0
    84
                                   renderQueue,
sl@0
    85
                                   (Node*) mesh,
sl@0
    86
                                   toCamera,
sl@0
    87
                                   i,
sl@0
    88
                                   m3gGetAppearanceSortKey(mesh->appearances[i])))
sl@0
    89
                return M3G_FALSE;
sl@0
    90
        }
sl@0
    91
    }
sl@0
    92
    return M3G_TRUE;
sl@0
    93
}
sl@0
    94
sl@0
    95
/*!
sl@0
    96
 * \internal
sl@0
    97
 * \brief Overloaded Node method.
sl@0
    98
 *
sl@0
    99
 * Setup mesh rendering by adding all submeshes to
sl@0
   100
 * the render queue.
sl@0
   101
 *
sl@0
   102
 * \param self Mesh object
sl@0
   103
 * \param toCamera transform to camera
sl@0
   104
 * \param alphaFactor total alpha factor
sl@0
   105
 * \param caller caller node
sl@0
   106
 * \param renderQueue RenderQueue
sl@0
   107
 *
sl@0
   108
 * \retval M3G_TRUE continue render setup
sl@0
   109
 * \retval M3G_FALSE abort render setup
sl@0
   110
 */
sl@0
   111
static M3Gbool m3gMeshSetupRender(Node *self,
sl@0
   112
                                  const Node *caller,
sl@0
   113
                                  SetupRenderState *s,
sl@0
   114
                                  RenderQueue *renderQueue)
sl@0
   115
{
sl@0
   116
	Mesh *mesh = (Mesh *)self;
sl@0
   117
    M3G_UNREF(caller);
sl@0
   118
    m3gIncStat(M3G_INTERFACE(self), M3G_STAT_RENDER_NODES, 1);
sl@0
   119
    
sl@0
   120
	if ((self->enableBits & NODE_RENDER_BIT) != 0 &&
sl@0
   121
        (self->scope & renderQueue->scope) != 0) {
sl@0
   122
sl@0
   123
        /* Check view frustum culling */
sl@0
   124
        
sl@0
   125
#       if defined(M3G_ENABLE_VF_CULLING)
sl@0
   126
        AABB bbox;
sl@0
   127
        m3gGetBoundingBox(mesh->vertexBuffer, &bbox);
sl@0
   128
        m3gUpdateCullingMask(s, renderQueue->camera, &bbox);
sl@0
   129
        if (s->cullMask == 0) {
sl@0
   130
            m3gIncStat(M3G_INTERFACE(self),
sl@0
   131
                       M3G_STAT_RENDER_NODES_CULLED, 1);
sl@0
   132
            return M3G_TRUE;
sl@0
   133
        }
sl@0
   134
#       endif
sl@0
   135
sl@0
   136
        /* No dice, let's render... */
sl@0
   137
sl@0
   138
        return m3gQueueMesh(mesh, &s->toCamera, renderQueue);
sl@0
   139
    }
sl@0
   140
    return M3G_TRUE;
sl@0
   141
}
sl@0
   142
sl@0
   143
/*!
sl@0
   144
 * \internal
sl@0
   145
 * \brief Overloaded Node method.
sl@0
   146
 *
sl@0
   147
 * Renders one submesh.
sl@0
   148
 *
sl@0
   149
 * \param self Mesh object
sl@0
   150
 * \param ctx current render context
sl@0
   151
 * \param patchIndex submesh index
sl@0
   152
 */
sl@0
   153
static void m3gMeshDoRender(Node *self,
sl@0
   154
                            RenderContext *ctx,
sl@0
   155
                            const Matrix *toCamera,
sl@0
   156
                            M3Gint patchIndex)
sl@0
   157
{
sl@0
   158
    Mesh *mesh = (Mesh *)self;
sl@0
   159
sl@0
   160
	m3gDrawMesh(ctx,
sl@0
   161
                mesh->vertexBuffer,
sl@0
   162
                mesh->indexBuffers[patchIndex],
sl@0
   163
                mesh->appearances[patchIndex],
sl@0
   164
                toCamera,
sl@0
   165
                mesh->totalAlphaFactor + 1,
sl@0
   166
                self->scope);
sl@0
   167
}
sl@0
   168
sl@0
   169
/*!
sl@0
   170
 * \internal
sl@0
   171
 * \brief Internal equivalent routine called
sl@0
   172
 * by m3gMeshRayIntersect.
sl@0
   173
 *
sl@0
   174
 * \param mesh      Mesh object
sl@0
   175
 * \param vertices  VertexBuffer object used in calculations
sl@0
   176
 * \param mask      pick scope mask
sl@0
   177
 * \param ray       pick ray
sl@0
   178
 * \param ri        RayIntersection object
sl@0
   179
 * \param toGroup   transform to originating group
sl@0
   180
 * \retval          M3G_TRUE    continue pick
sl@0
   181
 * \retval          M3G_FALSE   abort pick
sl@0
   182
 */
sl@0
   183
static M3Gbool m3gMeshRayIntersectInternal(	Mesh *mesh,
sl@0
   184
                                            VertexBuffer *vertices,
sl@0
   185
            								M3Gint mask,
sl@0
   186
            								M3Gfloat *ray,
sl@0
   187
            								RayIntersection *ri,
sl@0
   188
            								Matrix *toGroup)
sl@0
   189
{
sl@0
   190
    Vec3 v0, v1, v2, tuv;
sl@0
   191
    Vec4 transformed, p0, p1;
sl@0
   192
    M3Gint indices[4] = { 0, 0, 0, 0 }; 
sl@0
   193
    M3Gint i, j, k, cullMode;
sl@0
   194
    Matrix t;   /* Reused as texture transform */
sl@0
   195
sl@0
   196
    if (vertices == NULL ||
sl@0
   197
         mesh->appearances == NULL ||
sl@0
   198
         mesh->indexBuffers == NULL ||
sl@0
   199
         (((Node *)mesh)->scope & mask) == 0) {
sl@0
   200
        return M3G_TRUE;
sl@0
   201
    }
sl@0
   202
sl@0
   203
    if (vertices->vertices == NULL) {
sl@0
   204
        m3gRaiseError(M3G_INTERFACE(mesh), M3G_INVALID_OPERATION);
sl@0
   205
        return M3G_FALSE;
sl@0
   206
    }
sl@0
   207
sl@0
   208
    p0.x = ray[0];
sl@0
   209
    p0.y = ray[1];
sl@0
   210
    p0.z = ray[2];
sl@0
   211
    p0.w = 1.f;
sl@0
   212
sl@0
   213
    p1.x = ray[3];
sl@0
   214
    p1.y = ray[4];
sl@0
   215
    p1.z = ray[5];
sl@0
   216
    p1.w = 1.f;
sl@0
   217
sl@0
   218
    m3gCopyMatrix(&t, toGroup);
sl@0
   219
    M3G_BEGIN_PROFILE(M3G_INTERFACE(mesh), M3G_PROFILE_TRANSFORM_INVERT);
sl@0
   220
    if (!m3gInvertMatrix(&t)) {
sl@0
   221
        m3gRaiseError(M3G_INTERFACE(mesh), M3G_ARITHMETIC_ERROR);
sl@0
   222
        return M3G_FALSE;
sl@0
   223
    }
sl@0
   224
    M3G_END_PROFILE(M3G_INTERFACE(mesh), M3G_PROFILE_TRANSFORM_INVERT);
sl@0
   225
    m3gTransformVec4(&t, &p0);
sl@0
   226
    m3gTransformVec4(&t, &p1);
sl@0
   227
    
sl@0
   228
    m3gScaleVec3((Vec3*) &p0, m3gRcp(p0.w));
sl@0
   229
    m3gScaleVec3((Vec3*) &p1, m3gRcp(p1.w));
sl@0
   230
sl@0
   231
    m3gSubVec4(&p1, &p0);
sl@0
   232
sl@0
   233
    /* Quick bounding box test for Meshes */
sl@0
   234
    if (m3gGetClass((Object *)mesh) == M3G_CLASS_MESH) {
sl@0
   235
        AABB boundingBox;
sl@0
   236
        m3gGetBoundingBox(vertices, &boundingBox);
sl@0
   237
sl@0
   238
        if (!m3gIntersectBox((Vec3*) &p0, (Vec3*) &p1, &boundingBox)) {
sl@0
   239
            return M3G_TRUE;
sl@0
   240
        }
sl@0
   241
    }
sl@0
   242
sl@0
   243
    /* Apply the inverse of the vertex scale and bias to the ray */
sl@0
   244
    
sl@0
   245
    if (!IS_ZERO(vertices->vertexScale)) {
sl@0
   246
        const Vec3 *bias = (const Vec3*) vertices->vertexBias;
sl@0
   247
        M3Gfloat ooScale = m3gRcp(vertices->vertexScale);
sl@0
   248
        m3gSubVec3((Vec3*) &p0, bias);
sl@0
   249
        m3gScaleVec3((Vec3*) &p0, ooScale);
sl@0
   250
        m3gScaleVec3((Vec3*) &p1, ooScale); /* direction vector -> no bias */
sl@0
   251
    }
sl@0
   252
    else {
sl@0
   253
        m3gRaiseError(M3G_INTERFACE(mesh), M3G_ARITHMETIC_ERROR);
sl@0
   254
        return M3G_FALSE;
sl@0
   255
    }
sl@0
   256
    
sl@0
   257
    /* Go through all submeshes */
sl@0
   258
    for (i = 0; i < mesh->trianglePatchCount; i++) {
sl@0
   259
        /* Do not pick submeshes with null appearance */
sl@0
   260
        if (mesh->appearances[i] == NULL ||
sl@0
   261
            mesh->indexBuffers[i] == NULL) continue;
sl@0
   262
sl@0
   263
        /* Validate indices versus vertex buffer */
sl@0
   264
        if (m3gGetMaxIndex(mesh->indexBuffers[i]) >= m3gGetNumVertices(vertices)) {
sl@0
   265
            m3gRaiseError(M3G_INTERFACE(mesh), M3G_INVALID_OPERATION);
sl@0
   266
            return M3G_FALSE;
sl@0
   267
        }
sl@0
   268
sl@0
   269
        if (mesh->appearances[i]->polygonMode != NULL) {
sl@0
   270
            cullMode = m3gGetWinding(mesh->appearances[i]->polygonMode) == M3G_WINDING_CCW ? 0 : 1;
sl@0
   271
            switch(m3gGetCulling(mesh->appearances[i]->polygonMode)) {
sl@0
   272
            case M3G_CULL_FRONT: cullMode ^= 1; break;
sl@0
   273
            case M3G_CULL_NONE:  cullMode  = 2; break;
sl@0
   274
            }
sl@0
   275
        }
sl@0
   276
        else {
sl@0
   277
            cullMode = 0;
sl@0
   278
        }
sl@0
   279
sl@0
   280
        /* Go through all triangels */
sl@0
   281
        for (j = 0; m3gGetIndices(mesh->indexBuffers[i], j, indices); j++) {
sl@0
   282
            /* Ignore zero area triangles */
sl@0
   283
            if ( indices[0] == indices[1] ||
sl@0
   284
                 indices[0] == indices[2] ||
sl@0
   285
                 indices[1] == indices[2]) continue;
sl@0
   286
sl@0
   287
            m3gGetVertex(vertices, indices[0], &v0);
sl@0
   288
            m3gGetVertex(vertices, indices[1], &v1);
sl@0
   289
            m3gGetVertex(vertices, indices[2], &v2);
sl@0
   290
sl@0
   291
            if (m3gIntersectTriangle((Vec3*)&p0, (Vec3*)&p1, &v0, &v1, &v2, &tuv, indices[3] ^ cullMode)) {
sl@0
   292
                /* Check that we are going to fill this intersection */
sl@0
   293
                if (tuv.x <= 0.f || tuv.x >= ri->tMin) continue;
sl@0
   294
sl@0
   295
                /* Fill in to RayIntersection */
sl@0
   296
                ri->tMin = tuv.x;
sl@0
   297
                ri->distance = tuv.x;
sl@0
   298
                ri->submeshIndex = i;
sl@0
   299
                ri->intersected = (Node *)mesh;
sl@0
   300
sl@0
   301
                /* Fetch normal */
sl@0
   302
                if (m3gGetNormal(vertices, indices[0], &v0)) {
sl@0
   303
                    m3gGetNormal(vertices, indices[1], &v1);
sl@0
   304
                    m3gGetNormal(vertices, indices[2], &v2);
sl@0
   305
sl@0
   306
                    ri->normal[0] = m3gAdd(
sl@0
   307
                        m3gMul(v0.x, m3gSub(1.f, m3gAdd(tuv.y, tuv.z))),
sl@0
   308
                        m3gAdd(
sl@0
   309
                            m3gMul(v1.x, tuv.y),
sl@0
   310
                            m3gMul(v2.x, tuv.z)));
sl@0
   311
                    
sl@0
   312
                    ri->normal[1] = m3gAdd(
sl@0
   313
                        m3gMul(v0.y, m3gSub(1.f, m3gAdd(tuv.y, tuv.z))),
sl@0
   314
                        m3gAdd(
sl@0
   315
                            m3gMul(v1.y, tuv.y),
sl@0
   316
                            m3gMul(v2.y, tuv.z)));
sl@0
   317
                    
sl@0
   318
                    ri->normal[2] = m3gAdd(
sl@0
   319
                        m3gMul(v0.z, m3gSub(1.f, m3gAdd(tuv.y, tuv.z))),
sl@0
   320
                        m3gAdd(
sl@0
   321
                            m3gMul(v1.z, tuv.y),
sl@0
   322
                            m3gMul(v2.z, tuv.z)));
sl@0
   323
                }
sl@0
   324
                else {
sl@0
   325
                    ri->normal[0] = 0.f;
sl@0
   326
                    ri->normal[1] = 0.f;
sl@0
   327
                    ri->normal[2] = 1.f;
sl@0
   328
                }
sl@0
   329
            
sl@0
   330
                /* Fetch texture coordinates for each unit */
sl@0
   331
                for (k = 0; k < M3G_NUM_TEXTURE_UNITS; k++) {
sl@0
   332
                    if (m3gGetTexCoord(vertices, indices[0], k, &v0)) {
sl@0
   333
                        m3gGetTexCoord(vertices, indices[1], k, &v1);
sl@0
   334
                        m3gGetTexCoord(vertices, indices[2], k, &v2);
sl@0
   335
sl@0
   336
                        /* Calculate transformed S and T */
sl@0
   337
                        transformed.x = m3gAdd(
sl@0
   338
                            m3gMul(v0.x, m3gSub(1.f, m3gAdd(tuv.y, tuv.z))),
sl@0
   339
                            m3gAdd(
sl@0
   340
                                m3gMul(v1.x, tuv.y),
sl@0
   341
                                m3gMul(v2.x, tuv.z)));
sl@0
   342
                        
sl@0
   343
                        transformed.y = m3gAdd(
sl@0
   344
                            m3gMul(v0.y, m3gSub(1.f, m3gAdd(tuv.y, tuv.z))),
sl@0
   345
                            m3gAdd(
sl@0
   346
                                m3gMul(v1.y, tuv.y),
sl@0
   347
                                m3gMul(v2.y, tuv.z)));
sl@0
   348
                        
sl@0
   349
                        transformed.z = 0;
sl@0
   350
                        transformed.w = 1;
sl@0
   351
sl@0
   352
                        /* Transform and * 1/w */
sl@0
   353
                        if (mesh->appearances[i]->texture[k] != NULL) {
sl@0
   354
                            m3gGetCompositeTransform((Transformable *)mesh->appearances[i]->texture[k], &t);
sl@0
   355
                            m3gTransformVec4(&t, &transformed);
sl@0
   356
                            m3gScaleVec4(&transformed, m3gRcp(transformed.w));
sl@0
   357
                        }
sl@0
   358
sl@0
   359
                        ri->textureS[k] = transformed.x;
sl@0
   360
                        ri->textureT[k] = transformed.y;
sl@0
   361
                    }
sl@0
   362
                    else {
sl@0
   363
                        ri->textureS[k] = 0.f;
sl@0
   364
                        ri->textureT[k] = 0.f;
sl@0
   365
                    }
sl@0
   366
                }
sl@0
   367
            }
sl@0
   368
        }
sl@0
   369
    }
sl@0
   370
sl@0
   371
    return M3G_TRUE;
sl@0
   372
}
sl@0
   373
sl@0
   374
/*!
sl@0
   375
 * \internal
sl@0
   376
 * \brief Overloaded Node method.
sl@0
   377
 *
sl@0
   378
 * Just forward call internal ray intersect.
sl@0
   379
 *
sl@0
   380
 * \param self      Mesh object
sl@0
   381
 * \param mask      pick scope mask
sl@0
   382
 * \param ray       pick ray
sl@0
   383
 * \param ri        RayIntersection object
sl@0
   384
 * \param toGroup   transform to originating group
sl@0
   385
 * \retval          M3G_TRUE    continue pick
sl@0
   386
 * \retval          M3G_FALSE   abort pick
sl@0
   387
 */
sl@0
   388
static M3Gbool m3gMeshRayIntersect( Node *self,
sl@0
   389
    								M3Gint mask,
sl@0
   390
    								M3Gfloat *ray,
sl@0
   391
    								RayIntersection *ri,
sl@0
   392
    								Matrix *toGroup)
sl@0
   393
{
sl@0
   394
    Mesh *mesh = (Mesh *)self;
sl@0
   395
    return m3gMeshRayIntersectInternal(mesh, mesh->vertexBuffer, mask, ray, ri, toGroup);
sl@0
   396
}
sl@0
   397
sl@0
   398
/*!
sl@0
   399
 * \internal
sl@0
   400
 * \brief Initializes a Mesh object. See specification
sl@0
   401
 * for default values.
sl@0
   402
 *
sl@0
   403
 * \param m3g                   M3G interface
sl@0
   404
 * \param mesh                  Mesh object
sl@0
   405
 * \param hVertices             VertexBuffer object
sl@0
   406
 * \param hTriangles            array of IndexBuffer objects
sl@0
   407
 * \param hAppearances          array of Appearance objects
sl@0
   408
 * \param trianglePatchCount    number of submeshes
sl@0
   409
 * \param vfTable               virtual function table
sl@0
   410
 * \retval                      M3G_TRUE success
sl@0
   411
 * \retval                      M3G_FALSE failed
sl@0
   412
 */
sl@0
   413
static M3Gbool m3gInitMesh(Interface *m3g,
sl@0
   414
                           Mesh *mesh,
sl@0
   415
                           M3GVertexBuffer hVertices,
sl@0
   416
                           M3GIndexBuffer *hTriangles,
sl@0
   417
                           M3GAppearance *hAppearances,
sl@0
   418
                           M3Gint trianglePatchCount,
sl@0
   419
                           M3GClass classID)
sl@0
   420
{
sl@0
   421
    M3Gint i;
sl@0
   422
	
sl@0
   423
    /* Out of memory if more than 65535 triangle patches */
sl@0
   424
    if (trianglePatchCount > 65535) {
sl@0
   425
        m3gRaiseError(m3g, M3G_OUT_OF_MEMORY);
sl@0
   426
        return M3G_FALSE;
sl@0
   427
    }
sl@0
   428
sl@0
   429
	for (i = 0; i < trianglePatchCount; i++) {
sl@0
   430
		if (hTriangles[i] == NULL) {
sl@0
   431
			m3gRaiseError(m3g, M3G_NULL_POINTER);
sl@0
   432
            return M3G_FALSE;
sl@0
   433
		}
sl@0
   434
	}
sl@0
   435
sl@0
   436
	mesh->indexBuffers =
sl@0
   437
        m3gAllocZ(m3g, sizeof(IndexBuffer *) * trianglePatchCount);
sl@0
   438
	if (!mesh->indexBuffers) {
sl@0
   439
		return M3G_FALSE;
sl@0
   440
	}
sl@0
   441
sl@0
   442
	mesh->appearances =
sl@0
   443
        m3gAllocZ(m3g, sizeof(Appearance *) * trianglePatchCount);
sl@0
   444
	if (!mesh->appearances) {
sl@0
   445
		m3gFree(m3g, mesh->indexBuffers);
sl@0
   446
		return M3G_FALSE;
sl@0
   447
	}
sl@0
   448
sl@0
   449
	/* Mesh is derived from node */
sl@0
   450
	m3gInitNode(m3g, &mesh->node, classID);
sl@0
   451
    mesh->node.hasRenderables = M3G_TRUE;
sl@0
   452
    mesh->node.dirtyBits |= NODE_BBOX_BIT;
sl@0
   453
sl@0
   454
    for (i = 0; i < trianglePatchCount; i++) {
sl@0
   455
        M3G_ASSIGN_REF(mesh->indexBuffers[i], hTriangles[i]);
sl@0
   456
    }
sl@0
   457
	
sl@0
   458
	if (hAppearances != NULL) {
sl@0
   459
        for (i = 0; i < trianglePatchCount; i++) {
sl@0
   460
            M3G_ASSIGN_REF(mesh->appearances[i], hAppearances[i]);
sl@0
   461
        }
sl@0
   462
	}
sl@0
   463
	else {
sl@0
   464
		m3gZero(mesh->appearances, sizeof(Appearance *) * trianglePatchCount);
sl@0
   465
    }
sl@0
   466
	
sl@0
   467
    M3G_ASSIGN_REF(mesh->vertexBuffer, hVertices);
sl@0
   468
	mesh->trianglePatchCount = (M3Gshort) trianglePatchCount;
sl@0
   469
sl@0
   470
    m3gIncStat(M3G_INTERFACE(mesh), M3G_STAT_RENDERABLES, 1);
sl@0
   471
    
sl@0
   472
	return M3G_TRUE;
sl@0
   473
}
sl@0
   474
sl@0
   475
/*!
sl@0
   476
 * \internal
sl@0
   477
 * \brief Overloaded Object3D method.
sl@0
   478
 *
sl@0
   479
 * \param self Mesh object
sl@0
   480
 * \param references array of reference objects
sl@0
   481
 * \return number of references
sl@0
   482
 */
sl@0
   483
static M3Gint m3gMeshDoGetReferences(Object *self, Object **references)
sl@0
   484
{
sl@0
   485
    Mesh *mesh = (Mesh *)self;
sl@0
   486
    M3Gint i, num = m3gObjectDoGetReferences(self, references);
sl@0
   487
    if (references != NULL)
sl@0
   488
        references[num] = (Object *)mesh->vertexBuffer;
sl@0
   489
    num++;
sl@0
   490
    for (i = 0; i < mesh->trianglePatchCount; i++) {
sl@0
   491
        if (mesh->indexBuffers[i] != NULL) {
sl@0
   492
            if (references != NULL)
sl@0
   493
                references[num] = (Object *)mesh->indexBuffers[i];
sl@0
   494
            num++;
sl@0
   495
        }
sl@0
   496
        if (mesh->appearances[i] != NULL) {
sl@0
   497
            if (references != NULL)
sl@0
   498
                references[num] = (Object *)mesh->appearances[i];
sl@0
   499
            num++;
sl@0
   500
        }
sl@0
   501
    }
sl@0
   502
    return num;
sl@0
   503
}
sl@0
   504
sl@0
   505
/*!
sl@0
   506
 * \internal
sl@0
   507
 * \brief Overloaded Object3D method.
sl@0
   508
 */
sl@0
   509
static Object *m3gMeshFindID(Object *self, M3Gint userID)
sl@0
   510
{
sl@0
   511
    int i;
sl@0
   512
    Mesh *mesh = (Mesh *)self;
sl@0
   513
    Object *found = m3gObjectFindID(self, userID);
sl@0
   514
sl@0
   515
    if (!found) {
sl@0
   516
        found = m3gFindID((Object*) mesh->vertexBuffer, userID);
sl@0
   517
    }    
sl@0
   518
    for (i = 0; !found && i < mesh->trianglePatchCount; ++i) {
sl@0
   519
        if (mesh->indexBuffers[i] != NULL) {
sl@0
   520
            found = m3gFindID((Object*) mesh->indexBuffers[i], userID);
sl@0
   521
        }
sl@0
   522
        if (!found && mesh->appearances[i] != NULL) {
sl@0
   523
            found = m3gFindID((Object*) mesh->appearances[i], userID);
sl@0
   524
        }
sl@0
   525
    }
sl@0
   526
    return found;
sl@0
   527
}
sl@0
   528
sl@0
   529
/*!
sl@0
   530
 * \internal
sl@0
   531
 * \brief Overloaded Object3D method.
sl@0
   532
 *
sl@0
   533
 * \param originalObj original Mesh object
sl@0
   534
 * \param cloneObj pointer to cloned Mesh object
sl@0
   535
 * \param pairs array for all object-duplicate pairs
sl@0
   536
 * \param numPairs number of pairs
sl@0
   537
 */
sl@0
   538
static M3Gbool m3gMeshDuplicate(const Object *originalObj,
sl@0
   539
                                Object **cloneObj,
sl@0
   540
                                Object **pairs,
sl@0
   541
                                M3Gint *numPairs)
sl@0
   542
{
sl@0
   543
    /* Create the clone if it doesn't exist; otherwise we'll be all
sl@0
   544
     * set by the derived class(es) and can just call through to the
sl@0
   545
     * base class */
sl@0
   546
    
sl@0
   547
    if (*cloneObj == NULL) {
sl@0
   548
        Mesh *original = (Mesh *)originalObj;
sl@0
   549
        Mesh *clone = (Mesh *)m3gCreateMesh(originalObj->interface,
sl@0
   550
                                            original->vertexBuffer,
sl@0
   551
                                            original->indexBuffers,
sl@0
   552
                                            original->appearances,
sl@0
   553
                                            original->trianglePatchCount);
sl@0
   554
        *cloneObj = (Object *)clone;
sl@0
   555
        if (*cloneObj == NULL) {
sl@0
   556
            return M3G_FALSE;
sl@0
   557
        }
sl@0
   558
    }
sl@0
   559
    
sl@0
   560
    return m3gNodeDuplicate(originalObj, cloneObj, pairs, numPairs);
sl@0
   561
}
sl@0
   562
sl@0
   563
/*!
sl@0
   564
 * \internal
sl@0
   565
 * \brief Overloaded Object3D method.
sl@0
   566
 *
sl@0
   567
 * \param self Mesh object
sl@0
   568
 * \param time current world time
sl@0
   569
 * \return minimum validity
sl@0
   570
 */
sl@0
   571
static M3Gint m3gMeshApplyAnimation(Object *self, M3Gint time)
sl@0
   572
{
sl@0
   573
    M3Gint validity, minValidity;
sl@0
   574
    Mesh *mesh = (Mesh *)self;
sl@0
   575
    Object *vb;
sl@0
   576
    M3G_VALIDATE_OBJECT(mesh);
sl@0
   577
sl@0
   578
    minValidity = m3gObjectApplyAnimation(self, time);
sl@0
   579
sl@0
   580
    vb = (Object *) mesh->vertexBuffer;
sl@0
   581
sl@0
   582
    if (vb != NULL && minValidity > 0) {
sl@0
   583
        validity = M3G_VFUNC(Object, vb, applyAnimation)(vb, time);
sl@0
   584
        minValidity = M3G_MIN(validity, minValidity);
sl@0
   585
    }
sl@0
   586
    
sl@0
   587
    if (mesh->appearances != NULL) {
sl@0
   588
        Object *app;
sl@0
   589
        M3Gint i, n;
sl@0
   590
        n = mesh->trianglePatchCount;
sl@0
   591
        
sl@0
   592
        for (i = 0; i < n && minValidity > 0; ++i) {
sl@0
   593
            app = (Object *) mesh->appearances[i];
sl@0
   594
            if (app != NULL) {
sl@0
   595
                validity = M3G_VFUNC(Object, app, applyAnimation)(app, time);
sl@0
   596
                minValidity = M3G_MIN(validity, minValidity);
sl@0
   597
            }
sl@0
   598
        }
sl@0
   599
    }
sl@0
   600
sl@0
   601
    return minValidity;
sl@0
   602
}
sl@0
   603
sl@0
   604
/*!
sl@0
   605
 * \internal
sl@0
   606
 * \brief Overloaded Node method
sl@0
   607
 */
sl@0
   608
static M3Gint m3gMeshGetBBox(Node *self, AABB *bbox)
sl@0
   609
{
sl@0
   610
    Mesh *mesh = (Mesh *) self;
sl@0
   611
    VertexBuffer *vb = mesh->vertexBuffer;
sl@0
   612
sl@0
   613
    if (vb->vertices) {
sl@0
   614
        m3gGetBoundingBox(vb, bbox);
sl@0
   615
        return VFC_BBOX_COST + VFC_NODE_OVERHEAD;
sl@0
   616
    }
sl@0
   617
    else {
sl@0
   618
        return 0;
sl@0
   619
    }
sl@0
   620
}
sl@0
   621
sl@0
   622
/*!
sl@0
   623
 * \internal
sl@0
   624
 * \brief Overloaded Node method
sl@0
   625
 */
sl@0
   626
static M3Gbool m3gMeshValidate(Node *self, M3Gbitmask stateBits, M3Gint scope)
sl@0
   627
{
sl@0
   628
    Mesh *mesh = (Mesh *) self;
sl@0
   629
    VertexBuffer *vb = mesh->vertexBuffer;
sl@0
   630
    int i;
sl@0
   631
sl@0
   632
    if ((scope & self->scope) != 0) {
sl@0
   633
        if (stateBits & self->enableBits) {
sl@0
   634
            
sl@0
   635
            /* Validate vertex buffer components */
sl@0
   636
            
sl@0
   637
            for (i = 0; i < mesh->trianglePatchCount; ++i) {
sl@0
   638
                Appearance *app = mesh->appearances[i];
sl@0
   639
                if (app) {
sl@0
   640
                    if (!m3gValidateVertexBuffer(
sl@0
   641
                            vb, app, m3gGetMaxIndex(mesh->indexBuffers[i]))) {
sl@0
   642
                        m3gRaiseError(M3G_INTERFACE(mesh), M3G_INVALID_OPERATION);
sl@0
   643
                        return M3G_FALSE;
sl@0
   644
                    }
sl@0
   645
                }
sl@0
   646
            }
sl@0
   647
    
sl@0
   648
            /* Invalidate cached vertex stuff if source buffer changed */
sl@0
   649
            {
sl@0
   650
                M3Gint vbTimestamp = m3gGetTimestamp(vb);
sl@0
   651
                if (mesh->vbTimestamp != vbTimestamp) {
sl@0
   652
                    m3gInvalidateNode(self, NODE_BBOX_BIT);
sl@0
   653
                    mesh->vbTimestamp = vbTimestamp;
sl@0
   654
                }
sl@0
   655
            }
sl@0
   656
            
sl@0
   657
            return m3gNodeValidate(self, stateBits, scope);
sl@0
   658
        }
sl@0
   659
    }
sl@0
   660
    return M3G_TRUE;
sl@0
   661
}
sl@0
   662
sl@0
   663
#if 0
sl@0
   664
/*!
sl@0
   665
 * \internal
sl@0
   666
 * \brief Computes the estimated rendering cost for this Mesh node
sl@0
   667
 */
sl@0
   668
static M3Gint m3gMeshRenderingCost(const Mesh *mesh)
sl@0
   669
{
sl@0
   670
    /* Since we're using strips, just assume that each vertex
sl@0
   671
     * generates a new triangle... */
sl@0
   672
    
sl@0
   673
    return
sl@0
   674
        mesh->vertexBuffer->vertexCount * (VFC_VERTEX_COST +
sl@0
   675
                                           VFC_TRIANGLE_COST) +
sl@0
   676
        mesh->trianglePatchCount * VFC_RENDERCALL_OVERHEAD +
sl@0
   677
        VFC_NODE_OVERHEAD;
sl@0
   678
}
sl@0
   679
#endif
sl@0
   680
sl@0
   681
/*----------------------------------------------------------------------
sl@0
   682
 * Virtual function table
sl@0
   683
 *--------------------------------------------------------------------*/
sl@0
   684
sl@0
   685
static const NodeVFTable m3gvf_Mesh = {
sl@0
   686
    {
sl@0
   687
        {
sl@0
   688
            m3gMeshApplyAnimation,
sl@0
   689
            m3gNodeIsCompatible,
sl@0
   690
            m3gNodeUpdateProperty,
sl@0
   691
            m3gMeshDoGetReferences,
sl@0
   692
            m3gMeshFindID,
sl@0
   693
            m3gMeshDuplicate,
sl@0
   694
            m3gDestroyMesh
sl@0
   695
        }
sl@0
   696
    },
sl@0
   697
    m3gNodeAlign,
sl@0
   698
    m3gMeshDoRender,
sl@0
   699
    m3gMeshGetBBox,
sl@0
   700
    m3gMeshRayIntersect,
sl@0
   701
    m3gMeshSetupRender,
sl@0
   702
    m3gNodeUpdateDuplicateReferences,
sl@0
   703
    m3gMeshValidate
sl@0
   704
};
sl@0
   705
sl@0
   706
sl@0
   707
/*----------------------------------------------------------------------
sl@0
   708
 * Public API functions
sl@0
   709
 *--------------------------------------------------------------------*/
sl@0
   710
sl@0
   711
/*!
sl@0
   712
 * \brief Creates a Mesh object.
sl@0
   713
 *
sl@0
   714
 * \param interface             M3G interface
sl@0
   715
 * \param hVertices             VertexBuffer object
sl@0
   716
 * \param hTriangles            array of IndexBuffer objects
sl@0
   717
 * \param hAppearances          array of Appearance objects
sl@0
   718
 * \param trianglePatchCount    number of submeshes
sl@0
   719
 * \retval Mesh new Mesh object
sl@0
   720
 * \retval NULL Mesh creating failed
sl@0
   721
 */
sl@0
   722
M3G_API M3GMesh m3gCreateMesh(M3GInterface interface,
sl@0
   723
                              M3GVertexBuffer hVertices,
sl@0
   724
                              M3GIndexBuffer *hTriangles,
sl@0
   725
                              M3GAppearance *hAppearances,
sl@0
   726
                              M3Gint trianglePatchCount)
sl@0
   727
{
sl@0
   728
    Interface *m3g = (Interface *) interface;
sl@0
   729
    M3G_VALIDATE_INTERFACE(m3g);
sl@0
   730
sl@0
   731
	{
sl@0
   732
		Mesh *mesh = m3gAllocZ(m3g, sizeof(Mesh));
sl@0
   733
sl@0
   734
		if (mesh != NULL) {
sl@0
   735
    		if (!m3gInitMesh(m3g, mesh,
sl@0
   736
                             hVertices, hTriangles, hAppearances,
sl@0
   737
                             trianglePatchCount,
sl@0
   738
                             M3G_CLASS_MESH)) {
sl@0
   739
    			m3gFree(m3g, mesh);
sl@0
   740
    			return NULL;
sl@0
   741
    		}
sl@0
   742
		}
sl@0
   743
sl@0
   744
		return (M3GMesh)mesh;
sl@0
   745
	}
sl@0
   746
}
sl@0
   747
sl@0
   748
/*!
sl@0
   749
 * \brief Sets submesh appearance.
sl@0
   750
 *
sl@0
   751
 * \param handle                Mesh object
sl@0
   752
 * \param appearanceIndex       submesh index
sl@0
   753
 * \param hAppearance           Appearance object
sl@0
   754
 */
sl@0
   755
M3G_API void m3gSetAppearance(M3GMesh handle,
sl@0
   756
                              M3Gint appearanceIndex,
sl@0
   757
                              M3GAppearance hAppearance)
sl@0
   758
{
sl@0
   759
	Mesh *mesh = (Mesh *)handle;
sl@0
   760
    M3G_VALIDATE_OBJECT(mesh);
sl@0
   761
	
sl@0
   762
	if (appearanceIndex < 0 || appearanceIndex >= mesh->trianglePatchCount) {
sl@0
   763
		m3gRaiseError(M3G_INTERFACE(mesh), M3G_INVALID_INDEX);
sl@0
   764
        return;
sl@0
   765
	}
sl@0
   766
sl@0
   767
    M3G_ASSIGN_REF(mesh->appearances[appearanceIndex], (Appearance *) hAppearance);
sl@0
   768
}
sl@0
   769
sl@0
   770
/*!
sl@0
   771
 * \brief Gets submesh appearance.
sl@0
   772
 *
sl@0
   773
 * \param handle                Mesh object
sl@0
   774
 * \param idx                   submesh index
sl@0
   775
 * \return                      Appearance object
sl@0
   776
 */
sl@0
   777
M3G_API M3GAppearance m3gGetAppearance(M3GMesh handle,
sl@0
   778
                                       M3Gint idx)
sl@0
   779
{
sl@0
   780
	Mesh *mesh = (Mesh *)handle;
sl@0
   781
    M3G_VALIDATE_OBJECT(mesh);
sl@0
   782
	
sl@0
   783
	if (idx < 0 || idx >= mesh->trianglePatchCount) {
sl@0
   784
		m3gRaiseError(M3G_INTERFACE(mesh), M3G_INVALID_INDEX);
sl@0
   785
        return NULL;
sl@0
   786
	}
sl@0
   787
sl@0
   788
    return mesh->appearances[idx];
sl@0
   789
}
sl@0
   790
sl@0
   791
/*!
sl@0
   792
 * \brief Gets submesh index buffer.
sl@0
   793
 *
sl@0
   794
 * \param handle                Mesh object
sl@0
   795
 * \param idx                   submesh index
sl@0
   796
 * \return                      IndexBuffer object
sl@0
   797
 */
sl@0
   798
M3G_API M3GIndexBuffer m3gGetIndexBuffer(M3GMesh handle,
sl@0
   799
                                         M3Gint idx)
sl@0
   800
{
sl@0
   801
	Mesh *mesh = (Mesh *)handle;
sl@0
   802
    M3G_VALIDATE_OBJECT(mesh);
sl@0
   803
	
sl@0
   804
	if (idx < 0 || idx >= mesh->trianglePatchCount) {
sl@0
   805
		m3gRaiseError(M3G_INTERFACE(mesh), M3G_INVALID_INDEX);
sl@0
   806
        return NULL;
sl@0
   807
	}
sl@0
   808
sl@0
   809
    return mesh->indexBuffers[idx];
sl@0
   810
}
sl@0
   811
sl@0
   812
/*!
sl@0
   813
 * \brief Gets VertexBuffer.
sl@0
   814
 *
sl@0
   815
 * \param handle                Mesh object
sl@0
   816
 * \return                      VertexBuffer object
sl@0
   817
 */
sl@0
   818
M3G_API M3GVertexBuffer m3gGetVertexBuffer(M3GMesh handle)
sl@0
   819
{
sl@0
   820
	Mesh *mesh = (Mesh *)handle;
sl@0
   821
    M3G_VALIDATE_OBJECT(mesh);
sl@0
   822
sl@0
   823
    return mesh->vertexBuffer;
sl@0
   824
}
sl@0
   825
sl@0
   826
/*!
sl@0
   827
 * \brief Gets submesh count.
sl@0
   828
 *
sl@0
   829
 * \param handle                Mesh object
sl@0
   830
 * \return                      submesh count
sl@0
   831
 */
sl@0
   832
M3G_API M3Gint m3gGetSubmeshCount(M3GMesh handle)
sl@0
   833
{
sl@0
   834
	Mesh *mesh = (Mesh *)handle;
sl@0
   835
    M3G_VALIDATE_OBJECT(mesh);
sl@0
   836
sl@0
   837
    return mesh->trianglePatchCount;
sl@0
   838
}
sl@0
   839