diff --git a/ChangeLog b/ChangeLog index 295c607da..a2487707a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,42 @@ +2008-11-18 Emmanuele Bassi + + Bug 1049 - Clutter doesn't support most GLSL uniforms (patch + by Chris Lord and Neil Roberts) + + * README: Update release notes. + + * clutter/Makefile.am: + * clutter/clutter-shader-types.[ch]: Add GValue types for + shader values. + + * clutter/clutter-actor.[ch]: Update the shader API to use + the newly added GValue support for GLSL shader uniform + setters. + + * clutter/clutter-shader.[ch]: Add float and integer convenience + API for single value GLSL uniform setters. + + * clutter/cogl/cogl-shader.h: Add new uniform setters. + + * clutter/cogl/gl/cogl-context.c: + * clutter/cogl/gl/cogl-context.h: + * clutter/cogl/gl/cogl-defines.h.in: + * clutter/cogl/gl/cogl-program.c: + * clutter/cogl/gl/cogl.c: Update the GL implementation of COGL + to handle the GLSL uniform setters. + + * clutter/cogl/gles/cogl-gles2-wrapper.c: + * clutter/cogl/gles/cogl-gles2-wrapper.h: + * clutter/cogl/gles/cogl-internal.h: + * clutter/cogl/gles/cogl-program.c: Update the GLES 2.0 implementation + of COGL to handle the GLSL uniform setters. + + * doc/reference/clutter/clutter-sections.txt: + * doc/reference/cogl/cogl-sections.txt: Update the documentation. + + * tests/interactive/test-fbo.c: + * tests/interactive/test-shader.c: Update the shader tests. + 2008-11-18 Emmanuele Bassi * clutter/clutter-texture.c: diff --git a/README b/README index 27da12d13..5f0518e66 100644 --- a/README +++ b/README @@ -170,6 +170,12 @@ wanting to port to newer releases (See NEWS for general new feature info). Release Notes for Clutter 1.0 ------------------------------- +* The clutter_actor_set_shader_param() function now takes a + GValue, which can be set using the clutter_value_set_shader() + family of functions. The floating point wrapper has been + rename clutter_actor_set_shader_param_float() to match the newly + added clutter_actor_set_shader_param_int(). + * The Pango renderer API has been exposed as public API, after a full rename from PangoClutter to CoglPango, to avoid namespace collisions with upstream Pango. The Pango font map, renderer and diff --git a/clutter/Makefile.am b/clutter/Makefile.am index d82ba2ed3..6bf2c5caf 100644 --- a/clutter/Makefile.am +++ b/clutter/Makefile.am @@ -81,6 +81,7 @@ source_h = \ $(srcdir)/clutter-script.h \ $(srcdir)/clutter-scriptable.h \ $(srcdir)/clutter-shader.h \ + $(srcdir)/clutter-shader-types.h \ $(srcdir)/clutter-stage.h \ $(srcdir)/clutter-stage-manager.h \ $(srcdir)/clutter-texture.h \ @@ -171,6 +172,7 @@ source_c = \ clutter-script-parser.c \ clutter-scriptable.c \ clutter-shader.c \ + clutter-shader-types.c \ clutter-stage.c \ clutter-stage-manager.c \ clutter-stage-window.c \ diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index ed6d59ba7..f31a53ff6 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -7085,28 +7085,22 @@ clutter_actor_box_get_type (void) /******************************************************************************/ -typedef struct _BoxedFloat BoxedFloat; - -struct _BoxedFloat -{ - gfloat value; -}; - -static void -boxed_float_free (gpointer data) -{ - if (G_LIKELY (data)) - g_slice_free (BoxedFloat, data); -} - struct _ShaderData { ClutterShader *shader; - GHashTable *float1f_hash; /*< list of values that should be set + GHashTable *value_hash; /*< list of GValue's that should be set * on the shader before each paint cycle */ }; +static void +shader_value_free (gpointer data) +{ + GValue *var = data; + g_value_unset (var); + g_slice_free (GValue, var); +} + static void destroy_shader_data (ClutterActor *self) { @@ -7122,10 +7116,10 @@ destroy_shader_data (ClutterActor *self) shader_data->shader = NULL; } - if (shader_data->float1f_hash) + if (shader_data->value_hash) { - g_hash_table_destroy (shader_data->float1f_hash); - shader_data->float1f_hash = NULL; + g_hash_table_destroy (shader_data->value_hash); + shader_data->value_hash = NULL; } g_free (shader_data); @@ -7196,10 +7190,10 @@ clutter_actor_set_shader (ClutterActor *self, if (!shader_data) { actor_priv->shader_data = shader_data = g_new0 (ShaderData, 1); - shader_data->float1f_hash = + shader_data->value_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, - boxed_float_free); + shader_value_free); } if (shader_data->shader) { @@ -7224,10 +7218,10 @@ set_each_param (gpointer key, gpointer value, gpointer user_data) { - ClutterShader *shader = CLUTTER_SHADER (user_data); - BoxedFloat *box = value; + ClutterShader *shader = user_data; + GValue *var = value; - clutter_shader_set_uniform_1f (shader, key, box->value); + clutter_shader_set_uniform (shader, (const gchar *)key, var); } static void @@ -7252,7 +7246,7 @@ clutter_actor_shader_pre_paint (ClutterActor *actor, { clutter_shader_set_is_enabled (shader, TRUE); - g_hash_table_foreach (shader_data->float1f_hash, set_each_param, shader); + g_hash_table_foreach (shader_data->value_hash, set_each_param, shader); if (!repeat) context->shaders = g_slist_prepend (context->shaders, actor); @@ -7301,19 +7295,24 @@ clutter_actor_shader_post_paint (ClutterActor *actor) * Sets the value for a named parameter of the shader applied * to @actor. * - * Since: 0.6 + * Since: 1.0 */ void clutter_actor_set_shader_param (ClutterActor *self, const gchar *param, - gfloat value) + const GValue *value) { ClutterActorPrivate *priv; ShaderData *shader_data; - BoxedFloat *box; + GValue *var; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (param != 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 = self->priv; shader_data = priv->shader_data; @@ -7321,14 +7320,67 @@ clutter_actor_set_shader_param (ClutterActor *self, if (!shader_data) return; - box = g_slice_new (BoxedFloat); - box->value = value; - g_hash_table_insert (shader_data->float1f_hash, g_strdup (param), box); + var = g_slice_new0 (GValue); + g_value_init (var, G_VALUE_TYPE (value)); + g_value_copy (value, var); + g_hash_table_insert (shader_data->value_hash, g_strdup (param), var); if (CLUTTER_ACTOR_IS_VISIBLE (self)) clutter_actor_queue_redraw (self); } +/** + * clutter_actor_set_shader_param_float: + * @self: a #ClutterActor + * @param: the name of the parameter + * @value: the value of the parameter + * + * Sets the value for a named float parameter of the shader applied + * to @actor. + * + * Since: 0.8 + */ +void +clutter_actor_set_shader_param_float (ClutterActor *self, + const gchar *param, + gfloat value) +{ + GValue var = { 0, }; + + g_value_init (&var, G_TYPE_FLOAT); + g_value_set_float (&var, value); + + clutter_actor_set_shader_param (self, param, &var); + + g_value_unset (&var); +} + +/** + * clutter_actor_set_shader_param_int: + * @self: a #ClutterActor + * @param: the name of the parameter + * @value: the value of the parameter + * + * Sets the value for a named int parameter of the shader applied to + * @actor. + * + * Since: 0.8 + */ +void +clutter_actor_set_shader_param_int (ClutterActor *self, + const gchar *param, + gint value) +{ + GValue var = { 0, }; + + g_value_init (&var, G_TYPE_INT); + g_value_set_int (&var, value); + + clutter_actor_set_shader_param (self, param, &var); + + g_value_unset (&var); +} + /** * clutter_actor_is_rotated: * @self: a #ClutterActor diff --git a/clutter/clutter-actor.h b/clutter/clutter-actor.h index 5b25de576..021460b78 100644 --- a/clutter/clutter-actor.h +++ b/clutter/clutter-actor.h @@ -504,6 +504,12 @@ gboolean clutter_actor_set_shader (ClutterActor ClutterShader *shader); ClutterShader * clutter_actor_get_shader (ClutterActor *self); void clutter_actor_set_shader_param (ClutterActor *self, + const gchar *param, + const GValue *value); +void clutter_actor_set_shader_param_int (ClutterActor *self, + const gchar *param, + gint value); +void clutter_actor_set_shader_param_float (ClutterActor *self, const gchar *param, gfloat value); diff --git a/clutter/clutter-shader-types.c b/clutter/clutter-shader-types.c new file mode 100644 index 000000000..f19afac74 --- /dev/null +++ b/clutter/clutter-shader-types.c @@ -0,0 +1,563 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Authored By Matthew Allum + * Chris Lord + * + * Copyright (C) 2008 OpenedHand + * + * 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "clutter-shader-types.h" +#include "clutter-private.h" + +static GTypeInfo shader_float_info = { + 0, + NULL, + NULL, + NULL, + NULL, + NULL, + 0, + 0, + NULL, + NULL, +}; + +static GTypeFundamentalInfo shader_float_finfo = { 0, }; + +static GTypeInfo shader_int_info = { + 0, + NULL, + NULL, + NULL, + NULL, + NULL, + 0, + 0, + NULL, + NULL, +}; + +static GTypeFundamentalInfo shader_int_finfo = { 0, }; + +static GTypeInfo shader_matrix_info = { + 0, + NULL, + NULL, + NULL, + NULL, + NULL, + 0, + 0, + NULL, + NULL, +}; + +static GTypeFundamentalInfo shader_matrix_finfo = { 0, }; + +struct _ClutterShaderFloat +{ + gint size; + GLfloat value[4]; +}; + +struct _ClutterShaderInt +{ + gint size; + COGLint value[4]; +}; + +struct _ClutterShaderMatrix +{ + gint size; + GLfloat value[16]; +}; + +static gpointer +clutter_value_peek_pointer (const GValue *value) +{ + return value->data[0].v_pointer; +} + +/* Float */ + +static void +clutter_value_init_shader_float (GValue *value) +{ + value->data[0].v_pointer = g_slice_new0 (ClutterShaderFloat); +} + +static void +clutter_value_free_shader_float (GValue *value) +{ + g_slice_free (ClutterShaderFloat, value->data[0].v_pointer); +} + +static void +clutter_value_copy_shader_float (const GValue *src, + GValue *dest) +{ + dest->data[0].v_pointer = + g_slice_dup (ClutterShaderFloat, src->data[0].v_pointer); +} + +static gchar * +clutter_value_collect_shader_float (GValue *value, + guint n_collect_values, + GTypeCValue *collect_values, + guint collect_flags) +{ + gint float_count = collect_values[0].v_int; + const float *floats = collect_values[1].v_pointer; + + if (!floats) + return g_strdup_printf ("value location for `%s' passed as NULL", + G_VALUE_TYPE_NAME (value)); + + clutter_value_init_shader_float (value); + clutter_value_set_shader_float (value, float_count, floats); + + return NULL; +} + +static gchar * +clutter_value_lcopy_shader_float (const GValue *value, + guint n_collect_values, + GTypeCValue *collect_values, + guint collect_flags) +{ + gint *float_count = collect_values[0].v_pointer; + float **floats = collect_values[1].v_pointer; + ClutterShaderFloat *shader_float = value->data[0].v_pointer; + + if (!float_count || !floats) + return g_strdup_printf ("value location for `%s' passed as NULL", + G_VALUE_TYPE_NAME (value)); + + *float_count = shader_float->size; + *floats = g_memdup (shader_float->value, shader_float->size * sizeof (float)); + + return NULL; +} + +static const GTypeValueTable _clutter_shader_float_value_table = { + clutter_value_init_shader_float, + clutter_value_free_shader_float, + clutter_value_copy_shader_float, + clutter_value_peek_pointer, + "ip", + clutter_value_collect_shader_float, + "pp", + clutter_value_lcopy_shader_float +}; + +GType +clutter_shader_float_get_type (void) +{ + static GType _clutter_shader_float_type = 0; + + if (G_UNLIKELY (_clutter_shader_float_type == 0)) + { + shader_float_info.value_table = & _clutter_shader_float_value_table; + _clutter_shader_float_type = + g_type_register_fundamental (g_type_fundamental_next (), + I_("ClutterShaderFloat"), + &shader_float_info, + &shader_float_finfo, 0); + } + + return _clutter_shader_float_type; +} + + +/* Integer */ + +static void +clutter_value_init_shader_int (GValue *value) +{ + value->data[0].v_pointer = g_slice_new0 (ClutterShaderInt); +} + +static void +clutter_value_free_shader_int (GValue *value) +{ + g_slice_free (ClutterShaderInt, value->data[0].v_pointer); +} + +static void +clutter_value_copy_shader_int (const GValue *src, + GValue *dest) +{ + dest->data[0].v_pointer = + g_slice_dup (ClutterShaderInt, src->data[0].v_pointer); +} + +static gchar * +clutter_value_collect_shader_int (GValue *value, + guint n_collect_values, + GTypeCValue *collect_values, + guint collect_flags) +{ + gint int_count = collect_values[0].v_int; + const COGLint *ints = collect_values[1].v_pointer; + + if (!ints) + return g_strdup_printf ("value location for `%s' passed as NULL", + G_VALUE_TYPE_NAME (value)); + + clutter_value_init_shader_int (value); + clutter_value_set_shader_int (value, int_count, ints); + + return NULL; +} + +static gchar * +clutter_value_lcopy_shader_int (const GValue *value, + guint n_collect_values, + GTypeCValue *collect_values, + guint collect_flags) +{ + gint *int_count = collect_values[0].v_pointer; + COGLint **ints = collect_values[1].v_pointer; + ClutterShaderInt *shader_int = value->data[0].v_pointer; + + if (!int_count || !ints) + return g_strdup_printf ("value location for `%s' passed as NULL", + G_VALUE_TYPE_NAME (value)); + + *int_count = shader_int->size; + *ints = g_memdup (shader_int->value, shader_int->size * sizeof (COGLint)); + + return NULL; +} + +static const GTypeValueTable _clutter_shader_int_value_table = { + clutter_value_init_shader_int, + clutter_value_free_shader_int, + clutter_value_copy_shader_int, + clutter_value_peek_pointer, + "ip", + clutter_value_collect_shader_int, + "pp", + clutter_value_lcopy_shader_int +}; + +GType +clutter_shader_int_get_type (void) +{ + static GType _clutter_shader_int_type = 0; + + if (G_UNLIKELY (_clutter_shader_int_type == 0)) + { + shader_int_info.value_table = & _clutter_shader_int_value_table; + _clutter_shader_int_type = + g_type_register_fundamental (g_type_fundamental_next (), + I_("ClutterShaderInt"), + &shader_int_info, + &shader_int_finfo, 0); + } + + return _clutter_shader_int_type; +} + + +/* Matrix */ + +static void +clutter_value_init_shader_matrix (GValue *value) +{ + value->data[0].v_pointer = g_slice_new0 (ClutterShaderMatrix); +} + +static void +clutter_value_free_shader_matrix (GValue *value) +{ + g_slice_free (ClutterShaderMatrix, value->data[0].v_pointer); +} + +static void +clutter_value_copy_shader_matrix (const GValue *src, + GValue *dest) +{ + dest->data[0].v_pointer = + g_slice_dup (ClutterShaderMatrix, src->data[0].v_pointer); +} + +static gchar * +clutter_value_collect_shader_matrix (GValue *value, + guint n_collect_values, + GTypeCValue *collect_values, + guint collect_flags) +{ + gint float_count = collect_values[0].v_int; + const float *floats = collect_values[1].v_pointer; + + if (!floats) + return g_strdup_printf ("value location for `%s' passed as NULL", + G_VALUE_TYPE_NAME (value)); + + clutter_value_init_shader_matrix (value); + clutter_value_set_shader_matrix (value, float_count, floats); + + return NULL; +} + +static gchar * +clutter_value_lcopy_shader_matrix (const GValue *value, + guint n_collect_values, + GTypeCValue *collect_values, + guint collect_flags) +{ + gint *float_count = collect_values[0].v_pointer; + float **floats = collect_values[1].v_pointer; + ClutterShaderFloat *shader_float = value->data[0].v_pointer; + + if (!float_count || !floats) + return g_strdup_printf ("value location for `%s' passed as NULL", + G_VALUE_TYPE_NAME (value)); + + *float_count = shader_float->size; + *floats = g_memdup (shader_float->value, + shader_float->size * shader_float->size * sizeof (float)); + + return NULL; +} + +static const GTypeValueTable _clutter_shader_matrix_value_table = { + clutter_value_init_shader_matrix, + clutter_value_free_shader_matrix, + clutter_value_copy_shader_matrix, + clutter_value_peek_pointer, + "ip", + clutter_value_collect_shader_matrix, + "pp", + clutter_value_lcopy_shader_matrix +}; + +GType +clutter_shader_matrix_get_type (void) +{ + static GType _clutter_shader_matrix_type = 0; + + if (G_UNLIKELY (_clutter_shader_matrix_type == 0)) + { + shader_matrix_info.value_table = & _clutter_shader_matrix_value_table; + _clutter_shader_matrix_type = + g_type_register_fundamental (g_type_fundamental_next (), + I_("ClutterShaderMatrix"), + &shader_matrix_info, + &shader_matrix_finfo, 0); + } + + return _clutter_shader_matrix_type; +} + + +/* Utility functions */ + +/** + * clutter_value_set_shader_float: + * @value: a #GValue + * @size: number of floating point values in @floats + * @floats: an array of floating point values + * + * Sets @floats as the contents of @value. The passed #GValue + * must have been initialized using %CLUTTER_TYPE_SHADER_FLOAT. + * + * Since: 0.8 + */ +void +clutter_value_set_shader_float (GValue *value, + gint size, + const gfloat *floats) +{ + ClutterShaderFloat *shader_float; + gint i; + + g_return_if_fail (CLUTTER_VALUE_HOLDS_SHADER_FLOAT (value)); + + shader_float = value->data[0].v_pointer; + + shader_float->size = size; + + for (i = 0; i < size; i++) + shader_float->value[i] = floats[i]; +} + +/** + * clutter_value_set_shader_int: + * @value: a #GValue + * @size: number of integer values in @ints + * @ints: an array of integer values + * + * Sets @ints as the contents of @value. The passed #GValue + * must have been initialized using %CLUTTER_TYPE_SHADER_INT. + * + * Since: 0.8 + */ +void +clutter_value_set_shader_int (GValue *value, + gint size, + const gint *ints) +{ + ClutterShaderInt *shader_int; + gint i; + + g_return_if_fail (CLUTTER_VALUE_HOLDS_SHADER_INT (value)); + + shader_int = value->data[0].v_pointer; + + shader_int->size = size; + + for (i = 0; i < size; i++) + shader_int->value[i] = ints[i]; +} + +/** + * clutter_value_set_shader_matrix: + * @value: a #GValue + * @size: number of floating point values in @floats + * @matrix: a matrix of floating point values + * + * Sets @matrix as the contents of @value. The passed #GValue + * must have been initialized using %CLUTTER_TYPE_SHADER_MATRIX. + * + * Since: 0.8 + */ +void +clutter_value_set_shader_matrix (GValue *value, + gint size, + const gfloat *matrix) +{ + ClutterShaderMatrix *shader_matrix; + gint i; + + g_return_if_fail (CLUTTER_VALUE_HOLDS_SHADER_MATRIX (value)); + + shader_matrix = value->data[0].v_pointer; + + shader_matrix->size = size; + + for (i = 0; i < size * size; i++) + shader_matrix->value[i] = matrix[i]; +} + +/** + * clutter_value_get_shader_float: + * @value: a #GValue + * @length: return location for the number of returned floating + * point values, or %NULL + * + * Retrieves the list of floating point values stored inside + * the passed #GValue. @value must have been initialized with + * %CLUTTER_TYPE_SHADER_FLOAT. + * + * Return value: the pointer to a list of floating point values. + * The returned value is owned by the #GValue and should never + * be modified or freed. + * + * Since: 0.8 + */ +G_CONST_RETURN gfloat * +clutter_value_get_shader_float (const GValue *value, + gsize *length) +{ + ClutterShaderFloat *shader_float; + + g_return_val_if_fail (CLUTTER_VALUE_HOLDS_SHADER_FLOAT (value), 0); + + shader_float = value->data[0].v_pointer; + + if (length) + *length = shader_float->size; + + return shader_float->value; +} + +/** + * clutter_value_get_shader_int: + * @value: a #GValue + * @length: return location for the number of returned integer + * values, or %NULL + * + * Retrieves the list of integer values stored inside the passed + * #GValue. @value must have been initialized with + * %CLUTTER_TYPE_SHADER_INT. + * + * Return value: the pointer to a list of integer values. + * The returned value is owned by the #GValue and should never + * be modified or freed. + * + * Since: 0.8 + */ +G_CONST_RETURN COGLint * +clutter_value_get_shader_int (const GValue *value, + gsize *length) +{ + ClutterShaderInt *shader_int; + + g_return_val_if_fail (CLUTTER_VALUE_HOLDS_SHADER_INT (value), 0); + + shader_int = value->data[0].v_pointer; + + if (length) + *length = shader_int->size; + + return shader_int->value; +} + +/** + * clutter_value_get_shader_matrix: + * @value: a #GValue + * @length: return location for the number of returned floating + * point values, or %NULL + * + * Retrieves a matrix of floating point values stored inside + * the passed #GValue. @value must have been initialized with + * %CLUTTER_TYPE_SHADER_MATRIX. + * + * Return value: the pointer to a matrix of floating point values. + * The returned value is owned by the #GValue and should never + * be modified or freed. + * + * Since: 0.8 + */ +G_CONST_RETURN gfloat * +clutter_value_get_shader_matrix (const GValue *value, + gsize *length) +{ + ClutterShaderMatrix *shader_matrix; + + g_return_val_if_fail (CLUTTER_VALUE_HOLDS_SHADER_MATRIX (value), 0); + + shader_matrix = value->data[0].v_pointer; + + if (length) + *length = shader_matrix->size; + + return shader_matrix->value; +} diff --git a/clutter/clutter-shader-types.h b/clutter/clutter-shader-types.h new file mode 100644 index 000000000..1c9e89ff8 --- /dev/null +++ b/clutter/clutter-shader-types.h @@ -0,0 +1,96 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Authored By Matthew Allum + * + * Copyright (C) 2008 Intel Corporation. + * + * 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 . + */ + +#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __CLUTTER_SHADER_TYPES_H__ +#define __CLUTTER_SHADER_TYPES_H__ + +#include +#include + +G_BEGIN_DECLS + +#define CLUTTER_TYPE_SHADER_FLOAT (clutter_shader_float_get_type ()) +#define CLUTTER_TYPE_SHADER_INT (clutter_shader_int_get_type ()) +#define CLUTTER_TYPE_SHADER_MATRIX (clutter_shader_matrix_get_type ()) + +typedef struct _ClutterShaderFloat ClutterShaderFloat; +typedef struct _ClutterShaderInt ClutterShaderInt; +typedef struct _ClutterShaderMatrix ClutterShaderMatrix; + +/** + * CLUTTER_VALUE_HOLDS_SHADER_FLOAT: + * @x: a #GValue + * + * Evaluates to %TRUE if @x holds a #ClutterShaderFloat. + * + * Since: 1.0 + */ +#define CLUTTER_VALUE_HOLDS_SHADER_FLOAT(x) (G_VALUE_HOLDS ((x), CLUTTER_TYPE_SHADER_FLOAT)) + +/** + * CLUTTER_VALUE_HOLDS_SHADER_INT: + * @x: a #GValue + * + * Evaluates to %TRUE if @x holds a #ClutterShaderInt. + * + * Since: 1.0 + */ +#define CLUTTER_VALUE_HOLDS_SHADER_INT(x) (G_VALUE_HOLDS ((x), CLUTTER_TYPE_SHADER_INT)) + +/** + * CLUTTER_VALUE_HOLDS_SHADER_MATRIX: + * @x: a #GValue + * + * Evaluates to %TRUE if @x holds a #ClutterShaderMatrix. + * + * Since: 1.0 + */ +#define CLUTTER_VALUE_HOLDS_SHADER_MATRIX(x) (G_VALUE_HOLDS ((x), CLUTTER_TYPE_SHADER_MATRIX)) + +GType clutter_shader_float_get_type (void) G_GNUC_CONST; +GType clutter_shader_int_get_type (void) G_GNUC_CONST; +GType clutter_shader_matrix_get_type (void) G_GNUC_CONST; + +void clutter_value_set_shader_float (GValue *value, + gint size, + const gfloat *floats); +void clutter_value_set_shader_int (GValue *value, + gint size, + const gint *ints); +void clutter_value_set_shader_matrix (GValue *value, + gint size, + const gfloat *matrix); +G_CONST_RETURN gfloat * clutter_value_get_shader_float (const GValue *value, + gsize *length); +G_CONST_RETURN COGLint *clutter_value_get_shader_int (const GValue *value, + gsize *length); +G_CONST_RETURN GLfloat *clutter_value_get_shader_matrix (const GValue *value, + gsize *length); + +G_END_DECLS + +#endif /* __CLUTTER_SHADER_TYPES_H__ */ diff --git a/clutter/clutter-shader.c b/clutter/clutter-shader.c index 7ffefb3d6..7346bd4fe 100644 --- a/clutter/clutter-shader.c +++ b/clutter/clutter-shader.c @@ -70,7 +70,6 @@ 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; @@ -95,9 +94,6 @@ enum 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) { @@ -193,7 +189,6 @@ clutter_shader_constructor (GType type, return object; } - static void clutter_shader_class_init (ClutterShaderClass *klass) { @@ -341,8 +336,8 @@ clutter_shader_set_fragment_source (ClutterShader *shader, g_free (priv->fragment_source); - CLUTTER_NOTE (SHADER, "setting fragment shader (GLSL:%s, len:%" - G_GSSIZE_FORMAT ")", + CLUTTER_NOTE (SHADER, + "setting fragment shader (GLSL:%s, len:%" G_GSSIZE_FORMAT ")", is_glsl ? "yes" : "no", length); @@ -387,8 +382,8 @@ clutter_shader_set_vertex_source (ClutterShader *shader, g_free (priv->vertex_source); - CLUTTER_NOTE (SHADER, "setting vertex shader (GLSL:%s, len:%" - G_GSSIZE_FORMAT ")", + CLUTTER_NOTE (SHADER, + "setting vertex shader (GLSL:%s, len:%" G_GSSIZE_FORMAT ")", is_glsl ? "yes" : "no", length); @@ -668,6 +663,7 @@ clutter_shader_set_uniform_1f (ClutterShader *shader, GLfloat foo = value; g_return_if_fail (CLUTTER_IS_SHADER (shader)); + g_return_if_fail (name != NULL); priv = shader->priv; @@ -675,13 +671,83 @@ clutter_shader_set_uniform_1f (ClutterShader *shader, cogl_program_uniform_1f (location, foo); } +/** + * 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 + */ +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_uniform_float (location, size, 1, floats); + } + else if (CLUTTER_VALUE_HOLDS_SHADER_INT (value)) + { + const COGLint *ints; + + ints = clutter_value_get_shader_int (value, &size); + cogl_program_uniform_int (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_uniform_matrix (location, size, 1, FALSE, matrix); + } + else if (G_VALUE_HOLDS_FLOAT (value)) + { + GLfloat float_val = g_value_get_float (value); + + cogl_program_uniform_float (location, 1, 1, &float_val); + } + else if (G_VALUE_HOLDS_INT (value)) + { + COGLint int_val = g_value_get_int (value); + + cogl_program_uniform_int (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. - * - * Since: 0.6 */ void _clutter_shader_release_all (void) @@ -730,6 +796,57 @@ clutter_shader_get_vertex_source (ClutterShader *shader) return shader->priv->vertex_source; } +/** + * clutter_shader_get_cogl_program: + * @shader: a #ClutterShader + * + * Retrieves the underlying #CoglHandle for the shader program. + * + * Return value: A #CoglHandle for the shader program, or %NULL + * + * Since: 1.0 + */ +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: A #CoglHandle for the fragment shader, or %NULL + * + * Since: 1.0 + */ +CoglHandle +clutter_shader_get_cogl_fragment_shader (ClutterShader *shader) +{ + g_return_val_if_fail (CLUTTER_IS_SHADER (shader), NULL); + return shader->priv->fragment_shader; +} + +/** + * clutter_shader_get_cogl_vertex_shader: + * @shader: a #ClutterShader + * + * Retrieves the underlying #CoglHandle for the vertex shader. + * + * Return value: A #CoglHandle for the vertex shader, or %NULL + * + * Since: 1.0 + */ +CoglHandle +clutter_shader_get_cogl_vertex_shader (ClutterShader *shader) +{ + g_return_val_if_fail (CLUTTER_IS_SHADER (shader), NULL); + return shader->priv->vertex_shader; +} + GQuark clutter_shader_error_quark (void) { diff --git a/clutter/clutter-shader.h b/clutter/clutter-shader.h index f4bdb7c74..347c19151 100644 --- a/clutter/clutter-shader.h +++ b/clutter/clutter-shader.h @@ -29,7 +29,7 @@ #ifndef __CLUTTER_SHADER_H__ #define __CLUTTER_SHADER_H__ -#include +#include G_BEGIN_DECLS @@ -75,34 +75,45 @@ struct _ClutterShaderClass GObjectClass parent_class; }; -GQuark clutter_shader_error_quark (void); -GType clutter_shader_get_type (void) G_GNUC_CONST; +GQuark clutter_shader_error_quark (void); +GType clutter_shader_get_type (void) G_GNUC_CONST; -ClutterShader * clutter_shader_new (void); +ClutterShader * clutter_shader_new (void); -void clutter_shader_set_is_enabled (ClutterShader *shader, - gboolean enabled); -gboolean clutter_shader_get_is_enabled (ClutterShader *shader); +void clutter_shader_set_is_enabled (ClutterShader *shader, + gboolean enabled); +gboolean clutter_shader_get_is_enabled (ClutterShader *shader); -gboolean clutter_shader_compile (ClutterShader *shader, - GError **error); -void clutter_shader_release (ClutterShader *shader); -gboolean clutter_shader_is_compiled (ClutterShader *shader); +gboolean clutter_shader_compile (ClutterShader *shader, + GError **error); +void clutter_shader_release (ClutterShader *shader); +gboolean clutter_shader_is_compiled (ClutterShader *shader); -void clutter_shader_set_vertex_source (ClutterShader *shader, - const gchar *data, - gssize length); -void clutter_shader_set_fragment_source (ClutterShader *shader, - const gchar *data, - gssize length); +void clutter_shader_set_vertex_source (ClutterShader *shader, + const gchar *data, + gssize length); +void clutter_shader_set_fragment_source (ClutterShader *shader, + const gchar *data, + gssize length); -G_CONST_RETURN gchar *clutter_shader_get_vertex_source (ClutterShader *shader); -G_CONST_RETURN gchar *clutter_shader_get_fragment_source (ClutterShader *shader); +G_CONST_RETURN gchar *clutter_shader_get_vertex_source (ClutterShader *shader); +G_CONST_RETURN gchar *clutter_shader_get_fragment_source (ClutterShader *shader); -void clutter_shader_set_uniform_1f (ClutterShader *shader, - const gchar *name, - gfloat value); -/* should be private and internal */ +void clutter_shader_set_uniform (ClutterShader *shader, + const gchar *name, + const GValue *value); + +CoglHandle clutter_shader_get_cogl_program (ClutterShader *shader); +CoglHandle clutter_shader_get_cogl_fragment_shader (ClutterShader *shader); +CoglHandle clutter_shader_get_cogl_vertex_shader (ClutterShader *shader); + +#ifndef CLUTTER_DISABLE_DEPRECATED +void clutter_shader_set_uniform_1f (ClutterShader *shader, + const gchar *name, + gfloat value); +#endif + +/* private */ void _clutter_shader_release_all (void); G_END_DECLS diff --git a/clutter/cogl/cogl-shader.h b/clutter/cogl/cogl-shader.h index 8438b69e9..4c06abe1c 100644 --- a/clutter/cogl/cogl-shader.h +++ b/clutter/cogl/cogl-shader.h @@ -188,10 +188,10 @@ void cogl_program_link (CoglHandle handle); /** * cogl_program_use: - * @handle: a #CoglHandle for a shader program or COGL_INVALID_HANDLE. + * @handle: a #CoglHandle for a shader program or %COGL_INVALID_HANDLE. * * Activate a specific shader program replacing that part of the GL - * rendering pipeline, if passed in COGL_INVALID_HANDLE the default + * rendering pipeline, if passed in %COGL_INVALID_HANDLE the default * behavior of GL is reinstated. */ void cogl_program_use (CoglHandle handle); @@ -201,29 +201,77 @@ void cogl_program_use (CoglHandle handle); * @handle: a #CoglHandle for a shader program. * @uniform_name: the name of a uniform. * - * Retrieve the location (offset) of a uniform variable in a shader program, a - * uniform is a variable that is constant for all vertices/fragments for a + * Retrieve the location (offset) of a uniform variable in a shader program, + * a uniform is a variable that is constant for all vertices/fragments for a * shader object and is possible to modify as an external parameter. * - * Returns: the offset of a uniform in a specified program, this uniform can be - * set using #cogl_program_uniform_1f when the program is in use. + * Return value: the offset of a uniform in a specified program. + * This uniform can be set using cogl_program_uniform_1f() when the + * program is in use. */ COGLint cogl_program_get_uniform_location (CoglHandle handle, const gchar *uniform_name); - /** * cogl_program_uniform_1f: * @uniform_no: the unform to set. * @value: the new value of the uniform. * - * Changes the value of a uniform in the currently used (see #cogl_program_use) - * shader program. + * Changes the value of a uniform in the currently used (see + * cogl_program_use()) shader program. */ void cogl_program_uniform_1f (COGLint uniform_no, gfloat value); + /** + * cogl_program_uniform_float: + * @uniform_no: the uniform to set. + * @size: Size of float vector. + * @count: Size of array of uniforms. + * @value: the new value of the uniform. + * + * Changes the value of a float vector uniform, or uniform array in the + * currently used (see #cogl_program_use) shader program. + */ +void cogl_program_uniform_float (COGLint uniform_no, + gint size, + gint count, + const GLfloat *value); + +/** + * cogl_program_uniform_int: + * @uniform_no: the uniform to set. + * @size: Size of int vector. + * @count: Size of array of uniforms. + * @value: the new value of the uniform. + * + * Changes the value of a int vector uniform, or uniform array in the + * currently used (see cogl_program_use()) shader program. + */ +void cogl_program_uniform_int (COGLint uniform_no, + gint size, + gint count, + const COGLint *value); + +/** + * cogl_program_uniform_matrix: + * @uniform_no: the uniform to set. + * @size: Size of matrix. + * @count: Size of array of uniforms. + * @transpose: Whether to transpose the matrix when setting the uniform. + * @value: the new value of the uniform. + * + * Changes the value of a matrix uniform, or uniform array in the + * currently used (see cogl_program_use()) shader program. The @size + * parameter is used to determine the square size of the matrix. + */ +void cogl_program_uniform_matrix (COGLint uniform_no, + gint size, + gint count, + gboolean transpose, + const GLfloat *value); + G_END_DECLS #endif /* __COGL_SHADER_H__ */ diff --git a/clutter/cogl/gl/cogl-context.c b/clutter/cogl/gl/cogl-context.c index e4b7b0493..1cb41f85d 100644 --- a/clutter/cogl/gl/cogl-context.c +++ b/clutter/cogl/gl/cogl-context.c @@ -94,6 +94,24 @@ cogl_create_context () _context->pf_glGetInfoLogARB = NULL; _context->pf_glGetObjectParameterivARB = NULL; _context->pf_glUniform1fARB = NULL; + _context->pf_glUniform2fARB = NULL; + _context->pf_glUniform3fARB = NULL; + _context->pf_glUniform4fARB = NULL; + _context->pf_glUniform1fvARB = NULL; + _context->pf_glUniform2fvARB = NULL; + _context->pf_glUniform3fvARB = NULL; + _context->pf_glUniform4fvARB = NULL; + _context->pf_glUniform1iARB = NULL; + _context->pf_glUniform2iARB = NULL; + _context->pf_glUniform3iARB = NULL; + _context->pf_glUniform4iARB = NULL; + _context->pf_glUniform1ivARB = NULL; + _context->pf_glUniform2ivARB = NULL; + _context->pf_glUniform3ivARB = NULL; + _context->pf_glUniform4ivARB = NULL; + _context->pf_glUniformMatrix2fvARB = NULL; + _context->pf_glUniformMatrix3fvARB = NULL; + _context->pf_glUniformMatrix4fvARB = NULL; /* Init OpenGL state */ GE( glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE) ); diff --git a/clutter/cogl/gl/cogl-context.h b/clutter/cogl/gl/cogl-context.h index 62216dcbc..0bab8a2ff 100644 --- a/clutter/cogl/gl/cogl-context.h +++ b/clutter/cogl/gl/cogl-context.h @@ -96,7 +96,7 @@ typedef struct COGL_PFNGLDELETEOBJECTARBPROC pf_glDeleteObjectARB; COGL_PFNGLGETINFOLOGARBPROC pf_glGetInfoLogARB; COGL_PFNGLGETOBJECTPARAMETERIVARBPROC pf_glGetObjectParameterivARB; - COGL_PFNGLUNIFORM1FARBPROC pf_glUniform1fARB; + COGL_PFNGLVERTEXATTRIBPOINTERARBPROC pf_glVertexAttribPointerARB; COGL_PFNGLENABLEVERTEXATTRIBARRAYARBPROC pf_glEnableVertexAttribArrayARB; COGL_PFNGLDISABLEVERTEXATTRIBARRAYARBPROC pf_glDisableVertexAttribArrayARB; @@ -109,6 +109,25 @@ typedef struct COGL_PFNGLUNMAPBUFFERARBPROC pf_glUnmapBufferARB; COGL_PFNGLDELETEBUFFERSARBPROC pf_glDeleteBuffersARB; + COGL_PFNGLUNIFORM1FARBPROC pf_glUniform1fARB; + COGL_PFNGLUNIFORM2FARBPROC pf_glUniform2fARB; + COGL_PFNGLUNIFORM3FARBPROC pf_glUniform3fARB; + COGL_PFNGLUNIFORM4FARBPROC pf_glUniform4fARB; + COGL_PFNGLUNIFORM1FVARBPROC pf_glUniform1fvARB; + COGL_PFNGLUNIFORM2FVARBPROC pf_glUniform2fvARB; + COGL_PFNGLUNIFORM3FVARBPROC pf_glUniform3fvARB; + COGL_PFNGLUNIFORM4FVARBPROC pf_glUniform4fvARB; + COGL_PFNGLUNIFORM1IARBPROC pf_glUniform1iARB; + COGL_PFNGLUNIFORM2IARBPROC pf_glUniform2iARB; + COGL_PFNGLUNIFORM3IARBPROC pf_glUniform3iARB; + COGL_PFNGLUNIFORM4IARBPROC pf_glUniform4iARB; + COGL_PFNGLUNIFORM1IVARBPROC pf_glUniform1ivARB; + COGL_PFNGLUNIFORM2IVARBPROC pf_glUniform2ivARB; + COGL_PFNGLUNIFORM3IVARBPROC pf_glUniform3ivARB; + COGL_PFNGLUNIFORM4IVARBPROC pf_glUniform4ivARB; + COGL_PFNGLUNIFORMMATRIX2FVARBPROC pf_glUniformMatrix2fvARB; + COGL_PFNGLUNIFORMMATRIX3FVARBPROC pf_glUniformMatrix3fvARB; + COGL_PFNGLUNIFORMMATRIX4FVARBPROC pf_glUniformMatrix4fvARB; } CoglContext; CoglContext * diff --git a/clutter/cogl/gl/cogl-defines.h.in b/clutter/cogl/gl/cogl-defines.h.in index d33a8323b..31c75bbb2 100644 --- a/clutter/cogl/gl/cogl-defines.h.in +++ b/clutter/cogl/gl/cogl-defines.h.in @@ -837,11 +837,6 @@ typedef void GLenum pname, GLint *params); -typedef void - (APIENTRYP COGL_PFNGLUNIFORM1FARBPROC) - (GLint location, - GLfloat v0); - typedef void (APIENTRYP COGL_PFNGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, @@ -897,6 +892,127 @@ typedef void (GLsizei n, const GLuint *buffers); +typedef void + (APIENTRYP COGL_PFNGLUNIFORM1FARBPROC) + (GLint location, + GLfloat v0); + +typedef void + (APIENTRYP COGL_PFNGLUNIFORM2FARBPROC) + (GLint location, + GLfloat v0, + GLfloat v1); + +typedef void + (APIENTRYP COGL_PFNGLUNIFORM3FARBPROC) + (GLint location, + GLfloat v0, + GLfloat v1, + GLfloat v2); + +typedef void + (APIENTRYP COGL_PFNGLUNIFORM4FARBPROC) + (GLint location, + GLfloat v0, + GLfloat v1, + GLfloat v2, + GLfloat v3); + +typedef void + (APIENTRYP COGL_PFNGLUNIFORM1FVARBPROC) + (GLint location, + GLsizei count, + const GLfloat * value); + +typedef void + (APIENTRYP COGL_PFNGLUNIFORM2FVARBPROC) + (GLint location, + GLsizei count, + const GLfloat * value); + +typedef void + (APIENTRYP COGL_PFNGLUNIFORM3FVARBPROC) + (GLint location, + GLsizei count, + const GLfloat * value); + +typedef void + (APIENTRYP COGL_PFNGLUNIFORM4FVARBPROC) + (GLint location, + GLsizei count, + const GLfloat * value); + +typedef void + (APIENTRYP COGL_PFNGLUNIFORM1IARBPROC) + (GLint location, + GLint v0); + +typedef void + (APIENTRYP COGL_PFNGLUNIFORM2IARBPROC) + (GLint location, + GLint v0, + GLint v1); + +typedef void + (APIENTRYP COGL_PFNGLUNIFORM3IARBPROC) + (GLint location, + GLint v0, + GLint v1, + GLint v2); + +typedef void + (APIENTRYP COGL_PFNGLUNIFORM4IARBPROC) + (GLint location, + GLint v0, + GLint v1, + GLint v2, + GLint v3); + +typedef void + (APIENTRYP COGL_PFNGLUNIFORM1IVARBPROC) + (GLint location, + GLsizei count, + const GLint * value); + +typedef void + (APIENTRYP COGL_PFNGLUNIFORM2IVARBPROC) + (GLint location, + GLsizei count, + const GLint * value); + +typedef void + (APIENTRYP COGL_PFNGLUNIFORM3IVARBPROC) + (GLint location, + GLsizei count, + const GLint * value); + +typedef void + (APIENTRYP COGL_PFNGLUNIFORM4IVARBPROC) + (GLint location, + GLsizei count, + const GLint * value); + +typedef void + (APIENTRYP COGL_PFNGLUNIFORMMATRIX2FVARBPROC) + (GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + +typedef void + (APIENTRYP COGL_PFNGLUNIFORMMATRIX3FVARBPROC) + (GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + +typedef void + (APIENTRYP COGL_PFNGLUNIFORMMATRIX4FVARBPROC) + (GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value); + G_END_DECLS #endif diff --git a/clutter/cogl/gl/cogl-program.c b/clutter/cogl/gl/cogl-program.c index 667137876..060e5bcd4 100644 --- a/clutter/cogl/gl/cogl-program.c +++ b/clutter/cogl/gl/cogl-program.c @@ -43,6 +43,24 @@ #define glLinkProgramARB ctx->pf_glLinkProgramARB #define glGetUniformLocationARB ctx->pf_glGetUniformLocationARB #define glUniform1fARB ctx->pf_glUniform1fARB +#define glUniform2fARB ctx->pf_glUniform2fARB +#define glUniform3fARB ctx->pf_glUniform3fARB +#define glUniform4fARB ctx->pf_glUniform4fARB +#define glUniform1fvARB ctx->pf_glUniform1fvARB +#define glUniform2fvARB ctx->pf_glUniform2fvARB +#define glUniform3fvARB ctx->pf_glUniform3fvARB +#define glUniform4fvARB ctx->pf_glUniform4fvARB +#define glUniform1iARB ctx->pf_glUniform1iARB +#define glUniform2iARB ctx->pf_glUniform2iARB +#define glUniform3iARB ctx->pf_glUniform3iARB +#define glUniform4iARB ctx->pf_glUniform4iARB +#define glUniform1ivARB ctx->pf_glUniform1ivARB +#define glUniform2ivARB ctx->pf_glUniform2ivARB +#define glUniform3ivARB ctx->pf_glUniform3ivARB +#define glUniform4ivARB ctx->pf_glUniform4ivARB +#define glUniformMatrix2fvARB ctx->pf_glUniformMatrix2fvARB +#define glUniformMatrix3fvARB ctx->pf_glUniformMatrix3fvARB +#define glUniformMatrix4fvARB ctx->pf_glUniformMatrix4fvARB #define glDeleteObjectARB ctx->pf_glDeleteObjectARB static void _cogl_program_free (CoglProgram *program); @@ -121,7 +139,7 @@ cogl_program_use (CoglHandle handle) { program = _cogl_program_pointer_from_handle (handle); gl_handle = program->gl_handle; - } + } glUseProgramObjectARB (gl_handle); } @@ -148,3 +166,82 @@ cogl_program_uniform_1f (COGLint uniform_no, _COGL_GET_CONTEXT (ctx, NO_RETVAL); glUniform1fARB (uniform_no, value); } + +void +cogl_program_uniform_float (COGLint uniform_no, + gint size, + gint count, + const GLfloat *value) +{ + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + switch (size) + { + case 1: + glUniform1fvARB (uniform_no, count, value); + break; + case 2: + glUniform2fvARB (uniform_no, count, value); + break; + case 3: + glUniform3fvARB (uniform_no, count, value); + break; + case 4: + glUniform4fvARB (uniform_no, count, value); + break; + default: + g_warning ("%s called with invalid size parameter", G_STRFUNC); + } +} + +void +cogl_program_uniform_int (COGLint uniform_no, + gint size, + gint count, + const COGLint *value) +{ + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + switch (size) + { + case 1: + glUniform1ivARB (uniform_no, count, value); + break; + case 2: + glUniform2ivARB (uniform_no, count, value); + break; + case 3: + glUniform3ivARB (uniform_no, count, value); + break; + case 4: + glUniform4ivARB (uniform_no, count, value); + break; + default: + g_warning ("%s called with invalid size parameter", G_STRFUNC); + } +} + +void +cogl_program_uniform_matrix (COGLint uniform_no, + gint size, + gint count, + gboolean transpose, + const GLfloat *value) +{ + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + switch (size) + { + case 2 : + glUniformMatrix2fvARB (uniform_no, count, transpose, value); + break; + case 3 : + glUniformMatrix3fvARB (uniform_no, count, transpose, value); + break; + case 4 : + glUniformMatrix4fvARB (uniform_no, count, transpose, value); + break; + default : + g_warning ("%s called with invalid size parameter", G_STRFUNC); + } +} diff --git a/clutter/cogl/gl/cogl.c b/clutter/cogl/gl/cogl.c index 8963e494e..a605c2e81 100644 --- a/clutter/cogl/gl/cogl.c +++ b/clutter/cogl/gl/cogl.c @@ -1028,6 +1028,78 @@ _cogl_features_init () (COGL_PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) cogl_get_proc_address ("glDisableVertexAttribArrayARB"); + ctx->pf_glUniform2fARB = + (COGL_PFNGLUNIFORM2FARBPROC) + cogl_get_proc_address ("glUniform2fARB"); + + ctx->pf_glUniform3fARB = + (COGL_PFNGLUNIFORM3FARBPROC) + cogl_get_proc_address ("glUniform3fARB"); + + ctx->pf_glUniform4fARB = + (COGL_PFNGLUNIFORM4FARBPROC) + cogl_get_proc_address ("glUniform4fARB"); + + ctx->pf_glUniform1fvARB = + (COGL_PFNGLUNIFORM1FVARBPROC) + cogl_get_proc_address ("glUniform1fvARB"); + + ctx->pf_glUniform2fvARB = + (COGL_PFNGLUNIFORM2FVARBPROC) + cogl_get_proc_address ("glUniform2fvARB"); + + ctx->pf_glUniform3fvARB = + (COGL_PFNGLUNIFORM3FVARBPROC) + cogl_get_proc_address ("glUniform3fvARB"); + + ctx->pf_glUniform4fvARB = + (COGL_PFNGLUNIFORM4FVARBPROC) + cogl_get_proc_address ("glUniform4fvARB"); + + ctx->pf_glUniform1iARB = + (COGL_PFNGLUNIFORM1IARBPROC) + cogl_get_proc_address ("glUniform1iARB"); + + ctx->pf_glUniform2iARB = + (COGL_PFNGLUNIFORM2IARBPROC) + cogl_get_proc_address ("glUniform2iARB"); + + ctx->pf_glUniform3iARB = + (COGL_PFNGLUNIFORM3IARBPROC) + cogl_get_proc_address ("glUniform3iARB"); + + ctx->pf_glUniform4iARB = + (COGL_PFNGLUNIFORM4IARBPROC) + cogl_get_proc_address ("glUniform4iARB"); + + ctx->pf_glUniform1ivARB = + (COGL_PFNGLUNIFORM1IVARBPROC) + cogl_get_proc_address ("glUniform1ivARB"); + + ctx->pf_glUniform2ivARB = + (COGL_PFNGLUNIFORM2IVARBPROC) + cogl_get_proc_address ("glUniform2ivARB"); + + ctx->pf_glUniform3ivARB = + (COGL_PFNGLUNIFORM3IVARBPROC) + cogl_get_proc_address ("glUniform3ivARB"); + + ctx->pf_glUniform4ivARB = + (COGL_PFNGLUNIFORM4IVARBPROC) + cogl_get_proc_address ("glUniform4ivARB"); + + ctx->pf_glUniformMatrix2fvARB = + (COGL_PFNGLUNIFORMMATRIX2FVARBPROC) + cogl_get_proc_address ("glUniformMatrix2fvARB"); + + ctx->pf_glUniformMatrix3fvARB = + (COGL_PFNGLUNIFORMMATRIX3FVARBPROC) + cogl_get_proc_address ("glUniformMatrix3fvARB"); + + ctx->pf_glUniformMatrix4fvARB = + (COGL_PFNGLUNIFORMMATRIX4FVARBPROC) + cogl_get_proc_address ("glUniformMatrix4fvARB"); + if (ctx->pf_glCreateProgramObjectARB && ctx->pf_glCreateShaderObjectARB && ctx->pf_glShaderSourceARB && @@ -1039,14 +1111,31 @@ _cogl_features_init () ctx->pf_glDeleteObjectARB && ctx->pf_glGetInfoLogARB && ctx->pf_glGetObjectParameterivARB && - ctx->pf_glUniform1fARB && + ctx->pf_glUniform1fARB && + ctx->pf_glUniform2fARB && + ctx->pf_glUniform3fARB && + ctx->pf_glUniform4fARB && + ctx->pf_glUniform1fvARB && + ctx->pf_glUniform2fvARB && + ctx->pf_glUniform3fvARB && + ctx->pf_glUniform4fvARB && + ctx->pf_glUniform1iARB && + ctx->pf_glUniform2iARB && + ctx->pf_glUniform3iARB && + ctx->pf_glUniform4iARB && + ctx->pf_glUniform1ivARB && + ctx->pf_glUniform2ivARB && + ctx->pf_glUniform3ivARB && + ctx->pf_glUniform4ivARB && + ctx->pf_glUniformMatrix2fvARB && + ctx->pf_glUniformMatrix3fvARB && + ctx->pf_glUniformMatrix4fvARB && ctx->pf_glVertexAttribPointerARB && ctx->pf_glEnableVertexAttribArrayARB && ctx->pf_glDisableVertexAttribArrayARB) flags |= COGL_FEATURE_SHADERS_GLSL; } - if (cogl_check_extension ("GL_EXT_framebuffer_object", gl_extensions) || cogl_check_extension ("GL_ARB_framebuffer_object", gl_extensions)) { diff --git a/clutter/cogl/gles/cogl-gles2-wrapper.c b/clutter/cogl/gles/cogl-gles2-wrapper.c index 25e3896a2..fea76500e 100644 --- a/clutter/cogl/gles/cogl-gles2-wrapper.c +++ b/clutter/cogl/gles/cogl-gles2-wrapper.c @@ -462,6 +462,7 @@ void cogl_gles2_wrapper_deinit (CoglGles2Wrapper *wrapper) { GSList *node, *next; + int i; for (node = wrapper->compiled_programs; node; node = next) { @@ -486,6 +487,10 @@ cogl_gles2_wrapper_deinit (CoglGles2Wrapper *wrapper) g_slist_free1 (node); } wrapper->compiled_fragment_shaders = NULL; + + for (i = 0; i < COGL_GLES2_NUM_CUSTOM_UNIFORMS; i++) + if (wrapper->custom_uniforms[i].count > 1) + g_free (wrapper->custom_uniforms[i].v.array); } void @@ -814,6 +819,78 @@ cogl_wrap_glNormalPointer (GLenum type, GLsizei stride, const GLvoid *pointer) GL_FALSE, stride, pointer); } +static void +cogl_gles2_do_set_uniform (GLint location, CoglBoxedValue *value) +{ + switch (value->type) + { + case COGL_BOXED_NONE: + break; + + case COGL_BOXED_INT: + { + gint *ptr; + + if (value->count == 1) + ptr = value->v.int_value; + else + ptr = value->v.int_array; + + switch (value->size) + { + case 1: glUniform1iv (location, value->count, ptr); break; + case 2: glUniform2iv (location, value->count, ptr); break; + case 3: glUniform3iv (location, value->count, ptr); break; + case 4: glUniform4iv (location, value->count, ptr); break; + } + } + break; + + case COGL_BOXED_FLOAT: + { + gfloat *ptr; + + if (value->count == 1) + ptr = value->v.float_value; + else + ptr = value->v.float_array; + + switch (value->size) + { + case 1: glUniform1fv (location, value->count, ptr); break; + case 2: glUniform2fv (location, value->count, ptr); break; + case 3: glUniform3fv (location, value->count, ptr); break; + case 4: glUniform4fv (location, value->count, ptr); break; + } + } + break; + + case COGL_BOXED_MATRIX: + { + gfloat *ptr; + + if (value->count == 1) + ptr = value->v.matrix; + else + ptr = value->v.float_array; + + switch (value->size) + { + case 2: + glUniformMatrix2fv (location, value->count, value->transpose, ptr); + break; + case 3: + glUniformMatrix3fv (location, value->count, value->transpose, ptr); + break; + case 4: + glUniformMatrix4fv (location, value->count, value->transpose, ptr); + break; + } + } + break; + } +} + void cogl_wrap_glDrawArrays (GLenum mode, GLint first, GLsizei count) { @@ -914,8 +991,8 @@ cogl_wrap_glDrawArrays (GLenum mode, GLint first, GLsizei count) program->custom_uniforms[i] = glGetUniformLocation (program->program, uniform_name); if (program->custom_uniforms[i] >= 0) - glUniform1f (program->custom_uniforms[i], - w->custom_uniforms[i]); + cogl_gles2_do_set_uniform (program->custom_uniforms[i], + &w->custom_uniforms[i]); } } diff --git a/clutter/cogl/gles/cogl-gles2-wrapper.h b/clutter/cogl/gles/cogl-gles2-wrapper.h index 19b062088..ddf181e92 100644 --- a/clutter/cogl/gles/cogl-gles2-wrapper.h +++ b/clutter/cogl/gles/cogl-gles2-wrapper.h @@ -26,6 +26,8 @@ #ifndef __COGL_GLES2_WRAPPER_H__ #define __COGL_GLES2_WRAPPER_H__ +#include "cogl-internal.h" + G_BEGIN_DECLS #ifdef HAVE_COGL_GLES2 @@ -131,7 +133,7 @@ struct _CoglGles2Wrapper GLfloat fog_start; GLfloat fog_end; GLfloat fog_color[4]; - GLfloat custom_uniforms[COGL_GLES2_NUM_CUSTOM_UNIFORMS]; + CoglBoxedValue custom_uniforms[COGL_GLES2_NUM_CUSTOM_UNIFORMS]; }; struct _CoglGles2WrapperProgram diff --git a/clutter/cogl/gles/cogl-internal.h b/clutter/cogl/gles/cogl-internal.h index 9275f4ba0..8ca926ece 100644 --- a/clutter/cogl/gles/cogl-internal.h +++ b/clutter/cogl/gles/cogl-internal.h @@ -26,6 +26,30 @@ #ifndef __COGL_INTERNAL_H #define __COGL_INTERNAL_H +typedef enum { + COGL_BOXED_NONE, + COGL_BOXED_INT, + COGL_BOXED_FLOAT, + COGL_BOXED_MATRIX +} CoglBoxedType; + +typedef struct _CoglBoxedValue +{ + CoglBoxedType type; + int size, count; + gboolean transpose; + + union { + gfloat float_value[4]; + gint int_value[4]; + gfloat matrix[16]; + gfloat *float_array; + gint *int_array; + gpointer array; + } v; +} CoglBoxedValue; + + #define COGL_DEBUG 0 #if COGL_DEBUG diff --git a/clutter/cogl/gles/cogl-program.c b/clutter/cogl/gles/cogl-program.c index 36ac6d509..c550df453 100644 --- a/clutter/cogl/gles/cogl-program.c +++ b/clutter/cogl/gles/cogl-program.c @@ -162,16 +162,95 @@ cogl_program_get_uniform_location (CoglHandle handle, void cogl_program_uniform_1f (COGLint uniform_no, gfloat value) +{ + cogl_program_uniform_float (uniform_no, 1, 1, &value); +} + +static void +cogl_program_uniform_x (COGLint uniform_no, + gint size, + gint count, + CoglBoxedType type, + size_t value_size, + gconstpointer value) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); - if (uniform_no >= 0 && uniform_no < COGL_GLES2_NUM_CUSTOM_UNIFORMS) + if (uniform_no >= 0 && uniform_no < COGL_GLES2_NUM_CUSTOM_UNIFORMS + && size >= 1 && size <= 4 && count >= 1) { - ctx->gles2.custom_uniforms[uniform_no] = value; + CoglBoxedValue *bv = ctx->gles2.custom_uniforms + uniform_no; + + if (count == 1) + { + if (bv->count > 1) + g_free (bv->v.array); + + memcpy (bv->v.float_value, value, value_size); + } + else + { + if (bv->count > 1) + { + if (bv->count != count || bv->size != size || bv->type != type) + { + g_free (bv->v.array); + bv->v.array = g_malloc (count * value_size); + } + } + else + bv->v.array = g_malloc (count * value_size); + + memcpy (bv->v.array, value, count * value_size); + } + + bv->type = type; + bv->size = size; + bv->count = count; + ctx->gles2.dirty_custom_uniforms |= 1 << uniform_no; } } +void +cogl_program_uniform_float (COGLint uniform_no, + gint size, + gint count, + const GLfloat *value) +{ + cogl_program_uniform_x (uniform_no, size, count, COGL_BOXED_FLOAT, + sizeof (float) * size, value); +} + +void +cogl_program_uniform_int (COGLint uniform_no, + gint size, + gint count, + const GLint *value) +{ + cogl_program_uniform_x (uniform_no, size, count, COGL_BOXED_INT, + sizeof (gint) * size, value); +} + +void +cogl_program_uniform_matrix (COGLint uniform_no, + gint size, + gint count, + gboolean transpose, + const GLfloat *value) +{ + CoglBoxedValue *bv; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + bv = ctx->gles2.custom_uniforms + uniform_no; + + cogl_program_uniform_x (uniform_no, size, count, COGL_BOXED_MATRIX, + sizeof (float) * size * size, value); + + bv->transpose = transpose; +} + #else /* HAVE_COGL_GLES2 */ /* No support on regular OpenGL 1.1 */ @@ -228,4 +307,30 @@ cogl_program_uniform_1f (COGLint uniform_no, { } +void +cogl_program_uniform_float (COGLint uniform_no, + gint size, + gint count, + const GLfloat *value) +{ +} + +void +cogl_program_uniform_int (COGLint uniform_no, + gint size, + gint count, + const COGLint *value) +{ +} + +void +cogl_program_uniform_matrix (COGLint uniform_no, + gint size, + gint count, + gboolean transpose, + const GLfloat *value) +{ +} + + #endif /* HAVE_COGL_GLES2 */ diff --git a/doc/reference/clutter/clutter-sections.txt b/doc/reference/clutter/clutter-sections.txt index 1acd4bbf0..c41f49306 100644 --- a/doc/reference/clutter/clutter-sections.txt +++ b/doc/reference/clutter/clutter-sections.txt @@ -1503,6 +1503,10 @@ clutter_shader_is_compiled clutter_shader_set_is_enabled clutter_shader_get_is_enabled clutter_shader_set_uniform_1f +clutter_shader_set_uniform +clutter_shader_get_cogl_program +clutter_shader_get_cogl_fragment_shader +clutter_shader_get_cogl_vertex_shader CLUTTER_IS_SHADER diff --git a/doc/reference/cogl/cogl-sections.txt b/doc/reference/cogl/cogl-sections.txt index ee5dbad5d..3ff906e90 100644 --- a/doc/reference/cogl/cogl-sections.txt +++ b/doc/reference/cogl/cogl-sections.txt @@ -138,6 +138,9 @@ cogl_program_link cogl_program_use cogl_program_get_uniform_location cogl_program_uniform_1f +cogl_program_uniform_float +cogl_program_uniform_int +cogl_program_uniform_matrix
diff --git a/tests/interactive/test-fbo.c b/tests/interactive/test-fbo.c index 9bbb4190e..bdf99f1cb 100644 --- a/tests/interactive/test-fbo.c +++ b/tests/interactive/test-fbo.c @@ -142,10 +142,10 @@ test_fbo_main (gint argc, gchar *argv[]) /* apply a shader to it */ shader = make_shader(); clutter_actor_set_shader (fbo, shader); - clutter_actor_set_shader_param (fbo, "radius", 2.0); - clutter_actor_set_shader_param (fbo, "x_step", + clutter_actor_set_shader_param_float (fbo, "radius", 2.0); + clutter_actor_set_shader_param_float (fbo, "x_step", 1.0f / clutter_util_next_p2 (fbo_width)); - clutter_actor_set_shader_param (fbo, "y_step", + clutter_actor_set_shader_param_float (fbo, "y_step", 1.0f / clutter_util_next_p2 (fbo_height)); /* Third from cloning the fbo texture */ diff --git a/tests/interactive/test-shader.c b/tests/interactive/test-shader.c index 6a8b46540..4880a704a 100644 --- a/tests/interactive/test-shader.c +++ b/tests/interactive/test-shader.c @@ -238,9 +238,10 @@ set_shader_num (ClutterActor *actor, gint new_no) { clutter_actor_set_shader (actor, NULL); clutter_actor_set_shader (actor, shader); - clutter_actor_set_shader_param (actor, "radius", 3.0); - clutter_actor_set_shader_param (actor, "brightness", 0.4); - clutter_actor_set_shader_param (actor, "contrast", -1.9); + clutter_actor_set_shader_param_int (actor, "tex", 0); + clutter_actor_set_shader_param_float (actor, "radius", 3.0); + clutter_actor_set_shader_param_float (actor, "brightness", 0.4); + clutter_actor_set_shader_param_float (actor, "contrast", -1.9); if (CLUTTER_IS_TEXTURE (actor)) { @@ -249,10 +250,10 @@ set_shader_num (ClutterActor *actor, gint new_no) tex_height = clutter_actor_get_height (actor); tex_height = clutter_util_next_p2 (tex_height); - clutter_actor_set_shader_param (actor, "x_step", - 1.0f / tex_width); - clutter_actor_set_shader_param (actor, "y_step", - 1.0f / tex_height); + clutter_actor_set_shader_param_float (actor, "x_step", + 1.0f / tex_width); + clutter_actor_set_shader_param_float (actor, "y_step", + 1.0f / tex_height); } } } @@ -376,10 +377,10 @@ test_shader_main (gint argc, gchar *argv[]) clutter_container_add_actor (CLUTTER_CONTAINER (stage), actor); + clutter_actor_set_shader_param_int (actor, "tex", 0); + clutter_actor_set_shader_param_float (actor, "brightness", 0.4); + clutter_actor_set_shader_param_float (actor, "contrast", -1.9); - clutter_actor_set_shader_param (actor, "brightness", 0.4); - clutter_actor_set_shader_param (actor, "contrast", -1.9); - clutter_actor_set_reactive (actor, TRUE); g_signal_connect (actor, "button-release-event", G_CALLBACK (button_release_cb), NULL);