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: Light manager implementation
22 * \brief Light manager implementation
25 #ifndef M3G_CORE_INCLUDE
26 # error included by m3g_core.c; do not compile separately.
29 #include "m3g_lightmanager.h"
30 #include "m3g_light.h"
31 #include "m3g_rendercontext.h"
36 * \brief Light array element
40 /*! \internal \brief eye space spot direction */
43 /*! \internal \brief eye space position */
46 /*! \internal \brief reference to the Light node */
50 /*----------------------------------------------------------------------
52 *--------------------------------------------------------------------*/
56 * \brief Update a single light record
58 * Light position and spot direction are transformed into world space,
59 * i.e. omitting the viewing transformation which is applied by OpenGL
60 * when rendering. Both transformations are special cases and
61 * accomplished by just reading a part of the matrix.
63 * \note We need to transform the spotlight direction even if the
64 * light is not a spotlight, since in immediate mode, it may change
65 * into a spotlight later on!
67 static void m3gSetLightRecord(LightRecord *lrec,
72 M3G_ASSIGN_REF(lrec->light, light);
75 m3gGetMatrixColumn(tf, 3, &lrec->position);
76 m3gGetMatrixColumn(tf, 2, &v);
77 lrec->spotDir.x = -v.x;
78 lrec->spotDir.y = -v.y;
79 lrec->spotDir.z = -v.z;
80 lrec->spotDir.w = 0.0f;
83 lrec->spotDir.x = lrec->spotDir.y = lrec->spotDir.w = 0.0f;
84 lrec->spotDir.z = -1.0f;
85 lrec->position.x = lrec->position.y = lrec->position.z = 0.0f;
86 lrec->position.w = 1.0f;
90 /*----------------------------------------------------------------------
92 *--------------------------------------------------------------------*/
96 * \brief Clears all lights in the current pool of lights
98 static void m3gClearLights2(LightManager *mgr)
101 PointerArray *lights;
105 lights = &mgr->lights;
106 n = m3gArraySize(lights);
107 for (i = 0; i < n; ++i) {
108 lrec = m3gGetArrayElement(lights, i);
109 M3G_ASSIGN_REF(lrec->light, NULL);
117 * \brief Destroys the light manager, freeing allocated resources
119 static void m3gDestroyLightManager(LightManager *mgr, Interface *m3g)
123 M3G_VALIDATE_INTERFACE(m3g);
125 /* First remove all light references */
126 m3gClearLights2(mgr);
128 /* Free the records currently in the light array */
129 n = m3gArraySize(&mgr->lights);
130 for (i = 0; i < n; ++i) {
131 m3gFree(m3g, m3gGetArrayElement(&mgr->lights, i));
133 m3gDestroyArray(&mgr->lights, m3g);
138 * \brief Appends a light at the end of the light manager array
140 static M3Gint m3gInsertLight(LightManager *mgr,
146 PointerArray *lights;
149 M3G_VALIDATE_INTERFACE(m3g);
151 lights = &mgr->lights;
153 /* Get the first unused light record, or add a new one */
155 if (mgr->numActive < m3gArraySize(lights)) {
156 lrec = m3gGetArrayElement(lights, mgr->numActive);
159 M3G_ASSERT(mgr->numActive == m3gArraySize(lights));
160 lrec = m3gAllocZ(m3g, sizeof(LightRecord));
164 if (m3gArrayAppend(lights, lrec, m3g) == -1) {
168 idx = mgr->numActive++;
170 m3gSetLightRecord(lrec, light, tf);
178 static M3Gsizei m3gLightArraySize(const LightManager *mgr)
181 return mgr->numActive;
188 static Light *m3gGetLightTransformInternal(const LightManager *mgr, M3Gint idx, M3GMatrix *transform)
193 M3G_ASSERT(m3gInRange(idx, 0, mgr->numActive - 1));
195 lrec = m3gGetArrayElement(&mgr->lights, idx);
197 if (transform != NULL) {
198 m3gZero(matrix, sizeof(matrix));
200 matrix[0 * 4 + 0] = 1.f;
201 matrix[1 * 4 + 1] = 1.f;
203 matrix[2 * 4 + 0] = -lrec->spotDir.x;
204 matrix[2 * 4 + 1] = -lrec->spotDir.y;
205 matrix[2 * 4 + 2] = -lrec->spotDir.z;
207 matrix[3 * 4 + 0] = lrec->position.x;
208 matrix[3 * 4 + 1] = lrec->position.y;
209 matrix[3 * 4 + 2] = lrec->position.z;
210 matrix[3 * 4 + 3] = lrec->position.w;
212 m3gSetMatrixColumns(transform, matrix);
220 * \brief Replaces an existing light in the light array
222 static void m3gReplaceLight(LightManager *mgr,
229 M3G_ASSERT(m3gInRange(idx, 0, mgr->numActive - 1));
231 lrec = m3gGetArrayElement(&mgr->lights, idx);
232 m3gSetLightRecord(lrec, light, tf);
237 * \brief Selects a set of lights from the current light array for OpenGL
239 * Selects a maximum on \c maxNum lights from the array matching the
240 * given scope, sets those into the current OpenGL context, and
241 * disables the rest of the OpenGL lights GL_LIGHT0..GL_LIGHT7. A
242 * maximum of 8 lights is ever used.
245 static void m3gSelectGLLights(const LightManager *mgr,
248 M3Gfloat x, M3Gfloat y, M3Gfloat z)
250 const PointerArray *lights;
251 int i, required, total;
252 GLenum glIndex = GL_LIGHT0;
259 lights = &mgr->lights;
260 required = m3gClampInt(maxNum, 0, 8);
261 total = mgr->numActive;
263 /* Select the first n lights that match the scope */
265 for (i = 0; required > 0 && i < total; ++i) {
266 const LightRecord *lrec;
269 lrec = (const LightRecord *) m3gGetArrayElement(lights, i);
270 M3G_ASSERT(lrec != NULL);
273 if (light != NULL && (light->node.scope & scope) != 0) {
274 m3gApplyLight(light, glIndex++, &lrec->position, &lrec->spotDir);
279 /* Disable the leftover lights */
281 while (glIndex <= GL_LIGHT7) {
282 glDisable(glIndex++);
288 * \brief Transforms all lights with the given matrix
290 static void m3gTransformLights(LightManager *mgr, const Matrix *mtx)
292 const PointerArray *lights;
295 lights = &mgr->lights;
298 for (i = 0; i < n; ++i) {
299 LightRecord *lrec = (LightRecord*) m3gGetArrayElement(lights, i);
300 m3gTransformVec4(mtx, &lrec->position);
301 m3gTransformVec4(mtx, &lrec->spotDir);