/* BlurEffect.c generated by valac 0.56.18-dirty, the Vala compiler
 * generated from BlurEffect.vala, do not modify */

/*
 * Copyright 2023 elementary, Inc. <https://elementary.io>
 * SPDX-License-Identifier: GPL-3.0-or-later
 */

#include <clutter/clutter.h>
#include <glib-object.h>
#include <glib.h>
#include <float.h>
#include <math.h>
#include <cogl/cogl.h>
#include <graphene-gobject.h>
#include <cairo-gobject.h>
#include <stdlib.h>
#include <string.h>

#define GALA_BLUR_EFFECT_MIN_DOWNSCALE_SIZE 256.0f
#define GALA_BLUR_EFFECT_MAX_RADIUS 12.0f
#if !defined(VALA_STRICT_C)
#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ >= 14)
#pragma GCC diagnostic warning "-Wincompatible-pointer-types"
#elif defined(__clang__) && (__clang_major__ >= 16)
#pragma clang diagnostic ignored "-Wincompatible-function-pointer-types"
#pragma clang diagnostic ignored "-Wincompatible-pointer-types"
#endif
#endif
#if !defined(VALA_EXTERN)
#if defined(_MSC_VER)
#define VALA_EXTERN __declspec(dllexport) extern
#elif __GNUC__ >= 4
#define VALA_EXTERN __attribute__((visibility("default"))) extern
#else
#define VALA_EXTERN extern
#endif
#endif

#define GALA_TYPE_BLUR_EFFECT (gala_blur_effect_get_type ())
#define GALA_BLUR_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GALA_TYPE_BLUR_EFFECT, GalaBlurEffect))
#define GALA_BLUR_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GALA_TYPE_BLUR_EFFECT, GalaBlurEffectClass))
#define GALA_IS_BLUR_EFFECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GALA_TYPE_BLUR_EFFECT))
#define GALA_IS_BLUR_EFFECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GALA_TYPE_BLUR_EFFECT))
#define GALA_BLUR_EFFECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GALA_TYPE_BLUR_EFFECT, GalaBlurEffectClass))

typedef struct _GalaBlurEffect GalaBlurEffect;
typedef struct _GalaBlurEffectClass GalaBlurEffectClass;
typedef struct _GalaBlurEffectPrivate GalaBlurEffectPrivate;
enum  {
	GALA_BLUR_EFFECT_0_PROPERTY,
	GALA_BLUR_EFFECT_ACTOR_PROPERTY,
	GALA_BLUR_EFFECT_RADIUS_PROPERTY,
	GALA_BLUR_EFFECT_NUM_PROPERTIES
};
static GParamSpec* gala_blur_effect_properties[GALA_BLUR_EFFECT_NUM_PROPERTIES];
#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL)))
#define _g_error_free0(var) ((var == NULL) ? NULL : (var = (g_error_free (var), NULL)))
#define _cairo_surface_destroy0(var) ((var == NULL) ? NULL : (var = (cairo_surface_destroy (var), NULL)))
#define _clutter_paint_node_unref0(var) ((var == NULL) ? NULL : (var = (clutter_paint_node_unref (var), NULL)))

struct _GalaBlurEffect {
	ClutterEffect parent_instance;
	GalaBlurEffectPrivate * priv;
};

struct _GalaBlurEffectClass {
	ClutterEffectClass parent_class;
};

struct _GalaBlurEffectPrivate {
	ClutterActor* _actor;
	gfloat _radius;
	gboolean actor_painted;
	gboolean blur_applied;
	gint texture_width;
	gint texture_height;
	gfloat downscale_factor;
	CoglFramebuffer* actor_framebuffer;
	CoglPipeline* actor_pipeline;
	CoglTexture* actor_texture;
	CoglFramebuffer* framebuffer;
	CoglPipeline* pipeline;
	CoglTexture* texture;
};

static gint GalaBlurEffect_private_offset;
static gpointer gala_blur_effect_parent_class = NULL;

VALA_EXTERN GType gala_blur_effect_get_type (void) G_GNUC_CONST ;
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GalaBlurEffect, g_object_unref)
VALA_EXTERN GalaBlurEffect* gala_blur_effect_new (ClutterActor* actor,
                                      gfloat radius);
VALA_EXTERN GalaBlurEffect* gala_blur_effect_construct (GType object_type,
                                            ClutterActor* actor,
                                            gfloat radius);
static gboolean gala_blur_effect_needs_repaint (GalaBlurEffect* self,
                                         ClutterEffectPaintFlags flags);
static void gala_blur_effect_update_actor_box (GalaBlurEffect* self,
                                        ClutterPaintContext* paint_context,
                                        ClutterActorBox* result);
VALA_EXTERN ClutterActor* gala_blur_effect_get_actor (GalaBlurEffect* self);
static gfloat gala_blur_effect_calculate_downscale_factor (GalaBlurEffect* self,
                                                    gfloat width,
                                                    gfloat height,
                                                    gfloat radius);
static void gala_blur_effect_setup_projection_matrix (GalaBlurEffect* self,
                                               CoglFramebuffer* framebuffer,
                                               gfloat width,
                                               gfloat height);
static gboolean gala_blur_effect_update_general_fbo (GalaBlurEffect* self,
                                              gint width,
                                              gint height,
                                              gfloat downscale_factor);
static gboolean gala_blur_effect_update_actor_fbo (GalaBlurEffect* self,
                                            gint width,
                                            gint height,
                                            gfloat downscale_factor);
