diff -r 000000000000 -r bde4ae8d615e os/graphics/m3g/m3gcore11/src/m3g_appearance.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/graphics/m3g/m3gcore11/src/m3g_appearance.c Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,649 @@ +/* +* 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: Appearance implementation +* +*/ + + +/*! + * \internal + * \file + * \brief Appearance implementation + */ + +#ifndef M3G_CORE_INCLUDE +# error included by m3g_core.c; do not compile separately. +#endif + +#include "m3g_appearance.h" +#include "m3g_vertexbuffer.h" + +/*---------------------------------------------------------------------- + * Private functions + *--------------------------------------------------------------------*/ + +/*! + * \internal + * \brief Applies default appearance values to OpenGL. + */ +static void m3gApplyAppearanceDefaults(RenderContext *ctx) +{ + int i; + m3gApplyCompositingMode(NULL, ctx); + m3gApplyPolygonMode(NULL); + m3gApplyMaterial(NULL, 0x10000); + m3gApplyFog(NULL); + + for (i = 0; i < M3G_NUM_TEXTURE_UNITS; ++i) { + glActiveTexture(GL_TEXTURE0 + i); + glDisable(GL_TEXTURE_2D); + } +} + +/*! + * \internal + * \brief Generate a hash number for a pointer + */ +static M3Guint m3gGenPointerHash(const void *ptr) +{ + M3Guint p = ((M3Guint) ptr) >> 2; + M3Guint key = p ^ (p >> 5) ^ (p >> 10) ^ (p >> 15) ^ (p >> 20) ^ (p >> 25); + return key; +} + +/*! + * \internal + * \brief Generate a quick hash bit pattern for the textures of this + * appearance object + */ +static M3Guint m3gGen12BitTextureHash(const Appearance *app) +{ + M3Guint key = 0; + + int i; + + for (i = 0; i < M3G_NUM_TEXTURE_UNITS; ++i) { + const Texture *tex = app->texture[i]; + if (tex) { + key ^= (m3gGenPointerHash(m3gGetTextureImage((M3GTexture)tex)) >> i) << 6; + key ^= (m3gGenPointerHash(tex) >> i) & 0x3Fu; + } + } + return key & ((1u<<12)-1); +} + +/*! + * \internal + * \brief Generate the sorting key for render queue + * + * Sort key is a combination of user settable layer and + * blending mode. Blended objects are always drawn last. + * + * \param appearance Appearance object + * \return sort key + */ +static void m3gRegenerateSortKey(Appearance *appearance) +{ + M3Guint key = 0; + M3G_VALIDATE_OBJECT(appearance); + + /*------------------------------------------------------------ + * First do the mandatory sorting by layer index and blending + * state; this currently uses the top eight bits, 31..24 + *-----------------------------------------------------------*/ + + key = (appearance->layer - M3G_APPEARANCE_MIN_LAYER) + << (33 - M3G_APPEARANCE_HARD_SORT_BITS); + + /* NOTE the blending state bit is not set here, but dynamically in + * m3gGetAppearanceSortKey; this way we do not need to implement + * signaling from CompositingMode to Appearance when the blending + * state changes */ + + /*----------------------------------------------------------------- + * The rest of the bits, 23..0, affect performance only; ideally, + * these should be sorted so that the more expensive state is in the + * higher bits, but this is largely dependent on the hardware + *----------------------------------------------------------------*/ + + /* Texturing changes are often expensive in graphics hardware, so + * we put a hash of the texture objects into the top twelve + * bits + * + * NOTE we do not currently update this if a texture image + * changes, but that shouldn't happen too often and only has + * relatively minor performance implications + */ + + key |= m3gGen12BitTextureHash(appearance) << 12; + + /* Use the rest of the bits for the various components; depth + * function changes are another potentially costly operation, so + * put that next */ + + key |= (m3gGenPointerHash(appearance->compositingMode) & 0x0Fu) << 8; + key |= (m3gGenPointerHash(appearance->material) & 0x07u) << 5; + key |= (m3gGenPointerHash(appearance->polygonMode) & 0x07u) << 2; + key |= (m3gGenPointerHash(appearance->fog) & 0x03u); + + /* Store the final value */ + appearance->sortKey = key; +} + +/*---------------------------------------------------------------------- + * Internal functions + *--------------------------------------------------------------------*/ + +/*! + * \internal + * \brief Destroys this Appearance object. + * + * \param obj Appearance object + */ +static void m3gDestroyAppearance(Object *obj) +{ + int i; + Appearance *appearance = (Appearance *) obj; + M3G_VALIDATE_OBJECT(appearance); + + M3G_ASSIGN_REF(appearance->compositingMode, NULL); + M3G_ASSIGN_REF(appearance->fog, NULL); + M3G_ASSIGN_REF(appearance->material, NULL); + M3G_ASSIGN_REF(appearance->polygonMode, NULL); + for (i = 0; i < M3G_NUM_TEXTURE_UNITS; ++i) { + M3G_ASSIGN_REF(appearance->texture[i], NULL); + } + + m3gDestroyObject(obj); +} + +/*! + * \internal + * \brief Applies Apperance settings to current OpenGL state + * + * \note m3gReleaseTextures must be called when no longer using this, + * to properly reset texture usage counters and unmap the texture + * images. + * + * \param appearance Appearance object + * \param alphaFactor alpha factor as 1.16 fixed point + */ +static void m3gApplyAppearance(const Appearance *appearance, + RenderContext *ctx, + M3Gint alphaFactor) +{ + M3G_ASSERT_GL; + + if (appearance != NULL) { + int i; + +# if defined(M3G_NGL_TEXTURE_API) + m3gLockMemory(M3G_INTERFACE(appearance)); /* for textures */ +# endif + + m3gApplyCompositingMode(appearance->compositingMode, ctx); + m3gApplyPolygonMode(appearance->polygonMode); + m3gApplyMaterial(appearance->material, alphaFactor); + m3gApplyFog(appearance->fog); + + for (i = 0; i < M3G_NUM_TEXTURE_UNITS; ++i) { + Texture *tex = appearance->texture[i]; + glActiveTexture(GL_TEXTURE0 + i); + if (tex != NULL) { + glEnable(GL_TEXTURE_2D); + m3gBindTexture(appearance->texture[i]); + } + else { + glDisable(GL_TEXTURE_2D); + } + } + } + else { + m3gApplyAppearanceDefaults(ctx); + } + + M3G_ASSERT_GL; +} + +/*! + * \internal + * \brief Release the textures bound for this appearance + */ +static void m3gReleaseTextures(const Appearance *appearance) +{ + if (appearance != NULL) { + int i; + + for (i = 0; i < M3G_NUM_TEXTURE_UNITS; ++i) { + Texture *tex = appearance->texture[i]; + if (tex != NULL) { + m3gReleaseTexture(tex); + } + } + +# if defined(M3G_NGL_TEXTURE_API) + m3gUnlockMemory(M3G_INTERFACE(appearance)); +# endif + } +} + +/*! + * \internal + * \brief Overloaded Object3D method. + * + * \param self Appearance object + * \param time current world time + * \return minimum validity + */ +static M3Gint m3gAppearanceApplyAnimation(Object *self, M3Gint time) { + M3Gint i, validity, minValidity = 0x7fffffff; + Appearance *appearance = (Appearance *)self; + M3G_VALIDATE_OBJECT(appearance); + + if (appearance->compositingMode != NULL) { + validity = M3G_VFUNC(Object, appearance->compositingMode, applyAnimation)((Object *)appearance->compositingMode, time); + minValidity = (validity < minValidity ? validity : minValidity); + } + if (appearance->fog != NULL) { + validity = M3G_VFUNC(Object, appearance->fog, applyAnimation)((Object *)appearance->fog, time); + minValidity = (validity < minValidity ? validity : minValidity); + } + if (appearance->material != NULL) { + validity = M3G_VFUNC(Object, appearance->material, applyAnimation)((Object *)appearance->material, time); + minValidity = (validity < minValidity ? validity : minValidity); + } + for (i = 0; i < M3G_NUM_TEXTURE_UNITS; ++i) { + if (appearance->texture[i] != NULL) { + validity = M3G_VFUNC(Object, appearance->texture[i], applyAnimation)((Object *)appearance->texture[i], time); + minValidity = (validity < minValidity ? validity : minValidity); + } + } + + /* no animations can target an Appearance directly, so we need + not call super.applyAnimation() here. */ + return minValidity; +} + +/*! + * \internal + * \brief Overloaded Object3D method. + */ +static Object *m3gAppearanceFindID(Object *self, M3Gint userID) +{ + int i; + Appearance *app = (Appearance *)self; + Object *found = m3gObjectFindID(self, userID); + + if (!found && app->compositingMode) { + found = m3gFindID((Object*) app->compositingMode, userID); + } + if (!found && app->polygonMode) { + found = m3gFindID((Object*) app->polygonMode, userID); + } + if (!found && app->fog) { + found = m3gFindID((Object*) app->fog, userID); + } + if (!found && app->material) { + found = m3gFindID((Object*) app->material, userID); + } + for (i = 0; !found && i < M3G_NUM_TEXTURE_UNITS; ++i) { + if (app->texture[i]) { + found = m3gFindID((Object*) app->texture[i], userID); + } + } + return found; +} + +/*! + * \internal + * \brief Overloaded Object3D method. + * + * \param self Appearance object + * \param references array of reference objects + * \return number of references + */ +static M3Gint m3gAppearanceDoGetReferences(Object *self, Object **references) +{ + Appearance *app = (Appearance *)self; + M3Gint i, num = m3gObjectDoGetReferences(self, references); + if (app->compositingMode != NULL) { + if (references != NULL) + references[num] = (Object *)app->compositingMode; + num++; + } + if (app->polygonMode != NULL) { + if (references != NULL) + references[num] = (Object *)app->polygonMode; + num++; + } + if (app->fog != NULL) { + if (references != NULL) + references[num] = (Object *)app->fog; + num++; + } + if (app->material != NULL) { + if (references != NULL) + references[num] = (Object *)app->material; + num++; + } + for (i = 0; i < M3G_NUM_TEXTURE_UNITS; i++) { + if (app->texture[i] != NULL) { + if (references != NULL) + references[num] = (Object *)app->texture[i]; + num++; + } + } + return num; +} + + +/*! + * \internal + * \brief Overloaded Object3D method. + * + * \param originalObj original Appearance object + * \param cloneObj pointer to cloned Appearance object + * \param pairs array for all object-duplicate pairs + * \param numPairs number of pairs + */ +static M3Gbool m3gAppearanceDuplicate(const Object *originalObj, + Object **cloneObj, + Object **pairs, + M3Gint *numPairs) +{ + M3Gint i; + Appearance *original = (Appearance *)originalObj; + Appearance *clone = (Appearance *)m3gCreateAppearance(originalObj->interface); + *cloneObj = (Object *)clone; + if (*cloneObj == NULL) { + return M3G_FALSE; + } + + if (m3gObjectDuplicate(originalObj, cloneObj, pairs, numPairs)) { + clone->layer = original->layer; + + M3G_ASSIGN_REF(clone->compositingMode, original->compositingMode); + M3G_ASSIGN_REF(clone->fog, original->fog); + M3G_ASSIGN_REF(clone->polygonMode, original->polygonMode); + M3G_ASSIGN_REF(clone->material, original->material); + for (i = 0; i < M3G_NUM_TEXTURE_UNITS; i++) { + M3G_ASSIGN_REF(clone->texture[i], original->texture[i]); + } + + m3gRegenerateSortKey(clone); + + return M3G_TRUE; + } + else { + return M3G_FALSE; + } +} + +/*---------------------------------------------------------------------- + * Virtual function table + *--------------------------------------------------------------------*/ + +static const ObjectVFTable m3gvf_Appearance = { + m3gAppearanceApplyAnimation, + m3gObjectIsCompatible, + m3gObjectUpdateProperty, + m3gAppearanceDoGetReferences, + m3gAppearanceFindID, + m3gAppearanceDuplicate, + m3gDestroyAppearance +}; + + +/*---------------------------------------------------------------------- + * Public API functions + *--------------------------------------------------------------------*/ + +/*! + * \brief Creates a new Appearance with default values + * + * \param hInterface M3G interface + * \retval Appearance new Appearance object + * \retval NULL Appearance creating failed + */ +/*@access M3GInterface@*/ +/*@access M3GAppearance@*/ +M3G_API M3GAppearance m3gCreateAppearance(M3GInterface hInterface) +{ + Interface *m3g = (Interface *) hInterface; + M3G_VALIDATE_INTERFACE(m3g); + { + Appearance *appearance = m3gAllocZ(m3g, sizeof(Appearance)); + + if (appearance != NULL) { + m3gInitObject(&appearance->object, m3g, M3G_CLASS_APPEARANCE); + m3gRegenerateSortKey(appearance); + } + + return (M3GAppearance) appearance; + } +} + +/*! + * \brief Get compositing mode + * + * \param hAppearance Appearance object + * \return CompositingMode object + */ +M3G_API M3GCompositingMode m3gGetCompositingMode(M3GAppearance hAppearance) +{ + const Appearance *appearance = (const Appearance *) hAppearance; + M3G_VALIDATE_OBJECT(appearance); + return (M3GCompositingMode)(appearance->compositingMode); +} + +/*! + * \brief Get fog + * + * \param hAppearance Appearance object + * \return Fog object + */ +M3G_API M3GFog m3gGetFog(M3GAppearance hAppearance) +{ + const Appearance *appearance = (const Appearance *) hAppearance; + M3G_VALIDATE_OBJECT(appearance); + return (M3GFog)(appearance->fog); +} + +/*! + * \brief Get material + * + * \param hAppearance Appearance object + * \return Material object + */ +M3G_API M3GMaterial m3gGetMaterial(M3GAppearance hAppearance) +{ + const Appearance *appearance = (const Appearance *) hAppearance; + M3G_VALIDATE_OBJECT(appearance); + return (M3GMaterial)(appearance->material); +} + +/*! + * \brief Get polygon mode + * + * \param hAppearance Appearance object + * \return PolygonMode object + */ +M3G_API M3GPolygonMode m3gGetPolygonMode(M3GAppearance hAppearance) +{ + const Appearance *appearance = (const Appearance *) hAppearance; + M3G_VALIDATE_OBJECT(appearance); + return (M3GPolygonMode)(appearance->polygonMode); +} + +/*! + * \brief Get texture + * + * \param hAppearance Appearance object + * \param unit texturing unit + * \return Texture2D object + */ +M3G_API M3GTexture m3gGetTexture(M3GAppearance hAppearance, M3Gint unit) +{ + const Appearance *appearance = (const Appearance *) hAppearance; + M3G_VALIDATE_OBJECT(appearance); + if (!m3gInRange(unit, 0, M3G_NUM_TEXTURE_UNITS - 1)) { + m3gRaiseError(M3G_INTERFACE(appearance), M3G_INVALID_INDEX); + return (M3GTexture) NULL; + } + return (M3GTexture)(appearance->texture[unit]); +} + +/*! + * \brief Get layer + * + * \param hAppearance Appearance object + * \return layer number + */ +M3G_API M3Gint m3gGetLayer(M3GAppearance hAppearance) +{ + const Appearance *appearance = (const Appearance *) hAppearance; + M3G_VALIDATE_OBJECT(appearance); + return appearance->layer; +} + +/*! + * \brief Set compositing mode + * + * \param hAppearance Appearance object + * \param hMode CompositingMode object + */ +M3G_API void m3gSetCompositingMode(M3GAppearance hAppearance, + M3GCompositingMode hMode) +{ + Appearance *appearance = (Appearance *) hAppearance; + CompositingMode *mode = (CompositingMode *) hMode; + M3G_VALIDATE_OBJECT(appearance); + + M3G_ASSIGN_REF(appearance->compositingMode, mode); + + m3gRegenerateSortKey(appearance); +} + +/*! + * \brief Set polygon mode + * + * \param hAppearance Appearance object + * \param hMode PolygonMode object + */ +M3G_API void m3gSetPolygonMode(M3GAppearance hAppearance, + M3GPolygonMode hMode) +{ + Appearance *appearance = (Appearance *) hAppearance; + PolygonMode *mode = (PolygonMode *) hMode; + M3G_VALIDATE_OBJECT(appearance); + + M3G_ASSIGN_REF(appearance->polygonMode, mode); + + m3gRegenerateSortKey(appearance); +} + +/*! + * \brief Set layer + * + * \param hAppearance Appearance object + * \param layer layer number + */ +M3G_API void m3gSetLayer(M3GAppearance hAppearance, M3Gint layer) +{ + Appearance *appearance = (Appearance *) hAppearance; + M3G_VALIDATE_OBJECT(appearance); + + /* Check for errors */ + if (!m3gInRange(layer, M3G_APPEARANCE_MIN_LAYER, M3G_APPEARANCE_MAX_LAYER)) { + m3gRaiseError(M3G_INTERFACE(appearance), M3G_INVALID_INDEX); + return; + } + + appearance->layer = (M3Gshort) layer; + + m3gRegenerateSortKey(appearance); +} + +/*! + * \brief Set material + * + * \param hAppearance Appearance object + * \param hMaterial Material object + */ +M3G_API void m3gSetMaterial(M3GAppearance hAppearance, + M3GMaterial hMaterial) +{ + Appearance *appearance = (Appearance *) hAppearance; + Material *material = (Material *) hMaterial; + M3G_VALIDATE_OBJECT(appearance); + + M3G_ASSIGN_REF(appearance->material, material); + + if (material != NULL) { + appearance->vertexMask |= (M3Gushort)M3G_NORMAL_BIT; + } + else { + appearance->vertexMask &= ~(M3Gushort)M3G_NORMAL_BIT; + } + + m3gRegenerateSortKey(appearance); +} + +/*! + * \brief Set texture + * + * \param hAppearance Appearance object + * \param unit texturing unit + * \param hTexture Texture2D object + */ +M3G_API void m3gSetTexture(M3GAppearance hAppearance, + M3Gint unit, M3GTexture hTexture) +{ + Appearance *appearance = (Appearance *) hAppearance; + Texture *texture = (Texture *) hTexture; + M3G_VALIDATE_OBJECT(appearance); + + if (!m3gInRange(unit, 0, M3G_NUM_TEXTURE_UNITS - 1)) { + m3gRaiseError(M3G_INTERFACE(appearance), M3G_INVALID_INDEX); + return; + } + + M3G_ASSIGN_REF(appearance->texture[unit], texture); + + if (texture != NULL) { + appearance->vertexMask |= (M3Gushort) (M3G_TEXCOORD0_BIT << unit); + } + else { + appearance->vertexMask &= (M3Gushort) ~(M3G_TEXCOORD0_BIT << unit); + } + + m3gRegenerateSortKey(appearance); +} + +/*! + * \brief Set fog + * + * \param hAppearance Appearance object + * \param hFog Fog object + */ +M3G_API void m3gSetFog(M3GAppearance hAppearance, M3GFog hFog) +{ + Appearance *appearance = (Appearance *) hAppearance; + M3G_VALIDATE_OBJECT(appearance); + + M3G_ASSIGN_REF(appearance->fog, hFog); + + m3gRegenerateSortKey(appearance); +} +