[gtk+/wip/ebassi/gsk: 4/11] gsk: Add GskRenderer
- From: Emmanuele Bassi <ebassi src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/ebassi/gsk: 4/11] gsk: Add GskRenderer
- Date: Sun, 9 Aug 2015 15:50:55 +0000 (UTC)
commit 3b86df47442214696954e73ece83833aac86e045
Author: Emmanuele Bassi <ebassi gnome org>
Date: Sun Mar 8 20:56:15 2015 +0000
gsk: Add GskRenderer
A class that traverses a GSK graph and renders its contents on a given
Cairo surface.
gsk/Makefile.am | 4 +-
gsk/gsk.h | 1 +
gsk/gskrenderer.c | 353 +++++++++++++++++++++++++++++++++++++++++++++++++++++
gsk/gskrenderer.h | 61 +++++++++
gsk/gsktypes.h | 1 +
5 files changed, 419 insertions(+), 1 deletions(-)
---
diff --git a/gsk/Makefile.am b/gsk/Makefile.am
index 4842d59..70d4489 100644
--- a/gsk/Makefile.am
+++ b/gsk/Makefile.am
@@ -42,6 +42,7 @@ gsk_public_source_h = \
gsklayer.h \
gsklayeriter.h \
gskmacros.h \
+ gskrenderer.h \
gsktypes.h
gsk_private_source_h = \
@@ -53,7 +54,8 @@ gsk_source_c = \
gskdebug.c \
gsklayer.c \
gsklayeriter.c \
- gsklayerstate.c
+ gsklayerstate.c \
+ gskrenderer.c
all_sources = $(gsk_private_source_c) $(gsk_source_c) $(gsk_public_source_h) $(gsk_private_source_h)
$(BUILT_SOURCES)
diff --git a/gsk/gsk.h b/gsk/gsk.h
index 850355a..f43461a 100644
--- a/gsk/gsk.h
+++ b/gsk/gsk.h
@@ -26,6 +26,7 @@
#include <gsk/gskdebug.h>
#include <gsk/gsklayer.h>
#include <gsk/gsklayeriter.h>
+#include <gsk/gskrenderer.h>
#undef __GSK_H_INSIDE__
diff --git a/gsk/gskrenderer.c b/gsk/gskrenderer.c
new file mode 100644
index 0000000..549ae4e
--- /dev/null
+++ b/gsk/gskrenderer.c
@@ -0,0 +1,353 @@
+/* GSK - The GTK scene graph toolkit
+ * Copyright 2015 Emmanuele Bassi
+ *
+ * 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.1 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * SECTION:gskrenderer
+ * @Short_description: Renders the scene graph
+ * @Title: GskRenderer
+ *
+ * #GskRenderer is used to render a #GskLayer scene on a #cairo_surface_t.
+ */
+
+#include "config.h"
+
+#include "gskrenderer.h"
+
+#include "gskdebug.h"
+#include "gsklayerprivate.h"
+
+#include <cairo.h>
+
+struct _GskRenderer
+{
+ GObject parent_instance;
+
+ GskLayer *root;
+
+ graphene_rect_t viewport;
+
+ graphene_matrix_t modelview;
+ graphene_matrix_t projection;
+ graphene_matrix_t mvp;
+
+ int scale_factor;
+
+ guint needs_matrix_update : 1;
+};
+
+struct _GskRendererClass
+{
+ GObjectClass parent_class;
+};
+
+G_DEFINE_TYPE (GskRenderer, gsk_renderer, G_TYPE_OBJECT)
+
+enum {
+ PROP_ROOT = 1,
+ N_PROPS
+};
+
+static GParamSpec *obj_props[N_PROPS];
+
+static void
+gsk_renderer_finalize (GObject *gobject)
+{
+ GskRenderer *self = GSK_RENDERER (gobject);
+
+ g_clear_object (&self->root);
+
+ G_OBJECT_CLASS (gsk_renderer_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_renderer_set_property (GObject *gobject,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GskRenderer *self = GSK_RENDERER (gobject);
+
+ switch (prop_id)
+ {
+ case PROP_ROOT:
+ self->root = g_value_dup_object (value);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void
+gsk_renderer_get_property (GObject *gobject,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GskRenderer *self = GSK_RENDERER (gobject);
+
+ switch (prop_id)
+ {
+ case PROP_ROOT:
+ g_value_set_object (value, self->root);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void
+gsk_renderer_class_init (GskRendererClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->set_property = gsk_renderer_set_property;
+ gobject_class->get_property = gsk_renderer_get_property;
+ gobject_class->finalize = gsk_renderer_finalize;
+
+ /**
+ * GskRenderer:root:
+ *
+ * The root #GskLayer to render. All descendants of the root layer
+ * will be traversed and rendered on the surface associated to the
+ * #GskRenderer instance.
+ *
+ * Since: 3.16
+ */
+ obj_props[PROP_ROOT] =
+ g_param_spec_object ("root", "Root", "Root layer to render",
+ GSK_TYPE_LAYER,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (gobject_class, N_PROPS, obj_props);
+}
+
+static void
+gsk_renderer_init (GskRenderer *self)
+{
+ graphene_matrix_init_identity (&self->modelview);
+ graphene_matrix_init_identity (&self->projection);
+ graphene_matrix_init_identity (&self->mvp);
+
+ self->scale_factor = 1;
+
+ self->needs_matrix_update = FALSE;
+}
+
+GskRenderer *
+gsk_renderer_new (GskLayer *root)
+{
+ g_return_val_if_fail (GSK_IS_LAYER (root), NULL);
+
+ return g_object_new (GSK_TYPE_RENDERER, "root", root, NULL);
+}
+
+void
+gsk_renderer_set_viewport (GskRenderer *renderer,
+ const graphene_rect_t *viewport)
+{
+ g_return_if_fail (GSK_IS_RENDERER (renderer));
+ g_return_if_fail (viewport != NULL);
+
+ graphene_rect_init_from_rect (&renderer->viewport, viewport);
+}
+
+void
+gsk_renderer_set_modelview (GskRenderer *renderer,
+ const graphene_matrix_t *modelview)
+{
+ g_return_if_fail (GSK_IS_RENDERER (renderer));
+ g_return_if_fail (modelview != NULL);
+
+ graphene_matrix_init_from_matrix (&renderer->modelview, modelview);
+
+ renderer->needs_matrix_update = TRUE;
+}
+
+void
+gsk_renderer_set_projection (GskRenderer *renderer,
+ const graphene_matrix_t *projection)
+{
+ g_return_if_fail (GSK_IS_RENDERER (renderer));
+ g_return_if_fail (projection != NULL);
+
+ graphene_matrix_init_from_matrix (&renderer->projection, projection);
+
+ renderer->needs_matrix_update = TRUE;
+}
+
+void
+gsk_renderer_set_scale_factor (GskRenderer *renderer,
+ int scale)
+{
+ g_return_if_fail (GSK_IS_RENDERER (renderer));
+ g_return_if_fail (scale > 0);
+
+ renderer->scale_factor = scale;
+}
+
+static void
+gsk_renderer_maybe_update_matrices (GskRenderer *renderer)
+{
+ if (!renderer->needs_matrix_update)
+ return;
+
+ graphene_matrix_multiply (&renderer->modelview,
+ &renderer->projection,
+ &renderer->mvp);
+}
+
+static void
+gsk_renderer_render_layer (GskRenderer *renderer,
+ GskLayer *layer,
+ cairo_t *cr)
+{
+ GskLayerState *state = gsk_layer_get_state (layer);
+ const GeometryInfo *ginfo;
+ const RenderInfo *rinfo;
+ graphene_rect_t frame, clip;
+ GskLayerIter iter;
+ GskLayer *child;
+ const graphene_matrix_t *mv;
+ graphene_point_t pivot;
+ cairo_matrix_t ctm;
+ cairo_matrix_t matrix;
+ guint8 opacity;
+
+ cairo_save (cr);
+
+ ginfo = gsk_layer_state_peek_geometry_info (state);
+ rinfo = gsk_layer_state_peek_render_info (state);
+ opacity = CLAMP (rinfo->opacity * 255, 0, 255);
+
+ if (opacity != 255)
+ {
+ GSK_NOTE (RENDER, g_print ("Pushing group for opacity of %.2f\n", rinfo->opacity));
+ cairo_push_group (cr);
+ }
+
+ gsk_layer_get_frame (layer, &frame);
+ GSK_NOTE (RENDER, g_print ("Rendering layer { %.2f, %.2f x %.2f - %.2f }\n",
+ frame.origin.x, frame.origin.y,
+ frame.size.width, frame.size.height));
+
+ pivot.x = ginfo->pivot_point.x * frame.size.width;
+ pivot.y = ginfo->pivot_point.y * frame.size.height;
+ cairo_matrix_init_translate (&matrix, frame.origin.x + pivot.x, frame.origin.y + pivot.y);
+
+ /* If the layer only has a 2D modelview we can just
+ * draw it on the current surface...
+ */
+ mv = gsk_layer_get_modelview (layer);
+ if (graphene_matrix_to_2d (mv,
+ &ctm.xx, &ctm.yx,
+ &ctm.xy, &ctm.yy,
+ &ctm.x0, &ctm.y0))
+ {
+ cairo_matrix_multiply (&matrix, &ctm, &matrix);
+ }
+ else
+ {
+ /* Otherwise we break up the draw; we take the layer, draw it
+ * it inside a separate surface, then use GL to render the
+ * surface use the modelview matrix; then we take the render
+ * buffer and draw it on top of the previous source.
+ */
+ g_printerr ("Not a 2D transformation\n");
+ }
+
+ cairo_matrix_translate (&matrix, -pivot.x, -pivot.y);
+
+ cairo_transform (cr, &matrix);
+
+ gsk_layer_get_clip (layer, &clip);
+ cairo_rectangle (cr, clip.origin.x, clip.origin.y, clip.size.width, clip.size.height);
+ cairo_clip (cr);
+
+ cairo_save (cr);
+ gsk_layer_draw (layer, cr);
+ cairo_restore (cr);
+
+ gsk_layer_iter_init (&iter, layer);
+ while (gsk_layer_iter_next (&iter, &child))
+ gsk_renderer_render_layer (renderer, child, cr);
+
+ if (opacity != 255)
+ {
+ cairo_pop_group_to_source (cr);
+ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+ cairo_paint_with_alpha (cr, rinfo->opacity);
+ }
+
+ cairo_restore (cr);
+
+#ifdef G_ENABLE_DEBUG
+ if (gsk_get_debug_flags () & GSK_DEBUG_GEOMETRY)
+ {
+ float x = frame.origin.x + pivot.x;
+ float y = frame.origin.y + pivot.y;
+
+ /* Draw the frame */
+ cairo_save (cr);
+ cairo_set_line_width (cr, 1.0);
+ cairo_set_source_rgba (cr, 1, 0, 0, 0.25);
+ cairo_rectangle (cr, frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
+ cairo_stroke (cr);
+
+ /* Draw the pivot point */
+ cairo_set_source_rgba (cr, 0, 0, 1, 0.25);
+ cairo_move_to (cr, x, y);
+ cairo_arc (cr, x, y, 3, 0, G_PI * 2);
+ cairo_fill (cr);
+ cairo_restore (cr);
+ }
+#endif /* G_ENABLE_DEBUG */
+}
+
+void
+gsk_renderer_render (GskRenderer *renderer,
+ cairo_t *cr,
+ int width,
+ int height)
+{
+ cairo_surface_t *surface;
+ cairo_t *inner_cr;
+
+ g_return_if_fail (GSK_IS_RENDERER (renderer));
+
+ surface = cairo_surface_create_similar (cairo_get_target (cr),
+ CAIRO_CONTENT_COLOR_ALPHA,
+ width, height);
+ inner_cr = cairo_create (surface);
+
+ gsk_renderer_maybe_update_matrices (renderer);
+ gsk_renderer_render_layer (renderer, renderer->root, inner_cr);
+
+ cairo_destroy (inner_cr);
+
+ cairo_save (cr);
+
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_paint (cr);
+
+ cairo_restore (cr);
+
+ cairo_surface_destroy (surface);
+}
diff --git a/gsk/gskrenderer.h b/gsk/gskrenderer.h
new file mode 100644
index 0000000..b5802ce
--- /dev/null
+++ b/gsk/gskrenderer.h
@@ -0,0 +1,61 @@
+/* GSK - The GTK scene graph toolkit
+ * Copyright 2015 Emmanuele Bassi
+ *
+ * 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.1 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GSK_RENDERER_H__
+#define __GSK_RENDERER_H__
+
+#if !defined (__GSK_H_INSIDE__) && !defined (GSK_COMPILATION)
+#error "Only <gsk/gsk.h> can be included directly."
+#endif
+
+#include <gsk/gsktypes.h>
+
+G_BEGIN_DECLS
+
+#define GSK_TYPE_RENDERER (gsk_renderer_get_type ())
+
+GDK_AVAILABLE_IN_3_18
+G_DECLARE_FINAL_TYPE (GskRenderer, gsk_renderer, GSK, RENDERER, GObject)
+
+GDK_AVAILABLE_IN_3_18
+GskRenderer * gsk_renderer_new (GskLayer *root);
+
+GDK_AVAILABLE_IN_3_18
+void gsk_renderer_set_modelview (GskRenderer *renderer,
+ const graphene_matrix_t *mv);
+GDK_AVAILABLE_IN_3_18
+void gsk_renderer_set_projection (GskRenderer *renderer,
+ const graphene_matrix_t *projection);
+GDK_AVAILABLE_IN_3_18
+void gsk_renderer_set_viewport (GskRenderer *renderer,
+ const graphene_rect_t *viewport);
+GDK_AVAILABLE_IN_3_18
+void gsk_renderer_set_clear_color (GskRenderer *renderer,
+ const GdkRGBA *color);
+GDK_AVAILABLE_IN_3_18
+void gsk_renderer_set_scale_factor (GskRenderer *renderer,
+ int factor);
+
+GDK_AVAILABLE_IN_3_18
+void gsk_renderer_render (GskRenderer *renderer,
+ cairo_t *cr,
+ int width,
+ int height);
+
+G_END_DECLS
+
+#endif /* __GSK_RENDERER_H__ */
diff --git a/gsk/gsktypes.h b/gsk/gsktypes.h
index 00eb701..d6143ad 100644
--- a/gsk/gsktypes.h
+++ b/gsk/gsktypes.h
@@ -31,6 +31,7 @@ G_BEGIN_DECLS
typedef struct _GskLayer GskLayer;
typedef struct _GskLayerIter GskLayerIter;
+typedef struct _GskRenderer GskRenderer;
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]