static gboolean gala_blur_effect_update_framebuffers (GalaBlurEffect* self,
                                               ClutterPaintContext* paint_context,
                                               ClutterActorBox* actor_box);
VALA_EXTERN gfloat gala_blur_effect_get_radius (GalaBlurEffect* self);
static ClutterPaintNode* gala_blur_effect_create_blur_nodes (GalaBlurEffect* self,
                                                      ClutterPaintNode* node);
static void gala_blur_effect_paint_actor_offscreen (GalaBlurEffect* self,
                                             ClutterPaintNode* node,
                                             ClutterEffectPaintFlags flags);
static void gala_blur_effect_add_actor_node (GalaBlurEffect* self,
                                      ClutterPaintNode* node);
static void gala_blur_effect_add_blurred_pipeline (GalaBlurEffect* self,
                                            ClutterPaintNode* node);
static void gala_blur_effect_real_paint_node (ClutterEffect* base,
                                       ClutterPaintNode* node,
                                       ClutterPaintContext* paint_context,
                                       ClutterEffectPaintFlags flags);
static void gala_blur_effect_set_actor (GalaBlurEffect* self,
                                 ClutterActor* value);
static void gala_blur_effect_set_radius (GalaBlurEffect* self,
                                  gfloat value);
static GObject * gala_blur_effect_constructor (GType type,
                                        guint n_construct_properties,
                                        GObjectConstructParam * construct_properties);
static void gala_blur_effect_finalize (GObject * obj);
static GType gala_blur_effect_get_type_once (void);
static void _vala_gala_blur_effect_get_property (GObject * object,
                                          guint property_id,
                                          GValue * value,
                                          GParamSpec * pspec);
static void _vala_gala_blur_effect_set_property (GObject * object,
                                          guint property_id,
                                          const GValue * value,
                                          GParamSpec * pspec);

static inline gpointer
gala_blur_effect_get_instance_private (GalaBlurEffect* self)
{
	return G_STRUCT_MEMBER_P (self, GalaBlurEffect_private_offset);
}

GalaBlurEffect*
gala_blur_effect_construct (GType object_type,
                            ClutterActor* actor,
                            gfloat radius)
{
	GalaBlurEffect * self = NULL;
	g_return_val_if_fail (actor != NULL, NULL);
	self = (GalaBlurEffect*) g_object_new (object_type, "actor", actor, "radius", radius, NULL);
	return self;
}

GalaBlurEffect*
gala_blur_effect_new (ClutterActor* actor,
                      gfloat radius)
{
	return gala_blur_effect_construct (GALA_TYPE_BLUR_EFFECT, actor, radius);
}

static gboolean
gala_blur_effect_needs_repaint (GalaBlurEffect* self,
                                ClutterEffectPaintFlags flags)
{
	gboolean actor_dirty = FALSE;
	gboolean _tmp0_ = FALSE;
	gboolean _tmp1_ = FALSE;
	gboolean result;
	g_return_val_if_fail (self != NULL, FALSE);
	actor_dirty = (flags & CLUTTER_EFFECT_PAINT_ACTOR_DIRTY) != 0;
	if (actor_dirty) {
		_tmp1_ = TRUE;
	} else {
		_tmp1_ = !self->priv->blur_applied;
	}
	if (_tmp1_) {
		_tmp0_ = TRUE;
	} else {
		_tmp0_ = !self->priv->actor_painted;
	}
	result = _tmp0_;
	return result;
}

static void
gala_blur_effect_update_actor_box (GalaBlurEffect* self,
                                   ClutterPaintContext* paint_context,
                                   ClutterActorBox* result)
{
	ClutterActorBox actor_allocation_box = {0};
	ClutterActor* _tmp0_;
	ClutterActorBox _tmp1_ = {0};
	g_return_if_fail (self != NULL);
	g_return_if_fail (paint_context != NULL);
	_tmp0_ = self->priv->_actor;
	clutter_actor_get_allocation_box (_tmp0_, &_tmp1_);
	actor_allocation_box = _tmp1_;
	clutter_actor_box_clamp_to_pixel (&actor_allocation_box);
	*result = actor_allocation_box;
	return;
}

static gfloat
gala_blur_effect_calculate_downscale_factor (GalaBlurEffect* self,
                                             gfloat width,
                                             gfloat height,
                                             gfloat radius)
{
	gfloat downscale_factor = 0.0F;
	gfloat scaled_width = 0.0F;
	gfloat scaled_height = 0.0F;
	gfloat scaled_radius = 0.0F;
	gfloat result;
	g_return_val_if_fail (self != NULL, 0.0F);
	downscale_factor = 1.0f;
	scaled_width = width;
	scaled_height = height;
	scaled_radius = radius;
	while (TRUE) {
		gboolean _tmp0_ = FALSE;
		gboolean _tmp1_ = FALSE;
		if (scaled_radius > GALA_BLUR_EFFECT_MAX_RADIUS) {
			_tmp1_ = scaled_width > GALA_BLUR_EFFECT_MIN_DOWNSCALE_SIZE;
		} else {
			_tmp1_ = FALSE;
		}
		if (_tmp1_) {
			_tmp0_ = scaled_height > GALA_BLUR_EFFECT_MIN_DOWNSCALE_SIZE;
		} else {
			_tmp0_ = FALSE;
		}
		if (!_tmp0_) {
			break;
		}
		downscale_factor *= 2.0f;
		scaled_width = width / downscale_factor;
		scaled_height = height / downscale_factor;
		scaled_radius = radius / downscale_factor;
	}
	result = downscale_factor;
	return result;
}

