os/graphics/m3g/m3gcore11/src/m3g_vertexarray.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_vertexarray.c	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,1052 @@
     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: VertexArray implementation
    1.18 +*
    1.19 +*/
    1.20 +
    1.21 +
    1.22 +/*!
    1.23 + * \internal
    1.24 + * \file
    1.25 + * \brief VertexArray implementation
    1.26 + *
    1.27 + */
    1.28 +
    1.29 +#ifndef M3G_CORE_INCLUDE
    1.30 +#   error included by m3g_core.c; do not compile separately.
    1.31 +#endif
    1.32 +
    1.33 +#include "m3g_vertexarray.h"
    1.34 +
    1.35 +#define DIRTY_ALPHA_FACTOR (-1)
    1.36 +
    1.37 +/*----------------------------------------------------------------------
    1.38 + * Private functions
    1.39 + *--------------------------------------------------------------------*/
    1.40 +
    1.41 +/*!
    1.42 + * \internal
    1.43 + * \brief Signals that the contents of an array have changed
    1.44 + */
    1.45 +static M3G_INLINE void m3gInvalidateArray(VertexArray *array)
    1.46 +{
    1.47 +    array->cachedAlphaFactor = DIRTY_ALPHA_FACTOR;
    1.48 +    array->rangeMin = 1;
    1.49 +    array->rangeMax = 0;
    1.50 +    
    1.51 +    ++array->timestamp;
    1.52 +}
    1.53 +    
    1.54 +/*----------------------------------------------------------------------
    1.55 + * Internal functions
    1.56 + *--------------------------------------------------------------------*/
    1.57 +
    1.58 +/*!
    1.59 + * \internal
    1.60 + * \brief Destroys this VertexArray object.
    1.61 + *
    1.62 + * \param obj VertexArray object
    1.63 + */
    1.64 +static void m3gDestroyVertexArray(Object *obj)
    1.65 +{
    1.66 +    VertexArray *array = (VertexArray *) obj;
    1.67 +    M3G_VALIDATE_OBJECT(array);
    1.68 +    M3G_ASSERT(array->numLocks == 0);
    1.69 +    {
    1.70 +        Interface *m3g = M3G_INTERFACE(array);
    1.71 +        m3gFreeObject(m3g, array->data);
    1.72 +        m3gFreeObject(m3g, array->cachedColors);
    1.73 +    }
    1.74 +    m3gDestroyObject(&array->object);
    1.75 +}
    1.76 +
    1.77 +/*!
    1.78 + * \internal
    1.79 + * \brief Sends color array to OpenGL.
    1.80 + *
    1.81 + * \note Alpha scaling currently prevents an array from being used for
    1.82 + * anything else while it is being bound as a color array.
    1.83 + *
    1.84 + * \param array         VertexArray object
    1.85 + * \param alphaFactor   1.16 alpha factor in [0, 0x10000]
    1.86 + */
    1.87 +static void m3gLockColorArray(const VertexArray *array, M3Gint alphaFactor)
    1.88 +{
    1.89 +    Interface *m3g = M3G_INTERFACE(array);
    1.90 +    M3G_VALIDATE_OBJECT(array);
    1.91 +    M3G_ASSERT(!array->mapCount);
    1.92 +    M3G_ASSERT(array->numLocks == 0);
    1.93 +    M3G_ASSERT(m3gInRange(alphaFactor, 0, 0x10000));
    1.94 +
    1.95 +    /* With an alpha factor of 1.0, we can just load up the original data */
    1.96 +    
    1.97 +    if (alphaFactor >= 0x10000) {
    1.98 +        GLenum type = array->elementType;
    1.99 +        if (type >= GL_BYTE && type <= GL_UNSIGNED_SHORT) {
   1.100 +            type |= 0x01; /* force type to unsigned for GL */
   1.101 +        }
   1.102 +        glColorPointer(type == GL_UNSIGNED_BYTE ? 4 : array->elementSize,
   1.103 +                       type,
   1.104 +                       array->stride,
   1.105 +                       m3gMapObject(m3g, array->data));
   1.106 +    }
   1.107 +    else {
   1.108 +
   1.109 +        /* With a non-unit alpha factor, we may need to update the
   1.110 +         * cached pre-scaled colors. */
   1.111 +
   1.112 +        M3Gubyte* const cache = (M3Gubyte *)
   1.113 +            m3gMapObject(m3g, array->cachedColors);
   1.114 +            
   1.115 +        if (array->cachedAlphaFactor != alphaFactor) {
   1.116 +            M3Gubyte *dst = cache;
   1.117 +            int i, n;
   1.118 +
   1.119 +            M3G_VALIDATE_MEMBLOCK(cache);
   1.120 +            
   1.121 +            /* Scale the colors, converting from the source format */
   1.122 +
   1.123 +            n = array->vertexCount;
   1.124 +            
   1.125 +            /* Byte colors are always padded to 4 bytes per entry,
   1.126 +             * with the implicit alpha set to 0xFF for RGB colors, so
   1.127 +             * we can do a near-straight copy. */
   1.128 +            
   1.129 +            switch (array->elementType) {
   1.130 +            case GL_BYTE:
   1.131 +            case GL_UNSIGNED_BYTE:
   1.132 +            {   
   1.133 +                const M3Gubyte *src = (M3Gubyte *)m3gMapObject(m3g,
   1.134 +                                                               array->data);
   1.135 +                for (i = 0; i < n; ++i) {
   1.136 +                    *dst++ = *src++;
   1.137 +                    *dst++ = *src++;
   1.138 +                    *dst++ = *src++;
   1.139 +                    {
   1.140 +                        M3Guint tmp = *src++ * (M3Guint) alphaFactor;
   1.141 +                        *dst++ = (M3Gubyte)(tmp >> 16);
   1.142 +                    }
   1.143 +                }
   1.144 +                m3gUnmapObject(m3g, array->data);
   1.145 +                break;
   1.146 +            }
   1.147 +            default:
   1.148 +                M3G_ASSERT(M3G_FALSE);
   1.149 +            }
   1.150 +            
   1.151 +            ((VertexArray*)array)->cachedAlphaFactor = alphaFactor;
   1.152 +        }
   1.153 +        
   1.154 +        /* We now have the scaled colors in the cache, so just set the
   1.155 +         * pointer there */
   1.156 +        
   1.157 +        glColorPointer(4, GL_UNSIGNED_BYTE, 0, cache);
   1.158 +    }
   1.159 +    M3G_ASSERT_GL;
   1.160 +    
   1.161 +    ++((VertexArray*)array)->numLocks;
   1.162 +}
   1.163 +
   1.164 +/*!
   1.165 + * \internal
   1.166 + * \brief Creates the color cache required for alpha factors
   1.167 + */
   1.168 +static M3Gbool m3gCreateAlphaColorCache(VertexArray *array)
   1.169 +{
   1.170 +    M3G_VALIDATE_OBJECT(array);
   1.171 +    M3G_ASSERT(array->cachedColors == 0);
   1.172 +    
   1.173 +    /* There are always four bytes per color entry */
   1.174 +    
   1.175 +    array->cachedColors = m3gAllocObject(M3G_INTERFACE(array),
   1.176 +                                         4 * array->vertexCount);
   1.177 +    
   1.178 +    return (array->cachedColors != 0);
   1.179 +}
   1.180 +
   1.181 +/*!
   1.182 + * \internal
   1.183 + * \brief Sends normal array to OpenGL.
   1.184 + *
   1.185 + * \param array VertexArray object
   1.186 + */
   1.187 +static void m3gLockNormalArray(const VertexArray *array)
   1.188 +{
   1.189 +    M3G_VALIDATE_OBJECT(array);
   1.190 +    M3G_ASSERT(!array->mapCount);
   1.191 +
   1.192 +    glNormalPointer(array->elementType, array->stride,
   1.193 +                    m3gMapObject(M3G_INTERFACE(array), array->data));
   1.194 +    M3G_ASSERT_GL;
   1.195 +    
   1.196 +    ++((VertexArray*)array)->numLocks;
   1.197 +}
   1.198 +
   1.199 +/*!
   1.200 + * \internal
   1.201 + * \brief Sends texture coordinate array to OpenGL.
   1.202 + *
   1.203 + * \param array VertexArray object
   1.204 + */
   1.205 +static void m3gLockTexCoordArray(const VertexArray *array)
   1.206 +{
   1.207 +    M3G_VALIDATE_OBJECT(array);
   1.208 +    M3G_ASSERT(!array->mapCount);
   1.209 +
   1.210 +    glTexCoordPointer(array->elementSize,
   1.211 +                      array->elementType,
   1.212 +                      array->stride,
   1.213 +                      m3gMapObject(M3G_INTERFACE(array), array->data));
   1.214 +    M3G_ASSERT_GL;
   1.215 +    
   1.216 +    ++((VertexArray*)array)->numLocks;
   1.217 +}
   1.218 +
   1.219 +/*!
   1.220 + * \internal
   1.221 + * \brief Sends vertex array to OpenGL.
   1.222 + *
   1.223 + * \param array VertexArray object
   1.224 + */
   1.225 +static void m3gLockVertexArray(const VertexArray *array)
   1.226 +{
   1.227 +    M3G_VALIDATE_OBJECT(array);
   1.228 +    M3G_ASSERT(!array->mapCount);
   1.229 +
   1.230 +    glVertexPointer(array->elementSize,
   1.231 +                    array->elementType,
   1.232 +                    array->stride,
   1.233 +                    m3gMapObject(M3G_INTERFACE(array), array->data));
   1.234 +    M3G_ASSERT_GL;
   1.235 +    
   1.236 +    ++((VertexArray*)array)->numLocks;
   1.237 +}
   1.238 +
   1.239 +/*!
   1.240 + * \internal
   1.241 + * \brief Decreases array lock count.
   1.242 + *
   1.243 + * \param array VertexArray object
   1.244 + */
   1.245 +static void m3gUnlockArray(const VertexArray *array)
   1.246 +{
   1.247 +    M3G_VALIDATE_OBJECT(array);
   1.248 +    M3G_ASSERT(array->numLocks > 0);
   1.249 +    
   1.250 +    m3gUnmapObject(M3G_INTERFACE(array), array->data);
   1.251 +    
   1.252 +    --((VertexArray*)array)->numLocks;
   1.253 +}
   1.254 +
   1.255 +/*!
   1.256 + * \internal
   1.257 + * \brief Clones a VertexArray.
   1.258 + *
   1.259 + * Used by MorphingMesh.
   1.260 + *
   1.261 + * \param array VertexArray object
   1.262 + * \return cloned VertexArray object
   1.263 + *
   1.264 + */
   1.265 +static VertexArray *m3gCloneVertexArray(const VertexArray *array)
   1.266 +{
   1.267 +	VertexArray *clone;
   1.268 +	Interface *m3g = M3G_INTERFACE(array);
   1.269 +	
   1.270 +    M3G_VALIDATE_OBJECT(array);
   1.271 +    M3G_ASSERT(!array->mapCount);
   1.272 +
   1.273 +	clone = (VertexArray *) m3gAlloc(m3g, sizeof(VertexArray));
   1.274 +	if (clone == NULL) {
   1.275 +        return NULL;
   1.276 +    }
   1.277 +
   1.278 +	m3gCopy(clone, array, sizeof(VertexArray));
   1.279 +    m3gInitObject((Object*) clone, m3g, M3G_CLASS_VERTEX_ARRAY);
   1.280 +
   1.281 +	clone->data = m3gAllocObject(m3g, array->vertexCount * array->stride);
   1.282 +
   1.283 +	if (!clone->data) {
   1.284 +        m3gDestroyObject((Object*) clone);
   1.285 +		m3gFree(m3g, clone);
   1.286 +		return NULL;
   1.287 +	}
   1.288 +
   1.289 +	m3gCopy(m3gMapObject(m3g, clone->data),
   1.290 +            m3gMapObject(m3g, array->data),
   1.291 +            array->vertexCount * array->stride);
   1.292 +    m3gUnmapObject(m3g, clone->data);
   1.293 +    m3gUnmapObject(m3g, array->data);
   1.294 +
   1.295 +	return clone;
   1.296 +}
   1.297 +
   1.298 +/*!
   1.299 + * \internal
   1.300 + * \brief Gets array vertex count.
   1.301 + *
   1.302 + * \param array VertexArray object
   1.303 + * \return number of vertices
   1.304 + */
   1.305 +static M3Gint m3gGetArrayVertexCount(const VertexArray *array)
   1.306 +{
   1.307 +    return array->vertexCount;
   1.308 +}
   1.309 +
   1.310 +/*!
   1.311 + * \internal
   1.312 + * \brief Returns the minimum and maximum value stored in the array
   1.313 + */
   1.314 +static void m3gGetArrayValueRange(const VertexArray *array,
   1.315 +                                  M3Gint *minValue, M3Gint *maxValue)
   1.316 +{
   1.317 +    Interface *m3g = M3G_INTERFACE(array);
   1.318 +    
   1.319 +    if (array->rangeMin > array->rangeMax) {
   1.320 +        M3Gint count = array->elementSize * array->vertexCount;
   1.321 +        M3Gint minVal = 0, maxVal = 0;
   1.322 +        
   1.323 +        if (count > 0) {
   1.324 +            switch (array->elementType) {
   1.325 +            case GL_BYTE:
   1.326 +            {
   1.327 +                const GLbyte *src = (const GLbyte*) m3gMapObject(m3g,
   1.328 +                                                                 array->data);
   1.329 +                const M3Gint c = array->elementSize;
   1.330 +                const M3Gint skip = array->stride - c;
   1.331 +                minVal = maxVal = (M3Gint) *src++;
   1.332 +                while (count) {
   1.333 +                    M3Gint i;
   1.334 +                    for (i = 0; i < c; ++i) {
   1.335 +                        M3Gint v = (M3Gint) *src++;
   1.336 +                        minVal = M3G_MIN(minVal, v);
   1.337 +                        maxVal = M3G_MAX(maxVal, v);
   1.338 +                    }
   1.339 +                    count -= c;
   1.340 +                    src += skip;
   1.341 +                }
   1.342 +                break;
   1.343 +            }
   1.344 +            case GL_UNSIGNED_BYTE:
   1.345 +            {
   1.346 +                const GLubyte *src = (const GLubyte*) m3gMapObject(m3g,
   1.347 +                                                                   array->data);
   1.348 +                const M3Gint c = array->elementSize;
   1.349 +                const M3Gint skip = array->stride - c;
   1.350 +                minVal = maxVal = (M3Gint) *src++;
   1.351 +                while (count) {
   1.352 +                    M3Gint i;
   1.353 +                    for (i = 0; i < c; ++i) {
   1.354 +                        M3Gint v = (M3Gint) *src++;
   1.355 +                        minVal = M3G_MIN(minVal, v);
   1.356 +                        maxVal = M3G_MAX(maxVal, v);
   1.357 +                    }
   1.358 +                    count -= c;
   1.359 +                    src += skip;
   1.360 +                }
   1.361 +                break;
   1.362 +            }
   1.363 +            case GL_SHORT:
   1.364 +            {
   1.365 +                const GLshort *src = (const GLshort*)
   1.366 +                    m3gMapObject(m3g, array->data);
   1.367 +                minVal = maxVal = (M3Gint) *src++;
   1.368 +                while (--count) {
   1.369 +                    M3Gint v = (M3Gint) *src++;
   1.370 +                    minVal = M3G_MIN(minVal, v);
   1.371 +                    maxVal = M3G_MAX(maxVal, v);
   1.372 +                }
   1.373 +                break;
   1.374 +            }
   1.375 +            case GL_UNSIGNED_SHORT:
   1.376 +            {
   1.377 +                const GLushort *src = (const GLushort*)
   1.378 +                    m3gMapObject(m3g, array->data);
   1.379 +                minVal = maxVal = (M3Gint) *src++;
   1.380 +                while (--count) {
   1.381 +                    M3Gint v = (M3Gint) *src++;
   1.382 +                    minVal = M3G_MIN(minVal, v);
   1.383 +                    maxVal = M3G_MAX(maxVal, v);
   1.384 +                }
   1.385 +                break;
   1.386 +            }
   1.387 +            default:
   1.388 +                M3G_ASSERT(M3G_FALSE);
   1.389 +            }
   1.390 +        }
   1.391 +        m3gUnmapObject(m3g, array->data);
   1.392 +
   1.393 +        M3G_ASSERT(m3gInRange(minVal, -32768, 32767));
   1.394 +        M3G_ASSERT(m3gInRange(maxVal, -32768, 32767));
   1.395 +        
   1.396 +        ((VertexArray*)array)->rangeMin = (M3Gshort) minVal;
   1.397 +        ((VertexArray*)array)->rangeMax = (M3Gshort) maxVal;
   1.398 +    }
   1.399 +    
   1.400 +    *minValue = array->rangeMin;
   1.401 +    *maxValue = array->rangeMax;
   1.402 +}
   1.403 +
   1.404 +/*!
   1.405 + * \internal
   1.406 + * \brief Compares attributes of two vertex arrays.
   1.407 + *
   1.408 + * \param array         VertexArray object
   1.409 + * \param other         VertexArray object
   1.410 + * \retval M3G_TRUE     arrays are compatible
   1.411 + * \retval M3G_FALSE    arrays are not compatible
   1.412 + */
   1.413 +static M3Gbool m3gIsCompatible(const VertexArray *array, const VertexArray *other)
   1.414 +{
   1.415 +    return( other != NULL &&
   1.416 +            other->elementType == array->elementType &&
   1.417 +            other->elementSize == array->elementSize &&
   1.418 +            other->vertexCount == array->vertexCount);
   1.419 +}
   1.420 +
   1.421 +/*!
   1.422 + * \internal
   1.423 + * \brief Overloaded Object3D method.
   1.424 + *
   1.425 + * \param originalObj original VertexArray object
   1.426 + * \param cloneObj pointer to cloned VertexArray object
   1.427 + * \param pairs array for all object-duplicate pairs
   1.428 + * \param numPairs number of pairs
   1.429 + */
   1.430 +static M3Gbool m3gVertexArrayDuplicate(const Object *originalObj,
   1.431 +                                       Object **cloneObj,
   1.432 +                                       Object **pairs,
   1.433 +                                       M3Gint *numPairs)
   1.434 +{
   1.435 +    VertexArray *clone = m3gCloneVertexArray((VertexArray *)originalObj);
   1.436 +    if (!clone) {
   1.437 +        return M3G_FALSE;
   1.438 +    }
   1.439 +    *cloneObj = (Object*) clone;
   1.440 +    return m3gObjectDuplicate(originalObj, cloneObj, pairs, numPairs);
   1.441 +}
   1.442 +
   1.443 +/*!
   1.444 + * \internal
   1.445 + * \brief Gets array timestamp.
   1.446 + *
   1.447 + * \param array VertexArray object
   1.448 + * \return timestamp
   1.449 + */
   1.450 +static M3Gint m3gGetArrayTimestamp(const VertexArray *array)
   1.451 +{
   1.452 +    return array->timestamp;
   1.453 +}
   1.454 +
   1.455 +/*!
   1.456 + * \internal
   1.457 + * \brief Gets array bounding box as shorts.
   1.458 + *
   1.459 + * \param array VertexArray object
   1.460 + * \param boundingBox   array to fill in
   1.461 + *                      \arg [0] = minX
   1.462 + *                      \arg [1] = minY
   1.463 + *                      \arg [2] = minZ
   1.464 + *                      \arg [3] = maxX
   1.465 + *                      \arg [4] = maxY
   1.466 + *                      \arg [5] = maxZ
   1.467 + */
   1.468 +static void m3gGetArrayBoundingBox(const VertexArray *array, M3Gshort *boundingBox)
   1.469 +{
   1.470 +    Interface *m3g = M3G_INTERFACE(array);
   1.471 +    M3Gint i;
   1.472 +    M3Gshort minX, minY, minZ;
   1.473 +    M3Gshort maxX, maxY, maxZ;
   1.474 +    M3Gbyte *bptr;
   1.475 +    M3Gshort *sptr;
   1.476 +    
   1.477 +    /* Only support 3 component arrays */
   1.478 +    if (array->elementSize != 3 || array->vertexCount == 0) {
   1.479 +        return;
   1.480 +    }
   1.481 +
   1.482 +    switch(array->elementType) {
   1.483 +    case M3G_GLTYPE(M3G_BYTE):
   1.484 +    case M3G_GLTYPE(M3G_UBYTE):
   1.485 +        bptr = (M3Gbyte *) m3gMapObject(m3g, array->data);
   1.486 +
   1.487 +        minX = maxX = bptr[0];
   1.488 +        minY = maxY = bptr[1];
   1.489 +        minZ = maxZ = bptr[2];
   1.490 +        bptr += 4;
   1.491 +
   1.492 +        for (i = 0; i < array->vertexCount - 1; i++) {
   1.493 +            if (bptr[0] < minX) minX = bptr[0];
   1.494 +            if (bptr[0] > maxX) maxX = bptr[0];
   1.495 +            if (bptr[1] < minY) minY = bptr[1];
   1.496 +            if (bptr[1] > maxY) maxY = bptr[1];
   1.497 +            if (bptr[2] < minZ) minZ = bptr[2];
   1.498 +            if (bptr[2] > maxZ) maxZ = bptr[2];
   1.499 +            bptr += 4;
   1.500 +        }
   1.501 +        break;
   1.502 +
   1.503 +    case M3G_GLTYPE(M3G_SHORT):
   1.504 +    case M3G_GLTYPE(M3G_USHORT):
   1.505 +        sptr = (M3Gshort *) m3gMapObject(m3g, array->data);
   1.506 +
   1.507 +        minX = maxX = sptr[0];
   1.508 +        minY = maxY = sptr[1];
   1.509 +        minZ = maxZ = sptr[2];
   1.510 +        sptr += 3;
   1.511 +
   1.512 +        for (i = 0; i < array->vertexCount - 1; i++) {
   1.513 +            if (sptr[0] < minX) minX = sptr[0];
   1.514 +            if (sptr[0] > maxX) maxX = sptr[0];
   1.515 +            if (sptr[1] < minY) minY = sptr[1];
   1.516 +            if (sptr[1] > maxY) maxY = sptr[1];
   1.517 +            if (sptr[2] < minZ) minZ = sptr[2];
   1.518 +            if (sptr[2] > maxZ) maxZ = sptr[2];
   1.519 +            sptr += 3;
   1.520 +        }
   1.521 +        break;
   1.522 +
   1.523 +    default: /* Error */
   1.524 +        M3G_ASSERT(0);
   1.525 +        return;
   1.526 +    }
   1.527 +
   1.528 +    m3gUnmapObject(m3g, array->data);
   1.529 +
   1.530 +    boundingBox[0] = minX;
   1.531 +    boundingBox[1] = minY;
   1.532 +    boundingBox[2] = minZ;
   1.533 +    boundingBox[3] = maxX;
   1.534 +    boundingBox[4] = maxY;
   1.535 +    boundingBox[5] = maxZ;
   1.536 +}
   1.537 +
   1.538 +/*!
   1.539 + * \internal
   1.540 + * \brief Gets a coordinate from vertex array.
   1.541 + *
   1.542 + * \param va            VertexArray object
   1.543 + * \param elementCount  elemens in coordinate
   1.544 + * \param idx           index of coordinate
   1.545 + * \param v             vector to fill in
   1.546 + * \retval              M3G_TRUE get ok
   1.547 + * \retval              M3G_FALSE no such vertex
   1.548 + */
   1.549 +static M3Gbool m3gGetCoordinates(VertexArray *va,
   1.550 +                                 M3Gint elementCount,
   1.551 +                                 M3Gint idx,
   1.552 +                                 M3Gfloat *v)
   1.553 +{
   1.554 +    Interface *m3g;
   1.555 +    M3Gbyte *bptr;
   1.556 +    M3Gshort *sptr;
   1.557 +    int i;
   1.558 +    
   1.559 +    if (!va) {
   1.560 +        return M3G_FALSE;
   1.561 +    }
   1.562 +
   1.563 +    m3g = M3G_INTERFACE(va);
   1.564 +
   1.565 +    switch (va->elementType) {
   1.566 +    case M3G_GLTYPE(M3G_BYTE):
   1.567 +    case M3G_GLTYPE(M3G_UBYTE):
   1.568 +        idx *= 4;
   1.569 +        bptr = (M3Gbyte *) m3gMapObject(m3g, va->data);
   1.570 +        bptr += idx;
   1.571 +        for (i = 0; i < elementCount; ++i) {
   1.572 +            *v++ = *bptr++;
   1.573 +        }
   1.574 +        break;
   1.575 +
   1.576 +    case M3G_GLTYPE(M3G_SHORT):
   1.577 +    case M3G_GLTYPE(M3G_USHORT):
   1.578 +        idx *= elementCount;
   1.579 +        sptr = (M3Gshort *) m3gMapObject(m3g, va->data);
   1.580 +        sptr += idx;
   1.581 +        for (i = 0; i < elementCount; ++i) {
   1.582 +            *v++ = *sptr++;
   1.583 +        }
   1.584 +        break;
   1.585 +    }
   1.586 +
   1.587 +    m3gUnmapObject(m3g, va->data);
   1.588 +    return M3G_TRUE;
   1.589 +}
   1.590 +
   1.591 +/*----------------------------------------------------------------------
   1.592 + * Virtual function table
   1.593 + *--------------------------------------------------------------------*/
   1.594 +
   1.595 +static const ObjectVFTable m3gvf_VertexArray = {
   1.596 +    m3gObjectApplyAnimation,
   1.597 +    m3gObjectIsCompatible,
   1.598 +    m3gObjectUpdateProperty,
   1.599 +    m3gObjectDoGetReferences,
   1.600 +    m3gObjectFindID,
   1.601 +    m3gVertexArrayDuplicate,
   1.602 +    m3gDestroyVertexArray
   1.603 +};
   1.604 +        
   1.605 +
   1.606 +/*----------------------------------------------------------------------
   1.607 + * Public API functions
   1.608 + *--------------------------------------------------------------------*/
   1.609 +
   1.610 +/*!
   1.611 + * \brief Creates a VertexArray object.
   1.612 + *
   1.613 + * \param interface     M3G interface
   1.614 + * \param count         Count of vertices
   1.615 + * \param size          Size of each element [2, 4]
   1.616 + * \param type          Type of elements
   1.617 + * \retval VertexArray new VertexArray object
   1.618 + * \retval NULL VertexArray creating failed
   1.619 + */
   1.620 +
   1.621 +/*@access M3Ginterface@*/
   1.622 +/*@access M3GVertexArray@*/
   1.623 +M3G_API M3GVertexArray m3gCreateVertexArray(M3GInterface interface,
   1.624 +                                            M3Gsizei count,
   1.625 +                                            M3Gint size,
   1.626 +                                            M3Gdatatype type)
   1.627 +{
   1.628 +    Interface *m3g = (Interface *) interface;
   1.629 +    M3G_VALIDATE_INTERFACE(m3g);
   1.630 +    
   1.631 +    /* Check errors */
   1.632 +    if (count < 1 || count > 65535 ||
   1.633 +        size < 2 || size > 4 ||
   1.634 +        (type != M3G_BYTE && type != M3G_SHORT)) {
   1.635 +        m3gRaiseError(m3g, M3G_INVALID_VALUE);
   1.636 +        return NULL;
   1.637 +    }
   1.638 +
   1.639 +    {
   1.640 +        /* Allocate the array object and its data buffer */
   1.641 +        
   1.642 +        VertexArray *array = m3gAllocZ(m3g, (M3Gsizei) sizeof(VertexArray));
   1.643 +        if (!array) {
   1.644 +            return NULL;
   1.645 +        }
   1.646 +
   1.647 +        switch (type) {
   1.648 +        case M3G_BYTE:
   1.649 +            /* always padded to 4 bytes */
   1.650 +            array->stride = 4;
   1.651 +            break;
   1.652 +        case M3G_SHORT:
   1.653 +            array->stride = size * sizeof(M3Gshort);
   1.654 +            break;
   1.655 +        }
   1.656 +
   1.657 +        /* Alloc and initialize all values to zero */
   1.658 +        array->data = m3gAllocObject(m3g, count * array->stride);
   1.659 +        if (!array->data) {
   1.660 +            m3gFree(m3g, array);
   1.661 +            return NULL;
   1.662 +        }
   1.663 +        else {
   1.664 +            void *ptr = m3gMapObject(m3g, array->data);
   1.665 +            m3gZero(ptr, count * array->stride);
   1.666 +            m3gUnmapObject(m3g, array->data);
   1.667 +        }
   1.668 +
   1.669 +        m3gInitObject(&array->object, m3g, M3G_CLASS_VERTEX_ARRAY);
   1.670 +
   1.671 +        array->elementType = M3G_GLTYPE(type);
   1.672 +        array->elementSize = size;
   1.673 +        array->vertexCount = count;
   1.674 +        m3gInvalidateArray(array);
   1.675 +        
   1.676 +        return (M3GVertexArray) array;
   1.677 +    }
   1.678 +}
   1.679 +
   1.680 +/*!
   1.681 + * \brief Returns the data layout parameters for a vertex array
   1.682 + *
   1.683 + * This gives the format of the data mapped to user memory with \c
   1.684 + * m3gMapVertexArray.
   1.685 + *
   1.686 + * \param handle  array handle
   1.687 + * \param count   pointer for number of vertices (output)
   1.688 + * \param size    pointer for components per vertex (output)
   1.689 + * \param type    pointer to data element type (output)
   1.690 + * \param stride  pointer to stride, i.e. number of bytes from
   1.691 + *                the beginning of one vertex to the next (output)
   1.692 + */
   1.693 +M3G_API void m3gGetVertexArrayParams(M3GVertexArray handle,
   1.694 +                                     M3Gsizei *count,
   1.695 +                                     M3Gint *size,
   1.696 +                                     M3Gdatatype *type,
   1.697 +                                     M3Gsizei *stride)
   1.698 +{
   1.699 +    VertexArray *array = (VertexArray *) handle;
   1.700 +    M3G_VALIDATE_OBJECT(array);
   1.701 +
   1.702 +    if (count) {
   1.703 +        *count = array->vertexCount;
   1.704 +    }
   1.705 +    if (size) {
   1.706 +        *size = array->elementSize;
   1.707 +    }
   1.708 +    if (type) {
   1.709 +        *type = (M3Gdatatype) M3G_M3GTYPE(array->elementType);
   1.710 +    }
   1.711 +    if (stride) {
   1.712 +        *stride = array->stride;
   1.713 +    }
   1.714 +}
   1.715 +
   1.716 +/*!
   1.717 + * \brief Maps the data of a vertex array to application memory
   1.718 + *
   1.719 + * The contents of the array will remain mapped to application memory
   1.720 + * until a matching \c m3gUnMapVertexArray call. While mapped to user
   1.721 + * memory, the array can not be used for rendering.
   1.722 + *
   1.723 + * Deleting a mapped array will also implicitly unmap it.
   1.724 + *
   1.725 + * \param handle handle of the array to map
   1.726 + * \return pointer to the array data
   1.727 + */
   1.728 +M3G_API void *m3gMapVertexArray(M3GVertexArray handle)
   1.729 +{
   1.730 +    void *ptr = (void*) m3gMapVertexArrayReadOnly(handle);
   1.731 +    if (ptr) {
   1.732 +        m3gInvalidateArray((VertexArray*) handle);
   1.733 +    }
   1.734 +    return ptr;
   1.735 +}
   1.736 +
   1.737 +/*!
   1.738 + * \brief Maps a vertex array for reading only
   1.739 + *
   1.740 + * This is the same as m3gMapVertexArray, but maps the array for
   1.741 + * reading only, allowing internal optimizations.
   1.742 + *
   1.743 + */
   1.744 +M3G_API const void *m3gMapVertexArrayReadOnly(M3GVertexArray handle)
   1.745 +{
   1.746 +    VertexArray *array = (VertexArray *) handle;
   1.747 +    M3G_VALIDATE_OBJECT(array);
   1.748 +    
   1.749 +    if (array->numLocks > 0) {
   1.750 +        m3gRaiseError(M3G_INTERFACE(array), M3G_INVALID_OPERATION);
   1.751 +        return NULL;
   1.752 +    }
   1.753 +    
   1.754 +    ++array->mapCount;
   1.755 +    return m3gMapObject(M3G_INTERFACE(array), array->data);
   1.756 +}
   1.757 +
   1.758 +/*!
   1.759 + * \brief Releases an array mapped to user memory
   1.760 + *
   1.761 + * The pointer obtained with a preceding \c m3gMapVertexArray call
   1.762 + * will not be valid after unmapping the array.
   1.763 + *
   1.764 + * \param handle handle of the array to release
   1.765 + */
   1.766 +M3G_API void m3gUnmapVertexArray(M3GVertexArray handle)
   1.767 +{
   1.768 +    VertexArray *array = (VertexArray *) handle;
   1.769 +    M3G_VALIDATE_OBJECT(array);
   1.770 +    M3G_ASSERT(array->mapCount);
   1.771 +
   1.772 +    m3gUnmapObject(M3G_INTERFACE(array), array->data);
   1.773 +    --array->mapCount;
   1.774 +}
   1.775 +
   1.776 +/*!
   1.777 + * \brief Set a range of vertex array elements
   1.778 + *
   1.779 + * \param handle array handle
   1.780 + * \param first  index of first vertex to set
   1.781 + * \param count  number of total vertices to set
   1.782 + * \param srcLength length of source data
   1.783 + * \param type  data type of source data
   1.784 + * \param src   source data
   1.785 + */
   1.786 +M3G_API void m3gSetVertexArrayElements(M3GVertexArray handle,
   1.787 +                                       M3Gint first, M3Gsizei count,
   1.788 +                                       M3Gsizei srcLength,
   1.789 +                                       M3Gdatatype type,
   1.790 +                                       const void *src)
   1.791 +{
   1.792 +    VertexArray *array = (VertexArray *) handle;
   1.793 +    M3G_VALIDATE_OBJECT(array);
   1.794 +
   1.795 +    M3G_ASSERT(array->numLocks == 0);
   1.796 +
   1.797 +    /* Check errors */
   1.798 +    if (array->mapCount) {
   1.799 +        m3gRaiseError(M3G_INTERFACE(array), M3G_INVALID_OPERATION);
   1.800 +        return;
   1.801 +    }
   1.802 +    if (src == NULL) {
   1.803 +        m3gRaiseError(M3G_INTERFACE(array), M3G_NULL_POINTER);
   1.804 +        return;
   1.805 +    }
   1.806 +    if (first < 0 || first + count > array->vertexCount) {
   1.807 +        m3gRaiseError(M3G_INTERFACE(array), M3G_INVALID_INDEX);
   1.808 +        return;
   1.809 +    }
   1.810 +    if (count < 0 || srcLength < count * array->elementSize) {
   1.811 +        m3gRaiseError(M3G_INTERFACE(array), M3G_INVALID_VALUE);
   1.812 +        return;
   1.813 +    }
   1.814 +
   1.815 +    /* Copy source data according to destination array type */
   1.816 +    {
   1.817 +        int values = count * array->elementSize;
   1.818 +        
   1.819 +        switch (array->elementType) {
   1.820 +        case GL_BYTE:
   1.821 +        case GL_UNSIGNED_BYTE:
   1.822 +            if (type != M3G_BYTE) {
   1.823 +                m3gRaiseError(M3G_INTERFACE(array), M3G_INVALID_OPERATION);
   1.824 +                return;
   1.825 +            }
   1.826 +            else {
   1.827 +                GLubyte *dst =
   1.828 +                    ((GLubyte *)m3gMapObject(M3G_INTERFACE(array),
   1.829 +                                             array->data))
   1.830 +                    + first * array->stride;
   1.831 +                GLubyte *srcByte = (GLubyte *) src;
   1.832 +
   1.833 +                M3G_ASSERT(array->elementSize >= 2 && array->elementSize <= 4);
   1.834 +                M3G_ASSERT(array->stride == 4);
   1.835 +                
   1.836 +                while (values > 0) {
   1.837 +                    *dst++ = *srcByte++;
   1.838 +                    *dst++ = *srcByte++;
   1.839 +                    *dst++ = (M3Gubyte)((array->elementSize >= 3) ? *srcByte++ : 0x00);
   1.840 +                    *dst++ = (M3Gubyte)((array->elementSize == 4) ? *srcByte++ : 0xFF);
   1.841 +                    values -= array->elementSize;
   1.842 +                }
   1.843 +            }
   1.844 +            break;
   1.845 +        
   1.846 +        case GL_SHORT:
   1.847 +        case GL_UNSIGNED_SHORT:
   1.848 +            if (type != M3G_SHORT) {
   1.849 +                m3gRaiseError(M3G_INTERFACE(array), M3G_INVALID_OPERATION);
   1.850 +                return;
   1.851 +            }
   1.852 +            else {
   1.853 +                GLushort *dst =
   1.854 +                    ((GLushort *)m3gMapObject(M3G_INTERFACE(array),
   1.855 +                                              array->data))
   1.856 +                    + first * array->stride / 2;
   1.857 +                GLushort *srcShort = (GLushort *) src;
   1.858 +                M3G_ASSERT(array->stride == (GLsizei)(array->elementSize * sizeof(*dst)));
   1.859 +                
   1.860 +                while (values--) {
   1.861 +                    *dst++ = *srcShort++;
   1.862 +                }
   1.863 +            }
   1.864 +            break;
   1.865 +
   1.866 +        default:
   1.867 +            M3G_ASSERT(0);      /* fatal internal error */
   1.868 +        }
   1.869 +    }
   1.870 +
   1.871 +    m3gUnmapObject(M3G_INTERFACE(array), array->data);
   1.872 +    m3gInvalidateArray(array);
   1.873 +}
   1.874 +
   1.875 +/*!
   1.876 + * \brief Get a range of vertex array elements
   1.877 + *
   1.878 + * \param handle array handle
   1.879 + * \param first  index of first vertex to set
   1.880 + * \param count  number of total vertices to set
   1.881 + * \param dstLength length of destination data
   1.882 + * \param type  data type of destination data
   1.883 + * \param dst   destination data
   1.884 + */
   1.885 +M3G_API void m3gGetVertexArrayElements(M3GVertexArray handle,
   1.886 +                                       M3Gint first, M3Gsizei count,
   1.887 +                                       M3Gsizei dstLength, M3Gdatatype type, void *dst)
   1.888 +{
   1.889 +    VertexArray *array = (VertexArray *) handle;
   1.890 +    M3G_VALIDATE_OBJECT(array);
   1.891 +
   1.892 +    M3G_ASSERT(array->numLocks == 0);
   1.893 +
   1.894 +    /* Check errors */
   1.895 +    if (array->mapCount) {
   1.896 +        m3gRaiseError(M3G_INTERFACE(array), M3G_INVALID_OPERATION);
   1.897 +        return;
   1.898 +    }
   1.899 +    if (dst == NULL) {
   1.900 +        m3gRaiseError(M3G_INTERFACE(array), M3G_NULL_POINTER);
   1.901 +        return;
   1.902 +    }
   1.903 +    if (first < 0 || first + count > array->vertexCount) {
   1.904 +        m3gRaiseError(M3G_INTERFACE(array), M3G_INVALID_INDEX);
   1.905 +        return;
   1.906 +    }
   1.907 +    if (count < 0 || dstLength < count * array->elementSize) {
   1.908 +        m3gRaiseError(M3G_INTERFACE(array), M3G_INVALID_VALUE);
   1.909 +        return;
   1.910 +    }
   1.911 +
   1.912 +    /* Data according to destination array type */
   1.913 +    {
   1.914 +        int values = count * array->elementSize;
   1.915 +        
   1.916 +        switch (array->elementType) {
   1.917 +        case GL_BYTE:
   1.918 +        case GL_UNSIGNED_BYTE:
   1.919 +            if (type != M3G_BYTE) {
   1.920 +                m3gRaiseError(M3G_INTERFACE(array), M3G_INVALID_OPERATION);
   1.921 +                return;
   1.922 +            }
   1.923 +            else {
   1.924 +                GLubyte *src =
   1.925 +                    ((GLubyte *)m3gMapObject(M3G_INTERFACE(array),
   1.926 +                                             array->data))
   1.927 +                    + first * array->stride;
   1.928 +                GLubyte *dstByte = (GLubyte *) dst;
   1.929 +
   1.930 +                M3G_ASSERT(array->elementSize >= 2 && array->elementSize <= 4);
   1.931 +                M3G_ASSERT(array->stride == 4);
   1.932 +                
   1.933 +                while (values > 0) {
   1.934 +                    *dstByte++ = src[0];
   1.935 +                    *dstByte++ = src[1];
   1.936 +                    if (array->elementSize >= 3) {
   1.937 +                        *dstByte++ = src[2];
   1.938 +                    }
   1.939 +                    if (array->elementSize == 4) {
   1.940 +                        *dstByte++ = src[3];
   1.941 +                    }
   1.942 +                    src += 4;
   1.943 +                    values -= array->elementSize;
   1.944 +                }
   1.945 +            }
   1.946 +            break;
   1.947 +        
   1.948 +        case GL_SHORT:
   1.949 +        case GL_UNSIGNED_SHORT:
   1.950 +            if (type != M3G_SHORT) {
   1.951 +                m3gRaiseError(M3G_INTERFACE(array), M3G_INVALID_OPERATION);
   1.952 +                return;
   1.953 +            }
   1.954 +            else {
   1.955 +                GLushort *src =
   1.956 +                    ((GLushort *)m3gMapObject(M3G_INTERFACE(array),
   1.957 +                                              array->data))
   1.958 +                    + first * array->stride / 2;
   1.959 +                GLushort *dstShort = (GLushort *) dst;
   1.960 +                M3G_ASSERT(array->stride == (GLsizei)(array->elementSize * sizeof(*src)));
   1.961 +                
   1.962 +                while (values--) {
   1.963 +                    *dstShort++ = *src++;
   1.964 +                }
   1.965 +            }
   1.966 +            break;
   1.967 +
   1.968 +        default:
   1.969 +            M3G_ASSERT(0);      /* fatal internal error */
   1.970 +        }
   1.971 +    }
   1.972 +
   1.973 +    m3gUnmapObject(M3G_INTERFACE(array), array->data);
   1.974 +}
   1.975 +
   1.976 +/*!
   1.977 + * \brief Transform vertex array with
   1.978 + * given transform and w.
   1.979 + *
   1.980 + * \param handle        array handle
   1.981 + * \param transform     transform
   1.982 + * \param out           output array to fill in
   1.983 + * \param outLength     length of the output array
   1.984 + * \param w             use w
   1.985 + */
   1.986 +M3G_API void m3gTransformArray(M3GVertexArray handle,
   1.987 +                               M3GMatrix *transform,
   1.988 +                               M3Gfloat *out, M3Gint outLength,
   1.989 +                               M3Gbool w)
   1.990 +{
   1.991 +    M3Gbyte *bptr;
   1.992 +    M3Gshort *sptr;
   1.993 +    M3Gfloat *outPtr = out;
   1.994 +    M3Gint i;
   1.995 +    M3GVec4 vec;
   1.996 +    VertexArray *array = (VertexArray *) handle;
   1.997 +    M3G_VALIDATE_OBJECT(array);
   1.998 +
   1.999 +    /* Check for errors */
  1.1000 +    if (outLength < (4 * array->vertexCount) ||
  1.1001 +        array->elementSize == 4) {
  1.1002 +        m3gRaiseError(M3G_INTERFACE(array), M3G_INVALID_VALUE);
  1.1003 +        return;
  1.1004 +    }
  1.1005 +
  1.1006 +    switch(array->elementType) {
  1.1007 +        case GL_BYTE:
  1.1008 +        case GL_UNSIGNED_BYTE:
  1.1009 +            bptr = (M3Gbyte *)m3gMapObject(M3G_INTERFACE(array), array->data);
  1.1010 +
  1.1011 +            for (i = 0; i < array->vertexCount * 4; i += 4) {
  1.1012 +                vec.x = bptr[i + 0];
  1.1013 +                vec.y = bptr[i + 1];
  1.1014 +                vec.z = 0;
  1.1015 +                if (array->elementSize == 3) {
  1.1016 +                    vec.z = bptr[i + 2];
  1.1017 +                }
  1.1018 +                vec.w = (M3Gfloat)w;
  1.1019 +
  1.1020 +                m3gTransformVec4(transform, &vec);
  1.1021 +
  1.1022 +                *outPtr++ = vec.x;
  1.1023 +                *outPtr++ = vec.y;
  1.1024 +                *outPtr++ = vec.z;
  1.1025 +                *outPtr++ = vec.w;
  1.1026 +            }
  1.1027 +            break;
  1.1028 +
  1.1029 +        case GL_SHORT:
  1.1030 +        case GL_UNSIGNED_SHORT:
  1.1031 +            sptr = (M3Gshort *)m3gMapObject(M3G_INTERFACE(array), array->data);
  1.1032 +
  1.1033 +            for (i = 0; i < array->vertexCount * array->elementSize; i += array->elementSize) {
  1.1034 +                vec.x = sptr[i + 0];
  1.1035 +                vec.y = sptr[i + 1];
  1.1036 +                vec.z = 0;
  1.1037 +                if (array->elementSize == 3) {
  1.1038 +                    vec.z = sptr[i + 2];
  1.1039 +                }
  1.1040 +                vec.w = (M3Gfloat)w;
  1.1041 +
  1.1042 +                m3gTransformVec4(transform, &vec);
  1.1043 +
  1.1044 +                *outPtr++ = vec.x;
  1.1045 +                *outPtr++ = vec.y;
  1.1046 +                *outPtr++ = vec.z;
  1.1047 +                *outPtr++ = vec.w;
  1.1048 +            }
  1.1049 +            break;
  1.1050 +    }
  1.1051 +    m3gUnmapObject(M3G_INTERFACE(array), array->data);
  1.1052 +}
  1.1053 +
  1.1054 +#undef DIRTY_ALPHA_FACTOR
  1.1055 +