1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/graphics/m3g/m3gcore11/src/m3g_lightmanager.c Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,304 @@
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: Light manager implementation
1.18 +*
1.19 +*/
1.20 +
1.21 +
1.22 +/*!
1.23 + * \internal
1.24 + * \file
1.25 + * \brief Light manager implementation
1.26 + */
1.27 +
1.28 +#ifndef M3G_CORE_INCLUDE
1.29 +# error included by m3g_core.c; do not compile separately.
1.30 +#endif
1.31 +
1.32 +#include "m3g_lightmanager.h"
1.33 +#include "m3g_light.h"
1.34 +#include "m3g_rendercontext.h"
1.35 +#include "m3g_math.h"
1.36 +
1.37 +/*!
1.38 + * \internal
1.39 + * \brief Light array element
1.40 + */
1.41 +typedef struct
1.42 +{
1.43 + /*! \internal \brief eye space spot direction */
1.44 + Vec4 spotDir;
1.45 +
1.46 + /*! \internal \brief eye space position */
1.47 + Vec4 position;
1.48 +
1.49 + /*! \internal \brief reference to the Light node */
1.50 + Light *light;
1.51 +} LightRecord;
1.52 +
1.53 +/*----------------------------------------------------------------------
1.54 + * Private functions
1.55 + *--------------------------------------------------------------------*/
1.56 +
1.57 +/*!
1.58 + * \internal
1.59 + * \brief Update a single light record
1.60 + *
1.61 + * Light position and spot direction are transformed into world space,
1.62 + * i.e. omitting the viewing transformation which is applied by OpenGL
1.63 + * when rendering. Both transformations are special cases and
1.64 + * accomplished by just reading a part of the matrix.
1.65 + *
1.66 + * \note We need to transform the spotlight direction even if the
1.67 + * light is not a spotlight, since in immediate mode, it may change
1.68 + * into a spotlight later on!
1.69 + */
1.70 +static void m3gSetLightRecord(LightRecord *lrec,
1.71 + Light *light,
1.72 + const Matrix *tf)
1.73 +{
1.74 + Vec4 v;
1.75 + M3G_ASSIGN_REF(lrec->light, light);
1.76 +
1.77 + if (tf != NULL) {
1.78 + m3gGetMatrixColumn(tf, 3, &lrec->position);
1.79 + m3gGetMatrixColumn(tf, 2, &v);
1.80 + lrec->spotDir.x = -v.x;
1.81 + lrec->spotDir.y = -v.y;
1.82 + lrec->spotDir.z = -v.z;
1.83 + lrec->spotDir.w = 0.0f;
1.84 + }
1.85 + else {
1.86 + lrec->spotDir.x = lrec->spotDir.y = lrec->spotDir.w = 0.0f;
1.87 + lrec->spotDir.z = -1.0f;
1.88 + lrec->position.x = lrec->position.y = lrec->position.z = 0.0f;
1.89 + lrec->position.w = 1.0f;
1.90 + }
1.91 +}
1.92 +
1.93 +/*----------------------------------------------------------------------
1.94 + * Internal functions
1.95 + *--------------------------------------------------------------------*/
1.96 +
1.97 +/*!
1.98 + * \internal
1.99 + * \brief Clears all lights in the current pool of lights
1.100 + */
1.101 +static void m3gClearLights2(LightManager *mgr)
1.102 +{
1.103 + LightRecord *lrec;
1.104 + PointerArray *lights;
1.105 + int i, n;
1.106 + M3G_ASSERT_PTR(mgr);
1.107 +
1.108 + lights = &mgr->lights;
1.109 + n = m3gArraySize(lights);
1.110 + for (i = 0; i < n; ++i) {
1.111 + lrec = m3gGetArrayElement(lights, i);
1.112 + M3G_ASSIGN_REF(lrec->light, NULL);
1.113 + }
1.114 +
1.115 + mgr->numActive = 0;
1.116 +}
1.117 +
1.118 +/*!
1.119 + * \internal
1.120 + * \brief Destroys the light manager, freeing allocated resources
1.121 + */
1.122 +static void m3gDestroyLightManager(LightManager *mgr, Interface *m3g)
1.123 +{
1.124 + int i, n;
1.125 + M3G_ASSERT_PTR(mgr);
1.126 + M3G_VALIDATE_INTERFACE(m3g);
1.127 +
1.128 + /* First remove all light references */
1.129 + m3gClearLights2(mgr);
1.130 +
1.131 + /* Free the records currently in the light array */
1.132 + n = m3gArraySize(&mgr->lights);
1.133 + for (i = 0; i < n; ++i) {
1.134 + m3gFree(m3g, m3gGetArrayElement(&mgr->lights, i));
1.135 + }
1.136 + m3gDestroyArray(&mgr->lights, m3g);
1.137 +}
1.138 +
1.139 +/*!
1.140 + * \internal
1.141 + * \brief Appends a light at the end of the light manager array
1.142 + */
1.143 +static M3Gint m3gInsertLight(LightManager *mgr,
1.144 + Light *light,
1.145 + const Matrix *tf,
1.146 + Interface *m3g)
1.147 +{
1.148 + LightRecord *lrec;
1.149 + PointerArray *lights;
1.150 + M3Gint idx;
1.151 + M3G_ASSERT_PTR(mgr);
1.152 + M3G_VALIDATE_INTERFACE(m3g);
1.153 +
1.154 + lights = &mgr->lights;
1.155 +
1.156 + /* Get the first unused light record, or add a new one */
1.157 +
1.158 + if (mgr->numActive < m3gArraySize(lights)) {
1.159 + lrec = m3gGetArrayElement(lights, mgr->numActive);
1.160 + }
1.161 + else {
1.162 + M3G_ASSERT(mgr->numActive == m3gArraySize(lights));
1.163 + lrec = m3gAllocZ(m3g, sizeof(LightRecord));
1.164 + if (lrec == NULL) {
1.165 + return -1;
1.166 + }
1.167 + if (m3gArrayAppend(lights, lrec, m3g) == -1) {
1.168 + return -1;
1.169 + }
1.170 + }
1.171 + idx = mgr->numActive++;
1.172 +
1.173 + m3gSetLightRecord(lrec, light, tf);
1.174 + return idx;
1.175 +}
1.176 +
1.177 +/*!
1.178 + * \internal
1.179 + * \brief
1.180 + */
1.181 +static M3Gsizei m3gLightArraySize(const LightManager *mgr)
1.182 +{
1.183 + M3G_ASSERT_PTR(mgr);
1.184 + return mgr->numActive;
1.185 +}
1.186 +
1.187 +/*!
1.188 + * \internal
1.189 + * \brief
1.190 + */
1.191 +static Light *m3gGetLightTransformInternal(const LightManager *mgr, M3Gint idx, M3GMatrix *transform)
1.192 +{
1.193 + M3Gfloat matrix[16];
1.194 + LightRecord *lrec;
1.195 + M3G_ASSERT_PTR(mgr);
1.196 + M3G_ASSERT(m3gInRange(idx, 0, mgr->numActive - 1));
1.197 +
1.198 + lrec = m3gGetArrayElement(&mgr->lights, idx);
1.199 +
1.200 + if (transform != NULL) {
1.201 + m3gZero(matrix, sizeof(matrix));
1.202 +
1.203 + matrix[0 * 4 + 0] = 1.f;
1.204 + matrix[1 * 4 + 1] = 1.f;
1.205 +
1.206 + matrix[2 * 4 + 0] = -lrec->spotDir.x;
1.207 + matrix[2 * 4 + 1] = -lrec->spotDir.y;
1.208 + matrix[2 * 4 + 2] = -lrec->spotDir.z;
1.209 +
1.210 + matrix[3 * 4 + 0] = lrec->position.x;
1.211 + matrix[3 * 4 + 1] = lrec->position.y;
1.212 + matrix[3 * 4 + 2] = lrec->position.z;
1.213 + matrix[3 * 4 + 3] = lrec->position.w;
1.214 +
1.215 + m3gSetMatrixColumns(transform, matrix);
1.216 + }
1.217 +
1.218 + return lrec->light;
1.219 +}
1.220 +
1.221 +/*!
1.222 + * \internal
1.223 + * \brief Replaces an existing light in the light array
1.224 + */
1.225 +static void m3gReplaceLight(LightManager *mgr,
1.226 + M3Gint idx,
1.227 + Light *light,
1.228 + const Matrix *tf)
1.229 +{
1.230 + LightRecord *lrec;
1.231 + M3G_ASSERT_PTR(mgr);
1.232 + M3G_ASSERT(m3gInRange(idx, 0, mgr->numActive - 1));
1.233 +
1.234 + lrec = m3gGetArrayElement(&mgr->lights, idx);
1.235 + m3gSetLightRecord(lrec, light, tf);
1.236 +}
1.237 +
1.238 +/*!
1.239 + * \internal
1.240 + * \brief Selects a set of lights from the current light array for OpenGL
1.241 + *
1.242 + * Selects a maximum on \c maxNum lights from the array matching the
1.243 + * given scope, sets those into the current OpenGL context, and
1.244 + * disables the rest of the OpenGL lights GL_LIGHT0..GL_LIGHT7. A
1.245 + * maximum of 8 lights is ever used.
1.246 + *
1.247 + */
1.248 +static void m3gSelectGLLights(const LightManager *mgr,
1.249 + M3Gsizei maxNum,
1.250 + M3Guint scope,
1.251 + M3Gfloat x, M3Gfloat y, M3Gfloat z)
1.252 +{
1.253 + const PointerArray *lights;
1.254 + int i, required, total;
1.255 + GLenum glIndex = GL_LIGHT0;
1.256 + M3G_ASSERT_PTR(mgr);
1.257 +
1.258 + M3G_UNREF(x);
1.259 + M3G_UNREF(y);
1.260 + M3G_UNREF(z);
1.261 +
1.262 + lights = &mgr->lights;
1.263 + required = m3gClampInt(maxNum, 0, 8);
1.264 + total = mgr->numActive;
1.265 +
1.266 + /* Select the first n lights that match the scope */
1.267 +
1.268 + for (i = 0; required > 0 && i < total; ++i) {
1.269 + const LightRecord *lrec;
1.270 + const Light *light;
1.271 +
1.272 + lrec = (const LightRecord *) m3gGetArrayElement(lights, i);
1.273 + M3G_ASSERT(lrec != NULL);
1.274 + light = lrec->light;
1.275 +
1.276 + if (light != NULL && (light->node.scope & scope) != 0) {
1.277 + m3gApplyLight(light, glIndex++, &lrec->position, &lrec->spotDir);
1.278 + --required;
1.279 + }
1.280 + }
1.281 +
1.282 + /* Disable the leftover lights */
1.283 +
1.284 + while (glIndex <= GL_LIGHT7) {
1.285 + glDisable(glIndex++);
1.286 + }
1.287 +}
1.288 +
1.289 +/*!
1.290 + * \internal
1.291 + * \brief Transforms all lights with the given matrix
1.292 + */
1.293 +static void m3gTransformLights(LightManager *mgr, const Matrix *mtx)
1.294 +{
1.295 + const PointerArray *lights;
1.296 + M3Gint i, n;
1.297 +
1.298 + lights = &mgr->lights;
1.299 + n = mgr->numActive;
1.300 +
1.301 + for (i = 0; i < n; ++i) {
1.302 + LightRecord *lrec = (LightRecord*) m3gGetArrayElement(lights, i);
1.303 + m3gTransformVec4(mtx, &lrec->position);
1.304 + m3gTransformVec4(mtx, &lrec->spotDir);
1.305 + }
1.306 +}
1.307 +