m3g/m3gcore11/src/m3g_material.c
changeset 0 5d03bc08d59c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m3g/m3gcore11/src/m3g_material.c	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,375 @@
+/*
+* 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: Material implementation
+*
+*/
+
+
+/*!
+ * \internal
+ * \file
+ * \brief Material implementation
+ */
+
+#ifndef M3G_CORE_INCLUDE
+#   error included by m3g_core.c; do not compile separately.
+#endif
+
+#include "m3g_material.h"
+#include "m3g_animationtrack.h"
+
+#define ALL_TARGET_MASK (M3G_AMBIENT_BIT | M3G_DIFFUSE_BIT | M3G_EMISSIVE_BIT | M3G_SPECULAR_BIT)
+
+/*----------------------------------------------------------------------
+ * Internal functions
+ *--------------------------------------------------------------------*/
+
+/*!
+ * \internal
+ * \brief Applies default material to OpenGL.
+ */
+static void m3gApplyDefaultMaterial(void)
+{
+    glDisable(GL_COLOR_MATERIAL);
+    glDisable(GL_LIGHTING);
+}
+
+/*!
+ * \internal
+ * \brief Applies material to OpenGL.
+ *
+ * \param material Material object
+ * \param alphaFactor alpha factor as 1.16 fixed point
+ */
+static void m3gApplyMaterial(Material *material, M3Gint alphaFactor)
+{
+    if (material != NULL) {
+    	M3Gfloat colors[4];
+
+        /* NOTE We must set the ColorMaterial state *before* setting
+         * any of the material colors, as they will not change if
+         * tracking is enabled! */
+        
+        if (material->vertexColorTracking) {
+            glEnable(GL_COLOR_MATERIAL);
+        }
+        else {
+            glDisable(GL_COLOR_MATERIAL);
+
+            /* Ambient and diffuse only need to be set when tracking
+             * is disabled */
+            
+            m3gFloatColor(material->ambientColor, 1.0f, colors);
+            glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, colors);
+            m3gFloatColor(material->diffuseColor, 1.0f, colors);
+            if (alphaFactor < 0x10000) {
+                colors[3] = m3gMul(colors[3],
+                                   m3gMul((M3Gfloat) alphaFactor,
+                                          1.f/65536.f));
+            }
+            glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, colors);
+        }
+        m3gFloatColor(material->emissiveColor, 1.0f, colors);
+        glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, colors);
+        m3gFloatColor(material->specularColor, 1.0f, colors);
+        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, colors);
+        glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, material->shininess);
+
+        glEnable(GL_LIGHTING);
+    }
+    else {
+        m3gApplyDefaultMaterial();
+    }
+    M3G_ASSERT_GL;
+}
+
+/*!
+ * \internal
+ * \brief Overloaded Object3D method.
+ *
+ * \param property      animation property
+ * \retval M3G_TRUE     property supported
+ * \retval M3G_FALSE    property not supported
+ */
+static M3Gbool m3gMaterialIsCompatible(M3Gint property)
+{
+    switch (property) {
+    case M3G_ANIM_ALPHA:
+    case M3G_ANIM_AMBIENT_COLOR:
+    case M3G_ANIM_DIFFUSE_COLOR:
+    case M3G_ANIM_EMISSIVE_COLOR:
+    case M3G_ANIM_SHININESS:
+    case M3G_ANIM_SPECULAR_COLOR:
+        return M3G_TRUE;
+    default:
+        return m3gObjectIsCompatible(property);
+    }
+}
+
+/*!
+ * \internal
+ * \brief Overloaded Object3D method.
+ *
+ * \param self          Material object
+ * \param property      animation property
+ * \param valueSize     size of value array
+ * \param value         value array
+ */
+static void m3gMaterialUpdateProperty(Object *self,
+                                      M3Gint property,
+                                      M3Gint valueSize,
+                                      const M3Gfloat *value)
+{
+    Material *material = (Material *)self;
+    M3G_VALIDATE_OBJECT(material);
+    M3G_ASSERT_PTR(value);
+
+    switch (property) {
+    case M3G_ANIM_ALPHA:
+        M3G_ASSERT(valueSize >= 1);
+        material->diffuseColor = (material->diffuseColor | M3G_ALPHA_MASK) &
+            m3gAlpha1f(value[0]);
+        break;
+    case M3G_ANIM_AMBIENT_COLOR:
+        M3G_ASSERT(valueSize >= 3);
+        material->ambientColor = m3gColor3f(value[0], value[1], value[2]);
+        break;
+    case M3G_ANIM_DIFFUSE_COLOR:
+        M3G_ASSERT(valueSize >= 3);
+        material->diffuseColor = (material->diffuseColor | M3G_RGB_MASK)
+            & m3gColor3f(value[0], value[1], value[2]);
+        break;
+    case M3G_ANIM_EMISSIVE_COLOR:
+        M3G_ASSERT(valueSize >= 3);
+        material->emissiveColor = m3gColor3f(value[0], value[1], value[2]) & M3G_RGB_MASK;
+        break;
+    case M3G_ANIM_SHININESS:
+        M3G_ASSERT(valueSize >= 1);
+        material->shininess = m3gClampFloat(value[0], 0.f, 128.f);
+        break;
+    case M3G_ANIM_SPECULAR_COLOR:
+        M3G_ASSERT(valueSize >= 3);
+        material->specularColor = m3gColor3f(value[0], value[1], value[2]);
+        break;
+    default:
+        m3gObjectUpdateProperty(self, property, valueSize, value);
+    }
+}
+
+/*!
+ * \internal
+ * \brief Overloaded Object3D method.
+ *
+ * \param originalObj original Material object
+ * \param cloneObj pointer to cloned Material object
+ * \param pairs array for all object-duplicate pairs
+ * \param numPairs number of pairs
+ */
+static M3Gbool m3gMaterialDuplicate(const Object *originalObj,
+                                    Object **cloneObj,
+                                    Object **pairs,
+                                    M3Gint *numPairs)
+{
+    const Material *original = (const Material *)originalObj;
+
+    /* Create the clone object */
+    
+    Material *clone = (Material *)m3gCreateMaterial(originalObj->interface);
+    if (!clone) {
+        return M3G_FALSE;
+    }
+    *cloneObj = (Object *)clone;
+
+    /* Duplicate base class and own data */
+    
+    if (m3gObjectDuplicate(originalObj, cloneObj, pairs, numPairs)) {
+        clone->vertexColorTracking = original->vertexColorTracking;
+        clone->ambientColor = original->ambientColor;
+        clone->diffuseColor = original->diffuseColor;
+        clone->emissiveColor = original->emissiveColor;
+        clone->specularColor = original->specularColor;
+        clone->shininess = original->shininess;
+        return M3G_TRUE;
+    }
+    else {
+        return M3G_FALSE;
+    }
+}
+
+/*----------------------------------------------------------------------
+ * Virtual function table
+ *--------------------------------------------------------------------*/
+
+static const ObjectVFTable m3gvf_Material = {
+    m3gObjectApplyAnimation,
+    m3gMaterialIsCompatible,
+    m3gMaterialUpdateProperty,
+    m3gObjectDoGetReferences,
+    m3gObjectFindID,
+    m3gMaterialDuplicate,
+    m3gDestroyObject
+};
+
+
+/*----------------------------------------------------------------------
+ * Public API functions
+ *--------------------------------------------------------------------*/
+
+/*!
+ * \brief Creates a Material object.
+ *
+ * \param interface     M3G interface
+ * \retval Material new Material object
+ * \retval NULL Material creating failed
+ */
+M3G_API M3GMaterial m3gCreateMaterial(M3GInterface interface)
+{
+    Interface *m3g = (Interface *) interface;
+    M3G_VALIDATE_INTERFACE(m3g);
+
+    {
+        Material *material = m3gAllocZ(m3g, sizeof(Material));
+
+        if (material != NULL) {
+            m3gInitObject(&material->object, m3g, M3G_CLASS_MATERIAL);
+            /* Default values are from the jsr-184 specification */
+            material->vertexColorTracking = GL_FALSE;
+            material->ambientColor = 0x00333333U;
+            material->diffuseColor = 0xFFCCCCCCU;
+            material->emissiveColor = 0x00000000U;
+            material->specularColor = 0x00000000U;
+            material->shininess = 0.0f;
+        }
+
+        return (M3GMaterial)material;
+    }
+}
+
+/*!
+ * \brief Set material color.
+ *
+ * \param hMaterial Material object
+ * \param target    color target
+ * \param ARGB      ARGB color
+ */
+M3G_API void m3gSetColor(M3GMaterial hMaterial, M3Genum target, M3Guint ARGB)
+{
+    Material *material = (Material *) hMaterial;
+    M3G_VALIDATE_OBJECT(material);
+    /* is invalid target in the mask OR no target */
+    if (((target | ALL_TARGET_MASK) != ALL_TARGET_MASK) || ((target & ALL_TARGET_MASK) == 0)) {
+        m3gRaiseError(M3G_INTERFACE(material), M3G_INVALID_VALUE);
+        return;
+    }
+    if ((target & M3G_AMBIENT_BIT) != 0) {
+        material->ambientColor = ARGB & M3G_RGB_MASK;
+    }
+    if ((target & M3G_DIFFUSE_BIT) != 0) {
+        material->diffuseColor = ARGB;
+    }
+    if ((target & M3G_EMISSIVE_BIT) != 0) {
+        material->emissiveColor = ARGB & M3G_RGB_MASK;
+    }
+    if ((target & M3G_SPECULAR_BIT) != 0) {
+        material->specularColor = ARGB & M3G_RGB_MASK;
+    }
+}
+
+/*!
+ * \brief Get material color.
+ *
+ * \param hMaterial Material object
+ * \param target    color target
+ * \return          ARGB color
+ */
+M3G_API M3Guint m3gGetColor(M3GMaterial hMaterial, M3Genum target)
+{
+    Material *material = (Material *) hMaterial;
+    M3G_VALIDATE_OBJECT(material);
+    
+    switch (target) {
+    case M3G_AMBIENT_BIT:
+        return material->ambientColor;
+    case M3G_DIFFUSE_BIT:
+        return material->diffuseColor;
+    case M3G_EMISSIVE_BIT:
+        return material->emissiveColor;
+    case M3G_SPECULAR_BIT:
+        return material->specularColor;
+    default:
+        m3gRaiseError(M3G_INTERFACE(material), M3G_INVALID_VALUE);
+        break;
+    }
+
+    return 0; /* Error */
+}
+
+/*!
+ * \brief Set material shininess.
+ *
+ * \param hMaterial Material object
+ * \param shininess shininess
+ */
+M3G_API void m3gSetShininess(M3GMaterial hMaterial, M3Gfloat shininess)
+{
+    Material *material = (Material *) hMaterial;
+    M3G_VALIDATE_OBJECT(material);
+    if (!m3gInRangef(shininess, 0.0f, 128.f)) {
+        m3gRaiseError(M3G_INTERFACE(material), M3G_INVALID_VALUE);
+        return;
+    }
+    material->shininess = shininess;
+}
+
+/*!
+ * \brief Get material shininess.
+ *
+ * \param hMaterial Material object
+ * \return          shininess
+ */
+M3G_API GLfloat m3gGetShininess(M3GMaterial hMaterial)
+{
+    Material *material = (Material *) hMaterial;
+    M3G_VALIDATE_OBJECT(material);
+    return material->shininess;
+}
+
+/*!
+ * \brief Set vertex color tracking enable.
+ *
+ * \param hMaterial Material object
+ * \param enable color tracking enable
+ */
+M3G_API void m3gSetVertexColorTrackingEnable(M3GMaterial hMaterial,
+                                             M3Gbool enable)
+{
+    Material *material = (Material *) hMaterial;
+    M3G_VALIDATE_OBJECT(material);
+    material->vertexColorTracking = (GLboolean) enable;
+}
+
+/*!
+ * \brief Get vertex color tracking enable.
+ *
+ * \param hMaterial Material object
+ * \retval M3G_TRUE color tracking enabled
+ * \retval M3G_FALSE color tracking disabled
+ */
+M3G_API M3Gbool m3gIsVertexColorTrackingEnabled(M3GMaterial hMaterial)
+{
+    Material *material = (Material *) hMaterial;
+    M3G_VALIDATE_OBJECT(material);
+    return (M3Gbool) material->vertexColorTracking;
+}
+