Blame src/shell-glsl-quad.c

Packit d345d1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
Packit d345d1
Packit d345d1
/**
Packit d345d1
 * SECTION:shell-glsl-quad
Packit d345d1
 * @short_description: Draw a rectangle using GLSL
Packit d345d1
 *
Packit d345d1
 * A #ShellGLSLQuad draws one single rectangle, sized to the allocation
Packit d345d1
 * box, but allows running custom GLSL to the vertex and fragment
Packit d345d1
 * stages of the graphic pipeline.
Packit d345d1
 *
Packit d345d1
 * To ease writing the shader, a single texture layer is also used.
Packit d345d1
 */
Packit d345d1
Packit d345d1
#include "config.h"
Packit d345d1
Packit d345d1
#include <cogl/cogl.h>
Packit d345d1
#include "shell-glsl-quad.h"
Packit d345d1
Packit d345d1
typedef struct _ShellGLSLQuadPrivate ShellGLSLQuadPrivate;
Packit d345d1
struct _ShellGLSLQuadPrivate
Packit d345d1
{
Packit d345d1
  CoglPipeline  *pipeline;
Packit d345d1
};
Packit d345d1
Packit d345d1
G_DEFINE_TYPE_WITH_PRIVATE (ShellGLSLQuad, shell_glsl_quad, CLUTTER_TYPE_ACTOR);
Packit d345d1
Packit d345d1
static gboolean
Packit d345d1
shell_glsl_quad_get_paint_volume (ClutterActor       *actor,
Packit d345d1
                                  ClutterPaintVolume *volume)
Packit d345d1
{
Packit d345d1
  return clutter_paint_volume_set_from_allocation (volume, actor);
Packit d345d1
}
Packit d345d1
Packit d345d1
static void
Packit d345d1
shell_glsl_quad_paint (ClutterActor *actor)
Packit d345d1
{
Packit d345d1
  ShellGLSLQuad *self = SHELL_GLSL_QUAD (actor);
Packit d345d1
  ShellGLSLQuadPrivate *priv;
Packit d345d1
  guint8 paint_opacity;
Packit d345d1
  ClutterActorBox box;
Packit d345d1
Packit d345d1
  priv = shell_glsl_quad_get_instance_private (self);
Packit d345d1
Packit d345d1
  paint_opacity = clutter_actor_get_paint_opacity (actor);
Packit d345d1
  clutter_actor_get_allocation_box (actor, &box);
Packit d345d1
Packit d345d1
  cogl_pipeline_set_color4ub (priv->pipeline,
Packit d345d1
                              paint_opacity,
Packit d345d1
                              paint_opacity,
Packit d345d1
                              paint_opacity,
Packit d345d1
                              paint_opacity);
Packit d345d1
  cogl_framebuffer_draw_rectangle (cogl_get_draw_framebuffer (),
Packit d345d1
                                   priv->pipeline,
Packit d345d1
                                   box.x1, box.y1,
Packit d345d1
                                   box.x2, box.y2);
Packit d345d1
}
Packit d345d1
Packit d345d1
Packit d345d1
/**
Packit d345d1
 * shell_glsl_quad_add_glsl_snippet:
Packit d345d1
 * @quad: a #ShellGLSLQuad
Packit d345d1
 * @hook: where to insert the code
Packit d345d1
 * @declarations: GLSL declarations
Packit d345d1
 * @code: GLSL code
Packit d345d1
 * @is_replace: wheter Cogl code should be replaced by the custom shader
Packit d345d1
 *
Packit d345d1
 * Adds a GLSL snippet to the pipeline used for drawing the actor texture.
Packit d345d1
 * See #CoglSnippet for details.
Packit d345d1
 *
Packit d345d1
 * This is only valid inside the a call to the build_pipeline() virtual
Packit d345d1
 * function.
Packit d345d1
 */
Packit d345d1
void
Packit d345d1
shell_glsl_quad_add_glsl_snippet (ShellGLSLQuad    *quad,
Packit d345d1
                                  ShellSnippetHook  hook,
Packit d345d1
                                  const char       *declarations,
Packit d345d1
                                  const char       *code,
Packit d345d1
                                  gboolean          is_replace)
