#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 */
{
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;
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.
*/
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));
clone_texture_render_to_gl_quad (CLUTTER_CLONE_TEXTURE(self),
x1, y1, x2, y2);
-
- glDisable(GL_TEXTURE_2D);
+ glDisable(target_type);
glDisable(GL_BLEND);
}
--- /dev/null
+/*
+ * 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;
+
+}
#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 */
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
GLenum pixel_format,
GLenum pixel_type)
{
- GLint new_width;
+ GLint new_width = 0;
CLUTTER_DBG("checking %ix%i", width, height);
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,
priv = texture->priv;
+
+
qwidth = x2-x1;
qheight = y2-y1;
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;
{
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;
g_return_if_fail (priv->pixbuf != NULL);
-
CLUTTER_MARK();
if (!priv->tiled)
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,
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,
}
#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);
if (create_textures)
{
- glTexImage2D(GL_TEXTURE_2D,
+ glTexImage2D(priv->target_type,
0,
(gdk_pixbuf_get_n_channels (priv->pixbuf) == 4) ?
GL_RGBA : GL_RGB,
{
/* 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,
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);
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();
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:
"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
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;
}
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);
ClutterTexturePrivate *priv;
priv = texture->priv;
- glBindTexture(GL_TEXTURE_2D, priv->tiles[index]);
+ glBindTexture(priv->target_type, priv->tiles[index]);
}
/**