1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/graphics/m3g/m3gcore11/src/m3g_indexbuffer.c Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,555 @@
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: IndexBuffer implementation
1.18 +*
1.19 +*/
1.20 +
1.21 +
1.22 +/*!
1.23 + * \internal
1.24 + * \file
1.25 + * \brief IndexBuffer 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_indexbuffer.h"
1.33 +
1.34 +/*----------------------------------------------------------------------
1.35 + * Private functions
1.36 + *--------------------------------------------------------------------*/
1.37 +
1.38 +
1.39 +/*----------------------------------------------------------------------
1.40 + * Internal functions
1.41 + *--------------------------------------------------------------------*/
1.42 +
1.43 +/*!
1.44 + * \internal
1.45 + * \brief IndexBuffer destructor
1.46 + *
1.47 + * \param obj IndexBuffer object
1.48 + */
1.49 +static void m3gDestroyIndexBuffer(Object *obj)
1.50 +{
1.51 + IndexBuffer *ib = (IndexBuffer *) obj;
1.52 + M3G_VALIDATE_OBJECT(ib);
1.53 +
1.54 + {
1.55 + Interface *m3g = M3G_INTERFACE(ib);
1.56 + m3gFree(m3g, ib->indices);
1.57 + m3gFree(m3g, ib->lengths);
1.58 + }
1.59 +
1.60 + m3gDestroyObject(obj);
1.61 +}
1.62 +
1.63 +/*!
1.64 + * \internal
1.65 + * \brief Sends the contents of an IndexBuffer to the current GL
1.66 + * instance for processing
1.67 + *
1.68 + * \param buf IndexBuffer object
1.69 + */
1.70 +static void m3gSendIndexBuffer(const IndexBuffer *buf)
1.71 +{
1.72 + M3G_VALIDATE_OBJECT(buf);
1.73 +
1.74 + M3G_ASSERT(buf->indices);
1.75 + M3G_ASSERT(buf->glPrimitive == GL_TRIANGLE_STRIP);
1.76 +
1.77 + M3G_BEGIN_PROFILE(M3G_INTERFACE(buf), M3G_PROFILE_NGL_DRAW);
1.78 + glDrawElements(buf->glPrimitive, buf->indexCount, buf->glType, buf->indices);
1.79 + M3G_END_PROFILE(M3G_INTERFACE(buf), M3G_PROFILE_NGL_DRAW);
1.80 +
1.81 + M3G_ASSERT_GL;
1.82 +}
1.83 +
1.84 +/*!
1.85 + * \internal
1.86 + * \brief Gets triangle indices, used by mesh pick routine.
1.87 + *
1.88 + * \param buf IndexBuffer object
1.89 + * \param triangle triangle index
1.90 + * \param indices triangle indices
1.91 + * \retval M3G_TRUE indices fetched
1.92 + * \retval M3G_FALSE no such triangle
1.93 + */
1.94 +static M3Gbool m3gGetIndices(const IndexBuffer *buf,
1.95 + M3Gint triangle,
1.96 + M3Gint *indices) {
1.97 + M3Gubyte *bptr;
1.98 + M3Gushort *sptr;
1.99 +
1.100 + if(triangle + 2 >= buf->indexCount) return M3G_FALSE;
1.101 +
1.102 + switch(buf->glType) {
1.103 + case GL_UNSIGNED_BYTE:
1.104 + bptr = (M3Gubyte *)buf->indices;
1.105 + bptr += triangle;
1.106 + indices[0] = *bptr++;
1.107 + indices[1] = *bptr++;
1.108 + indices[2] = *bptr;
1.109 + break;
1.110 +
1.111 + case GL_UNSIGNED_SHORT:
1.112 + sptr = (M3Gushort *)buf->indices;
1.113 + sptr += triangle;
1.114 + indices[0] = (M3Gint) *sptr++;
1.115 + indices[1] = (M3Gint) *sptr++;
1.116 + indices[2] = (M3Gint) *sptr;
1.117 + break;
1.118 + }
1.119 +
1.120 + /* Winding */
1.121 + indices[3] = triangle & 1;
1.122 +
1.123 + return M3G_TRUE;
1.124 +}
1.125 +
1.126 +/*!
1.127 + * \internal
1.128 + * \brief Overloaded Object3D method.
1.129 + *
1.130 + * \param originalObj original IndexBuffer object
1.131 + * \param cloneObj pointer to cloned IndexBuffer object
1.132 + * \param pairs array for all object-duplicate pairs
1.133 + * \param numPairs number of pairs
1.134 + */
1.135 +static M3Gbool m3gIndexBufferDuplicate(const Object *originalObj,
1.136 + Object **cloneObj,
1.137 + Object **pairs,
1.138 + M3Gint *numPairs)
1.139 +{
1.140 + M3Gint size;
1.141 + IndexBuffer *original = (IndexBuffer *)originalObj;
1.142 + IndexBuffer *clone = (IndexBuffer *)m3gAllocZ(originalObj->interface, sizeof(IndexBuffer));
1.143 +
1.144 + if (clone == NULL) {
1.145 + return M3G_FALSE;
1.146 + }
1.147 +
1.148 + *cloneObj = (Object *)clone;
1.149 +
1.150 + /* Call init since this object is 'manually' created */
1.151 + m3gInitObject((Object*) clone, originalObj->interface, M3G_CLASS_INDEX_BUFFER);
1.152 +
1.153 + if(!m3gObjectDuplicate(originalObj, cloneObj, pairs, numPairs)) {
1.154 + return M3G_FALSE;
1.155 + }
1.156 +
1.157 + clone->indexCount = original->indexCount;
1.158 + clone->glType = original->glType;
1.159 + clone->glPrimitive = original->glPrimitive;
1.160 + clone->stripCount = original->stripCount;
1.161 +
1.162 + if (clone->glType == GL_UNSIGNED_BYTE) {
1.163 + size = clone->indexCount;
1.164 + clone->indices = m3gAlloc(originalObj->interface, size);
1.165 + }
1.166 + else {
1.167 + size = clone->indexCount * sizeof(M3Gshort);
1.168 + clone->indices = m3gAlloc(originalObj->interface, size);
1.169 + }
1.170 +
1.171 + clone->lengths = (M3Gushort *) m3gAlloc(originalObj->interface, (M3Gsize) clone->stripCount*2);
1.172 +
1.173 + if(clone->indices == NULL || clone->lengths == NULL) {
1.174 + /* Duplicate will call m3gDeleteObject */
1.175 + return M3G_FALSE;
1.176 + }
1.177 +
1.178 + m3gCopy(clone->lengths, original->lengths, clone->stripCount*2);
1.179 + m3gCopy(clone->indices, original->indices, size);
1.180 +
1.181 + return M3G_TRUE;
1.182 +}
1.183 +
1.184 +/*!
1.185 + * \internal
1.186 + * \brief Gets maximum index of this index buffer.
1.187 + *
1.188 + * \param buf IndexBuffer object
1.189 + * \return maximum index used
1.190 + */
1.191 +static M3Gint m3gGetMaxIndex(const IndexBuffer *buf)
1.192 +{
1.193 + return buf->maxIndex;
1.194 +}
1.195 +
1.196 +/*----------------------------------------------------------------------
1.197 + * Virtual function table
1.198 + *--------------------------------------------------------------------*/
1.199 +
1.200 +static const ObjectVFTable m3gvf_IndexBuffer = {
1.201 + m3gObjectApplyAnimation,
1.202 + m3gObjectIsCompatible,
1.203 + m3gObjectUpdateProperty,
1.204 + m3gObjectDoGetReferences,
1.205 + m3gObjectFindID,
1.206 + m3gIndexBufferDuplicate,
1.207 + m3gDestroyIndexBuffer
1.208 +};
1.209 +
1.210 +/*----------------------------------------------------------------------
1.211 + * Public functions
1.212 + *--------------------------------------------------------------------*/
1.213 +
1.214 +/*!
1.215 + * \brief Creates an implicit strip buffer
1.216 + *
1.217 + * \param interface M3G interface
1.218 + * \param stripCount number of triangle strips
1.219 + * \param stripLengths array of strip lengths
1.220 + * \param firstIndex first index
1.221 + * \retval IndexBuffer new IndexBuffer object
1.222 + * \retval NULL IndexBuffer creating failed
1.223 + */
1.224 +M3G_API M3GIndexBuffer m3gCreateImplicitStripBuffer(
1.225 + M3GInterface interface,
1.226 + M3Gsizei stripCount,
1.227 + const M3Gsizei *stripLengths,
1.228 + M3Gint firstIndex)
1.229 +{
1.230 + M3GIndexBuffer ib;
1.231 + M3Gint *stripIndices, i, indexCount = 0;
1.232 + Interface *m3g = (Interface *) interface;
1.233 + M3G_VALIDATE_INTERFACE(m3g);
1.234 +
1.235 + if (stripLengths == NULL) {
1.236 + m3gRaiseError(m3g, M3G_NULL_POINTER);
1.237 + return 0;
1.238 + }
1.239 +
1.240 + if (stripCount == 0) {
1.241 + m3gRaiseError(m3g, M3G_INVALID_VALUE);
1.242 + return 0;
1.243 + }
1.244 +
1.245 + for (i = 0; i < stripCount; i++) {
1.246 + if(stripLengths[i] < 3) {
1.247 + m3gRaiseError(m3g, M3G_INVALID_VALUE);
1.248 + return 0;
1.249 + }
1.250 + indexCount += stripLengths[i];
1.251 + }
1.252 +
1.253 + if (firstIndex < 0 ||
1.254 + (firstIndex + indexCount) > 65535) {
1.255 + m3gRaiseError(m3g, M3G_INVALID_INDEX);
1.256 + return 0;
1.257 + }
1.258 +
1.259 + stripIndices = m3gAlloc(m3g, indexCount * sizeof(M3Gint));
1.260 +
1.261 + if (stripIndices == NULL) {
1.262 + return 0; /* automatic out of memory from m3gAlloc */
1.263 + }
1.264 +
1.265 + /* Generate explict arrays */
1.266 +
1.267 + for (i = 0; i < indexCount; i++) {
1.268 + stripIndices[i] = firstIndex + i;
1.269 + }
1.270 +
1.271 + ib = m3gCreateStripBuffer(interface,
1.272 + M3G_TRIANGLE_STRIPS,
1.273 + stripCount, stripLengths,
1.274 + M3G_INT, indexCount, stripIndices);
1.275 + m3gFree(m3g, stripIndices);
1.276 + return ib;
1.277 +}
1.278 +
1.279 +/*!
1.280 + * \brief Creates an indexed triangle strip buffer
1.281 + *
1.282 + * \note Optimizes rendering by joining the indices. Also scans the
1.283 + * array for the maximum value, and allocates the storage using the
1.284 + * smallest possible data type.
1.285 + *
1.286 + * \param interface M3G interface
1.287 + * \param primitive primitive type, always M3G_TRIANGLE_STRIPS
1.288 + * \param stripCount number of triangle strips
1.289 + * \param stripLengths array of strip lengths
1.290 + * \param type data type of indices
1.291 + * \param numIndices number of indices
1.292 + * \param stripIndices array of indices
1.293 + * \retval IndexBuffer new IndexBuffer object
1.294 + * \retval NULL IndexBuffer creating failed
1.295 + */
1.296 +M3G_API M3GIndexBuffer m3gCreateStripBuffer(M3GInterface interface,
1.297 + M3Gprimitive primitive,
1.298 + M3Gsizei stripCount,
1.299 + const M3Gsizei *stripLengths,
1.300 + M3Gdatatype type,
1.301 + M3Gsizei numIndices,
1.302 + const void *stripIndices)
1.303 +{
1.304 + M3Gsizei joinedIndexCount = 0;
1.305 + M3Gsizei originalIndexCount = 0;
1.306 + M3Gint maxIndex = 0;
1.307 +
1.308 + Interface *m3g = (Interface *) interface;
1.309 + M3G_VALIDATE_INTERFACE(m3g);
1.310 +
1.311 + if (primitive != M3G_TRIANGLE_STRIPS
1.312 + || (type != M3G_INT && type != M3G_UINT)) {
1.313 + m3gRaiseError(m3g, M3G_INVALID_ENUM);
1.314 + return 0;
1.315 + }
1.316 + if (stripIndices == NULL ||
1.317 + stripLengths == NULL) {
1.318 + m3gRaiseError(m3g, M3G_NULL_POINTER);
1.319 + return 0;
1.320 + }
1.321 +
1.322 + if (stripCount == 0 || numIndices == 0) {
1.323 + m3gRaiseError(m3g, M3G_INVALID_VALUE);
1.324 + return 0;
1.325 + }
1.326 +
1.327 + {
1.328 + /* Find the maximum index and count the actual number of indices
1.329 + * required for joining the strips */
1.330 +
1.331 + int strip;
1.332 + M3Gint *idx = (M3Gint *) stripIndices;
1.333 + for (strip = 0; strip < stripCount; ++strip) {
1.334 + if(stripLengths[strip] < 3) {
1.335 + m3gRaiseError(m3g, M3G_INVALID_VALUE);
1.336 + return 0;
1.337 + }
1.338 + if (strip != 0) {
1.339 + joinedIndexCount += (M3Guint)((joinedIndexCount & 1) ? 3 : 2);
1.340 + }
1.341 +
1.342 + joinedIndexCount += (M3Guint) stripLengths[strip];
1.343 + originalIndexCount += (M3Guint) stripLengths[strip];
1.344 +
1.345 + if (numIndices < originalIndexCount) {
1.346 + m3gRaiseError(m3g, M3G_INVALID_VALUE);
1.347 + return 0;
1.348 + }
1.349 +
1.350 + M3G_ASSERT(stripLengths[strip] > 0);
1.351 + {
1.352 + int i;
1.353 + for (i = 0; i < stripLengths[strip]; ++i, ++idx) {
1.354 + if ((*idx & 0xFFFF0000u) != 0) { /* > 65535? */
1.355 + m3gRaiseError(m3g, M3G_INVALID_INDEX);
1.356 + return 0;
1.357 + }
1.358 + if (*idx > maxIndex)
1.359 + maxIndex = *idx;
1.360 + }
1.361 + }
1.362 + }
1.363 + }
1.364 +
1.365 + {
1.366 + /* Allocate the buffer object */
1.367 +
1.368 + IndexBuffer *buf = m3gAllocZ(m3g, sizeof(IndexBuffer));
1.369 + if (buf == NULL) {
1.370 + return 0;
1.371 + }
1.372 + /* IndexBuffer is derived from Object */
1.373 + m3gInitObject(&buf->object, m3g, M3G_CLASS_INDEX_BUFFER);
1.374 +
1.375 + buf->glPrimitive = GL_TRIANGLE_STRIP;
1.376 + buf->indexCount = joinedIndexCount;
1.377 +
1.378 + /* Allocate the index elements as either bytes or shorts,
1.379 + * depending on the maximum value we need to store. Note that
1.380 + * OpenGL ES does not support 32-bit indices */
1.381 +
1.382 + if (maxIndex <= 0xFF) {
1.383 + buf->indices = m3gAlloc(m3g, (M3Gsize) joinedIndexCount);
1.384 + buf->glType = GL_UNSIGNED_BYTE;
1.385 + }
1.386 + else {
1.387 + M3G_ASSERT(maxIndex <= 0xFFFF);
1.388 + buf->indices = m3gAlloc(m3g, (M3Gsize) joinedIndexCount*2);
1.389 + buf->glType = GL_UNSIGNED_SHORT;
1.390 + }
1.391 +
1.392 + /* Allocate space for original strip lengths */
1.393 + buf->lengths = (M3Gushort *) m3gAlloc(m3g, (M3Gsize) stripCount*2);
1.394 +
1.395 + if (buf->indices == NULL || buf->lengths == NULL) {
1.396 + m3gDeleteObject((M3GObject) buf);
1.397 + return 0;
1.398 + }
1.399 +
1.400 + buf->stripCount = stripCount;
1.401 +
1.402 + {
1.403 + /* Copy the indices, converting to the chosen type and
1.404 + * joining the strips as we go */
1.405 +
1.406 + M3Guint *src = (M3Guint*) stripIndices; /* type asserted above */
1.407 + void *dstStrip = buf->indices;
1.408 + int strip;
1.409 +
1.410 + for (strip = 0; strip < stripCount; ++strip) {
1.411 + int i;
1.412 +
1.413 + buf->lengths[strip] = (M3Gushort) stripLengths[strip];
1.414 +
1.415 + /*@notfunction@*/
1.416 + #define COPY_STRIP(indexType) do { \
1.417 + indexType *dst = (indexType *) dstStrip; \
1.418 + if (strip != 0) { \
1.419 + *dst++ = (indexType) *(src-1); \
1.420 + *dst++ = (indexType) *src; \
1.421 + if (stripLengths[strip-1] & 1) { \
1.422 + *dst++ = (indexType) *src; \
1.423 + } \
1.424 + } \
1.425 + for (i = 0; i < stripLengths[strip]; ++i) { \
1.426 + *dst++ = (indexType) *src++; \
1.427 + } \
1.428 + dstStrip = (void *) dst; \
1.429 + M3G_ASSERT(dst <= (indexType *)(buf->indices) + buf->indexCount); \
1.430 + } while (0)
1.431 +
1.432 + switch (buf->glType) {
1.433 +
1.434 + case GL_UNSIGNED_BYTE:
1.435 + COPY_STRIP(GLubyte);
1.436 + break;
1.437 +
1.438 + case GL_UNSIGNED_SHORT:
1.439 + COPY_STRIP(GLushort);
1.440 + break;
1.441 +
1.442 + default:
1.443 + M3G_ASSERT(0);
1.444 + }
1.445 +
1.446 + #undef COPY_STRIP
1.447 + }
1.448 + }
1.449 +
1.450 + /* Store maximum index */
1.451 + buf->maxIndex = maxIndex;
1.452 +
1.453 + /* All done! */
1.454 + return (M3GIndexBuffer) buf;
1.455 + }
1.456 +}
1.457 +
1.458 +/*!
1.459 + * \brief Gets the number of index batches in an index buffer
1.460 + *
1.461 + * An index batch usually corresponds to a single OpenGL rendering
1.462 + * call.
1.463 + *
1.464 + * \param buffer index buffer handle
1.465 + * \return number of rendering batches
1.466 + */
1.467 +M3G_API M3Gint m3gGetBatchCount(M3GIndexBuffer buffer)
1.468 +{
1.469 + M3G_VALIDATE_OBJECT(buffer);
1.470 + M3G_UNREF(buffer);
1.471 + return 1;
1.472 +}
1.473 +
1.474 +/*!
1.475 + * \brief Returns the indices in an index batch
1.476 + *
1.477 + * \param buffer index buffer handle
1.478 + * \param batchIndex batch index
1.479 + * \param indices pointer to a buffer to hold the indices
1.480 + * \retval M3G_TRUE buffer has explicit indices
1.481 + * \retval M3G_FALSE buffer has implicit indices; only the first index
1.482 + * is stored in \c indices
1.483 + */
1.484 +M3G_API M3Gbool m3gGetBatchIndices(M3GIndexBuffer buffer,
1.485 + M3Gint batchIndex,
1.486 + M3Gint *indices)
1.487 +{
1.488 + M3Gint i, j, tri = 0;
1.489 + M3Gint triIndices[4] = {0, 0, 0, 0};
1.490 + M3G_VALIDATE_OBJECT(buffer);
1.491 + M3G_UNREF(batchIndex);
1.492 +
1.493 + for (i = 0; i < buffer->stripCount; i++) {
1.494 + for (j = 0; j < buffer->lengths[i] - 2; j++) {
1.495 + m3gGetIndices(buffer, tri, triIndices);
1.496 +
1.497 + *indices++ = triIndices[0];
1.498 + if (triIndices[3] == 0) {
1.499 + *indices++ = triIndices[1];
1.500 + *indices++ = triIndices[2];
1.501 + }
1.502 + else {
1.503 + *indices++ = triIndices[2];
1.504 + *indices++ = triIndices[1];
1.505 + }
1.506 +
1.507 + ++tri;
1.508 + }
1.509 +
1.510 + /* Eliminate degenerate triangles */
1.511 + if (buffer->lengths[i] & 1) {
1.512 + tri += 5;
1.513 + }
1.514 + else {
1.515 + tri += 4;
1.516 + }
1.517 + }
1.518 +
1.519 + return M3G_TRUE;
1.520 +}
1.521 +
1.522 +/*!
1.523 + * \brief Returns the size of an index batch
1.524 + *
1.525 + * \param buffer index buffer handle
1.526 + * \param batchIndex batch index
1.527 + * \return number of indices in the batch
1.528 + */
1.529 +M3G_API M3Gint m3gGetBatchSize(M3GIndexBuffer buffer, M3Gint batchIndex)
1.530 +{
1.531 + M3Gint i, count = 0;
1.532 + M3G_VALIDATE_OBJECT(buffer);
1.533 +
1.534 + if (batchIndex != 0) {
1.535 + return 0;
1.536 + }
1.537 +
1.538 + for (i = 0; i < buffer->stripCount; i++) {
1.539 + count += buffer->lengths[i] - 2;
1.540 + }
1.541 +
1.542 + return count * 3;
1.543 +}
1.544 +
1.545 +/*!
1.546 + * \brief Returns the primitive type of an index buffer
1.547 + *
1.548 + * \param buffer index buffer handle
1.549 + * \return type of primitives stored in the buffer
1.550 + */
1.551 +M3G_API M3Gprimitive m3gGetPrimitive(M3GIndexBuffer buffer)
1.552 +{
1.553 + M3G_UNREF(buffer);
1.554 + M3G_VALIDATE_OBJECT(buffer);
1.555 + M3G_ASSERT(buffer->glPrimitive == GL_TRIANGLE_STRIP);
1.556 + return M3G_TRIANGLE_STRIPS;
1.557 +}
1.558 +