--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/m3g/m3gcore11/src/m3g_renderqueue.c Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,302 @@
+/*
+* Copyright (c) 2003 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: RenderQueue implementation
+*
+*/
+
+
+/*!
+ * \internal
+ * \file
+ * \brief RenderQueue implementation.
+ *
+ * Render queue holds
+ * meshes and sprites that are added to queue in rendering
+ * setup. After setup, queue is committed and contents are
+ * rendered. Queue grows dynamically, its initial size is
+ * defined in m3g_defs.h.
+ */
+
+#ifndef M3G_CORE_INCLUDE
+# error included by m3g_core.c; do not compile separately.
+#endif
+
+#include "m3g_array.h"
+
+/*----------------------------------------------------------------------
+ * Private data structures
+ *--------------------------------------------------------------------*/
+
+/*!
+ * \internal
+ * \brief RenderQueue entry object
+ */
+struct RenderItemImpl
+{
+ Node *node;
+ Matrix toCamera;
+
+ M3Gint subMeshIndex;
+ M3Guint sortKey;
+};
+
+/*!
+ * \internal
+ * \brief Drawable queue
+ */
+struct RenderBucketImpl
+{
+ PointerArray items;
+};
+
+
+/* Sanity checking... */
+M3G_CT_ASSERT(M3G_RENDERQUEUE_BUCKET_BITS >= M3G_APPEARANCE_HARD_SORT_BITS);
+
+
+/*----------------------------------------------------------------------
+ * Private functions
+ *--------------------------------------------------------------------*/
+
+static M3G_INLINE RenderBucket *m3gGetRenderBucket(RenderQueue *rq,
+ M3Guint sortKey,
+ Interface *m3g)
+{
+ int i = (int)(sortKey >> (32 - M3G_RENDERQUEUE_BUCKET_BITS));
+ RenderBucket *bucket = rq->buckets[i];
+
+ if (!bucket) {
+ bucket = m3gAllocZ(m3g, sizeof(RenderBucket));
+ /* array already initialized by zero-allocation; see m3g_array.h */
+ rq->buckets[i] = bucket;
+ }
+
+ if (i < rq->minBucket) {
+ rq->minBucket = i;
+ }
+ if (i > rq->maxBucket) {
+ rq->maxBucket = i;
+ }
+
+ return bucket;
+}
+
+static void m3gDestroyRenderBucket(RenderBucket *bucket, Interface *m3g)
+{
+ if (bucket) {
+ int i;
+ PointerArray *items = &bucket->items;
+ for (i = 0; i < m3gArraySize(items); ++i) {
+ m3gFree(m3g, m3gGetArrayElement(items, i));
+ }
+ m3gDestroyArray(items, m3g);
+ }
+ m3gFree(m3g, bucket);
+}
+
+static RenderItem *m3gGetRenderItem(RenderQueue *rq, Interface *m3g)
+{
+ RenderItem *item = rq->freeItems;
+ if (!item) {
+ m3gIncStat(m3g, M3G_STAT_RENDERQUEUE_SIZE, 1);
+ item = m3gAlloc(m3g, sizeof(RenderItem));
+ }
+ else {
+ M3G_VALIDATE_MEMBLOCK(item);
+ rq->freeItems = *(RenderItem**)item; /* move to next */
+ }
+ return item;
+}
+
+static void m3gRecycleRenderItem(RenderQueue *rq, RenderItem *item)
+{
+ if (item) {
+ *(RenderItem**)item = rq->freeItems; /* store "next" pointer */
+ rq->freeItems = item;
+ }
+}
+
+static M3Gbool m3gInsertRenderItem(RenderBucket *bucket,
+ RenderItem *item,
+ Interface *m3g)
+{
+ PointerArray *items = &bucket->items;
+ int idx = m3gArraySize(items);
+
+ /* Do a binary search for the sorting key of the item */
+ {
+ M3Guint key = item->sortKey;
+ int low = 0;
+ int high = idx;
+ const RenderItem *cmp;
+
+ idx >>= 1;
+
+ while (low < high) {
+ cmp = (const RenderItem*) m3gGetArrayElement(items, idx);
+
+ if (cmp->sortKey < key) {
+ low = idx + 1;
+ }
+ else if (cmp->sortKey > key) {
+ high = idx;
+ }
+ else {
+ break;
+ }
+ idx = (low + high) >> 1;
+ }
+ }
+
+ /* Now that we know where to insert, insert; out of memory here
+ * returns < 0 */
+
+ return (m3gArrayInsert(items, idx, item, m3g) >= 0);
+}
+
+
+/*----------------------------------------------------------------------
+ * Internal functions
+ *--------------------------------------------------------------------*/
+
+/*!
+ * \internal
+ * \brief Creates a new render queue.
+ *
+ * \param m3g M3G interface object
+ * \return RenderQueue object
+ */
+static RenderQueue *m3gCreateRenderQueue(Interface *m3g)
+{
+ RenderQueue *rq;
+
+ rq = m3gAllocZ(m3g, (M3Gsizei) sizeof(RenderQueue));
+ return rq;
+}
+
+/*!
+ * \internal
+ * \brief Destroys a render queue and frees
+ * all allocated memory.
+ *
+ * \param m3g M3G interface object
+ * \param rq RenderQueue
+ */
+static void m3gDestroyRenderQueue(Interface *m3g, RenderQueue *rq)
+{
+ if (rq) {
+ int i;
+ for (i = 0; i < (1 << M3G_RENDERQUEUE_BUCKET_BITS); ++i) {
+ RenderBucket *bucket = rq->buckets[i];
+ m3gDestroyRenderBucket(bucket, m3g);
+ }
+ while (rq->freeItems) {
+ RenderItem *item = rq->freeItems;
+ rq->freeItems = *(RenderItem**)item;
+ m3gFree(m3g, item);
+ }
+ }
+ m3gFree(m3g, rq);
+}
+
+/*!
+ * \internal
+ * \brief Inserts a mesh to the queue. May allocate
+ * memory if queue size is exceeded.
+ *
+ * \param m3g M3G interface object
+ * \param rq RenderQueue
+ * \param mesh Mesh object
+ * \param subMeshIndex submesh index inside mesh
+ * \param sortKey sorting key
+ */
+static M3Gbool m3gInsertDrawable(Interface *m3g,
+ RenderQueue *rq,
+ Node *node,
+ const Matrix *toCamera,
+ M3Gint subMeshIndex,
+ M3Guint sortKey)
+{
+ RenderItem *item;
+ RenderBucket *bucket;
+
+ item = m3gGetRenderItem(rq, m3g);
+ if (!item) {
+ goto OutOfMemory;
+ }
+
+ bucket = m3gGetRenderBucket(rq, sortKey, m3g);
+ if (!bucket) {
+ goto OutOfMemory;
+ }
+
+ item->node = node;
+ item->toCamera = *toCamera;
+ item->subMeshIndex = subMeshIndex;
+ item->sortKey = (sortKey << M3G_RENDERQUEUE_BUCKET_BITS);
+
+ M3G_BEGIN_PROFILE(m3g, M3G_PROFILE_SETUP_SORT);
+ if (!m3gInsertRenderItem(bucket, item, m3g)) {
+ goto OutOfMemory;
+ }
+ M3G_END_PROFILE(m3g, M3G_PROFILE_SETUP_SORT);
+ return M3G_TRUE;
+
+OutOfMemory:
+ m3gRecycleRenderItem(rq, item);
+ return M3G_FALSE;
+}
+
+/*!
+ * \internal
+ * \brief Clears the queue.
+ *
+ * \param rq RenderQueue
+ */
+static void m3gClearRenderQueue(RenderQueue *rq)
+{
+ rq->root = NULL;
+ rq->lightManager = NULL;
+ rq->minBucket = (1 << M3G_RENDERQUEUE_BUCKET_BITS);
+ rq->maxBucket = 0;
+}
+
+/*!
+ * \internal
+ * \brief Commits the queue by rendering its contents.
+ *
+ * \param rq RenderQueue
+ * \param ctx RenderContext object
+ */
+static void m3gCommit(RenderQueue *rq, RenderContext *ctx)
+{
+ M3Gint b;
+
+ for (b = rq->minBucket; b <= rq->maxBucket; ++b) {
+ if (rq->buckets[b]) {
+ PointerArray *items = &rq->buckets[b]->items;
+ int n = m3gArraySize(items);
+ int i;
+ for (i = 0; i < n; ++i) {
+ RenderItem *item = (RenderItem*) m3gGetArrayElement(items, i);
+ M3G_VFUNC(Node, item->node, doRender)(
+ item->node, ctx, &item->toCamera, item->subMeshIndex);
+ m3gRecycleRenderItem(rq, item);
+ }
+ m3gClearArray(items);
+ m3gIncStat(M3G_INTERFACE(ctx), M3G_STAT_RENDER_NODES_DRAWN, n);
+ }
+ }
+}
+