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