os/graphics/m3g/m3gcore11/src/m3g_appearance.c
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 /*
     2 * Copyright (c) 2003 Nokia Corporation and/or its subsidiary(-ies).
     3 * All rights reserved.
     4 * This component and the accompanying materials are made available
     5 * under the terms of the License "Eclipse Public License v1.0"
     6 * which accompanies this distribution, and is available
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
     8 *
     9 * Initial Contributors:
    10 * Nokia Corporation - initial contribution.
    11 *
    12 * Contributors:
    13 *
    14 * Description: Appearance implementation
    15 *
    16 */
    17 
    18 
    19 /*!
    20  * \internal
    21  * \file
    22  * \brief Appearance implementation
    23  */
    24 
    25 #ifndef M3G_CORE_INCLUDE
    26 #   error included by m3g_core.c; do not compile separately.
    27 #endif
    28 
    29 #include "m3g_appearance.h"
    30 #include "m3g_vertexbuffer.h"
    31 
    32 /*----------------------------------------------------------------------
    33  * Private functions
    34  *--------------------------------------------------------------------*/
    35 
    36 /*!
    37  * \internal
    38  * \brief Applies default appearance values to OpenGL.
    39  */
    40 static void m3gApplyAppearanceDefaults(RenderContext *ctx)
    41 {
    42     int i;
    43     m3gApplyCompositingMode(NULL, ctx);
    44     m3gApplyPolygonMode(NULL);
    45     m3gApplyMaterial(NULL, 0x10000);
    46 	m3gApplyFog(NULL);
    47 
    48     for (i = 0; i < M3G_NUM_TEXTURE_UNITS; ++i) {
    49         glActiveTexture(GL_TEXTURE0 + i);
    50         glDisable(GL_TEXTURE_2D);
    51     }
    52 }
    53 
    54 /*!
    55  * \internal
    56  * \brief Generate a hash number for a pointer
    57  */
    58 static M3Guint m3gGenPointerHash(const void *ptr)
    59 {
    60     M3Guint p = ((M3Guint) ptr) >> 2;
    61     M3Guint key = p ^ (p >> 5) ^ (p >> 10) ^ (p >> 15) ^ (p >> 20) ^ (p >> 25);
    62     return key;
    63 }
    64 
    65 /*!
    66  * \internal
    67  * \brief Generate a quick hash bit pattern for the textures of this
    68  * appearance object
    69  */
    70 static M3Guint m3gGen12BitTextureHash(const Appearance *app)
    71 {
    72     M3Guint key = 0; 
    73 	
    74     int i;
    75     
    76     for (i = 0; i < M3G_NUM_TEXTURE_UNITS; ++i) {
    77         const Texture *tex = app->texture[i];
    78         if (tex) {
    79             key ^= (m3gGenPointerHash(m3gGetTextureImage((M3GTexture)tex)) >> i) << 6;
    80             key ^= (m3gGenPointerHash(tex) >> i) & 0x3Fu;
    81         }
    82     }
    83     return key & ((1u<<12)-1);
    84 }
    85 
    86 /*!
    87  * \internal
    88  * \brief Generate the sorting key for render queue
    89  *
    90  * Sort key is a combination of user settable layer and
    91  * blending mode. Blended objects are always drawn last.
    92  *
    93  * \param appearance    Appearance object
    94  * \return              sort key
    95  */
    96 static void m3gRegenerateSortKey(Appearance *appearance)
    97 {
    98 	M3Guint key = 0;
    99     M3G_VALIDATE_OBJECT(appearance);
   100 
   101     /*------------------------------------------------------------
   102      * First do the mandatory sorting by layer index and blending
   103      * state; this currently uses the top eight bits, 31..24
   104      *-----------------------------------------------------------*/
   105         
   106     key = (appearance->layer - M3G_APPEARANCE_MIN_LAYER)
   107         << (33 - M3G_APPEARANCE_HARD_SORT_BITS);
   108     
   109     /* NOTE the blending state bit is not set here, but dynamically in
   110      * m3gGetAppearanceSortKey; this way we do not need to implement
   111      * signaling from CompositingMode to Appearance when the blending
   112      * state changes */
   113 
   114     /*-----------------------------------------------------------------
   115      * The rest of the bits, 23..0, affect performance only; ideally,
   116      * these should be sorted so that the more expensive state is in the
   117      * higher bits, but this is largely dependent on the hardware
   118      *----------------------------------------------------------------*/
   119 
   120     /* Texturing changes are often expensive in graphics hardware, so
   121      * we put a hash of the texture objects into the top twelve
   122      * bits
   123      *
   124      * NOTE we do not currently update this if a texture image
   125      * changes, but that shouldn't happen too often and only has
   126      * relatively minor performance implications
   127      */
   128 
   129     key |= m3gGen12BitTextureHash(appearance) << 12;
   130 
   131     /* Use the rest of the bits for the various components; depth
   132      * function changes are another potentially costly operation, so
   133      * put that next */
   134 
   135     key |= (m3gGenPointerHash(appearance->compositingMode) & 0x0Fu) << 8;
   136     key |= (m3gGenPointerHash(appearance->material) & 0x07u) << 5;
   137     key |= (m3gGenPointerHash(appearance->polygonMode) & 0x07u) << 2;
   138     key |= (m3gGenPointerHash(appearance->fog) & 0x03u);
   139     
   140     /* Store the final value */
   141     appearance->sortKey = key;
   142 }
   143 
   144 /*----------------------------------------------------------------------
   145  * Internal functions
   146  *--------------------------------------------------------------------*/
   147 
   148 /*!
   149  * \internal
   150  * \brief Destroys this Appearance object.
   151  *
   152  * \param obj Appearance object
   153  */
   154 static void m3gDestroyAppearance(Object *obj)
   155 {
   156     int i;
   157     Appearance *appearance = (Appearance *) obj;
   158     M3G_VALIDATE_OBJECT(appearance);
   159 
   160     M3G_ASSIGN_REF(appearance->compositingMode, NULL);
   161     M3G_ASSIGN_REF(appearance->fog,             NULL);
   162     M3G_ASSIGN_REF(appearance->material,        NULL);
   163     M3G_ASSIGN_REF(appearance->polygonMode,     NULL);
   164     for (i = 0; i < M3G_NUM_TEXTURE_UNITS; ++i) {
   165         M3G_ASSIGN_REF(appearance->texture[i], NULL);
   166     }
   167     
   168     m3gDestroyObject(obj);
   169 }
   170 
   171 /*!
   172  * \internal
   173  * \brief Applies Apperance settings to current OpenGL state
   174  *
   175  * \note m3gReleaseTextures must be called when no longer using this,
   176  * to properly reset texture usage counters and unmap the texture
   177  * images.
   178  * 
   179  * \param appearance    Appearance object
   180  * \param alphaFactor   alpha factor as 1.16 fixed point
   181  */
   182 static void m3gApplyAppearance(const Appearance *appearance,
   183 							   RenderContext *ctx,
   184                                M3Gint alphaFactor)
   185 {
   186     M3G_ASSERT_GL;
   187 
   188     if (appearance != NULL) {
   189         int i;
   190 
   191 #       if defined(M3G_NGL_TEXTURE_API)
   192         m3gLockMemory(M3G_INTERFACE(appearance)); /* for textures */
   193 #       endif
   194     
   195         m3gApplyCompositingMode(appearance->compositingMode, ctx);
   196         m3gApplyPolygonMode(appearance->polygonMode);
   197         m3gApplyMaterial(appearance->material, alphaFactor);
   198         m3gApplyFog(appearance->fog);
   199 
   200         for (i = 0; i < M3G_NUM_TEXTURE_UNITS; ++i) {
   201             Texture *tex = appearance->texture[i];
   202             glActiveTexture(GL_TEXTURE0 + i);
   203             if (tex != NULL) {
   204                 glEnable(GL_TEXTURE_2D);
   205                 m3gBindTexture(appearance->texture[i]);
   206             }
   207             else {
   208                 glDisable(GL_TEXTURE_2D);
   209             }
   210         }
   211     }
   212     else {
   213         m3gApplyAppearanceDefaults(ctx);
   214     }
   215 
   216     M3G_ASSERT_GL;
   217 }
   218 
   219 /*!
   220  * \internal
   221  * \brief Release the textures bound for this appearance
   222  */
   223 static void m3gReleaseTextures(const Appearance *appearance)
   224 {
   225     if (appearance != NULL) {
   226         int i;
   227 
   228         for (i = 0; i < M3G_NUM_TEXTURE_UNITS; ++i) {
   229             Texture *tex = appearance->texture[i];
   230             if (tex != NULL) {
   231                 m3gReleaseTexture(tex);
   232             }
   233         }
   234 
   235 #       if defined(M3G_NGL_TEXTURE_API)
   236         m3gUnlockMemory(M3G_INTERFACE(appearance));
   237 #       endif
   238     }
   239 }
   240 
   241 /*!
   242  * \internal
   243  * \brief Overloaded Object3D method.
   244  *
   245  * \param self Appearance object
   246  * \param time current world time
   247  * \return minimum validity
   248  */
   249 static M3Gint m3gAppearanceApplyAnimation(Object *self, M3Gint time) {
   250     M3Gint i, validity, minValidity = 0x7fffffff;
   251     Appearance *appearance = (Appearance *)self;
   252     M3G_VALIDATE_OBJECT(appearance);
   253 
   254     if (appearance->compositingMode != NULL) {
   255         validity = M3G_VFUNC(Object, appearance->compositingMode, applyAnimation)((Object *)appearance->compositingMode, time);
   256         minValidity = (validity < minValidity ? validity : minValidity);
   257     }
   258     if (appearance->fog != NULL) {
   259         validity = M3G_VFUNC(Object, appearance->fog, applyAnimation)((Object *)appearance->fog, time);
   260         minValidity = (validity < minValidity ? validity : minValidity);
   261     }
   262     if (appearance->material != NULL) {
   263         validity = M3G_VFUNC(Object, appearance->material, applyAnimation)((Object *)appearance->material, time);
   264         minValidity = (validity < minValidity ? validity : minValidity);
   265     }
   266     for (i = 0; i < M3G_NUM_TEXTURE_UNITS; ++i) {
   267         if (appearance->texture[i] != NULL) {
   268             validity = M3G_VFUNC(Object, appearance->texture[i], applyAnimation)((Object *)appearance->texture[i], time);
   269             minValidity = (validity < minValidity ? validity : minValidity);
   270         }
   271     }
   272 
   273     /* no animations can target an Appearance directly, so we need
   274        not call super.applyAnimation() here. */
   275     return minValidity;
   276 }    
   277 
   278 /*!
   279  * \internal
   280  * \brief Overloaded Object3D method.
   281  */
   282 static Object *m3gAppearanceFindID(Object *self, M3Gint userID)
   283 {
   284     int i;
   285     Appearance *app = (Appearance *)self;
   286     Object *found = m3gObjectFindID(self, userID);
   287     
   288     if (!found && app->compositingMode) {
   289         found = m3gFindID((Object*) app->compositingMode, userID);
   290     }
   291     if (!found && app->polygonMode) {
   292         found = m3gFindID((Object*) app->polygonMode, userID);
   293     }
   294     if (!found && app->fog) {
   295         found = m3gFindID((Object*) app->fog, userID);
   296     }
   297     if (!found && app->material) {
   298         found = m3gFindID((Object*) app->material, userID);
   299     }
   300     for (i = 0; !found && i < M3G_NUM_TEXTURE_UNITS; ++i) {
   301         if (app->texture[i]) {
   302             found = m3gFindID((Object*) app->texture[i], userID);
   303         }
   304     }
   305     return found;
   306 }
   307 
   308 /*!
   309  * \internal
   310  * \brief Overloaded Object3D method.
   311  *
   312  * \param self Appearance object
   313  * \param references array of reference objects
   314  * \return number of references
   315  */
   316 static M3Gint m3gAppearanceDoGetReferences(Object *self, Object **references)
   317 {
   318     Appearance *app = (Appearance *)self;
   319     M3Gint i, num = m3gObjectDoGetReferences(self, references);
   320     if (app->compositingMode != NULL) {
   321         if (references != NULL)
   322             references[num] = (Object *)app->compositingMode;
   323         num++;
   324     }
   325     if (app->polygonMode != NULL) {
   326         if (references != NULL)
   327             references[num] = (Object *)app->polygonMode;
   328         num++;
   329     }
   330     if (app->fog != NULL) {
   331         if (references != NULL)
   332             references[num] = (Object *)app->fog;
   333         num++;
   334     }
   335     if (app->material != NULL) {
   336         if (references != NULL)
   337             references[num] = (Object *)app->material;
   338         num++;
   339     }
   340     for (i = 0; i < M3G_NUM_TEXTURE_UNITS; i++) {
   341         if (app->texture[i] != NULL) {
   342             if (references != NULL)
   343                 references[num] = (Object *)app->texture[i];
   344             num++;
   345         }
   346     }
   347     return num;
   348 }
   349 
   350 
   351 /*!
   352  * \internal
   353  * \brief Overloaded Object3D method.
   354  *
   355  * \param originalObj original Appearance object
   356  * \param cloneObj pointer to cloned Appearance object
   357  * \param pairs array for all object-duplicate pairs
   358  * \param numPairs number of pairs
   359  */
   360 static M3Gbool m3gAppearanceDuplicate(const Object *originalObj,
   361                                       Object **cloneObj,
   362                                       Object **pairs,
   363                                       M3Gint *numPairs)
   364 {
   365     M3Gint i;
   366     Appearance *original = (Appearance *)originalObj;
   367     Appearance *clone = (Appearance *)m3gCreateAppearance(originalObj->interface);
   368     *cloneObj = (Object *)clone;
   369     if (*cloneObj == NULL) {
   370         return M3G_FALSE;
   371     }
   372 
   373     if (m3gObjectDuplicate(originalObj, cloneObj, pairs, numPairs)) {
   374         clone->layer = original->layer;
   375     
   376         M3G_ASSIGN_REF(clone->compositingMode, original->compositingMode);
   377         M3G_ASSIGN_REF(clone->fog, original->fog);
   378         M3G_ASSIGN_REF(clone->polygonMode, original->polygonMode);
   379         M3G_ASSIGN_REF(clone->material, original->material);
   380         for (i = 0; i < M3G_NUM_TEXTURE_UNITS; i++) {
   381             M3G_ASSIGN_REF(clone->texture[i], original->texture[i]);
   382         }
   383 
   384         m3gRegenerateSortKey(clone);
   385         
   386         return M3G_TRUE;
   387     }
   388     else {
   389         return M3G_FALSE;
   390     }
   391 }
   392 
   393 /*----------------------------------------------------------------------
   394  * Virtual function table
   395  *--------------------------------------------------------------------*/
   396 
   397 static const ObjectVFTable m3gvf_Appearance = {
   398     m3gAppearanceApplyAnimation,
   399     m3gObjectIsCompatible,
   400     m3gObjectUpdateProperty,
   401     m3gAppearanceDoGetReferences,
   402     m3gAppearanceFindID,
   403     m3gAppearanceDuplicate,
   404     m3gDestroyAppearance
   405 };
   406 
   407 
   408 /*----------------------------------------------------------------------
   409  * Public API functions
   410  *--------------------------------------------------------------------*/
   411 
   412 /*!
   413  * \brief Creates a new Appearance with default values
   414  *
   415  * \param hInterface            M3G interface
   416  * \retval Appearance new Appearance object
   417  * \retval NULL Appearance creating failed
   418  */
   419 /*@access M3GInterface@*/
   420 /*@access M3GAppearance@*/
   421 M3G_API M3GAppearance m3gCreateAppearance(M3GInterface hInterface)
   422 {
   423     Interface *m3g = (Interface *) hInterface;
   424     M3G_VALIDATE_INTERFACE(m3g);
   425     {
   426         Appearance *appearance = m3gAllocZ(m3g, sizeof(Appearance));
   427 
   428         if (appearance != NULL) {
   429     		m3gInitObject(&appearance->object, m3g, M3G_CLASS_APPEARANCE);
   430             m3gRegenerateSortKey(appearance);
   431         }
   432         
   433         return (M3GAppearance) appearance;
   434     }
   435 }
   436 
   437 /*!
   438  * \brief Get compositing mode
   439  *
   440  * \param hAppearance Appearance object
   441  * \return CompositingMode object
   442  */
   443 M3G_API M3GCompositingMode m3gGetCompositingMode(M3GAppearance hAppearance)
   444 {
   445     const Appearance *appearance = (const Appearance *) hAppearance;
   446     M3G_VALIDATE_OBJECT(appearance);
   447     return (M3GCompositingMode)(appearance->compositingMode);
   448 }
   449 
   450 /*!
   451  * \brief Get fog
   452  *
   453  * \param hAppearance Appearance object
   454  * \return Fog object
   455  */
   456 M3G_API M3GFog m3gGetFog(M3GAppearance hAppearance)
   457 {
   458     const Appearance *appearance = (const Appearance *) hAppearance;
   459     M3G_VALIDATE_OBJECT(appearance);
   460     return (M3GFog)(appearance->fog);
   461 }
   462 
   463 /*!
   464  * \brief Get material
   465  *
   466  * \param hAppearance Appearance object
   467  * \return Material object
   468  */
   469 M3G_API M3GMaterial m3gGetMaterial(M3GAppearance hAppearance)
   470 {
   471     const Appearance *appearance = (const Appearance *) hAppearance;
   472     M3G_VALIDATE_OBJECT(appearance);
   473     return (M3GMaterial)(appearance->material);
   474 }
   475 
   476 /*!
   477  * \brief Get polygon mode
   478  *
   479  * \param hAppearance Appearance object
   480  * \return PolygonMode object
   481  */
   482 M3G_API M3GPolygonMode m3gGetPolygonMode(M3GAppearance hAppearance)
   483 {
   484     const Appearance *appearance = (const Appearance *) hAppearance;
   485     M3G_VALIDATE_OBJECT(appearance);
   486     return (M3GPolygonMode)(appearance->polygonMode);
   487 }
   488 
   489 /*!
   490  * \brief Get texture
   491  *
   492  * \param hAppearance Appearance object
   493  * \param unit texturing unit
   494  * \return Texture2D object
   495  */
   496 M3G_API M3GTexture m3gGetTexture(M3GAppearance hAppearance, M3Gint unit)
   497 {
   498     const Appearance *appearance = (const Appearance *) hAppearance;
   499     M3G_VALIDATE_OBJECT(appearance);
   500     if (!m3gInRange(unit, 0, M3G_NUM_TEXTURE_UNITS - 1)) {
   501         m3gRaiseError(M3G_INTERFACE(appearance), M3G_INVALID_INDEX);
   502         return (M3GTexture) NULL;
   503     }
   504     return (M3GTexture)(appearance->texture[unit]);
   505 }
   506 
   507 /*!
   508  * \brief Get layer
   509  *
   510  * \param hAppearance Appearance object
   511  * \return layer number
   512  */
   513 M3G_API M3Gint m3gGetLayer(M3GAppearance hAppearance)
   514 {
   515     const Appearance *appearance = (const Appearance *) hAppearance;
   516     M3G_VALIDATE_OBJECT(appearance);
   517     return appearance->layer;
   518 }
   519 
   520 /*!
   521  * \brief Set compositing mode
   522  *
   523  * \param hAppearance Appearance object
   524  * \param hMode CompositingMode object
   525  */
   526 M3G_API void m3gSetCompositingMode(M3GAppearance hAppearance,
   527                                    M3GCompositingMode hMode)
   528 {
   529     Appearance *appearance = (Appearance *) hAppearance;
   530     CompositingMode *mode = (CompositingMode *) hMode;
   531     M3G_VALIDATE_OBJECT(appearance);
   532     
   533     M3G_ASSIGN_REF(appearance->compositingMode, mode);
   534 
   535     m3gRegenerateSortKey(appearance);
   536 }
   537 
   538 /*!
   539  * \brief Set polygon mode
   540  *
   541  * \param hAppearance Appearance object
   542  * \param hMode PolygonMode object
   543  */
   544 M3G_API void m3gSetPolygonMode(M3GAppearance hAppearance,
   545                                M3GPolygonMode hMode)
   546 {
   547     Appearance *appearance = (Appearance *) hAppearance;
   548     PolygonMode *mode = (PolygonMode *) hMode;
   549     M3G_VALIDATE_OBJECT(appearance);
   550 
   551     M3G_ASSIGN_REF(appearance->polygonMode, mode);
   552 
   553     m3gRegenerateSortKey(appearance);
   554 }
   555 
   556 /*!
   557  * \brief Set layer
   558  *
   559  * \param hAppearance Appearance object
   560  * \param layer layer number
   561  */
   562 M3G_API void m3gSetLayer(M3GAppearance hAppearance, M3Gint layer)
   563 {
   564     Appearance *appearance = (Appearance *) hAppearance;
   565     M3G_VALIDATE_OBJECT(appearance);
   566 
   567     /* Check for errors */
   568     if (!m3gInRange(layer, M3G_APPEARANCE_MIN_LAYER, M3G_APPEARANCE_MAX_LAYER)) {
   569         m3gRaiseError(M3G_INTERFACE(appearance), M3G_INVALID_INDEX);
   570         return;
   571     }
   572 
   573     appearance->layer = (M3Gshort) layer;
   574     
   575     m3gRegenerateSortKey(appearance);
   576 }
   577 
   578 /*!
   579  * \brief Set material
   580  *
   581  * \param hAppearance Appearance object
   582  * \param hMaterial Material object
   583  */
   584 M3G_API void m3gSetMaterial(M3GAppearance hAppearance,
   585                             M3GMaterial hMaterial)
   586 {
   587     Appearance *appearance = (Appearance *) hAppearance;
   588     Material *material = (Material *) hMaterial;
   589     M3G_VALIDATE_OBJECT(appearance);
   590 
   591     M3G_ASSIGN_REF(appearance->material, material);
   592     
   593     if (material != NULL) {
   594         appearance->vertexMask |= (M3Gushort)M3G_NORMAL_BIT;
   595     }
   596     else {
   597         appearance->vertexMask &= ~(M3Gushort)M3G_NORMAL_BIT;
   598     }
   599 
   600     m3gRegenerateSortKey(appearance);
   601 }
   602 
   603 /*!
   604  * \brief Set texture
   605  *
   606  * \param hAppearance Appearance object
   607  * \param unit texturing unit
   608  * \param hTexture Texture2D object
   609  */
   610 M3G_API void m3gSetTexture(M3GAppearance hAppearance,
   611                            M3Gint unit, M3GTexture hTexture)
   612 {
   613     Appearance *appearance = (Appearance *) hAppearance;
   614     Texture *texture = (Texture *) hTexture;
   615     M3G_VALIDATE_OBJECT(appearance);
   616     
   617     if (!m3gInRange(unit, 0, M3G_NUM_TEXTURE_UNITS - 1)) {
   618         m3gRaiseError(M3G_INTERFACE(appearance), M3G_INVALID_INDEX);
   619         return;
   620     }
   621     
   622     M3G_ASSIGN_REF(appearance->texture[unit], texture);
   623     
   624     if (texture != NULL) {
   625         appearance->vertexMask |= (M3Gushort) (M3G_TEXCOORD0_BIT << unit);
   626     }
   627     else {
   628         appearance->vertexMask &= (M3Gushort) ~(M3G_TEXCOORD0_BIT << unit);
   629     }
   630 
   631     m3gRegenerateSortKey(appearance);
   632 }
   633 
   634 /*!
   635  * \brief Set fog
   636  *
   637  * \param hAppearance Appearance object
   638  * \param hFog Fog object
   639  */
   640 M3G_API void m3gSetFog(M3GAppearance hAppearance, M3GFog hFog)
   641 {
   642     Appearance *appearance = (Appearance *) hAppearance;
   643     M3G_VALIDATE_OBJECT(appearance);
   644 	
   645 	M3G_ASSIGN_REF(appearance->fog, hFog);
   646 
   647     m3gRegenerateSortKey(appearance);
   648 }
   649