From 4582ab12b8daa65647676fae0891c383d778b154 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Kol=C3=A5s?= Date: Sat, 7 Jun 2008 15:08:05 +0000 Subject: [PATCH] * clutter/clutter-texture.c: made the filter-quality proeprty also control the use of mipmapping. * clutter/clutter-texture.h: added ClutterTextureQuality enum. * tests/test-texture-quality.c: new test. * tests/Makefile.am: added test-texture-quality --- ChangeLog | 8 ++ clutter/clutter-texture.c | 157 +++++++++++++++++++++++------------ clutter/clutter-texture.h | 22 ++++- tests/Makefile.am | 4 +- tests/test-texture-quality.c | 98 ++++++++++++++++++++++ 5 files changed, 233 insertions(+), 56 deletions(-) create mode 100644 tests/test-texture-quality.c diff --git a/ChangeLog b/ChangeLog index 45e7081cc..2d6ff4bee 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2008-06-07 Øyvind Kolås + + * clutter/clutter-texture.c: made the filter-quality proeprty also + control the use of mipmapping. + * clutter/clutter-texture.h: added ClutterTextureQuality enum. + * tests/test-texture-quality.c: new test. + * tests/Makefile.am: added test-texture-quality + 2008-06-06 Emmanuele Bassi * clutter/clutter-texture.c: diff --git a/clutter/clutter-texture.c b/clutter/clutter-texture.c index 7c3fc3546..6567d0a27 100644 --- a/clutter/clutter-texture.c +++ b/clutter/clutter-texture.c @@ -59,6 +59,7 @@ #include "clutter-scriptable.h" #include "clutter-debug.h" #include "clutter-fixed.h" +#include "clutter-enum-types.h" #include "cogl/cogl.h" @@ -78,7 +79,7 @@ struct _ClutterTexturePrivate gint height; guint sync_actor_size : 1; gint max_tile_waste; - guint filter_quality; + ClutterTextureQuality filter_quality; guint repeat_x : 1; guint repeat_y : 1; CoglHandle texture; @@ -132,6 +133,54 @@ clutter_texture_error_quark (void) return g_quark_from_static_string ("clutter-texture-error-quark"); } +static COGLenum +clutter_texture_quality_to_cogl_min_filter (ClutterTextureQuality buf_filter) +{ + switch (buf_filter) + { + case CLUTTER_TEXTURE_QUALITY_LOW: + return CGL_NEAREST; + case CLUTTER_TEXTURE_QUALITY_MEDIUM: + return CGL_LINEAR; + case CLUTTER_TEXTURE_QUALITY_HIGH: + return CGL_LINEAR_MIPMAP_LINEAR; + } + return 0; +} + +static COGLenum +clutter_texture_quality_to_cogl_mag_filter (ClutterTextureQuality buf_filter) +{ + switch (buf_filter) + { + case CLUTTER_TEXTURE_QUALITY_LOW: + return CGL_NEAREST; + case CLUTTER_TEXTURE_QUALITY_MEDIUM: + case CLUTTER_TEXTURE_QUALITY_HIGH: + return CGL_LINEAR; + } + return 0; +} + +static ClutterTextureQuality +cogl_filters_to_clutter_texture_quality (COGLenum min, + COGLenum mag) +{ + switch (min) + { + case CGL_NEAREST: + g_assert (mag == min); /* just for sanity */ + return CLUTTER_TEXTURE_QUALITY_LOW; + case CGL_LINEAR: + g_assert (mag == min); /* just for sanity */ + return CLUTTER_TEXTURE_QUALITY_MEDIUM; + case CGL_LINEAR_MIPMAP_LINEAR: + g_assert (mag == CGL_LINEAR); /* just for sanity */ + return CLUTTER_TEXTURE_QUALITY_HIGH; + } + return 0; +} + static void texture_free_gl_resources (ClutterTexture *texture) { @@ -221,14 +270,12 @@ clutter_texture_realize (ClutterActor *actor) (priv->width, priv->height, priv->no_slice ? -1 : priv->max_tile_waste, - FALSE, + priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH, COGL_PIXEL_FORMAT_RGBA_8888); cogl_texture_set_filters (priv->texture, - priv->filter_quality - ? CGL_LINEAR : CGL_NEAREST, - priv->filter_quality - ? CGL_LINEAR : CGL_NEAREST); + clutter_texture_quality_to_cogl_min_filter (priv->filter_quality), + clutter_texture_quality_to_cogl_mag_filter (priv->filter_quality)); priv->fbo_handle = cogl_offscreen_new_to_texture (priv->texture); @@ -428,7 +475,7 @@ clutter_texture_set_property (GObject *object, break; case PROP_FILTER_QUALITY: clutter_texture_set_filter_quality (texture, - g_value_get_int (value)); + g_value_get_enum (value)); break; case PROP_COGL_TEXTURE: clutter_texture_set_cogl_texture @@ -481,7 +528,7 @@ clutter_texture_get_property (GObject *object, g_value_set_boolean (value, priv->repeat_y); break; case PROP_FILTER_QUALITY: - g_value_set_int (value, clutter_texture_get_filter_quality (texture)); + g_value_set_enum (value, clutter_texture_get_filter_quality (texture)); break; case PROP_COGL_TEXTURE: g_value_set_boxed (value, clutter_texture_get_cogl_texture (texture)); @@ -558,16 +605,12 @@ clutter_texture_class_init (ClutterTextureClass *klass) */ g_object_class_install_property (gobject_class, PROP_FILTER_QUALITY, - g_param_spec_int ("filter-quality", - "Quality of filter used when scaling a texture", - "Values 0 and 1 current only supported, with 0 " - "being lower quality but fast, 1 being better " - "quality but slower. ( Currently just maps to " - "GL_NEAREST / GL_LINEAR )", - 0, - G_MAXINT, - 1, - CLUTTER_PARAM_READWRITE)); + g_param_spec_enum ("filter-quality", + "Filter Quality", + "Rendering quality used when drawing the texture.", + CLUTTER_TYPE_TEXTURE_QUALITY, + CLUTTER_TEXTURE_QUALITY_MEDIUM, + G_PARAM_CONSTRUCT | CLUTTER_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_MAX_TILE_WASTE, @@ -727,7 +770,7 @@ clutter_texture_init (ClutterTexture *self) self->priv = priv = CLUTTER_TEXTURE_GET_PRIVATE (self); priv->max_tile_waste = 64; - priv->filter_quality = 1; + priv->filter_quality = CLUTTER_TEXTURE_QUALITY_MEDIUM; priv->repeat_x = FALSE; priv->repeat_y = FALSE; priv->sync_actor_size = TRUE; @@ -917,13 +960,13 @@ clutter_texture_set_from_data (ClutterTexture *texture, priv = texture->priv; if ((new_texture = cogl_texture_new_from_data - (width, height, - priv->no_slice ? -1 : priv->max_tile_waste, - FALSE, - source_format, - COGL_PIXEL_FORMAT_ANY, - rowstride, - data)) == COGL_INVALID_HANDLE) + (width, height, + priv->no_slice ? -1 : priv->max_tile_waste, + priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH, + source_format, + COGL_PIXEL_FORMAT_ANY, + rowstride, + data)) == COGL_INVALID_HANDLE) { g_set_error (error, CLUTTER_TEXTURE_ERROR, CLUTTER_TEXTURE_ERROR_BAD_FORMAT, @@ -933,10 +976,8 @@ clutter_texture_set_from_data (ClutterTexture *texture, } cogl_texture_set_filters (new_texture, - priv->filter_quality - ? CGL_LINEAR : CGL_NEAREST, - priv->filter_quality - ? CGL_LINEAR : CGL_NEAREST); + clutter_texture_quality_to_cogl_min_filter (priv->filter_quality), + clutter_texture_quality_to_cogl_mag_filter (priv->filter_quality)); clutter_texture_set_cogl_texture (texture, new_texture); @@ -1100,11 +1141,11 @@ clutter_texture_set_from_file (ClutterTexture *texture, g_return_val_if_fail (error == NULL || *error == NULL, FALSE); if ((new_texture = cogl_texture_new_from_file - (filename, - priv->no_slice ? -1 : priv->max_tile_waste, - FALSE, - COGL_PIXEL_FORMAT_ANY, - error)) + (filename, + priv->no_slice ? -1 : priv->max_tile_waste, + priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH, + COGL_PIXEL_FORMAT_ANY, + error)) == COGL_INVALID_HANDLE) { /* If COGL didn't give an error then make one up */ @@ -1119,10 +1160,8 @@ clutter_texture_set_from_file (ClutterTexture *texture, } cogl_texture_set_filters (new_texture, - priv->filter_quality - ? CGL_LINEAR : CGL_NEAREST, - priv->filter_quality - ? CGL_LINEAR : CGL_NEAREST); + clutter_texture_quality_to_cogl_min_filter (priv->filter_quality), + clutter_texture_quality_to_cogl_mag_filter (priv->filter_quality)); clutter_texture_set_cogl_texture (texture, new_texture); @@ -1144,23 +1183,35 @@ clutter_texture_set_from_file (ClutterTexture *texture, * Since: 0.8 */ void -clutter_texture_set_filter_quality (ClutterTexture *texture, - guint filter_quality) +clutter_texture_set_filter_quality (ClutterTexture *texture, + ClutterTextureQuality filter_quality) { ClutterTexturePrivate *priv; + ClutterTextureQuality old_quality; g_return_if_fail (CLUTTER_IS_TEXTURE (texture)); priv = texture->priv; - if (filter_quality != clutter_texture_get_filter_quality (texture)) + old_quality = clutter_texture_get_filter_quality (texture); + if (filter_quality != old_quality) { priv->filter_quality = filter_quality; if (priv->texture != COGL_INVALID_HANDLE) cogl_texture_set_filters (priv->texture, - filter_quality ? CGL_LINEAR : CGL_NEAREST, - filter_quality ? CGL_LINEAR : CGL_NEAREST); + clutter_texture_quality_to_cogl_min_filter (priv->filter_quality), + clutter_texture_quality_to_cogl_mag_filter (priv->filter_quality)); + + + if ((old_quality == CLUTTER_TEXTURE_QUALITY_HIGH || + filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH) && + CLUTTER_ACTOR_IS_REALIZED (texture)) + { + clutter_texture_unrealize (CLUTTER_ACTOR (texture)); + clutter_texture_realize (CLUTTER_ACTOR (texture)); + } + if (CLUTTER_ACTOR_IS_VISIBLE (texture)) clutter_actor_queue_redraw (CLUTTER_ACTOR (texture)); @@ -1177,7 +1228,7 @@ clutter_texture_set_filter_quality (ClutterTexture *texture, * * Since: 0.8 */ -guint +ClutterTextureQuality clutter_texture_get_filter_quality (ClutterTexture *texture) { ClutterTexturePrivate *priv; @@ -1191,8 +1242,10 @@ clutter_texture_get_filter_quality (ClutterTexture *texture) else /* If we have a valid texture handle then use the filter quality from that instead */ - return cogl_texture_get_min_filter (texture->priv->texture) - == CGL_LINEAR ? 1 : 0; + + return cogl_filters_to_clutter_texture_quality ( + cogl_texture_get_min_filter (texture->priv->texture), + cogl_texture_get_mag_filter (texture->priv->texture)); } /** @@ -1452,14 +1505,12 @@ on_fbo_source_size_change (GObject *object, priv->texture = cogl_texture_new_with_size (priv->width, priv->height, -1, - FALSE, + priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH, COGL_PIXEL_FORMAT_RGBA_8888); - cogl_texture_set_filters (priv->texture, - priv->filter_quality - ? CGL_LINEAR : CGL_NEAREST, - priv->filter_quality - ? CGL_LINEAR : CGL_NEAREST); + cogl_texture_set_filters (priv->texture, + clutter_texture_quality_to_cogl_min_filter (priv->filter_quality), + clutter_texture_quality_to_cogl_mag_filter (priv->filter_quality)); priv->fbo_handle = cogl_offscreen_new_to_texture (priv->texture); diff --git a/clutter/clutter-texture.h b/clutter/clutter-texture.h index 6ae700703..d2330ba11 100644 --- a/clutter/clutter-texture.h +++ b/clutter/clutter-texture.h @@ -112,6 +112,22 @@ typedef enum { /*< prefix=CLUTTER_TEXTURE >*/ /* FIXME: add compressed types ? */ } ClutterTextureFlags; +/** + * ClutterTextureQuality: + * @CLUTTER_TEXTURE_QUALITY_LOW: fastest rendering will use nearest neighbour + * interpolation when rendering. + * good setting. + * @CLUTTER_TEXTURE_QUALITY_MEDIUM: higher quality rendering without using + * extra resources. + * @CLUTTER_TEXTURE_QUALITY_HIGH: render the texture with the best quality + * available using extra memory. + */ +typedef enum { /*< prefix=CLUTTER_TEXTURE_QUALITY >*/ + CLUTTER_TEXTURE_QUALITY_LOW = 0, + CLUTTER_TEXTURE_QUALITY_MEDIUM, + CLUTTER_TEXTURE_QUALITY_HIGH +} ClutterTextureQuality; + GType clutter_texture_get_type (void) G_GNUC_CONST; GType clutter_texture_handle_get_type (void) G_GNUC_CONST; @@ -153,8 +169,10 @@ void clutter_texture_get_base_size (ClutterTexture *texture, gint *width, gint *height); void clutter_texture_set_filter_quality (ClutterTexture *texture, - guint filter_quality); -guint clutter_texture_get_filter_quality (ClutterTexture *texture); + ClutterTextureQuality + filter_quality); +ClutterTextureQuality + clutter_texture_get_filter_quality (ClutterTexture *texture); void clutter_texture_set_max_tile_waste (ClutterTexture *texture, gint max_tile_waste); gint clutter_texture_get_max_tile_waste (ClutterTexture *texture); diff --git a/tests/Makefile.am b/tests/Makefile.am index 586579b42..92eb08d3a 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -12,7 +12,8 @@ noinst_PROGRAMS = test-textures test-events test-offscreen test-scale \ test-cogl-tex-convert test-cogl-tex-foreign \ test-cogl-tex-getset test-cogl-offscreen \ test-cogl-tex-polygon test-stage-read-pixels \ - test-random-text test-clip test-paint-wrapper + test-random-text test-clip test-paint-wrapper \ + test-texture-quality if X11_TESTS noinst_PROGRAMS += test-pixmap @@ -64,5 +65,6 @@ test_cogl_offscreen_SOURCES = test-cogl-offscreen.c test_stage_read_pixels_SOURCES = test-stage-read-pixels.c test_random_text_SOURCES = test-random-text.c test_paint_wrapper_SOURCES = test-paint-wrapper.c +test_texture_quality_SOURCES = test-texture-quality.c EXTRA_DIST = redhand.png test-script.json diff --git a/tests/test-texture-quality.c b/tests/test-texture-quality.c new file mode 100644 index 000000000..3688e9a7f --- /dev/null +++ b/tests/test-texture-quality.c @@ -0,0 +1,98 @@ +#include +#include + +/* each time the timeline animating the label completes, swap the direction */ +static void +timeline_completed (ClutterTimeline *timeline, + gpointer user_data) +{ + clutter_timeline_set_direction (timeline, + !clutter_timeline_get_direction (timeline)); + clutter_timeline_start (timeline); +} + +static gboolean +change_filter (gpointer actor) +{ + ClutterTextureQuality old_quality; + + old_quality = clutter_texture_get_filter_quality (actor); + switch (old_quality) + { + case CLUTTER_TEXTURE_QUALITY_LOW: + clutter_texture_set_filter_quality (actor, + CLUTTER_TEXTURE_QUALITY_MEDIUM); + g_print ("Setting texture rendering quality to medium\n"); + break; + case CLUTTER_TEXTURE_QUALITY_MEDIUM: + clutter_texture_set_filter_quality (actor, + CLUTTER_TEXTURE_QUALITY_HIGH); + g_print ("Setting texture rendering quality to high\n"); + break; + case CLUTTER_TEXTURE_QUALITY_HIGH: + clutter_texture_set_filter_quality (actor, + CLUTTER_TEXTURE_QUALITY_LOW); + g_print ("Setting texture rendering quality to low\n"); + break; + } + return TRUE; +} + +gint +main (int argc, char *argv[]) +{ + ClutterTimeline *timeline; + ClutterBehaviour *depth_behavior; + ClutterActor *stage; + ClutterActor *image; + ClutterColor stage_color = { 0x12, 0x34, 0x56, 0xff }; + GError *error; + + clutter_init (&argc, &argv); + + stage = clutter_stage_get_default (); + clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); + clutter_stage_set_use_fog (CLUTTER_STAGE (stage), TRUE); + clutter_stage_set_fog (CLUTTER_STAGE (stage), 1.0, 10, -50); + + g_signal_connect (stage, + "button-press-event", G_CALLBACK (clutter_main_quit), + NULL); + + error = NULL; + image = clutter_texture_new_from_file (argv[1]?argv[1]:"redhand.png", &error); + if (error) + g_error ("Unable to load image.", error->message); + + if (!argv[1]) + g_print ("Hint: the redhand.png isn't a good test image for this, this test can take any clutter loadable image as an argument\n"); + + /* center the image */ + clutter_actor_set_position (image, + (clutter_actor_get_width (stage) - clutter_actor_get_width (image))/2, + (clutter_actor_get_height (stage) - clutter_actor_get_height (image))/2); + clutter_container_add (CLUTTER_CONTAINER (stage), image, NULL); + + timeline = clutter_timeline_new (60*5, 60); + g_signal_connect (timeline, + "completed", G_CALLBACK (timeline_completed), + NULL); + + depth_behavior = clutter_behaviour_depth_new ( + clutter_alpha_new_full (timeline, CLUTTER_ALPHA_RAMP_INC, NULL, NULL), + -2500, 400); + + clutter_behaviour_apply (depth_behavior, image); + + clutter_actor_show (stage); + clutter_timeline_start (timeline); + + g_timeout_add (10000, change_filter, image); + + clutter_main (); + + g_object_unref (depth_behavior); + g_object_unref (timeline); + + return EXIT_SUCCESS; +}