static void
gala_blur_effect_setup_projection_matrix (GalaBlurEffect* self,
                                          CoglFramebuffer* framebuffer,
                                          gfloat width,
                                          gfloat height)
{
	graphene_matrix_t projection = {0};
	graphene_matrix_t _tmp0_ = {0};
	graphene_point3d_t _tmp1_ = {0};
	graphene_matrix_t _tmp2_;
	g_return_if_fail (self != NULL);
	g_return_if_fail (framebuffer != NULL);
	projection = _tmp0_;
	_tmp1_.x = (-width) / 2.0f;
	_tmp1_.y = (-height) / 2.0f;
	_tmp1_.z = 0.0f;
	graphene_matrix_init_translate (&projection, &_tmp1_);
	graphene_matrix_scale (&projection, 2.0f / width, (-2.0f) / height, 1.0f);
	_tmp2_ = projection;
	cogl_framebuffer_set_projection_matrix (framebuffer, &_tmp2_);
}

static gboolean
gala_blur_effect_update_general_fbo (GalaBlurEffect* self,
                                     gint width,
                                     gint height,
                                     gfloat downscale_factor)
{
	gboolean _tmp0_ = FALSE;
	gboolean _tmp1_ = FALSE;
	gboolean _tmp2_ = FALSE;
	CoglContext* ctx = NULL;
	ClutterBackend* _tmp4_;
	CoglContext* _tmp5_;
	gint new_width = 0;
	gint new_height = 0;
	cairo_surface_t* surface = NULL;
	cairo_surface_t* _tmp6_;
	CoglPipeline* _tmp17_;
	CoglTexture* _tmp18_;
	CoglTexture* _tmp19_;
	CoglOffscreen* _tmp20_;
	CoglFramebuffer* _tmp21_;
	GError* _inner_error0_ = NULL;
	gboolean result;
	g_return_val_if_fail (self != NULL, FALSE);
	if (self->priv->texture_width == width) {
		_tmp2_ = self->priv->texture_height == height;
	} else {
		_tmp2_ = FALSE;
	}
	if (_tmp2_) {
		_tmp1_ = self->priv->downscale_factor == downscale_factor;
	} else {
		_tmp1_ = FALSE;
	}
	if (_tmp1_) {
		CoglFramebuffer* _tmp3_;
		_tmp3_ = self->priv->framebuffer;
		_tmp0_ = _tmp3_ != NULL;
	} else {
		_tmp0_ = FALSE;
	}
	if (_tmp0_) {
		result = TRUE;
		return result;
	}
	_tmp4_ = clutter_get_default_backend ();
	_tmp5_ = clutter_backend_get_cogl_context (_tmp4_);
	ctx = _tmp5_;
	_g_object_unref0 (self->priv->framebuffer);
	self->priv->framebuffer = NULL;
	_g_object_unref0 (self->priv->texture);
	self->priv->texture = NULL;
	new_width = (gint) floorf (width / downscale_factor);
	new_height = (gint) floorf (height / downscale_factor);
	_tmp6_ = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, new_width, new_height);
	surface = _tmp6_;
	{
		CoglTexture2D* _tmp7_ = NULL;
		CoglContext* _tmp8_;
		cairo_surface_t* _tmp9_;
		cairo_surface_t* _tmp10_;
		guchar* _tmp11_;
		CoglTexture2D* _tmp12_;
		CoglTexture2D* _tmp13_;
		_tmp8_ = ctx;
		_tmp9_ = surface;
		_tmp10_ = surface;
		_tmp11_ = cairo_image_surface_get_data (_tmp10_);
		_tmp12_ = (CoglTexture2D*) cogl_texture_2d_new_from_data (_tmp8_, new_width, new_height, COGL_PIXEL_FORMAT_BGRA_8888_PRE, cairo_image_surface_get_stride (_tmp9_), _tmp11_, &_inner_error0_);
		_tmp7_ = _tmp12_;
		if (G_UNLIKELY (_inner_error0_ != NULL)) {
			goto __catch0_g_error;
		}
		_tmp13_ = _tmp7_;
		_tmp7_ = NULL;
		_g_object_unref0 (self->priv->texture);
		self->priv->texture = (CoglTexture*) _tmp13_;
		_g_object_unref0 (_tmp7_);
	}
	goto __finally0;
	__catch0_g_error:
	{
		GError* e = NULL;
		GError* _tmp14_;
		const gchar* _tmp15_;
		e = _inner_error0_;
		_inner_error0_ = NULL;
		_tmp14_ = e;
		_tmp15_ = _tmp14_->message;
		g_warning ("BlurEffect.vala:122: %s", _tmp15_);
		result = FALSE;
		_g_error_free0 (e);
		_cairo_surface_destroy0 (surface);
		return result;
	}
	__finally0:
	if (G_UNLIKELY (_inner_error0_ != NULL)) {
		gboolean _tmp16_ = FALSE;
		_cairo_surface_destroy0 (surface);
		g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error0_->message, g_quark_to_string (_inner_error0_->domain), _inner_error0_->code);
		g_clear_error (&_inner_error0_);
		return _tmp16_;
	}
	_tmp17_ = self->priv->pipeline;
	_tmp18_ = self->priv->texture;
	cogl_pipeline_set_layer_texture (_tmp17_, 0, _tmp18_);
	_tmp19_ = self->priv->texture;
	_tmp20_ = cogl_offscreen_new_with_texture (_tmp19_);
	_g_object_unref0 (self->priv->framebuffer);
	self->priv->framebuffer = (CoglFramebuffer*) _tmp20_;
	_tmp21_ = self->priv->framebuffer;
	gala_blur_effect_setup_projection_matrix (self, _tmp21_, (gfloat) new_width, (gfloat) new_height);
	result = TRUE;
	_cairo_surface_destroy0 (surface);
	return result;
}

