1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/graphics/m3g/m3gcore11/src/m3g_light.c Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,534 @@
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 implementation
1.18 +*
1.19 +*/
1.20 +
1.21 +
1.22 +/*!
1.23 + * \internal
1.24 + * \file
1.25 + * \brief Light 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_light.h"
1.33 +#include "m3g_animationtrack.h"
1.34 +
1.35 +/*----------------------------------------------------------------------
1.36 + * Internal functions
1.37 + *--------------------------------------------------------------------*/
1.38 +
1.39 +/*!
1.40 + * \internal
1.41 + * \brief Overloaded Node method.
1.42 + *
1.43 + * Insert light to render queue.
1.44 + *
1.45 + * \param self Light object
1.46 + * \param toCamera transform to camera
1.47 + * \param alphaFactor total alpha factor
1.48 + * \param caller caller node
1.49 + * \param renderQueue RenderQueue
1.50 + *
1.51 + * \retval M3G_TRUE continue render setup
1.52 + * \retval M3G_FALSE abort render setup
1.53 + */
1.54 +static M3Gbool m3gLightSetupRender(Node *self,
1.55 + const Node *caller,
1.56 + SetupRenderState *s,
1.57 + RenderQueue *renderQueue)
1.58 +{
1.59 + M3G_UNREF(caller);
1.60 +
1.61 + if (renderQueue->lightManager != NULL) {
1.62 + Light *light = (Light *)self;
1.63 +
1.64 + if (self->enableBits & NODE_RENDER_BIT) {
1.65 + if (m3gInsertLight(renderQueue->lightManager,
1.66 + light, &s->toCamera, M3G_INTERFACE(light)) == -1)
1.67 + return M3G_FALSE;
1.68 + }
1.69 + }
1.70 +
1.71 + return M3G_TRUE;
1.72 +}
1.73 +
1.74 +/*!
1.75 + * \internal
1.76 + * \brief Overloaded Object3D method.
1.77 + *
1.78 + * \param property animation property
1.79 + * \retval M3G_TRUE property supported
1.80 + * \retval M3G_FALSE property not supported
1.81 + */
1.82 +static M3Gbool m3gLightIsCompatible(M3Gint property)
1.83 +{
1.84 + switch (property) {
1.85 + case M3G_ANIM_COLOR:
1.86 + case M3G_ANIM_INTENSITY:
1.87 + case M3G_ANIM_SPOT_ANGLE:
1.88 + case M3G_ANIM_SPOT_EXPONENT:
1.89 + return M3G_TRUE;
1.90 + default:
1.91 + return m3gNodeIsCompatible(property);
1.92 + }
1.93 +}
1.94 +
1.95 +/*!
1.96 + * \internal
1.97 + * \brief Overloaded Object3D method.
1.98 + *
1.99 + * \param self Light object
1.100 + * \param property animation property
1.101 + * \param valueSize size of value array
1.102 + * \param value value array
1.103 + */
1.104 +static void m3gLightUpdateProperty(Object *self,
1.105 + M3Gint property,
1.106 + M3Gint valueSize,
1.107 + const M3Gfloat *value)
1.108 +{
1.109 + Light *light = (Light *)self;
1.110 + M3G_VALIDATE_OBJECT(light);
1.111 + M3G_ASSERT_PTR(value);
1.112 +
1.113 + switch (property) {
1.114 + case M3G_ANIM_COLOR:
1.115 + M3G_ASSERT(valueSize >= 3);
1.116 + light->color = m3gColor3f(value[0], value[1], value[2]);
1.117 + break;
1.118 + case M3G_ANIM_INTENSITY:
1.119 + M3G_ASSERT(valueSize >= 1);
1.120 + light->intensity = value[0];
1.121 + break;
1.122 + case M3G_ANIM_SPOT_ANGLE:
1.123 + M3G_ASSERT(valueSize >= 1);
1.124 + light->spotAngle = m3gClampFloat(value[0], 0.f, 90.f);
1.125 + break;
1.126 + case M3G_ANIM_SPOT_EXPONENT:
1.127 + M3G_ASSERT(valueSize >= 1);
1.128 + light->spotExponent = m3gClampFloat(value[0], 0.f, 128.f);
1.129 + break;
1.130 + default:
1.131 + m3gNodeUpdateProperty(self, property, valueSize, value);
1.132 + }
1.133 +}
1.134 +
1.135 +/*!
1.136 + * \internal
1.137 + * \brief Overloaded Object3D method.
1.138 + *
1.139 + * \param originalObj original Light object
1.140 + * \param cloneObj pointer to cloned Light object
1.141 + * \param pairs array for all object-duplicate pairs
1.142 + * \param numPairs number of pairs
1.143 + */
1.144 +static M3Gbool m3gLightDuplicate(const Object *originalObj,
1.145 + Object **cloneObj,
1.146 + Object **pairs,
1.147 + M3Gint *numPairs)
1.148 +{
1.149 + const Light *original = (const Light *) originalObj;
1.150 + Light *clone;
1.151 + M3G_ASSERT(*cloneObj == NULL); /* no derived classes for light */
1.152 +
1.153 + /* Create the clone object and exit on failure */
1.154 +
1.155 + clone = (Light *)m3gCreateLight(originalObj->interface);
1.156 + if (!clone) {
1.157 + return M3G_FALSE;
1.158 + }
1.159 + *cloneObj = (Object *)clone;
1.160 +
1.161 + /* Duplicate base class data */
1.162 +
1.163 + if (!m3gNodeDuplicate(originalObj, cloneObj, pairs, numPairs)) {
1.164 + return M3G_FALSE;
1.165 + }
1.166 +
1.167 + /* Duplicate own data */
1.168 +
1.169 + clone->constantAttenuation = original->constantAttenuation;
1.170 + clone->linearAttenuation = original->linearAttenuation;
1.171 + clone->quadraticAttenuation = original->quadraticAttenuation;
1.172 + clone->intensity = original->intensity;
1.173 + clone->color = original->color;
1.174 + clone->mode = original->mode;
1.175 + clone->spotAngle = original->spotAngle;
1.176 + clone->spotExponent = original->spotExponent;
1.177 +
1.178 + return M3G_TRUE;
1.179 +}
1.180 +
1.181 +/*!
1.182 + * \internal
1.183 + * \brief Initializes a Light object. See specification
1.184 + * for default values.
1.185 + *
1.186 + * \param m3g M3G interface
1.187 + * \param light Light object
1.188 + */
1.189 +static void m3gInitLight(Interface *m3g, Light *light)
1.190 +{
1.191 + /* Light is derived from node */
1.192 + m3gInitNode(m3g, &light->node, M3G_CLASS_LIGHT);
1.193 +
1.194 + light->constantAttenuation = 1.0f;
1.195 + light->intensity = 1.0f;
1.196 + light->color = 0x00ffffff; /* Full white */
1.197 + light->mode = M3G_DIRECTIONAL;
1.198 + light->spotAngle = 45.0f;
1.199 +}
1.200 +
1.201 +/*!
1.202 + * \internal
1.203 + * \brief Applies this light to the current OpenGL context.
1.204 + *
1.205 + * \param self Light object
1.206 + * \param glLight OpenGL light index
1.207 + * \param pos light position
1.208 + * \param spotDir light direction
1.209 + */
1.210 +static void m3gApplyLight(const Light *self,
1.211 + GLenum glLight,
1.212 + const Vec4 *pos,
1.213 + const Vec4 *spotDir)
1.214 +{
1.215 + static const M3Gfloat BLACK[] = { 0.0f, 0.0f, 0.0f, 0.0f };
1.216 + M3Gfloat light[4];
1.217 +
1.218 + M3G_ASSERT(m3gInRange(glLight, GL_LIGHT0, GL_LIGHT7));
1.219 + glEnable(glLight);
1.220 +
1.221 + m3gFloatColor(self->color, self->intensity, light);
1.222 +
1.223 + /* Set light position */
1.224 +
1.225 + if (self->mode == M3G_DIRECTIONAL) {
1.226 + GLfloat temp[4];
1.227 + temp[0] = -spotDir->x;
1.228 + temp[1] = -spotDir->y;
1.229 + temp[2] = -spotDir->z;
1.230 + temp[3] = 0.0f;
1.231 + glLightfv(glLight, GL_POSITION, temp);
1.232 + }
1.233 + else {
1.234 + glLightfv(glLight, GL_POSITION, &pos->x);
1.235 + if (self->mode == M3G_SPOT) {
1.236 + glLightfv(glLight, GL_SPOT_DIRECTION, &spotDir->x);
1.237 + }
1.238 + }
1.239 +
1.240 + /* Set ambient, diffuse, and specular contributions */
1.241 +
1.242 + if (self->mode == M3G_AMBIENT) {
1.243 + glLightfv(glLight, GL_AMBIENT, light);
1.244 + glLightfv(glLight, GL_DIFFUSE, BLACK);
1.245 + glLightfv(glLight, GL_SPECULAR, BLACK);
1.246 + }
1.247 + else {
1.248 + glLightfv(glLight, GL_AMBIENT, BLACK);
1.249 + glLightfv(glLight, GL_DIFFUSE, light);
1.250 + glLightfv(glLight, GL_SPECULAR, light);
1.251 + }
1.252 +
1.253 + /* Set spot parameters */
1.254 +
1.255 + if (self->mode == M3G_SPOT) {
1.256 + glLightf(glLight, GL_SPOT_EXPONENT, self->spotExponent);
1.257 + glLightf(glLight, GL_SPOT_CUTOFF, self->spotAngle);
1.258 + }
1.259 + else {
1.260 + glLightf(glLight, GL_SPOT_CUTOFF, 180.0f);
1.261 + }
1.262 +
1.263 + /* Set attenuation */
1.264 +
1.265 + if (self->mode == M3G_OMNI || self->mode == M3G_SPOT) {
1.266 + glLightf(glLight, GL_CONSTANT_ATTENUATION, self->constantAttenuation);
1.267 + glLightf(glLight, GL_LINEAR_ATTENUATION, self->linearAttenuation);
1.268 + glLightf(glLight, GL_QUADRATIC_ATTENUATION, self->quadraticAttenuation);
1.269 + }
1.270 + else if (self->mode == M3G_AMBIENT) {
1.271 + glLightf(glLight, GL_CONSTANT_ATTENUATION, 1.0f);
1.272 + glLightf(glLight, GL_LINEAR_ATTENUATION, 0.0f);
1.273 + glLightf(glLight, GL_QUADRATIC_ATTENUATION, 0.0f);
1.274 + }
1.275 +}
1.276 +
1.277 +/*----------------------------------------------------------------------
1.278 + * Virtual function table
1.279 + *--------------------------------------------------------------------*/
1.280 +
1.281 +static const NodeVFTable m3gvf_Light = {
1.282 + {
1.283 + {
1.284 + m3gObjectApplyAnimation,
1.285 + m3gLightIsCompatible,
1.286 + m3gLightUpdateProperty,
1.287 + m3gObjectDoGetReferences,
1.288 + m3gObjectFindID,
1.289 + m3gLightDuplicate,
1.290 + m3gDestroyNode
1.291 + }
1.292 + },
1.293 + m3gNodeAlign,
1.294 + NULL, /* pure virtual DoRender */
1.295 + m3gNodeGetBBox,
1.296 + m3gNodeRayIntersect,
1.297 + m3gLightSetupRender,
1.298 + m3gNodeUpdateDuplicateReferences,
1.299 + m3gNodeValidate
1.300 +};
1.301 +
1.302 +
1.303 +/*----------------------------------------------------------------------
1.304 + * Public API functions
1.305 + *--------------------------------------------------------------------*/
1.306 +
1.307 +/*!
1.308 + * \brief Creates a Light object.
1.309 + *
1.310 + * \param interface M3G interface
1.311 + * \retval Light new Light object
1.312 + * \retval NULL Light creating failed
1.313 + */
1.314 +M3G_API M3GLight m3gCreateLight(M3GInterface interface)
1.315 +{
1.316 + Interface *m3g = (Interface *) interface;
1.317 + M3G_VALIDATE_INTERFACE(m3g);
1.318 +
1.319 + {
1.320 + Light *light = m3gAllocZ(m3g, sizeof(Light));
1.321 +
1.322 + if (light != NULL) {
1.323 + m3gInitLight(m3g, light);
1.324 + }
1.325 +
1.326 + return (M3GLight) light;
1.327 + }
1.328 +}
1.329 +
1.330 +/*!
1.331 + * \brief Set light intensity.
1.332 + *
1.333 + * \param handle Light object
1.334 + * \param intensity light intensity
1.335 + */
1.336 +M3G_API void m3gSetIntensity(M3GLight handle, M3Gfloat intensity)
1.337 +{
1.338 + Light *light = (Light *) handle;
1.339 + M3G_VALIDATE_OBJECT(light);
1.340 +
1.341 + light->intensity = intensity;
1.342 +}
1.343 +
1.344 +/*!
1.345 + * \brief Set light color as RGB.
1.346 + *
1.347 + * \param handle Light object
1.348 + * \param rgb light color as RGB
1.349 + */
1.350 +M3G_API void m3gSetLightColor(M3GLight handle, M3Guint rgb)
1.351 +{
1.352 + Light *light = (Light *) handle;
1.353 + M3G_VALIDATE_OBJECT(light);
1.354 +
1.355 + light->color = rgb & M3G_RGB_MASK;
1.356 +}
1.357 +
1.358 +/*!
1.359 + * \brief Set light mode.
1.360 + *
1.361 + * \param handle Light object
1.362 + * \param mode light mode
1.363 + */
1.364 +M3G_API void m3gSetLightMode(M3GLight handle, M3Gint mode)
1.365 +{
1.366 + Light *light = (Light *) handle;
1.367 + M3G_VALIDATE_OBJECT(light);
1.368 +
1.369 + if (mode < M3G_AMBIENT || mode > M3G_SPOT) {
1.370 + m3gRaiseError(M3G_INTERFACE(light), M3G_INVALID_VALUE);
1.371 + return;
1.372 + }
1.373 +
1.374 + light->mode = mode;
1.375 +}
1.376 +
1.377 +/*!
1.378 + * \brief Set light spot angle.
1.379 + *
1.380 + * \param handle Light object
1.381 + * \param angle spot angle
1.382 + */
1.383 +M3G_API void m3gSetSpotAngle(M3GLight handle, M3Gfloat angle)
1.384 +{
1.385 + Light *light = (Light *) handle;
1.386 + M3G_VALIDATE_OBJECT(light);
1.387 +
1.388 + if (angle < 0.0f || angle > 90.f) {
1.389 + m3gRaiseError(M3G_INTERFACE(light), M3G_INVALID_VALUE);
1.390 + return;
1.391 + }
1.392 +
1.393 + light->spotAngle = angle;
1.394 +}
1.395 +
1.396 +/*!
1.397 + * \brief Set light spot exponent.
1.398 + *
1.399 + * \param handle Light object
1.400 + * \param exponent spot exponent
1.401 + */
1.402 +M3G_API void m3gSetSpotExponent(M3GLight handle, M3Gfloat exponent)
1.403 +{
1.404 + Light *light = (Light *) handle;
1.405 + M3G_VALIDATE_OBJECT(light);
1.406 +
1.407 + if (exponent < 0.0f || exponent > 128.0f) {
1.408 + m3gRaiseError(M3G_INTERFACE(light), M3G_INVALID_VALUE);
1.409 + return;
1.410 + }
1.411 +
1.412 + light->spotExponent = exponent;
1.413 +}
1.414 +
1.415 +/*!
1.416 + * \brief Set light attenuation factors.
1.417 + *
1.418 + * \param handle Light object
1.419 + * \param constant constant attenuation
1.420 + * \param linear linear attenuation
1.421 + * \param quadratic quadratic attenuation
1.422 + */
1.423 +M3G_API void m3gSetAttenuation(M3GLight handle,
1.424 + M3Gfloat constant,
1.425 + M3Gfloat linear,
1.426 + M3Gfloat quadratic)
1.427 +{
1.428 + Light *light = (Light *) handle;
1.429 + M3G_VALIDATE_OBJECT(light);
1.430 +
1.431 + if (constant < 0.0f || linear < 0.0f || quadratic < 0.0f
1.432 + || (constant == 0.0f && linear == 0.0f && quadratic == 0.0f)) {
1.433 + m3gRaiseError(M3G_INTERFACE(light), M3G_INVALID_VALUE);
1.434 + return;
1.435 + }
1.436 +
1.437 + light->constantAttenuation = constant;
1.438 + light->linearAttenuation = linear;
1.439 + light->quadraticAttenuation = quadratic;
1.440 +}
1.441 +
1.442 +/*!
1.443 + * \brief Get light intensity.
1.444 + *
1.445 + * \param handle Light object
1.446 + * \return light intensity
1.447 + */
1.448 +M3G_API M3Gfloat m3gGetIntensity(M3GLight handle)
1.449 +{
1.450 + Light *light = (Light *) handle;
1.451 + M3G_VALIDATE_OBJECT(light);
1.452 +
1.453 + return light->intensity;
1.454 +}
1.455 +
1.456 +/*!
1.457 + * \brief Get light color as RGB.
1.458 + *
1.459 + * \param handle Light object
1.460 + * \return light color as RGB
1.461 + */
1.462 +M3G_API M3Guint m3gGetLightColor(M3GLight handle)
1.463 +{
1.464 + Light *light = (Light *) handle;
1.465 + M3G_VALIDATE_OBJECT(light);
1.466 +
1.467 + return light->color;
1.468 +}
1.469 +
1.470 +/*!
1.471 + * \brief Get light mode.
1.472 + *
1.473 + * \param handle Light object
1.474 + * \return light mode
1.475 + */
1.476 +M3G_API M3Gint m3gGetLightMode(M3GLight handle)
1.477 +{
1.478 + Light *light = (Light *) handle;
1.479 + M3G_VALIDATE_OBJECT(light);
1.480 +
1.481 + return light->mode;
1.482 +}
1.483 +
1.484 +/*!
1.485 + * \brief Get light spot angle.
1.486 + *
1.487 + * \param handle Light object
1.488 + * \return light spot angle
1.489 + */
1.490 +M3G_API M3Gfloat m3gGetSpotAngle(M3GLight handle)
1.491 +{
1.492 + Light *light = (Light *) handle;
1.493 + M3G_VALIDATE_OBJECT(light);
1.494 +
1.495 + return light->spotAngle;
1.496 +}
1.497 +
1.498 +/*!
1.499 + * \brief Get light spot exponent.
1.500 + *
1.501 + * \param handle Light object
1.502 + * \return light spot exponent
1.503 + */
1.504 +M3G_API M3Gfloat m3gGetSpotExponent(M3GLight handle)
1.505 +{
1.506 + Light *light = (Light *) handle;
1.507 + M3G_VALIDATE_OBJECT(light);
1.508 +
1.509 + return light->spotExponent;
1.510 +}
1.511 +
1.512 +/*!
1.513 + * \brief Get light attenuation factor.
1.514 + *
1.515 + * \param handle Light object
1.516 + * \param type which factor to return
1.517 + * \arg M3G_GET_CONSTANT
1.518 + * \arg M3G_GET_LINEAR
1.519 + * \arg M3G_GET_QUADRATIC
1.520 + * \return light attenuation factor
1.521 + */
1.522 +M3G_API M3Gfloat m3gGetAttenuation(M3GLight handle, M3Gint type)
1.523 +{
1.524 + Light *light = (Light *) handle;
1.525 + M3G_VALIDATE_OBJECT(light);
1.526 +
1.527 + switch(type) {
1.528 + case M3G_GET_CONSTANT:
1.529 + return light->constantAttenuation;
1.530 + case M3G_GET_LINEAR:
1.531 + return light->linearAttenuation;
1.532 + case M3G_GET_QUADRATIC:
1.533 + default:
1.534 + return light->quadraticAttenuation;
1.535 + }
1.536 +}
1.537 +