2006-07-24 Matthew Allum <mallum@openedhand.com>
authorMatthew Allum <mallum@openedhand.com>
Mon, 24 Jul 2006 21:15:19 +0000 (21:15 +0000)
committerMatthew Allum <mallum@openedhand.com>
Mon, 24 Jul 2006 21:15:19 +0000 (21:15 +0000)
        * clutter/Makefile.am:
        * clutter/clutter-feature.c:
        * clutter/clutter-feature.h:

        Add new funcs for checking for available runtime GL
        extensions.

        * clutter/clutter-clone-texture.c:
        * clutter/clutter-texture.c:

        Add support for non power of two textures
       if GL_TEXTURE_RECTANGLE_ARB extension available ( at runtime ).
       Should lower texture memory needs a little.

ChangeLog
clutter/Makefile.am
clutter/clutter-clone-texture.c
clutter/clutter-feature.c [new file with mode: 0644]
clutter/clutter-feature.h [new file with mode: 0644]
clutter/clutter-main.c
clutter/clutter-main.h
clutter/clutter-texture.c

index 59cb0c9..ee6edae 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2006-07-24  Matthew Allum  <mallum@openedhand.com>
+
+       * clutter/Makefile.am:
+       * clutter/clutter-feature.c:
+       * clutter/clutter-feature.h:
+
+       Add new funcs for checking for available runtime GL 
+       extensions.     
+       
+       * clutter/clutter-clone-texture.c:
+       * clutter/clutter-texture.c:
+
+       Add support for non power of two textures 
+       if GL_TEXTURE_RECTANGLE_ARB extension available ( at runtime ).
+       Should lower texture memory needs a little.
+
 2006-07-17  Emmanuele Bassi  <ebassi@openedhand.com>
 
        * clutter/clutter-stage.c (clutter_stage_get_default): Fix
index e1c1d89..1fcd58a 100644 (file)
@@ -11,6 +11,7 @@ source_h =                              \
        $(srcdir)/clutter-media.h         \
         $(srcdir)/clutter-event.h         \
        $(srcdir)/clutter-color.h         \
+       $(srcdir)/clutter-feature.h       \
        $(srcdir)/clutter-timeline.h      \
        $(srcdir)/clutter-actor.h         \
        $(srcdir)/clutter-group.h         \
@@ -69,6 +70,7 @@ CLEANFILES = $(BUILT_SOURCES) stamp-clutter-enum-types.h
 
 source_c = clutter-main.c          \
           clutter-util.c          \
+          clutter-feature.c       \
           clutter-media.c         \
            clutter-event.c         \
           clutter-color.c         \
index fe42afe..2f63c98 100644 (file)
@@ -34,6 +34,7 @@
 
 #include "clutter-clone-texture.h"
 #include "clutter-main.h"
+#include "clutter-feature.h"
 #include "clutter-util.h" 
 #include "clutter-enum-types.h"
 #include "clutter-private.h"   /* for DBG */
