--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/m3g/m3gcore11/src/m3g_background.c Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,676 @@
+/*
+* 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: Background implementation
+*
+*/
+
+
+/*!
+ * \internal
+ * \file
+ * \brief Background implementation
+ */
+
+#ifndef M3G_CORE_INCLUDE
+# error included by m3g_core.c; do not compile separately.
+#endif
+
+#include "m3g_background.h"
+#include "m3g_image.h"
+#include "m3g_memory.h"
+#include "m3g_animationtrack.h"
+#include "m3g_rendercontext.h"
+
+/*----------------------------------------------------------------------
+ * Internal functions
+ *--------------------------------------------------------------------*/
+
+/*!
+ * \internal
+ * \brief Destroys this Background object.
+ *
+ * \param obj Background object
+ */
+static void m3gDestroyBackground(Object *obj)
+{
+ Background *background = (Background *) obj;
+ M3G_VALIDATE_OBJECT(background);
+
+ M3G_ASSIGN_REF(background->image, NULL);
+ m3gDestroyObject(obj);
+}
+
+/*!
+ * \internal
+ * \brief Applies background color and image
+ * using a textured quad.
+ *
+ * \param ctx render context
+ * \param background Background object
+ */
+static void m3gApplyBackground(RenderContext *ctx, Background *background)
+{
+ GLbitfield glBits = 0;
+ GLfixed temp[4];
+
+ if (background->depthClearEnable) {
+ glBits |= GL_DEPTH_BUFFER_BIT;
+ }
+
+ /* Skip color buffer clearing if the background image
+ * fills the whole viewport. This is guaranteed to happen
+ * if the crop rectangle is non-zero and both X and Y
+ * wrapping modes are REPEAT. */
+
+ if (background->colorClearEnable) {
+ if (background->image == NULL ||
+ background->crop.width == 0 ||
+ background->crop.height == 0 ||
+ background->modeX == M3G_BORDER ||
+ background->modeY == M3G_BORDER)
+ {
+ glBits |= GL_COLOR_BUFFER_BIT;
+ m3gGLColor(background->color, temp);
+ glClearColorx(temp[0], temp[1], temp[2], temp[3]);
+ }
+ }
+
+ /* Clear color and/or depth buffer (or neither) */
+ glClear(glBits);
+
+ /* Apply background image using a quad that
+ fills the viewport */
+
+ if (background->colorClearEnable &&
+ background->image != NULL &&
+ background->crop.width != 0 &&
+ background->crop.height != 0)
+ {
+ {
+ /* Texture coordinates */
+ M3Gshort texvert[4 * 2];
+ /* Quad that fills the viewport */
+ M3Gint vert[4 * 3] = { -65536, 65536, 0,
+ -65536, -65536, 0,
+ 65536, 65536, 0,
+ 65536, -65536, 0 };
+ Rect rImage, rIntersection;
+ M3Gbool intersects;
+ Image *imagePow2;
+
+ /* Get power of two image */
+ imagePow2 = m3gGetPowerOfTwoImage(background->image);
+ /* If NULL -> out of memory */
+ if (!imagePow2) {
+ return;
+ }
+
+ rImage.x = 0;
+ rImage.y = 0;
+ rImage.width = m3gGetWidth(background->image);
+ rImage.height = m3gGetHeight(background->image);
+
+ /* Intersection of source image and crop rectangle */
+ intersects = m3gIntersectRectangle(&rIntersection, &rImage, &background->crop);
+
+ /* Setup X vertices and texture S coordinates */
+ if (background->modeX == M3G_BORDER) {
+ /* If both modes are border and no intersection ->
+ nothing to draw */
+ if (background->modeY == M3G_BORDER && !intersects) {
+ return;
+ }
+
+ texvert[0 * 2 + 0] = (M3Gshort) rIntersection.x;
+ texvert[1 * 2 + 0] = (M3Gshort) rIntersection.x;
+ texvert[2 * 2 + 0] = (M3Gshort) (rIntersection.x + rIntersection.width);
+ texvert[3 * 2 + 0] = (M3Gshort) (rIntersection.x + rIntersection.width);
+
+ vert[0 * 3 + 0] = -65536 + 2 * 65536 * (rIntersection.x - background->crop.x) / background->crop.width;
+ vert[1 * 3 + 0] = vert[0 * 3 + 0];
+ vert[2 * 3 + 0] = vert[0 * 3 + 0] + 2 * 65536 * rIntersection.width / background->crop.width;
+ vert[3 * 3 + 0] = vert[2 * 3 + 0];
+ }
+ else {
+ /* In repeat mode texture coordinates are directly crop rectangle coordinates */
+ texvert[0 * 2 + 0] = (M3Gshort) background->crop.x;
+ texvert[1 * 2 + 0] = (M3Gshort) background->crop.x;
+ texvert[2 * 2 + 0] = (M3Gshort) (background->crop.x + background->crop.width);
+ texvert[3 * 2 + 0] = (M3Gshort) (background->crop.x + background->crop.width);
+ }
+
+ /* Setup Y vertices and texture T coordinates */
+ if (background->modeY == M3G_BORDER) {
+ texvert[0 * 2 + 1] = (M3Gshort) rIntersection.y;
+ texvert[1 * 2 + 1] = (M3Gshort) (rIntersection.y + rIntersection.height);
+ texvert[2 * 2 + 1] = (M3Gshort) rIntersection.y;
+ texvert[3 * 2 + 1] = (M3Gshort) (rIntersection.y + rIntersection.height);
+
+
+ vert[0 * 3 + 1] = 65536 - 2 * 65536 * (rIntersection.y - background->crop.y) / background->crop.height;
+ vert[1 * 3 + 1] = vert[0 * 3 + 1] - 2 * 65536 * rIntersection.height / background->crop.height;
+ vert[2 * 3 + 1] = vert[0 * 3 + 1];
+ vert[3 * 3 + 1] = vert[1 * 3 + 1];
+ }
+ else {
+ /* In repeat mode texture coordinates are directly crop rectangle coordinates */
+ texvert[0 * 2 + 1] = (M3Gshort) background->crop.y;
+ texvert[1 * 2 + 1] = (M3Gshort) (background->crop.y + background->crop.height);
+ texvert[2 * 2 + 1] = (M3Gshort) background->crop.y;
+ texvert[3 * 2 + 1] = (M3Gshort) (background->crop.y + background->crop.height);
+ }
+
+ /* Disable unwanted state and depth writes */
+ m3gApplyAppearance(NULL, ctx, 0);
+ glDepthMask(GL_FALSE);
+
+ /* Disable color array, normals and textures*/
+ glDisableClientState(GL_COLOR_ARRAY);
+ glDisableClientState(GL_NORMAL_ARRAY);
+
+ /* Background image to texture unit 0 */
+ glClientActiveTexture(GL_TEXTURE0);
+ glActiveTexture(GL_TEXTURE0);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(2, GL_SHORT, 0, texvert);
+ glEnable(GL_TEXTURE_2D);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, (GLfixed) GL_REPLACE);
+ m3gBindTextureImage(imagePow2,
+ M3G_FILTER_BASE_LEVEL,
+ m3gIsAccelerated(ctx) ? M3G_FILTER_LINEAR : M3G_FILTER_NEAREST);
+
+ /* Set wrapping */
+ if (background->modeX == M3G_REPEAT) {
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ }
+ else {
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ }
+
+ if (background->modeY == M3G_REPEAT) {
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ }
+ else {
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ }
+
+ /* Texture matrix scale */
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ glScalef( m3gRcp((M3Gfloat)m3gGetWidth(background->image)),
+ m3gRcp((M3Gfloat)m3gGetHeight(background->image)),
+ 1.f);
+ glMatrixMode(GL_MODELVIEW);
+
+ /* Load vertices */
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(3, GL_FIXED, 0, vert);
+
+ /* Set up an identity modelview and projection */
+ m3gPushScreenSpace(ctx, M3G_FALSE);
+
+ /* Load indices -> draws the background */
+ M3G_BEGIN_PROFILE(M3G_INTERFACE(ctx), M3G_PROFILE_NGL_DRAW);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ M3G_END_PROFILE(M3G_INTERFACE(ctx), M3G_PROFILE_NGL_DRAW);
+
+ m3gPopSpace(ctx);
+ m3gReleaseTextureImage(imagePow2);
+ }
+ }
+}
+
+/*!
+ * \internal
+ * \brief Overloaded Object3D method.
+ *
+ * \param property animation property
+ * \retval M3G_TRUE property supported
+ * \retval M3G_FALSE property not supported
+ */
+static M3Gbool m3gBackgroundIsCompatible(M3Gint property)
+{
+ switch (property) {
+ case M3G_ANIM_ALPHA:
+ case M3G_ANIM_COLOR:
+ case M3G_ANIM_CROP:
+ return M3G_TRUE;
+ default:
+ return m3gObjectIsCompatible(property);
+ }
+}
+
+/*!
+ * \internal
+ * \brief Overloaded Object3D method.
+ *
+ * \param self Background object
+ * \param property animation property
+ * \param valueSize size of value array
+ * \param value value array
+ */
+static void m3gBackgroundUpdateProperty(Object *self,
+ M3Gint property,
+ M3Gint valueSize,
+ const M3Gfloat *value)
+{
+ Background *background = (Background *)self;
+ M3G_VALIDATE_OBJECT(background);
+ M3G_ASSERT_PTR(value);
+
+ switch (property) {
+ case M3G_ANIM_ALPHA:
+ M3G_ASSERT(valueSize >= 1);
+ background->color = m3gAlpha1f(value[0])
+ & (background->color | M3G_ALPHA_MASK);
+ break;
+ case M3G_ANIM_COLOR:
+ M3G_ASSERT(valueSize >= 3);
+ background->color = m3gColor3f(value[0], value[1], value[2])
+ & (background->color | M3G_RGB_MASK);
+ break;
+ case M3G_ANIM_CROP:
+ M3G_ASSERT(valueSize >= 2);
+ background->crop.x = m3gRoundToInt(value[0]);
+ background->crop.y = m3gRoundToInt(value[1]);
+ if (valueSize > 2) {
+ M3G_ASSERT(valueSize >= 4);
+ background->crop.width =
+ (value[2] < 0) ? 0 : m3gRoundToInt(value[2]);
+ background->crop.height =
+ (value[3] < 0) ? 0 : m3gRoundToInt(value[3]);
+ }
+ break;
+ default:
+ m3gObjectUpdateProperty(self, property, valueSize, value);
+ }
+}
+
+/*!
+ * \internal
+ * \brief Overloaded Object3D method.
+ *
+ * \param self Background object
+ * \param references array of reference objects
+ * \return number of references
+ */
+static M3Gint m3gBackgroundDoGetReferences(Object *self, Object **references)
+{
+ Background *bg = (Background *)self;
+ M3Gint num = m3gObjectDoGetReferences(self, references);
+ if (bg->image != NULL) {
+ if (references != NULL)
+ references[num] = (Object *)bg->image;
+ num++;
+ }
+ return num;
+}
+
+/*!
+ * \internal
+ * \brief Overloaded Object3D method.
+ */
+static Object *m3gBackgroundFindID(Object *self, M3Gint userID)
+{
+ Background *bg = (Background *)self;
+ Object *found = m3gObjectFindID(self, userID);
+
+ if (!found && bg->image) {
+ found = m3gFindID((Object*) bg->image, userID);
+ }
+ return found;
+}
+
+/*!
+ * \internal
+ * \brief Overloaded Object3D method.
+ *
+ * \param originalObj original Background object
+ * \param cloneObj pointer to cloned Background object
+ * \param pairs array for all object-duplicate pairs
+ * \param numPairs number of pairs
+ */
+static M3Gbool m3gBackgroundDuplicate(const Object *originalObj,
+ Object **cloneObj,
+ Object **pairs,
+ M3Gint *numPairs)
+{
+ Background *original = (Background *)originalObj;
+ Background *clone = (Background *)m3gCreateBackground(originalObj->interface);
+ *cloneObj = (Object *)clone;
+ if (*cloneObj == NULL) {
+ return M3G_FALSE;
+ }
+
+ if (m3gObjectDuplicate(originalObj, cloneObj, pairs, numPairs)) {
+ clone->color = original->color;
+ clone->modeX = original->modeX;
+ clone->modeY = original->modeY;
+ clone->crop = original->crop;
+ clone->colorClearEnable = original->colorClearEnable;
+ clone->depthClearEnable = original->depthClearEnable;
+ M3G_ASSIGN_REF(clone->image, original->image);
+ return M3G_TRUE;
+ }
+ else {
+ return M3G_FALSE;
+ }
+}
+
+/*!
+ * \internal
+ * \brief Initializes a Background object. See specification
+ * for default values.
+ *
+ * \param m3g M3G interface
+ * \param background Background object
+ */
+static void m3gInitBackground(Interface *m3g, Background *background)
+{
+ /* Background is derived from Object */
+ m3gInitObject(&background->object, m3g, M3G_CLASS_BACKGROUND);
+
+ background->modeX = M3G_BORDER;
+ background->modeY = M3G_BORDER;
+ background->colorClearEnable = M3G_TRUE;
+ background->depthClearEnable = M3G_TRUE;
+}
+
+/*----------------------------------------------------------------------
+ * Virtual function table
+ *--------------------------------------------------------------------*/
+
+static const ObjectVFTable m3gvf_Background = {
+ m3gObjectApplyAnimation,
+ m3gBackgroundIsCompatible,
+ m3gBackgroundUpdateProperty,
+ m3gBackgroundDoGetReferences,
+ m3gBackgroundFindID,
+ m3gBackgroundDuplicate,
+ m3gDestroyBackground
+};
+
+
+/*----------------------------------------------------------------------
+ * Public API functions
+ *--------------------------------------------------------------------*/
+
+/*!
+ * \brief Creates a Background object.
+ *
+ * \param interface M3G interface
+ * \retval Background new Background object
+ * \retval NULL Background creating failed
+ */
+
+/*@access M3GInterface@*/
+/*@access M3Gobject@*/
+M3G_API M3GBackground m3gCreateBackground(M3GInterface interface)
+{
+ Interface *m3g = (Interface *) interface;
+ M3G_VALIDATE_INTERFACE(m3g);
+
+ {
+ Background *background = m3gAllocZ(m3g, sizeof(Background));
+
+ if (background != NULL) {
+ m3gInitBackground(m3g, background);
+ }
+
+ return (M3GBackground) background;
+ }
+}
+
+/*!
+ * \brief Sets background color.
+ *
+ * \param handle Background object
+ * \param ARGB background color as ARGB
+ */
+
+/*@access M3Gobject@*/
+M3G_API void m3gSetBgColor(M3GBackground handle, M3Guint ARGB)
+{
+ Background *background = (Background *) handle;
+ M3G_VALIDATE_OBJECT(background);
+
+ background->color = ARGB;
+}
+
+/*!
+ * \brief Sets background image x and y mode.
+ *
+ * \param handle Background object
+ * \param modeX Image X mode
+ * \param modeY Image Y mode
+ */
+
+/*@access M3Gobject@*/
+M3G_API void m3gSetBgMode(M3GBackground handle, M3Gint modeX, M3Gint modeY)
+{
+ Background *background = (Background *) handle;
+ M3G_VALIDATE_OBJECT(background);
+
+ /* Check for errors */
+ if (modeX < M3G_BORDER || modeX > M3G_REPEAT ||
+ modeY < M3G_BORDER || modeY > M3G_REPEAT) {
+ m3gRaiseError(M3G_INTERFACE(background), M3G_INVALID_VALUE);
+ return;
+ }
+
+ background->modeX = modeX;
+ background->modeY = modeY;
+}
+
+/*!
+ * \brief Sets background image crop rectangle.
+ *
+ * \param handle Background object
+ * \param cropX crop upper left x
+ * \param cropY crop upper left y
+ * \param width crop width
+ * \param height crop height
+ */
+
+/*@access M3Gobject@*/
+M3G_API void m3gSetBgCrop(M3GBackground handle,
+ M3Gint cropX, M3Gint cropY,
+ M3Gint width, M3Gint height)
+{
+ Background *background = (Background *) handle;
+ M3G_VALIDATE_OBJECT(background);
+
+ /* Check for errors */
+ if (width < 0 || height < 0) {
+ m3gRaiseError(M3G_INTERFACE(background), M3G_INVALID_VALUE);
+ return;
+ }
+
+ background->crop.x = cropX;
+ background->crop.y = cropY;
+ background->crop.width = width;
+ background->crop.height = height;
+}
+
+/*!
+ * \brief Sets background image.
+ *
+ * \param handle Background object
+ * \param hImage Image2D object or NULL
+ */
+
+/*@access M3Gobject@*/
+M3G_API void m3gSetBgImage(M3GBackground handle, M3GImage hImage)
+{
+ Background *background = (Background *) handle;
+ Image *image = (Image *)hImage;
+ M3G_VALIDATE_OBJECT(background);
+
+ if (image != NULL) {
+ /* Check allowed formats */
+ if (m3gGetFormat(image) != M3G_RGB &&
+ m3gGetFormat(image) != M3G_RGBA) {
+ m3gRaiseError(M3G_INTERFACE(background), M3G_INVALID_VALUE);
+ return;
+ }
+
+ background->crop.x = 0;
+ background->crop.y = 0;
+ background->crop.width = m3gGetWidth(image);
+ background->crop.height = m3gGetHeight(image);
+ }
+
+ M3G_ASSIGN_REF(background->image, image);
+}
+
+/*!
+ * \brief Gets background image.
+ *
+ * \param handle Background object
+ * \return Image2D object or NULL
+ */
+
+/*@access M3GObject@*/
+M3G_API M3GImage m3gGetBgImage(M3GBackground handle)
+{
+ Background *bg = (Background *) handle;
+ M3G_VALIDATE_OBJECT(bg);
+
+ return (M3GImage) bg->image;
+}
+
+/*!
+ * \brief Gets background color as ARGB.
+ *
+ * \param handle Background object
+ * \return ARGB color
+ */
+
+/*@access M3Gobject@*/
+M3G_API M3Guint m3gGetBgColor(M3GBackground handle)
+{
+ Background *background = (Background *) handle;
+ M3G_VALIDATE_OBJECT(background);
+
+ return background->color;
+}
+
+/*!
+ * \brief Gets background image x or y mode.
+ *
+ * \param handle Background object
+ * \param which which mode to return
+ * \arg M3G_GET_MODEX
+ * \arg M3G_GET_MODEY
+ * \return image x or y mode
+ */
+
+/*@access M3Gobject@*/
+M3G_API M3Gint m3gGetBgMode(M3GBackground handle, M3Gint which)
+{
+ Background *background = (Background *) handle;
+ M3G_VALIDATE_OBJECT(background);
+
+ switch(which) {
+ case M3G_GET_MODEX:
+ return background->modeX;
+ case M3G_GET_MODEY:
+ default:
+ return background->modeY;
+ }
+}
+
+/*!
+ * \brief Gets background image crop parameter.
+ *
+ * \param handle Background object
+ * \param which which crop parameter to return
+ * \arg M3G_GET_CROPX
+ * \arg M3G_GET_CROPY
+ * \arg M3G_GET_CROPWIDTH
+ * \arg M3G_GET_CROPHEIGHT
+ * \return image crop parameter
+ */
+
+/*@access M3Gobject@*/
+M3G_API M3Gint m3gGetBgCrop(M3GBackground handle, M3Gint which)
+{
+ Background *background = (Background *) handle;
+ M3G_VALIDATE_OBJECT(background);
+
+ switch(which) {
+ case M3G_GET_CROPX:
+ return background->crop.x;
+ case M3G_GET_CROPY:
+ return background->crop.y;
+ case M3G_GET_CROPWIDTH:
+ return background->crop.width;
+ case M3G_GET_CROPHEIGHT:
+ default:
+ return background->crop.height;
+ }
+}
+
+/*!
+ * \brief Sets background color or depth clear enable.
+ *
+ * \param handle Background object
+ * \param which which clear to enable
+ * \arg M3G_SETGET_COLORCLEAR
+ * \arg M3G_SETGET_DEPTHCLEAR
+ * \param enable clear enable/disable
+ */
+
+/*@access M3Gobject@*/
+M3G_API void m3gSetBgEnable(M3GBackground handle, M3Gint which, M3Gbool enable)
+{
+ Background *background = (Background *) handle;
+ M3G_VALIDATE_OBJECT(background);
+
+ switch(which) {
+ case M3G_SETGET_COLORCLEAR:
+ background->colorClearEnable = enable;
+ break;
+ case M3G_SETGET_DEPTHCLEAR:
+ default:
+ background->depthClearEnable = enable;
+ break;
+ }
+}
+
+/*!
+ * \brief Gets background color or depth clear enable.
+ *
+ * \param handle Background object
+ * \param which which clear to return
+ * \arg M3G_SETGET_COLORCLEAR
+ * \arg M3G_SETGET_DEPTHCLEAR
+ * \return clear enabled
+ */
+
+/*@access M3Gobject@*/
+M3G_API M3Gbool m3gIsBgEnabled(M3GBackground handle, M3Gint which)
+{
+ Background *background = (Background *) handle;
+ M3G_VALIDATE_OBJECT(background);
+
+ switch(which) {
+ case M3G_SETGET_COLORCLEAR:
+ return background->colorClearEnable;
+ case M3G_SETGET_DEPTHCLEAR:
+ default:
+ return background->depthClearEnable;
+ }
+}
+