Support for shaders in clutter. At the moment limited to drivers
providing GLSL support. * clutter/cogl/cogl.h: added rather direct binding of needed for glsl shaders. * clutter/cogl/gl/cogl-defines.h.in: * clutter/cogl/gl/cogl.c: * clutter/cogl/gles/cogl-defines.h: added stubs. * clutter/cogl/gles/cogl.c: added stubs. * clutter/glx/clutter-stage-glx.c: (clutter_stage_glx_realize): unrelated memory management sanity fix. (clutter_stage_glx_unrealize): unbind all shaders on stage unrealize. * clutter/Makefile.am: added clutter-shader.[ch] * clutter/clutter-actor.[ch]: adding shader capability to actors. * clutter/clutter-feature.h: added CLUTTER_FEATURE_SHADERS_GLSL * clutter/clutter-private.h: added stack of shaders to context. * clutter/clutter-shader.[ch]: new. * tests/Makefile.am: added shader test. * tests/test-shader.c: (frame_cb), (main): simple shader test, cycle through the inline shader with right/left mouse buttons.
This commit is contained in:
parent
ace69e71b3
commit
e92b864dff
27
ChangeLog
27
ChangeLog
@ -1,3 +1,30 @@
|
||||
2007-12-03 Øyvind Kolås <pippin@o-hand.com>
|
||||
|
||||
Support for shaders in clutter. At the moment limited to drivers
|
||||
providing GLSL support.
|
||||
|
||||
* clutter/cogl/cogl.h: added rather direct binding of needed for glsl
|
||||
shaders.
|
||||
* clutter/cogl/gl/cogl-defines.h.in:
|
||||
* clutter/cogl/gl/cogl.c:
|
||||
* clutter/cogl/gles/cogl-defines.h: added stubs.
|
||||
* clutter/cogl/gles/cogl.c: added stubs.
|
||||
|
||||
* clutter/glx/clutter-stage-glx.c:
|
||||
(clutter_stage_glx_realize): unrelated memory management sanity fix.
|
||||
(clutter_stage_glx_unrealize): unbind all shaders on stage unrealize.
|
||||
|
||||
* clutter/Makefile.am: added clutter-shader.[ch]
|
||||
* clutter/clutter-actor.[ch]: adding shader capability to
|
||||
actors.
|
||||
* clutter/clutter-feature.h: added CLUTTER_FEATURE_SHADERS_GLSL
|
||||
* clutter/clutter-private.h: added stack of shaders to context.
|
||||
* clutter/clutter-shader.[ch]: new.
|
||||
|
||||
* tests/Makefile.am: added shader test.
|
||||
* tests/test-shader.c: (frame_cb), (main): simple shader test,
|
||||
cycle through the inline shader with right/left mouse buttons.
|
||||
|
||||
2007-12-03 Øyvind Kolås <pippin@o-hand.com>
|
||||
|
||||
* clutter/glx/clutter-stage-glx.c: for extra sanity, set
|
||||
|
@ -69,6 +69,7 @@ source_h = \
|
||||
$(srcdir)/clutter-score.h \
|
||||
$(srcdir)/clutter-script.h \
|
||||
$(srcdir)/clutter-scriptable.h \
|
||||
$(srcdir)/clutter-shader.h \
|
||||
$(srcdir)/clutter-stage.h \
|
||||
$(srcdir)/clutter-texture.h \
|
||||
$(srcdir)/clutter-timeline.h \
|
||||
@ -153,6 +154,7 @@ source_c = \
|
||||
clutter-script.c \
|
||||
clutter-script-parser.c \
|
||||
clutter-scriptable.c \
|
||||
clutter-shader.c \
|
||||
clutter-stage.c \
|
||||
clutter-texture.c \
|
||||
clutter-timeline.c \
|
||||
|
@ -156,6 +156,8 @@ static guint32 __id = 0;
|
||||
#define CLUTTER_ACTOR_GET_PRIVATE(obj) \
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
|
||||
|
||||
typedef struct _ShaderData ShaderData;
|
||||
|
||||
struct _ClutterActorPrivate
|
||||
{
|
||||
ClutterActorBox coords;
|
||||
@ -170,6 +172,8 @@ struct _ClutterActorPrivate
|
||||
gchar *name;
|
||||
ClutterFixed scale_x, scale_y;
|
||||
guint32 id; /* Unique ID */
|
||||
|
||||
ShaderData *shader_data;
|
||||
ClutterUnit anchor_x, anchor_y;
|
||||
};
|
||||
|
||||
@ -221,6 +225,11 @@ static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
|
||||
static void _clutter_actor_apply_modelview_transform (ClutterActor *self);
|
||||
static void _clutter_actor_apply_modelview_transform_recursive (ClutterActor *self);
|
||||
|
||||
static void clutter_actor_shader_pre_paint (ClutterActor *actor,
|
||||
gboolean repeat);
|
||||
static void clutter_actor_shader_post_paint (ClutterActor *actor);
|
||||
static void destroy_shader_data (ClutterActor *self);
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (ClutterActor,
|
||||
clutter_actor,
|
||||
G_TYPE_INITIALLY_UNOWNED,
|
||||
@ -907,8 +916,10 @@ clutter_actor_paint (ClutterActor *self)
|
||||
}
|
||||
else
|
||||
{
|
||||
clutter_actor_shader_pre_paint (self, FALSE);
|
||||
if (G_LIKELY(klass->paint))
|
||||
(klass->paint) (self);
|
||||
clutter_actor_shader_post_paint (self);
|
||||
}
|
||||
|
||||
if (priv->has_clip)
|
||||
@ -1175,6 +1186,8 @@ clutter_actor_dispose (GObject *object)
|
||||
g_type_name (G_OBJECT_TYPE (self)),
|
||||
object->ref_count);
|
||||
|
||||
destroy_shader_data (self);
|
||||
|
||||
if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IN_DESTRUCTION))
|
||||
{
|
||||
CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_ACTOR_IN_DESTRUCTION);
|
||||
@ -1730,6 +1743,7 @@ clutter_actor_init (ClutterActor *self)
|
||||
priv->id = __id++;
|
||||
priv->scale_x = CFX_ONE;
|
||||
priv->scale_y = CFX_ONE;
|
||||
priv->shader_data = NULL;
|
||||
|
||||
clutter_actor_request_coords (self, &box);
|
||||
}
|
||||
@ -4036,3 +4050,175 @@ clutter_actor_box_get_type (void)
|
||||
(GBoxedFreeFunc) clutter_actor_box_free);
|
||||
return our_type;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
typedef struct _BoxedFloat BoxedFloat;
|
||||
struct _BoxedFloat
|
||||
{
|
||||
gfloat value;
|
||||
};
|
||||
|
||||
struct _ShaderData
|
||||
{
|
||||
ClutterShader *shader;
|
||||
GHashTable *float1f_hash; /*< list of values that should be set
|
||||
* on the shader before each paint cycle
|
||||
*/
|
||||
};
|
||||
|
||||
static void
|
||||
destroy_shader_data (ClutterActor *self)
|
||||
{
|
||||
ClutterActorPrivate *actor_priv = self->priv;
|
||||
ShaderData *shader_data = actor_priv->shader_data;
|
||||
|
||||
if (!shader_data)
|
||||
return;
|
||||
|
||||
if (shader_data->shader)
|
||||
{
|
||||
g_object_unref (shader_data->shader);
|
||||
}
|
||||
shader_data->shader = NULL;
|
||||
if (shader_data->float1f_hash)
|
||||
{
|
||||
g_hash_table_destroy (shader_data->float1f_hash);
|
||||
shader_data->float1f_hash = NULL;
|
||||
}
|
||||
g_free (shader_data);
|
||||
actor_priv->shader_data = NULL;
|
||||
}
|
||||
|
||||
gboolean clutter_actor_apply_shader (ClutterActor *self,
|
||||
ClutterShader *shader)
|
||||
{
|
||||
ClutterActorPrivate *actor_priv;
|
||||
ShaderData *shader_data;
|
||||
|
||||
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
|
||||
|
||||
actor_priv = self->priv;
|
||||
shader_data = actor_priv->shader_data;
|
||||
|
||||
if (shader_data == NULL)
|
||||
{
|
||||
actor_priv->shader_data = shader_data = g_new0 (ShaderData, 1);
|
||||
shader_data->float1f_hash = g_hash_table_new_full (
|
||||
g_str_hash, g_str_equal,
|
||||
g_free, g_free);
|
||||
}
|
||||
if (shader_data->shader)
|
||||
{
|
||||
g_object_unref (shader_data->shader);
|
||||
}
|
||||
if (shader)
|
||||
{
|
||||
shader_data->shader = g_object_ref (shader);
|
||||
}
|
||||
else
|
||||
{
|
||||
shader_data->shader = NULL;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
each_param (gpointer key,
|
||||
gpointer value,
|
||||
gpointer user_data)
|
||||
{
|
||||
ClutterShader *shader = CLUTTER_SHADER (user_data);
|
||||
BoxedFloat *box = value;
|
||||
clutter_shader_set_uniform_1f (shader, key, box->value);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_actor_shader_pre_paint (ClutterActor *actor,
|
||||
gboolean repeat)
|
||||
{
|
||||
ClutterActorPrivate *actor_priv;
|
||||
ShaderData *shader_data;
|
||||
ClutterShader *shader;
|
||||
ClutterMainContext *context;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
|
||||
|
||||
actor_priv = actor->priv;
|
||||
shader_data = actor_priv->shader_data;
|
||||
|
||||
if (!shader_data)
|
||||
return;
|
||||
|
||||
context = clutter_context_get_default ();
|
||||
shader = shader_data->shader;
|
||||
|
||||
if (shader)
|
||||
{
|
||||
clutter_shader_enable (shader);
|
||||
|
||||
g_hash_table_foreach (shader_data->float1f_hash, each_param, shader);
|
||||
|
||||
if (!repeat)
|
||||
{
|
||||
context->shaders = g_slist_prepend (context->shaders, actor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_actor_shader_post_paint (ClutterActor *actor)
|
||||
{
|
||||
ClutterActorPrivate *actor_priv;
|
||||
ShaderData *shader_data;
|
||||
ClutterShader *shader;
|
||||
ClutterMainContext *context;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
|
||||
|
||||
actor_priv = actor->priv;
|
||||
shader_data = actor_priv->shader_data;
|
||||
|
||||
if (!shader_data)
|
||||
return;
|
||||
|
||||
context = clutter_context_get_default ();
|
||||
shader = shader_data->shader;
|
||||
|
||||
if (shader)
|
||||
{
|
||||
clutter_shader_disable (shader);
|
||||
|
||||
context->shaders = g_slist_remove (context->shaders, actor);
|
||||
if (context->shaders)
|
||||
{
|
||||
/* call pre-paint again, this time with the second argument being
|
||||
* TRUE, indicating that we are reapplying the shader and thus
|
||||
* should not be prepended to the stack
|
||||
*/
|
||||
clutter_actor_shader_pre_paint (context->shaders->data, TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
clutter_actor_set_shader_param (ClutterActor *actor,
|
||||
const gchar *param,
|
||||
gfloat value)
|
||||
{
|
||||
ClutterActorPrivate *actor_priv;
|
||||
ShaderData *shader_data;
|
||||
BoxedFloat *box;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
|
||||
|
||||
actor_priv = actor->priv;
|
||||
shader_data = actor_priv->shader_data;
|
||||
|
||||
if (!shader_data)
|
||||
return;
|
||||
|
||||
box = g_malloc (sizeof (BoxedFloat));
|
||||
box->value = value;
|
||||
g_hash_table_insert (shader_data->float1f_hash, g_strdup (param), box);
|
||||
}
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <clutter/clutter-types.h>
|
||||
#include <clutter/clutter-units.h>
|
||||
#include <clutter/clutter-event.h>
|
||||
#include <clutter/clutter-shader.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@ -216,9 +217,10 @@ struct _ClutterActorClass
|
||||
void (* focus_in) (ClutterActor *actor);
|
||||
void (* focus_out) (ClutterActor *actor);
|
||||
|
||||
gboolean shadable;
|
||||
/*< private >*/
|
||||
/* padding for future expansion */
|
||||
gpointer _padding_dummy[32];
|
||||
gpointer _padding_dummy[31];
|
||||
};
|
||||
|
||||
GType clutter_actor_get_type (void) G_GNUC_CONST;
|
||||
@ -390,6 +392,14 @@ ClutterActor * clutter_get_actor_by_gid (guint32 id);
|
||||
|
||||
gboolean clutter_actor_should_pick_paint (ClutterActor *self);
|
||||
|
||||
gboolean clutter_actor_apply_shader (ClutterActor *self,
|
||||
ClutterShader *shader);
|
||||
|
||||
void clutter_actor_set_shader_param (ClutterActor *self,
|
||||
const gchar *param,
|
||||
gfloat value);
|
||||
|
||||
|
||||
void clutter_actor_set_anchor_point (ClutterActor *self,
|
||||
gint anchor_x,
|
||||
gint anchor_y);
|
||||
|
@ -46,6 +46,7 @@ G_BEGIN_DECLS
|
||||
* @CLUTTER_FEATURE_STAGE_STATIC: Set if stage size if fixed (i.e framebuffer)
|
||||
* @CLUTTER_FEATURE_STAGE_USER_RESIZE: Set if stage is able to be user resized.
|
||||
* @CLUTTER_FEATURE_STAGE_CURSOR: Set if stage has a graphical cursor.
|
||||
* @CLUTTER_FEATURE_SHADER_GLSL: Set if the backend supports GLSL shaders.
|
||||
*
|
||||
* Runtime flags indicating specific features available via Clutter window
|
||||
* sysytem and graphics backend.
|
||||
@ -60,7 +61,8 @@ typedef enum
|
||||
CLUTTER_FEATURE_TEXTURE_READ_PIXELS = (1 << 4),
|
||||
CLUTTER_FEATURE_STAGE_STATIC = (1 << 5),
|
||||
CLUTTER_FEATURE_STAGE_USER_RESIZE = (1 << 6),
|
||||
CLUTTER_FEATURE_STAGE_CURSOR = (1 << 7)
|
||||
CLUTTER_FEATURE_STAGE_CURSOR = (1 << 7),
|
||||
CLUTTER_FEATURE_SHADERS_GLSL = (1 << 8)
|
||||
} ClutterFeatureFlags;
|
||||
|
||||
gboolean clutter_feature_available (ClutterFeatureFlags feature);
|
||||
|
@ -93,6 +93,7 @@ struct _ClutterMainContext
|
||||
ClutterActor *keyboard_grab_actor; /* The actor having the pointer grab
|
||||
(or NULL if there is no pointer grab)
|
||||
*/
|
||||
GSList *shaders; /* stack of overridden shaders */
|
||||
};
|
||||
|
||||
#define CLUTTER_CONTEXT() (clutter_context_get_default ())
|
||||
|
433
clutter/clutter-shader.c
Normal file
433
clutter/clutter-shader.c
Normal file
@ -0,0 +1,433 @@
|
||||
/*
|
||||
* Clutter.
|
||||
*
|
||||
* An OpenGL based 'interactive canvas' library.
|
||||
*
|
||||
* Authored By Matthew Allum <mallum@openedhand.com>
|
||||
* Øyvind Kolås <pippin@o-hand.com>
|
||||
*
|
||||
* Copyright (C) 2007 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.
|
||||
*/
|
||||
|
||||
#include "clutter.h"
|
||||
#include "clutter-private.h"
|
||||
#include "clutter-shader.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <glib.h>
|
||||
#include <cogl/cogl.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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);
|
||||
|
||||
struct _ClutterShaderPrivate
|
||||
{
|
||||
gboolean glsl; /* The shader is a GLSL shader */
|
||||
gboolean bound; /* The shader is bound to the GL context */
|
||||
|
||||
gchar *vertex_shader_source; /* source (or asm) for vertex shader */
|
||||
gchar *fragment_shader_source;/* source (or asm) for fragment shader*/
|
||||
|
||||
GLhandleARB program;
|
||||
|
||||
GLhandleARB vertex_shader;
|
||||
GLhandleARB fragment_shader;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_VERTEX_SOURCE,
|
||||
PROP_FRAGMENT_SOURCE
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (ClutterShader, clutter_shader, G_TYPE_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));
|
||||
|
||||
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));
|
||||
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));
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_shader_init (ClutterShader *self)
|
||||
{
|
||||
ClutterShaderPrivate *priv;
|
||||
|
||||
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->program = 0;
|
||||
priv->vertex_shader = 0;
|
||||
priv->fragment_shader = 0;
|
||||
}
|
||||
|
||||
static gboolean bind_glsl_shader (ClutterShader *self)
|
||||
{
|
||||
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)
|
||||
{
|
||||
priv->vertex_shader = cogl_create_shader (CGL_VERTEX_SHADER);
|
||||
cogl_shader_source (priv->vertex_shader, priv->vertex_shader_source);
|
||||
cogl_shader_compile (priv->vertex_shader);
|
||||
cogl_program_attach_shader (priv->program, priv->vertex_shader);
|
||||
}
|
||||
if (priv->fragment_shader_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_compile (priv->fragment_shader);
|
||||
|
||||
cogl_shader_get_parameteriv (priv->fragment_shader,
|
||||
CGL_OBJECT_COMPILE_STATUS,
|
||||
&compiled);
|
||||
if (compiled != CGL_TRUE)
|
||||
{
|
||||
GLcharARB *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);
|
||||
return FALSE;
|
||||
}
|
||||
cogl_program_attach_shader (priv->program, priv->fragment_shader);
|
||||
}
|
||||
cogl_program_link (priv->program);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
clutter_shader_bind (ClutterShader *self)
|
||||
{
|
||||
ClutterShaderPrivate *priv;
|
||||
|
||||
priv = self->priv;
|
||||
if (priv->bound)
|
||||
return priv->bound;
|
||||
|
||||
if (priv->glsl)
|
||||
{
|
||||
priv->bound = bind_glsl_shader (self);
|
||||
}
|
||||
|
||||
return priv->bound;
|
||||
}
|
||||
|
||||
void
|
||||
clutter_shader_release (ClutterShader *self)
|
||||
{
|
||||
ClutterShaderPrivate *priv;
|
||||
|
||||
priv = self->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;
|
||||
}
|
||||
priv->bound = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_shader_finalize (GObject *object)
|
||||
{
|
||||
ClutterShader *shader;
|
||||
ClutterShaderPrivate *priv;
|
||||
|
||||
shader = CLUTTER_SHADER (object);
|
||||
priv = shader->priv;
|
||||
|
||||
clutter_shader_release (shader);
|
||||
|
||||
shader_list = g_list_remove (shader_list, object);
|
||||
|
||||
if (priv->fragment_shader_source)
|
||||
g_free (priv->fragment_shader_source);
|
||||
if (priv->vertex_shader_source)
|
||||
g_free (priv->vertex_shader_source);
|
||||
|
||||
G_OBJECT_CLASS (clutter_shader_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
clutter_shader_enable (ClutterShader *self)
|
||||
{
|
||||
ClutterShaderPrivate *priv = self->priv;
|
||||
|
||||
clutter_shader_bind (self);
|
||||
|
||||
cogl_program_use (priv->program);
|
||||
}
|
||||
|
||||
void
|
||||
clutter_shader_disable (ClutterShader *self)
|
||||
{
|
||||
cogl_program_use (0);
|
||||
}
|
||||
|
||||
void
|
||||
clutter_shader_set_uniform_1f (ClutterShader *self,
|
||||
const gchar *name,
|
||||
gfloat value)
|
||||
{
|
||||
ClutterShaderPrivate *priv = self->priv;
|
||||
GLint location = 0;
|
||||
GLfloat foo = value;
|
||||
|
||||
location =cogl_program_get_uniform_location (priv->program, name);
|
||||
cogl_program_uniform_1f (location, foo);
|
||||
}
|
||||
|
||||
void
|
||||
clutter_shader_release_all (void)
|
||||
{
|
||||
GList *iter;
|
||||
for (iter = shader_list; iter; iter = g_list_next (iter))
|
||||
{
|
||||
clutter_shader_release (iter->data);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
ClutterShader *
|
||||
clutter_shader_new_from_strings (const gchar *vertex_shader_program,
|
||||
const gchar *fragment_shader_program)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
ClutterShader *
|
||||
clutter_shader_new_from_files (const gchar *vertex_file,
|
||||
const gchar *fragment_file)
|
||||
{
|
||||
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;
|
||||
}
|
80
clutter/clutter-shader.h
Normal file
80
clutter/clutter-shader.h
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Clutter.
|
||||
*
|
||||
* An OpenGL based 'interactive canvas' library.
|
||||
*
|
||||
* Authored By Matthew Allum <mallum@openedhand.com>
|
||||
* Øyvind Kolås <pippin@o-hand.com>
|
||||
*
|
||||
* Copyright (C) 2007 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.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CLUTTER_SHADER_H
|
||||
#define CLUTTER_SHADER_H
|
||||
|
||||
#include <GL/gl.h>
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CLUTTER_TYPE_SHADER (clutter_shader_get_type ())
|
||||
#define CLUTTER_SHADER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CLUTTER_TYPE_SHADER, ClutterShader))
|
||||
#define CLUTTER_SHADER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CLUTTER_TYPE_SHADER, ClutterShaderClass))
|
||||
#define CLUTTER_IS_SHADER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CLUTTER_TYPE_SHADER))
|
||||
#define CLUTTER_IS_SHADER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CLUTTER_TYPE_SHADER))
|
||||
#define CLUTTER_SHADER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CLUTTER_TYPE_SHADER, ClutterShaderClass))
|
||||
|
||||
typedef struct _ClutterShader ClutterShader;
|
||||
typedef struct _ClutterShaderPrivate ClutterShaderPrivate;
|
||||
typedef struct _ClutterShaderClass ClutterShaderClass;
|
||||
|
||||
struct _ClutterShader
|
||||
{
|
||||
GObject parent;
|
||||
ClutterShaderPrivate *priv;
|
||||
};
|
||||
|
||||
struct _ClutterShaderClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
GType clutter_shader_get_type ();
|
||||
|
||||
ClutterShader * clutter_shader_new_from_files (const gchar *vertex_file,
|
||||
const gchar *fragment_file);
|
||||
ClutterShader * clutter_shader_new_from_strings (const gchar *vertex_file,
|
||||
const gchar *fragment_file);
|
||||
void clutter_shader_enable (ClutterShader *self);
|
||||
void clutter_shader_disable (ClutterShader *self);
|
||||
|
||||
gboolean clutter_shader_bind (ClutterShader *self);
|
||||
void clutter_shader_release (ClutterShader *self);
|
||||
void clutter_shader_set_uniform_1f (ClutterShader *self,
|
||||
const gchar *name,
|
||||
gfloat value);
|
||||
/* should be private and internal */
|
||||
void clutter_shader_release_all (void);
|
||||
gboolean clutter_shader_has_glsl (void);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* CLUTTER_SHADER_H */
|
@ -207,6 +207,58 @@ cogl_fog_set (const ClutterColor *fog_color,
|
||||
ClutterFixed z_near,
|
||||
ClutterFixed z_far);
|
||||
|
||||
|
||||
COGLint
|
||||
cogl_create_shader (COGLenum shaderType);
|
||||
|
||||
void
|
||||
cogl_shader_destroy (COGLint handle);
|
||||
|
||||
|
||||
void
|
||||
cogl_shader_source (COGLint shader,
|
||||
const gchar *source);
|
||||
void
|
||||
cogl_shader_compile (COGLint shader_handle);
|
||||
|
||||
void
|
||||
cogl_shader_get_info_log (COGLint handle,
|
||||
guint size,
|
||||
gchar *buffer);
|
||||
|
||||
void
|
||||
cogl_shader_get_parameteriv (COGLint handle,
|
||||
COGLenum pname,
|
||||
COGLint *dest);
|
||||
|
||||
|
||||
COGLint
|
||||
cogl_create_program (void);
|
||||
|
||||
void
|
||||
cogl_program_destroy (COGLint handle);
|
||||
|
||||
void
|
||||
cogl_program_attach_shader (COGLint program_handle,
|
||||
COGLint shader_handle);
|
||||
|
||||
/* 0 to use none */
|
||||
void
|
||||
cogl_program_link (COGLint program_handle);
|
||||
|
||||
void
|
||||
cogl_program_use (COGLint program_handle);
|
||||
|
||||
COGLint
|
||||
cogl_program_get_uniform_location (COGLint program_int,
|
||||
const gchar *uniform_name);
|
||||
|
||||
|
||||
void
|
||||
cogl_program_uniform_1f (COGLint uniform_no,
|
||||
gfloat value);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __COGL_H__ */
|
||||
|
@ -698,6 +698,12 @@ typedef GLuint COGLuint;
|
||||
#define CGL_UNSIGNED_SHORT_8_8_MESA 0
|
||||
#endif
|
||||
|
||||
#define CGL_FRAGMENT_SHADER GL_FRAGMENT_SHADER_ARB
|
||||
#define CGL_VERTEX_SHADER GL_VERTEX_SHADER_ARB
|
||||
|
||||
#define CGL_OBJECT_COMPILE_STATUS GL_OBJECT_COMPILE_STATUS_ARB
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
|
@ -621,6 +621,12 @@ cogl_get_features ()
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cogl_check_extension ("GL_ARB_vertex_shader", gl_extensions) &&
|
||||
cogl_check_extension ("GL_ARB_fragment_shader", gl_extensions))
|
||||
{
|
||||
flags |= CLUTTER_FEATURE_SHADERS_GLSL;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
@ -746,3 +752,134 @@ cogl_fog_set (const ClutterColor *fog_color,
|
||||
glFogf (GL_FOG_START, CLUTTER_FIXED_TO_FLOAT (start));
|
||||
glFogf (GL_FOG_END, CLUTTER_FIXED_TO_FLOAT (stop));
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
||||
#define PROC(rettype, retval, procname, args...) \
|
||||
static rettype (*proc) (args) = NULL; \
|
||||
if (proc == NULL) \
|
||||
{ \
|
||||
proc = (void*)cogl_get_proc_address (#procname);\
|
||||
if (!proc)\
|
||||
{\
|
||||
g_warning ("failed to lookup proc: %s", #procname);\
|
||||
return retval;\
|
||||
}\
|
||||
}
|
||||
#else
|
||||
|
||||
#define PROC(rettype, retval, procname, ...) \
|
||||
static rettype (*proc) (__VA_ARGS__) = NULL; \
|
||||
if (proc == NULL) \
|
||||
{ \
|
||||
proc = (void*)cogl_get_proc_address (#procname);\
|
||||
if (!proc)\
|
||||
{\
|
||||
g_warning ("failed to lookup proc: %s", #procname);\
|
||||
return retval;\
|
||||
}\
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
COGLint
|
||||
cogl_create_program (void)
|
||||
{
|
||||
PROC (GLhandleARB, 0, glCreateProgramObjectARB, void);
|
||||
return proc ();
|
||||
}
|
||||
|
||||
COGLint
|
||||
cogl_create_shader (COGLenum shaderType)
|
||||
{
|
||||
PROC (GLhandleARB, 0, glCreateShaderObjectARB, GLenum);
|
||||
return proc (shaderType);
|
||||
}
|
||||
|
||||
void
|
||||
cogl_shader_source (COGLint shader,
|
||||
const gchar *source)
|
||||
{
|
||||
PROC (GLvoid,, glShaderSourceARB, GLhandleARB, GLsizei, const GLcharARB **, const GLint *)
|
||||
proc (shader, 1, &source, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
cogl_shader_compile (COGLint shader_handle)
|
||||
{
|
||||
PROC (GLvoid,, glCompileShaderARB, GLhandleARB);
|
||||
proc (shader_handle);
|
||||
}
|
||||
|
||||
void
|
||||
cogl_program_attach_shader (COGLint program_handle,
|
||||
COGLint shader_handle)
|
||||
{
|
||||
PROC (GLvoid,, glAttachObjectARB, GLhandleARB, GLhandleARB);
|
||||
proc (program_handle, shader_handle);
|
||||
}
|
||||
|
||||
void
|
||||
cogl_program_link (COGLint program_handle)
|
||||
{
|
||||
PROC (GLvoid,, glLinkProgramARB, GLhandleARB);
|
||||
proc (program_handle);
|
||||
}
|
||||
|
||||
void
|
||||
cogl_program_use (COGLint program_handle)
|
||||
{
|
||||
PROC (GLvoid,, glUseProgramObjectARB, GLhandleARB);
|
||||
proc (program_handle);
|
||||
}
|
||||
|
||||
COGLint
|
||||
cogl_program_get_uniform_location (COGLint program_handle,
|
||||
const gchar *uniform_name)
|
||||
{
|
||||
PROC (GLint,0, glGetUniformLocationARB, GLhandleARB, const GLcharARB *)
|
||||
return proc (program_handle, uniform_name);
|
||||
}
|
||||
|
||||
void
|
||||
cogl_program_destroy (COGLint handle)
|
||||
{
|
||||
PROC (GLvoid,, glDeleteObjectARB, GLhandleARB);
|
||||
proc (handle);
|
||||
}
|
||||
|
||||
void
|
||||
cogl_shader_destroy (COGLint handle)
|
||||
{
|
||||
PROC (GLvoid,, glDeleteObjectARB, GLhandleARB);
|
||||
proc (handle);
|
||||
}
|
||||
|
||||
void
|
||||
cogl_shader_get_info_log (COGLint handle,
|
||||
guint size,
|
||||
gchar *buffer)
|
||||
{
|
||||
gint len;
|
||||
PROC (GLvoid,, glGetInfoLogARB, GLhandleARB, GLsizei, GLsizei *, GLcharARB *);
|
||||
proc (handle, size-1, &len, buffer);
|
||||
buffer[len]='\0';
|
||||
}
|
||||
|
||||
void
|
||||
cogl_shader_get_parameteriv (COGLint handle,
|
||||
COGLenum pname,
|
||||
COGLint *dest)
|
||||
{
|
||||
PROC (GLvoid,, glGetObjectParameterivARB, GLhandleARB, GLenum, GLint*)
|
||||
proc (handle, pname, dest);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cogl_program_uniform_1f (COGLint uniform_no,
|
||||
gfloat value)
|
||||
{
|
||||
PROC (GLvoid,, glUniform1fARB, GLint, GLfloat);
|
||||
proc (uniform_no, value);
|
||||
}
|
||||
|
@ -460,6 +460,24 @@ typedef GLuint COGLuint;
|
||||
#define CGL_UNSIGNED_SHORT_8_8_REV_MESA 0
|
||||
#define CGL_UNSIGNED_SHORT_8_8_MESA 0
|
||||
|
||||
#ifdef GL_FRAGMENT_SHADER
|
||||
#define CGL_FRAGMENT_SHADER GL_FRAGMENT_SHADER
|
||||
#else
|
||||
#define CGL_FRAGMENT_SHADER 0
|
||||
#endif
|
||||
|
||||
#ifdef GL_VERTEX_SHADER
|
||||
#define CGL_VERTEX_SHADER GL_VERTEX_SHADER
|
||||
#else
|
||||
#define CGL_VERTEX_SHADER 0
|
||||
#endif
|
||||
|
||||
#ifdef GL_OBJECT_COMPILE_STATUS
|
||||
#define CGL_OBJECT_COMPILE_STATUS GL_OBJECT_COMPILE_STATUS
|
||||
#else
|
||||
#define CGL_OBJECT_COMPILE_STATUS 0
|
||||
#endif
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
|
@ -214,13 +214,13 @@ cogl_enable (gulong flags)
|
||||
if (flags & CGL_ENABLE_TEXTURE_RECT)
|
||||
{
|
||||
if (!(__enable_flags & CGL_ENABLE_TEXTURE_RECT))
|
||||
glEnable (GL_TEXTURE_RECTANGLE_ARB);
|
||||
glEnable (GL_TEXTURE_RECTANGLE_);
|
||||
|
||||
__enable_flags |= CGL_ENABLE_TEXTURE_RECT;
|
||||
}
|
||||
else if (__enable_flags & CGL_ENABLE_TEXTURE_RECT)
|
||||
{
|
||||
glDisable (GL_TEXTURE_RECTANGLE_ARB);
|
||||
glDisable (GL_TEXTURE_RECTANGLE_);
|
||||
__enable_flags &= ~CGL_ENABLE_TEXTURE_RECT;
|
||||
}
|
||||
#endif
|
||||
@ -630,3 +630,67 @@ cogl_fog_set (const ClutterColor *fog_color,
|
||||
glFogx (GL_FOG_START, (GLfixed) z_near);
|
||||
glFogx (GL_FOG_END, (GLfixed) z_far);
|
||||
}
|
||||
|
||||
COGLint cogl_create_program (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
COGLint cogl_create_shader (COGLenum shaderType)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cogl_shader_source (COGLint shader,
|
||||
const gchar *source)
|
||||
{
|
||||
}
|
||||
|
||||
void cogl_shader_compile (COGLint shader_handle)
|
||||
{
|
||||
}
|
||||
|
||||
void cogl_program_attach_shader (COGLint program_handle,
|
||||
COGLint shader_handle)
|
||||
{
|
||||
}
|
||||
|
||||
void cogl_program_link (COGLint program_handle)
|
||||
{
|
||||
}
|
||||
|
||||
void cogl_program_use (COGLint program_handle)
|
||||
{
|
||||
}
|
||||
|
||||
COGLint cogl_program_get_uniform_location (COGLint program_handle,
|
||||
const gchar *uniform_name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cogl_program_destroy (COGLint handle)
|
||||
{
|
||||
}
|
||||
|
||||
void cogl_shader_destroy (COGLint handle)
|
||||
{
|
||||
}
|
||||
|
||||
void cogl_shader_get_info_log (COGLint handle,
|
||||
guint size,
|
||||
gchar *buffer)
|
||||
{
|
||||
}
|
||||
|
||||
void cogl_shader_get_parameteriv (COGLint handle,
|
||||
COGLenum pname,
|
||||
COGLint *dest)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void cogl_program_uniform_1f (COGLint uniform_no,
|
||||
gfloat value)
|
||||
{
|
||||
}
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "../clutter-private.h"
|
||||
#include "../clutter-debug.h"
|
||||
#include "../clutter-units.h"
|
||||
#include "../clutter-shader.h"
|
||||
|
||||
#include "cogl.h"
|
||||
|
||||
@ -60,6 +61,9 @@ clutter_stage_glx_unrealize (ClutterActor *actor)
|
||||
|
||||
clutter_x11_trap_x_errors ();
|
||||
|
||||
/* Unrealize all shaders, since the GL context is going away */
|
||||
clutter_shader_release_all ();
|
||||
|
||||
if (G_UNLIKELY (was_offscreen))
|
||||
{
|
||||
if (stage_glx->glxpixmap)
|
||||
|
@ -2,7 +2,7 @@ noinst_PROGRAMS = test-textures test-events test-offscreen test-scale \
|
||||
test-actors test-behave test-text test-entry test-project \
|
||||
test-perspective test-rotate test-depth \
|
||||
test-threads test-timeline test-score test-script \
|
||||
test-model test-grab test-effects test-fullscreen
|
||||
test-model test-grab test-effects test-fullscreen test-shader
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/
|
||||
LDADD = $(top_builddir)/clutter/libclutter-@CLUTTER_FLAVOUR@-@CLUTTER_MAJORMINOR@.la
|
||||
@ -24,6 +24,7 @@ test_rotate_SOURCES = test-rotate.c
|
||||
test_depth_SOURCES = test-depth.c
|
||||
test_threads_SOURCES = test-threads.c
|
||||
test_timeline_SOURCES = test-timeline.c
|
||||
test_shader_SOURCES = test-shader.c
|
||||
test_score_SOURCES = test-score.c
|
||||
test_script_SOURCES = test-script.c
|
||||
test_model_SOURCES = test-model.c
|
||||
|
246
tests/test-shader.c
Normal file
246
tests/test-shader.c
Normal file
@ -0,0 +1,246 @@
|
||||
/* #define TEST_GROUP 1 */
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <glib.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gchar *name;
|
||||
gchar *source;
|
||||
} ShaderSource;
|
||||
|
||||
static ShaderSource shaders[]=
|
||||
{
|
||||
{"brightness-contrast",
|
||||
|
||||
"uniform float brightness;"
|
||||
"uniform float contrast;"
|
||||
"uniform sampler2DRect pend_s3_tex;"
|
||||
""
|
||||
"void main()"
|
||||
"{"
|
||||
" vec4 pend_s4_result;"
|
||||
" pend_s4_result = texture2DRect(pend_s3_tex, gl_TexCoord[0].xy);"
|
||||
" pend_s4_result.x = (pend_s4_result.x - 0.5)*contrast + brightness + 0.5;"
|
||||
" pend_s4_result.y = (pend_s4_result.y - 0.5)*contrast + brightness + 0.5;"
|
||||
" pend_s4_result.z = (pend_s4_result.z - 0.5)*contrast + brightness + 0.5;"
|
||||
" gl_FragColor = pend_s4_result;"
|
||||
"}",
|
||||
},
|
||||
{"box-blur",
|
||||
|
||||
"uniform float radius ;"
|
||||
"uniform sampler2DRect rectTexture;"
|
||||
""
|
||||
"void main()"
|
||||
"{"
|
||||
" vec4 color = texture2DRect(rectTexture, gl_TexCoord[0].st);"
|
||||
" float u;"
|
||||
" float v;"
|
||||
" int count = 1;"
|
||||
" for (u=-radius;u<radius;u++)"
|
||||
" for (v=-radius;v<radius;v++)"
|
||||
" {"
|
||||
" color += texture2DRect(rectTexture, vec2(gl_TexCoord[0].s + u * 2, gl_TexCoord[0].t +v * 2));"
|
||||
" count ++;"
|
||||
" }"
|
||||
""
|
||||
" gl_FragColor = color / count;"
|
||||
"}"
|
||||
},
|
||||
{"brightness-contrast.asm",
|
||||
|
||||
"!!ARBfp1.0\n"
|
||||
"PARAM brightness = program.local[0];\n"
|
||||
"PARAM contrast = program.local[1];\n"
|
||||
"\n"
|
||||
"TEMP R0;\n"
|
||||
"TEX R0, fragment.texcoord[0], texture[0], RECT;\n"
|
||||
"ADD R0.z, R0, -0.5;\n"
|
||||
"MUL R0.z, R0, contrast.x;\n"
|
||||
"ADD R0.z, R0, brightness.x;\n"
|
||||
"ADD R0.y, R0, -0.5;\n"
|
||||
"ADD R0.x, R0, -0.5;\n"
|
||||
"MUL R0.y, R0, contrast.x;\n"
|
||||
"MUL R0.x, R0, contrast.x;\n"
|
||||
"ADD R0.y, R0, brightness.x;\n"
|
||||
"ADD R0.x, R0, brightness.x;\n"
|
||||
"ADD result.color.z, R0, 0.5;\n"
|
||||
"ADD result.color.y, R0, 0.5;\n"
|
||||
"ADD result.color.x, R0, 0.5;\n"
|
||||
"MOV result.color.w, R0;\n"
|
||||
"END ",
|
||||
},
|
||||
{"invert",
|
||||
|
||||
"uniform sampler2DRect tex;\n"
|
||||
"void main ()\n"
|
||||
"{\n"
|
||||
" vec4 color = texture2DRect (tex, vec2(gl_TexCoord[0].st));\n"
|
||||
" gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0) - color;\n"
|
||||
" gl_FragColor.a = color.a;\n"
|
||||
"}"
|
||||
},
|
||||
{"brightness-contrast",
|
||||
|
||||
"uniform sampler2DRect tex;"
|
||||
"uniform float brightness;"
|
||||
"uniform float contrast;"
|
||||
"void main ()"
|
||||
"{"
|
||||
" vec4 color = texture2DRect (tex, vec2(gl_TexCoord[0].st));"
|
||||
" color.r = (color.r - 0.5) * contrast + brightness + 0.5;"
|
||||
" color.g = (color.g - 0.5) * contrast + brightness + 0.5;"
|
||||
" color.b = (color.b - 0.5) * contrast + brightness + 0.5;"
|
||||
" gl_FragColor = color;"
|
||||
"}",
|
||||
},
|
||||
{"gray",
|
||||
"uniform sampler2DRect tex;"
|
||||
"void main ()"
|
||||
"{"
|
||||
" vec4 color = texture2DRect (tex, vec2(gl_TexCoord[0].st));"
|
||||
" float avg = (color.r + color.g + color.b) / 3;"
|
||||
" color.r = avg;"
|
||||
" color.g = avg;"
|
||||
" color.b = avg;"
|
||||
" gl_FragColor = color;"
|
||||
"}",
|
||||
},
|
||||
{"combined-mirror",
|
||||
"uniform sampler2DRect tex;"
|
||||
"void main ()"
|
||||
"{"
|
||||
" vec4 color = texture2DRect (tex, vec2(gl_TexCoord[0].st));"
|
||||
" vec4 colorB = texture2DRect (tex, vec2(gl_TexCoord[0].ts));"
|
||||
" float avg = (color.r + color.g + color.b) / 3;"
|
||||
" color.r = avg;"
|
||||
" color.g = avg;"
|
||||
" color.b = avg;"
|
||||
" color = (color + colorB)/2;"
|
||||
" gl_FragColor = color;"
|
||||
"}",
|
||||
},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static gint shader_no=0;
|
||||
|
||||
static gboolean
|
||||
button_release_cb (ClutterActor *actor,
|
||||
ClutterEvent *event,
|
||||
gpointer data)
|
||||
{
|
||||
gint new_no;
|
||||
if (event->button.button == 1)
|
||||
{
|
||||
new_no = shader_no-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_no = shader_no+1;
|
||||
}
|
||||
|
||||
if (new_no >= 0 && shaders[new_no].name)
|
||||
{
|
||||
ClutterShader *shader;
|
||||
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);
|
||||
|
||||
clutter_actor_set_shader_param (actor, "radius", 3.0);
|
||||
clutter_redraw();
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
gint
|
||||
main (gint argc,
|
||||
gchar *argv[])
|
||||
{
|
||||
ClutterTimeline *timeline;
|
||||
ClutterAlpha *alpha;
|
||||
ClutterActor *actor;
|
||||
ClutterActor *stage;
|
||||
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);
|
||||
|
||||
if (!pixbuf)
|
||||
g_error("pixbuf load failed");
|
||||
|
||||
clutter_stage_set_title (CLUTTER_STAGE (stage), "Shader Test");
|
||||
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
|
||||
|
||||
/* Create a timeline to manage animation */
|
||||
timeline = clutter_timeline_new (360, 60); /* num frames, fps */
|
||||
g_object_set (timeline, "loop", TRUE, NULL); /* have it loop */
|
||||
|
||||
#ifndef TEST_GROUP
|
||||
actor = clutter_texture_new_from_pixbuf (pixbuf);
|
||||
#else
|
||||
actor = clutter_group_new ();
|
||||
{
|
||||
ClutterActor *child1, *child2, *child3, *child4;
|
||||
ClutterColor color={0xff, 0x22, 0x66, 0x99};
|
||||
|
||||
child1 = clutter_texture_new_from_pixbuf (pixbuf);
|
||||
child2 = clutter_texture_new_from_pixbuf (pixbuf);
|
||||
child3 = clutter_rectangle_new ();
|
||||
child4 = clutter_label_new_with_text ("Sans 20px", "Shady stuff");
|
||||
|
||||
clutter_rectangle_set_color (child3, &color);
|
||||
clutter_actor_set_size (child3, 50, 50);
|
||||
clutter_actor_set_position (child1, 0, 0);
|
||||
clutter_actor_set_position (child2, 50, 100);
|
||||
clutter_actor_set_position (child3, 30, -30);
|
||||
clutter_actor_set_position (child4, -50, 20);
|
||||
|
||||
clutter_group_add (CLUTTER_GROUP (actor), child1);
|
||||
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_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_actor_set_reactive (actor, TRUE);
|
||||
g_signal_connect (actor, "button-release-event",
|
||||
G_CALLBACK (button_release_cb), NULL);
|
||||
|
||||
/* Show everying ( and map window ) */
|
||||
clutter_actor_show_all (stage);
|
||||
|
||||
/* and start it */
|
||||
clutter_timeline_start (timeline);
|
||||
|
||||
clutter_main ();
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user