@@ -91,8 +92,18 @@ clone_texture_render_to_gl_quad (ClutterCloneTexture *ctexture,
     {
       clutter_texture_bind_tile (priv->parent_texture, 0);
 
-      tx = (float) pwidth / clutter_util_next_p2 (pwidth);  
-      ty = (float) pheight / clutter_util_next_p2 (pheight);
+      /* NPOTS textures *always* used if extension available
+       */
+      if (clutter_feature_available (CLUTTER_FEATURE_TEXTURE_RECTANGLE))
+       {
+         tx = (float) pwidth;
+         ty = (float) pheight;
+       }
+      else
+       {
+         tx = (float) pwidth / clutter_util_next_p2 (pwidth);  
+         ty = (float) pheight / clutter_util_next_p2 (pheight);
+       }
 
       qx1 = x1; qx2 = x2;
       qy1 = y1; qy2 = y2;
@@ -160,11 +171,13 @@ static void
 clutter_clone_texture_paint (ClutterActor *self)
 {
   ClutterCloneTexturePrivate  *priv;
-  ClutterActor              *parent_texture;
+  ClutterActor                *parent_texture;
   gint                         x1, y1, x2, y2;
+  GLenum                       target_type;
 
   priv = CLUTTER_CLONE_TEXTURE (self)->priv;
 
+
   /* parent texture may have been hidden, there for need to make sure its 
    * realised with resources available.  
   */
@@ -172,8 +185,16 @@ clutter_clone_texture_paint (ClutterActor *self)
   if (!CLUTTER_ACTOR_IS_REALIZED (parent_texture))
     clutter_actor_realize (parent_texture);
 
+  /* FIXME: figure out nicer way of getting at this info...  
+   */  
+  if (clutter_feature_available (CLUTTER_FEATURE_TEXTURE_RECTANGLE)
+      && clutter_texture_is_tiled (CLUTTER_TEXTURE(parent_texture)) == FALSE)
+    target_type = GL_TEXTURE_RECTANGLE_ARB;
+  else
+    target_type = GL_TEXTURE_2D;
+
   glEnable(GL_BLEND);
-  glEnable(GL_TEXTURE_2D);
+  glEnable(target_type);
   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
   glColor4ub(255, 255, 255, clutter_actor_get_opacity(self));
@@ -185,8 +206,7 @@ clutter_clone_texture_paint (ClutterActor *self)
 
   clone_texture_render_to_gl_quad (CLUTTER_CLONE_TEXTURE(self), 
                                   x1, y1, x2, y2);
-
-  glDisable(GL_TEXTURE_2D);
+  glDisable(target_type);
   glDisable(GL_BLEND);
 }
 
diff --git a/clutter/clutter-feature.c b/clutter/clutter-feature.c
new file mode 100644 (file)
index 0000000..e1aa055
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Matthew Allum  <mallum@openedhand.com>
+ *
+ * Copyright (C) 2006 OpenedHand
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:clutter-feature
+ * @short_description: functions to query available GL features ay runtime 
+ *
+ * Functions to query available GL features ay runtime 
+ */
+
+#include "config.h"
+#include "clutter-feature.h"
+#include "string.h"
+
+static gulong __features;
+
+/* Note must be called after context created */
+static gboolean 
+check_gl_extension (const gchar *name)
+{
+  const gchar *ext;
+  gchar       *end;
+  gint         name_len, n;
+
+  ext = (const gchar*)glGetString(GL_EXTENSIONS);
+
+  if (name == NULL || ext == NULL)
+    return FALSE;
+
+  end = (gchar*)(ext + strlen(ext));
+
+  name_len = strlen(name);
+
+  while (ext < end) 
+    {
+      n = strcspn(ext, " ");
+
+      if ((name_len == n) && (!strncmp(name, ext, n)))
+       return TRUE;
+      ext += (n + 1);
+    }
+
+  return FALSE;
+}
+
+gboolean
+clutter_feature_available (gulong query)
+{
+  return (__features & query);
+}
+
+gulong 
+clutter_feature_all (void)
+{
+  return __features;
+}
+
+void
+clutter_feature_init (void)
+{
+  if (__features)
+    return;
+
+  __features = 0;
+
+  if (check_gl_extension ("GL_ARB_texture_rectangle"))
+      __features |= CLUTTER_FEATURE_TEXTURE_RECTANGLE;
+
+}
diff --git a/clutter/clutter-feature.h b/clutter/clutter-feature.h
new file mode 100644 (file)
index 0000000..1e8f1f4
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Matthew Allum  <mallum@openedhand.com>
+ *
+ * Copyright (C) 2006 OpenedHand
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/**
+ * SECTION:clutter-main
+ * @short_description: Various 'global' clutter functions.
+ *
+ * Functions to retrieve various global Clutter resources and other utility
+ * functions for mainloops, events and threads
+ */
+
+#ifndef _HAVE_CLUTTER_FEATURE_H
+#define _HAVE_CLUTTER_FEATURE_H
+
+#include <glib.h>
+#include <GL/glx.h>
+#include <GL/gl.h>
+
+G_END_DECLS
+
+enum 
+{
+  CLUTTER_FEATURE_TEXTURE_RECTANGLE = (1 << 1)
+};
+
+gboolean
+clutter_feature_available (gulong query);
+
+gulong 
+clutter_feature_get_all (void);
+
+void
+clutter_feature_init (void);
+
+G_END_DECLS
+
+#endif
+
index a702b76..3b573cf 100644 (file)
@@ -36,6 +36,7 @@
 #include <stdlib.h>
 
 #include "clutter-main.h"
+#include "clutter-feature.h"
 #include "clutter-actor.h"
 #include "clutter-stage.h"
 #include "clutter-private.h"
@@ -516,6 +517,7 @@ is_gl_version_at_least_12 (void)
   return FALSE;
 }
 
+
 /**
  * clutter_init:
  * @argc: The number of arguments in @argv
@@ -573,13 +575,18 @@ clutter_init (int *argc, char ***argv)
   g_return_val_if_fail (CLUTTER_IS_STAGE (context->stage), -3);
   g_object_ref_sink (context->stage);
 
+  /* Realize to get context */
   clutter_actor_realize (CLUTTER_ACTOR (context->stage));
+
   g_return_val_if_fail 
       (CLUTTER_ACTOR_IS_REALIZED(CLUTTER_ACTOR(context->stage)), -4);
 
   /* At least GL 1.2 is needed for CLAMP_TO_EDGE */
   g_return_val_if_fail(is_gl_version_at_least_12 (), -5);
 
+  /* Check available features */
+  clutter_feature_init ();
+
   events_init ();
 
   context->is_initialized = TRUE;
index 67f3ee0..41d6bdf 100644 (file)
@@ -34,6 +34,8 @@
 #include <GL/glx.h>
 #include <GL/gl.h>
 
+G_BEGIN_DECLS
+
 #define CLUTTER_HAS_DEBUG_MESSGES 1
 
 #if (CLUTTER_HAS_DEBUG_MESSGES)
@@ -92,5 +94,6 @@ clutter_threads_enter (void);
 void
 clutter_threads_leave (void);
 
+G_END_DECLS
 
 #endif
index 053bf69..db3f8d7 100644 (file)
@@ -34,6 +34,7 @@
 #include "clutter-texture.h"
 #include "clutter-main.h"
 #include "clutter-marshal.h"
+#include "clutter-feature.h"
 #include "clutter-util.h"
 #include "clutter-private.h"   /* for DBG */
 
@@ -60,16 +61,19 @@ struct ClutterTexturePrivate
   gint                         width, height;
   GLenum                       pixel_format;
   GLenum                       pixel_type;
+  GLenum                       target_type; 
 
   gboolean                     sync_actor_size;
   gint                         max_tile_waste;
   guint                        filter_quality;
   gboolean                     repeat_x, repeat_y; /* non working */
+
   
   gboolean                     tiled;
   ClutterTextureTileDimention *x_tiles, *y_tiles;
   gint                         n_x_tiles, n_y_tiles;
   GLuint                      *tiles;
+
 };
 
 enum
