1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/graphics/m3g/m3gcore11/src/m3g_renderqueue.c Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,302 @@
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: RenderQueue implementation
1.18 +*
1.19 +*/
1.20 +
1.21 +
1.22 +/*!
1.23 + * \internal
1.24 + * \file
1.25 + * \brief RenderQueue implementation.
1.26 + *
1.27 + * Render queue holds
1.28 + * meshes and sprites that are added to queue in rendering
1.29 + * setup. After setup, queue is committed and contents are
1.30 + * rendered. Queue grows dynamically, its initial size is
1.31 + * defined in m3g_defs.h.
1.32 + */
1.33 +
1.34 +#ifndef M3G_CORE_INCLUDE
1.35 +# error included by m3g_core.c; do not compile separately.
1.36 +#endif
1.37 +
1.38 +#include "m3g_array.h"
1.39 +
1.40 +/*----------------------------------------------------------------------
1.41 + * Private data structures
1.42 + *--------------------------------------------------------------------*/
1.43 +
1.44 +/*!
1.45 + * \internal
1.46 + * \brief RenderQueue entry object
1.47 + */
1.48 +struct RenderItemImpl
1.49 +{
1.50 + Node *node;
1.51 + Matrix toCamera;
1.52 +
1.53 + M3Gint subMeshIndex;
1.54 + M3Guint sortKey;
1.55 +};
1.56 +
1.57 +/*!
1.58 + * \internal
1.59 + * \brief Drawable queue
1.60 + */
1.61 +struct RenderBucketImpl
1.62 +{
1.63 + PointerArray items;
1.64 +};
1.65 +
1.66 +
1.67 +/* Sanity checking... */
1.68 +M3G_CT_ASSERT(M3G_RENDERQUEUE_BUCKET_BITS >= M3G_APPEARANCE_HARD_SORT_BITS);
1.69 +
1.70 +
1.71 +/*----------------------------------------------------------------------
1.72 + * Private functions
1.73 + *--------------------------------------------------------------------*/
1.74 +
1.75 +static M3G_INLINE RenderBucket *m3gGetRenderBucket(RenderQueue *rq,
1.76 + M3Guint sortKey,
1.77 + Interface *m3g)
1.78 +{
1.79 + int i = (int)(sortKey >> (32 - M3G_RENDERQUEUE_BUCKET_BITS));
1.80 + RenderBucket *bucket = rq->buckets[i];
1.81 +
1.82 + if (!bucket) {
1.83 + bucket = m3gAllocZ(m3g, sizeof(RenderBucket));
1.84 + /* array already initialized by zero-allocation; see m3g_array.h */
1.85 + rq->buckets[i] = bucket;
1.86 + }
1.87 +
1.88 + if (i < rq->minBucket) {
1.89 + rq->minBucket = i;
1.90 + }
1.91 + if (i > rq->maxBucket) {
1.92 + rq->maxBucket = i;
1.93 + }
1.94 +
1.95 + return bucket;
1.96 +}
1.97 +
1.98 +static void m3gDestroyRenderBucket(RenderBucket *bucket, Interface *m3g)
1.99 +{
1.100 + if (bucket) {
1.101 + int i;
1.102 + PointerArray *items = &bucket->items;
1.103 + for (i = 0; i < m3gArraySize(items); ++i) {
1.104 + m3gFree(m3g, m3gGetArrayElement(items, i));
1.105 + }
1.106 + m3gDestroyArray(items, m3g);
1.107 + }
1.108 + m3gFree(m3g, bucket);
1.109 +}
1.110 +
1.111 +static RenderItem *m3gGetRenderItem(RenderQueue *rq, Interface *m3g)
1.112 +{
1.113 + RenderItem *item = rq->freeItems;
1.114 + if (!item) {
1.115 + m3gIncStat(m3g, M3G_STAT_RENDERQUEUE_SIZE, 1);
1.116 + item = m3gAlloc(m3g, sizeof(RenderItem));
1.117 + }
1.118 + else {
1.119 + M3G_VALIDATE_MEMBLOCK(item);
1.120 + rq->freeItems = *(RenderItem**)item; /* move to next */
1.121 + }
1.122 + return item;
1.123 +}
1.124 +
1.125 +static void m3gRecycleRenderItem(RenderQueue *rq, RenderItem *item)
1.126 +{
1.127 + if (item) {
1.128 + *(RenderItem**)item = rq->freeItems; /* store "next" pointer */
1.129 + rq->freeItems = item;
1.130 + }
1.131 +}
1.132 +
1.133 +static M3Gbool m3gInsertRenderItem(RenderBucket *bucket,
1.134 + RenderItem *item,
1.135 + Interface *m3g)
1.136 +{
1.137 + PointerArray *items = &bucket->items;
1.138 + int idx = m3gArraySize(items);
1.139 +
1.140 + /* Do a binary search for the sorting key of the item */
1.141 + {
1.142 + M3Guint key = item->sortKey;
1.143 + int low = 0;
1.144 + int high = idx;
1.145 + const RenderItem *cmp;
1.146 +
1.147 + idx >>= 1;
1.148 +
1.149 + while (low < high) {
1.150 + cmp = (const RenderItem*) m3gGetArrayElement(items, idx);
1.151 +
1.152 + if (cmp->sortKey < key) {
1.153 + low = idx + 1;
1.154 + }
1.155 + else if (cmp->sortKey > key) {
1.156 + high = idx;
1.157 + }
1.158 + else {
1.159 + break;
1.160 + }
1.161 + idx = (low + high) >> 1;
1.162 + }
1.163 + }
1.164 +
1.165 + /* Now that we know where to insert, insert; out of memory here
1.166 + * returns < 0 */
1.167 +
1.168 + return (m3gArrayInsert(items, idx, item, m3g) >= 0);
1.169 +}
1.170 +
1.171 +
1.172 +/*----------------------------------------------------------------------
1.173 + * Internal functions
1.174 + *--------------------------------------------------------------------*/
1.175 +
1.176 +/*!
1.177 + * \internal
1.178 + * \brief Creates a new render queue.
1.179 + *
1.180 + * \param m3g M3G interface object
1.181 + * \return RenderQueue object
1.182 + */
1.183 +static RenderQueue *m3gCreateRenderQueue(Interface *m3g)
1.184 +{
1.185 + RenderQueue *rq;
1.186 +
1.187 + rq = m3gAllocZ(m3g, (M3Gsizei) sizeof(RenderQueue));
1.188 + return rq;
1.189 +}
1.190 +
1.191 +/*!
1.192 + * \internal
1.193 + * \brief Destroys a render queue and frees
1.194 + * all allocated memory.
1.195 + *
1.196 + * \param m3g M3G interface object
1.197 + * \param rq RenderQueue
1.198 + */
1.199 +static void m3gDestroyRenderQueue(Interface *m3g, RenderQueue *rq)
1.200 +{
1.201 + if (rq) {
1.202 + int i;
1.203 + for (i = 0; i < (1 << M3G_RENDERQUEUE_BUCKET_BITS); ++i) {
1.204 + RenderBucket *bucket = rq->buckets[i];
1.205 + m3gDestroyRenderBucket(bucket, m3g);
1.206 + }
1.207 + while (rq->freeItems) {
1.208 + RenderItem *item = rq->freeItems;
1.209 + rq->freeItems = *(RenderItem**)item;
1.210 + m3gFree(m3g, item);
1.211 + }
1.212 + }
1.213 + m3gFree(m3g, rq);
1.214 +}
1.215 +
1.216 +/*!
1.217 + * \internal
1.218 + * \brief Inserts a mesh to the queue. May allocate
1.219 + * memory if queue size is exceeded.
1.220 + *
1.221 + * \param m3g M3G interface object
1.222 + * \param rq RenderQueue
1.223 + * \param mesh Mesh object
1.224 + * \param subMeshIndex submesh index inside mesh
1.225 + * \param sortKey sorting key
1.226 + */
1.227 +static M3Gbool m3gInsertDrawable(Interface *m3g,
1.228 + RenderQueue *rq,
1.229 + Node *node,
1.230 + const Matrix *toCamera,
1.231 + M3Gint subMeshIndex,
1.232 + M3Guint sortKey)
1.233 +{
1.234 + RenderItem *item;
1.235 + RenderBucket *bucket;
1.236 +
1.237 + item = m3gGetRenderItem(rq, m3g);
1.238 + if (!item) {
1.239 + goto OutOfMemory;
1.240 + }
1.241 +
1.242 + bucket = m3gGetRenderBucket(rq, sortKey, m3g);
1.243 + if (!bucket) {
1.244 + goto OutOfMemory;
1.245 + }
1.246 +
1.247 + item->node = node;
1.248 + item->toCamera = *toCamera;
1.249 + item->subMeshIndex = subMeshIndex;
1.250 + item->sortKey = (sortKey << M3G_RENDERQUEUE_BUCKET_BITS);
1.251 +
1.252 + M3G_BEGIN_PROFILE(m3g, M3G_PROFILE_SETUP_SORT);
1.253 + if (!m3gInsertRenderItem(bucket, item, m3g)) {
1.254 + goto OutOfMemory;
1.255 + }
1.256 + M3G_END_PROFILE(m3g, M3G_PROFILE_SETUP_SORT);
1.257 + return M3G_TRUE;
1.258 +
1.259 +OutOfMemory:
1.260 + m3gRecycleRenderItem(rq, item);
1.261 + return M3G_FALSE;
1.262 +}
1.263 +
1.264 +/*!
1.265 + * \internal
1.266 + * \brief Clears the queue.
1.267 + *
1.268 + * \param rq RenderQueue
1.269 + */
1.270 +static void m3gClearRenderQueue(RenderQueue *rq)
1.271 +{
1.272 + rq->root = NULL;
1.273 + rq->lightManager = NULL;
1.274 + rq->minBucket = (1 << M3G_RENDERQUEUE_BUCKET_BITS);
1.275 + rq->maxBucket = 0;
1.276 +}
1.277 +
1.278 +/*!
1.279 + * \internal
1.280 + * \brief Commits the queue by rendering its contents.
1.281 + *
1.282 + * \param rq RenderQueue
1.283 + * \param ctx RenderContext object
1.284 + */
1.285 +static void m3gCommit(RenderQueue *rq, RenderContext *ctx)
1.286 +{
1.287 + M3Gint b;
1.288 +
1.289 + for (b = rq->minBucket; b <= rq->maxBucket; ++b) {
1.290 + if (rq->buckets[b]) {
1.291 + PointerArray *items = &rq->buckets[b]->items;
1.292 + int n = m3gArraySize(items);
1.293 + int i;
1.294 + for (i = 0; i < n; ++i) {
1.295 + RenderItem *item = (RenderItem*) m3gGetArrayElement(items, i);
1.296 + M3G_VFUNC(Node, item->node, doRender)(
1.297 + item->node, ctx, &item->toCamera, item->subMeshIndex);
1.298 + m3gRecycleRenderItem(rq, item);
1.299 + }
1.300 + m3gClearArray(items);
1.301 + m3gIncStat(M3G_INTERFACE(ctx), M3G_STAT_RENDER_NODES_DRAWN, n);
1.302 + }
1.303 + }
1.304 +}
1.305 +