Packit d345d1
{
Packit d345d1
  ShellGLSLQuadClass *klass = SHELL_GLSL_QUAD_GET_CLASS (quad);
Packit d345d1
  CoglSnippet *snippet;
Packit d345d1
Packit d345d1
  g_return_if_fail (klass->base_pipeline != NULL);
Packit d345d1
Packit d345d1
  if (is_replace)
Packit d345d1
    {
Packit d345d1
      snippet = cogl_snippet_new ((CoglSnippetHook)hook, declarations, NULL);
Packit d345d1
      cogl_snippet_set_replace (snippet, code);
Packit d345d1
    }
Packit d345d1
  else
Packit d345d1
    {
Packit d345d1
      snippet = cogl_snippet_new ((CoglSnippetHook)hook, declarations, code);
Packit d345d1
    }
Packit d345d1
Packit d345d1
  if (hook == SHELL_SNIPPET_HOOK_VERTEX ||
Packit d345d1
      hook == SHELL_SNIPPET_HOOK_FRAGMENT)
Packit d345d1
    cogl_pipeline_add_snippet (klass->base_pipeline, snippet);
Packit d345d1
  else
Packit d345d1
    cogl_pipeline_add_layer_snippet (klass->base_pipeline, 0, snippet);
Packit d345d1
Packit d345d1
  cogl_object_unref (snippet);
Packit d345d1
}
Packit d345d1
Packit d345d1
static void
Packit d345d1
shell_glsl_quad_dispose (GObject *gobject)
Packit d345d1
{
Packit d345d1
  ShellGLSLQuad *self = SHELL_GLSL_QUAD (gobject);
Packit d345d1
  ShellGLSLQuadPrivate *priv;
Packit d345d1
Packit d345d1
  priv = shell_glsl_quad_get_instance_private (self);
Packit d345d1
Packit d345d1
  g_clear_pointer (&priv->pipeline, cogl_object_unref);
Packit d345d1
Packit d345d1
  G_OBJECT_CLASS (shell_glsl_quad_parent_class)->dispose (gobject);
Packit d345d1
}
Packit d345d1
Packit d345d1
static void
Packit d345d1
shell_glsl_quad_init (ShellGLSLQuad *quad)
Packit d345d1
{
Packit d345d1
}
Packit d345d1
Packit d345d1
static void
Packit d345d1
shell_glsl_quad_constructed (GObject *object)
Packit d345d1
{
Packit d345d1
  ShellGLSLQuad *self;
Packit d345d1
  ShellGLSLQuadClass *klass;
Packit d345d1
  ShellGLSLQuadPrivate *priv;
Packit d345d1
  CoglContext *ctx =
Packit d345d1
    clutter_backend_get_cogl_context (clutter_get_default_backend ());
Packit d345d1
Packit d345d1
  G_OBJECT_CLASS (shell_glsl_quad_parent_class)->constructed (object);
Packit d345d1
Packit d345d1
  /* Note that, differently from ClutterBlurEffect, we are calling
Packit d345d1
     this inside constructed, not init, so klass points to the most-derived
Packit d345d1
     GTypeClass, not ShellGLSLQuadClass.
Packit d345d1
  */
Packit d345d1
  klass = SHELL_GLSL_QUAD_GET_CLASS (object);
Packit d345d1
  self = SHELL_GLSL_QUAD (object);
Packit d345d1
  priv = shell_glsl_quad_get_instance_private (self);
Packit d345d1
Packit d345d1
  if (G_UNLIKELY (klass->base_pipeline == NULL))
Packit d345d1
    {
Packit d345d1
      klass->base_pipeline = cogl_pipeline_new (ctx);
Packit d345d1
      cogl_pipeline_set_blend (klass->base_pipeline, "RGBA = ADD (SRC_COLOR * (SRC_COLOR[A]), DST_COLOR * (1-SRC_COLOR[A]))", NULL);
Packit d345d1
Packit d345d1
      if (klass->build_pipeline != NULL)
Packit d345d1
        klass->build_pipeline (self);
Packit d345d1
    }
Packit d345d1
Packit d345d1
  priv->pipeline = cogl_pipeline_copy (klass->base_pipeline);
Packit d345d1
Packit d345d1
  cogl_pipeline_set_layer_null_texture (priv->pipeline, 0, COGL_TEXTURE_TYPE_2D);
Packit d345d1
}
Packit d345d1
Packit d345d1
static void
Packit d345d1
shell_glsl_quad_class_init (ShellGLSLQuadClass *klass)
Packit d345d1
{
Packit d345d1
  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
Packit d345d1
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
Packit d345d1
Packit d345d1
  gobject_class->constructed = shell_glsl_quad_constructed;
Packit d345d1
  gobject_class->dispose = shell_glsl_quad_dispose;
Packit d345d1
Packit d345d1
  actor_class->get_paint_volume = shell_glsl_quad_get_paint_volume;
Packit d345d1
  actor_class->paint = shell_glsl_quad_paint;
Packit d345d1
}
Packit d345d1
Packit d345d1
/**
Packit d345d1
 * shell_glsl_quad_get_uniform_location:
Packit d345d1
 * @quad: a #ShellGLSLQuad
Packit d345d1
 * @name: the uniform name
Packit d345d1
 *
Packit d345d1
 * Returns: the location of the uniform named @name, that can be
Packit d345d1
 *          passed to shell_glsl_quad_set_uniform_float().
Packit d345d1
 */
Packit d345d1
int
Packit d345d1
shell_glsl_quad_get_uniform_location (ShellGLSLQuad *quad,
Packit d345d1
                                      const char    *name)
Packit d345d1
{
Packit d345d1
  ShellGLSLQuadPrivate *priv = shell_glsl_quad_get_instance_private (quad);
Packit d345d1
  return cogl_pipeline_get_uniform_location (priv->pipeline, name);
Packit d345d1
}
Packit d345d1
Packit d345d1
/**
Packit d345d1
 * shell_glsl_quad_set_uniform_float:
Packit d345d1
 * @quad: a #ShellGLSLQuad
Packit d345d1
 * @uniform: the uniform location (as returned by shell_glsl_quad_get_uniform_location())
Packit d345d1
 * @n_components: the number of components in the uniform (eg. 3 for a vec3)
Packit d345d1
 * @total_count: the total number of floats in @value
Packit d345d1
 * @value: (array length=total_count): the array of floats to set @uniform
Packit d345d1
 */
Packit d345d1
void
Packit d345d1
shell_glsl_quad_set_uniform_float (ShellGLSLQuad *quad,
Packit d345d1
                                   int            uniform,
Packit d345d1
                                   int            n_components,
Packit d345d1
                                   int            total_count,
Packit d345d1
                                   const float   *value)
Packit d345d1
{
Packit d345d1
  ShellGLSLQuadPrivate *priv = shell_glsl_quad_get_instance_private (quad);
Packit d345d1
  cogl_pipeline_set_uniform_float (priv->pipeline, uniform,
Packit d345d1
                                   n_components, total_count / n_components,
Packit d345d1
                                   value);
Packit d345d1
}