os/graphics/m3g/m3gcore11/src/m3g_background.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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: Background implementation
    15 *
    16 */
    17 
    18 
    19 /*!
    20  * \internal
    21  * \file
    22  * \brief Background 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_background.h"
    30 #include "m3g_image.h"
    31 #include "m3g_memory.h"
    32 #include "m3g_animationtrack.h"
    33 #include "m3g_rendercontext.h"
    34 
    35 /*----------------------------------------------------------------------
    36  * Internal functions
    37  *--------------------------------------------------------------------*/
    38 
    39 /*!
    40  * \internal
    41  * \brief Destroys this Background object.
    42  *
    43  * \param obj Background object
    44  */
    45 static void m3gDestroyBackground(Object *obj)
    46 {
    47     Background *background = (Background *) obj;
    48     M3G_VALIDATE_OBJECT(background);
    49 
    50     M3G_ASSIGN_REF(background->image, NULL);
    51     m3gDestroyObject(obj);
    52 }
    53 
    54 /*!
    55  * \internal
    56  * \brief Applies background color and image
    57  * using a textured quad.
    58  *
    59  * \param ctx           render context
    60  * \param background    Background object
    61  */
    62 static void m3gApplyBackground(RenderContext *ctx, Background *background)
    63 {
    64     GLbitfield glBits = 0;
    65     GLfixed temp[4];
    66     
    67     if (background->depthClearEnable) {
    68         glBits |= GL_DEPTH_BUFFER_BIT;
    69     }
    70 
    71     /* Skip color buffer clearing if the background image
    72      * fills the whole viewport. This is guaranteed to happen
    73      * if the crop rectangle is non-zero and both X and Y
    74      * wrapping modes are REPEAT. */
    75     
    76     if (background->colorClearEnable) {
    77         if (background->image == NULL ||
    78             background->crop.width == 0 ||
    79             background->crop.height == 0 ||
    80             background->modeX == M3G_BORDER ||
    81             background->modeY == M3G_BORDER)
    82         {
    83             glBits |= GL_COLOR_BUFFER_BIT;
    84             m3gGLColor(background->color, temp);
    85             glClearColorx(temp[0], temp[1], temp[2], temp[3]);
    86         }
    87     }
    88     
    89     /* Clear color and/or depth buffer (or neither) */
    90     glClear(glBits);
    91 
    92     /* Apply background image using a quad that
    93        fills the viewport */
    94 
    95     if (background->colorClearEnable &&
    96         background->image != NULL &&
    97         background->crop.width != 0 && 
    98         background->crop.height != 0)
    99     {
   100         {
   101             /* Texture coordinates */
   102             M3Gshort texvert[4 * 2];
   103             /* Quad that fills the viewport */
   104             M3Gint vert[4 * 3]   = { -65536,  65536, 0,
   105                                      -65536, -65536, 0,
   106                                       65536,  65536, 0,
   107                                       65536, -65536, 0 };
   108             Rect rImage, rIntersection;
   109             M3Gbool intersects;
   110             Image *imagePow2;
   111 
   112             /* Get power of two image */
   113             imagePow2 = m3gGetPowerOfTwoImage(background->image);
   114             /* If NULL -> out of memory */
   115             if (!imagePow2) {
   116                 return;
   117             }
   118 
   119             rImage.x = 0;
   120             rImage.y = 0;
   121             rImage.width = m3gGetWidth(background->image);
   122             rImage.height = m3gGetHeight(background->image);
   123 
   124             /* Intersection of source image and crop rectangle */
   125             intersects = m3gIntersectRectangle(&rIntersection, &rImage, &background->crop);
   126 
   127             /* Setup X vertices and texture S coordinates */
   128             if (background->modeX == M3G_BORDER) {
   129                 /* If both modes are border and no intersection ->
   130                    nothing to draw */
   131                 if (background->modeY == M3G_BORDER && !intersects) {
   132                     return;
   133                 }
   134 
   135                 texvert[0 * 2 + 0] = (M3Gshort) rIntersection.x;
   136                 texvert[1 * 2 + 0] = (M3Gshort) rIntersection.x;
   137                 texvert[2 * 2 + 0] = (M3Gshort) (rIntersection.x + rIntersection.width);
   138                 texvert[3 * 2 + 0] = (M3Gshort) (rIntersection.x + rIntersection.width);
   139 
   140                 vert[0 * 3 + 0] = -65536 + 2 * 65536 * (rIntersection.x - background->crop.x) / background->crop.width;
   141                 vert[1 * 3 + 0] = vert[0 * 3 + 0];
   142                 vert[2 * 3 + 0] = vert[0 * 3 + 0] + 2 * 65536 * rIntersection.width / background->crop.width;
   143                 vert[3 * 3 + 0] = vert[2 * 3 + 0];
   144             }
   145             else {
   146                 /* In repeat mode texture coordinates are directly crop rectangle coordinates */
   147                 texvert[0 * 2 + 0] = (M3Gshort) background->crop.x;
   148                 texvert[1 * 2 + 0] = (M3Gshort) background->crop.x;
   149                 texvert[2 * 2 + 0] = (M3Gshort) (background->crop.x + background->crop.width);
   150                 texvert[3 * 2 + 0] = (M3Gshort) (background->crop.x + background->crop.width);
   151             }
   152 
   153             /* Setup Y vertices and texture T coordinates */
   154             if (background->modeY == M3G_BORDER) {
   155                 texvert[0 * 2 + 1] = (M3Gshort) rIntersection.y;
   156                 texvert[1 * 2 + 1] = (M3Gshort) (rIntersection.y + rIntersection.height);
   157                 texvert[2 * 2 + 1] = (M3Gshort) rIntersection.y;
   158                 texvert[3 * 2 + 1] = (M3Gshort) (rIntersection.y + rIntersection.height);
   159 
   160 
   161                 vert[0 * 3 + 1] =  65536 - 2 * 65536 * (rIntersection.y - background->crop.y) / background->crop.height;
   162                 vert[1 * 3 + 1] = vert[0 * 3 + 1] - 2 * 65536 * rIntersection.height / background->crop.height;
   163                 vert[2 * 3 + 1] = vert[0 * 3 + 1];
   164                 vert[3 * 3 + 1] = vert[1 * 3 + 1];
   165             }
   166             else {
   167                 /* In repeat mode texture coordinates are directly crop rectangle coordinates */
   168                 texvert[0 * 2 + 1] = (M3Gshort) background->crop.y;
   169                 texvert[1 * 2 + 1] = (M3Gshort) (background->crop.y + background->crop.height);
   170                 texvert[2 * 2 + 1] = (M3Gshort) background->crop.y;
   171                 texvert[3 * 2 + 1] = (M3Gshort) (background->crop.y + background->crop.height);
   172             }
   173 
   174             /* Disable unwanted state and depth writes */
   175             m3gApplyAppearance(NULL, ctx, 0);
   176             glDepthMask(GL_FALSE);
   177 
   178             /* Disable color array, normals and textures*/
   179             glDisableClientState(GL_COLOR_ARRAY);
   180             glDisableClientState(GL_NORMAL_ARRAY);
   181         
   182             /* Background image to texture unit 0 */
   183             glClientActiveTexture(GL_TEXTURE0);
   184             glActiveTexture(GL_TEXTURE0);
   185             glEnableClientState(GL_TEXTURE_COORD_ARRAY);
   186             glTexCoordPointer(2, GL_SHORT, 0, texvert);
   187             glEnable(GL_TEXTURE_2D);
   188             glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, (GLfixed) GL_REPLACE);
   189             m3gBindTextureImage(imagePow2,
   190                                 M3G_FILTER_BASE_LEVEL,
   191                                 m3gIsAccelerated(ctx) ? M3G_FILTER_LINEAR : M3G_FILTER_NEAREST);
   192 
   193             /* Set wrapping */
   194             if (background->modeX == M3G_REPEAT) {
   195                 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
   196             }
   197             else {
   198                 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
   199             }
   200     
   201             if (background->modeY == M3G_REPEAT) {
   202                 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
   203             }
   204             else {
   205                 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
   206             }
   207 
   208             /* Texture matrix scale */
   209             glMatrixMode(GL_TEXTURE);
   210             glLoadIdentity();
   211             glScalef(   m3gRcp((M3Gfloat)m3gGetWidth(background->image)),
   212                         m3gRcp((M3Gfloat)m3gGetHeight(background->image)),
   213                         1.f);
   214             glMatrixMode(GL_MODELVIEW);
   215 
   216             /* Load vertices */
   217             glEnableClientState(GL_VERTEX_ARRAY);
   218             glVertexPointer(3, GL_FIXED, 0, vert);
   219         
   220             /* Set up an identity modelview and projection */
   221             m3gPushScreenSpace(ctx, M3G_FALSE);
   222 
   223             /* Load indices -> draws the background */
   224             M3G_BEGIN_PROFILE(M3G_INTERFACE(ctx), M3G_PROFILE_NGL_DRAW);
   225             glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
   226             M3G_END_PROFILE(M3G_INTERFACE(ctx), M3G_PROFILE_NGL_DRAW);
   227         
   228             m3gPopSpace(ctx);
   229             m3gReleaseTextureImage(imagePow2);
   230         }
   231     }
   232 }
   233 
   234 /*!
   235  * \internal
   236  * \brief Overloaded Object3D method.
   237  *
   238  * \param property      animation property
   239  * \retval M3G_TRUE     property supported
   240  * \retval M3G_FALSE    property not supported
   241  */
   242 static M3Gbool m3gBackgroundIsCompatible(M3Gint property)
   243 {
   244     switch (property) {
   245     case M3G_ANIM_ALPHA:
   246     case M3G_ANIM_COLOR:
   247     case M3G_ANIM_CROP:
   248         return M3G_TRUE;
   249     default:
   250         return m3gObjectIsCompatible(property);
   251     }
   252 }
   253 
   254 /*!
   255  * \internal
   256  * \brief Overloaded Object3D method.
   257  *
   258  * \param self          Background object
   259  * \param property      animation property
   260  * \param valueSize     size of value array
   261  * \param value         value array
   262  */
   263 static void m3gBackgroundUpdateProperty(Object *self,
   264                                         M3Gint property,
   265                                         M3Gint valueSize,
   266                                         const M3Gfloat *value)
   267 {
   268     Background *background = (Background *)self;
   269     M3G_VALIDATE_OBJECT(background);
   270     M3G_ASSERT_PTR(value);
   271     
   272     switch (property) {
   273     case M3G_ANIM_ALPHA:
   274         M3G_ASSERT(valueSize >= 1);
   275         background->color = m3gAlpha1f(value[0])
   276             & (background->color | M3G_ALPHA_MASK);
   277         break;
   278     case M3G_ANIM_COLOR:
   279         M3G_ASSERT(valueSize >= 3);
   280         background->color = m3gColor3f(value[0], value[1], value[2])
   281             & (background->color | M3G_RGB_MASK);
   282         break;
   283     case M3G_ANIM_CROP:
   284         M3G_ASSERT(valueSize >= 2);
   285         background->crop.x = m3gRoundToInt(value[0]);
   286         background->crop.y = m3gRoundToInt(value[1]);
   287         if (valueSize > 2) {
   288             M3G_ASSERT(valueSize >= 4);
   289             background->crop.width =
   290                 (value[2] < 0) ? 0 : m3gRoundToInt(value[2]);
   291             background->crop.height =
   292                 (value[3] < 0) ? 0 : m3gRoundToInt(value[3]);
   293         }
   294         break;
   295     default:
   296         m3gObjectUpdateProperty(self, property, valueSize, value);
   297     }
   298 }
   299 
   300 /*!
   301  * \internal
   302  * \brief Overloaded Object3D method.
   303  *
   304  * \param self Background object
   305  * \param references array of reference objects
   306  * \return number of references
   307  */
   308 static M3Gint m3gBackgroundDoGetReferences(Object *self, Object **references)
   309 {
   310     Background *bg = (Background *)self;
   311     M3Gint num = m3gObjectDoGetReferences(self, references);
   312     if (bg->image != NULL) {
   313         if (references != NULL)
   314             references[num] = (Object *)bg->image;
   315         num++;
   316     }
   317     return num;
   318 }
   319 
   320 /*!
   321  * \internal
   322  * \brief Overloaded Object3D method.
   323  */
   324 static Object *m3gBackgroundFindID(Object *self, M3Gint userID)
   325 {
   326     Background *bg = (Background *)self;
   327     Object *found = m3gObjectFindID(self, userID);
   328 
   329     if (!found && bg->image) {
   330         found = m3gFindID((Object*) bg->image, userID);
   331     }
   332     return found;
   333 }
   334 
   335 /*!
   336  * \internal
   337  * \brief Overloaded Object3D method.
   338  *
   339  * \param originalObj original Background object
   340  * \param cloneObj pointer to cloned Background object
   341  * \param pairs array for all object-duplicate pairs
   342  * \param numPairs number of pairs
   343  */
   344 static M3Gbool m3gBackgroundDuplicate(const Object *originalObj,
   345                                       Object **cloneObj,
   346                                       Object **pairs,
   347                                       M3Gint *numPairs)
   348 {
   349     Background *original = (Background *)originalObj;
   350     Background *clone = (Background *)m3gCreateBackground(originalObj->interface);
   351     *cloneObj = (Object *)clone;
   352     if (*cloneObj == NULL) {
   353         return M3G_FALSE;
   354     }
   355 
   356     if (m3gObjectDuplicate(originalObj, cloneObj, pairs, numPairs)) {
   357         clone->color = original->color;
   358         clone->modeX = original->modeX;
   359         clone->modeY = original->modeY;
   360         clone->crop = original->crop;
   361         clone->colorClearEnable = original->colorClearEnable;
   362         clone->depthClearEnable = original->depthClearEnable;
   363         M3G_ASSIGN_REF(clone->image, original->image);
   364         return M3G_TRUE;
   365     }
   366     else {
   367         return M3G_FALSE;
   368     }
   369 }
   370 
   371 /*!
   372  * \internal
   373  * \brief Initializes a Background object. See specification
   374  * for default values.
   375  *
   376  * \param m3g           M3G interface
   377  * \param background    Background object
   378  */
   379 static void m3gInitBackground(Interface *m3g, Background *background)
   380 {
   381     /* Background is derived from Object */
   382     m3gInitObject(&background->object, m3g, M3G_CLASS_BACKGROUND);
   383 
   384     background->modeX = M3G_BORDER; 
   385     background->modeY = M3G_BORDER; 
   386     background->colorClearEnable = M3G_TRUE;
   387     background->depthClearEnable = M3G_TRUE;
   388 }
   389 
   390 /*----------------------------------------------------------------------
   391  * Virtual function table
   392  *--------------------------------------------------------------------*/
   393 
   394 static const ObjectVFTable m3gvf_Background = {
   395     m3gObjectApplyAnimation,
   396     m3gBackgroundIsCompatible,
   397     m3gBackgroundUpdateProperty,
   398     m3gBackgroundDoGetReferences,
   399     m3gBackgroundFindID,
   400     m3gBackgroundDuplicate,
   401     m3gDestroyBackground
   402 };
   403 
   404 
   405 /*----------------------------------------------------------------------
   406  * Public API functions
   407  *--------------------------------------------------------------------*/
   408 
   409 /*!
   410  * \brief Creates a Background object.
   411  *
   412  * \param interface     M3G interface
   413  * \retval Background new Background object
   414  * \retval NULL Background creating failed
   415  */
   416 
   417 /*@access M3GInterface@*/
   418 /*@access M3Gobject@*/
   419 M3G_API M3GBackground m3gCreateBackground(M3GInterface interface)
   420 {
   421     Interface *m3g = (Interface *) interface;
   422     M3G_VALIDATE_INTERFACE(m3g);
   423 
   424     {
   425         Background *background =  m3gAllocZ(m3g, sizeof(Background));
   426     
   427         if (background != NULL) {
   428             m3gInitBackground(m3g, background);
   429         }
   430 
   431         return (M3GBackground) background;
   432     }
   433 }
   434 
   435 /*!
   436  * \brief Sets background color.
   437  *
   438  * \param handle        Background object
   439  * \param ARGB          background color as ARGB
   440  */
   441 
   442 /*@access M3Gobject@*/
   443 M3G_API void m3gSetBgColor(M3GBackground handle, M3Guint ARGB)
   444 {
   445     Background *background = (Background *) handle;
   446     M3G_VALIDATE_OBJECT(background);
   447     
   448     background->color = ARGB;
   449 }
   450 
   451 /*!
   452  * \brief Sets background image x and y mode.
   453  *
   454  * \param handle        Background object
   455  * \param modeX         Image X mode
   456  * \param modeY         Image Y mode
   457  */
   458 
   459 /*@access M3Gobject@*/
   460 M3G_API void m3gSetBgMode(M3GBackground handle, M3Gint modeX, M3Gint modeY)
   461 {
   462     Background *background = (Background *) handle;
   463     M3G_VALIDATE_OBJECT(background);
   464     
   465     /* Check for errors */
   466     if (modeX < M3G_BORDER || modeX > M3G_REPEAT ||
   467         modeY < M3G_BORDER || modeY > M3G_REPEAT) {
   468         m3gRaiseError(M3G_INTERFACE(background), M3G_INVALID_VALUE);
   469         return;
   470     }
   471 
   472     background->modeX = modeX;
   473     background->modeY = modeY;
   474 }
   475 
   476 /*!
   477  * \brief Sets background image crop rectangle.
   478  *
   479  * \param handle        Background object
   480  * \param cropX         crop upper left x
   481  * \param cropY         crop upper left y
   482  * \param width         crop width
   483  * \param height        crop height
   484  */
   485 
   486 /*@access M3Gobject@*/
   487 M3G_API void m3gSetBgCrop(M3GBackground handle,
   488                           M3Gint cropX, M3Gint cropY,
   489                           M3Gint width, M3Gint height)
   490 {
   491     Background *background = (Background *) handle;
   492     M3G_VALIDATE_OBJECT(background);
   493 
   494     /* Check for errors */
   495     if (width < 0 || height < 0) {
   496         m3gRaiseError(M3G_INTERFACE(background), M3G_INVALID_VALUE);
   497         return;
   498     }
   499 
   500     background->crop.x = cropX;
   501     background->crop.y = cropY;
   502     background->crop.width = width;
   503     background->crop.height = height;
   504 }
   505 
   506 /*!
   507  * \brief Sets background image.
   508  *
   509  * \param handle        Background object
   510  * \param hImage        Image2D object or NULL
   511  */
   512 
   513 /*@access M3Gobject@*/
   514 M3G_API void m3gSetBgImage(M3GBackground handle, M3GImage hImage)
   515 {
   516     Background *background = (Background *) handle;
   517     Image *image = (Image *)hImage;
   518     M3G_VALIDATE_OBJECT(background);
   519 
   520     if (image != NULL) {
   521         /* Check allowed formats */
   522         if (m3gGetFormat(image) != M3G_RGB &&
   523             m3gGetFormat(image) != M3G_RGBA) {
   524             m3gRaiseError(M3G_INTERFACE(background), M3G_INVALID_VALUE);
   525             return;
   526         }
   527 
   528         background->crop.x = 0;
   529         background->crop.y = 0;
   530         background->crop.width = m3gGetWidth(image);
   531         background->crop.height = m3gGetHeight(image);
   532     }
   533 
   534     M3G_ASSIGN_REF(background->image, image);
   535 }
   536 
   537 /*!
   538  * \brief Gets background image.
   539  *
   540  * \param handle        Background object
   541  * \return              Image2D object or NULL
   542  */
   543 
   544 /*@access M3GObject@*/
   545 M3G_API M3GImage m3gGetBgImage(M3GBackground handle)
   546 {
   547     Background *bg = (Background *) handle;
   548     M3G_VALIDATE_OBJECT(bg);
   549 
   550     return (M3GImage) bg->image;
   551 }
   552 
   553 /*!
   554  * \brief Gets background color as ARGB.
   555  *
   556  * \param handle        Background object
   557  * \return              ARGB color
   558  */
   559 
   560 /*@access M3Gobject@*/
   561 M3G_API M3Guint m3gGetBgColor(M3GBackground handle)
   562 {
   563     Background *background = (Background *) handle;
   564     M3G_VALIDATE_OBJECT(background);
   565 
   566     return background->color;
   567 }
   568 
   569 /*!
   570  * \brief Gets background image x or y mode.
   571  *
   572  * \param handle        Background object
   573  * \param which         which mode to return
   574  *                      \arg M3G_GET_MODEX
   575  *                      \arg M3G_GET_MODEY
   576  * \return              image x or y mode
   577  */
   578 
   579 /*@access M3Gobject@*/
   580 M3G_API M3Gint m3gGetBgMode(M3GBackground handle, M3Gint which)
   581 {
   582     Background *background = (Background *) handle;
   583     M3G_VALIDATE_OBJECT(background);
   584 
   585     switch(which) {
   586         case M3G_GET_MODEX:
   587             return background->modeX;
   588         case M3G_GET_MODEY:
   589         default:
   590             return background->modeY;
   591     }
   592 }
   593 
   594 /*!
   595  * \brief Gets background image crop parameter.
   596  *
   597  * \param handle        Background object
   598  * \param which         which crop parameter to return
   599  *                      \arg M3G_GET_CROPX
   600  *                      \arg M3G_GET_CROPY
   601  *                      \arg M3G_GET_CROPWIDTH
   602  *                      \arg M3G_GET_CROPHEIGHT
   603  * \return              image crop parameter
   604  */
   605 
   606 /*@access M3Gobject@*/
   607 M3G_API M3Gint m3gGetBgCrop(M3GBackground handle, M3Gint which)
   608 {
   609     Background *background = (Background *) handle;
   610     M3G_VALIDATE_OBJECT(background);
   611 
   612     switch(which) {
   613         case M3G_GET_CROPX:
   614             return background->crop.x;
   615         case M3G_GET_CROPY:
   616             return background->crop.y;
   617         case M3G_GET_CROPWIDTH:
   618             return background->crop.width;
   619         case M3G_GET_CROPHEIGHT:
   620         default:
   621             return background->crop.height;
   622     }
   623 }
   624 
   625 /*!
   626  * \brief Sets background color or depth clear enable.
   627  *
   628  * \param handle        Background object
   629  * \param which         which clear to enable
   630  *                      \arg M3G_SETGET_COLORCLEAR
   631  *                      \arg M3G_SETGET_DEPTHCLEAR
   632  * \param enable        clear enable/disable
   633  */
   634 
   635 /*@access M3Gobject@*/
   636 M3G_API void m3gSetBgEnable(M3GBackground handle, M3Gint which, M3Gbool enable)
   637 {
   638     Background *background = (Background *) handle;
   639     M3G_VALIDATE_OBJECT(background);
   640 
   641     switch(which) {
   642         case M3G_SETGET_COLORCLEAR:
   643             background->colorClearEnable = enable;
   644             break;
   645         case M3G_SETGET_DEPTHCLEAR:
   646         default:
   647             background->depthClearEnable = enable;
   648             break;
   649     }
   650 }
   651 
   652 /*!
   653  * \brief Gets background color or depth clear enable.
   654  *
   655  * \param handle        Background object
   656  * \param which         which clear to return
   657  *                      \arg M3G_SETGET_COLORCLEAR
   658  *                      \arg M3G_SETGET_DEPTHCLEAR
   659  * \return              clear enabled
   660  */
   661 
   662 /*@access M3Gobject@*/
   663 M3G_API M3Gbool m3gIsBgEnabled(M3GBackground handle, M3Gint which)
   664 {
   665     Background *background = (Background *) handle;
   666     M3G_VALIDATE_OBJECT(background);
   667 
   668     switch(which) {
   669         case M3G_SETGET_COLORCLEAR:
   670             return background->colorClearEnable;
   671         case M3G_SETGET_DEPTHCLEAR:
   672         default:
   673             return background->depthClearEnable;
   674     }
   675 }
   676