mirror of
https://github.com/brl/mutter.git
synced 2024-12-26 12:52:14 +00:00
c9a81f035e
Some of the Clutter code was using GL types for the primitive types such as GLint and GLubyte and then passing these to Cogl. This doesn't make much sense because the Cogl functions directly take native C types. This patch just replaces them with either a native C type or a glib type. Some of the cogl conformance tests are trying to directly call GL for example to test creating a foreign texture. These tests have been changed to manually define the GL enum values instead of relying on a GL header to define them. This is necessary because Cogl may soon stop including a GL header from its public headers. Reviewed-by: Emmanuele Bassi <ebassi@linux.intel.com>
943 lines
25 KiB
C
943 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
|
|
|
|
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
|
|
|
|
#include <glib.h>
|
|
#include <glib/gi18n-lib.h>
|
|
|
|
/* This file depends on the cogl 1.x api which isn't exposed when
|
|
* COGL_ENABLE_EXPERIMENTAL_2_0_API is defined...
|
|
*/
|
|
#undef COGL_ENABLE_EXPERIMENTAL_2_0_API
|
|
#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;
|
|
int 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 float *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 float *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))
|
|
{
|
|
float 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_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");
|
|
}
|