static gboolean
gala_blur_effect_update_actor_fbo (GalaBlurEffect* self,
                                   gint width,
                                   gint height,
                                   gfloat downscale_factor)
{
	gboolean _tmp0_ = FALSE;
	gboolean _tmp1_ = FALSE;
	gboolean _tmp2_ = FALSE;
	CoglContext* ctx = NULL;
	ClutterBackend* _tmp4_;
	CoglContext* _tmp5_;
	gint new_width = 0;
	gint new_height = 0;
	cairo_surface_t* surface = NULL;
	cairo_surface_t* _tmp6_;
	CoglPipeline* _tmp17_;
	CoglTexture* _tmp18_;
	CoglTexture* _tmp19_;
	CoglOffscreen* _tmp20_;
	CoglFramebuffer* _tmp21_;
	GError* _inner_error0_ = NULL;
	gboolean result;
	g_return_val_if_fail (self != NULL, FALSE);
	if (self->priv->texture_width == width) {
		_tmp2_ = self->priv->texture_height == height;
	} else {
		_tmp2_ = FALSE;
	}
	if (_tmp2_) {
		_tmp1_ = self->priv->downscale_factor == downscale_factor;
	} else {
		_tmp1_ = FALSE;
	}
	if (_tmp1_) {
		CoglFramebuffer* _tmp3_;
		_tmp3_ = self->priv->actor_framebuffer;
		_tmp0_ = _tmp3_ != NULL;
	} else {
		_tmp0_ = FALSE;
	}
	if (_tmp0_) {
		result = TRUE;
		return result;
	}
	self->priv->actor_painted = FALSE;
	_tmp4_ = clutter_get_default_backend ();
	_tmp5_ = clutter_backend_get_cogl_context (_tmp4_);
	ctx = _tmp5_;
	_g_object_unref0 (self->priv->actor_framebuffer);
	self->priv->actor_framebuffer = NULL;
	_g_object_unref0 (self->priv->actor_texture);
	self->priv->actor_texture = NULL;
	new_width = (gint) floorf (width / downscale_factor);
	new_height = (gint) floorf (height / downscale_factor);
	_tmp6_ = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, new_width, new_height);
	surface = _tmp6_;
	{
		CoglTexture2D* _tmp7_ = NULL;
		CoglContext* _tmp8_;
		cairo_surface_t* _tmp9_;
		cairo_surface_t* _tmp10_;
		guchar* _tmp11_;
		CoglTexture2D* _tmp12_;
		CoglTexture2D* _tmp13_;
		_tmp8_ = ctx;
		_tmp9_ = surface;
		_tmp10_ = surface;
		_tmp11_ = cairo_image_surface_get_data (_tmp10_);
		_tmp12_ = (CoglTexture2D*) cogl_texture_2d_new_from_data (_tmp8_, new_width, new_height, COGL_PIXEL_FORMAT_BGRA_8888_PRE, cairo_image_surface_get_stride (_tmp9_), _tmp11_, &_inner_error0_);
		_tmp7_ = _tmp12_;
		if (G_UNLIKELY (_inner_error0_ != NULL)) {
			goto __catch0_g_error;
		}
		_tmp13_ = _tmp7_;
		_tmp7_ = NULL;
		_g_object_unref0 (self->priv->actor_texture);
		self->priv->actor_texture = (CoglTexture*) _tmp13_;
		_g_object_unref0 (_tmp7_);
	}
	goto __finally0;
	__catch0_g_error:
	{
		GError* e = NULL;
		GError* _tmp14_;
		const gchar* _tmp15_;
		e = _inner_error0_;
		_inner_error0_ = NULL;
		_tmp14_ = e;
		_tmp15_ = _tmp14_->message;
		g_warning ("BlurEffect.vala:164: %s", _tmp15_);
		result = FALSE;
		_g_error_free0 (e);
		_cairo_surface_destroy0 (surface);
		return result;
	}
	__finally0:
	if (G_UNLIKELY (_inner_error0_ != NULL)) {
		gboolean _tmp16_ = FALSE;
		_cairo_surface_destroy0 (surface);
		g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error0_->message, g_quark_to_string (_inner_error0_->domain), _inner_error0_->code);
		g_clear_error (&_inner_error0_);
		return _tmp16_;
	}
	_tmp17_ = self->priv->actor_pipeline;
	_tmp18_ = self->priv->actor_texture;
	cogl_pipeline_set_layer_texture (_tmp17_, 0, _tmp18_);
	_tmp19_ = self->priv->actor_texture;
	_tmp20_ = cogl_offscreen_new_with_texture (_tmp19_);
	_g_object_unref0 (self->priv->actor_framebuffer);
	self->priv->actor_framebuffer = G_TYPE_CHECK_INSTANCE_CAST (_tmp20_, cogl_framebuffer_get_type (), CoglFramebuffer);
	_tmp21_ = self->priv->actor_framebuffer;
	gala_blur_effect_setup_projection_matrix (self, _tmp21_, (gfloat) new_width, (gfloat) new_height);
	result = TRUE;
	_cairo_surface_destroy0 (surface);
	return result;
}

