Update contrib.
2 * Copyright (c) 2003 Nokia Corporation and/or its subsidiary(-ies).
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".
9 * Initial Contributors:
10 * Nokia Corporation - initial contribution.
14 * Description: IndexBuffer implementation
22 * \brief IndexBuffer implementation
25 #ifndef M3G_CORE_INCLUDE
26 # error included by m3g_core.c; do not compile separately.
29 #include "m3g_indexbuffer.h"
31 /*----------------------------------------------------------------------
33 *--------------------------------------------------------------------*/
36 /*----------------------------------------------------------------------
38 *--------------------------------------------------------------------*/
42 * \brief IndexBuffer destructor
44 * \param obj IndexBuffer object
46 static void m3gDestroyIndexBuffer(Object *obj)
48 IndexBuffer *ib = (IndexBuffer *) obj;
49 M3G_VALIDATE_OBJECT(ib);
52 Interface *m3g = M3G_INTERFACE(ib);
53 m3gFree(m3g, ib->indices);
54 m3gFree(m3g, ib->lengths);
57 m3gDestroyObject(obj);
62 * \brief Sends the contents of an IndexBuffer to the current GL
63 * instance for processing
65 * \param buf IndexBuffer object
67 static void m3gSendIndexBuffer(const IndexBuffer *buf)
69 M3G_VALIDATE_OBJECT(buf);
71 M3G_ASSERT(buf->indices);
72 M3G_ASSERT(buf->glPrimitive == GL_TRIANGLE_STRIP);
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);
83 * \brief Gets triangle indices, used by mesh pick routine.
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
91 static M3Gbool m3gGetIndices(const IndexBuffer *buf,
97 if(triangle + 2 >= buf->indexCount) return M3G_FALSE;
100 case GL_UNSIGNED_BYTE:
101 bptr = (M3Gubyte *)buf->indices;
103 indices[0] = *bptr++;
104 indices[1] = *bptr++;
108 case GL_UNSIGNED_SHORT:
109 sptr = (M3Gushort *)buf->indices;
111 indices[0] = (M3Gint) *sptr++;
112 indices[1] = (M3Gint) *sptr++;
113 indices[2] = (M3Gint) *sptr;
118 indices[3] = triangle & 1;
125 * \brief Overloaded Object3D method.
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
132 static M3Gbool m3gIndexBufferDuplicate(const Object *originalObj,
138 IndexBuffer *original = (IndexBuffer *)originalObj;
139 IndexBuffer *clone = (IndexBuffer *)m3gAllocZ(originalObj->interface, sizeof(IndexBuffer));
145 *cloneObj = (Object *)clone;
147 /* Call init since this object is 'manually' created */
148 m3gInitObject((Object*) clone, originalObj->interface, M3G_CLASS_INDEX_BUFFER);
150 if(!m3gObjectDuplicate(originalObj, cloneObj, pairs, numPairs)) {
154 clone->indexCount = original->indexCount;
155 clone->glType = original->glType;
156 clone->glPrimitive = original->glPrimitive;
157 clone->stripCount = original->stripCount;
159 if (clone->glType == GL_UNSIGNED_BYTE) {
160 size = clone->indexCount;
161 clone->indices = m3gAlloc(originalObj->interface, size);
164 size = clone->indexCount * sizeof(M3Gshort);
165 clone->indices = m3gAlloc(originalObj->interface, size);
168 clone->lengths = (M3Gushort *) m3gAlloc(originalObj->interface, (M3Gsize) clone->stripCount*2);
170 if(clone->indices == NULL || clone->lengths == NULL) {
171 /* Duplicate will call m3gDeleteObject */
175 m3gCopy(clone->lengths, original->lengths, clone->stripCount*2);
176 m3gCopy(clone->indices, original->indices, size);
183 * \brief Gets maximum index of this index buffer.
185 * \param buf IndexBuffer object
186 * \return maximum index used
188 static M3Gint m3gGetMaxIndex(const IndexBuffer *buf)
190 return buf->maxIndex;
193 /*----------------------------------------------------------------------
194 * Virtual function table
195 *--------------------------------------------------------------------*/
197 static const ObjectVFTable m3gvf_IndexBuffer = {
198 m3gObjectApplyAnimation,
199 m3gObjectIsCompatible,
200 m3gObjectUpdateProperty,
201 m3gObjectDoGetReferences,
203 m3gIndexBufferDuplicate,
204 m3gDestroyIndexBuffer
207 /*----------------------------------------------------------------------
209 *--------------------------------------------------------------------*/
212 * \brief Creates an implicit strip buffer
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
221 M3G_API M3GIndexBuffer m3gCreateImplicitStripBuffer(
222 M3GInterface interface,
224 const M3Gsizei *stripLengths,
228 M3Gint *stripIndices, i, indexCount = 0;
229 Interface *m3g = (Interface *) interface;
230 M3G_VALIDATE_INTERFACE(m3g);
232 if (stripLengths == NULL) {
233 m3gRaiseError(m3g, M3G_NULL_POINTER);
237 if (stripCount == 0) {
238 m3gRaiseError(m3g, M3G_INVALID_VALUE);
242 for (i = 0; i < stripCount; i++) {
243 if(stripLengths[i] < 3) {
244 m3gRaiseError(m3g, M3G_INVALID_VALUE);
247 indexCount += stripLengths[i];
250 if (firstIndex < 0 ||
251 (firstIndex + indexCount) > 65535) {
252 m3gRaiseError(m3g, M3G_INVALID_INDEX);
256 stripIndices = m3gAlloc(m3g, indexCount * sizeof(M3Gint));
258 if (stripIndices == NULL) {
259 return 0; /* automatic out of memory from m3gAlloc */
262 /* Generate explict arrays */
264 for (i = 0; i < indexCount; i++) {
265 stripIndices[i] = firstIndex + i;
268 ib = m3gCreateStripBuffer(interface,
270 stripCount, stripLengths,
271 M3G_INT, indexCount, stripIndices);
272 m3gFree(m3g, stripIndices);
277 * \brief Creates an indexed triangle strip buffer
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.
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
293 M3G_API M3GIndexBuffer m3gCreateStripBuffer(M3GInterface interface,
294 M3Gprimitive primitive,
296 const M3Gsizei *stripLengths,
299 const void *stripIndices)
301 M3Gsizei joinedIndexCount = 0;
302 M3Gsizei originalIndexCount = 0;
305 Interface *m3g = (Interface *) interface;
306 M3G_VALIDATE_INTERFACE(m3g);
308 if (primitive != M3G_TRIANGLE_STRIPS
309 || (type != M3G_INT && type != M3G_UINT)) {
310 m3gRaiseError(m3g, M3G_INVALID_ENUM);
313 if (stripIndices == NULL ||
314 stripLengths == NULL) {
315 m3gRaiseError(m3g, M3G_NULL_POINTER);
319 if (stripCount == 0 || numIndices == 0) {
320 m3gRaiseError(m3g, M3G_INVALID_VALUE);
325 /* Find the maximum index and count the actual number of indices
326 * required for joining the strips */
329 M3Gint *idx = (M3Gint *) stripIndices;
330 for (strip = 0; strip < stripCount; ++strip) {
331 if(stripLengths[strip] < 3) {
332 m3gRaiseError(m3g, M3G_INVALID_VALUE);
336 joinedIndexCount += (M3Guint)((joinedIndexCount & 1) ? 3 : 2);
339 joinedIndexCount += (M3Guint) stripLengths[strip];
340 originalIndexCount += (M3Guint) stripLengths[strip];
342 if (numIndices < originalIndexCount) {
343 m3gRaiseError(m3g, M3G_INVALID_VALUE);
347 M3G_ASSERT(stripLengths[strip] > 0);
350 for (i = 0; i < stripLengths[strip]; ++i, ++idx) {
351 if ((*idx & 0xFFFF0000u) != 0) { /* > 65535? */
352 m3gRaiseError(m3g, M3G_INVALID_INDEX);
363 /* Allocate the buffer object */
365 IndexBuffer *buf = m3gAllocZ(m3g, sizeof(IndexBuffer));
369 /* IndexBuffer is derived from Object */
370 m3gInitObject(&buf->object, m3g, M3G_CLASS_INDEX_BUFFER);
372 buf->glPrimitive = GL_TRIANGLE_STRIP;
373 buf->indexCount = joinedIndexCount;
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 */
379 if (maxIndex <= 0xFF) {
380 buf->indices = m3gAlloc(m3g, (M3Gsize) joinedIndexCount);
381 buf->glType = GL_UNSIGNED_BYTE;
384 M3G_ASSERT(maxIndex <= 0xFFFF);
385 buf->indices = m3gAlloc(m3g, (M3Gsize) joinedIndexCount*2);
386 buf->glType = GL_UNSIGNED_SHORT;
389 /* Allocate space for original strip lengths */
390 buf->lengths = (M3Gushort *) m3gAlloc(m3g, (M3Gsize) stripCount*2);
392 if (buf->indices == NULL || buf->lengths == NULL) {
393 m3gDeleteObject((M3GObject) buf);
397 buf->stripCount = stripCount;
400 /* Copy the indices, converting to the chosen type and
401 * joining the strips as we go */
403 M3Guint *src = (M3Guint*) stripIndices; /* type asserted above */
404 void *dstStrip = buf->indices;
407 for (strip = 0; strip < stripCount; ++strip) {
410 buf->lengths[strip] = (M3Gushort) stripLengths[strip];
413 #define COPY_STRIP(indexType) do { \
414 indexType *dst = (indexType *) dstStrip; \
416 *dst++ = (indexType) *(src-1); \
417 *dst++ = (indexType) *src; \
418 if (stripLengths[strip-1] & 1) { \
419 *dst++ = (indexType) *src; \
422 for (i = 0; i < stripLengths[strip]; ++i) { \
423 *dst++ = (indexType) *src++; \
425 dstStrip = (void *) dst; \
426 M3G_ASSERT(dst <= (indexType *)(buf->indices) + buf->indexCount); \
429 switch (buf->glType) {
431 case GL_UNSIGNED_BYTE:
435 case GL_UNSIGNED_SHORT:
436 COPY_STRIP(GLushort);
447 /* Store maximum index */
448 buf->maxIndex = maxIndex;
451 return (M3GIndexBuffer) buf;
456 * \brief Gets the number of index batches in an index buffer
458 * An index batch usually corresponds to a single OpenGL rendering
461 * \param buffer index buffer handle
462 * \return number of rendering batches
464 M3G_API M3Gint m3gGetBatchCount(M3GIndexBuffer buffer)
466 M3G_VALIDATE_OBJECT(buffer);
472 * \brief Returns the indices in an index batch
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
481 M3G_API M3Gbool m3gGetBatchIndices(M3GIndexBuffer buffer,
485 M3Gint i, j, tri = 0;
486 M3Gint triIndices[4] = {0, 0, 0, 0};
487 M3G_VALIDATE_OBJECT(buffer);
488 M3G_UNREF(batchIndex);
490 for (i = 0; i < buffer->stripCount; i++) {
491 for (j = 0; j < buffer->lengths[i] - 2; j++) {
492 m3gGetIndices(buffer, tri, triIndices);
494 *indices++ = triIndices[0];
495 if (triIndices[3] == 0) {
496 *indices++ = triIndices[1];
497 *indices++ = triIndices[2];
500 *indices++ = triIndices[2];
501 *indices++ = triIndices[1];
507 /* Eliminate degenerate triangles */
508 if (buffer->lengths[i] & 1) {
520 * \brief Returns the size of an index batch
522 * \param buffer index buffer handle
523 * \param batchIndex batch index
524 * \return number of indices in the batch
526 M3G_API M3Gint m3gGetBatchSize(M3GIndexBuffer buffer, M3Gint batchIndex)
529 M3G_VALIDATE_OBJECT(buffer);
531 if (batchIndex != 0) {
535 for (i = 0; i < buffer->stripCount; i++) {
536 count += buffer->lengths[i] - 2;
543 * \brief Returns the primitive type of an index buffer
545 * \param buffer index buffer handle
546 * \return type of primitives stored in the buffer
548 M3G_API M3Gprimitive m3gGetPrimitive(M3GIndexBuffer buffer)
551 M3G_VALIDATE_OBJECT(buffer);
552 M3G_ASSERT(buffer->glPrimitive == GL_TRIANGLE_STRIP);
553 return M3G_TRIANGLE_STRIPS;