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 +