static gboolean
gala_blur_effect_update_framebuffers (GalaBlurEffect* self,
                                      ClutterPaintContext* paint_context,
                                      ClutterActorBox* actor_box)
{
	gint width = 0;
	gint height = 0;
	gfloat downscale_factor = 0.0F;
	gfloat _tmp0_;
	gboolean _tmp1_ = FALSE;
	gboolean updated = FALSE;
	gboolean result;
	g_return_val_if_fail (self != NULL, FALSE);
	g_return_val_if_fail (paint_context != NULL, FALSE);
	g_return_val_if_fail (actor_box != NULL, FALSE);
	width = (gint) clutter_actor_box_get_width (actor_box);
	height = (gint) clutter_actor_box_get_height (actor_box);
	_tmp0_ = self->priv->_radius;
	downscale_factor = gala_blur_effect_calculate_downscale_factor (self, (gfloat) width, (gfloat) height, _tmp0_);
	if (gala_blur_effect_update_actor_fbo (self, width, height, downscale_factor)) {
		_tmp1_ = gala_blur_effect_update_general_fbo (self, width, height, downscale_factor);
	} else {
		_tmp1_ = FALSE;
	}
	updated = _tmp1_;
	self->priv->texture_width = width;
	self->priv->texture_height = height;
	self->priv->downscale_factor = downscale_factor;
	result = updated;
	return result;
}

static ClutterPaintNode*
gala_blur_effect_create_blur_nodes (GalaBlurEffect* self,
                                    ClutterPaintNode* node)
{
	gfloat width = 0.0F;
	gfloat height = 0.0F;
	ClutterActor* _tmp0_;
	gfloat _tmp1_ = 0.0F;
	gfloat _tmp2_ = 0.0F;
	ClutterLayerNode* general_node = NULL;
	CoglFramebuffer* _tmp3_;
	CoglPipeline* _tmp4_;
	ClutterLayerNode* _tmp5_;
	ClutterActorBox _tmp6_ = {0};
	ClutterBlurNode* blur_node = NULL;
	gfloat _tmp7_;
	ClutterBlurNode* _tmp8_;
	CoglTexture* _tmp9_;
	CoglTexture* _tmp10_;
	ClutterActorBox _tmp11_ = {0};
	ClutterPaintNode* result;
	g_return_val_if_fail (self != NULL, NULL);
	g_return_val_if_fail (node != NULL, NULL);
	_tmp0_ = self->priv->_actor;
	clutter_actor_get_size (_tmp0_, &_tmp1_, &_tmp2_);
	width = _tmp1_;
	height = _tmp2_;
	_tmp3_ = self->priv->framebuffer;
	_tmp4_ = self->priv->pipeline;
	_tmp5_ = (ClutterLayerNode*) clutter_layer_node_new_to_framebuffer (_tmp3_, _tmp4_);
	general_node = _tmp5_;
	clutter_paint_node_add_child (node, (ClutterPaintNode*) general_node);
	_tmp6_.x1 = 0.0f;
	_tmp6_.y1 = 0.0f;
	_tmp6_.x2 = width;
	_tmp6_.y2 = height;
	clutter_paint_node_add_rectangle ((ClutterPaintNode*) general_node, &_tmp6_);
	_tmp7_ = self->priv->_radius;
	_tmp8_ = (ClutterBlurNode*) clutter_blur_node_new ((guint) (self->priv->texture_width / self->priv->downscale_factor), (guint) (self->priv->texture_height / self->priv->downscale_factor), _tmp7_ / self->priv->downscale_factor);
	blur_node = _tmp8_;
	clutter_paint_node_add_child ((ClutterPaintNode*) general_node, (ClutterPaintNode*) blur_node);
	_tmp9_ = self->priv->texture;
	_tmp10_ = self->priv->texture;
	_tmp11_.x1 = 0.0f;
	_tmp11_.y1 = 0.0f;
	_tmp11_.x2 = (gfloat) cogl_texture_get_width (_tmp9_);
	_tmp11_.y2 = (gfloat) cogl_texture_get_height (_tmp10_);
	clutter_paint_node_add_rectangle ((ClutterPaintNode*) blur_node, &_tmp11_);
	self->priv->blur_applied = TRUE;
	result = (ClutterPaintNode*) blur_node;
	_clutter_paint_node_unref0 (general_node);
	return result;
}

