os/graphics/m3g/m3gcore11/src/m3g_light.c
changeset 0 bde4ae8d615e
     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 +