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 +