* Boston, MA 02111-1307, USA.
*/
-#include "clutter.h"
-#include "clutter-private.h"
-#include "clutter-shader.h"
+#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 <cogl/cogl.h>
-#include <string.h>
-#include <stdlib.h>
+
+#include "clutter-debug.h"
+#include "clutter-private.h"
+#include "clutter-shader.h"
+
+static GList *clutter_shaders_list = NULL;
#define CLUTTER_SHADER_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
CLUTTER_TYPE_SHADER, ClutterShaderPrivate))
-static GList *shader_list;
-
-static void clutter_shader_class_init (ClutterShaderClass *klass);
-static void clutter_shader_init (ClutterShader *sp);
-static void clutter_shader_finalize (GObject *object);
-static GObject *clutter_shader_constructor (GType type,
- guint n_params,
- GObjectConstructParam *params);
-static void clutter_shader_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec);
-static void clutter_shader_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec);
+typedef enum {
+ CLUTTER_VERTEX_SHADER,
+ CLUTTER_FRAGMENT_SHADER
+} ClutterShaderType;
struct _ClutterShaderPrivate
{
- gboolean glsl; /* The shader is a GLSL shader */
- gboolean bound; /* The shader is bound to the GL context */
+ guint bound : 1; /* The shader is bound to the GL context */
+ guint is_enabled : 1;
- gchar *vertex_shader_source; /* source (or asm) for vertex shader */
- gchar *fragment_shader_source;/* source (or asm) for fragment shader*/
+ guint vertex_is_glsl : 1;
+ guint fragment_is_glsl : 1;
+
+ gchar *vertex_source; /* source (or asm) for vertex shader */
+ gchar *fragment_source; /* source (or asm) for fragment shader */
COGLint program;
enum
{
PROP_0,
+
PROP_VERTEX_SOURCE,
- PROP_FRAGMENT_SOURCE
+ PROP_FRAGMENT_SOURCE,
+ PROP_BOUND,
+ PROP_ENABLED
};
+
+
G_DEFINE_TYPE (ClutterShader, clutter_shader, G_TYPE_OBJECT);
+G_CONST_RETURN gchar *clutter_shader_get_source (ClutterShader *shader,
+ ClutterShaderType type);
+
+static void
+clutter_shader_finalize (GObject *object)
+{
+ ClutterShader *shader;
+ ClutterShaderPrivate *priv;
+
+ shader = CLUTTER_SHADER (object);
+ priv = shader->priv;
+
+ clutter_shader_release (shader);
+
+ 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_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_BOUND:
+ g_value_set_boolean (value, priv->bound);
+ 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)
+{
+ GObject *object;
+
+ object = G_OBJECT_CLASS (clutter_shader_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);
- clutter_shader_parent_class = g_type_class_peek_parent (klass);
object_class->finalize = clutter_shader_finalize;
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:
+ *
+ * FIXME
+ *
+ * Since: 0.6
+ */
g_object_class_install_property (object_class,
PROP_VERTEX_SOURCE,
g_param_spec_string ("vertex-source",
"Vertex Source",
"Source of vertex shader",
NULL,
- CLUTTER_PARAM_READWRITE|
- G_PARAM_CONSTRUCT_ONLY));
+ CLUTTER_PARAM_READWRITE));
+ /**
+ * ClutterShader:fragment-source:
+ *
+ * FIXME
+ *
+ * Since: 0.6
+ */
g_object_class_install_property (object_class,
PROP_FRAGMENT_SOURCE,
g_param_spec_string ("fragment-source",
"Fragment Source",
"Source of fragment shader",
NULL,
- CLUTTER_PARAM_READWRITE|
- G_PARAM_CONSTRUCT_ONLY));
+ CLUTTER_PARAM_READWRITE));
+ /**
+ * ClutterShader:bound:
+ *
+ * FIXME
+ *
+ * Since: 0.6
+ */
+ g_object_class_install_property (object_class,
+ PROP_BOUND,
+ g_param_spec_boolean ("bound",
+ "Bound",
+ "Whether the shader is bound",
+ FALSE,
+ CLUTTER_PARAM_READABLE));
+ /**
+ * ClutterShader:enabled:
+ *
+ * FIXME
+ *
+ * Since: 0.6
+ */
+ g_object_class_install_property (object_class,
+ PROP_ENABLED,
+ g_param_spec_boolean ("enabled",
+ "Enabled",
+ "Whether the shader is enabled",
+ FALSE,
+ CLUTTER_PARAM_READWRITE));
}
static void
priv = self->priv = CLUTTER_SHADER_GET_PRIVATE (self);
- priv->glsl = FALSE;
priv->bound = FALSE;
- priv->vertex_shader_source = NULL;
- priv->fragment_shader_source = NULL;
+
+ priv->vertex_source = NULL;
+ priv->fragment_source = NULL;
+
priv->program = 0;
priv->vertex_shader = 0;
priv->fragment_shader = 0;
}
-static gboolean bind_glsl_shader (ClutterShader *self)
+/**
+ * clutter_shader_new:
+ *
+ * FIXME
+ *
+ * Return value: FIXME
+ *
+ * Since: 0.6
+ */
+ClutterShader *
+clutter_shader_new (void)
+{
+ return g_object_new (CLUTTER_TYPE_SHADER, NULL);
+}
+
+
+/**
+ * clutter_shader_set_fragment_source:
+ * @shader: a #ClutterShader
+ * @data: FIXME
+ * @length: FIXME (currently ignored)
+ *
+ * FIXME
+ *
+ *
+ * Since: 0.6
+ */
+void
+clutter_shader_set_fragment_source (ClutterShader *shader,
+ const gchar *data,
+ gssize length)
+{
+ ClutterShaderPrivate *priv;
+ gboolean is_glsl;
+
+ if (shader == NULL)
+ g_error ("quack!");
+
+ g_return_if_fail (CLUTTER_IS_SHADER (shader));
+ g_return_if_fail (data != NULL);
+
+ priv = shader->priv;
+
+ /* release shader if bound when changing the source, the shader will
+ * automatically be rebound on the next use.
+ */
+ if (clutter_shader_is_bound (shader))
+ clutter_shader_release (shader);
+
+ is_glsl = !g_str_has_prefix (data, "!!ARBfp");
+
+ if (priv->fragment_source)
+ {
+ g_free (priv->fragment_source);
+ }
+
+ CLUTTER_NOTE (SHADER, "setting fragment shader (GLSL:%s, len:%d)",
+ is_glsl ? "yes" : "no",
+ length);
+
+ priv->fragment_source = g_strdup (data);
+ priv->fragment_is_glsl = is_glsl;
+}
+
+
+/**
+ * clutter_shader_set_vertex_source:
+ * @shader: a #ClutterShader
+ * @data: FIXME
+ * @length: FIXME (currently ignored)
+ *
+ * FIXME
+ *
+ * Since: 0.6
+ */
+void
+clutter_shader_set_vertex_source (ClutterShader *shader,
+ const gchar *data,
+ gssize length)
+{
+ ClutterShaderPrivate *priv;
+ gboolean is_glsl;
+
+ if (shader == NULL)
+ g_error ("quack!");
+
+ g_return_if_fail (CLUTTER_IS_SHADER (shader));
+ g_return_if_fail (data != NULL);
+
+ priv = shader->priv;
+
+ /* release shader if bound when changing the source, the shader will
+ * automatically be rebound on the next use.
+ */
+ if (clutter_shader_is_bound (shader))
+ clutter_shader_release (shader);
+
+
+ is_glsl = !g_str_has_prefix (data, "!!ARBvp");
+
+ if (priv->vertex_source)
+ {
+ g_free (priv->vertex_source);
+ }
+
+ CLUTTER_NOTE (SHADER, "setting vertex shader (GLSL:%s, len:%d)",
+ is_glsl ? "yes" : "no",
+ length);
+
+ priv->vertex_source = g_strdup (data);
+ priv->vertex_is_glsl = is_glsl;
+}
+
+static gboolean
+bind_glsl_shader (ClutterShader *self,
+ GError **error)
{
ClutterShaderPrivate *priv;
priv = self->priv;
cogl_enable (CGL_FRAGMENT_SHADER);
cogl_enable (CGL_VERTEX_SHADER);
- priv->glsl = TRUE;
priv->program = cogl_create_program ();
- if (priv->vertex_shader_source)
+ if (priv->vertex_is_glsl && priv->vertex_source)
{
priv->vertex_shader = cogl_create_shader (CGL_VERTEX_SHADER);
- cogl_shader_source (priv->vertex_shader, priv->vertex_shader_source);
+
+ cogl_shader_source (priv->vertex_shader, priv->vertex_source);
cogl_shader_compile (priv->vertex_shader);
cogl_program_attach_shader (priv->program, priv->vertex_shader);
}
- if (priv->fragment_shader_source)
+
+ if (priv->fragment_is_glsl && priv->fragment_source)
{
GLint compiled = CGL_FALSE;
+
priv->fragment_shader = cogl_create_shader (CGL_FRAGMENT_SHADER);
- cogl_shader_source (priv->fragment_shader, priv->fragment_shader_source);
+
+ cogl_shader_source (priv->fragment_shader, priv->fragment_source);
cogl_shader_compile (priv->fragment_shader);
cogl_shader_get_parameteriv (priv->fragment_shader,
&compiled);
if (compiled != CGL_TRUE)
{
- gchar *buffer;
- gint max_length = 512;
-
- buffer = g_malloc (max_length);
- cogl_shader_get_info_log (priv->fragment_shader, max_length, buffer);
- g_print ("Shader compilation failed:\n%s", buffer);
- g_free (buffer);
- g_object_unref (self);
+ gchar error_buf[512];
+
+ cogl_shader_get_info_log (priv->fragment_shader, 512, error_buf);
+
+ g_set_error (error, CLUTTER_SHADER_ERROR,
+ CLUTTER_SHADER_ERROR_COMPILE,
+ "Shader compilation failed: %s",
+ error_buf);
+
return FALSE;
}
- cogl_program_attach_shader (priv->program, priv->fragment_shader);
+ else
+ cogl_program_attach_shader (priv->program, priv->fragment_shader);
}
+
cogl_program_link (priv->program);
+
return TRUE;
}
+/**
+ * clutter_shader_bind:
+ * @shader: a #ClutterShader
+ *
+ * FIXME
+ *
+ * Return value: FIXME
+ *
+ * Since: 0.6
+ */
gboolean
-clutter_shader_bind (ClutterShader *self)
+clutter_shader_bind (ClutterShader *shader,
+ GError **error)
{
ClutterShaderPrivate *priv;
-
- priv = self->priv;
+
+ g_return_val_if_fail (CLUTTER_IS_SHADER (shader), FALSE);
+
+ priv = shader->priv;
+
if (priv->bound)
return priv->bound;
- if (priv->glsl)
+ if ((priv->vertex_source && !priv->vertex_is_glsl) ||
+ (priv->fragment_source && !priv->fragment_is_glsl))
+ {
+ /* XXX: maybe this error message should be about only GLSL
+shaders supportes as of now
+ */
+ g_set_error (error, CLUTTER_SHADER_ERROR,
+ CLUTTER_SHADER_ERROR_NO_ASM,
+ "ASM shaders not supported");
+ priv->bound = FALSE;
+ return priv->bound;
+ }
+
+ if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
{
- priv->bound = bind_glsl_shader (self);
+ g_set_error (error, CLUTTER_SHADER_ERROR,
+ CLUTTER_SHADER_ERROR_NO_GLSL,
+ "GLSL shaders not supported");
+ priv->bound = FALSE;
+ return priv->bound;
}
+ priv->bound = bind_glsl_shader (shader, error);
+
+ if (priv->bound)
+ g_object_notify (G_OBJECT (shader), "bound");
+
return priv->bound;
}
+/**
+ * clutter_shader_release:
+ * @shader: a #ClutterShader
+ *
+ * FIXME
+ *
+ * Since: 0.6
+ */
void
-clutter_shader_release (ClutterShader *self)
+clutter_shader_release (ClutterShader *shader)
{
ClutterShaderPrivate *priv;
- priv = self->priv;
+ g_return_if_fail (CLUTTER_IS_SHADER (shader));
+
+ priv = shader->priv;
+
if (!priv->bound)
return;
g_assert (priv->program);
- if (priv->glsl)
- {
- if (priv->vertex_shader)
- cogl_shader_destroy (priv->vertex_shader);
- if (priv->fragment_shader)
- cogl_shader_destroy (priv->fragment_shader);
- if (priv->program)
- cogl_program_destroy (priv->program);
- priv->vertex_shader = 0;
- priv->fragment_shader = 0;
- priv->program = 0;
- }
+ if (priv->vertex_is_glsl && priv->vertex_shader)
+ cogl_shader_destroy (priv->vertex_shader);
+
+ if (priv->fragment_is_glsl && priv->fragment_shader)
+ cogl_shader_destroy (priv->fragment_shader);
+
+ if (priv->program)
+ cogl_program_destroy (priv->program);
+
+ priv->vertex_shader = 0;
+ priv->fragment_shader = 0;
+ priv->program = 0;
priv->bound = FALSE;
+
+ g_object_notify (G_OBJECT (shader), "bound");
}
-static void
-clutter_shader_finalize (GObject *object)
+/**
+ * clutter_shader_is_bound:
+ * @shader: a #ClutterShader
+ *
+ * FIXME
+ *
+ * Return value: FIXME
+ *
+ * Since: 0.6
+ */
+gboolean
+clutter_shader_is_bound (ClutterShader *shader)
{
- ClutterShader *shader;
- ClutterShaderPrivate *priv;
+ g_return_val_if_fail (CLUTTER_IS_SHADER (shader), FALSE);
- shader = CLUTTER_SHADER (object);
- priv = shader->priv;
+ return shader->priv->bound;
+}
- clutter_shader_release (shader);
+/**
+ * clutter_shader_set_is_enabled:
+ * @shader: a #ClutterShader
+ * @enabled: FIXME
+ *
+ * FIXME
+ *
+ * Since: 0.6
+ */
+void
+clutter_shader_set_is_enabled (ClutterShader *shader,
+ gboolean enabled)
+{
+ ClutterShaderPrivate *priv;
- shader_list = g_list_remove (shader_list, object);
+ g_return_if_fail (CLUTTER_IS_SHADER (shader));
- if (priv->fragment_shader_source)
- g_free (priv->fragment_shader_source);
- if (priv->vertex_shader_source)
- g_free (priv->vertex_shader_source);
+ priv = shader->priv;
- G_OBJECT_CLASS (clutter_shader_parent_class)->finalize (object);
-}
+ if (priv->is_enabled != enabled)
+ {
+ GError *error = NULL;
+ gboolean res;
+ res = clutter_shader_bind (shader, &error);
+ if (!res)
+ {
+ g_warning ("Unable to bind the shader: %s",
+ error ? error->message : "unknown error");
+ if (error)
+ g_error_free (error);
-void
-clutter_shader_enable (ClutterShader *self)
-{
- ClutterShaderPrivate *priv = self->priv;
+ return;
+ }
- clutter_shader_bind (self);
+ priv->is_enabled = enabled;
- cogl_program_use (priv->program);
+ if (priv->is_enabled)
+ cogl_program_use (priv->program);
+ else
+ cogl_program_use (0);
+
+ g_object_notify (G_OBJECT (shader), "enabled");
+ }
}
-void
-clutter_shader_disable (ClutterShader *self)
+/**
+ * clutter_shader_get_is_enabled:
+ * @shader: a #ClutterShader
+ *
+ * FIXME
+ *
+ * Return value: FIXME
+ *
+ * Since: 0.6
+ */
+gboolean
+clutter_shader_get_is_enabled (ClutterShader *shader)
{
- cogl_program_use (0);
+ g_return_val_if_fail (CLUTTER_IS_SHADER (shader), FALSE);
+
+ return shader->priv->is_enabled;
}
+/**
+ * clutter_shader_set_uniform_1f:
+ * @shader: a #ClutterShader
+ * @name: FIXME
+ * @value: FIXME
+ *
+ * FIXME
+ *
+ * Since: 0.6
+ */
void
-clutter_shader_set_uniform_1f (ClutterShader *self,
+clutter_shader_set_uniform_1f (ClutterShader *shader,
const gchar *name,
gfloat value)
{
- ClutterShaderPrivate *priv = self->priv;
+ ClutterShaderPrivate *priv;
GLint location = 0;
GLfloat foo = value;
- location =cogl_program_get_uniform_location (priv->program, name);
+ g_return_if_fail (CLUTTER_IS_SHADER (shader));
+
+ priv = shader->priv;
+
+ location = cogl_program_get_uniform_location (priv->program, name);
cogl_program_uniform_1f (location, foo);
}
+/**
+ * clutter_shader_release_all:
+ *
+ * FIXME
+ *
+ * Since: 0.6
+ */
void
clutter_shader_release_all (void)
{
- GList *iter;
- for (iter = shader_list; iter; iter = g_list_next (iter))
- {
- clutter_shader_release (iter->data);
- }
+ g_list_foreach (clutter_shaders_list,
+ (GFunc) clutter_shader_release,
+ NULL);
}
-static void
-clutter_shader_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- ClutterShader *shader;
- ClutterShaderPrivate *priv;
-
- shader = CLUTTER_SHADER(object);
- priv = shader->priv;
-
- switch (prop_id)
- {
- case PROP_VERTEX_SOURCE:
- if (priv->vertex_shader_source)
- {
- g_free (priv->vertex_shader_source);
- priv->vertex_shader_source = NULL;
- }
- priv->vertex_shader_source = g_value_dup_string (value);
- break;
- case PROP_FRAGMENT_SOURCE:
- if (priv->fragment_shader_source)
- {
- g_free (priv->fragment_shader_source);
- priv->fragment_shader_source = NULL;
- }
- priv->fragment_shader_source = g_value_dup_string (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_shader_source);
- break;
- case PROP_FRAGMENT_SOURCE:
- g_value_set_string (value, priv->fragment_shader_source);
- 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)
+/**
+ * clutter_shader_get_fragment_source:
+ * @shader: a #ClutterShader
+ *
+ * FIXME
+ *
+ * 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
+ */
+G_CONST_RETURN gchar *
+clutter_shader_get_fragment_source (ClutterShader *shader)
{
- GObject *object;
- ClutterShader *shader;
- ClutterShaderPrivate *priv;
-
- object = G_OBJECT_CLASS (clutter_shader_parent_class)->constructor (
- type, n_params, params);
- shader = CLUTTER_SHADER (object);
- priv = shader->priv;
-
- priv->glsl = !((priv->vertex_shader_source &&
- g_str_has_prefix (priv->vertex_shader_source, "!!ARBvp")) ||
- (priv->fragment_shader_source &&
- g_str_has_prefix (priv->fragment_shader_source, "!!ARBfp")));
- if (!priv->glsl)
- {
- g_warning ("ASM shader support not available");
- g_object_unref (object);
- return NULL;
- }
- if (priv->glsl && !clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
- {
- g_warning ("GLSL shaders not supported\n");
- g_object_unref (object);
- return NULL;
- }
-
- shader_list = g_list_prepend (shader_list, object);
- return object;
+ g_return_val_if_fail (CLUTTER_IS_SHADER (shader), NULL);
+ return shader->priv->fragment_source;
}
-ClutterShader *
-clutter_shader_new_from_strings (const gchar *vertex_shader_program,
- const gchar *fragment_shader_program)
+/**
+ * clutter_shader_get_vertex_source:
+ * @shader: a #ClutterShader
+ *
+ * FIXME
+ *
+ * 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
+ */
+G_CONST_RETURN gchar *
+clutter_shader_get_vertex_source (ClutterShader *shader)
{
- /* evil hack, since g_object_new would interpret a NULL passed as
- * a argument termination
- */
- if (vertex_shader_program &&
- fragment_shader_program)
- return g_object_new (CLUTTER_TYPE_SHADER,
- "vertex-source", vertex_shader_program,
- "fragment-source", fragment_shader_program,
- NULL);
- else if (fragment_shader_program)
- return g_object_new (CLUTTER_TYPE_SHADER,
- "fragment-source", fragment_shader_program,
- NULL);
- else if (vertex_shader_program)
- return g_object_new (CLUTTER_TYPE_SHADER,
- "vertex-source", vertex_shader_program,
- NULL);
- else {
- g_warning ("neither fragment nor vertex shader provided");
- return NULL;
- }
+ g_return_val_if_fail (CLUTTER_IS_SHADER (shader), NULL);
+ return shader->priv->vertex_source;
}
-ClutterShader *
-clutter_shader_new_from_files (const gchar *vertex_file,
- const gchar *fragment_file)
+GQuark
+clutter_shader_error_quark (void)
{
- ClutterShader *shader;
- gchar *vertex_shader_program = NULL;
- gchar *fragment_shader_program = NULL;
-
- g_assert (vertex_file != NULL ||
- fragment_file != NULL);
-
- if (vertex_file)
- {
- g_file_get_contents (vertex_file, &vertex_shader_program,
- NULL, NULL);
- }
- if (fragment_file)
- {
- g_file_get_contents (fragment_file, &fragment_shader_program,
- NULL, NULL);
- }
- shader = clutter_shader_new_from_strings (vertex_shader_program,
- fragment_shader_program);
-
- if (vertex_shader_program)
- {
- g_free (vertex_shader_program);
- }
- if (fragment_shader_program)
- {
- g_free (fragment_shader_program);
- }
- return shader;
+ return g_quark_from_static_string ("clutter-shader-error");
}
-/* #define TEST_GROUP 1 */
+/*#define TEST_GROUP */
#include <clutter/clutter.h>
{NULL, NULL}
};
-static gint shader_no=0;
+static gint shader_no = 0;
+ ClutterShader *shader;
static gboolean
button_release_cb (ClutterActor *actor,
gpointer data)
{
gint new_no;
+
if (event->button.button == 1)
{
- new_no = shader_no-1;
+ new_no = shader_no - 1;
}
else
{
- new_no = shader_no+1;
+ new_no = shader_no + 1;
}
if (new_no >= 0 && shaders[new_no].name)
{
ClutterShader *shader;
+ GError *error;
shader_no = new_no;
- g_print ("setting shaders[%i] named '%s'\n", shader_no, shaders[shader_no].name);
- shader = clutter_shader_new_from_strings (NULL, shaders[shader_no].source);
- clutter_actor_apply_shader (actor, shader);
+ g_print ("setting shaders[%i] named '%s'\n",
+ shader_no,
+ shaders[shader_no].name);
+
+ shader = clutter_shader_new ();
- clutter_actor_set_shader_param (actor, "radius", 3.0);
- clutter_redraw();
+ error = NULL;
+ g_object_set (G_OBJECT (shader), "fragment-source", shaders[shader_no].source, NULL);
+
+ /* try to bind the shader, provoking an error we catch if there is issues
+ * with the shader sources we've provided. At a later stage it should be possible to
+ * iterate through a set of alternate shader sources (glsl -> asm -> cg?) and the one
+ * that succesfully compiles is used.
+ */
+ clutter_shader_bind (shader, &error);
+
+ if (error)
+ {
+ g_print ("unable to set shaders[%i] named '%s': %s",
+ shader_no, shaders[shader_no].name,
+ error->message);
+ g_error_free (error);
+ clutter_actor_apply_shader (actor, NULL);
+ }
+ else
+ {
+ clutter_actor_apply_shader (actor, shader);
+ clutter_actor_set_shader_param (actor, "radius", 3.0);
+ }
}
return FALSE;
}
ClutterColor stage_color = { 0x61, 0x64, 0x8c, 0xff };
GdkPixbuf *pixbuf;
GError *error;
- ClutterShader *shader;
-
- error = NULL;
clutter_init (&argc, &argv);
- g_print ("applying shaders[%i] named '%s'\n", shader_no, shaders[shader_no].name);
- shader = clutter_shader_new_from_strings (NULL, shaders[shader_no].source);
stage = clutter_stage_get_default ();
clutter_actor_set_size (stage, 512, 384);
- pixbuf = gdk_pixbuf_new_from_file ("redhand.png", NULL);
+ g_print ("applying shaders[%i] named '%s'\n",
+ shader_no,
+ shaders[shader_no].name);
+
+ shader = clutter_shader_new ();
+
+ error = NULL;
+ clutter_shader_set_fragment_source (shader, shaders[shader_no].source, NULL);
+ clutter_shader_bind (shader, &error);
+ if (error)
+ {
+ g_print ("unable to load shaders[%d] named '%s': %s\n",
+ shader_no,
+ shaders[shader_no].name,
+ error->message);
+ g_error_free (error);
+
+ return EXIT_FAILURE;
+ }
+ pixbuf = gdk_pixbuf_new_from_file ("redhand.png", &error);
if (!pixbuf)
- g_error("pixbuf load failed");
+ g_error("pixbuf load failed: %s", error ? error->message : "Unknown");
clutter_stage_set_title (CLUTTER_STAGE (stage), "Shader Test");
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
actor = clutter_group_new ();
{
ClutterActor *child1, *child2, *child3, *child4;
- ClutterColor color={0xff, 0x22, 0x66, 0x99};
+ ClutterColor color = { 0xff, 0x22, 0x66, 0x99 };
child1 = clutter_texture_new_from_pixbuf (pixbuf);
child2 = clutter_texture_new_from_pixbuf (pixbuf);
clutter_group_add (CLUTTER_GROUP (actor), child2);
clutter_group_add (CLUTTER_GROUP (actor), child3);
clutter_group_add (CLUTTER_GROUP (actor), child4);
+
clutter_actor_show_all (actor);
}
#endif
+
+ clutter_actor_apply_shader (actor, shader);
clutter_actor_set_position (actor, 100, 100);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), actor);
- clutter_actor_apply_shader (actor, shader);
clutter_actor_set_shader_param (actor, "brightness", 0.4);
clutter_actor_set_shader_param (actor, "contrast", -1.9);
clutter_main ();
- return 0;
+ return EXIT_SUCCESS;
}