Compare commits
7 Commits
path-itera
...
texture-fi
Author | SHA1 | Date | |
---|---|---|---|
|
d4dfbc1def | ||
|
fb73acc885 | ||
|
acad0e8893 | ||
|
d869aec29f | ||
|
aae99a8704 | ||
|
19ba03d0a6 | ||
|
ac59d553ce |
@@ -3,7 +3,9 @@
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_PAINTABLE = 1,
|
||||
PROP_TEXTURE = 1,
|
||||
PROP_MIN_FILTER,
|
||||
PROP_MAG_FILTER,
|
||||
PROP_SCALE
|
||||
};
|
||||
|
||||
@@ -11,8 +13,10 @@ struct _Demo3Widget
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
|
||||
GdkPaintable *paintable;
|
||||
GdkTexture *texture;
|
||||
float scale;
|
||||
GskScalingFilter min_filter;
|
||||
GskScalingFilter mag_filter;
|
||||
|
||||
GtkWidget *menu;
|
||||
};
|
||||
@@ -28,6 +32,8 @@ static void
|
||||
demo3_widget_init (Demo3Widget *self)
|
||||
{
|
||||
self->scale = 1.f;
|
||||
self->min_filter = GSK_SCALING_FILTER_NEAREST;
|
||||
self->mag_filter = GSK_SCALING_FILTER_NEAREST;
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
@@ -36,7 +42,7 @@ demo3_widget_dispose (GObject *object)
|
||||
{
|
||||
Demo3Widget *self = DEMO3_WIDGET (object);
|
||||
|
||||
g_clear_object (&self->paintable);
|
||||
g_clear_object (&self->texture);
|
||||
|
||||
gtk_widget_dispose_template (GTK_WIDGET (self), DEMO3_TYPE_WIDGET);
|
||||
|
||||
@@ -50,12 +56,13 @@ demo3_widget_snapshot (GtkWidget *widget,
|
||||
Demo3Widget *self = DEMO3_WIDGET (widget);
|
||||
int x, y, width, height;
|
||||
double w, h;
|
||||
GskRenderNode *node;
|
||||
|
||||
width = gtk_widget_get_width (widget);
|
||||
height = gtk_widget_get_height (widget);
|
||||
|
||||
w = self->scale * gdk_paintable_get_intrinsic_width (self->paintable);
|
||||
h = self->scale * gdk_paintable_get_intrinsic_height (self->paintable);
|
||||
w = self->scale * gdk_texture_get_width (self->texture);
|
||||
h = self->scale * gdk_texture_get_height (self->texture);
|
||||
|
||||
x = MAX (0, (width - ceil (w)) / 2);
|
||||
y = MAX (0, (height - ceil (h)) / 2);
|
||||
@@ -63,7 +70,12 @@ demo3_widget_snapshot (GtkWidget *widget,
|
||||
gtk_snapshot_push_clip (snapshot, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
gtk_snapshot_save (snapshot);
|
||||
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (x, y));
|
||||
gdk_paintable_snapshot (self->paintable, snapshot, w, h);
|
||||
node = gsk_texture_node_new_with_filters (self->texture,
|
||||
&GRAPHENE_RECT_INIT (0, 0, w, h),
|
||||
self->min_filter,
|
||||
self->mag_filter);
|
||||
gtk_snapshot_append_node (snapshot, node);
|
||||
gsk_render_node_unref (node);
|
||||
gtk_snapshot_restore (snapshot);
|
||||
gtk_snapshot_pop (snapshot);
|
||||
}
|
||||
@@ -81,9 +93,9 @@ demo3_widget_measure (GtkWidget *widget,
|
||||
int size;
|
||||
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
size = gdk_paintable_get_intrinsic_width (self->paintable);
|
||||
size = gdk_texture_get_width (self->texture);
|
||||
else
|
||||
size = gdk_paintable_get_intrinsic_height (self->paintable);
|
||||
size = gdk_texture_get_height (self->texture);
|
||||
|
||||
*minimum = *natural = self->scale * size;
|
||||
}
|
||||
@@ -113,9 +125,9 @@ demo3_widget_set_property (GObject *object,
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PAINTABLE:
|
||||
g_clear_object (&self->paintable);
|
||||
self->paintable = g_value_dup_object (value);
|
||||
case PROP_TEXTURE:
|
||||
g_clear_object (&self->texture);
|
||||
self->texture = g_value_dup_object (value);
|
||||
gtk_widget_queue_resize (GTK_WIDGET (object));
|
||||
break;
|
||||
|
||||
@@ -124,6 +136,16 @@ demo3_widget_set_property (GObject *object,
|
||||
gtk_widget_queue_resize (GTK_WIDGET (object));
|
||||
break;
|
||||
|
||||
case PROP_MIN_FILTER:
|
||||
self->min_filter = g_value_get_enum (value);
|
||||
gtk_widget_queue_resize (GTK_WIDGET (object));
|
||||
break;
|
||||
|
||||
case PROP_MAG_FILTER:
|
||||
self->mag_filter = g_value_get_enum (value);
|
||||
gtk_widget_queue_resize (GTK_WIDGET (object));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -140,14 +162,22 @@ demo3_widget_get_property (GObject *object,
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PAINTABLE:
|
||||
g_value_set_object (value, self->paintable);
|
||||
case PROP_TEXTURE:
|
||||
g_value_set_object (value, self->texture);
|
||||
break;
|
||||
|
||||
case PROP_SCALE:
|
||||
g_value_set_float (value, self->scale);
|
||||
break;
|
||||
|
||||
case PROP_MIN_FILTER:
|
||||
g_value_set_enum (value, self->min_filter);
|
||||
break;
|
||||
|
||||
case PROP_MAG_FILTER:
|
||||
g_value_set_enum (value, self->mag_filter);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -205,16 +235,26 @@ demo3_widget_class_init (Demo3WidgetClass *class)
|
||||
widget_class->measure = demo3_widget_measure;
|
||||
widget_class->size_allocate = demo3_widget_size_allocate;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_PAINTABLE,
|
||||
g_param_spec_object ("paintable", "Paintable", "Paintable",
|
||||
GDK_TYPE_PAINTABLE,
|
||||
g_object_class_install_property (object_class, PROP_TEXTURE,
|
||||
g_param_spec_object ("texture", NULL, NULL,
|
||||
GDK_TYPE_TEXTURE,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_SCALE,
|
||||
g_param_spec_float ("scale", "Scale", "Scale",
|
||||
g_param_spec_float ("scale", NULL, NULL,
|
||||
0.0, 10.0, 1.0,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_MIN_FILTER,
|
||||
g_param_spec_enum ("min-filter", NULL, NULL,
|
||||
GSK_TYPE_SCALING_FILTER, GSK_SCALING_FILTER_LINEAR,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_MAG_FILTER,
|
||||
g_param_spec_enum ("mag-filter", NULL, NULL,
|
||||
GSK_TYPE_SCALING_FILTER, GSK_SCALING_FILTER_LINEAR,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
/* These are the actions that we are using in the menu */
|
||||
gtk_widget_class_install_action (widget_class, "zoom.in", NULL, zoom_cb);
|
||||
gtk_widget_class_install_action (widget_class, "zoom.out", NULL, zoom_cb);
|
||||
@@ -229,16 +269,13 @@ GtkWidget *
|
||||
demo3_widget_new (const char *resource)
|
||||
{
|
||||
Demo3Widget *self;
|
||||
GdkPixbuf *pixbuf;
|
||||
GdkPaintable *paintable;
|
||||
GdkTexture *texture;
|
||||
|
||||
pixbuf = gdk_pixbuf_new_from_resource (resource, NULL);
|
||||
paintable = GDK_PAINTABLE (gdk_texture_new_for_pixbuf (pixbuf));
|
||||
texture = gdk_texture_new_from_resource (resource);
|
||||
|
||||
self = g_object_new (DEMO3_TYPE_WIDGET, "paintable", paintable, NULL);
|
||||
self = g_object_new (DEMO3_TYPE_WIDGET, "texture", texture, NULL);
|
||||
|
||||
g_object_unref (pixbuf);
|
||||
g_object_unref (paintable);
|
||||
g_object_unref (texture);
|
||||
|
||||
return GTK_WIDGET (self);
|
||||
}
|
||||
|
@@ -22,9 +22,11 @@ do_menu (GtkWidget *do_widget)
|
||||
if (!window)
|
||||
{
|
||||
GtkWidget *box;
|
||||
GtkWidget *box2;
|
||||
GtkWidget *sw;
|
||||
GtkWidget *widget;
|
||||
GtkWidget *scale;
|
||||
GtkWidget *dropdown;
|
||||
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Menu");
|
||||
@@ -43,10 +45,20 @@ do_menu (GtkWidget *do_widget)
|
||||
widget = demo3_widget_new ("/transparent/portland-rose.jpg");
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), widget);
|
||||
|
||||
box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
gtk_box_append (GTK_BOX (box), box2);
|
||||
|
||||
scale = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 0.01, 10.0, 0.1);
|
||||
gtk_range_set_value (GTK_RANGE (scale), 1.0);
|
||||
gtk_box_append (GTK_BOX (box), scale);
|
||||
gtk_widget_set_hexpand (scale, TRUE);
|
||||
gtk_box_append (GTK_BOX (box2), scale);
|
||||
|
||||
dropdown = gtk_drop_down_new (G_LIST_MODEL (gtk_string_list_new ((const char *[]){ "Linear", "Nearest", "Trilinear", NULL })), NULL);
|
||||
gtk_box_append (GTK_BOX (box2), dropdown);
|
||||
|
||||
g_object_bind_property (dropdown, "selected", widget, "min-filter", G_BINDING_DEFAULT);
|
||||
g_object_bind_property (dropdown, "selected", widget, "mag-filter", G_BINDING_DEFAULT);
|
||||
|
||||
g_object_bind_property (gtk_range_get_adjustment (GTK_RANGE (scale)), "value",
|
||||
widget, "scale",
|
||||
G_BINDING_BIDIRECTIONAL);
|
||||
|
@@ -1439,8 +1439,7 @@ gsk_gl_command_queue_upload_texture (GskGLCommandQueue *self,
|
||||
|
||||
g_assert (GSK_IS_GL_COMMAND_QUEUE (self));
|
||||
g_assert (!GDK_IS_GL_TEXTURE (texture));
|
||||
g_assert (min_filter == GL_LINEAR || min_filter == GL_NEAREST);
|
||||
g_assert (mag_filter == GL_LINEAR || min_filter == GL_NEAREST);
|
||||
g_assert (mag_filter == GL_LINEAR || mag_filter == GL_NEAREST);
|
||||
|
||||
width = gdk_texture_get_width (texture);
|
||||
height = gdk_texture_get_height (texture);
|
||||
@@ -1464,6 +1463,9 @@ gsk_gl_command_queue_upload_texture (GskGLCommandQueue *self,
|
||||
|
||||
gsk_gl_command_queue_do_upload_texture (self, texture);
|
||||
|
||||
if (min_filter == GL_LINEAR_MIPMAP_LINEAR)
|
||||
glGenerateMipmap (GL_TEXTURE_2D);
|
||||
|
||||
/* Restore previous texture state if any */
|
||||
if (self->attachments->textures[0].id > 0)
|
||||
glBindTexture (self->attachments->textures[0].target,
|
||||
|
@@ -3443,9 +3443,13 @@ gsk_gl_render_job_visit_gl_shader_node (GskGLRenderJob *job,
|
||||
static void
|
||||
gsk_gl_render_job_upload_texture (GskGLRenderJob *job,
|
||||
GdkTexture *texture,
|
||||
int min_filter,
|
||||
int mag_filter,
|
||||
GskGLRenderOffscreen *offscreen)
|
||||
{
|
||||
if (gsk_gl_texture_library_can_cache ((GskGLTextureLibrary *)job->driver->icons_library,
|
||||
if (min_filter == GL_LINEAR &&
|
||||
mag_filter == GL_LINEAR &&
|
||||
gsk_gl_texture_library_can_cache ((GskGLTextureLibrary *)job->driver->icons_library,
|
||||
texture->width,
|
||||
texture->height) &&
|
||||
!GDK_IS_GL_TEXTURE (texture))
|
||||
@@ -3458,7 +3462,7 @@ gsk_gl_render_job_upload_texture (GskGLRenderJob *job,
|
||||
}
|
||||
else
|
||||
{
|
||||
offscreen->texture_id = gsk_gl_driver_load_texture (job->driver, texture, GL_LINEAR, GL_LINEAR);
|
||||
offscreen->texture_id = gsk_gl_driver_load_texture (job->driver, texture, min_filter, mag_filter);
|
||||
init_full_texture_region (offscreen);
|
||||
}
|
||||
}
|
||||
@@ -3468,6 +3472,10 @@ gsk_gl_render_job_visit_texture_node (GskGLRenderJob *job,
|
||||
const GskRenderNode *node)
|
||||
{
|
||||
GdkTexture *texture = gsk_texture_node_get_texture (node);
|
||||
int min_filters[] = { GL_LINEAR, GL_NEAREST, GL_LINEAR_MIPMAP_LINEAR };
|
||||
int mag_filters[] = { GL_LINEAR, GL_NEAREST, GL_LINEAR };
|
||||
int min_filter = min_filters[gsk_texture_node_get_min_filter (node)];
|
||||
int mag_filter = mag_filters[gsk_texture_node_get_mag_filter (node)];
|
||||
int max_texture_size = job->command_queue->max_texture_size;
|
||||
|
||||
if G_LIKELY (texture->width <= max_texture_size &&
|
||||
@@ -3475,7 +3483,7 @@ gsk_gl_render_job_visit_texture_node (GskGLRenderJob *job,
|
||||
{
|
||||
GskGLRenderOffscreen offscreen = {0};
|
||||
|
||||
gsk_gl_render_job_upload_texture (job, texture, &offscreen);
|
||||
gsk_gl_render_job_upload_texture (job, texture, min_filter, mag_filter, &offscreen);
|
||||
|
||||
g_assert (offscreen.texture_id);
|
||||
g_assert (offscreen.was_offscreen == FALSE);
|
||||
@@ -3808,7 +3816,7 @@ gsk_gl_render_job_visit_node_with_offscreen (GskGLRenderJob *job,
|
||||
offscreen->force_offscreen == FALSE)
|
||||
{
|
||||
GdkTexture *texture = gsk_texture_node_get_texture (node);
|
||||
gsk_gl_render_job_upload_texture (job, texture, offscreen);
|
||||
gsk_gl_render_job_upload_texture (job, texture, GL_LINEAR, GL_LINEAR, offscreen);
|
||||
g_assert (offscreen->was_offscreen == FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
|
@@ -214,8 +214,18 @@ GType gsk_texture_node_get_type (void) G_GNUC_CO
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskRenderNode * gsk_texture_node_new (GdkTexture *texture,
|
||||
const graphene_rect_t *bounds);
|
||||
GDK_AVAILABLE_IN_4_10
|
||||
GskRenderNode * gsk_texture_node_new_with_filters (GdkTexture *texture,
|
||||
const graphene_rect_t *bounds,
|
||||
GskScalingFilter min_filter,
|
||||
GskScalingFilter mag_filter);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GdkTexture * gsk_texture_node_get_texture (const GskRenderNode *node) G_GNUC_PURE;
|
||||
GDK_AVAILABLE_IN_4_10
|
||||
GskScalingFilter gsk_texture_node_get_min_filter (const GskRenderNode *node);
|
||||
GDK_AVAILABLE_IN_4_10
|
||||
GskScalingFilter gsk_texture_node_get_mag_filter (const GskRenderNode *node);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gsk_linear_gradient_node_get_type (void) G_GNUC_CONST;
|
||||
|
@@ -1471,6 +1471,9 @@ struct _GskTextureNode
|
||||
GskRenderNode render_node;
|
||||
|
||||
GdkTexture *texture;
|
||||
|
||||
GskScalingFilter min_filter;
|
||||
GskScalingFilter mag_filter;
|
||||
};
|
||||
|
||||
static void
|
||||
@@ -1492,6 +1495,11 @@ gsk_texture_node_draw (GskRenderNode *node,
|
||||
cairo_surface_t *surface;
|
||||
cairo_pattern_t *pattern;
|
||||
cairo_matrix_t matrix;
|
||||
cairo_filter_t filters[] = {
|
||||
CAIRO_FILTER_BILINEAR,
|
||||
CAIRO_FILTER_NEAREST,
|
||||
CAIRO_FILTER_GOOD,
|
||||
};
|
||||
|
||||
surface = gdk_texture_download_surface (self->texture);
|
||||
pattern = cairo_pattern_create_for_surface (surface);
|
||||
@@ -1504,6 +1512,10 @@ gsk_texture_node_draw (GskRenderNode *node,
|
||||
-node->bounds.origin.x,
|
||||
-node->bounds.origin.y);
|
||||
cairo_pattern_set_matrix (pattern, &matrix);
|
||||
if (gdk_texture_get_width (self->texture) > node->bounds.size.width)
|
||||
cairo_pattern_set_filter (pattern, filters[self->min_filter]);
|
||||
else
|
||||
cairo_pattern_set_filter (pattern, filters[self->mag_filter]);
|
||||
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_pattern_destroy (pattern);
|
||||
@@ -1522,7 +1534,9 @@ gsk_texture_node_diff (GskRenderNode *node1,
|
||||
GskTextureNode *self2 = (GskTextureNode *) node2;
|
||||
|
||||
if (graphene_rect_equal (&node1->bounds, &node2->bounds) &&
|
||||
self1->texture == self2->texture)
|
||||
self1->texture == self2->texture &&
|
||||
self1->min_filter ==self2->min_filter &&
|
||||
self1->mag_filter ==self2->mag_filter)
|
||||
return;
|
||||
|
||||
gsk_render_node_diff_impossible (node1, node2, region);
|
||||
@@ -1544,6 +1558,38 @@ gsk_texture_node_get_texture (const GskRenderNode *node)
|
||||
return self->texture;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_texture_node_get_min_filter:
|
||||
* @node: (type GskTextureNode): a `GskRenderNode` of type %GSK_TEXTURE_NODE
|
||||
*
|
||||
* Retrieves the filter to apply when scaling the texture down.
|
||||
*
|
||||
* Since: 4.10
|
||||
*/
|
||||
GskScalingFilter
|
||||
gsk_texture_node_get_min_filter (const GskRenderNode *node)
|
||||
{
|
||||
const GskTextureNode *self = (const GskTextureNode *) node;
|
||||
|
||||
return self->min_filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_texture_node_get_mag_filter:
|
||||
* @node: (type GskTextureNode): a `GskRenderNode` of type %GSK_TEXTURE_NODE
|
||||
*
|
||||
* Retrieves the filter to apply when scaling the texture up.
|
||||
*
|
||||
* Since: 4.10
|
||||
*/
|
||||
GskScalingFilter
|
||||
gsk_texture_node_get_mag_filter (const GskRenderNode *node)
|
||||
{
|
||||
const GskTextureNode *self = (const GskTextureNode *) node;
|
||||
|
||||
return self->mag_filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_texture_node_new:
|
||||
* @texture: the `GdkTexture`
|
||||
@@ -1569,6 +1615,49 @@ gsk_texture_node_new (GdkTexture *texture,
|
||||
node->offscreen_for_opacity = FALSE;
|
||||
|
||||
self->texture = g_object_ref (texture);
|
||||
self->min_filter = GSK_SCALING_FILTER_LINEAR;
|
||||
self->mag_filter = GSK_SCALING_FILTER_LINEAR;
|
||||
graphene_rect_init_from_rect (&node->bounds, bounds);
|
||||
|
||||
node->prefers_high_depth = gdk_memory_format_prefers_high_depth (gdk_texture_get_format (texture));
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_texture_node_new_with_filters:
|
||||
* @texture: the `GdkTexture`
|
||||
* @bounds: the rectangle to render the texture into
|
||||
* @min_filter: filter to apply when scaling down
|
||||
* @mag_filter: filter to apply when scaling up
|
||||
*
|
||||
* Creates a `GskRenderNode` that will render the given
|
||||
* @texture into the area given by @bounds, using the
|
||||
* given filters when required.
|
||||
*
|
||||
* Returns: (transfer full) (type GskTextureNode): A new `GskRenderNode`
|
||||
*
|
||||
* Since: 4.10
|
||||
*/
|
||||
GskRenderNode *
|
||||
gsk_texture_node_new_with_filters (GdkTexture *texture,
|
||||
const graphene_rect_t *bounds,
|
||||
GskScalingFilter min_filter,
|
||||
GskScalingFilter mag_filter)
|
||||
{
|
||||
GskTextureNode *self;
|
||||
GskRenderNode *node;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_TEXTURE (texture), NULL);
|
||||
g_return_val_if_fail (bounds != NULL, NULL);
|
||||
|
||||
self = gsk_render_node_alloc (GSK_TEXTURE_NODE);
|
||||
node = (GskRenderNode *) self;
|
||||
node->offscreen_for_opacity = FALSE;
|
||||
|
||||
self->texture = g_object_ref (texture);
|
||||
self->min_filter = min_filter;
|
||||
self->mag_filter = mag_filter;
|
||||
graphene_rect_init_from_rect (&node->bounds, bounds);
|
||||
|
||||
node->prefers_high_depth = gdk_memory_format_prefers_high_depth (gdk_texture_get_format (texture));
|
||||
|
Reference in New Issue
Block a user