static void
gala_blur_effect_paint_actor_offscreen (GalaBlurEffect* self,
                                        ClutterPaintNode* node,
                                        ClutterEffectPaintFlags flags)
{
	gboolean actor_dirty = FALSE;
	gboolean _tmp0_ = FALSE;
	g_return_if_fail (self != NULL);
	g_return_if_fail (node != NULL);
	actor_dirty = (flags & CLUTTER_EFFECT_PAINT_ACTOR_DIRTY) != 0;
	if (actor_dirty) {
		_tmp0_ = TRUE;
	} else {
		_tmp0_ = !self->priv->actor_painted;
	}
	if (_tmp0_) {
		ClutterLayerNode* layer_node = NULL;
		CoglFramebuffer* _tmp1_;
		CoglPipeline* _tmp2_;
		ClutterLayerNode* _tmp3_;
		ClutterLayerNode* _tmp4_;
		ClutterLayerNode* _tmp5_;
		ClutterActorBox _tmp6_ = {0};
		graphene_matrix_t transform = {0};
		graphene_matrix_t _tmp7_ = {0};
		ClutterTransformNode* transform_node = NULL;
		graphene_matrix_t _tmp8_;
		ClutterTransformNode* _tmp9_;
		ClutterLayerNode* _tmp10_;
		ClutterTransformNode* _tmp11_;
		ClutterTransformNode* _tmp12_;
		_tmp1_ = self->priv->actor_framebuffer;
		_tmp2_ = self->priv->actor_pipeline;
		_tmp3_ = (ClutterLayerNode*) clutter_layer_node_new_to_framebuffer (_tmp1_, _tmp2_);
		layer_node = _tmp3_;
		_tmp4_ = layer_node;
		clutter_paint_node_add_child (node, (ClutterPaintNode*) _tmp4_);
		_tmp5_ = layer_node;
		_tmp6_.x1 = 0.0f;
		_tmp6_.y1 = 0.0f;
		_tmp6_.x2 = self->priv->texture_width / self->priv->downscale_factor;
		_tmp6_.y2 = self->priv->texture_height / self->priv->downscale_factor;
		clutter_paint_node_add_rectangle ((ClutterPaintNode*) _tmp5_, &_tmp6_);
		transform = _tmp7_;
		graphene_matrix_init_scale (&transform, 1.0f / self->priv->downscale_factor, 1.0f / self->priv->downscale_factor, 1.0f);
		_tmp8_ = transform;
		_tmp9_ = (ClutterTransformNode*) clutter_transform_node_new (&_tmp8_);
		transform_node = _tmp9_;
		_tmp10_ = layer_node;
		_tmp11_ = transform_node;
		clutter_paint_node_add_child ((ClutterPaintNode*) _tmp10_, (ClutterPaintNode*) _tmp11_);
		_tmp12_ = transform_node;
		gala_blur_effect_add_actor_node (self, (ClutterPaintNode*) _tmp12_);
		self->priv->actor_painted = TRUE;
		_clutter_paint_node_unref0 (transform_node);
		_clutter_paint_node_unref0 (layer_node);
	} else {
		ClutterPaintNode* pipeline_node = NULL;
		CoglPipeline* _tmp13_;
		ClutterPipelineNode* _tmp14_;
		ClutterPaintNode* _tmp15_;
		ClutterPaintNode* _tmp16_;
		ClutterActorBox _tmp17_ = {0};
		pipeline_node = NULL;
		_tmp13_ = self->priv->actor_pipeline;
		_tmp14_ = (ClutterPipelineNode*) clutter_pipeline_node_new (_tmp13_);
		_clutter_paint_node_unref0 (pipeline_node);
		pipeline_node = (ClutterPaintNode*) _tmp14_;
		_tmp15_ = pipeline_node;
		clutter_paint_node_add_child (node, _tmp15_);
		_tmp16_ = pipeline_node;
		_tmp17_.x1 = 0.0f;
		_tmp17_.y1 = 0.0f;
		_tmp17_.x2 = self->priv->texture_width / self->priv->downscale_factor;
		_tmp17_.y2 = self->priv->texture_height / self->priv->downscale_factor;
		clutter_paint_node_add_rectangle (_tmp16_, &_tmp17_);
		_clutter_paint_node_unref0 (pipeline_node);
	}
}

static void
gala_blur_effect_add_actor_node (GalaBlurEffect* self,
                                 ClutterPaintNode* node)
{
	ClutterActorNode* actor_node = NULL;
	ClutterActor* _tmp0_;
	ClutterActorNode* _tmp1_;
	g_return_if_fail (self != NULL);
	g_return_if_fail (node != NULL);
	_tmp0_ = self->priv->_actor;
	_tmp1_ = (ClutterActorNode*) clutter_actor_node_new (_tmp0_, 255);
	actor_node = _tmp1_;
	clutter_paint_node_add_child (node, (ClutterPaintNode*) actor_node);
	_clutter_paint_node_unref0 (actor_node);
}

static void
gala_blur_effect_add_blurred_pipeline (GalaBlurEffect* self,
                                       ClutterPaintNode* node)
{
	ClutterPaintNode* pipeline_node = NULL;
	gfloat width = 0.0F;
	gfloat height = 0.0F;
	ClutterActor* _tmp0_;
	gfloat _tmp1_ = 0.0F;
	gfloat _tmp2_ = 0.0F;
	CoglPipeline* _tmp3_;
	ClutterPipelineNode* _tmp4_;
	ClutterPaintNode* _tmp5_;
	ClutterPaintNode* _tmp6_;
	ClutterActorBox _tmp7_ = {0};
	g_return_if_fail (self != NULL);
	g_return_if_fail (node != NULL);
	pipeline_node = NULL;
	_tmp0_ = self->priv->_actor;
	clutter_actor_get_size (_tmp0_, &_tmp1_, &_tmp2_);
	width = _tmp1_;
	height = _tmp2_;
	_tmp3_ = self->priv->pipeline;
	_tmp4_ = (ClutterPipelineNode*) clutter_pipeline_node_new (_tmp3_);
	_clutter_paint_node_unref0 (pipeline_node);
	pipeline_node = (ClutterPaintNode*) _tmp4_;
	_tmp5_ = pipeline_node;
	clutter_paint_node_add_child (node, _tmp5_);
	_tmp6_ = pipeline_node;
	_tmp7_.x1 = 0.0f;
	_tmp7_.y1 = 0.0f;
	_tmp7_.x2 = width;
	_tmp7_.y2 = height;
	clutter_paint_node_add_rectangle (_tmp6_, &_tmp7_);
	_clutter_paint_node_unref0 (pipeline_node);
}