@@ -104,7 +108,7 @@ can_create (int    width,
            GLenum pixel_format,
            GLenum pixel_type)
 {
-  GLint new_width;
+  GLint new_width = 0;
 
   CLUTTER_DBG("checking %ix%i", width, height);
 
@@ -120,6 +124,19 @@ can_create (int    width,
   return new_width != 0;
 }
 
+static gboolean
+can_create_rect_arb (int    width, 
+                    int    height,
+                    GLenum pixel_format,
+                    GLenum pixel_type)
+{
+  /* FIXME: How to correctly query what max size of NPOTS text can be */
+  if (width > 4096 || height > 4096)
+    return FALSE;
+
+  return TRUE;
+}
+
 static int
 tile_dimension (int                          to_fill,
                int                          start_size,
@@ -224,6 +241,8 @@ texture_render_to_gl_quad (ClutterTexture *texture,
 
   priv = texture->priv;
 
+
+
   qwidth  = x2-x1;
   qheight = y2-y1;
 
@@ -240,10 +259,19 @@ texture_render_to_gl_quad (ClutterTexture *texture,
 
   if (!priv->tiled)
     {
-      glBindTexture(GL_TEXTURE_2D, priv->tiles[0]);
+      glBindTexture(priv->target_type, priv->tiles[0]);
 
-      tx = (float) priv->width / clutter_util_next_p2 (priv->width);  
-      ty = (float) priv->height / clutter_util_next_p2 (priv->height);
+      if (priv->target_type == GL_TEXTURE_2D) /* POT */
+       {
+         tx = (float) priv->width / clutter_util_next_p2 (priv->width);  
+         ty = (float) priv->height / clutter_util_next_p2 (priv->height);
+       }
+      else
+       {
+         tx = (float) priv->width;
+         ty = (float) priv->height;
+
+       }
 
       qx1 = x1; qx2 = x2;
       qy1 = y1; qy2 = y2;
@@ -266,7 +294,7 @@ texture_render_to_gl_quad (ClutterTexture *texture,
        {
          int actual_w, actual_h;
 
-         glBindTexture(GL_TEXTURE_2D, priv->tiles[i]);
+         glBindTexture(priv->target_type, priv->tiles[i]);
         
          actual_w = priv->x_tiles[x].size - priv->x_tiles[x].waste;
          actual_h = priv->y_tiles[y].size - priv->y_tiles[y].waste;
@@ -356,7 +384,6 @@ clutter_texture_sync_pixbuf (ClutterTexture *texture)
 
   g_return_if_fail (priv->pixbuf != NULL);
 
-
   CLUTTER_MARK();
 
   if (!priv->tiled)
@@ -373,20 +400,22 @@ clutter_texture_sync_pixbuf (ClutterTexture *texture)
 
       CLUTTER_DBG("syncing for single tile");
 
-      glBindTexture(GL_TEXTURE_2D, priv->tiles[0]);
+      glBindTexture(priv->target_type, priv->tiles[0]);
 
-      glTexParameteri(GL_TEXTURE_2D
+      glTexParameteri(priv->target_type
                      GL_TEXTURE_WRAP_S, 
                      priv->repeat_x ? GL_REPEAT : GL_CLAMP_TO_EDGE);
 
-      glTexParameteri(GL_TEXTURE_2D
+      glTexParameteri(priv->target_type
                      GL_TEXTURE_WRAP_T, 
                      priv->repeat_y ? GL_REPEAT : GL_CLAMP_TO_EDGE);
 
-      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, 
+      priv->filter_quality = 1;
+
+      glTexParameteri(priv->target_type, GL_TEXTURE_MAG_FILTER, 
                      priv->filter_quality ? GL_LINEAR : GL_NEAREST);
 
-      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 
+      glTexParameteri(priv->target_type, GL_TEXTURE_MIN_FILTER, 
                      priv->filter_quality ? GL_LINEAR : GL_NEAREST);
 
       glPixelStorei (GL_UNPACK_ROW_LENGTH, 
@@ -396,20 +425,31 @@ clutter_texture_sync_pixbuf (ClutterTexture *texture)
          
       if (create_textures)
        {
+         gint width, height;
+
+         width = priv->width;
+         height = priv->height;
+
+         if (priv->target_type == GL_TEXTURE_2D) /* POT */
+           {
+             width  = clutter_util_next_p2(priv->width);
+             height = clutter_util_next_p2(priv->height);
+           }
+
          /* NOTE: Change to GL_RGB for non alpha textures */
-         glTexImage2D(GL_TEXTURE_2D
+         glTexImage2D(priv->target_type
                       0, 
                       (gdk_pixbuf_get_n_channels (priv->pixbuf) == 4) ? 
                              GL_RGBA : GL_RGB,
-                      clutter_util_next_p2(priv->width),
-                      clutter_util_next_p2(priv->height),
+                      width,
+                      height,
                       0, 
                       priv->pixel_format, 
                       priv->pixel_type, 
                       NULL);
        }
 
-      glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0,
+      glTexSubImage2D (priv->target_type, 0, 0, 0,
                       priv->width,
                       priv->height,
                       priv->pixel_format, 
@@ -489,20 +529,20 @@ clutter_texture_sync_pixbuf (ClutterTexture *texture)
        }
 #endif
 
-       glBindTexture(GL_TEXTURE_2D, priv->tiles[i]);
+       glBindTexture(priv->target_type, priv->tiles[i]);
 
-       glTexParameteri(GL_TEXTURE_2D
+       glTexParameteri(priv->target_type
                        GL_TEXTURE_WRAP_S, 
                        priv->repeat_x ? GL_REPEAT : GL_CLAMP_TO_EDGE);
 
-       glTexParameteri(GL_TEXTURE_2D
+       glTexParameteri(priv->target_type
                        GL_TEXTURE_WRAP_T, 
                        priv->repeat_y ? GL_REPEAT : GL_CLAMP_TO_EDGE);
 
-       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, 
+       glTexParameteri(priv->target_type, GL_TEXTURE_MAG_FILTER, 
                        priv->filter_quality ? GL_LINEAR : GL_NEAREST);
 
-       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 
+       glTexParameteri(priv->target_type, GL_TEXTURE_MIN_FILTER, 
                        priv->filter_quality ? GL_LINEAR : GL_NEAREST);
 
        glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
@@ -514,7 +554,7 @@ clutter_texture_sync_pixbuf (ClutterTexture *texture)
        if (create_textures)
          {
 
-           glTexImage2D(GL_TEXTURE_2D
+           glTexImage2D(priv->target_type
                         0, 
                         (gdk_pixbuf_get_n_channels (priv->pixbuf) == 4) ? 
                         GL_RGBA : GL_RGB,
@@ -529,7 +569,7 @@ clutter_texture_sync_pixbuf (ClutterTexture *texture)
          {
            /* Textures already created, so just update whats inside 
            */
-           glTexSubImage2D (GL_TEXTURE_2D, 0, 
+           glTexSubImage2D (priv->target_type, 0, 
                             0, 0,
                             priv->x_tiles[x].size,
                             priv->y_tiles[y].size,
@@ -595,7 +635,7 @@ clutter_texture_paint (ClutterActor *self)
   glPushMatrix();
 
   glEnable(GL_BLEND);
-  glEnable(GL_TEXTURE_2D);
+  glEnable(texture->priv->target_type);
   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
   opacity = clutter_actor_get_opacity(self);
@@ -606,7 +646,7 @@ clutter_texture_paint (ClutterActor *self)
   clutter_actor_get_coords (self, &x1, &y1, &x2, &y2);
   texture_render_to_gl_quad (texture, x1, y1, x2, y2);
 
-  glDisable(GL_TEXTURE_2D);
+  glDisable(texture->priv->target_type);
   glDisable(GL_BLEND);
 
   glPopMatrix();
@@ -668,6 +708,11 @@ clutter_texture_set_property (GObject      *object,
       break;
     case PROP_USE_TILES:
       priv->tiled = g_value_get_boolean (value);
+
+      if (priv->target_type == GL_TEXTURE_RECTANGLE_ARB
+         && priv->tiled == TRUE)
+       priv->target_type  = GL_TEXTURE_2D;
+
       CLUTTER_DBG("Texture is tiled ? %i", priv->tiled);
       break;
     case PROP_MAX_TILE_WASTE:
@@ -778,7 +823,12 @@ clutter_texture_class_init (ClutterTextureClass *klass)
                           "Enable use of tiled textures",
                           "Enables the use of tiled GL textures to more "
                           "efficiently use available texture memory",
-                          TRUE,
+                          /* FIXME: This default set at runtime :/  
+                            * As tiling depends on what GL features available.
+                            * Need to figure out better solution
+                          */
+                          (clutter_feature_available 
+                            (CLUTTER_FEATURE_TEXTURE_RECTANGLE) == FALSE),
                           G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
 
   g_object_class_install_property
@@ -897,8 +947,15 @@ clutter_texture_init (ClutterTexture *self)
   priv->pixel_format = GL_RGBA;
   priv->repeat_x     = FALSE;
   priv->repeat_y     = FALSE;
-  priv->pixbuf = NULL;
+  priv->pixbuf       = NULL;
 
+  if (clutter_feature_available (CLUTTER_FEATURE_TEXTURE_RECTANGLE))
+    {
+      priv->target_type  = GL_TEXTURE_RECTANGLE_ARB;
+      priv->tiled        = FALSE;
+    }
+  else
+    priv->target_type = GL_TEXTURE_2D;
 
   self->priv  = priv;
 }
@@ -986,19 +1043,33 @@ clutter_texture_set_pixbuf (ClutterTexture *texture, GdkPixbuf *pixbuf)
     priv->pixel_format = GL_RGBA;
 
   /* Force tiling if pixbuf is too big for single texture */
-  if (priv->tiled == FALSE 
-      && texture_dirty 
-      && !can_create(clutter_util_next_p2(priv->width), 
-                    clutter_util_next_p2(priv->height),
-                    priv->pixel_format, 
-                    priv->pixel_type))
-    priv->tiled = TRUE;
+  if (priv->tiled == FALSE && texture_dirty)
+    {
+      if (priv->target_type == GL_TEXTURE_RECTANGLE_ARB
+         && !can_create_rect_arb (priv->width, 
+                                  priv->height,
+                                  priv->pixel_format,
+                                  priv->pixel_type))
+       {
+         /* If we cant create NPOT tex of this size fall back to tiles */
+         priv->tiled = TRUE; 
+         priv->target_type = GL_TEXTURE_2D;
+       }
+      else if (priv->target_type == GL_TEXTURE_2D
+              && !can_create(clutter_util_next_p2(priv->width), 
+                             clutter_util_next_p2(priv->height),
+                             priv->pixel_format, 
+                             priv->pixel_type))
+       { 
+         priv->tiled = TRUE; 
+       }
+    }
   clutter_threads_leave();
 
   if (priv->sync_actor_size)
     clutter_actor_set_size (CLUTTER_ACTOR(texture), 
-                             priv->width, 
-                             priv->height);
+                           priv->width, 
+                           priv->height);
 
   CLUTTER_DBG("set size %ix%i\n", priv->width, priv->height);
 
@@ -1096,7 +1167,7 @@ clutter_texture_bind_tile (ClutterTexture *texture, gint index)
   ClutterTexturePrivate *priv;
 
   priv = texture->priv;
-  glBindTexture(GL_TEXTURE_2D, priv->tiles[index]);
+  glBindTexture(priv->target_type, priv->tiles[index]);
 }
 
 /**