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: RenderQueue implementation
22 * \brief RenderQueue implementation.
25 * meshes and sprites that are added to queue in rendering
26 * setup. After setup, queue is committed and contents are
27 * rendered. Queue grows dynamically, its initial size is
28 * defined in m3g_defs.h.
31 #ifndef M3G_CORE_INCLUDE
32 # error included by m3g_core.c; do not compile separately.
35 #include "m3g_array.h"
37 /*----------------------------------------------------------------------
38 * Private data structures
39 *--------------------------------------------------------------------*/
43 * \brief RenderQueue entry object
56 * \brief Drawable queue
58 struct RenderBucketImpl
64 /* Sanity checking... */
65 M3G_CT_ASSERT(M3G_RENDERQUEUE_BUCKET_BITS >= M3G_APPEARANCE_HARD_SORT_BITS);
68 /*----------------------------------------------------------------------
70 *--------------------------------------------------------------------*/
72 static M3G_INLINE RenderBucket *m3gGetRenderBucket(RenderQueue *rq,
76 int i = (int)(sortKey >> (32 - M3G_RENDERQUEUE_BUCKET_BITS));
77 RenderBucket *bucket = rq->buckets[i];
80 bucket = m3gAllocZ(m3g, sizeof(RenderBucket));
81 /* array already initialized by zero-allocation; see m3g_array.h */
82 rq->buckets[i] = bucket;
85 if (i < rq->minBucket) {
88 if (i > rq->maxBucket) {
95 static void m3gDestroyRenderBucket(RenderBucket *bucket, Interface *m3g)
99 PointerArray *items = &bucket->items;
100 for (i = 0; i < m3gArraySize(items); ++i) {
101 m3gFree(m3g, m3gGetArrayElement(items, i));
103 m3gDestroyArray(items, m3g);
105 m3gFree(m3g, bucket);
108 static RenderItem *m3gGetRenderItem(RenderQueue *rq, Interface *m3g)
110 RenderItem *item = rq->freeItems;
112 m3gIncStat(m3g, M3G_STAT_RENDERQUEUE_SIZE, 1);
113 item = m3gAlloc(m3g, sizeof(RenderItem));
116 M3G_VALIDATE_MEMBLOCK(item);
117 rq->freeItems = *(RenderItem**)item; /* move to next */
122 static void m3gRecycleRenderItem(RenderQueue *rq, RenderItem *item)
125 *(RenderItem**)item = rq->freeItems; /* store "next" pointer */
126 rq->freeItems = item;
130 static M3Gbool m3gInsertRenderItem(RenderBucket *bucket,
134 PointerArray *items = &bucket->items;
135 int idx = m3gArraySize(items);
137 /* Do a binary search for the sorting key of the item */
139 M3Guint key = item->sortKey;
142 const RenderItem *cmp;
147 cmp = (const RenderItem*) m3gGetArrayElement(items, idx);
149 if (cmp->sortKey < key) {
152 else if (cmp->sortKey > key) {
158 idx = (low + high) >> 1;
162 /* Now that we know where to insert, insert; out of memory here
165 return (m3gArrayInsert(items, idx, item, m3g) >= 0);
169 /*----------------------------------------------------------------------
171 *--------------------------------------------------------------------*/
175 * \brief Creates a new render queue.
177 * \param m3g M3G interface object
178 * \return RenderQueue object
180 static RenderQueue *m3gCreateRenderQueue(Interface *m3g)
184 rq = m3gAllocZ(m3g, (M3Gsizei) sizeof(RenderQueue));
190 * \brief Destroys a render queue and frees
191 * all allocated memory.
193 * \param m3g M3G interface object
194 * \param rq RenderQueue
196 static void m3gDestroyRenderQueue(Interface *m3g, RenderQueue *rq)
200 for (i = 0; i < (1 << M3G_RENDERQUEUE_BUCKET_BITS); ++i) {
201 RenderBucket *bucket = rq->buckets[i];
202 m3gDestroyRenderBucket(bucket, m3g);
204 while (rq->freeItems) {
205 RenderItem *item = rq->freeItems;
206 rq->freeItems = *(RenderItem**)item;
215 * \brief Inserts a mesh to the queue. May allocate
216 * memory if queue size is exceeded.
218 * \param m3g M3G interface object
219 * \param rq RenderQueue
220 * \param mesh Mesh object
221 * \param subMeshIndex submesh index inside mesh
222 * \param sortKey sorting key
224 static M3Gbool m3gInsertDrawable(Interface *m3g,
227 const Matrix *toCamera,
232 RenderBucket *bucket;
234 item = m3gGetRenderItem(rq, m3g);
239 bucket = m3gGetRenderBucket(rq, sortKey, m3g);
245 item->toCamera = *toCamera;
246 item->subMeshIndex = subMeshIndex;
247 item->sortKey = (sortKey << M3G_RENDERQUEUE_BUCKET_BITS);
249 M3G_BEGIN_PROFILE(m3g, M3G_PROFILE_SETUP_SORT);
250 if (!m3gInsertRenderItem(bucket, item, m3g)) {
253 M3G_END_PROFILE(m3g, M3G_PROFILE_SETUP_SORT);
257 m3gRecycleRenderItem(rq, item);
263 * \brief Clears the queue.
265 * \param rq RenderQueue
267 static void m3gClearRenderQueue(RenderQueue *rq)
270 rq->lightManager = NULL;
271 rq->minBucket = (1 << M3G_RENDERQUEUE_BUCKET_BITS);
277 * \brief Commits the queue by rendering its contents.
279 * \param rq RenderQueue
280 * \param ctx RenderContext object
282 static void m3gCommit(RenderQueue *rq, RenderContext *ctx)
286 for (b = rq->minBucket; b <= rq->maxBucket; ++b) {
287 if (rq->buckets[b]) {
288 PointerArray *items = &rq->buckets[b]->items;
289 int n = m3gArraySize(items);
291 for (i = 0; i < n; ++i) {
292 RenderItem *item = (RenderItem*) m3gGetArrayElement(items, i);
293 M3G_VFUNC(Node, item->node, doRender)(
294 item->node, ctx, &item->toCamera, item->subMeshIndex);
295 m3gRecycleRenderItem(rq, item);
297 m3gClearArray(items);
298 m3gIncStat(M3G_INTERFACE(ctx), M3G_STAT_RENDER_NODES_DRAWN, n);