static void
gala_blur_effect_real_paint_node (ClutterEffect* base,
                                  ClutterPaintNode* node,
                                  ClutterPaintContext* paint_context,
                                  ClutterEffectPaintFlags flags)
{
	GalaBlurEffect * self;
	gfloat _tmp0_;
	self = (GalaBlurEffect*) base;
	g_return_if_fail (node != NULL);
	g_return_if_fail (paint_context != NULL);
	_tmp0_ = self->priv->_radius;
	if (_tmp0_ <= ((gfloat) 0)) {
		gala_blur_effect_add_actor_node (self, node);
		return;
	}
	if (gala_blur_effect_needs_repaint (self, flags)) {
		ClutterActorBox actor_box = {0};
		ClutterActorBox _tmp1_ = {0};
		ClutterActorBox _tmp2_;
		ClutterPaintNode* blur_node = NULL;
		ClutterPaintNode* _tmp3_;
		ClutterPaintNode* _tmp4_;
		gala_blur_effect_update_actor_box (self, paint_context, &_tmp1_);
		actor_box = _tmp1_;
		_tmp2_ = actor_box;
		if (!gala_blur_effect_update_framebuffers (self, paint_context, &_tmp2_)) {
			gala_blur_effect_add_actor_node (self, node);
			return;
		}
		_tmp3_ = gala_blur_effect_create_blur_nodes (self, node);
		blur_node = _tmp3_;
		_tmp4_ = blur_node;
		gala_blur_effect_paint_actor_offscreen (self, _tmp4_, flags);
		_clutter_paint_node_unref0 (blur_node);
	} else {
		gala_blur_effect_add_blurred_pipeline (self, node);
	}
}

ClutterActor*
gala_blur_effect_get_actor (GalaBlurEffect* self)
{
	ClutterActor* result;
	ClutterActor* _tmp0_;
	g_return_val_if_fail (self != NULL, NULL);
	_tmp0_ = self->priv->_actor;
	result = _tmp0_;
	return result;
}

static gpointer
_g_object_ref0 (gpointer self)
{
	return self ? g_object_ref (self) : NULL;
}

static void
gala_blur_effect_set_actor (GalaBlurEffect* self,
                            ClutterActor* value)
{
	ClutterActor* old_value;
	g_return_if_fail (self != NULL);
	old_value = gala_blur_effect_get_actor (self);
	if (old_value != value) {
		ClutterActor* _tmp0_;
		_tmp0_ = _g_object_ref0 (value);
		_g_object_unref0 (self->priv->_actor);
		self->priv->_actor = _tmp0_;
		g_object_notify_by_pspec ((GObject *) self, gala_blur_effect_properties[GALA_BLUR_EFFECT_ACTOR_PROPERTY]);
	}
}

gfloat
gala_blur_effect_get_radius (GalaBlurEffect* self)
{
	gfloat result;
	g_return_val_if_fail (self != NULL, 0.0F);
	result = self->priv->_radius;
	return result;
}

static void
gala_blur_effect_set_radius (GalaBlurEffect* self,
                             gfloat value)
{
	gfloat old_value;
	g_return_if_fail (self != NULL);
	old_value = gala_blur_effect_get_radius (self);
	if (old_value != value) {
		self->priv->_radius = value;
		g_object_notify_by_pspec ((GObject *) self, gala_blur_effect_properties[GALA_BLUR_EFFECT_RADIUS_PROPERTY]);
	}
}

