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