m3g/m3gcore11/src/m3g_light.c
changeset 0 5d03bc08d59c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m3g/m3gcore11/src/m3g_light.c	Tue Feb 02 01:47:50 2010 +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;
+	}
+}
+