static GObject *
gala_blur_effect_constructor (GType type,
                              guint n_construct_properties,
                              GObjectConstructParam * construct_properties)
{
	GObject * obj;
	GObjectClass * parent_class;
	GalaBlurEffect * self;
	CoglContext* ctx = NULL;
	ClutterBackend* _tmp0_;
	CoglContext* _tmp1_;
	CoglContext* _tmp2_;
	CoglPipeline* _tmp3_;
	CoglPipeline* _tmp4_;
	CoglPipeline* _tmp5_;
	CoglPipeline* _tmp6_;
	CoglContext* _tmp7_;
	CoglPipeline* _tmp8_;
	CoglPipeline* _tmp9_;
	CoglPipeline* _tmp10_;
	CoglPipeline* _tmp11_;
	parent_class = G_OBJECT_CLASS (gala_blur_effect_parent_class);
	obj = parent_class->constructor (type, n_construct_properties, construct_properties);
	self = G_TYPE_CHECK_INSTANCE_CAST (obj, GALA_TYPE_BLUR_EFFECT, GalaBlurEffect);
	_tmp0_ = clutter_get_default_backend ();
	_tmp1_ = clutter_backend_get_cogl_context (_tmp0_);
	ctx = _tmp1_;
	_tmp2_ = ctx;
	_tmp3_ = cogl_pipeline_new (_tmp2_);
	_g_object_unref0 (self->priv->actor_pipeline);
	self->priv->actor_pipeline = _tmp3_;
	_tmp4_ = self->priv->actor_pipeline;
	cogl_pipeline_set_layer_null_texture (_tmp4_, 0);
	_tmp5_ = self->priv->actor_pipeline;
	cogl_pipeline_set_layer_filters (_tmp5_, 0, COGL_PIPELINE_FILTER_LINEAR, COGL_PIPELINE_FILTER_LINEAR);
	_tmp6_ = self->priv->actor_pipeline;
	cogl_pipeline_set_layer_wrap_mode (_tmp6_, 0, COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
	_tmp7_ = ctx;
	_tmp8_ = cogl_pipeline_new (_tmp7_);
	_g_object_unref0 (self->priv->pipeline);
	self->priv->pipeline = _tmp8_;
	_tmp9_ = self->priv->pipeline;
	cogl_pipeline_set_layer_null_texture (_tmp9_, 0);
	_tmp10_ = self->priv->pipeline;
	cogl_pipeline_set_layer_filters (_tmp10_, 0, COGL_PIPELINE_FILTER_LINEAR, COGL_PIPELINE_FILTER_LINEAR);
	_tmp11_ = self->priv->pipeline;
	cogl_pipeline_set_layer_wrap_mode (_tmp11_, 0, COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
	return obj;
}

static void
gala_blur_effect_class_init (GalaBlurEffectClass * klass,
                             gpointer klass_data)
{
	gala_blur_effect_parent_class = g_type_class_peek_parent (klass);
	g_type_class_adjust_private_offset (klass, &GalaBlurEffect_private_offset);
	((ClutterEffectClass *) klass)->paint_node = (void (*) (ClutterEffect*, ClutterPaintNode*, ClutterPaintContext*, ClutterEffectPaintFlags)) gala_blur_effect_real_paint_node;
	G_OBJECT_CLASS (klass)->get_property = _vala_gala_blur_effect_get_property;
	G_OBJECT_CLASS (klass)->set_property = _vala_gala_blur_effect_set_property;
	G_OBJECT_CLASS (klass)->constructor = gala_blur_effect_constructor;
	G_OBJECT_CLASS (klass)->finalize = gala_blur_effect_finalize;
	g_object_class_install_property (G_OBJECT_CLASS (klass), GALA_BLUR_EFFECT_ACTOR_PROPERTY, gala_blur_effect_properties[GALA_BLUR_EFFECT_ACTOR_PROPERTY] = g_param_spec_object ("actor", "actor", "actor", clutter_actor_get_type (), G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
	g_object_class_install_property (G_OBJECT_CLASS (klass), GALA_BLUR_EFFECT_RADIUS_PROPERTY, gala_blur_effect_properties[GALA_BLUR_EFFECT_RADIUS_PROPERTY] = g_param_spec_float ("radius", "radius", "radius", -G_MAXFLOAT, G_MAXFLOAT, 0.0F, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
}

static void
gala_blur_effect_instance_init (GalaBlurEffect * self,
                                gpointer klass)
{
	self->priv = gala_blur_effect_get_instance_private (self);
	self->priv->actor_painted = FALSE;
	self->priv->blur_applied = FALSE;
}

static void
gala_blur_effect_finalize (GObject * obj)
{
	GalaBlurEffect * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (obj, GALA_TYPE_BLUR_EFFECT, GalaBlurEffect);
	_g_object_unref0 (self->priv->_actor);
	_g_object_unref0 (self->priv->actor_framebuffer);
	_g_object_unref0 (self->priv->actor_pipeline);
	_g_object_unref0 (self->priv->actor_texture);
	_g_object_unref0 (self->priv->framebuffer);
	_g_object_unref0 (self->priv->pipeline);
	_g_object_unref0 (self->priv->texture);
	G_OBJECT_CLASS (gala_blur_effect_parent_class)->finalize (obj);
}

 G_GNUC_NO_INLINE static GType
gala_blur_effect_get_type_once (void)
{
	static const GTypeInfo g_define_type_info = { sizeof (GalaBlurEffectClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) gala_blur_effect_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (GalaBlurEffect), 0, (GInstanceInitFunc) gala_blur_effect_instance_init, NULL };
	GType gala_blur_effect_type_id;
	gala_blur_effect_type_id = g_type_register_static (clutter_effect_get_type (), "GalaBlurEffect", &g_define_type_info, 0);
	GalaBlurEffect_private_offset = g_type_add_instance_private (gala_blur_effect_type_id, sizeof (GalaBlurEffectPrivate));
	return gala_blur_effect_type_id;
}

GType
gala_blur_effect_get_type (void)
{
	static gsize gala_blur_effect_type_id__once = 0;
	if (g_once_init_enter (&gala_blur_effect_type_id__once)) {
		GType gala_blur_effect_type_id;
		gala_blur_effect_type_id = gala_blur_effect_get_type_once ();
		g_once_init_leave (&gala_blur_effect_type_id__once, gala_blur_effect_type_id);
	}
	return gala_blur_effect_type_id__once;
}

static void
_vala_gala_blur_effect_get_property (GObject * object,
                                     guint property_id,
                                     GValue * value,
                                     GParamSpec * pspec)
{
	GalaBlurEffect * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (object, GALA_TYPE_BLUR_EFFECT, GalaBlurEffect);
	switch (property_id) {
		case GALA_BLUR_EFFECT_ACTOR_PROPERTY:
		g_value_set_object (value, gala_blur_effect_get_actor (self));
		break;
		case GALA_BLUR_EFFECT_RADIUS_PROPERTY:
		g_value_set_float (value, gala_blur_effect_get_radius (self));
		break;
		default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
		break;
	}
}

static void
_vala_gala_blur_effect_set_property (GObject * object,
                                     guint property_id,
                                     const GValue * value,
                                     GParamSpec * pspec)
{
	GalaBlurEffect * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (object, GALA_TYPE_BLUR_EFFECT, GalaBlurEffect);
	switch (property_id) {
		case GALA_BLUR_EFFECT_ACTOR_PROPERTY:
		gala_blur_effect_set_actor (self, g_value_get_object (value));
		break;
		case GALA_BLUR_EFFECT_RADIUS_PROPERTY:
		gala_blur_effect_set_radius (self, g_value_get_float (value));
		break;
		default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
		break;
	}
}

