diff -r 000000000000 -r bde4ae8d615e os/graphics/m3g/m3gcore11/src/m3g_light.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/graphics/m3g/m3gcore11/src/m3g_light.c Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,534 @@ +/* +* Copyright (c) 2003 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: Light implementation +* +*/ + + +/*! + * \internal + * \file + * \brief Light implementation + */ + +#ifndef M3G_CORE_INCLUDE +# error included by m3g_core.c; do not compile separately. +#endif + +#include "m3g_light.h" +#include "m3g_animationtrack.h" + +/*---------------------------------------------------------------------- + * Internal functions + *--------------------------------------------------------------------*/ + +/*! + * \internal + * \brief Overloaded Node method. + * + * Insert light to render queue. + * + * \param self Light object + * \param toCamera transform to camera + * \param alphaFactor total alpha factor + * \param caller caller node + * \param renderQueue RenderQueue + * + * \retval M3G_TRUE continue render setup + * \retval M3G_FALSE abort render setup + */ +static M3Gbool m3gLightSetupRender(Node *self, + const Node *caller, + SetupRenderState *s, + RenderQueue *renderQueue) +{ + M3G_UNREF(caller); + + if (renderQueue->lightManager != NULL) { + Light *light = (Light *)self; + + if (self->enableBits & NODE_RENDER_BIT) { + if (m3gInsertLight(renderQueue->lightManager, + light, &s->toCamera, M3G_INTERFACE(light)) == -1) + return M3G_FALSE; + } + } + + return M3G_TRUE; +} + +/*! + * \internal + * \brief Overloaded Object3D method. + * + * \param property animation property + * \retval M3G_TRUE property supported + * \retval M3G_FALSE property not supported + */ +static M3Gbool m3gLightIsCompatible(M3Gint property) +{ + switch (property) { + case M3G_ANIM_COLOR: + case M3G_ANIM_INTENSITY: + case M3G_ANIM_SPOT_ANGLE: + case M3G_ANIM_SPOT_EXPONENT: + return M3G_TRUE; + default: + return m3gNodeIsCompatible(property); + } +} + +/*! + * \internal + * \brief Overloaded Object3D method. + * + * \param self Light object + * \param property animation property + * \param valueSize size of value array + * \param value value array + */ +static void m3gLightUpdateProperty(Object *self, + M3Gint property, + M3Gint valueSize, + const M3Gfloat *value) +{ + Light *light = (Light *)self; + M3G_VALIDATE_OBJECT(light); + M3G_ASSERT_PTR(value); + + switch (property) { + case M3G_ANIM_COLOR: + M3G_ASSERT(valueSize >= 3); + light->color = m3gColor3f(value[0], value[1], value[2]); + break; + case M3G_ANIM_INTENSITY: + M3G_ASSERT(valueSize >= 1); + light->intensity = value[0]; + break; + case M3G_ANIM_SPOT_ANGLE: + M3G_ASSERT(valueSize >= 1); + light->spotAngle = m3gClampFloat(value[0], 0.f, 90.f); + break; + case M3G_ANIM_SPOT_EXPONENT: + M3G_ASSERT(valueSize >= 1); + light->spotExponent = m3gClampFloat(value[0], 0.f, 128.f); + break; + default: + m3gNodeUpdateProperty(self, property, valueSize, value); + } +} + +/*! + * \internal + * \brief Overloaded Object3D method. + * + * \param originalObj original Light object + * \param cloneObj pointer to cloned Light object + * \param pairs array for all object-duplicate pairs + * \param numPairs number of pairs + */ +static M3Gbool m3gLightDuplicate(const Object *originalObj, + Object **cloneObj, + Object **pairs, + M3Gint *numPairs) +{ + const Light *original = (const Light *) originalObj; + Light *clone; + M3G_ASSERT(*cloneObj == NULL); /* no derived classes for light */ + + /* Create the clone object and exit on failure */ + + clone = (Light *)m3gCreateLight(originalObj->interface); + if (!clone) { + return M3G_FALSE; + } + *cloneObj = (Object *)clone; + + /* Duplicate base class data */ + + if (!m3gNodeDuplicate(originalObj, cloneObj, pairs, numPairs)) { + return M3G_FALSE; + } + + /* Duplicate own data */ + + clone->constantAttenuation = original->constantAttenuation; + clone->linearAttenuation = original->linearAttenuation; + clone->quadraticAttenuation = original->quadraticAttenuation; + clone->intensity = original->intensity; + clone->color = original->color; + clone->mode = original->mode; + clone->spotAngle = original->spotAngle; + clone->spotExponent = original->spotExponent; + + return M3G_TRUE; +} + +/*! + * \internal + * \brief Initializes a Light object. See specification + * for default values. + * + * \param m3g M3G interface + * \param light Light object + */ +static void m3gInitLight(Interface *m3g, Light *light) +{ + /* Light is derived from node */ + m3gInitNode(m3g, &light->node, M3G_CLASS_LIGHT); + + light->constantAttenuation = 1.0f; + light->intensity = 1.0f; + light->color = 0x00ffffff; /* Full white */ + light->mode = M3G_DIRECTIONAL; + light->spotAngle = 45.0f; +} + +/*! + * \internal + * \brief Applies this light to the current OpenGL context. + * + * \param self Light object + * \param glLight OpenGL light index + * \param pos light position + * \param spotDir light direction + */ +static void m3gApplyLight(const Light *self, + GLenum glLight, + const Vec4 *pos, + const Vec4 *spotDir) +{ + static const M3Gfloat BLACK[] = { 0.0f, 0.0f, 0.0f, 0.0f }; + M3Gfloat light[4]; + + M3G_ASSERT(m3gInRange(glLight, GL_LIGHT0, GL_LIGHT7)); + glEnable(glLight); + + m3gFloatColor(self->color, self->intensity, light); + + /* Set light position */ + + if (self->mode == M3G_DIRECTIONAL) { + GLfloat temp[4]; + temp[0] = -spotDir->x; + temp[1] = -spotDir->y; + temp[2] = -spotDir->z; + temp[3] = 0.0f; + glLightfv(glLight, GL_POSITION, temp); + } + else { + glLightfv(glLight, GL_POSITION, &pos->x); + if (self->mode == M3G_SPOT) { + glLightfv(glLight, GL_SPOT_DIRECTION, &spotDir->x); + } + } + + /* Set ambient, diffuse, and specular contributions */ + + if (self->mode == M3G_AMBIENT) { + glLightfv(glLight, GL_AMBIENT, light); + glLightfv(glLight, GL_DIFFUSE, BLACK); + glLightfv(glLight, GL_SPECULAR, BLACK); + } + else { + glLightfv(glLight, GL_AMBIENT, BLACK); + glLightfv(glLight, GL_DIFFUSE, light); + glLightfv(glLight, GL_SPECULAR, light); + } + + /* Set spot parameters */ + + if (self->mode == M3G_SPOT) { + glLightf(glLight, GL_SPOT_EXPONENT, self->spotExponent); + glLightf(glLight, GL_SPOT_CUTOFF, self->spotAngle); + } + else { + glLightf(glLight, GL_SPOT_CUTOFF, 180.0f); + } + + /* Set attenuation */ + + if (self->mode == M3G_OMNI || self->mode == M3G_SPOT) { + glLightf(glLight, GL_CONSTANT_ATTENUATION, self->constantAttenuation); + glLightf(glLight, GL_LINEAR_ATTENUATION, self->linearAttenuation); + glLightf(glLight, GL_QUADRATIC_ATTENUATION, self->quadraticAttenuation); + } + else if (self->mode == M3G_AMBIENT) { + glLightf(glLight, GL_CONSTANT_ATTENUATION, 1.0f); + glLightf(glLight, GL_LINEAR_ATTENUATION, 0.0f); + glLightf(glLight, GL_QUADRATIC_ATTENUATION, 0.0f); + } +} + +/*---------------------------------------------------------------------- + * Virtual function table + *--------------------------------------------------------------------*/ + +static const NodeVFTable m3gvf_Light = { + { + { + m3gObjectApplyAnimation, + m3gLightIsCompatible, + m3gLightUpdateProperty, + m3gObjectDoGetReferences, + m3gObjectFindID, + m3gLightDuplicate, + m3gDestroyNode + } + }, + m3gNodeAlign, + NULL, /* pure virtual DoRender */ + m3gNodeGetBBox, + m3gNodeRayIntersect, + m3gLightSetupRender, + m3gNodeUpdateDuplicateReferences, + m3gNodeValidate +}; + + +/*---------------------------------------------------------------------- + * Public API functions + *--------------------------------------------------------------------*/ + +/*! + * \brief Creates a Light object. + * + * \param interface M3G interface + * \retval Light new Light object + * \retval NULL Light creating failed + */ +M3G_API M3GLight m3gCreateLight(M3GInterface interface) +{ + Interface *m3g = (Interface *) interface; + M3G_VALIDATE_INTERFACE(m3g); + + { + Light *light = m3gAllocZ(m3g, sizeof(Light)); + + if (light != NULL) { + m3gInitLight(m3g, light); + } + + return (M3GLight) light; + } +} + +/*! + * \brief Set light intensity. + * + * \param handle Light object + * \param intensity light intensity + */ +M3G_API void m3gSetIntensity(M3GLight handle, M3Gfloat intensity) +{ + Light *light = (Light *) handle; + M3G_VALIDATE_OBJECT(light); + + light->intensity = intensity; +} + +/*! + * \brief Set light color as RGB. + * + * \param handle Light object + * \param rgb light color as RGB + */ +M3G_API void m3gSetLightColor(M3GLight handle, M3Guint rgb) +{ + Light *light = (Light *) handle; + M3G_VALIDATE_OBJECT(light); + + light->color = rgb & M3G_RGB_MASK; +} + +/*! + * \brief Set light mode. + * + * \param handle Light object + * \param mode light mode + */ +M3G_API void m3gSetLightMode(M3GLight handle, M3Gint mode) +{ + Light *light = (Light *) handle; + M3G_VALIDATE_OBJECT(light); + + if (mode < M3G_AMBIENT || mode > M3G_SPOT) { + m3gRaiseError(M3G_INTERFACE(light), M3G_INVALID_VALUE); + return; + } + + light->mode = mode; +} + +/*! + * \brief Set light spot angle. + * + * \param handle Light object + * \param angle spot angle + */ +M3G_API void m3gSetSpotAngle(M3GLight handle, M3Gfloat angle) +{ + Light *light = (Light *) handle; + M3G_VALIDATE_OBJECT(light); + + if (angle < 0.0f || angle > 90.f) { + m3gRaiseError(M3G_INTERFACE(light), M3G_INVALID_VALUE); + return; + } + + light->spotAngle = angle; +} + +/*! + * \brief Set light spot exponent. + * + * \param handle Light object + * \param exponent spot exponent + */ +M3G_API void m3gSetSpotExponent(M3GLight handle, M3Gfloat exponent) +{ + Light *light = (Light *) handle; + M3G_VALIDATE_OBJECT(light); + + if (exponent < 0.0f || exponent > 128.0f) { + m3gRaiseError(M3G_INTERFACE(light), M3G_INVALID_VALUE); + return; + } + + light->spotExponent = exponent; +} + +/*! + * \brief Set light attenuation factors. + * + * \param handle Light object + * \param constant constant attenuation + * \param linear linear attenuation + * \param quadratic quadratic attenuation + */ +M3G_API void m3gSetAttenuation(M3GLight handle, + M3Gfloat constant, + M3Gfloat linear, + M3Gfloat quadratic) +{ + Light *light = (Light *) handle; + M3G_VALIDATE_OBJECT(light); + + if (constant < 0.0f || linear < 0.0f || quadratic < 0.0f + || (constant == 0.0f && linear == 0.0f && quadratic == 0.0f)) { + m3gRaiseError(M3G_INTERFACE(light), M3G_INVALID_VALUE); + return; + } + + light->constantAttenuation = constant; + light->linearAttenuation = linear; + light->quadraticAttenuation = quadratic; +} + +/*! + * \brief Get light intensity. + * + * \param handle Light object + * \return light intensity + */ +M3G_API M3Gfloat m3gGetIntensity(M3GLight handle) +{ + Light *light = (Light *) handle; + M3G_VALIDATE_OBJECT(light); + + return light->intensity; +} + +/*! + * \brief Get light color as RGB. + * + * \param handle Light object + * \return light color as RGB + */ +M3G_API M3Guint m3gGetLightColor(M3GLight handle) +{ + Light *light = (Light *) handle; + M3G_VALIDATE_OBJECT(light); + + return light->color; +} + +/*! + * \brief Get light mode. + * + * \param handle Light object + * \return light mode + */ +M3G_API M3Gint m3gGetLightMode(M3GLight handle) +{ + Light *light = (Light *) handle; + M3G_VALIDATE_OBJECT(light); + + return light->mode; +} + +/*! + * \brief Get light spot angle. + * + * \param handle Light object + * \return light spot angle + */ +M3G_API M3Gfloat m3gGetSpotAngle(M3GLight handle) +{ + Light *light = (Light *) handle; + M3G_VALIDATE_OBJECT(light); + + return light->spotAngle; +} + +/*! + * \brief Get light spot exponent. + * + * \param handle Light object + * \return light spot exponent + */ +M3G_API M3Gfloat m3gGetSpotExponent(M3GLight handle) +{ + Light *light = (Light *) handle; + M3G_VALIDATE_OBJECT(light); + + return light->spotExponent; +} + +/*! + * \brief Get light attenuation factor. + * + * \param handle Light object + * \param type which factor to return + * \arg M3G_GET_CONSTANT + * \arg M3G_GET_LINEAR + * \arg M3G_GET_QUADRATIC + * \return light attenuation factor + */ +M3G_API M3Gfloat m3gGetAttenuation(M3GLight handle, M3Gint type) +{ + Light *light = (Light *) handle; + M3G_VALIDATE_OBJECT(light); + + switch(type) { + case M3G_GET_CONSTANT: + return light->constantAttenuation; + case M3G_GET_LINEAR: + return light->linearAttenuation; + case M3G_GET_QUADRATIC: + default: + return light->quadraticAttenuation; + } +} +