2b81d90dd7
The G_CONST_RETURN define in GLib is, and has always been, a bit fuzzy. We always used it to conform to the platform, at least for public-facing API. At first I assumed it has something to do with brain-damaged compilers or with weird platforms where const was not really supported; sadly, it's something much, much worse: it's a define that can be toggled at compile-time to remove const from the signature of public API. This is a truly terrifying feature that I assume was added in the past century, and whose inception clearly had something to do with massive doses of absynthe and opium — because any other explanation would make the existence of such a feature even worse than assuming drugs had anything to do with it. Anyway, and pleasing the gods, this dubious feature is being removed/deprecated in GLib; see bug: https://bugzilla.gnome.org/show_bug.cgi?id=644611 Before deprecation, though, we should just remove its usage from the whole API. We should especially remove its usage from Cally's internals, since there it never made sense in the first place.
951 lines
25 KiB
C
951 lines
25 KiB
C
/*
|
|
* Clutter.
|
|
*
|
|
* An OpenGL based 'interactive canvas' library.
|
|
*
|
|
* Authored By: Matthew Allum <mallum@openedhand.com>
|
|
* Øyvind Kolås <pippin@o-hand.com>
|
|
* Emmanuele Bassi <ebassi@linux.intel.com>
|
|
*
|
|
* Copyright (C) 2007, 2008 OpenedHand
|
|
* Copyright (C) 2009 Intel Corp
|
|
*
|
|
* 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 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:clutter-shader
|
|
* @short_description: Programmable pipeline abstraction
|
|
*
|
|
* #ClutterShader is an object providing an abstraction over the
|
|
* OpenGL programmable pipeline. By using #ClutterShader<!-- -->s is
|
|
* possible to override the drawing pipeline by using small programs
|
|
* also known as "shaders".
|
|
*
|
|
* #ClutterShader is available since Clutter 0.6.
|
|
*
|
|
* #ClutterShader is deprecated since Clutter 1.8; use #ClutterShaderEffect
|
|
* in newly written code.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#include <glib.h>
|
|
#include <glib/gi18n-lib.h>
|
|
|
|
#include <cogl/cogl.h>
|
|
|
|
#include "clutter-shader.h"
|
|
|
|
#include "clutter-debug.h"
|
|
#include "clutter-private.h"
|
|
|
|
/* global list of shaders */
|
|
static GList *clutter_shaders_list = NULL;
|
|
|
|
#define CLUTTER_SHADER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_SHADER, ClutterShaderPrivate))
|
|
|
|
struct _ClutterShaderPrivate
|
|
{
|
|
guint compiled : 1; /* Shader is bound to the GL context */
|
|
guint is_enabled : 1;
|
|
guint vertex_is_glsl : 1;
|
|
guint fragment_is_glsl : 1;
|
|
|
|
gchar *vertex_source; /* GLSL source for vertex shader */
|
|
gchar *fragment_source; /* GLSL source for fragment shader */
|
|
|
|
CoglHandle program;
|
|
|
|
CoglHandle vertex_shader;
|
|
CoglHandle fragment_shader;
|
|
};
|
|
|
|
enum
|
|
{
|
|
PROP_0,
|
|
|
|
PROP_VERTEX_SOURCE,
|
|
PROP_FRAGMENT_SOURCE,
|
|
PROP_COMPILED,
|
|
PROP_ENABLED,
|
|
|
|
PROP_LAST
|
|
};
|
|
|
|
static GParamSpec *obj_props[PROP_LAST];
|
|
|
|
G_DEFINE_TYPE (ClutterShader, clutter_shader, G_TYPE_OBJECT);
|
|
|
|
static inline void
|
|
clutter_shader_release_internal (ClutterShader *shader)
|
|
{
|
|
ClutterShaderPrivate *priv = shader->priv;
|
|
|
|
if (!priv->compiled)
|
|
return;
|
|
|
|
g_assert (priv->program != COGL_INVALID_HANDLE);
|
|
|
|
if (priv->vertex_is_glsl && priv->vertex_shader != COGL_INVALID_HANDLE)
|
|
cogl_handle_unref (priv->vertex_shader);
|
|
|
|
if (priv->fragment_is_glsl && priv->fragment_shader != COGL_INVALID_HANDLE)
|
|
cogl_handle_unref (priv->fragment_shader);
|
|
|
|
if (priv->program != COGL_INVALID_HANDLE)
|
|
cogl_handle_unref (priv->program);
|
|
|
|
priv->vertex_shader = COGL_INVALID_HANDLE;
|
|
priv->fragment_shader = COGL_INVALID_HANDLE;
|
|
priv->program = COGL_INVALID_HANDLE;
|
|
priv->compiled = FALSE;
|
|
}
|
|
|
|
static void
|
|
clutter_shader_finalize (GObject *object)
|
|
{
|
|
ClutterShader *shader;
|
|
ClutterShaderPrivate *priv;
|
|
|
|
shader = CLUTTER_SHADER (object);
|
|
priv = shader->priv;
|
|
|
|
clutter_shaders_list = g_list_remove (clutter_shaders_list, object);
|
|
|
|
g_free (priv->fragment_source);
|
|
g_free (priv->vertex_source);
|
|
|
|
G_OBJECT_CLASS (clutter_shader_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
clutter_shader_dispose (GObject *object)
|
|
{
|
|
ClutterShader *shader = CLUTTER_SHADER (object);
|
|
|
|
clutter_shader_release_internal (shader);
|
|
|
|
G_OBJECT_CLASS (clutter_shader_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
clutter_shader_set_property (GObject *object,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
ClutterShader *shader = CLUTTER_SHADER(object);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_VERTEX_SOURCE:
|
|
clutter_shader_set_vertex_source (shader,
|
|
g_value_get_string (value), -1);
|
|
break;
|
|
case PROP_FRAGMENT_SOURCE:
|
|
clutter_shader_set_fragment_source (shader,
|
|
g_value_get_string (value), -1);
|
|
break;
|
|
case PROP_ENABLED:
|
|
clutter_shader_set_is_enabled (shader, g_value_get_boolean (value));
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
clutter_shader_get_property (GObject *object,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
ClutterShader *shader;
|
|
ClutterShaderPrivate *priv;
|
|
|
|
shader = CLUTTER_SHADER(object);
|
|
priv = shader->priv;
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_VERTEX_SOURCE:
|
|
g_value_set_string (value, priv->vertex_source);
|
|
break;
|
|
case PROP_FRAGMENT_SOURCE:
|
|
g_value_set_string (value, priv->fragment_source);
|
|
break;
|
|
case PROP_COMPILED:
|
|
g_value_set_boolean (value, priv->compiled);
|
|
break;
|
|
case PROP_ENABLED:
|
|
g_value_set_boolean (value, priv->is_enabled);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static GObject *
|
|
clutter_shader_constructor (GType type,
|
|
guint n_params,
|
|
GObjectConstructParam *params)
|
|
{
|
|
GObjectClass *parent_class;
|
|
GObject *object;
|
|
|
|
parent_class = G_OBJECT_CLASS (clutter_shader_parent_class);
|
|
object = parent_class->constructor (type, n_params, params);
|
|
|
|
/* add this instance to the global list of shaders */
|
|
clutter_shaders_list = g_list_prepend (clutter_shaders_list, object);
|
|
|
|
return object;
|
|
}
|
|
|
|
static void
|
|
clutter_shader_class_init (ClutterShaderClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
GParamSpec *pspec = NULL;
|
|
|
|
object_class->finalize = clutter_shader_finalize;
|
|
object_class->dispose = clutter_shader_dispose;
|
|
object_class->set_property = clutter_shader_set_property;
|
|
object_class->get_property = clutter_shader_get_property;
|
|
object_class->constructor = clutter_shader_constructor;
|
|
|
|
g_type_class_add_private (klass, sizeof (ClutterShaderPrivate));
|
|
|
|
/**
|
|
* ClutterShader:vertex-source:
|
|
*
|
|
* GLSL source code for the vertex shader part of the shader
|
|
* program, if any
|
|
*
|
|
* Since: 0.6
|
|
*
|
|
* Deprecated: 1.8: Use #ClutterShaderEffect instead.
|
|
*/
|
|
pspec = g_param_spec_string ("vertex-source",
|
|
P_("Vertex Source"),
|
|
P_("Source of vertex shader"),
|
|
NULL,
|
|
CLUTTER_PARAM_READWRITE);
|
|
obj_props[PROP_VERTEX_SOURCE] = pspec;
|
|
g_object_class_install_property (object_class, PROP_VERTEX_SOURCE, pspec);
|
|
|
|
/**
|
|
* ClutterShader:fragment-source:
|
|
*
|
|
* GLSL source code for the fragment shader part of the shader program.
|
|
*
|
|
* Since: 0.6
|
|
*
|
|
* Deprecated: 1.8: Use #ClutterShaderEffect instead.
|
|
*/
|
|
pspec = g_param_spec_string ("fragment-source",
|
|
P_("Fragment Source"),
|
|
P_("Source of fragment shader"),
|
|
NULL,
|
|
CLUTTER_PARAM_READWRITE);
|
|
obj_props[PROP_FRAGMENT_SOURCE] = pspec;
|
|
g_object_class_install_property (object_class, PROP_FRAGMENT_SOURCE, pspec);
|
|
|
|
/**
|
|
* ClutterShader:compiled:
|
|
*
|
|
* Whether the shader is compiled and linked, ready for use
|
|
* in the GL context.
|
|
*
|
|
* Since: 0.8
|
|
*
|
|
* Deprecated: 1.8: Use #ClutterShaderEffect instead.
|
|
*/
|
|
pspec = g_param_spec_boolean ("compiled",
|
|
P_("Compiled"),
|
|
P_("Whether the shader is compiled and linked"),
|
|
FALSE,
|
|
CLUTTER_PARAM_READABLE);
|
|
obj_props[PROP_COMPILED] = pspec;
|
|
g_object_class_install_property (object_class, PROP_COMPILED, pspec);
|
|
|
|
/**
|
|
* ClutterShader:enabled:
|
|
*
|
|
* Whether the shader is currently used in the GL rendering pipeline.
|
|
*
|
|
* Since: 0.6
|
|
*
|
|
* Deprecated: 1.8: Use #ClutterShaderEffect instead.
|
|
*/
|
|
pspec = g_param_spec_boolean ("enabled",
|
|
P_("Enabled"),
|
|
P_("Whether the shader is enabled"),
|
|
FALSE,
|
|
CLUTTER_PARAM_READWRITE);
|
|
obj_props[PROP_ENABLED] = pspec;
|
|
g_object_class_install_property (object_class, PROP_ENABLED, pspec);
|
|
}
|
|
|
|
static void
|
|
clutter_shader_init (ClutterShader *self)
|
|
{
|
|
ClutterShaderPrivate *priv;
|
|
|
|
priv = self->priv = CLUTTER_SHADER_GET_PRIVATE (self);
|
|
|
|
priv->compiled = FALSE;
|
|
|
|
priv->vertex_source = NULL;
|
|
priv->fragment_source = NULL;
|
|
|
|
priv->program = COGL_INVALID_HANDLE;
|
|
priv->vertex_shader = COGL_INVALID_HANDLE;
|
|
priv->fragment_shader = COGL_INVALID_HANDLE;
|
|
}
|
|
|
|
/**
|
|
* clutter_shader_new:
|
|
*
|
|
* Create a new #ClutterShader instance.
|
|
*
|
|
* Return value: a new #ClutterShader.
|
|
*
|
|
* Since: 0.6
|
|
*
|
|
* Deprecated: 1.8: Use #ClutterShaderEffect instead.
|
|
*/
|
|
ClutterShader *
|
|
clutter_shader_new (void)
|
|
{
|
|
return g_object_new (CLUTTER_TYPE_SHADER, NULL);
|
|
}
|
|
|
|
static inline void
|
|
clutter_shader_set_source (ClutterShader *shader,
|
|
ClutterShaderType shader_type,
|
|
const gchar *data,
|
|
gssize length)
|
|
{
|
|
ClutterShaderPrivate *priv = shader->priv;
|
|
gboolean is_glsl = FALSE;
|
|
|
|
if (length < 0)
|
|
length = strlen (data);
|
|
|
|
g_object_freeze_notify (G_OBJECT (shader));
|
|
|
|
/* release shader if bound when changing the source, the shader will
|
|
* automatically be rebound on the next use.
|
|
*/
|
|
if (clutter_shader_is_compiled (shader))
|
|
clutter_shader_release (shader);
|
|
|
|
is_glsl = !g_str_has_prefix (data, "!!ARBfp");
|
|
|
|
CLUTTER_NOTE (SHADER,
|
|
"setting %s shader (GLSL:%s, len:%" G_GSSIZE_FORMAT ")",
|
|
shader_type == CLUTTER_VERTEX_SHADER ? "vertex" : "fragment",
|
|
is_glsl ? "yes" : "no",
|
|
length);
|
|
|
|
switch (shader_type)
|
|
{
|
|
case CLUTTER_FRAGMENT_SHADER:
|
|
g_free (priv->fragment_source);
|
|
|
|
priv->fragment_source = g_strndup (data, length);
|
|
priv->fragment_is_glsl = is_glsl;
|
|
g_object_notify_by_pspec (G_OBJECT (shader), obj_props[PROP_FRAGMENT_SOURCE]);
|
|
break;
|
|
|
|
case CLUTTER_VERTEX_SHADER:
|
|
g_free (priv->vertex_source);
|
|
|
|
priv->vertex_source = g_strndup (data, length);
|
|
priv->vertex_is_glsl = is_glsl;
|
|
g_object_notify_by_pspec (G_OBJECT (shader), obj_props[PROP_VERTEX_SOURCE]);
|
|
break;
|
|
}
|
|
|
|
g_object_thaw_notify (G_OBJECT (shader));
|
|
}
|
|
|
|
/**
|
|
* clutter_shader_set_fragment_source:
|
|
* @shader: a #ClutterShader
|
|
* @data: GLSL source code.
|
|
* @length: length of source buffer (currently ignored)
|
|
*
|
|
* Sets the GLSL source code to be used by a #ClutterShader for the fragment
|
|
* program.
|
|
*
|
|
* Since: 0.6
|
|
*
|
|
* Deprecated: 1.8: Use #ClutterShaderEffect instead.
|
|
*/
|
|
void
|
|
clutter_shader_set_fragment_source (ClutterShader *shader,
|
|
const gchar *data,
|
|
gssize length)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_SHADER (shader));
|
|
g_return_if_fail (data != NULL);
|
|
|
|
clutter_shader_set_source (shader, CLUTTER_FRAGMENT_SHADER, data, length);
|
|
}
|
|
|
|
/**
|
|
* clutter_shader_set_vertex_source:
|
|
* @shader: a #ClutterShader
|
|
* @data: GLSL source code.
|
|
* @length: length of source buffer (currently ignored)
|
|
*
|
|
* Sets the GLSL source code to be used by a #ClutterShader for the vertex
|
|
* program.
|
|
*
|
|
* Since: 0.6
|
|
*
|
|
* Deprecated: 1.8: Use #ClutterShaderEffect instead.
|
|
*/
|
|
void
|
|
clutter_shader_set_vertex_source (ClutterShader *shader,
|
|
const gchar *data,
|
|
gssize length)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_SHADER (shader));
|
|
g_return_if_fail (data != NULL);
|
|
|
|
clutter_shader_set_source (shader, CLUTTER_VERTEX_SHADER, data, length);
|
|
}
|
|
|
|
static const gchar *
|
|
clutter_shader_get_source (ClutterShader *shader,
|
|
ClutterShaderType shader_type)
|
|
{
|
|
switch (shader_type)
|
|
{
|
|
case CLUTTER_FRAGMENT_SHADER:
|
|
return shader->priv->fragment_source;
|
|
|
|
case CLUTTER_VERTEX_SHADER:
|
|
return shader->priv->vertex_source;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static CoglHandle
|
|
clutter_shader_get_cogl_shader (ClutterShader *shader,
|
|
ClutterShaderType shader_type)
|
|
{
|
|
switch (shader_type)
|
|
{
|
|
case CLUTTER_FRAGMENT_SHADER:
|
|
return shader->priv->fragment_shader;
|
|
|
|
case CLUTTER_VERTEX_SHADER:
|
|
return shader->priv->vertex_shader;
|
|
}
|
|
|
|
return COGL_INVALID_HANDLE;
|
|
}
|
|
|
|
static gboolean
|
|
clutter_shader_glsl_bind (ClutterShader *self,
|
|
ClutterShaderType shader_type,
|
|
GError **error)
|
|
{
|
|
ClutterShaderPrivate *priv = self->priv;
|
|
CoglHandle shader = COGL_INVALID_HANDLE;
|
|
|
|
switch (shader_type)
|
|
{
|
|
case CLUTTER_VERTEX_SHADER:
|
|
shader = cogl_create_shader (COGL_SHADER_TYPE_VERTEX);
|
|
cogl_shader_source (shader, priv->vertex_source);
|
|
|
|
priv->vertex_shader = shader;
|
|
break;
|
|
|
|
case CLUTTER_FRAGMENT_SHADER:
|
|
shader = cogl_create_shader (COGL_SHADER_TYPE_FRAGMENT);
|
|
cogl_shader_source (shader, priv->fragment_source);
|
|
|
|
priv->fragment_shader = shader;
|
|
break;
|
|
}
|
|
|
|
g_assert (shader != COGL_INVALID_HANDLE);
|
|
|
|
cogl_shader_compile (shader);
|
|
if (!cogl_shader_is_compiled (shader))
|
|
{
|
|
gchar *log_buf;
|
|
|
|
log_buf = cogl_shader_get_info_log (shader);
|
|
|
|
/* translators: the first %s is the type of the shader, either
|
|
* Vertex shader or Fragment shader; the second %s is the actual
|
|
* error as reported by COGL
|
|
*/
|
|
g_set_error (error, CLUTTER_SHADER_ERROR,
|
|
CLUTTER_SHADER_ERROR_COMPILE,
|
|
_("%s compilation failed: %s"),
|
|
shader_type == CLUTTER_VERTEX_SHADER ? _("Vertex shader")
|
|
: _("Fragment shader"),
|
|
log_buf);
|
|
|
|
g_free (log_buf);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
cogl_program_attach_shader (priv->program, shader);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
bind_glsl_shader (ClutterShader *self,
|
|
GError **error)
|
|
{
|
|
ClutterShaderPrivate *priv = self->priv;
|
|
GError *bind_error = NULL;
|
|
gboolean res;
|
|
|
|
priv->program = cogl_create_program ();
|
|
|
|
if (priv->vertex_is_glsl && priv->vertex_source != COGL_INVALID_HANDLE)
|
|
{
|
|
res = clutter_shader_glsl_bind (self,
|
|
CLUTTER_VERTEX_SHADER,
|
|
&bind_error);
|
|
|
|
if (!res)
|
|
{
|
|
g_propagate_error (error, bind_error);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (priv->fragment_is_glsl && priv->fragment_source != COGL_INVALID_HANDLE)
|
|
{
|
|
res = clutter_shader_glsl_bind (self,
|
|
CLUTTER_FRAGMENT_SHADER,
|
|
&bind_error);
|
|
|
|
if (!res)
|
|
{
|
|
g_propagate_error (error, bind_error);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
cogl_program_link (priv->program);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* clutter_shader_compile:
|
|
* @shader: a #ClutterShader
|
|
* @error: return location for a #GError, or %NULL
|
|
*
|
|
* Compiles and links GLSL sources set for vertex and fragment shaders for
|
|
* a #ClutterShader. If the compilation fails and a #GError return location is
|
|
* provided the error will contain the errors from the compiler, if any.
|
|
*
|
|
* Return value: returns TRUE if the shader was succesfully compiled.
|
|
*
|
|
* Since: 0.8
|
|
*
|
|
* Deprecated: 1.8: Use #ClutterShaderEffect instead.
|
|
*/
|
|
gboolean
|
|
clutter_shader_compile (ClutterShader *shader,
|
|
GError **error)
|
|
{
|
|
ClutterShaderPrivate *priv;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_SHADER (shader), FALSE);
|
|
|
|
priv = shader->priv;
|
|
|
|
if (priv->compiled)
|
|
return priv->compiled;
|
|
|
|
if ((priv->vertex_source != COGL_INVALID_HANDLE && !priv->vertex_is_glsl) ||
|
|
(priv->fragment_source != COGL_INVALID_HANDLE && !priv->fragment_is_glsl))
|
|
{
|
|
/* XXX: Could remove this check, since we only advertise support for GLSL
|
|
* shaders anyways. */
|
|
g_set_error (error, CLUTTER_SHADER_ERROR,
|
|
CLUTTER_SHADER_ERROR_NO_ASM,
|
|
"ASM shaders not supported");
|
|
priv->compiled = FALSE;
|
|
return priv->compiled;
|
|
}
|
|
|
|
if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
|
|
{
|
|
g_set_error (error, CLUTTER_SHADER_ERROR,
|
|
CLUTTER_SHADER_ERROR_NO_GLSL,
|
|
"GLSL shaders not supported");
|
|
priv->compiled = FALSE;
|
|
return priv->compiled;
|
|
}
|
|
|
|
priv->compiled = bind_glsl_shader (shader, error);
|
|
g_object_notify_by_pspec (G_OBJECT (shader), obj_props[PROP_COMPILED]);
|
|
|
|
return priv->compiled;
|
|
}
|
|
|
|
/**
|
|
* clutter_shader_release:
|
|
* @shader: a #ClutterShader
|
|
*
|
|
* Frees up any GL context resources held by the shader.
|
|
*
|
|
* Since: 0.6
|
|
*
|
|
* Deprecated: 1.8: Use #ClutterShaderEffect instead.
|
|
*/
|
|
void
|
|
clutter_shader_release (ClutterShader *shader)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_SHADER (shader));
|
|
|
|
clutter_shader_release_internal (shader);
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (shader), obj_props[PROP_COMPILED]);
|
|
}
|
|
|
|
/**
|
|
* clutter_shader_is_compiled:
|
|
* @shader: a #ClutterShader
|
|
*
|
|
* Checks whether @shader is is currently compiled, linked and bound
|
|
* to the GL context.
|
|
*
|
|
* Return value: %TRUE if the shader is compiled, linked and ready for use.
|
|
*
|
|
* Since: 0.8
|
|
*
|
|
* Deprecated: 1.8: Use #ClutterShaderEffect instead.
|
|
*/
|
|
gboolean
|
|
clutter_shader_is_compiled (ClutterShader *shader)
|
|
{
|
|
g_return_val_if_fail (CLUTTER_IS_SHADER (shader), FALSE);
|
|
|
|
return shader->priv->compiled;
|
|
}
|
|
|
|
/**
|
|
* clutter_shader_set_is_enabled:
|
|
* @shader: a #ClutterShader
|
|
* @enabled: The new state of the shader.
|
|
*
|
|
* Enables a shader. This function will attempt to compile and link
|
|
* the shader, if it isn't already.
|
|
*
|
|
* When @enabled is %FALSE the default state of the GL pipeline will be
|
|
* used instead.
|
|
*
|
|
* Since: 0.6
|
|
*
|
|
* Deprecated: 1.8: Use #ClutterShaderEffect instead.
|
|
*/
|
|
void
|
|
clutter_shader_set_is_enabled (ClutterShader *shader,
|
|
gboolean enabled)
|
|
{
|
|
ClutterShaderPrivate *priv;
|
|
|
|
g_return_if_fail (CLUTTER_IS_SHADER (shader));
|
|
|
|
priv = shader->priv;
|
|
|
|
if (priv->is_enabled != enabled)
|
|
{
|
|
GError *error = NULL;
|
|
gboolean res;
|
|
|
|
res = clutter_shader_compile (shader, &error);
|
|
if (!res)
|
|
{
|
|
g_warning ("Unable to bind the shader: %s",
|
|
error ? error->message : "unknown error");
|
|
if (error)
|
|
g_error_free (error);
|
|
|
|
return;
|
|
}
|
|
|
|
priv->is_enabled = enabled;
|
|
|
|
if (priv->is_enabled)
|
|
cogl_program_use (priv->program);
|
|
else
|
|
cogl_program_use (COGL_INVALID_HANDLE);
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (shader), obj_props[PROP_ENABLED]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* clutter_shader_get_is_enabled:
|
|
* @shader: a #ClutterShader
|
|
*
|
|
* Checks whether @shader is enabled.
|
|
*
|
|
* Return value: %TRUE if the shader is enabled.
|
|
*
|
|
* Since: 0.6
|
|
*
|
|
* Deprecated: 1.8: Use #ClutterShaderEffect instead.
|
|
*/
|
|
gboolean
|
|
clutter_shader_get_is_enabled (ClutterShader *shader)
|
|
{
|
|
g_return_val_if_fail (CLUTTER_IS_SHADER (shader), FALSE);
|
|
|
|
return shader->priv->is_enabled;
|
|
}
|
|
|
|
/**
|
|
* clutter_shader_set_uniform:
|
|
* @shader: a #ClutterShader.
|
|
* @name: name of uniform in GLSL shader program to set.
|
|
* @value: a #ClutterShaderFloat, #ClutterShaderInt or #ClutterShaderMatrix
|
|
* #GValue.
|
|
*
|
|
* Sets a user configurable variable in the GLSL shader programs attached to
|
|
* a #ClutterShader.
|
|
*
|
|
* Since: 1.0
|
|
*
|
|
* Deprecated: 1.8: Use #ClutterShaderEffect instead.
|
|
*/
|
|
void
|
|
clutter_shader_set_uniform (ClutterShader *shader,
|
|
const gchar *name,
|
|
const GValue *value)
|
|
{
|
|
ClutterShaderPrivate *priv;
|
|
GLint location = 0;
|
|
gsize size;
|
|
|
|
g_return_if_fail (CLUTTER_IS_SHADER (shader));
|
|
g_return_if_fail (name != NULL);
|
|
g_return_if_fail (value != NULL);
|
|
g_return_if_fail (CLUTTER_VALUE_HOLDS_SHADER_FLOAT (value) ||
|
|
CLUTTER_VALUE_HOLDS_SHADER_INT (value) ||
|
|
CLUTTER_VALUE_HOLDS_SHADER_MATRIX (value) ||
|
|
G_VALUE_HOLDS_FLOAT (value) ||
|
|
G_VALUE_HOLDS_INT (value));
|
|
|
|
priv = shader->priv;
|
|
g_return_if_fail (priv->program != COGL_INVALID_HANDLE);
|
|
|
|
location = cogl_program_get_uniform_location (priv->program, name);
|
|
|
|
if (CLUTTER_VALUE_HOLDS_SHADER_FLOAT (value))
|
|
{
|
|
const GLfloat *floats;
|
|
|
|
floats = clutter_value_get_shader_float (value, &size);
|
|
cogl_program_set_uniform_float (priv->program,
|
|
location, size, 1, floats);
|
|
}
|
|
else if (CLUTTER_VALUE_HOLDS_SHADER_INT (value))
|
|
{
|
|
const int *ints;
|
|
|
|
ints = clutter_value_get_shader_int (value, &size);
|
|
cogl_program_set_uniform_int (priv->program,
|
|
location, size, 1, ints);
|
|
}
|
|
else if (CLUTTER_VALUE_HOLDS_SHADER_MATRIX (value))
|
|
{
|
|
const GLfloat *matrix;
|
|
|
|
matrix = clutter_value_get_shader_matrix (value, &size);
|
|
cogl_program_set_uniform_matrix (priv->program,
|
|
location, size, 1, FALSE, matrix);
|
|
}
|
|
else if (G_VALUE_HOLDS_FLOAT (value))
|
|
{
|
|
GLfloat float_val = g_value_get_float (value);
|
|
|
|
cogl_program_set_uniform_float (priv->program,
|
|
location, 1, 1, &float_val);
|
|
}
|
|
else if (G_VALUE_HOLDS_INT (value))
|
|
{
|
|
int int_val = g_value_get_int (value);
|
|
|
|
cogl_program_set_uniform_int (priv->program,
|
|
location, 1, 1, &int_val);
|
|
}
|
|
else
|
|
g_assert_not_reached ();
|
|
}
|
|
|
|
/*
|
|
* _clutter_shader_release_all:
|
|
*
|
|
* Iterate through all #ClutterShaders and tell them to release GL context
|
|
* related sources.
|
|
*/
|
|
void
|
|
_clutter_shader_release_all (void)
|
|
{
|
|
g_list_foreach (clutter_shaders_list,
|
|
(GFunc) clutter_shader_release,
|
|
NULL);
|
|
}
|
|
|
|
/**
|
|
* clutter_shader_get_fragment_source:
|
|
* @shader: a #ClutterShader
|
|
*
|
|
* Query the current GLSL fragment source set on @shader.
|
|
*
|
|
* Return value: the source of the fragment shader for this
|
|
* ClutterShader object or %NULL. The returned string is owned by the
|
|
* shader object and should never be modified or freed
|
|
*
|
|
* Since: 0.6
|
|
*
|
|
* Deprecated: 1.8: Use #ClutterShaderEffect instead.
|
|
*/
|
|
const gchar *
|
|
clutter_shader_get_fragment_source (ClutterShader *shader)
|
|
{
|
|
g_return_val_if_fail (CLUTTER_IS_SHADER (shader), NULL);
|
|
|
|
return clutter_shader_get_source (shader, CLUTTER_FRAGMENT_SHADER);
|
|
}
|
|
|
|
/**
|
|
* clutter_shader_get_vertex_source:
|
|
* @shader: a #ClutterShader
|
|
*
|
|
* Query the current GLSL vertex source set on @shader.
|
|
*
|
|
* Return value: the source of the vertex shader for this
|
|
* ClutterShader object or %NULL. The returned string is owned by the
|
|
* shader object and should never be modified or freed
|
|
*
|
|
* Since: 0.6
|
|
*
|
|
* Deprecated: 1.8: Use #ClutterShaderEffect instead.
|
|
*/
|
|
const gchar *
|
|
clutter_shader_get_vertex_source (ClutterShader *shader)
|
|
{
|
|
g_return_val_if_fail (CLUTTER_IS_SHADER (shader), NULL);
|
|
|
|
return clutter_shader_get_source (shader, CLUTTER_VERTEX_SHADER);
|
|
}
|
|
|
|
/**
|
|
* clutter_shader_get_cogl_program:
|
|
* @shader: a #ClutterShader
|
|
*
|
|
* Retrieves the underlying #CoglHandle for the shader program.
|
|
*
|
|
* Return value: (transfer none): A #CoglHandle for the shader program,
|
|
* or %NULL. The handle is owned by the #ClutterShader and it should
|
|
* not be unreferenced
|
|
*
|
|
* Since: 1.0
|
|
*
|
|
* Deprecated: 1.8: Use #ClutterShaderEffect instead.
|
|
*/
|
|
CoglHandle
|
|
clutter_shader_get_cogl_program (ClutterShader *shader)
|
|
{
|
|
g_return_val_if_fail (CLUTTER_IS_SHADER (shader), NULL);
|
|
|
|
return shader->priv->program;
|
|
}
|
|
|
|
/**
|
|
* clutter_shader_get_cogl_fragment_shader:
|
|
* @shader: a #ClutterShader
|
|
*
|
|
* Retrieves the underlying #CoglHandle for the fragment shader.
|
|
*
|
|
* Return value: (transfer none): A #CoglHandle for the fragment
|
|
* shader, or %NULL. The handle is owned by the #ClutterShader
|
|
* and it should not be unreferenced
|
|
*
|
|
* Since: 1.0
|
|
*
|
|
* Deprecated: 1.8: Use #ClutterShaderEffect instead.
|
|
*/
|
|
CoglHandle
|
|
clutter_shader_get_cogl_fragment_shader (ClutterShader *shader)
|
|
{
|
|
g_return_val_if_fail (CLUTTER_IS_SHADER (shader), NULL);
|
|
|
|
return clutter_shader_get_cogl_shader (shader, CLUTTER_FRAGMENT_SHADER);
|
|
}
|
|
|
|
/**
|
|
* clutter_shader_get_cogl_vertex_shader:
|
|
* @shader: a #ClutterShader
|
|
*
|
|
* Retrieves the underlying #CoglHandle for the vertex shader.
|
|
*
|
|
* Return value: (transfer none): A #CoglHandle for the vertex
|
|
* shader, or %NULL. The handle is owned by the #ClutterShader
|
|
* and it should not be unreferenced
|
|
*
|
|
* Since: 1.0
|
|
*
|
|
* Deprecated: 1.8: Use #ClutterShaderEffect instead.
|
|
*/
|
|
CoglHandle
|
|
clutter_shader_get_cogl_vertex_shader (ClutterShader *shader)
|
|
{
|
|
g_return_val_if_fail (CLUTTER_IS_SHADER (shader), NULL);
|
|
|
|
return clutter_shader_get_cogl_shader (shader, CLUTTER_VERTEX_SHADER);
|
|
}
|
|
|
|
GQuark
|
|
clutter_shader_error_quark (void)
|
|
{
|
|
return g_quark_from_static_string ("clutter-shader-error");
|
|
}
|