m3g/m3gcore11/src/m3g_texture.c
changeset 0 5d03bc08d59c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m3g/m3gcore11/src/m3g_texture.c	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,598 @@
+/*
+* 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: Texture2D implementation
+*
+*/
+
+
+/*!
+ * \internal
+ * \file
+ * \brief Texture2D implementation
+ */
+
+#ifndef M3G_CORE_INCLUDE
+#   error included by m3g_core.c; do not compile separately.
+#endif
+
+/*
+ * Uncomment this line to switch tracing on for this file's functions
+ */
+/* #define M3G_LOCAL_TRACEF_ON */
+
+#include "m3g_object.h"
+
+#include "m3g_image.h"
+#include "m3g_math.h"
+#include "m3g_texture.h"
+#include "m3g_animationtrack.h"
+#include "m3g_transformable.h"
+
+/*!
+ * \internal
+ * \brief Texture object
+ */
+struct M3GTextureImpl
+{
+    Transformable transformable;
+
+    Image *image;
+
+    M3Guint blendColor;
+    M3Genum blendFunc;
+
+    M3Genum levelFilter;
+    M3Genum imageFilter;
+
+    M3Genum wrapS;
+    M3Genum wrapT;
+};
+
+/*
+ * Uncomment this line to switch tracing on for this file's functions
+ */
+/* #define M3G_LOCAL_TRACEF_ON */
+
+/*----------------------------------------------------------------------
+ * Internal functions
+ *--------------------------------------------------------------------*/
+
+/*!
+ * \internal
+ * \brief Destroys this Texture object.
+ *
+ * \param obj Texture object
+ */
+static void m3gDestroyTexture(Object *obj)
+{
+    Texture *tex = (Texture *) obj;
+    M3G_VALIDATE_OBJECT(tex);
+
+    M3G_ASSIGN_REF(tex->image, NULL);
+    m3gDestroyTransformable(obj);
+}
+
+/*!
+ * \internal
+ * \brief Disables all texturing units and texture coordinate arrays
+ */
+static void m3gDisableTextures(void)
+{
+    M3Gint i;
+    for (i = 0; i < M3G_NUM_TEXTURE_UNITS; ++i) {
+        glClientActiveTexture(GL_TEXTURE0 + i);
+        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+        glActiveTexture(GL_TEXTURE0 + i);
+        glDisable(GL_TEXTURE_2D);
+    }
+}
+
+/*!
+ * \internal
+ * \brief Applies texture to OpenGL.
+ *
+ * \param texture Texture object
+ */
+static void m3gBindTexture(Texture *texture)
+{
+    M3Gfloat colors[4];
+    M3Gint mode;
+
+    M3G_VALIDATE_OBJECT(texture);
+    
+    m3gBindTextureImage(texture->image,
+                        texture->levelFilter,
+                        texture->imageFilter); 
+
+    /* setting up texturing mode */
+    {
+        M3GMatrix mtx;
+        M3Gfloat matrixValues[16];
+        m3gGetCompositeTransform((Transformable *) texture, &mtx);
+        m3gGetMatrixColumns(&mtx, matrixValues);
+        glMatrixMode(GL_TEXTURE);
+        glLoadMatrixf(matrixValues);
+    }
+    glMatrixMode(GL_MODELVIEW);
+
+    mode = GL_REPLACE;
+    switch (texture->blendFunc) {
+    case M3G_FUNC_REPLACE:
+        mode = GL_REPLACE;
+        break;
+    case M3G_FUNC_ADD:
+        mode = GL_ADD;
+        break;
+    case M3G_FUNC_BLEND:
+        mode = GL_BLEND;
+        break;
+    case M3G_FUNC_DECAL:
+        mode = GL_DECAL;
+        break;
+    case M3G_FUNC_MODULATE:
+        mode = GL_MODULATE;
+        break;
+    default:
+        /* This should never happen */
+        M3G_ASSERT(0);
+        break;
+    }
+    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, (GLfixed)mode);
+
+    m3gFloatColor(texture->blendColor, 1.f, colors);
+    glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, colors);
+
+    /* setting up wrapping */
+    if (texture->wrapS  == M3G_WRAP_CLAMP) {
+        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    }
+    else {
+        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+    }
+    if (texture->wrapT == M3G_WRAP_CLAMP) {
+        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    }
+    else {
+        glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+    }
+
+    M3G_ASSERT_GL;
+}
+
+/*!
+ * \internal
+ * \brief Releases a bound texture from the current texture unit
+ *
+ */
+static void m3gReleaseTexture(Texture *texture)
+{
+    m3gReleaseTextureImage(texture->image);
+}
+
+#if defined(M3G_NGL_TEXTURE_API)
+/*!
+ * \internal
+ * \brief Make sure that mipmaps are allocated if needed
+ */
+static M3Gbool m3gValidateTextureMipmapping(Texture *texture)
+{
+    return (texture->levelFilter == M3G_FILTER_BASE_LEVEL
+            || texture->image->mipData);
+}
+#endif
+
+/*!
+ * \internal
+ * \brief Overloaded Object3D method.
+ *
+ * \param property      animation property
+ * \retval M3G_TRUE     property supported
+ * \retval M3G_FALSE    property not supported
+ */
+static M3Gbool m3gTextureIsCompatible(M3Gint property)
+{
+    switch (property) {
+    case M3G_ANIM_COLOR:
+        return M3G_TRUE;
+    default:
+        return m3gTransformableIsCompatible(property);
+    }
+}
+
+/*!
+ * \internal
+ * \brief Overloaded Object3D method.
+ *
+ * \param self          Texture object
+ * \param property      animation property
+ * \param valueSize     size of value array
+ * \param value         value array
+ */
+static void m3gTextureUpdateProperty(Object *self,
+                                     M3Gint property,
+                                     M3Gint valueSize,
+                                     const M3Gfloat *value)
+{
+    Texture *texture = (Texture *)self;
+    M3G_VALIDATE_OBJECT(texture);
+    M3G_ASSERT_PTR(value);
+
+    switch (property) {
+    case M3G_ANIM_COLOR:
+        M3G_ASSERT(valueSize >= 3);
+        texture->blendColor =
+            (valueSize == 3
+             ? m3gColor3f(value[0], value[1], value[2])
+             : m3gColor4f(value[0], value[1], value[2], value[3]));
+        break;
+    default:
+        m3gTransformableUpdateProperty(self, property, valueSize, value);
+    }
+}
+
+/*!
+ * \internal
+ * \brief Overloaded Object3D method.
+ *
+ * \param self Texture object
+ * \param references array of reference objects
+ * \return number of references
+ */
+static M3Gint m3gTextureDoGetReferences(Object *self, Object **references)
+{
+    Texture *texture = (Texture *)self;
+    M3Gint num = m3gObjectDoGetReferences(self, references);
+    if (texture->image != NULL) {
+        if (references != NULL)
+            references[num] = (Object *)texture->image;
+        num++;
+    }
+    return num;
+}
+
+/*!
+ * \internal
+ * \brief Overloaded Object3D method.
+ */
+static Object *m3gTextureFindID(Object *self, M3Gint userID)
+{
+    Texture *texture = (Texture *)self;
+    Object *found = m3gObjectFindID(self, userID);
+    
+    if (!found && texture->image != NULL) {
+        found = m3gFindID((Object*) texture->image, userID);
+    }
+    return found;
+}
+
+/*!
+ * \internal
+ * \brief Overloaded Object3D method.
+ *
+ * \param originalObj original Texture object
+ * \param cloneObj pointer to cloned Texture object
+ * \param pairs array for all object-duplicate pairs
+ * \param numPairs number of pairs
+ */
+static M3Gbool m3gTextureDuplicate(const Object *originalObj,
+                                   Object **cloneObj,
+                                   Object **pairs,
+                                   M3Gint *numPairs)
+{
+    Texture *original = (Texture *)originalObj;
+    Texture *clone;
+    M3G_ASSERT(*cloneObj == NULL); /* no derived classes */
+
+    /* Create the clone object */
+    
+    clone = (Texture *)m3gCreateTexture(originalObj->interface,
+                                        original->image);
+    if (!clone) {
+        return M3G_FALSE;
+    }
+    *cloneObj = (Object *)clone;
+
+    /* Duplicate base class data */
+    
+    if (!m3gTransformableDuplicate(originalObj, cloneObj, pairs, numPairs)) {
+        return M3G_FALSE;
+    }
+
+    /* Duplicate our own data */
+    
+    clone->blendColor = original->blendColor;
+    clone->blendFunc = original->blendFunc;
+    clone->levelFilter = original->levelFilter;
+    clone->imageFilter = original->imageFilter;
+    clone->wrapS = original->wrapS;
+    clone->wrapT = original->wrapT;
+
+    return M3G_TRUE;
+}
+
+/*!
+ * \internal
+ * \brief Check texture dimensions.
+ *
+ * \retval M3G_TRUE dimensions valid
+ * \retval M3G_FALSE dimensions invalid
+ */
+static M3Gbool m3gIsValidDimensions(M3Gint width, M3Gint height)
+{
+    return (       m3gInRange(width,  1, M3G_MAX_TEXTURE_DIMENSION)
+                && m3gInRange(height, 1, M3G_MAX_TEXTURE_DIMENSION)
+                && m3gIsPowerOfTwo(width)
+                && m3gIsPowerOfTwo(height) );
+}
+
+/*----------------------------------------------------------------------
+ * Virtual function table
+ *--------------------------------------------------------------------*/
+
+static const ObjectVFTable m3gvf_Texture = {
+    m3gObjectApplyAnimation,
+    m3gTextureIsCompatible,
+    m3gTextureUpdateProperty,
+    m3gTextureDoGetReferences,
+    m3gTextureFindID,
+    m3gTextureDuplicate,
+    m3gDestroyTexture
+};
+
+
+/*----------------------------------------------------------------------
+ * Public API functions
+ *--------------------------------------------------------------------*/
+
+/*!
+ * \brief Texture constructor, creates a texture with
+ * default values.
+ *
+ *
+ * \param interface             M3G interface
+ * \param hImage                texture Image object
+ * \retval Texture new Texture object
+ * \retval NULL Texture creating failed
+ */
+M3G_API M3GTexture m3gCreateTexture(M3GInterface interface,
+                                    M3GImage hImage)
+{
+    Interface *m3g = (Interface *) interface;
+    Image* image = (Image *)hImage;
+    M3G_VALIDATE_INTERFACE(m3g);
+
+    /* Check inputs */
+    if (image == NULL) {
+        m3gRaiseError(m3g, M3G_NULL_POINTER);
+        return NULL;
+    }
+
+    if (!m3gIsValidDimensions(image->width, image->height)) {
+        m3gRaiseError(m3g, M3G_INVALID_VALUE);
+        return NULL;
+    }
+
+    /* Allocate and initialize the object */
+    {
+        Texture *texture;
+        texture = m3gAllocZ(m3g, sizeof(Texture));
+        if (texture != NULL) {
+            m3gInitTransformable(&texture->transformable, m3g,
+                                 M3G_CLASS_TEXTURE);
+
+            M3G_ASSIGN_REF(texture->image, image);
+    
+            texture->blendColor = 0x00000000;   /* Black */
+            texture->blendFunc = M3G_FUNC_MODULATE;
+            texture->levelFilter = M3G_FILTER_BASE_LEVEL;
+            texture->imageFilter = M3G_FILTER_NEAREST;
+            texture->wrapS = M3G_WRAP_REPEAT;
+            texture->wrapT = M3G_WRAP_REPEAT;
+        }
+
+        return (M3GTexture)texture;
+    }
+}
+
+/*!
+ * \brief Set texture image.
+ *
+ * \param hTexture  Texture object
+ * \param hImage    Image object
+ */
+M3G_API void m3gSetTextureImage(M3GTexture hTexture, M3GImage hImage)
+{
+    Texture *texture = (Texture*)hTexture;
+    Image *image = (Image *)hImage;
+    M3G_VALIDATE_OBJECT(texture);
+
+    if (image == NULL) {
+        m3gRaiseError(M3G_INTERFACE(texture), M3G_NULL_POINTER);
+        return;
+    }
+
+    if (!m3gIsValidDimensions(image->width, image->height)) {
+        m3gRaiseError(M3G_INTERFACE(texture), M3G_INVALID_VALUE);
+        return;
+    }
+
+    M3G_ASSIGN_REF(texture->image, image);
+}
+
+/*!
+ * \brief Get texture image.
+ *
+ * \param hTexture  Texture object
+ * \return          Image object
+ */
+M3G_API M3GImage m3gGetTextureImage(M3GTexture hTexture)
+{
+    const Texture *texture = (const Texture *) hTexture;
+    M3G_VALIDATE_OBJECT(texture);
+
+    return (M3GImage)(texture->image);
+}
+
+/*!
+ * \brief Set texture filtering.
+ *
+ * \param hTexture      Texture object
+ * \param levelFilter   level filter type
+ * \param imageFilter   image filter type
+ */
+M3G_API void m3gSetFiltering(M3GTexture hTexture,
+                             M3Gint levelFilter,
+                             M3Gint imageFilter)
+{
+    Texture *texture = (Texture*)hTexture;
+    if ((levelFilter != M3G_FILTER_LINEAR &&
+         levelFilter != M3G_FILTER_NEAREST &&
+         levelFilter != M3G_FILTER_BASE_LEVEL)
+        || (imageFilter != M3G_FILTER_LINEAR &&
+            imageFilter != M3G_FILTER_NEAREST)) {
+        m3gRaiseError(M3G_INTERFACE(texture), M3G_INVALID_VALUE);
+        return;
+    }
+    texture->levelFilter = levelFilter;
+    texture->imageFilter = imageFilter;
+}
+
+/*!
+ * \brief Set texture S & T wrapping mode.
+ *
+ * \param hTexture  Texture object
+ * \param wrapS     S wrap mode
+ * \param wrapT     T wrap mode
+ */
+M3G_API void m3gSetWrapping(M3GTexture hTexture, M3Gint wrapS, M3Gint wrapT)
+{
+    Texture *texture = (Texture*)hTexture;
+    if (wrapS != M3G_WRAP_CLAMP && wrapS != M3G_WRAP_REPEAT) {
+        m3gRaiseError(M3G_INTERFACE(texture), M3G_INVALID_VALUE);
+        return;
+    }
+    if (wrapT != M3G_WRAP_CLAMP && wrapT != M3G_WRAP_REPEAT) {
+        m3gRaiseError(M3G_INTERFACE(texture), M3G_INVALID_VALUE);
+        return;
+    }
+    texture->wrapS = wrapS;
+    texture->wrapT = wrapT;
+}
+
+/*!
+ * \brief Get texture S wrapping mode.
+ *
+ * \param hTexture  Texture object
+ * \return S wrapping mode
+ */
+M3G_API M3Gint m3gGetWrappingS(M3GTexture hTexture)
+{
+    Texture *texture = (Texture*)hTexture;
+    return texture->wrapS;
+}
+
+/*!
+ * \brief Get texture T wrapping mode.
+ *
+ * \param hTexture  Texture object
+ * \return T wrapping mode
+ */
+M3G_API M3Gint m3gGetWrappingT(M3GTexture hTexture)
+{
+    Texture *texture = (Texture*)hTexture;
+    return texture->wrapT;
+}
+
+/*!
+ * \brief Set texture blending function.
+ *
+ * \param hTexture  Texture object
+ * \param func      blending function
+ */
+M3G_API void m3gTextureSetBlending(M3GTexture hTexture, M3Gint func)
+{
+    Texture *texture = (Texture*)hTexture;
+
+    switch (func) {
+    case M3G_FUNC_ADD:
+    case M3G_FUNC_BLEND:
+    case M3G_FUNC_DECAL:
+    case M3G_FUNC_MODULATE:
+    case M3G_FUNC_REPLACE:
+        texture->blendFunc = func;
+        break;
+    default:
+        m3gRaiseError(M3G_INTERFACE(texture), M3G_INVALID_VALUE);
+        break;
+    }
+}
+
+/*!
+ * \brief Get texture blending function.
+ *
+ * \param hTexture  Texture object
+ * \return          blending function
+ */
+M3G_API M3Gint m3gTextureGetBlending(M3GTexture hTexture)
+{
+    Texture *texture = (Texture*)hTexture;
+    return texture->blendFunc;
+}
+
+/*!
+ * \brief Set texture blend color as RGB.
+ *
+ * \param hTexture  Texture object
+ * \param RGB       blend color as RGB
+ */
+M3G_API void m3gSetBlendColor(M3GTexture hTexture, M3Guint RGB)
+{
+    Texture *texture = (Texture*)hTexture;
+    texture->blendColor = RGB & M3G_RGB_MASK;
+}
+
+/*!
+ * \brief Get texture blend color as RGB.
+ *
+ * \param hTexture  Texture object
+ * \return          blend color as RGB
+ */
+M3G_API M3Guint m3gGetBlendColor(M3GTexture hTexture)
+{
+    Texture *texture = (Texture*)hTexture;
+    return texture->blendColor;
+}
+
+/*!
+ * \brief Get texture filtering
+ *
+ * \param hTexture      Texture object
+ * \param levelFilter   pointer to store level filter
+ * \param imageFilter   pointer to store image filter
+ */
+M3G_API void m3gGetFiltering(M3GTexture hTexture, M3Gint *levelFilter, M3Gint *imageFilter)
+{
+    Texture *texture = (Texture*)hTexture;
+    *levelFilter = texture->levelFilter;
+    *imageFilter = texture->imageFilter;
+}
+
+/*
+ * Uncomment these lines' opening pair at the begining of the file
+ * if you want to switch tracing on for this file.
+ */
+#ifdef M3G_LOCAL_TRACEF_ON
+#undef M3G_LOCAL_TRACEF_ON
+#endif
+