os/graphics/m3g/m3gcore11/src/m3g_indexbuffer.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 /*
     2 * Copyright (c) 2003 Nokia Corporation and/or its subsidiary(-ies).
     3 * All rights reserved.
     4 * This component and the accompanying materials are made available
     5 * under the terms of the License "Eclipse Public License v1.0"
     6 * which accompanies this distribution, and is available
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
     8 *
     9 * Initial Contributors:
    10 * Nokia Corporation - initial contribution.
    11 *
    12 * Contributors:
    13 *
    14 * Description: IndexBuffer implementation
    15 *
    16 */
    17 
    18 
    19 /*!
    20  * \internal
    21  * \file
    22  * \brief IndexBuffer implementation
    23  */
    24 
    25 #ifndef M3G_CORE_INCLUDE
    26 #   error included by m3g_core.c; do not compile separately.
    27 #endif
    28 
    29 #include "m3g_indexbuffer.h"
    30 
    31 /*----------------------------------------------------------------------
    32  * Private functions
    33  *--------------------------------------------------------------------*/
    34 
    35 
    36 /*----------------------------------------------------------------------
    37  * Internal functions
    38  *--------------------------------------------------------------------*/
    39 
    40 /*!
    41  * \internal
    42  * \brief IndexBuffer destructor
    43  *
    44  * \param obj IndexBuffer object
    45  */
    46 static void m3gDestroyIndexBuffer(Object *obj)
    47 {
    48     IndexBuffer *ib = (IndexBuffer *) obj;
    49     M3G_VALIDATE_OBJECT(ib);
    50 
    51 	{
    52 		Interface *m3g = M3G_INTERFACE(ib);
    53 		m3gFree(m3g, ib->indices);
    54 		m3gFree(m3g, ib->lengths);
    55 	}
    56 
    57     m3gDestroyObject(obj);
    58 }
    59 
    60 /*!
    61  * \internal
    62  * \brief Sends the contents of an IndexBuffer to the current GL
    63  * instance for processing
    64  *
    65  * \param buf IndexBuffer object
    66  */
    67 static void m3gSendIndexBuffer(const IndexBuffer *buf)
    68 {
    69     M3G_VALIDATE_OBJECT(buf);
    70     
    71     M3G_ASSERT(buf->indices);
    72     M3G_ASSERT(buf->glPrimitive == GL_TRIANGLE_STRIP);
    73     
    74     M3G_BEGIN_PROFILE(M3G_INTERFACE(buf), M3G_PROFILE_NGL_DRAW);
    75     glDrawElements(buf->glPrimitive, buf->indexCount, buf->glType, buf->indices);
    76     M3G_END_PROFILE(M3G_INTERFACE(buf), M3G_PROFILE_NGL_DRAW);
    77 
    78     M3G_ASSERT_GL;
    79 }
    80 
    81 /*!
    82  * \internal
    83  * \brief Gets triangle indices, used by mesh pick routine.
    84  *
    85  * \param buf IndexBuffer object
    86  * \param triangle triangle index
    87  * \param indices triangle indices
    88  * \retval M3G_TRUE  indices fetched
    89  * \retval M3G_FALSE no such triangle
    90  */
    91 static M3Gbool m3gGetIndices(const IndexBuffer *buf,
    92                              M3Gint triangle,
    93                              M3Gint *indices) {
    94     M3Gubyte *bptr;
    95     M3Gushort *sptr;
    96 
    97     if(triangle + 2 >= buf->indexCount) return M3G_FALSE;
    98 
    99     switch(buf->glType) {
   100         case GL_UNSIGNED_BYTE:
   101             bptr = (M3Gubyte *)buf->indices;
   102             bptr += triangle;
   103             indices[0] = *bptr++;
   104             indices[1] = *bptr++;
   105             indices[2] = *bptr;
   106             break;
   107 
   108         case GL_UNSIGNED_SHORT:
   109             sptr = (M3Gushort *)buf->indices;
   110             sptr += triangle;
   111             indices[0] = (M3Gint) *sptr++;
   112             indices[1] = (M3Gint) *sptr++;
   113             indices[2] = (M3Gint) *sptr;
   114             break;
   115     }
   116 
   117     /* Winding */
   118     indices[3] = triangle & 1;
   119 
   120     return M3G_TRUE;
   121 }
   122 
   123 /*!
   124  * \internal
   125  * \brief Overloaded Object3D method.
   126  *
   127  * \param originalObj original IndexBuffer object
   128  * \param cloneObj pointer to cloned IndexBuffer object
   129  * \param pairs array for all object-duplicate pairs
   130  * \param numPairs number of pairs
   131  */
   132 static M3Gbool m3gIndexBufferDuplicate(const Object *originalObj,
   133                                        Object **cloneObj,
   134                                        Object **pairs,
   135                                        M3Gint *numPairs)
   136 {
   137     M3Gint size;
   138     IndexBuffer *original = (IndexBuffer *)originalObj;
   139     IndexBuffer *clone = (IndexBuffer *)m3gAllocZ(originalObj->interface, sizeof(IndexBuffer));
   140 
   141     if (clone == NULL) {
   142         return M3G_FALSE;
   143     }
   144 
   145     *cloneObj = (Object *)clone;
   146 
   147     /* Call init since this object is 'manually' created */
   148     m3gInitObject((Object*) clone, originalObj->interface, M3G_CLASS_INDEX_BUFFER);
   149 
   150     if(!m3gObjectDuplicate(originalObj, cloneObj, pairs, numPairs)) {
   151         return M3G_FALSE;
   152     }
   153 
   154     clone->indexCount = original->indexCount;
   155     clone->glType = original->glType;
   156     clone->glPrimitive = original->glPrimitive;
   157     clone->stripCount = original->stripCount;
   158 
   159     if (clone->glType == GL_UNSIGNED_BYTE) {
   160         size = clone->indexCount;
   161         clone->indices = m3gAlloc(originalObj->interface, size);
   162     }
   163     else {
   164         size = clone->indexCount * sizeof(M3Gshort);
   165         clone->indices = m3gAlloc(originalObj->interface, size);
   166     }
   167 
   168     clone->lengths = (M3Gushort *) m3gAlloc(originalObj->interface, (M3Gsize) clone->stripCount*2);
   169 
   170     if(clone->indices == NULL || clone->lengths == NULL) {
   171         /* Duplicate will call m3gDeleteObject */
   172         return M3G_FALSE;
   173     }
   174 
   175     m3gCopy(clone->lengths, original->lengths, clone->stripCount*2);
   176     m3gCopy(clone->indices, original->indices, size);
   177 
   178     return M3G_TRUE;
   179 }
   180 
   181 /*!
   182  * \internal
   183  * \brief Gets maximum index of this index buffer.
   184  *
   185  * \param buf IndexBuffer object
   186  * \return maximum index used
   187  */
   188 static M3Gint m3gGetMaxIndex(const IndexBuffer *buf)
   189 {
   190     return buf->maxIndex;
   191 }
   192 
   193 /*----------------------------------------------------------------------
   194  * Virtual function table
   195  *--------------------------------------------------------------------*/
   196 
   197 static const ObjectVFTable m3gvf_IndexBuffer = {
   198     m3gObjectApplyAnimation,
   199     m3gObjectIsCompatible,
   200     m3gObjectUpdateProperty,
   201     m3gObjectDoGetReferences,
   202     m3gObjectFindID,
   203     m3gIndexBufferDuplicate,
   204     m3gDestroyIndexBuffer
   205 };
   206 
   207 /*----------------------------------------------------------------------
   208  * Public functions
   209  *--------------------------------------------------------------------*/
   210 
   211 /*!
   212  * \brief Creates an implicit strip buffer
   213  *
   214  * \param interface     M3G interface
   215  * \param stripCount    number of triangle strips
   216  * \param stripLengths  array of strip lengths
   217  * \param firstIndex    first index
   218  * \retval IndexBuffer new IndexBuffer object
   219  * \retval NULL IndexBuffer creating failed
   220  */
   221 M3G_API M3GIndexBuffer m3gCreateImplicitStripBuffer(
   222     M3GInterface interface,
   223     M3Gsizei stripCount,
   224     const M3Gsizei *stripLengths,
   225     M3Gint firstIndex)
   226 {
   227 	M3GIndexBuffer ib;
   228 	M3Gint *stripIndices, i, indexCount = 0;
   229     Interface *m3g = (Interface *) interface;
   230     M3G_VALIDATE_INTERFACE(m3g);
   231 	
   232 	if (stripLengths == NULL) {
   233 		m3gRaiseError(m3g, M3G_NULL_POINTER);
   234         return 0;
   235 	}
   236 
   237     if (stripCount == 0) {
   238 		m3gRaiseError(m3g, M3G_INVALID_VALUE);
   239         return 0;
   240     }
   241 
   242 	for (i = 0; i < stripCount; i++) {
   243 		if(stripLengths[i] < 3) {
   244 			m3gRaiseError(m3g, M3G_INVALID_VALUE);
   245             return 0;
   246 		}
   247 		indexCount += stripLengths[i];
   248 	}
   249 
   250 	if (firstIndex < 0 ||
   251 		(firstIndex + indexCount) > 65535) {
   252 		m3gRaiseError(m3g, M3G_INVALID_INDEX);
   253         return 0;
   254 	}
   255 
   256 	stripIndices = m3gAlloc(m3g, indexCount * sizeof(M3Gint));
   257 
   258 	if (stripIndices == NULL) {
   259 		return 0;	/* automatic out of memory from m3gAlloc */
   260 	}
   261 
   262 	/* Generate explict arrays */
   263     
   264 	for (i = 0; i < indexCount; i++) {
   265 		stripIndices[i] = firstIndex + i;
   266 	}
   267 
   268 	ib = m3gCreateStripBuffer(interface,
   269                               M3G_TRIANGLE_STRIPS,
   270                               stripCount, stripLengths,
   271                               M3G_INT, indexCount, stripIndices);
   272 	m3gFree(m3g, stripIndices);
   273 	return ib;
   274 }
   275 
   276 /*!
   277  * \brief Creates an indexed triangle strip buffer
   278  *
   279  * \note Optimizes rendering by joining the indices. Also scans the
   280  * array for the maximum value, and allocates the storage using the
   281  * smallest possible data type.
   282  *
   283  * \param interface     M3G interface
   284  * \param primitive     primitive type, always M3G_TRIANGLE_STRIPS
   285  * \param stripCount    number of triangle strips
   286  * \param stripLengths  array of strip lengths
   287  * \param type          data type of indices
   288  * \param numIndices    number of indices
   289  * \param stripIndices  array of indices
   290  * \retval IndexBuffer new IndexBuffer object
   291  * \retval NULL IndexBuffer creating failed
   292  */
   293 M3G_API M3GIndexBuffer m3gCreateStripBuffer(M3GInterface interface,
   294                                             M3Gprimitive primitive,
   295                                             M3Gsizei stripCount,
   296                                             const M3Gsizei *stripLengths,
   297                                             M3Gdatatype type,
   298                                             M3Gsizei numIndices,
   299                                             const void *stripIndices)
   300 {
   301     M3Gsizei joinedIndexCount = 0;
   302     M3Gsizei originalIndexCount = 0;
   303     M3Gint maxIndex = 0;
   304 
   305     Interface *m3g = (Interface *) interface;
   306     M3G_VALIDATE_INTERFACE(m3g);
   307 
   308     if (primitive != M3G_TRIANGLE_STRIPS
   309         || (type != M3G_INT && type != M3G_UINT)) {
   310         m3gRaiseError(m3g, M3G_INVALID_ENUM);
   311         return 0;
   312     }
   313     if (stripIndices == NULL ||
   314     	stripLengths == NULL) {
   315         m3gRaiseError(m3g, M3G_NULL_POINTER);
   316         return 0;
   317     }
   318 
   319 	if (stripCount == 0 || numIndices == 0) {
   320         m3gRaiseError(m3g, M3G_INVALID_VALUE);
   321         return 0;
   322 	}
   323 
   324 	{
   325         /* Find the maximum index and count the actual number of indices
   326          * required for joining the strips */
   327         
   328         int strip;
   329         M3Gint *idx = (M3Gint *) stripIndices;
   330         for (strip = 0; strip < stripCount; ++strip) {
   331             if(stripLengths[strip] < 3) {
   332                 m3gRaiseError(m3g, M3G_INVALID_VALUE);
   333                 return 0;
   334             }
   335             if (strip != 0) {
   336                 joinedIndexCount += (M3Guint)((joinedIndexCount & 1) ? 3 : 2);
   337             }
   338 
   339             joinedIndexCount += (M3Guint) stripLengths[strip];
   340             originalIndexCount += (M3Guint) stripLengths[strip];
   341 
   342         	if (numIndices < originalIndexCount) {
   343         		m3gRaiseError(m3g, M3G_INVALID_VALUE);
   344                 return 0;
   345         	}
   346 
   347             M3G_ASSERT(stripLengths[strip] > 0);
   348             {
   349                 int i;
   350                 for (i = 0; i < stripLengths[strip]; ++i, ++idx) {
   351                     if ((*idx & 0xFFFF0000u) != 0) { /* > 65535? */
   352                     	m3gRaiseError(m3g, M3G_INVALID_INDEX);
   353                         return 0;
   354                     }
   355                     if (*idx > maxIndex)
   356                         maxIndex = *idx;
   357                 }
   358             }
   359         }
   360     }
   361 
   362     {
   363         /* Allocate the buffer object */
   364     
   365         IndexBuffer *buf = m3gAllocZ(m3g, sizeof(IndexBuffer));
   366         if (buf == NULL) {
   367             return 0;
   368         }
   369 		/* IndexBuffer is derived from Object */
   370 		m3gInitObject(&buf->object, m3g, M3G_CLASS_INDEX_BUFFER);
   371 
   372         buf->glPrimitive = GL_TRIANGLE_STRIP;
   373         buf->indexCount = joinedIndexCount;
   374 
   375         /* Allocate the index elements as either bytes or shorts,
   376          * depending on the maximum value we need to store. Note that
   377          * OpenGL ES does not support 32-bit indices */
   378         
   379         if (maxIndex <= 0xFF) {
   380             buf->indices = m3gAlloc(m3g, (M3Gsize) joinedIndexCount);
   381             buf->glType = GL_UNSIGNED_BYTE;
   382         }
   383         else {
   384             M3G_ASSERT(maxIndex <= 0xFFFF);
   385             buf->indices = m3gAlloc(m3g, (M3Gsize) joinedIndexCount*2);
   386             buf->glType = GL_UNSIGNED_SHORT;
   387         }
   388         
   389         /* Allocate space for original strip lengths */
   390         buf->lengths = (M3Gushort *) m3gAlloc(m3g, (M3Gsize) stripCount*2);
   391 
   392         if (buf->indices == NULL || buf->lengths == NULL) {
   393             m3gDeleteObject((M3GObject) buf);
   394             return 0;
   395         }
   396 
   397         buf->stripCount = stripCount;
   398 
   399         {
   400             /* Copy the indices, converting to the chosen type and
   401              * joining the strips as we go */
   402             
   403             M3Guint *src = (M3Guint*) stripIndices;     /* type asserted above */
   404             void *dstStrip = buf->indices;
   405             int strip;
   406             
   407             for (strip = 0; strip < stripCount; ++strip) {
   408                 int i;
   409 
   410                 buf->lengths[strip] = (M3Gushort) stripLengths[strip];
   411 
   412                 /*@notfunction@*/
   413                 #define COPY_STRIP(indexType) do {              \
   414                     indexType *dst = (indexType *) dstStrip;    \
   415                     if (strip != 0) {                           \
   416                         *dst++ = (indexType) *(src-1);          \
   417                         *dst++ = (indexType) *src;              \
   418                         if (stripLengths[strip-1] & 1) {        \
   419                             *dst++ = (indexType) *src;          \
   420                         }                                       \
   421                     }                                           \
   422                     for (i = 0; i < stripLengths[strip]; ++i) { \
   423                         *dst++ = (indexType) *src++;            \
   424                     }                                           \
   425                     dstStrip = (void *) dst;                    \
   426                     M3G_ASSERT(dst <= (indexType *)(buf->indices) + buf->indexCount); \
   427                 } while (0)
   428                     
   429                 switch (buf->glType) {
   430                     
   431                 case GL_UNSIGNED_BYTE:
   432                     COPY_STRIP(GLubyte);
   433                     break;
   434                     
   435                 case GL_UNSIGNED_SHORT:
   436                     COPY_STRIP(GLushort);
   437                     break;
   438                     
   439                 default:
   440                     M3G_ASSERT(0);
   441                 }
   442                 
   443                 #undef COPY_STRIP
   444             }
   445         }
   446 
   447         /* Store maximum index */
   448         buf->maxIndex = maxIndex;
   449 
   450         /* All done! */
   451         return (M3GIndexBuffer) buf;
   452     }
   453 }
   454 
   455 /*!
   456  * \brief Gets the number of index batches in an index buffer
   457  *
   458  * An index batch usually corresponds to a single OpenGL rendering
   459  * call.
   460  *
   461  * \param buffer  index buffer handle
   462  * \return number of rendering batches
   463  */
   464 M3G_API M3Gint m3gGetBatchCount(M3GIndexBuffer buffer)
   465 {
   466     M3G_VALIDATE_OBJECT(buffer);
   467     M3G_UNREF(buffer);
   468     return 1;
   469 }
   470 
   471 /*!
   472  * \brief Returns the indices in an index batch
   473  *
   474  * \param buffer      index buffer handle
   475  * \param batchIndex  batch index
   476  * \param indices     pointer to a buffer to hold the indices
   477  * \retval M3G_TRUE   buffer has explicit indices
   478  * \retval M3G_FALSE  buffer has implicit indices; only the first index
   479  *                    is stored in \c indices
   480  */
   481 M3G_API M3Gbool m3gGetBatchIndices(M3GIndexBuffer buffer,
   482                                    M3Gint batchIndex,
   483                                    M3Gint *indices)
   484 {
   485     M3Gint i, j, tri = 0;
   486     M3Gint triIndices[4] = {0, 0, 0, 0};
   487     M3G_VALIDATE_OBJECT(buffer);
   488     M3G_UNREF(batchIndex);
   489 
   490     for (i = 0; i < buffer->stripCount; i++) {
   491         for (j = 0; j < buffer->lengths[i] - 2; j++) {
   492             m3gGetIndices(buffer, tri, triIndices); 
   493 
   494             *indices++ = triIndices[0];
   495             if (triIndices[3] == 0) {
   496                 *indices++ = triIndices[1];
   497                 *indices++ = triIndices[2];
   498             }
   499             else {
   500                 *indices++ = triIndices[2];
   501                 *indices++ = triIndices[1];
   502             }
   503 
   504             ++tri;
   505         }
   506 
   507         /* Eliminate degenerate triangles */
   508         if (buffer->lengths[i] & 1) {
   509             tri += 5;
   510         }
   511         else {
   512             tri += 4;
   513         }
   514     }
   515 
   516     return M3G_TRUE;
   517 }
   518 
   519 /*!
   520  * \brief Returns the size of an index batch
   521  *
   522  * \param buffer      index buffer handle
   523  * \param batchIndex  batch index
   524  * \return number of indices in the batch
   525  */
   526 M3G_API M3Gint m3gGetBatchSize(M3GIndexBuffer buffer, M3Gint batchIndex)
   527 {
   528     M3Gint i, count = 0;
   529     M3G_VALIDATE_OBJECT(buffer);
   530     
   531     if (batchIndex != 0) {
   532         return 0;
   533     }
   534 
   535     for (i = 0; i < buffer->stripCount; i++) {
   536         count += buffer->lengths[i] - 2;
   537     }
   538 
   539     return count * 3;
   540 }
   541 
   542 /*!
   543  * \brief Returns the primitive type of an index buffer
   544  *
   545  * \param buffer  index buffer handle
   546  * \return type of primitives stored in the buffer
   547  */
   548 M3G_API M3Gprimitive m3gGetPrimitive(M3GIndexBuffer buffer)
   549 {
   550     M3G_UNREF(buffer);
   551     M3G_VALIDATE_OBJECT(buffer);
   552     M3G_ASSERT(buffer->glPrimitive == GL_TRIANGLE_STRIP);
   553     return M3G_TRIANGLE_STRIPS;
   554 }
   555