os/graphics/m3g/m3gcore11/src/m3g_vertexbuffer.c
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/graphics/m3g/m3gcore11/src/m3g_vertexbuffer.c	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,1014 @@
     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: Vertex buffer implementation
    1.18 +*
    1.19 +*/
    1.20 +
    1.21 +
    1.22 +/*!
    1.23 + * \internal
    1.24 + * \file
    1.25 + * \brief Vertex buffer 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_vertexbuffer.h"
    1.33 +#include "m3g_vertexarray.h"
    1.34 +
    1.35 +#include "m3g_appearance.h"
    1.36 +#include "m3g_node.h" /* for NODE_ALPHA_FACTOR_BITS */
    1.37 +
    1.38 +/*----------------------------------------------------------------------
    1.39 + * Private functions
    1.40 + *--------------------------------------------------------------------*/
    1.41 +
    1.42 +/*----------------------------------------------------------------------
    1.43 + * Internal functions
    1.44 + *--------------------------------------------------------------------*/
    1.45 +
    1.46 +/*!
    1.47 + * \internal
    1.48 + * \brief Deletes a vertex buffer
    1.49 + *
    1.50 + * \param obj VertexBuffer object
    1.51 + */
    1.52 +static void m3gDestroyVertexBuffer(Object *obj)
    1.53 +{
    1.54 +    M3Gint i;
    1.55 +    VertexBuffer *buffer = (VertexBuffer *) obj;
    1.56 +    M3G_VALIDATE_OBJECT(buffer);
    1.57 +
    1.58 +    if (buffer->locked) {
    1.59 +        M3G_ASSERT(M3G_FALSE);
    1.60 +        m3gReleaseVertexBuffer(buffer);
    1.61 +    }
    1.62 +
    1.63 +    M3G_ASSIGN_REF(buffer->vertices, NULL);
    1.64 +    M3G_ASSIGN_REF(buffer->normals, NULL);
    1.65 +    M3G_ASSIGN_REF(buffer->colors, NULL);
    1.66 +    for(i = 0; i < M3G_NUM_TEXTURE_UNITS; i++) {
    1.67 +        M3G_ASSIGN_REF(buffer->texCoords[i], NULL);
    1.68 +    }
    1.69 +    
    1.70 +    m3gDestroyObject(&buffer->object);
    1.71 +}
    1.72 +
    1.73 +/*!
    1.74 + * \internal
    1.75 + * \brief Applies the scale and bias values of a vertex buffer to the
    1.76 + * current GL state
    1.77 + *
    1.78 + * The scale and bias transformations are applied to the existing
    1.79 + * values in the GL_MODELVIEW and GL_TEXTURE matrix stacks.
    1.80 + *
    1.81 + * \param buffer VertexBuffer object
    1.82 + */
    1.83 +static void m3gApplyScaleAndBias(const VertexBuffer *buffer)
    1.84 +{
    1.85 +    M3G_VALIDATE_OBJECT(buffer);
    1.86 +    
    1.87 +    glMatrixMode(GL_TEXTURE);
    1.88 +    {
    1.89 +        M3Gint i;
    1.90 +        for (i = 0; i < M3G_NUM_TEXTURE_UNITS; ++i) {
    1.91 +            if (buffer->texCoords[i] != NULL) {
    1.92 +                glActiveTexture((GLenum)(GL_TEXTURE0 + i));
    1.93 +                glTranslatef(buffer->texCoordBias[i][0],
    1.94 +                             buffer->texCoordBias[i][1],
    1.95 +                             buffer->texCoordBias[i][2]);
    1.96 +                glScalef(buffer->texCoordScale[i],
    1.97 +                         buffer->texCoordScale[i],
    1.98 +                         buffer->texCoordScale[i]);
    1.99 +            }
   1.100 +        }
   1.101 +    }
   1.102 +
   1.103 +    glMatrixMode(GL_MODELVIEW);
   1.104 +    if (buffer->vertices != NULL) {
   1.105 +        glTranslatef(buffer->vertexBias[0],
   1.106 +                     buffer->vertexBias[1],
   1.107 +                     buffer->vertexBias[2]);
   1.108 +        glScalef(buffer->vertexScale,
   1.109 +                 buffer->vertexScale,
   1.110 +                 buffer->vertexScale);
   1.111 +    }
   1.112 +}
   1.113 +
   1.114 +/*!
   1.115 + * \internal
   1.116 + * \brief Locks a vertex buffer for subsequent rendering
   1.117 + *
   1.118 + * \param buffer        VertexBuffer object
   1.119 + * \param alphaFactor   alpha factor as 1.16 fixed point
   1.120 + */
   1.121 +static void m3gLockVertexBuffer(const VertexBuffer *buffer,
   1.122 +                                M3Gint alphaFactor)
   1.123 +{
   1.124 +    M3G_VALIDATE_OBJECT(buffer);
   1.125 +    M3G_ASSERT(!buffer->locked);
   1.126 +
   1.127 +    if (buffer->colors != NULL) {
   1.128 +        glEnableClientState(GL_COLOR_ARRAY);
   1.129 +        m3gLockColorArray(buffer->colors, alphaFactor);
   1.130 +    }
   1.131 +    else {
   1.132 +        GLfixed r = buffer->defaultColor.r;
   1.133 +        GLfixed g = buffer->defaultColor.g;
   1.134 +        GLfixed b = buffer->defaultColor.b;
   1.135 +        GLfixed a = buffer->defaultColor.a * alphaFactor;
   1.136 +
   1.137 +        r = (r << 8) + r + (r >> 7);
   1.138 +        g = (g << 8) + g + (g >> 7);
   1.139 +        b = (b << 8) + b + (b >> 7);
   1.140 +        a = (a >> (NODE_ALPHA_FACTOR_BITS - 8))
   1.141 +            + (a >> NODE_ALPHA_FACTOR_BITS)
   1.142 +            + (a >> (NODE_ALPHA_FACTOR_BITS + 7));
   1.143 +        
   1.144 +        glDisableClientState(GL_COLOR_ARRAY);
   1.145 +        glColor4x(r, g, b, a);
   1.146 +    }
   1.147 +
   1.148 +    if (buffer->normals != NULL) {
   1.149 +        glEnableClientState(GL_NORMAL_ARRAY);
   1.150 +        m3gLockNormalArray(buffer->normals);
   1.151 +    }
   1.152 +    else {
   1.153 +        glDisableClientState(GL_NORMAL_ARRAY);
   1.154 +    }
   1.155 +
   1.156 +    if (buffer->vertices != NULL) {
   1.157 +        glEnableClientState(GL_VERTEX_ARRAY);
   1.158 +        m3gLockVertexArray(buffer->vertices);
   1.159 +    }
   1.160 +    else {
   1.161 +        glDisableClientState(GL_VERTEX_ARRAY);
   1.162 +    }
   1.163 +    
   1.164 +    {
   1.165 +        M3Gint i;
   1.166 +        for (i = 0; i < M3G_NUM_TEXTURE_UNITS; ++i) {
   1.167 +            const VertexArray *array = buffer->texCoords[i];
   1.168 +            glClientActiveTexture(GL_TEXTURE0 + i);
   1.169 +            glActiveTexture(GL_TEXTURE0 + i);
   1.170 +            if (array != NULL) {
   1.171 +                glEnableClientState(GL_TEXTURE_COORD_ARRAY);
   1.172 +                m3gLockTexCoordArray(array);
   1.173 +            }
   1.174 +            else {
   1.175 +                glDisableClientState(GL_TEXTURE_COORD_ARRAY);
   1.176 +            }    
   1.177 +        }
   1.178 +    }
   1.179 +    
   1.180 +    ((VertexBuffer*)buffer)->locked = M3G_TRUE;
   1.181 +}
   1.182 +
   1.183 +/*!
   1.184 + * \internal
   1.185 + * \brief Releases a vertex buffer
   1.186 + *
   1.187 + * \param buffer        VertexBuffer object
   1.188 + */
   1.189 +static void m3gReleaseVertexBuffer(const VertexBuffer *buffer)
   1.190 +{
   1.191 +    M3G_VALIDATE_OBJECT(buffer);
   1.192 +    M3G_ASSERT(buffer->locked);
   1.193 +
   1.194 +    if (buffer->colors != NULL) {
   1.195 +        m3gUnlockArray(buffer->colors);
   1.196 +    }
   1.197 +    if (buffer->normals != NULL) {
   1.198 +        m3gUnlockArray(buffer->normals);
   1.199 +    }
   1.200 +    if (buffer->vertices != NULL) {
   1.201 +        m3gUnlockArray(buffer->vertices);
   1.202 +    }
   1.203 +    {
   1.204 +        M3Gint i;
   1.205 +        for (i = 0; i < M3G_NUM_TEXTURE_UNITS; ++i) {
   1.206 +            const VertexArray *array = buffer->texCoords[i];
   1.207 +            if (array != NULL) {
   1.208 +                m3gUnlockArray(array);
   1.209 +            }
   1.210 +        }
   1.211 +    }
   1.212 +    
   1.213 +    ((VertexBuffer*)buffer)->locked = M3G_FALSE;
   1.214 +}
   1.215 +
   1.216 +/*!
   1.217 + * \internal
   1.218 + * \brief Gets a vertex position. Scale and bias
   1.219 + * are not applied.
   1.220 + *
   1.221 + * \param buffer    VertexBuffer object
   1.222 + * \param idx       index of coordinate
   1.223 + * \param v         vector to fill in
   1.224 + * \retval          M3G_TRUE get ok
   1.225 + * \retval          M3G_FALSE no such vertex
   1.226 + */
   1.227 +static M3Gbool m3gGetVertex(const VertexBuffer *buffer, M3Gint idx, M3GVec3 *v)
   1.228 +{
   1.229 +    return m3gGetCoordinates(buffer->vertices, 3, idx, &v->x);
   1.230 +}
   1.231 +
   1.232 +/*!
   1.233 + * \internal
   1.234 + * \brief Gets a normal coordinate.
   1.235 + *
   1.236 + * \param buffer    VertexBuffer object
   1.237 + * \param idx       index of coordinate
   1.238 + * \param v         vector to fill in
   1.239 + * \retval          M3G_TRUE get ok
   1.240 + * \retval          M3G_FALSE no such vertex
   1.241 + */
   1.242 +static M3Gbool m3gGetNormal(const VertexBuffer *buffer, M3Gint idx, M3GVec3 *v)
   1.243 +{
   1.244 +    return m3gGetCoordinates(buffer->normals, 3, idx, &v->x);
   1.245 +}
   1.246 +
   1.247 +/*!
   1.248 + * \internal
   1.249 + * \brief Gets a texture coordinate, used in pick routines.
   1.250 + * Scale and bias are applied to the coordinates.
   1.251 + *
   1.252 + * \param buffer    VertexBuffer object
   1.253 + * \param idx       index of coordinate
   1.254 + * \param unit      texturing unit
   1.255 + * \param v         vector to fill in
   1.256 + * \retval          M3G_TRUE get ok
   1.257 + * \retval          M3G_FALSE no such vertex
   1.258 + */
   1.259 +static M3Gbool m3gGetTexCoord(const VertexBuffer *buffer, M3Gint idx, M3Gint unit, M3GVec3 *v)
   1.260 +{
   1.261 +    M3Gbool res;
   1.262 +    res = m3gGetCoordinates(buffer->texCoords[unit], 2, idx, &v->x);
   1.263 +
   1.264 +    v->x = m3gMul(v->x, buffer->texCoordScale[unit]);
   1.265 +    v->y = m3gMul(v->y, buffer->texCoordScale[unit]);
   1.266 +
   1.267 +    v->x = m3gAdd(v->x, buffer->texCoordBias[unit][0]);
   1.268 +    v->y = m3gAdd(v->y, buffer->texCoordBias[unit][1]);
   1.269 +
   1.270 +    v->z = 0.f;
   1.271 +
   1.272 +    return res;
   1.273 +}
   1.274 +
   1.275 +/*!
   1.276 + * \internal
   1.277 + * \brief Gets vertex buffer positions bounding box.
   1.278 + *
   1.279 + * The bounding box is returned as floats, with scale and bias
   1.280 + * applied.
   1.281 + *
   1.282 + * \param buffer        VertexBuffer object
   1.283 + * \param boundingBox   bounding box float array
   1.284 + */
   1.285 +static void m3gGetBoundingBox(VertexBuffer *vb, AABB *boundingBox)
   1.286 +{
   1.287 +    /* If timestamp is changed, refresh bounding box */
   1.288 +    
   1.289 +    if (vb->vertices && (m3gGetArrayTimestamp(vb->vertices)
   1.290 +                         != vb->verticesTimestamp)) {
   1.291 +        M3Gshort ab[6];
   1.292 +        vb->verticesTimestamp = m3gGetArrayTimestamp(vb->vertices);
   1.293 +        m3gGetArrayBoundingBox(vb->vertices, ab);
   1.294 +        
   1.295 +        vb->bbox.min[0] = m3gMadd(ab[0], vb->vertexScale, vb->vertexBias[0]);
   1.296 +        vb->bbox.min[1] = m3gMadd(ab[1], vb->vertexScale, vb->vertexBias[1]);
   1.297 +        vb->bbox.min[2] = m3gMadd(ab[2], vb->vertexScale, vb->vertexBias[2]);
   1.298 +        vb->bbox.max[0] = m3gMadd(ab[3], vb->vertexScale, vb->vertexBias[0]);
   1.299 +        vb->bbox.max[1] = m3gMadd(ab[4], vb->vertexScale, vb->vertexBias[1]);
   1.300 +        vb->bbox.max[2] = m3gMadd(ab[5], vb->vertexScale, vb->vertexBias[2]);
   1.301 +
   1.302 +        /* Flip the bounding box if the scale was negative */
   1.303 +        
   1.304 +        if (vb->vertexScale < 0) {
   1.305 +            M3Gint i;
   1.306 +            for (i = 0; i < 3; ++i) {
   1.307 +                M3Gfloat t = vb->bbox.min[i];
   1.308 +                vb->bbox.min[i] = vb->bbox.max[i];
   1.309 +                vb->bbox.max[i] = t;
   1.310 +            }
   1.311 +        }
   1.312 +    }
   1.313 +    *boundingBox = vb->bbox;
   1.314 +}
   1.315 +
   1.316 +/*!
   1.317 + * \internal
   1.318 + * \brief Gets vertex buffer timestamp.
   1.319 + *
   1.320 + * \param buffer        VertexBuffer object
   1.321 + * \return timestamp
   1.322 + */
   1.323 +static M3Gint m3gGetTimestamp(const VertexBuffer *buffer)
   1.324 +{
   1.325 +    if (buffer->vertices &&
   1.326 +        m3gGetArrayTimestamp(buffer->vertices) != buffer->verticesTimestamp) {
   1.327 +        return buffer->timestamp + 1;
   1.328 +    }
   1.329 +    return buffer->timestamp;
   1.330 +}
   1.331 +
   1.332 +/**
   1.333 + * Updates the vertex count bookkeeping when setting vertex
   1.334 + * arrays.
   1.335 + *
   1.336 + * \param buffer        VertexBuffer object
   1.337 + * \param oldArray      VertexArray object
   1.338 + * \param newArray      VertexArray object
   1.339 + * \param maskBit       array mask bit
   1.340 + */
   1.341 +static void m3gUpdateArray(VertexBuffer *buffer,
   1.342 +                           VertexArray *oldArray,
   1.343 +                           VertexArray *newArray,
   1.344 +                           M3Gbitmask maskBit)
   1.345 +{
   1.346 +    M3Gint change = (oldArray == NULL && newArray != NULL) ?  1 :
   1.347 +        (oldArray != NULL && newArray == NULL) ? -1 :
   1.348 +        0;
   1.349 +
   1.350 +    /* If adding or replacing an array, set the initial vertex count,
   1.351 +     * or compare the new array against the current vertex count */
   1.352 +    
   1.353 +    if (newArray != NULL) {
   1.354 +    	if (buffer->arrayCount == 0 || (buffer->arrayCount == 1
   1.355 +                                        && change == 0)) {
   1.356 +    		buffer->vertexCount = m3gGetArrayVertexCount(newArray);
   1.357 +    	}
   1.358 +    	else if (m3gGetArrayVertexCount(newArray) != buffer->vertexCount) {
   1.359 +            m3gRaiseError(M3G_INTERFACE(buffer), M3G_INVALID_VALUE);
   1.360 +            return;
   1.361 +    	}
   1.362 +    }
   1.363 +
   1.364 +    /* Update the array bitmask */
   1.365 +    
   1.366 +    if (newArray != NULL) {
   1.367 +        buffer->arrayMask |= maskBit;
   1.368 +    }
   1.369 +    else {
   1.370 +        buffer->arrayMask &= ~maskBit;
   1.371 +    }
   1.372 +
   1.373 +    /* Update the array count, and reset the vertex count to zero if
   1.374 +     * no arrays remain */
   1.375 +    
   1.376 +    buffer->arrayCount += change;
   1.377 +    if (buffer->arrayCount == 0) {
   1.378 +        M3G_ASSERT(buffer->arrayMask == 0);
   1.379 +        buffer->vertexCount = 0;
   1.380 +    }
   1.381 +}
   1.382 +
   1.383 +/*!
   1.384 + * \internal
   1.385 + * \brief Overloaded Object3D method
   1.386 + *
   1.387 + * \param self VertexBuffer object
   1.388 + * \param references array of reference objects
   1.389 + * \return number of references
   1.390 + */
   1.391 +static M3Gint m3gVertexBufferDoGetReferences(Object *self, Object **references)
   1.392 +{
   1.393 +    VertexBuffer *vb = (VertexBuffer *)self;
   1.394 +    M3Gint i, num = m3gObjectDoGetReferences(self, references);
   1.395 +    if (vb->vertices != NULL) {
   1.396 +        if (references != NULL)
   1.397 +            references[num] = (Object *)vb->vertices;
   1.398 +        num++;
   1.399 +    }
   1.400 +    if (vb->normals != NULL) {
   1.401 +        if (references != NULL)
   1.402 +            references[num] = (Object *)vb->normals;
   1.403 +        num++;
   1.404 +    }
   1.405 +    if (vb->colors != NULL) {
   1.406 +        if (references != NULL)
   1.407 +            references[num] = (Object *)vb->colors;
   1.408 +        num++;
   1.409 +    }
   1.410 +    for (i = 0; i < M3G_NUM_TEXTURE_UNITS; i++) {
   1.411 +        if (vb->texCoords[i] != NULL) {
   1.412 +            if (references != NULL)
   1.413 +                references[num] = (Object *)vb->texCoords[i];
   1.414 +            num++;
   1.415 +        }
   1.416 +    }
   1.417 +    return num;
   1.418 +}
   1.419 +
   1.420 +/*!
   1.421 + * \internal
   1.422 + * \brief Overloaded Object3D method
   1.423 + */
   1.424 +static Object *m3gVertexBufferFindID(Object *self, M3Gint userID)
   1.425 +{
   1.426 +    int i;
   1.427 +    VertexBuffer *vb = (VertexBuffer *)self;
   1.428 +    Object *found = m3gObjectFindID(self, userID);
   1.429 +    
   1.430 +    if (!found && vb->vertices != NULL) {
   1.431 +        found = m3gFindID((Object*) vb->vertices, userID);
   1.432 +    }
   1.433 +    if (!found && vb->normals != NULL) {
   1.434 +        found = m3gFindID((Object*) vb->normals, userID);
   1.435 +    }
   1.436 +    if (!found && vb->colors != NULL) {
   1.437 +        found = m3gFindID((Object*) vb->colors, userID);
   1.438 +    }
   1.439 +    for (i = 0; !found && i < M3G_NUM_TEXTURE_UNITS; ++i) {
   1.440 +        if (vb->texCoords[i] != NULL) {
   1.441 +            found = m3gFindID((Object*) vb->texCoords[i], userID);
   1.442 +        }
   1.443 +    }
   1.444 +    return found;
   1.445 +}
   1.446 +
   1.447 +/*!
   1.448 + * \internal
   1.449 + * \brief Duplicates vertex buffer data and array configuration
   1.450 + */
   1.451 +static void m3gDuplicateVertexBufferData(VertexBuffer *clone,
   1.452 +                                         const VertexBuffer *original)
   1.453 +{
   1.454 +    M3Gint i;
   1.455 +    
   1.456 +    clone->vertexScale = original->vertexScale;
   1.457 +    m3gCopy(clone->vertexBias, original->vertexBias, 3 * sizeof(GLfloat));
   1.458 +    clone->defaultColor = original->defaultColor;
   1.459 +    clone->locked = original->locked;
   1.460 +    clone->vertexCount = original->vertexCount;
   1.461 +    clone->arrayCount = original->arrayCount;
   1.462 +    clone->arrayMask = original->arrayMask;
   1.463 +    clone->timestamp = original->timestamp;
   1.464 +    
   1.465 +    for (i = 0; i < M3G_NUM_TEXTURE_UNITS; i++) {
   1.466 +        clone->texCoordScale[i] = original->texCoordScale[i];
   1.467 +        clone->texCoordBias[i][0] = original->texCoordBias[i][0];
   1.468 +        clone->texCoordBias[i][1] = original->texCoordBias[i][1];
   1.469 +        clone->texCoordBias[i][2] = original->texCoordBias[i][2];
   1.470 +        M3G_ASSIGN_REF(clone->texCoords[i], original->texCoords[i]);
   1.471 +    }
   1.472 +    M3G_ASSIGN_REF(clone->colors, original->colors);
   1.473 +    M3G_ASSIGN_REF(clone->normals, original->normals);
   1.474 +    M3G_ASSIGN_REF(clone->vertices, original->vertices);
   1.475 +}
   1.476 +
   1.477 +/*!
   1.478 + * \internal
   1.479 + * \brief Overloaded Object3D method
   1.480 + *
   1.481 + * \param originalObj original VertexBuffer object
   1.482 + * \param cloneObj pointer to cloned VertexBuffer object
   1.483 + * \param pairs array for all object-duplicate pairs
   1.484 + * \param numPairs number of pairs
   1.485 + */
   1.486 +static M3Gbool m3gVertexBufferDuplicate(const Object *originalObj,
   1.487 +                                        Object **cloneObj,
   1.488 +                                        Object **pairs,
   1.489 +                                        M3Gint *numPairs)
   1.490 +{
   1.491 +    VertexBuffer *original = (VertexBuffer*) originalObj;
   1.492 +    VertexBuffer *clone;
   1.493 +    M3G_ASSERT(*cloneObj == NULL); /* no derived classes */
   1.494 +
   1.495 +    /* Create the clone object */
   1.496 +    
   1.497 +    clone = (VertexBuffer*) m3gCreateVertexBuffer(originalObj->interface);
   1.498 +    if (!clone) {
   1.499 +        return M3G_FALSE;
   1.500 +    }
   1.501 +    *cloneObj = (Object *)clone;
   1.502 +
   1.503 +    /* Duplicate base class data */
   1.504 +    
   1.505 +    if (!m3gObjectDuplicate(originalObj, cloneObj, pairs, numPairs)) {
   1.506 +        return M3G_FALSE;
   1.507 +    }
   1.508 +
   1.509 +    /* Duplicate our own data */
   1.510 +
   1.511 +    m3gDuplicateVertexBufferData(clone, original);
   1.512 +    return M3G_TRUE;
   1.513 +}
   1.514 +
   1.515 +/*!
   1.516 + * \internal
   1.517 + * \brief Overloaded Object3D method.
   1.518 + *
   1.519 + * \param property      animation property
   1.520 + * \retval M3G_TRUE     property supported
   1.521 + * \retval M3G_FALSE    property not supported
   1.522 + */
   1.523 +static M3Gbool m3gVertexBufferIsCompatible(M3Gint property)
   1.524 +{
   1.525 +    switch (property) {
   1.526 +    case M3G_ANIM_ALPHA:
   1.527 +    case M3G_ANIM_COLOR:
   1.528 +        return M3G_TRUE;
   1.529 +    default:
   1.530 +        return m3gObjectIsCompatible(property);
   1.531 +    }
   1.532 +}
   1.533 +
   1.534 +/*!
   1.535 + * \internal
   1.536 + * \brief Overloaded Object3D method
   1.537 + *
   1.538 + * \param self          VertexBuffer object
   1.539 + * \param property      animation property
   1.540 + * \param valueSize     size of value array
   1.541 + * \param value         value array
   1.542 + */
   1.543 +static void m3gVertexBufferUpdateProperty(Object *self,
   1.544 +                                          M3Gint property,
   1.545 +                                          M3Gint valueSize,
   1.546 +                                          const M3Gfloat *value)
   1.547 +{
   1.548 +    VertexBuffer *buffer = (VertexBuffer *) self;
   1.549 +    M3G_VALIDATE_OBJECT(buffer);
   1.550 +    M3G_ASSERT_PTR(value);
   1.551 +
   1.552 +    switch (property) {
   1.553 +    case M3G_ANIM_ALPHA:
   1.554 +        M3G_ASSERT(valueSize >= 1);
   1.555 +        buffer->defaultColor.a =
   1.556 +            (GLubyte)m3gAdd(m3gMul(255.f, m3gClampFloat(value[0], 0.f, 1.f)), 0.5f);
   1.557 +        break;
   1.558 +    case M3G_ANIM_COLOR:
   1.559 +        M3G_ASSERT(valueSize >= 3);
   1.560 +        buffer->defaultColor.r =
   1.561 +            (GLubyte)m3gAdd(m3gMul(255.f, m3gClampFloat(value[0], 0.f, 1.f)), 0.5f);
   1.562 +        buffer->defaultColor.g =
   1.563 +            (GLubyte)m3gAdd(m3gMul(255.f, m3gClampFloat(value[1], 0.f, 1.f)), 0.5f);
   1.564 +        buffer->defaultColor.b =
   1.565 +            (GLubyte)m3gAdd(m3gMul(255.f, m3gClampFloat(value[2], 0.f, 1.f)), 0.5f);
   1.566 +        break;
   1.567 +    default:
   1.568 +        m3gObjectUpdateProperty(self, property, valueSize, value);
   1.569 +    }
   1.570 +}
   1.571 +
   1.572 +/*!
   1.573 + * \internal
   1.574 + * \brief Checks that a vertex buffer can be properly rendered
   1.575 + *
   1.576 + * The vertex format required by \c app is compared against the vertex
   1.577 + * arrays included in \c vb, and \c vb is checked to have at least \c
   1.578 + * maxIndex vertex entries.
   1.579 + *
   1.580 + * \param vb        VertexBuffer object
   1.581 + * \param app       Appearance object
   1.582 + * \param maxIndex  maximum index in index buffer
   1.583 + * \retval M3G_TRUE  valid state
   1.584 + * \retval M3G_FALSE invalid state
   1.585 + */
   1.586 +static M3Gbool m3gValidateVertexBuffer(const VertexBuffer *vb,
   1.587 +                                       const Appearance *app,
   1.588 +                                       M3Gsizei maxIndex)
   1.589 +{
   1.590 +    M3Gbitmask reqMask;
   1.591 +    M3G_UNREF(app);
   1.592 +    reqMask = M3G_POSITION_BIT;
   1.593 +    if ((m3gGetArrayMask(vb) & reqMask) != reqMask) {
   1.594 +        return M3G_FALSE;
   1.595 +    }
   1.596 +    return (m3gGetNumVertices(vb) > maxIndex);
   1.597 +}
   1.598 +
   1.599 +/*!
   1.600 + * \internal
   1.601 + * \brief Sets a vertex buffer up for subsequent vertex modification
   1.602 + *
   1.603 + * A specified subset of the arrays of \c srcBuffer will be replicated
   1.604 + * in \c buffer, without copying the contents.  The others will be
   1.605 + * copied as references only.
   1.606 + *
   1.607 + * \param buffer       the modified buffer
   1.608 + * \param srcBuffer    the source buffer
   1.609 + * \param arrayMask    bitmask of arrays to modify
   1.610 + * \param createArrays M3G_TRUE to create the arrays specified by
   1.611 + *                     \c arrayMask, M3G_FALSE to leave them NULL
   1.612 + * \retval M3G_TRUE success
   1.613 + * \retval M3G_FALSE out of memory
   1.614 + */
   1.615 +static M3Gbool m3gMakeModifiedVertexBuffer(VertexBuffer *buffer,
   1.616 +                                           const VertexBuffer *srcBuffer,
   1.617 +                                           M3Gbitmask arrayMask,
   1.618 +                                           M3Gbool createArrays)
   1.619 +{
   1.620 +    M3G_VALIDATE_OBJECT(buffer);
   1.621 +    M3G_VALIDATE_OBJECT(srcBuffer);
   1.622 +    {
   1.623 +        Interface *m3g = M3G_INTERFACE(buffer);
   1.624 +        VertexArray *array;
   1.625 +        int i;
   1.626 +
   1.627 +        /* First, just copy the data from the other buffer */
   1.628 +
   1.629 +        m3gDuplicateVertexBufferData(buffer, srcBuffer);
   1.630 +        
   1.631 +        /* Now, override the specified arrays: release the existing
   1.632 +         * array, and either allocate a new one or leave as NULL,
   1.633 +         * depending on the value of the createArrays flag */
   1.634 +
   1.635 +#       define MODIFY_ARRAY(bit, name)                          \
   1.636 +            if (arrayMask & (bit)) {                            \
   1.637 +                array = NULL;                                   \
   1.638 +                if (srcBuffer->name && createArrays) {          \
   1.639 +                    array = m3gCreateVertexArray(               \
   1.640 +                        m3g,                                    \
   1.641 +                        srcBuffer->name->vertexCount,           \
   1.642 +                        srcBuffer->name->elementSize,           \
   1.643 +                        srcBuffer->name->elementType == GL_SHORT ? M3G_SHORT : M3G_BYTE); \
   1.644 +                    if (!array) {                               \
   1.645 +                        return M3G_FALSE;                       \
   1.646 +                    }                                           \
   1.647 +                }                                               \
   1.648 +                m3gUpdateArray(buffer, buffer->name, array, bit); \
   1.649 +                M3G_ASSIGN_REF(buffer->name, array);            \
   1.650 +            }
   1.651 +
   1.652 +        MODIFY_ARRAY(M3G_POSITION_BIT, vertices);
   1.653 +        MODIFY_ARRAY(M3G_COLOR_BIT, colors);
   1.654 +        MODIFY_ARRAY(M3G_NORMAL_BIT, normals);
   1.655 +        
   1.656 +        for (i = 0; i < M3G_NUM_TEXTURE_UNITS; ++i) {
   1.657 +            MODIFY_ARRAY(M3G_TEXCOORD0_BIT << i, texCoords[i]);
   1.658 +        }
   1.659 +
   1.660 +#       undef MODIFY_ARRAY
   1.661 +
   1.662 +        return M3G_TRUE;
   1.663 +    }
   1.664 +}
   1.665 +
   1.666 +/*----------------------------------------------------------------------
   1.667 + * Virtual function table
   1.668 + *--------------------------------------------------------------------*/
   1.669 +
   1.670 +static const ObjectVFTable m3gvf_VertexBuffer = {
   1.671 +    m3gObjectApplyAnimation,
   1.672 +    m3gVertexBufferIsCompatible,
   1.673 +    m3gVertexBufferUpdateProperty,
   1.674 +    m3gVertexBufferDoGetReferences,
   1.675 +    m3gVertexBufferFindID,
   1.676 +    m3gVertexBufferDuplicate,
   1.677 +    m3gDestroyVertexBuffer
   1.678 +};
   1.679 +
   1.680 +
   1.681 +/*----------------------------------------------------------------------
   1.682 + * Public API functions
   1.683 + *--------------------------------------------------------------------*/
   1.684 +
   1.685 +/*!
   1.686 + * \brief Creates an empty vertex buffer
   1.687 + *
   1.688 + * \param interface    M3G interface
   1.689 + * \retval VertexBuffer new VertexBuffer object
   1.690 + * \retval NULL VertexBuffer creating failed
   1.691 + */
   1.692 +/*@access M3Ginterface@*/
   1.693 +/*@access M3Gobject@*/
   1.694 +M3G_API M3GVertexBuffer m3gCreateVertexBuffer(M3GInterface interface)
   1.695 +{
   1.696 +    Interface *m3g = (Interface *) interface;
   1.697 +    M3G_VALIDATE_INTERFACE(m3g);
   1.698 +    
   1.699 +    {
   1.700 +        VertexBuffer *buffer = m3gAllocZ(m3g, sizeof(VertexBuffer));
   1.701 +
   1.702 +        if (buffer != NULL) {
   1.703 +            m3gInitObject(&buffer->object, m3g, M3G_CLASS_VERTEX_BUFFER);
   1.704 +        
   1.705 +            /* Set default color to white */
   1.706 +            buffer->defaultColor.r = (GLubyte) 0xFF;
   1.707 +            buffer->defaultColor.g = (GLubyte) 0xFF;
   1.708 +            buffer->defaultColor.b = (GLubyte) 0xFF;
   1.709 +            buffer->defaultColor.a = (GLubyte) 0xFF;
   1.710 +        }
   1.711 +
   1.712 +        return (M3GVertexBuffer) buffer;
   1.713 +    }
   1.714 +}
   1.715 +
   1.716 +/*!
   1.717 + * \brief Sets the color array of a vertex buffer
   1.718 + *
   1.719 + * \param hBuffer   VertexBuffer object
   1.720 + * \param hArray    VertexArray object
   1.721 + */
   1.722 +/*@access M3Gobject@*/
   1.723 +M3G_API void m3gSetColorArray(M3GVertexBuffer hBuffer, M3GVertexArray hArray)
   1.724 +{
   1.725 +    VertexBuffer *buffer = (VertexBuffer *) hBuffer;
   1.726 +    VertexArray *array = (VertexArray *) hArray;
   1.727 +    M3G_VALIDATE_OBJECT(buffer);
   1.728 +    
   1.729 +    if (array != NULL) {
   1.730 +        M3G_VALIDATE_OBJECT(array);
   1.731 +
   1.732 +        /* Check for errors */
   1.733 +        if (!m3gInRange(array->elementSize, 3, 4) ||
   1.734 +            array->elementType != M3G_GLTYPE(M3G_BYTE)) {
   1.735 +            m3gRaiseError(M3G_INTERFACE(array), M3G_INVALID_VALUE);
   1.736 +            return;
   1.737 +        }
   1.738 +    }
   1.739 +    
   1.740 +    m3gUpdateArray(buffer, buffer->colors, array, M3G_COLOR_BIT);
   1.741 +    M3G_ASSIGN_REF(buffer->colors, array);
   1.742 +    ++buffer->timestamp;
   1.743 +}
   1.744 +
   1.745 +/*!
   1.746 + * \brief Sets the normal array of a vertex buffer
   1.747 + *
   1.748 + * \param hBuffer   VertexBuffer object
   1.749 + * \param hArray    VertexArray object
   1.750 + */
   1.751 +/*@access M3Gobject@*/
   1.752 +M3G_API void m3gSetNormalArray(M3GVertexBuffer hBuffer, M3GVertexArray hArray)
   1.753 +{
   1.754 +    VertexBuffer *buffer = (VertexBuffer *) hBuffer;
   1.755 +    VertexArray *array = (VertexArray *) hArray;
   1.756 +    M3G_VALIDATE_OBJECT(buffer);
   1.757 +    if (array != NULL) {
   1.758 +        M3G_VALIDATE_OBJECT(array);
   1.759 +
   1.760 +        /* Check for errors */
   1.761 +        if (array->elementSize != 3) {
   1.762 +            m3gRaiseError(M3G_INTERFACE(array), M3G_INVALID_VALUE);
   1.763 +            return;
   1.764 +        }
   1.765 +    }
   1.766 +    
   1.767 +    m3gUpdateArray(buffer, buffer->normals, array, M3G_NORMAL_BIT);
   1.768 +    M3G_ASSIGN_REF(buffer->normals, array);
   1.769 +    ++buffer->timestamp;
   1.770 +}
   1.771 +
   1.772 +/*!
   1.773 + * \brief Sets the texture coordinate array of a vertex buffer
   1.774 + *
   1.775 + * \param hBuffer   VertexBuffer object
   1.776 + * \param unit      texturing unit
   1.777 + * \param hArray    VertexArray object
   1.778 + * \param scale     scale
   1.779 + * \param bias      bias array
   1.780 + * \param biasLength bias array length
   1.781 + */
   1.782 +/*@access M3Gobject@*/
   1.783 +M3G_API void m3gSetTexCoordArray(M3GVertexBuffer hBuffer,
   1.784 +                                 M3Gint unit,
   1.785 +                                 M3GVertexArray hArray,
   1.786 +                                 M3Gfloat scale, M3Gfloat *bias,
   1.787 +                                 M3Gint biasLength)
   1.788 +{
   1.789 +    VertexBuffer *buffer = (VertexBuffer *) hBuffer;
   1.790 +    VertexArray *array = (VertexArray *) hArray;
   1.791 +
   1.792 +    M3G_VALIDATE_OBJECT(buffer);
   1.793 +    if (array != NULL) {
   1.794 +        M3G_VALIDATE_OBJECT(array);
   1.795 +    }
   1.796 +
   1.797 +    /* Check errors */
   1.798 +    
   1.799 +    if (unit < 0 || unit >= M3G_NUM_TEXTURE_UNITS) {
   1.800 +        m3gRaiseError(M3G_INTERFACE(buffer), M3G_INVALID_INDEX);
   1.801 +        return;
   1.802 +    }
   1.803 +
   1.804 +    if (array != NULL) {
   1.805 +        if (array->elementSize != 2 && array->elementSize != 3) {
   1.806 +            m3gRaiseError(M3G_INTERFACE(buffer), M3G_INVALID_VALUE);
   1.807 +            return;
   1.808 +        }
   1.809 +        if (bias != NULL && biasLength < array->elementSize) {
   1.810 +            m3gRaiseError(M3G_INTERFACE(buffer), M3G_INVALID_VALUE);
   1.811 +            return;
   1.812 +        }
   1.813 +    }
   1.814 +
   1.815 +    m3gUpdateArray(buffer, buffer->texCoords[unit], array, M3G_TEXCOORD0_BIT << unit);
   1.816 +    M3G_ASSIGN_REF(buffer->texCoords[unit], array);
   1.817 +
   1.818 +    if (array != NULL && bias != NULL) {
   1.819 +        buffer->texCoordBias[unit][0] = bias[0];
   1.820 +        buffer->texCoordBias[unit][1] = bias[1];
   1.821 +        if (biasLength > 2) {
   1.822 +            buffer->texCoordBias[unit][2] = bias[2];
   1.823 +        }
   1.824 +    }
   1.825 +    else {
   1.826 +        buffer->texCoordBias[unit][0] = 0.f;
   1.827 +        buffer->texCoordBias[unit][1] = 0.f;
   1.828 +        buffer->texCoordBias[unit][2] = 0.f;
   1.829 +    }
   1.830 +
   1.831 +    buffer->texCoordScale[unit] = scale;
   1.832 +
   1.833 +    ++buffer->timestamp;
   1.834 +}
   1.835 +
   1.836 +/*!
   1.837 + * \brief Sets the vertex array of a vertex buffer
   1.838 + *
   1.839 + * \param hBuffer   VertexBuffer object
   1.840 + * \param hArray    VertexArray object
   1.841 + * \param scale     scale
   1.842 + * \param bias      bias array
   1.843 + * \param biasLength bias array length
   1.844 + */
   1.845 +/*@access M3Gobject@*/
   1.846 +M3G_API void m3gSetVertexArray(M3GVertexBuffer hBuffer,
   1.847 +                               M3GVertexArray hArray,
   1.848 +                               M3Gfloat scale,
   1.849 +                               M3Gfloat *bias, M3Gint biasLength)
   1.850 +{
   1.851 +    VertexBuffer *buffer = (VertexBuffer *) hBuffer;
   1.852 +    VertexArray *array = (VertexArray *) hArray;
   1.853 +    M3G_VALIDATE_OBJECT(buffer);
   1.854 +    if (array != NULL) {
   1.855 +        M3G_VALIDATE_OBJECT(array);
   1.856 +    }
   1.857 +
   1.858 +    if (array != NULL && array->elementSize != 3) {
   1.859 +        m3gRaiseError(M3G_INTERFACE(buffer), M3G_INVALID_VALUE);
   1.860 +        return;
   1.861 +    }
   1.862 +
   1.863 +    if (array != NULL && bias != NULL && biasLength < 3) {
   1.864 +        m3gRaiseError(M3G_INTERFACE(buffer), M3G_INVALID_VALUE);
   1.865 +        return;
   1.866 +    }
   1.867 +
   1.868 +    m3gUpdateArray(buffer, buffer->vertices, array, M3G_POSITION_BIT);
   1.869 +    M3G_ASSIGN_REF(buffer->vertices, array);
   1.870 +
   1.871 +    if (array != NULL && bias != NULL) {
   1.872 +        buffer->vertexBias[0] = bias[0];
   1.873 +        buffer->vertexBias[1] = bias[1];
   1.874 +        buffer->vertexBias[2] = bias[2];
   1.875 +    }
   1.876 +    else {
   1.877 +        buffer->vertexBias[0] = 0.f;
   1.878 +        buffer->vertexBias[1] = 0.f;
   1.879 +        buffer->vertexBias[2] = 0.f;
   1.880 +    }
   1.881 +    buffer->vertexScale = scale;
   1.882 +
   1.883 +    /* Make sure we invalidate the cached bounding box */
   1.884 +    
   1.885 +    ++buffer->timestamp;
   1.886 +    if (array != NULL) {
   1.887 +        buffer->verticesTimestamp = ~m3gGetArrayTimestamp(array); /*lint !e502 ok for signed */
   1.888 +    }
   1.889 +}
   1.890 +
   1.891 +/*!
   1.892 + * \brief Sets the default color of a vertex buffer
   1.893 + *
   1.894 + * \param handle    VertexBuffer object
   1.895 + * \param ARGB      default color as ARGB
   1.896 + */
   1.897 +/*@access M3Gobject@*/
   1.898 +
   1.899 +M3G_API void m3gSetVertexDefaultColor(M3GVertexBuffer handle, M3Guint ARGB)
   1.900 +{
   1.901 +    VertexBuffer *buffer = (VertexBuffer *) handle;
   1.902 +    M3G_VALIDATE_OBJECT(buffer);    
   1.903 +
   1.904 +    buffer->defaultColor.b = (GLubyte)(ARGB);
   1.905 +    buffer->defaultColor.g = (GLubyte)(ARGB >> 8);
   1.906 +    buffer->defaultColor.r = (GLubyte)(ARGB >> 16);
   1.907 +    buffer->defaultColor.a = (GLubyte)(ARGB >> 24);
   1.908 +    ++buffer->timestamp;
   1.909 +}
   1.910 +
   1.911 +/*!
   1.912 + * \brief Gets the default color of a vertex buffer
   1.913 + * \param handle    VertexBuffer object
   1.914 + * \return          default color as ARGB
   1.915 + */
   1.916 +/*@access M3Gobject@*/
   1.917 +
   1.918 +M3G_API M3Guint m3gGetVertexDefaultColor(M3GVertexBuffer handle)
   1.919 +{
   1.920 +	unsigned ARGB;
   1.921 +    VertexBuffer *buffer = (VertexBuffer *) handle;
   1.922 +    M3G_VALIDATE_OBJECT(buffer);    
   1.923 +
   1.924 +	ARGB = buffer->defaultColor.a;
   1.925 +	ARGB <<= 8;
   1.926 +	ARGB |= buffer->defaultColor.r;
   1.927 +	ARGB <<= 8;
   1.928 +	ARGB |= buffer->defaultColor.g;
   1.929 +	ARGB <<= 8;
   1.930 +	ARGB |= buffer->defaultColor.b;
   1.931 +
   1.932 +	return ARGB;
   1.933 +}
   1.934 +
   1.935 +/*!
   1.936 + * \brief Gets vertex array of a vertex buffer
   1.937 + *
   1.938 + * \param handle    VertexBuffer object
   1.939 + * \param which     which array to get
   1.940 + *                  \arg M3G_GET_POSITIONS
   1.941 + *                  \arg M3G_GET_NORMALS
   1.942 + *                  \arg M3G_GET_COLORS
   1.943 + *                  \arg M3G_GET_TEXCOORDS0
   1.944 + *                  \arg M3G_GET_TEXCOORDS0 + 1
   1.945 + * \param scaleBias array for scale and bias (s, bx, by, bz)
   1.946 + * \param sbLength  length of scale bias array
   1.947 + */
   1.948 +
   1.949 +/*@access M3Gobject@*/
   1.950 +M3G_API M3GVertexArray m3gGetVertexArray(M3GVertexBuffer handle,
   1.951 +                                         M3Gint which,
   1.952 +                                         M3Gfloat *scaleBias, M3Gint sbLength)
   1.953 +{
   1.954 +    M3Gint tci = 1;
   1.955 +    VertexBuffer *buffer = (VertexBuffer *) handle;
   1.956 +    M3G_VALIDATE_OBJECT(buffer);
   1.957 +
   1.958 +    switch(which) {
   1.959 +    case M3G_GET_POSITIONS:
   1.960 +        if (scaleBias != NULL && sbLength < 4) {
   1.961 +            m3gRaiseError(M3G_INTERFACE(buffer), M3G_INVALID_VALUE);
   1.962 +            return 0;
   1.963 +        }
   1.964 +
   1.965 +        if (scaleBias != NULL) {
   1.966 +            scaleBias[0] = buffer->vertexScale;
   1.967 +            scaleBias[1] = buffer->vertexBias[0];
   1.968 +            scaleBias[2] = buffer->vertexBias[1];
   1.969 +            scaleBias[3] = buffer->vertexBias[2];
   1.970 +        }
   1.971 +        return buffer->vertices;
   1.972 +    case M3G_GET_NORMALS: return buffer->normals;
   1.973 +    case M3G_GET_COLORS:  return buffer->colors;
   1.974 +    case M3G_GET_TEXCOORDS0:
   1.975 +        --tci;
   1.976 +        /* Flow through */
   1.977 +    case M3G_GET_TEXCOORDS0 + 1:
   1.978 +        if (buffer->texCoords[tci] != NULL) {
   1.979 +            if (scaleBias != NULL && sbLength < (buffer->texCoords[tci]->elementSize + 1)) {
   1.980 +                m3gRaiseError(M3G_INTERFACE(buffer), M3G_INVALID_VALUE);
   1.981 +                return 0;
   1.982 +            }
   1.983 +    
   1.984 +            if (scaleBias != NULL) {
   1.985 +                scaleBias[0] = buffer->texCoordScale[tci];
   1.986 +                scaleBias[1] = buffer->texCoordBias[tci][0];
   1.987 +                scaleBias[2] = buffer->texCoordBias[tci][1];
   1.988 +                if (buffer->texCoords[tci]->elementSize > 2) {
   1.989 +                    scaleBias[3] = buffer->texCoordBias[tci][2];
   1.990 +                }
   1.991 +            }
   1.992 +        }
   1.993 +        return buffer->texCoords[tci];
   1.994 +    default:
   1.995 +        m3gRaiseError(M3G_INTERFACE(buffer), M3G_INVALID_VALUE);
   1.996 +        break;
   1.997 +    }
   1.998 +
   1.999 +    return 0; /* Error */
  1.1000 +}
  1.1001 +
  1.1002 +/*!
  1.1003 + * \brief Gets vertex count of a vertex buffer
  1.1004 + *
  1.1005 + * \param handle    VertexBuffer object
  1.1006 + * \return vertex count
  1.1007 + */
  1.1008 +
  1.1009 +/*@access M3Gobject@*/
  1.1010 +M3G_API M3Gint  m3gGetVertexCount(M3GVertexBuffer handle)
  1.1011 +{
  1.1012 +    VertexBuffer *buffer = (VertexBuffer *) handle;
  1.1013 +    M3G_VALIDATE_OBJECT(buffer);    
  1.1014 +
  1.1015 +    return buffer->vertexCount;    
  1.1016 +}
  1.1017 +