diff --git a/clutter/cogl/cogl-material.h b/clutter/cogl/cogl-material.h new file mode 100644 index 000000000..9a6f0eb10 --- /dev/null +++ b/clutter/cogl/cogl-material.h @@ -0,0 +1,481 @@ +#if !defined(__COGL_H_INSIDE__) && !defined(CLUTTER_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __COGL_MATERIAL_H__ +#define __COGL_MATERIAL_H__ + +G_BEGIN_DECLS + +#include +#include + +/** + * SECTION:cogl-material + * @short_description: Fuctions for creating and manipulating materials + * + * COGL allows creating and manipulating materials used to fill in + * geometry. Materials may simply be lighting attributes (such as an + * ambient and diffuse colour) or might represent one or more textures + * blended together. + */ + +G_END_DECLS + +typedef enum _CoglMaterialAlphaFunc +{ + COGL_MATERIAL_ALPHA_FUNC_NEVER = GL_NEVER, + COGL_MATERIAL_ALPHA_FUNC_LESS = GL_LESS, + COGL_MATERIAL_ALPHA_FUNC_EQUAL = GL_EQUAL, + COGL_MATERIAL_ALPHA_FUNC_LEQUAL = GL_LEQUAL, + COGL_MATERIAL_ALPHA_FUNC_GREATER = GL_GREATER, + COGL_MATERIAL_ALPHA_FUNC_NOTEQUAL = GL_NOTEQUAL, + COGL_MATERIAL_ALPHA_FUNC_GEQUAL = GL_GEQUAL, + COGL_MATERIAL_ALPHA_FUNC_ALWAYS = GL_ALWAYS +} CoglMaterialAlphaFunc; + +typedef enum _CoglMaterialBlendFactor +{ + COGL_MATERIAL_BLEND_FACTOR_ZERO = GL_ZERO, + COGL_MATERIAL_BLEND_FACTOR_ONE = GL_ONE, + COGL_MATERIAL_BLEND_FACTOR_DST_COLOR = GL_DST_COLOR, + COGL_MATERIAL_BLEND_FACTOR_SRC_COLOR = GL_SRC_COLOR, + COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_DST_COLOR = GL_ONE_MINUS_DST_COLOR, + COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_SRC_COLOR = GL_ONE_MINUS_SRC_COLOR, + COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA = GL_SRC_ALPHA, + COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA = GL_ONE_MINUS_SRC_ALPHA, + COGL_MATERIAL_BLEND_FACTOR_DST_ALPHA = GL_DST_ALPHA, + COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_DST_ALPHA = GL_ONE_MINUS_DST_ALPHA, + COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA_SATURATE = GL_SRC_ALPHA_SATURATE, + COGL_MATERIAL_BLEND_FACTOR_CONSTANT_COLOR = GL_CONSTANT_COLOR, + COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR = + GL_ONE_MINUS_CONSTANT_COLOR, + COGL_MATERIAL_BLEND_FACTOR_CONSTANT_ALPHA = GL_CONSTANT_ALPHA, + COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA = + GL_ONE_MINUS_CONSTANT_ALPHA +} CoglMaterialBlendFactor; + +typedef enum _CoglMaterialLayerType +{ + COGL_MATERIAL_LAYER_TYPE_TEXTURE +} CoglMaterialLayerType; + +typedef enum _CoglMaterialLayerCombineFunc +{ + COGL_MATERIAL_LAYER_COMBINE_FUNC_REPLACE = GL_REPLACE, + COGL_MATERIAL_LAYER_COMBINE_FUNC_MODULATE = GL_MODULATE, + COGL_MATERIAL_LAYER_COMBINE_FUNC_ADD = GL_ADD, + COGL_MATERIAL_LAYER_COMBINE_FUNC_ADD_SIGNED = GL_ADD_SIGNED, + COGL_MATERIAL_LAYER_COMBINE_FUNC_INTERPOLATE = GL_INTERPOLATE, + COGL_MATERIAL_LAYER_COMBINE_FUNC_SUBTRACT = GL_SUBTRACT, + COGL_MATERIAL_LAYER_COMBINE_FUNC_DOT3_RGB = GL_DOT3_RGB, + COGL_MATERIAL_LAYER_COMBINE_FUNC_DOT3_RGBA = GL_DOT3_RGBA +} CoglMaterialLayerCombineFunc; + +typedef enum _CoglMaterialLayerCombineChannels +{ + COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB, + COGL_MATERIAL_LAYER_COMBINE_CHANNELS_ALPHA, + COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA +} CoglMaterialLayerCombineChannels; + +typedef enum _CoglMaterialLayerCombineSrc +{ + COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE = GL_TEXTURE, + + /* Can we find a nicer way... */ + COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE0 = GL_TEXTURE0, + COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE1 = GL_TEXTURE1, + COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE2 = GL_TEXTURE2, + COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE3 = GL_TEXTURE3, + COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE4 = GL_TEXTURE4, + COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE5 = GL_TEXTURE5, + COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE6 = GL_TEXTURE6, + COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE7 = GL_TEXTURE7, + /* .. who would ever need more than 8 texture layers.. :-) */ + + COGL_MATERIAL_LAYER_COMBINE_SRC_CONSTANT = GL_CONSTANT, + COGL_MATERIAL_LAYER_COMBINE_SRC_PRIMARY_COLOR = GL_PRIMARY_COLOR, + COGL_MATERIAL_LAYER_COMBINE_SRC_PREVIOUS = GL_PREVIOUS +} CoglMaterialLayerCombineSrc; + +typedef enum _CoglMaterialLayerCombineOp +{ + COGL_MATERIAL_LAYER_COMBINE_OP_SRC_COLOR = GL_SRC_COLOR, + COGL_MATERIAL_LAYER_COMBINE_OP_ONE_MINUS_SRC_COLOR = GL_ONE_MINUS_SRC_COLOR, + + COGL_MATERIAL_LAYER_COMBINE_OP_SRC_ALPHA = GL_SRC_ALPHA, + COGL_MATERIAL_LAYER_COMBINE_OP_ONE_MINUS_SRC_ALPHA = GL_ONE_MINUS_SRC_ALPHA +} CoglMaterialLayerCombineOp; + +/** + * cogl_material_new: + * + * Allocates and initializes blank white material + */ +CoglHandle cogl_material_new (void); + +/** + * cogl_material_ref: + * @handle: a @CoglHandle. + * + * Increment the reference count for a cogl material. + * + * Returns: the @handle. + */ +CoglHandle cogl_material_ref (CoglHandle handle); + +/** + * cogl_material_unref: + * @handle: a @CoglHandle. + * + * Deccrement the reference count for a cogl material. + */ +void cogl_material_unref (CoglHandle handle); + +/** + * cogl_material_set_diffuse: + * @material: A CoglMaterial object + * @diffuse: The components of the desired diffuse color + * + * Exposing the standard OpenGL lighting model; this function sets + * the material's diffuse color. The diffuse color is most intense + * where the light hits the surface directly; perpendicular to the + * surface. + */ +void cogl_material_set_diffuse (CoglHandle material, + const CoglColor *diffuse); + +/** + * cogl_material_set_ambient: + * @material: A CoglMaterial object + * @ambient: The components of the desired ambient color + * + * Exposing the standard OpenGL lighting model; this function sets + * the material's ambient color. The ambient color affects the overall + * color of the object. Since the diffuse color will be intense when + * the light hits the surface directly, the ambient will most aparent + * where the light hits at a slant. + */ +void cogl_material_set_ambient (CoglHandle material, + const CoglColor *ambient); + +/** + * cogl_material_set_ambient_and_diffuse: + * @material: A CoglMaterial object + * @color: The components of the desired ambient and diffuse colors + * + * This is a convenience for setting the diffuse and ambient color + * of the material at the same time. + */ +void cogl_material_set_ambient_and_diffuse (CoglHandle material, + const CoglColor *color); + +/** + * cogl_material_set_specular: + * @material: A CoglMaterial object + * @specular: The components of the desired specular color + * + * Exposing the standard OpenGL lighting model; this function sets + * the material's specular color. The intensity of the specular color + * depends on the viewport position, and is brightest along the lines + * of reflection. + */ +void cogl_material_set_specular (CoglHandle material, + const CoglColor *specular); + +/** + * cogl_material_set_shininess: + * @material: A CoglMaterial object + * shininess: The desired shininess; range: [0.0, 1.0] + * + * This function sets the materials shininess which determines how + * specular highlights are calculated. A higher shininess will produce + * smaller brigher highlights. + */ +void cogl_material_set_shininess (CoglHandle material, + float shininess); + +/** + * cogl_material_set_emission: + * @material: A CoglMaterial object + * @emission: The components of the desired emissive color + * + * Exposing the standard OpenGL lighting model; this function sets + * the material's emissive color. It will look like the surface is + * a light source emitting this color. + */ +void cogl_material_set_emission (CoglHandle material, + const CoglColor *emission); + +/** + * cogl_set_source: + * @material: A CoglMaterial object + * + * This function sets the source material that will be used to fill + * subsequent geometry emitted via the cogl API. + * + * XXX: This doesn't really belong to the cogl-material API, it should + * move to cogl.h + */ +void cogl_set_source (CoglHandle material); + +/** + * cogl_material_set_alpha_test_func: + * @material: A CoglMaterial object + * + * Before a primitive is blended with the framebuffer, it goes through an + * alpha test stage which lets you discard fragments based on the current + * alpha value. This function lets you change the function used to evaluate + * the alpha channel, and thus determine which fragments are discarded + * and which continue on to the blending stage. + * TODO: expand on this + */ +void cogl_material_set_alpha_test_func (CoglHandle material, + CoglMaterialAlphaFunc alpha_func, + float alpha_reference); + +/** + * cogl_material_set_blend_function: + * @material: A CoglMaterial object + * @src_factor: Chooses the source factor you want plugged in to the blend + * equation. + * @dst_factor: Chooses the source factor you want plugged in to the blend + * equation. + * + * This function lets you control how primitives using this material will get + * blended with the contents of your framebuffer. The blended RGBA components + * are calculated like this: + * + * (RsSr+RdDr, GsSg+GdDg, BsSb+BsSb, AsSa+AdDa) + * + * Where (Rs,Gs,Bs,As) represents your source - material- color, + * (Rd,Gd,Bd,Ad) represents your destination - framebuffer - color, + * (Sr,Sg,Sb,Sa) represents your source blend factor and + * (Dr,Dg,Db,Da) represents you destination blend factor. + * + * All factors lie in the range [0,1] and incoming color components are also + * normalized to the range [0,1] + * + * The factors are selected with the following constants: + * + * COGL_MATERIAL_BLEND_FACTOR_ZERO: (0,0,0,0) + * COGL_MATERIAL_BLEND_FACTOR_ONE: (1,1,1,1) + * COGL_MATERIAL_BLEND_FACTOR_DST_COLOR: (Rd,Gd,Bd,Ad) + * COGL_MATERIAL_BLEND_FACTOR_SRC_COLOR: (Rs,Gs,Bs,As) + * COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_DST_COLOR: + * (1,1,1,1)-(Rd,Gd,Bd,Ad) [Only valid for src_factor] + * COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_SRC_COLOR: + * (1,1,1,1)-(Rs,Gs,Bs,As) + * COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA: (As,As,As,As) + * COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA: + * (1,1,1,1)-(As,As,As,As) [Only valid for dst_factor] + * COGL_MATERIAL_BLEND_FACTOR_DST_ALPHA: (Ad,Ad,Ad,Ad) + * COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_DST_ALPHA: + * (1,1,1,1)-(Ad,Ad,Ad,Ad) + * COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA_SATURATE: + * (f,f,f,1) where f=MIN(As,1-Ad) + * + */ +void cogl_material_set_blend_function (CoglHandle material, + CoglMaterialBlendFactor src_factor, + CoglMaterialBlendFactor dst_factor); + +/** + * cogl_material_set_layer: + * @material: A CoglMaterial object + * + * In addition to the standard OpenGL lighting model a Cogl material may have + * one or more layers comprised of textures that can be blended together in + * order with a number of different texture combine modes. This function + * defines a new texture layer. + * + * The index values of multiple layers do not have to be consecutive; it is + * only their relative order that is important. + * + * XXX: In the future, we may define other types of material layers, such + * as purely GLSL based layers. + */ +void cogl_material_set_layer (CoglHandle material, + gint layer_index, + CoglHandle texture); + +/** + * cogl_material_add_texture: + * @material: A CoglMaterial object + * + * + */ +void cogl_material_remove_layer (CoglHandle material, + gint layer_index); + +/** + * cogl_material_set_layer_alpha_combine_func: + * @material: A CoglMaterial object + * + * TODO: Brew, a nice hot cup of tea, and document these functions... + */ +void cogl_material_set_layer_combine_func ( + CoglHandle material, + gint layer_index, + CoglMaterialLayerCombineChannels channels, + CoglMaterialLayerCombineFunc func); + +void cogl_material_set_layer_combine_arg_src ( + CoglHandle material, + gint layer_index, + gint argument, + CoglMaterialLayerCombineChannels channels, + CoglMaterialLayerCombineSrc src); + +void cogl_material_set_layer_combine_arg_op ( + CoglHandle material, + gint layer_index, + gint argument, + CoglMaterialLayerCombineChannels channels, + CoglMaterialLayerCombineOp op); + +/* TODO: */ +#if 0 + I think it would be be really neat to support a simple string description + of the fixed function texture combine modes exposed above. I think we can + consider this stuff to be set in stone from the POV that more advanced + texture combine functions are catered for with GLSL, so it seems reasonable + to find a concise string representation that can represent all the above + modes in a *much* more readable/useable fashion. I think somthing like + this would be quite nice: + + "MODULATE(TEXTURE[RGB], PREVIOUS[A])" + "ADD(TEXTURE[A],PREVIOUS[RGB])" + "INTERPOLATE(TEXTURE[1-A], PREVIOUS[RGB])" + +void cogl_material_set_layer_rgb_combine (CoglHandle material + gint layer_index, + const char *combine_description); +void cogl_material_set_layer_alpha_combine (CoglHandle material + gint layer_index, + const char *combine_description); +#endif + +/** + * cogl_material_set_layer_matrix: + * @material: A CoglMaterial object + * + * This function lets you set a matrix that can be used to e.g. translate + * and rotate a single layer of a material used to fill your geometry. + */ +void cogl_material_set_layer_matrix (CoglHandle material, + gint layer_index, + CoglMatrix *matrix); + +/** + * cogl_material_get_cogl_enable_flags: + * @material: A CoglMaterial object + * + * This determines what flags need to be passed to cogl_enable before + * this material can be used. Normally you shouldn't need to use this + * function directly since Cogl will do this internally, but if you are + * developing custom primitives directly with OpenGL you may want to use + * this. + * + * Note: This API is hopfully just a stop-gap solution. Ideally + * cogl_enable will be replaced. + */ +gulong +cogl_material_get_cogl_enable_flags (CoglHandle handle); + +/** + * cogl_material_flush_gl_material_state: + * @material: A CoglMaterial object + * + * This commits the glMaterial state to the OpenGL driver. Normally you + * shouldn't need to use this function directly, since Cogl will do this + * internally, but if you are developing custom primitives directly with + * OpenGL you may want to use this. + */ +void cogl_material_flush_gl_material_state (CoglHandle material_handle); + +/** + * cogl_material_flush_gl_alpha_func: + * @material: A CoglMaterial object + * + */ +void cogl_material_flush_gl_alpha_func (CoglHandle material_handle); + +/** + * cogl_material_flush_gl_blend_func: + * @material: A CoglMaterial object + * + */ +void cogl_material_flush_gl_blend_func (CoglHandle material_handle); + +/** + * cogl_material_get_layers: + * @material: A CoglMaterial object + * + * This function lets you access a materials internal list of layers + * for iteration. + * + * Note: Normally you shouldn't need to use this function directly since + * Cogl will do this internally, but if you are developing custom primitives + * directly with OpenGL, you will need to iterate the layers that you want + * to texture with. + * + * Note: This function may return more layers than OpenGL can use at once + * so it's your responsability limit yourself to + * CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS. + * + * Note: It's a bit out of the ordinary to return a const GList *, but it + * was considered sensible to try and avoid list manipulation for every + * primitive emitted in a scene, every frame. + */ +const GList *cogl_material_get_layers (CoglHandle material_handle); + +/** + * cogl_material_layer_get_type: + * @material: A CoglMaterial object + * + * Currently there is only one type of layer defined: + * COGL_MATERIAL_LAYER_TYPE_TEXTURE, but considering we may add purely GLSL + * based layers in the future, you should write code that checks the type + * first. + * + * Note: Normally you shouldn't need to use this function directly since + * Cogl will do this internally, but if you are developing custom primitives + * directly with OpenGL, you will need to iterate the layers that you want + * to texture with, and thus should be checking the layer types. + */ +CoglMaterialLayerType cogl_material_layer_get_type (CoglHandle layer_handle); + +/** + * cogl_material_layer_get_texture: + * @material: A CoglMaterial object + * + * This lets you extract a CoglTexture handle for a specific layer. Normally + * you shouldn't need to use this function directly since Cogl will do this + * internally, but if you are developing custom primitives directly with + * OpenGL you may need this. + * + * Note: In the future, we may support purely GLSL based layers which will + * likley return COGL_INVALID_HANDLE if you try to get the texture. + * Considering this, you should always call cogl_material_layer_get_type + * first, to check it is of type COGL_MATERIAL_LAYER_TYPE_TEXTURE. + */ +CoglHandle cogl_material_layer_get_texture (CoglHandle layer_handle); + +/** + * cogl_material_layer_flush_gl_sampler_state: + * @material: A CoglMaterial object + * + * This commits the sampler state for a single material layer to the OpenGL + * driver. Normally you shouldn't need to use this function directly since + * Cogl will do this internally, but if you are developing custom primitives + * directly with OpenGL you may want to use this. + * + * Note: It assumes you have already activated the appropriate sampler + * by calling glActiveTexture (); + */ +void cogl_material_layer_flush_gl_sampler_state (CoglHandle layer_handle); + +#endif /* __COGL_MATERIAL_H__ */ + diff --git a/clutter/cogl/cogl.h.in b/clutter/cogl/cogl.h.in index ea81c7b2c..091770227 100644 --- a/clutter/cogl/cogl.h.in +++ b/clutter/cogl/cogl.h.in @@ -33,9 +33,11 @@ #include #include +#include #include #include #include +#include #include #include #include diff --git a/clutter/cogl/common/Makefile.am b/clutter/cogl/common/Makefile.am index 755001e1f..f78a2c645 100644 --- a/clutter/cogl/common/Makefile.am +++ b/clutter/cogl/common/Makefile.am @@ -30,4 +30,5 @@ libclutter_cogl_common_la_SOURCES = \ cogl-fixed.c \ cogl-color.c \ cogl-mesh.c \ - cogl-matrix.c + cogl-matrix.c \ + cogl-material.c diff --git a/clutter/cogl/common/cogl-material-private.h b/clutter/cogl/common/cogl-material-private.h new file mode 100644 index 000000000..d64d8485b --- /dev/null +++ b/clutter/cogl/common/cogl-material-private.h @@ -0,0 +1,72 @@ +#ifndef __COGL_MATERIAL_PRIVATE_H +#define __COGL_MATERIAL_PRIVATE_H + +#include "cogl-material.h" +#include "cogl-matrix.h" + +#include + +typedef struct _CoglMaterial CoglMaterial; +typedef struct _CoglMaterialLayer CoglMaterialLayer; + +typedef enum _CoglMaterialLayerFlags +{ + COGL_MATERIAL_LAYER_FLAG_USER_MATRIX = 1L<<0, +} CoglMaterialLayerFlags; + +struct _CoglMaterialLayer +{ + guint ref_count; + guint index; /*!< lowest index is blended first then others + on top */ + gulong flags; + CoglHandle texture; /*!< The texture for this layer, or COGL_INVALID_HANDLE + for an empty layer */ + + /* Determines how the color of individual texture fragments + * are calculated. */ + CoglMaterialLayerCombineFunc texture_combine_rgb_func; + CoglMaterialLayerCombineSrc texture_combine_rgb_src[3]; + CoglMaterialLayerCombineOp texture_combine_rgb_op[3]; + + CoglMaterialLayerCombineFunc texture_combine_alpha_func; + CoglMaterialLayerCombineSrc texture_combine_alpha_src[3]; + CoglMaterialLayerCombineOp texture_combine_alpha_op[3]; + + /* TODO: Support purely GLSL based material layers */ + + CoglMatrix matrix; +}; + +typedef enum _CoglMaterialFlags +{ + COGL_MATERIAL_FLAG_ENABLE_BLEND = 1L<<0, + COGL_MATERIAL_FLAG_SHOWN_SAMPLER_WARNING = 1L<<1 +} CoglMaterialFlags; + +struct _CoglMaterial +{ + guint ref_count; + + gulong flags; + + /* Standard OpenGL lighting model attributes */ + GLfloat ambient[4]; + GLfloat diffuse[4]; + GLfloat specular[4]; + GLfloat emission[4]; + GLfloat shininess; + + /* Determines what fragments are discarded based on their alpha */ + CoglMaterialAlphaFunc alpha_func; + GLfloat alpha_func_reference; + + /* Determines how this material is blended with other primitives */ + CoglMaterialBlendFactor blend_src_factor; + CoglMaterialBlendFactor blend_dst_factor; + + GList *layers; +}; + +#endif /* __COGL_MATERIAL_PRIVATE_H */ + diff --git a/clutter/cogl/common/cogl-material.c b/clutter/cogl/common/cogl-material.c new file mode 100644 index 000000000..d720c120f --- /dev/null +++ b/clutter/cogl/common/cogl-material.c @@ -0,0 +1,680 @@ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "cogl.h" +#include "cogl-internal.h" +#include "cogl-context.h" +#include "cogl-handle.h" + +#include "cogl-material-private.h" + +#include + +static void _cogl_material_free (CoglMaterial *tex); +static void _cogl_material_layer_free (CoglMaterialLayer *layer); + +COGL_HANDLE_DEFINE (Material, material, material_handles); +COGL_HANDLE_DEFINE (MaterialLayer, + material_layer, + material_layer_handles); + +CoglHandle +cogl_material_new (void) +{ + /* Create new - blank - material */ + CoglMaterial *material = g_new0 (CoglMaterial, 1); + GLfloat *ambient = material->ambient; + GLfloat *diffuse = material->diffuse; + GLfloat *specular = material->specular; + GLfloat *emission = material->emission; + + material->ref_count = 1; + COGL_HANDLE_DEBUG_NEW (material, material); + + /* Use the same defaults as the GL spec... */ + ambient[0] = 0.2; ambient[1] = 0.2; ambient[2] = 0.2; ambient[3] = 1.0; + diffuse[0] = 0.8; diffuse[1] = 0.8; diffuse[2] = 0.8; diffuse[3] = 1.0; + specular[0] = 0; specular[1] = 0; specular[2] = 0; specular[3] = 1.0; + emission[0] = 0; emission[1] = 0; emission[2] = 0; emission[3] = 1.0; + + /* Use the same defaults as the GL spec... */ + material->alpha_func = COGL_MATERIAL_ALPHA_FUNC_ALWAYS; + material->alpha_func_reference = 0.0; + + /* Not the same as the GL default, but seems saner... */ + material->blend_src_factor = COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA; + material->blend_dst_factor = COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + + material->layers = NULL; + + return _cogl_material_handle_new (material); +} + +static void +_cogl_material_free (CoglMaterial *material) +{ + /* Frees material resources but its handle is not + released! Do that separately before this! */ + + g_list_foreach (material->layers, + (GFunc)cogl_material_layer_unref, NULL); + g_free (material); +} + +void +cogl_material_set_ambient (CoglHandle handle, + const CoglColor *ambient_color) +{ + CoglMaterial *material; + GLfloat *ambient; + + g_return_if_fail (cogl_is_material (handle)); + + material = _cogl_material_pointer_from_handle (handle); + + ambient = material->ambient; + ambient[0] = cogl_color_get_red_float (ambient_color); + ambient[1] = cogl_color_get_green_float (ambient_color); + ambient[2] = cogl_color_get_blue_float (ambient_color); + ambient[3] = cogl_color_get_alpha_float (ambient_color); + /* material->ambient = *ambient_color; */ +} + +void +cogl_material_set_diffuse (CoglHandle handle, + const CoglColor *diffuse_color) +{ + CoglMaterial *material; + GLfloat *diffuse; + + g_return_if_fail (cogl_is_material (handle)); + + material = _cogl_material_pointer_from_handle (handle); + + diffuse = material->diffuse; + diffuse[0] = cogl_color_get_red_float (diffuse_color); + diffuse[1] = cogl_color_get_green_float (diffuse_color); + diffuse[2] = cogl_color_get_blue_float (diffuse_color); + diffuse[3] = cogl_color_get_alpha_float (diffuse_color); + /* material->diffuse = *diffuse_color; */ +} + +void +cogl_material_set_ambient_and_diffuse (CoglHandle handle, + const CoglColor *color) +{ + cogl_material_set_ambient (handle, color); + cogl_material_set_diffuse (handle, color); +} + +void +cogl_material_set_specular (CoglHandle handle, + const CoglColor *specular_color) +{ + CoglMaterial *material; + GLfloat *specular; + + g_return_if_fail (cogl_is_material (handle)); + + material = _cogl_material_pointer_from_handle (handle); + + specular = material->specular; + specular[0] = cogl_color_get_red_float (specular_color); + specular[1] = cogl_color_get_green_float (specular_color); + specular[2] = cogl_color_get_blue_float (specular_color); + specular[3] = cogl_color_get_alpha_float (specular_color); + /* material->specular = *specular_color; */ +} + +void +cogl_material_set_shininess (CoglHandle handle, + float shininess) +{ + CoglMaterial *material; + + g_return_if_fail (cogl_is_material (handle)); + + if (shininess < 0.0 || shininess > 1.0) + g_warning ("Out of range shininess %f supplied for material\n", + shininess); + + material = _cogl_material_pointer_from_handle (handle); + + material->shininess = (GLfloat)shininess * 128.0; +} + +void +cogl_material_set_emission (CoglHandle handle, + const CoglColor *emission_color) +{ + CoglMaterial *material; + GLfloat *emission; + + g_return_if_fail (cogl_is_material (handle)); + + material = _cogl_material_pointer_from_handle (handle); + + emission = material->emission; + emission[0] = cogl_color_get_red_float (emission_color); + emission[1] = cogl_color_get_green_float (emission_color); + emission[2] = cogl_color_get_blue_float (emission_color); + emission[3] = cogl_color_get_alpha_float (emission_color); + /* material->emission = *emission_color; */ +} + +/* TODO: Should go in cogl.c */ +void +cogl_set_source (CoglHandle material_handle) +{ + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + g_return_if_fail (cogl_is_material (material_handle)); + + if (ctx->source_material) + cogl_material_unref (ctx->source_material); + + cogl_material_ref (material_handle); + ctx->source_material = material_handle; +} + +void +cogl_material_set_alpha_test_func (CoglHandle handle, + CoglMaterialAlphaFunc alpha_func, + float alpha_reference) +{ + CoglMaterial *material; + + g_return_if_fail (cogl_is_material (handle)); + + material = _cogl_material_pointer_from_handle (handle); + material->alpha_func = alpha_func; + material->alpha_func_reference = (GLfloat)alpha_reference; +} + +void +cogl_material_set_blend_function (CoglHandle handle, + CoglMaterialBlendFactor src_factor, + CoglMaterialBlendFactor dst_factor) +{ + CoglMaterial *material; + + g_return_if_fail (cogl_is_material (handle)); + + material = _cogl_material_pointer_from_handle (handle); + material->blend_src_factor = src_factor; + material->blend_dst_factor = dst_factor; +} + +/* Asserts that a layer corresponding to the given index exists. If no + * match is found, then a new empty layer is added. + */ +static CoglMaterialLayer * +_cogl_material_get_layer (CoglMaterial *material, + gint index, + gboolean create_if_not_found) +{ + CoglMaterialLayer *layer; + GList *tmp; + CoglHandle layer_handle; + + for (tmp = material->layers; tmp != NULL; tmp = tmp->next) + { + layer = + _cogl_material_layer_pointer_from_handle ((CoglHandle)tmp->data); + if (layer->index == index) + return layer; + + /* The layers are always sorted, so at this point we know this layer + * doesn't exist */ + if (layer->index > index) + break; + } + /* NB: if we now insert a new layer before tmp, that will maintain order. + */ + + if (!create_if_not_found) + return NULL; + + layer = g_new0 (CoglMaterialLayer, 1); + + layer->ref_count = 1; + layer->index = index; + layer->texture = COGL_INVALID_HANDLE; + + /* Choose the same default combine mode as OpenGL: + * MODULATE(PREVIOUS[RGBA],TEXTURE[RGBA]) */ + layer->texture_combine_rgb_func = COGL_MATERIAL_LAYER_COMBINE_FUNC_MODULATE; + layer->texture_combine_rgb_src[0] = COGL_MATERIAL_LAYER_COMBINE_SRC_PREVIOUS; + layer->texture_combine_rgb_src[1] = COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE; + layer->texture_combine_rgb_op[0] = COGL_MATERIAL_LAYER_COMBINE_OP_SRC_COLOR; + layer->texture_combine_rgb_op[1] = COGL_MATERIAL_LAYER_COMBINE_OP_SRC_COLOR; + layer->texture_combine_alpha_func = + COGL_MATERIAL_LAYER_COMBINE_FUNC_MODULATE; + layer->texture_combine_alpha_src[0] = + COGL_MATERIAL_LAYER_COMBINE_SRC_PREVIOUS; + layer->texture_combine_alpha_src[1] = + COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE; + layer->texture_combine_alpha_op[0] = + COGL_MATERIAL_LAYER_COMBINE_OP_SRC_ALPHA; + layer->texture_combine_alpha_op[1] = + COGL_MATERIAL_LAYER_COMBINE_OP_SRC_ALPHA; + + layer_handle = _cogl_material_layer_handle_new (layer); + /* Note: see comment after for() loop above */ + material->layers = + g_list_insert_before (material->layers, tmp, layer_handle); + + return layer; +} + +void +cogl_material_set_layer (CoglHandle material_handle, + gint layer_index, + CoglHandle texture_handle) +{ + CoglMaterial *material; + CoglMaterialLayer *layer; + int n_layers; + + g_return_if_fail (cogl_is_material (material_handle)); + g_return_if_fail (cogl_is_texture (texture_handle)); + + material = _cogl_material_pointer_from_handle (material_handle); + layer = _cogl_material_get_layer (material_handle, layer_index, TRUE); + + /* XXX: If we expose manual control over ENABLE_BLEND, we'll add + * a flag to know when it's user configured, so we don't trash it */ + if (cogl_texture_get_format (texture_handle) & COGL_A_BIT) + material->flags |= COGL_MATERIAL_FLAG_ENABLE_BLEND; + + n_layers = g_list_length (material->layers); + if (n_layers >= CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS) + { + if (!(material->flags & COGL_MATERIAL_FLAG_SHOWN_SAMPLER_WARNING)) + { + g_warning ("Your hardware doesnot have enough texture samplers" + "to handle this many texture layers"); + material->flags |= COGL_MATERIAL_FLAG_SHOWN_SAMPLER_WARNING; + } + /* Note: We always make a best effort attempt to display as many + * layers as possible, so this isn't an _error_ */ + /* Note: in the future we may support enabling/disabling layers + * too, so it may become valid to add more than + * MAX_COMBINED_TEXTURE_IMAGE_UNITS layers. */ + } + + if (layer->texture) + cogl_texture_unref (layer->texture); + + cogl_texture_ref (texture_handle); + layer->texture = texture_handle; +} + +void +cogl_material_set_layer_combine_func ( + CoglHandle handle, + gint layer_index, + CoglMaterialLayerCombineChannels channels, + CoglMaterialLayerCombineFunc func) +{ + CoglMaterial *material; + CoglMaterialLayer *layer; + gboolean set_alpha_func = FALSE; + gboolean set_rgb_func = FALSE; + + g_return_if_fail (cogl_is_material (handle)); + + material = _cogl_material_pointer_from_handle (handle); + layer = _cogl_material_get_layer (material, layer_index, FALSE); + if (!layer) + return; + + if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA) + set_alpha_func = set_rgb_func = TRUE; + else if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB) + set_rgb_func = TRUE; + else if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_ALPHA) + set_alpha_func = TRUE; + + if (set_rgb_func) + layer->texture_combine_rgb_func = func; + if (set_alpha_func) + layer->texture_combine_alpha_func = func; +} + +void +cogl_material_set_layer_combine_arg_src ( + CoglHandle handle, + gint layer_index, + gint argument, + CoglMaterialLayerCombineChannels channels, + CoglMaterialLayerCombineSrc src) +{ + CoglMaterial *material; + CoglMaterialLayer *layer; + gboolean set_arg_alpha_src = FALSE; + gboolean set_arg_rgb_src = FALSE; + + g_return_if_fail (cogl_is_material (handle)); + g_return_if_fail (argument >=0 && argument <= 3); + + material = _cogl_material_pointer_from_handle (handle); + layer = _cogl_material_get_layer (material, layer_index, FALSE); + if (!layer) + return; + + if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA) + set_arg_alpha_src = set_arg_rgb_src = TRUE; + else if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB) + set_arg_rgb_src = TRUE; + else if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_ALPHA) + set_arg_alpha_src = TRUE; + + if (set_arg_rgb_src) + layer->texture_combine_rgb_src[argument] = src; + if (set_arg_alpha_src) + layer->texture_combine_alpha_src[argument] = src; +} + +void +cogl_material_set_layer_combine_arg_op ( + CoglHandle material_handle, + gint layer_index, + gint argument, + CoglMaterialLayerCombineChannels channels, + CoglMaterialLayerCombineOp op) +{ + CoglMaterial *material; + CoglMaterialLayer *layer; + gboolean set_arg_alpha_op = FALSE; + gboolean set_arg_rgb_op = FALSE; + + g_return_if_fail (cogl_is_material (material_handle)); + g_return_if_fail (argument >=0 && argument <= 3); + + material = _cogl_material_pointer_from_handle (material_handle); + layer = _cogl_material_get_layer (material, layer_index, FALSE); + if (!layer) + return; + + if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA) + set_arg_alpha_op = set_arg_rgb_op = TRUE; + else if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB) + set_arg_rgb_op = TRUE; + else if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_ALPHA) + set_arg_alpha_op = TRUE; + + if (set_arg_rgb_op) + layer->texture_combine_rgb_op[argument] = op; + if (set_arg_alpha_op) + layer->texture_combine_alpha_op[argument] = op; +} + +void +cogl_material_set_layer_matrix (CoglHandle material_handle, + gint layer_index, + CoglMatrix *matrix) +{ + CoglMaterial *material; + CoglMaterialLayer *layer; + + g_return_if_fail (cogl_is_material (material_handle)); + + material = _cogl_material_pointer_from_handle (material_handle); + layer = _cogl_material_get_layer (material, layer_index, FALSE); + if (!layer) + return; + + layer->matrix = *matrix; + layer->flags |= COGL_MATERIAL_LAYER_FLAG_USER_MATRIX; +} + +static void +_cogl_material_layer_free (CoglMaterialLayer *layer) +{ + cogl_texture_unref (layer->texture); + g_free (layer); +} + +void +cogl_material_remove_layer (CoglHandle material_handle, + gint layer_index) +{ + CoglMaterial *material; + CoglMaterialLayer *layer; + GList *tmp; + + g_return_if_fail (cogl_is_material (material_handle)); + + material = _cogl_material_pointer_from_handle (material_handle); + material->flags &= ~COGL_MATERIAL_FLAG_ENABLE_BLEND; + for (tmp = material->layers; tmp != NULL; tmp = tmp->next) + { + layer = tmp->data; + if (layer->index == layer_index) + { + CoglHandle handle = + _cogl_material_layer_handle_from_pointer (layer); + cogl_material_layer_unref (handle); + material->layers = g_list_remove (material->layers, layer); + continue; + } + + /* XXX: If we expose manual control over ENABLE_BLEND, we'll add + * a flag to know when it's user configured, so we don't trash it */ + if (cogl_texture_get_format (layer->texture) & COGL_A_BIT) + material->flags |= COGL_MATERIAL_FLAG_ENABLE_BLEND; + } +} + +/* XXX: This API is hopfully just a stop-gap solution. Ideally cogl_enable + * will be replaced. */ +gulong +cogl_material_get_cogl_enable_flags (CoglHandle material_handle) +{ + CoglMaterial *material; + gulong enable_flags = 0; + + _COGL_GET_CONTEXT (ctx, 0); + + g_return_val_if_fail (cogl_is_material (material_handle), 0); + + material = _cogl_material_pointer_from_handle (material_handle); + + /* Enable blending if the geometry has an associated alpha color, + * or the material wants blending enabled. */ + if (material->flags & COGL_MATERIAL_FLAG_ENABLE_BLEND + || ctx->color_alpha < 255) + enable_flags |= COGL_ENABLE_BLEND; + + return enable_flags; +} + +void +cogl_material_flush_gl_material_state (CoglHandle material_handle) +{ + CoglMaterial *material; + + g_return_if_fail (cogl_is_material (material_handle)); + + material = _cogl_material_pointer_from_handle (material_handle); + + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, material->ambient)); + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, material->diffuse)); + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, material->specular)); + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, material->emission)); + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS, &material->shininess)); +} + +void +cogl_material_flush_gl_alpha_func (CoglHandle material_handle) +{ + CoglMaterial *material; + + g_return_if_fail (cogl_is_material (material_handle)); + + material = _cogl_material_pointer_from_handle (material_handle); + + /* NB: Currently the Cogl defines are compatible with the GL ones: */ + GE (glAlphaFunc (material->alpha_func, material->alpha_func_reference)); +} + +void +cogl_material_flush_gl_blend_func (CoglHandle material_handle) +{ + CoglMaterial *material; + + g_return_if_fail (cogl_is_material (material_handle)); + GE (glBlendFunc (material->blend_src_factor, material->blend_dst_factor)); +} + +/* It's a bit out of the ordinary to return a const GList *, but it's + * probably sensible to try and avoid list manipulation for every + * primitive emitted in a scene, every frame. + * + * Alternativly; we could either add a _foreach function, or maybe + * a function that gets a passed a buffer (that may be stack allocated) + * by the caller. + */ +const GList * +cogl_material_get_layers (CoglHandle material_handle) +{ + CoglMaterial *material; + + g_return_val_if_fail (cogl_is_material (material_handle), NULL); + + material = _cogl_material_pointer_from_handle (material_handle); + + return material->layers; +} + +CoglMaterialLayerType +cogl_material_layer_get_type (CoglHandle layer_handle) +{ + return COGL_MATERIAL_LAYER_TYPE_TEXTURE; +} + +CoglHandle +cogl_material_layer_get_texture (CoglHandle layer_handle) +{ + CoglMaterialLayer *layer; + + g_return_val_if_fail (cogl_is_material_layer (layer_handle), + COGL_INVALID_HANDLE); + + layer = _cogl_material_layer_pointer_from_handle (layer_handle); + return layer->texture; +} + +static guint +get_n_args_for_combine_func (CoglMaterialLayerCombineFunc func) +{ + switch (func) + { + case COGL_MATERIAL_LAYER_COMBINE_FUNC_REPLACE: + return 1; + case COGL_MATERIAL_LAYER_COMBINE_FUNC_MODULATE: + case COGL_MATERIAL_LAYER_COMBINE_FUNC_ADD: + case COGL_MATERIAL_LAYER_COMBINE_FUNC_ADD_SIGNED: + case COGL_MATERIAL_LAYER_COMBINE_FUNC_SUBTRACT: + case COGL_MATERIAL_LAYER_COMBINE_FUNC_DOT3_RGB: + case COGL_MATERIAL_LAYER_COMBINE_FUNC_DOT3_RGBA: + return 2; + case COGL_MATERIAL_LAYER_COMBINE_FUNC_INTERPOLATE: + return 3; + } + return 0; +} + +void +cogl_material_layer_flush_gl_sampler_state (CoglHandle layer_handle) +{ + CoglMaterialLayer *layer; + int n_rgb_func_args; + int n_alpha_func_args; + + g_return_if_fail (cogl_is_material_layer (layer_handle)); + + layer = _cogl_material_layer_pointer_from_handle (layer_handle); + + /* XXX: We really want some kind of cache/dirty flag mechanism + * somewhere here so we can avoid as much mucking about with + * the texture units per primitive as possible! + * + * E.g. some recent profiling of clutter-actor suggested that + * validating/updating the texture environment may currently + * be a significant bottleneck. Given that all the actors should + * have the same texture environment, that implies we could do a + * much better job of avoiding redundant glTexEnv calls. + */ + + GE (glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE)); + + /* Set the combiner functions... */ + GE (glTexEnvi (GL_TEXTURE_ENV, + GL_COMBINE_RGB, + layer->texture_combine_rgb_func)); + GE (glTexEnvi (GL_TEXTURE_ENV, + GL_COMBINE_ALPHA, + layer->texture_combine_alpha_func)); + + /* + * Setup the function arguments... + */ + + /* For the RGB components... */ + n_rgb_func_args = + get_n_args_for_combine_func (layer->texture_combine_rgb_func); + + GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, + layer->texture_combine_rgb_src[0])); + GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, + layer->texture_combine_rgb_op[0])); + if (n_rgb_func_args > 1) + { + GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, + layer->texture_combine_rgb_src[1])); + GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, + layer->texture_combine_rgb_op[1])); + } + if (n_rgb_func_args > 2) + { + GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC2_RGB, + layer->texture_combine_rgb_src[2])); + GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_RGB, + layer->texture_combine_rgb_op[2])); + } + + /* For the Alpha component */ + n_alpha_func_args = + get_n_args_for_combine_func (layer->texture_combine_alpha_func); + + GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, + layer->texture_combine_alpha_src[0])); + GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, + layer->texture_combine_alpha_op[0])); + if (n_alpha_func_args > 1) + { + GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, + layer->texture_combine_alpha_src[1])); + GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, + layer->texture_combine_alpha_op[1])); + } + if (n_alpha_func_args > 2) + { + GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC2_ALPHA, + layer->texture_combine_alpha_src[2])); + GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, + layer->texture_combine_alpha_op[2])); + } + + if (layer->flags & COGL_MATERIAL_LAYER_FLAG_USER_MATRIX) + { + GE (glMatrixMode (GL_TEXTURE)); + GE (glLoadMatrixf ((GLfloat *)&layer->matrix)); + GE (glMatrixMode (GL_MODELVIEW)); + } +} + diff --git a/clutter/cogl/common/cogl-matrix.h b/clutter/cogl/common/cogl-matrix.h deleted file mode 100644 index 2f6874fae..000000000 --- a/clutter/cogl/common/cogl-matrix.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef __COGL_MATRIX_H -#define __COGL_MATRIX_H - -/* Note: This is ordered according to how OpenGL expects to get 4x4 matrices */ -typedef struct { - /* column 0 */ - float xx; - float yx; - float zx; - float wx; - - /* column 1 */ - float xy; - float yy; - float zy; - float wy; - - /* column 2 */ - float xz; - float yz; - float zz; - float wz; - - /* column 3 */ - float xw; - float yw; - float zw; - float ww; - - /* Note: we may want to extend this later with private flags - * and a cache of the inverse transform matrix. */ -} CoglMatrix; - -void cogl_matrix_init_identity (CoglMatrix *matrix); - -void cogl_matrix_multiply (CoglMatrix *result, - const CoglMatrix *a, - const CoglMatrix *b); - -void cogl_matrix_rotate (CoglMatrix *matrix, - float angle, - float x, - float y, - float z); - -void cogl_matrix_translate (CoglMatrix *matrix, - float x, - float y, - float z); - -void cogl_matrix_scale (CoglMatrix *matrix, - float sx, - float sy, - float sz); - -#endif /* __COGL_MATRIX_H */ - diff --git a/clutter/cogl/gl/cogl-context.c b/clutter/cogl/gl/cogl-context.c index 86a3d425a..84e46bc92 100644 --- a/clutter/cogl/gl/cogl-context.c +++ b/clutter/cogl/gl/cogl-context.c @@ -59,8 +59,9 @@ cogl_create_context () _context->texture_vertices_size = 0; _context->texture_vertices = NULL; - _context->multi_texture_handles = NULL; - _context->multi_texture_layer_handles = NULL; + _context->material_handles = NULL; + _context->material_layer_handles = NULL; + _context->source_material = NULL; _context->fbo_handles = NULL; _context->draw_buffer = COGL_WINDOW_BUFFER; diff --git a/clutter/cogl/gl/cogl-context.h b/clutter/cogl/gl/cogl-context.h index afcf9c347..81ec93219 100644 --- a/clutter/cogl/gl/cogl-context.h +++ b/clutter/cogl/gl/cogl-context.h @@ -66,11 +66,10 @@ typedef struct CoglTextureGLVertex *texture_vertices; gulong texture_vertices_size; - /* Multi Textures */ - GArray *multi_texture_handles; - - /* Multi Texture Layers */ - GArray *multi_texture_layer_handles; + /* Materials */ + GArray *material_handles; + GArray *material_layer_handles; + CoglHandle source_material; /* Framebuffer objects */ GArray *fbo_handles; diff --git a/clutter/cogl/gl/cogl-texture-private.h b/clutter/cogl/gl/cogl-texture-private.h index b6c5af5ec..44fd7712e 100644 --- a/clutter/cogl/gl/cogl-texture-private.h +++ b/clutter/cogl/gl/cogl-texture-private.h @@ -31,8 +31,8 @@ typedef struct _CoglTexture CoglTexture; typedef struct _CoglTexSliceSpan CoglTexSliceSpan; typedef struct _CoglSpanIter CoglSpanIter; -typedef struct _CoglMultiTexture CoglMultiTexture; -typedef struct _CoglMultiTextureLayer CoglMultiTextureLayer; +typedef struct _CoglCompositeTexture CoglCompositeTexture; +typedef struct _CoglCompositeTextureLayer CoglCompositeTextureLayer; struct _CoglTexSliceSpan { @@ -61,7 +61,7 @@ struct _CoglTexture gboolean auto_mipmap; }; -struct _CoglMultiTextureLayer +struct _CoglCompositeTextureLayer { guint ref_count; @@ -74,7 +74,7 @@ struct _CoglMultiTextureLayer * unit. For example we should support dot3 normal mapping. */ }; -struct _CoglMultiTexture +struct _CoglCompositeTexture { guint ref_count; GList *layers; diff --git a/clutter/cogl/gl/cogl-texture.c b/clutter/cogl/gl/cogl-texture.c index 73478b8db..c1a8ab682 100644 --- a/clutter/cogl/gl/cogl-texture.c +++ b/clutter/cogl/gl/cogl-texture.c @@ -32,6 +32,7 @@ #include "cogl-util.h" #include "cogl-bitmap.h" #include "cogl-texture-private.h" +#include "cogl-material.h" #include "cogl-context.h" #include "cogl-handle.h" @@ -50,14 +51,8 @@ } */ static void _cogl_texture_free (CoglTexture *tex); -static void _cogl_multi_texture_free (CoglMultiTexture *multi_texture); -static void _cogl_multi_texture_layer_free (CoglMultiTextureLayer *layer); COGL_HANDLE_DEFINE (Texture, texture, texture_handles); -COGL_HANDLE_DEFINE (MultiTexture, multi_texture, multi_texture_handles); -COGL_HANDLE_DEFINE (MultiTextureLayer, - multi_texture_layer, - multi_texture_layer_handles); struct _CoglSpanIter { @@ -2411,210 +2406,79 @@ cogl_texture_polygon (CoglHandle handle, } } -CoglHandle -cogl_multi_texture_new (void) -{ - CoglMultiTexture *multi_tex = g_new0 (CoglMultiTexture, 1); - return _cogl_multi_texture_handle_new (multi_tex); -} - -static void -_cogl_multi_texture_free (CoglMultiTexture *multi_tex) -{ - g_list_foreach (multi_tex->layers, - (GFunc)cogl_multi_texture_layer_unref, NULL); - g_free (multi_tex); -} - -static CoglMultiTextureLayer * -_cogl_multi_texture_get_layer (CoglMultiTexture *multi_tex, guint index) -{ - CoglMultiTextureLayer *layer; - GList *tmp; - - for (tmp = multi_tex->layers; tmp != NULL; tmp = tmp->next) - { - layer = tmp->data; - if (layer->index == index) - return layer; - - /* The layers are always sorted, so we know this layer doesn't exists */ - if (layer->index > index) - break; - } - /* NB: if we now insert a new layer before tmp, that will maintain order. - */ - - layer = g_new (CoglMultiTextureLayer, 1); - - layer->ref_count = 1; - layer->index = index; - /* Note: comment after for() loop above */ - multi_tex->layers = g_list_insert_before (multi_tex->layers, tmp, layer); - - return layer; -} - void -cogl_multi_texture_layer_set_texture (CoglHandle multi_texture_handle, - guint layer_index, - CoglHandle tex_handle) +cogl_material_rectangle (CoglFixed x1, + CoglFixed y1, + CoglFixed x2, + CoglFixed y2, + CoglFixed *user_tex_coords) { - CoglMultiTexture *multi_tex; - CoglMultiTextureLayer *layer; - CoglTexture *tex; + CoglHandle material; + const GList *layers; + int n_layers; + const GList *tmp; + CoglHandle *valid_layers = NULL; + int n_valid_layers = 0; + gboolean handle_slicing = FALSE; + int i; + GLfloat *tex_coords_buff; + GLfloat quad_coords[8]; + gulong enable_flags = 0; + GLfloat values[4]; - if (!cogl_is_multi_texture (multi_texture_handle) - || !cogl_is_texture (tex_handle)) - return; - - multi_tex = _cogl_multi_texture_pointer_from_handle (multi_texture_handle); - layer = _cogl_multi_texture_get_layer (multi_tex, layer_index); - tex = _cogl_texture_pointer_from_handle (tex_handle); - - cogl_texture_ref (tex_handle); - - layer->tex = tex; -} - -static void -_cogl_multi_texture_layer_free (CoglMultiTextureLayer *layer) -{ - cogl_texture_unref (layer->tex); - g_free (layer); -} - -void -cogl_multi_texture_layer_remove (CoglHandle multi_texture_handle, - guint layer_index) -{ - CoglMultiTexture *multi_tex; - CoglMultiTextureLayer *layer; - GList *tmp; - - /* Check if valid multi texture */ - if (!cogl_is_multi_texture (multi_texture_handle)) - return; - - multi_tex = _cogl_multi_texture_pointer_from_handle (multi_texture_handle); - for (tmp = multi_tex->layers; tmp != NULL; tmp = tmp->next) - { - layer = tmp->data; - if (layer->index == layer_index) - { - CoglHandle handle = - _cogl_multi_texture_layer_handle_from_pointer (layer); - cogl_multi_texture_layer_unref (handle); - multi_tex->layers = g_list_remove (multi_tex->layers, layer); - return; - } - } -} - -void -cogl_multi_texture_rectangle (CoglHandle multi_texture_handle, - CoglFixed x1, - CoglFixed y1, - CoglFixed x2, - CoglFixed y2, - CoglFixed *user_tex_coords) -{ - CoglMultiTexture *multi_tex; - GLfloat quad_coords[8]; - GList *tmp; - GList *valid_layers = NULL; - int count; - GLfloat *tex_coords_buff; - gulong enable_flags = 0; - /* FIXME - currently cogl deals with enabling texturing - * via enable flags, but that can't scale to n texture - * units. Currently we have to be carefull how we leave the - * environment so we don't break things. See the cleanup + /* FIXME - currently cogl deals with enabling texturing via enable flags, + * but that can't scale to n texture units. Currently we have to be carefull + * how we leave the environment so we don't break things. See the cleanup * notes at the end of this function */ _COGL_GET_CONTEXT (ctx, NO_RETVAL); - /* Check if valid multi texture */ - if (!cogl_is_multi_texture (multi_texture_handle)) - return; + material = ctx->source_material; - multi_tex = _cogl_multi_texture_pointer_from_handle (multi_texture_handle); + layers = cogl_material_get_layers (material); + n_layers = g_list_length ((GList *)layers); + valid_layers = alloca (sizeof (CoglHandle) * n_layers); -#define CFX_F COGL_FIXED_TO_FLOAT - quad_coords[0] = CFX_F (x1); - quad_coords[1] = CFX_F (y1); - quad_coords[2] = CFX_F (x2); - quad_coords[3] = CFX_F (y1); - quad_coords[4] = CFX_F (x1); - quad_coords[5] = CFX_F (y2); - quad_coords[6] = CFX_F (x2); - quad_coords[7] = CFX_F (y2); -#undef CFX_F - - enable_flags |= COGL_ENABLE_VERTEX_ARRAY; - GE( glVertexPointer (2, GL_FLOAT, 0, quad_coords)); - - for (count = 0, tmp = multi_tex->layers; - tmp != NULL; - count++, tmp = tmp->next) + for (tmp = layers; tmp != NULL; tmp = tmp->next) { - CoglMultiTextureLayer *layer = tmp->data; - - /* Skip empty layers */ - if (!layer->tex) - { - count--; - continue; - } - - /* FIXME - currently we don't support sliced textures */ - if (layer->tex->slice_gl_handles == NULL - || layer->tex->slice_gl_handles->len < 1) + CoglHandle layer = tmp->data; + CoglHandle texture = cogl_material_layer_get_texture (layer); + + if (cogl_material_layer_get_type (layer) + != COGL_MATERIAL_LAYER_TYPE_TEXTURE) continue; - if (count >= CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS) + /* FIXME: support sliced textures. For now if the first layer is + * sliced then all other layers are ignored, or if the first layer + * is not sliced, we ignore sliced textures in other layers. */ + if (cogl_texture_is_sliced (texture)) { - static gboolean shown_warning = FALSE; - - if (!shown_warning) + if (n_valid_layers == 0) { - g_warning ("Your driver does not support enough texture layers" - "to correctly handle this multi texturing"); - shown_warning = TRUE; + valid_layers[n_valid_layers++] = layer; + handle_slicing = TRUE; + break; } - /* NB: We make a best effort attempt to display as many layers as - * possible. */ - break; + continue; } + valid_layers[n_valid_layers++] = tmp->data; - if (layer->tex->bitmap.format & COGL_A_BIT) - enable_flags |= COGL_ENABLE_BLEND; - - valid_layers = g_list_prepend (valid_layers, layer); + if (n_valid_layers >= CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS) + break; } - valid_layers = g_list_reverse (valid_layers); - - /* Enable blending if the geometry has an associated alpha color, - * or - see above - we also check each layer texture and if any has - * an alpha channel also enable blending. */ - if (ctx->color_alpha < 255) - enable_flags |= COGL_ENABLE_BLEND; - cogl_enable (enable_flags); - + /* NB: It could be that no valid texture layers were found, but * we will still submit a non-textured rectangle in that case. */ - if (count) - tex_coords_buff = alloca (sizeof(GLfloat) * 8 * count); + if (n_valid_layers) + tex_coords_buff = alloca (sizeof(GLfloat) * 8 * n_valid_layers); - /* NB: valid_layers is in order, sorted by index */ - for (count = 0, tmp = valid_layers; - tmp != NULL; - count++, tmp = tmp->next) + for (i = 0; i < n_valid_layers; i++) { - CoglMultiTextureLayer *layer = tmp->data; - CoglFixed *in_tex_coords = &user_tex_coords[count * 4]; - GLfloat *out_tex_coords = &tex_coords_buff[count * 8]; - GLenum gl_tex_handle; + CoglHandle layer = valid_layers[i]; + CoglHandle texture = cogl_material_layer_get_texture (layer); + CoglFixed *in_tex_coords = &user_tex_coords[i * 4]; + GLfloat *out_tex_coords = &tex_coords_buff[i * 8]; + GLuint gl_tex_handle; #define CFX_F COGL_FIXED_TO_FLOAT /* IN LAYOUT: [ tx1:0, ty1:1, tx2:2, ty2:3 ] */ @@ -2629,24 +2493,22 @@ cogl_multi_texture_rectangle (CoglHandle multi_texture_handle, #undef CFX_F /* TODO - support sliced textures */ - gl_tex_handle = g_array_index (layer->tex->slice_gl_handles, GLuint, 0); + cogl_texture_get_gl_texture (texture, &gl_tex_handle, NULL); + //gl_tex_handle = g_array_index (layer->tex->slice_gl_handles, GLuint, 0); - GE (glActiveTexture (GL_TEXTURE0 + count)); - GE (glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)); + GE (glActiveTexture (GL_TEXTURE0 + i)); + cogl_material_layer_flush_gl_sampler_state (layer); GE (glBindTexture (GL_TEXTURE_2D, gl_tex_handle)); /* GE (glEnable (GL_TEXTURE_2D)); */ - GE (glClientActiveTexture (GL_TEXTURE0 + count)); + GE (glClientActiveTexture (GL_TEXTURE0 + i)); GE (glTexCoordPointer (2, GL_FLOAT, 0, out_tex_coords)); /* GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY)); */ /* FIXME - cogl only knows about one texture unit a.t.m * (Also see cleanup note below) */ - if (count == 0) - { - enable_flags |= COGL_ENABLE_TEXTURE_2D | COGL_ENABLE_TEXCOORD_ARRAY; - cogl_enable (enable_flags); - } + if (i == 0) + enable_flags |= COGL_ENABLE_TEXTURE_2D | COGL_ENABLE_TEXCOORD_ARRAY; else { GE (glEnable (GL_TEXTURE_2D)); @@ -2654,19 +2516,62 @@ cogl_multi_texture_rectangle (CoglHandle multi_texture_handle, } } +#define CFX_F COGL_FIXED_TO_FLOAT + quad_coords[0] = CFX_F (x1); + quad_coords[1] = CFX_F (y1); + quad_coords[2] = CFX_F (x2); + quad_coords[3] = CFX_F (y1); + quad_coords[4] = CFX_F (x1); + quad_coords[5] = CFX_F (y2); + quad_coords[6] = CFX_F (x2); + quad_coords[7] = CFX_F (y2); +#undef CFX_F + + enable_flags |= COGL_ENABLE_VERTEX_ARRAY; + GE( glVertexPointer (2, GL_FLOAT, 0, quad_coords)); + + /* Setup the remaining GL state according to this material... */ + cogl_material_flush_gl_material_state (material); + cogl_material_flush_gl_alpha_func (material); + cogl_material_flush_gl_blend_func (material); + /* FIXME: This api is a bit yukky, ideally it will be removed if we + * re-work the cogl_enable mechanism */ + enable_flags |= cogl_material_get_cogl_enable_flags (material); + + /* FIXME - cogl only knows about one texture unit so assumes that unit 0 + * is always active...*/ + GE (glActiveTexture (GL_TEXTURE0)); + GE (glClientActiveTexture (GL_TEXTURE0)); + cogl_enable (enable_flags); glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); /* FIXME - cogl doesn't currently have a way of caching the * enable states for more than one texture unit so for now, * we just disable anything relating to additional units once * we are done with them. */ - while (--count > 0) + for (i = 1; i < n_valid_layers; i++) { - GE (glActiveTexture (GL_TEXTURE0 + count)); - GE (glClientActiveTexture (GL_TEXTURE0 + count)); + GE (glActiveTexture (GL_TEXTURE0 + i)); + GE (glClientActiveTexture (GL_TEXTURE0 + i)); GE (glDisable (GL_TEXTURE_2D)); GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY)); } + + /* FIXME - CoglMaterials aren't yet used pervasively throughout + * the cogl API, so we currently need to cleanup material state + * that will confuse other parts of the API. + * Other places to tweak, include the primitives API and lite + * GL wrappers like cogl_rectangle */ + values[0] = 0.2; values[1] = 0.2; values[2] = 0.2; values[3] = 1.0; + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, values)); + values[0] = 0.8; values[1] = 0.8; values[2] = 0.8; values[3] = 1.0; + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, values)); + values[0] = 0; values[1] = 0; values[2] = 0; values[3] = 1.0; + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, values)); + values[0] = 0; values[1] = 0; values[2] = 0; values[3] = 1.0; + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, values)); + values[0] = 0; + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS, values)); } diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 061acaaa1..58efa73c5 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -3,6 +3,5 @@ EXTRA_DIST = \ redhand.png \ redhand_alpha.png \ light0.png \ - light1.png \ test-script.json diff --git a/tests/data/light0.png b/tests/data/light0.png index fdb84250a..66871ddb3 100644 Binary files a/tests/data/light0.png and b/tests/data/light0.png differ diff --git a/tests/data/light1.png b/tests/data/light1.png deleted file mode 100644 index 5934a0c41..000000000 Binary files a/tests/data/light1.png and /dev/null differ diff --git a/tests/interactive/Makefile.am b/tests/interactive/Makefile.am index 025814236..05b5977a1 100644 --- a/tests/interactive/Makefile.am +++ b/tests/interactive/Makefile.am @@ -31,7 +31,7 @@ UNIT_TESTS = \ test-cogl-tex-getset.c \ test-cogl-offscreen.c \ test-cogl-tex-polygon.c \ - test-cogl-multi-texture.c \ + test-cogl-material.c \ test-stage-read-pixels.c \ test-random-text.c \ test-clip.c \ diff --git a/tests/interactive/test-cogl-material.c b/tests/interactive/test-cogl-material.c new file mode 100644 index 000000000..e34082465 --- /dev/null +++ b/tests/interactive/test-cogl-material.c @@ -0,0 +1,161 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define TIMELINE_FRAME_COUNT 200 + +typedef struct _TestMultiLayerMaterialState +{ + ClutterActor *group; + CoglHandle material; + CoglHandle alpha_tex; + CoglHandle redhand_tex; + CoglHandle light_tex0; + ClutterFixed *tex_coords; + + CoglMatrix tex_matrix; + CoglMatrix rot_matrix; + +} TestMultiLayerMaterialState; + + +static void +frame_cb (ClutterTimeline *timeline, + gint frame_no, + gpointer data) +{ + TestMultiLayerMaterialState *state = data; + + cogl_matrix_multiply (&state->tex_matrix, + &state->tex_matrix, + &state->rot_matrix); + cogl_material_set_layer_matrix (state->material, 2, &state->tex_matrix); +} + +static gboolean +material_rectangle_paint (ClutterActor *actor, gpointer data) +{ + TestMultiLayerMaterialState *state = data; + + cogl_set_source (state->material); + cogl_material_rectangle (CLUTTER_INT_TO_FIXED(0), + CLUTTER_INT_TO_FIXED(0), + CLUTTER_INT_TO_FIXED(TIMELINE_FRAME_COUNT), + CLUTTER_INT_TO_FIXED(TIMELINE_FRAME_COUNT), + state->tex_coords); +} + +G_MODULE_EXPORT int +test_cogl_material_main (int argc, char *argv[]) +{ + ClutterTimeline *timeline; + ClutterAlpha *alpha; + ClutterBehaviour *r_behave; + ClutterActor *stage; + ClutterColor stage_color = { 0x61, 0x56, 0x56, 0xff }; + TestMultiLayerMaterialState *state = g_new0 (TestMultiLayerMaterialState, 1); + ClutterGeometry geom; + ClutterFixed tex_coords[] = + { + /* tx1 ty1 tx2 ty2 */ + 0, 0, CLUTTER_INT_TO_FIXED (1), CLUTTER_INT_TO_FIXED (1), + 0, 0, CLUTTER_INT_TO_FIXED (1), CLUTTER_INT_TO_FIXED (1), + 0, 0, CLUTTER_INT_TO_FIXED (1), CLUTTER_INT_TO_FIXED (1) + }; + + clutter_init (&argc, &argv); + + stage = clutter_stage_get_default (); + clutter_actor_get_geometry (stage, &geom); + + clutter_stage_set_color (CLUTTER_STAGE (stage), + &stage_color); + + /* We create a non-descript actor that we know doesn't have a + * default paint handler, so that we can easily control + * painting in a paint signal handler, without having to + * sub-class anything etc. */ + state->group = clutter_group_new (); + clutter_actor_set_position (state->group, geom.width/2, geom.height/2); + g_signal_connect (state->group, "paint", + G_CALLBACK(material_rectangle_paint), state); + + state->alpha_tex = + cogl_texture_new_from_file ("./redhand_alpha.png", + -1, /* disable slicing */ + TRUE, + COGL_PIXEL_FORMAT_ANY, + NULL); + state->redhand_tex = + cogl_texture_new_from_file ("./redhand.png", + -1, /* disable slicing */ + TRUE, + COGL_PIXEL_FORMAT_ANY, + NULL); + state->light_tex0 = + cogl_texture_new_from_file ("./light0.png", + -1, /* disable slicing */ + TRUE, + COGL_PIXEL_FORMAT_ANY, + NULL); + + state->material = cogl_material_new (); + cogl_material_set_layer (state->material, 0, state->alpha_tex); + cogl_material_set_layer (state->material, 1, state->redhand_tex); + cogl_material_set_layer (state->material, 2, state->light_tex0); + + state->tex_coords = tex_coords; + + cogl_matrix_init_identity (&state->tex_matrix); + cogl_matrix_init_identity (&state->rot_matrix); + + cogl_matrix_translate (&state->rot_matrix, 0.5, 0.5, 0); + cogl_matrix_rotate (&state->rot_matrix, 10.0, 0, 0, 1.0); + cogl_matrix_translate (&state->rot_matrix, -0.5, -0.5, 0); + + clutter_actor_set_anchor_point (state->group, 86, 125); + clutter_container_add_actor (CLUTTER_CONTAINER(stage), + state->group); + + timeline = clutter_timeline_new (TIMELINE_FRAME_COUNT, 26 /* fps */); + g_object_set (timeline, "loop", TRUE, NULL); + + g_signal_connect (timeline, "new-frame", G_CALLBACK (frame_cb), state); + + /* Set an alpha func to power behaviour - ramp is constant rise/fall */ + alpha = clutter_alpha_new_for_mode (CLUTTER_LINEAR); + clutter_alpha_set_timeline (alpha, timeline); + + /* Create a behaviour for that alpha */ + r_behave = clutter_behaviour_rotate_new (alpha, + CLUTTER_Y_AXIS, + CLUTTER_ROTATE_CW, + 0.0, 360.0); + + /* Apply it to our actor */ + clutter_behaviour_apply (r_behave, state->group); + + /* start the timeline and thus the animations */ + clutter_timeline_start (timeline); + + clutter_actor_show_all (stage); + + clutter_main(); + + cogl_material_unref (state->material); + cogl_texture_unref (state->alpha_tex); + cogl_texture_unref (state->redhand_tex); + cogl_texture_unref (state->light_tex0); + g_free (state); + + g_object_unref (r_behave); + + return 0; +} diff --git a/tests/interactive/test-cogl-multi-texture.c b/tests/interactive/test-cogl-multi-texture.c deleted file mode 100644 index 123de7c7c..000000000 --- a/tests/interactive/test-cogl-multi-texture.c +++ /dev/null @@ -1,250 +0,0 @@ -#include -#include -#include - -#include -#include -#include - -#include -#include - -#define TIMELINE_FRAME_COUNT 200 - -typedef struct _MultiTextureState -{ - ClutterActor *group; - CoglHandle multi_tex; - CoglHandle alpha_tex; - CoglHandle redhand_tex; - CoglHandle light_tex0; - CoglHandle light_tex1; - ClutterFixed *tex_coords; - - /* For handling light switching */ - guint last_light_change; - gboolean light_on; - - /* For handling texture coord sliding */ - guint last_frame_no; - gint light_x_dir; - gint light_y_dir; - gint light_x_pos; - gint light_y_pos; - -} MultiTextureState; - - -static void -frame_cb (ClutterTimeline *timeline, - gint frame_no, - gpointer data) -{ - MultiTextureState *state = data; - ClutterFixed *tex_coords = &state->tex_coords[8]; - int prev_frame_delta; - int light_duration; - - light_duration = frame_no - state->last_light_change; - if (light_duration < 0) - light_duration += TIMELINE_FRAME_COUNT; - - if (light_duration > 10) - { - if (state->light_on) - { - cogl_multi_texture_layer_set_texture (state->multi_tex, - 2, - state->light_tex1); - state->light_on = FALSE; - } - else - { - cogl_multi_texture_layer_set_texture (state->multi_tex, - 2, - state->light_tex0); - state->light_on = TRUE; - } - state->last_light_change = frame_no; - } - - /* slide the texture coordinates */ - - /* This is worked out as if the texture has a virtual resolution - * of TIMELINE_FRAME_COUNT x TIMELINE_FRAME_COUNT. - * - * We are always showing an apature of the texture that is - * (TIMELINE_FRAME_COUNT/2) x (TIMELINE_FRAME_COUNT/2) - * - * To remain within the texture we don't let the tx1, ty1 positions - * go past ((TIMELINE_FRAME_COUNT/2), (TIMELINE_FRAME_COUNT/2)) - */ - prev_frame_delta = frame_no - state->last_frame_no; - if (prev_frame_delta < 0) - prev_frame_delta += TIMELINE_FRAME_COUNT; - - state->light_x_pos += prev_frame_delta * state->light_x_dir; - if (state->light_x_pos > TIMELINE_FRAME_COUNT/2) - { - state->light_x_pos = TIMELINE_FRAME_COUNT/2; - state->light_x_dir = -state->light_x_dir; - } - else if (state->light_x_pos < 0) - { - state->light_x_pos = 0; - state->light_x_dir = 1; - } - - state->light_y_pos += prev_frame_delta * state->light_y_dir; - if (state->light_y_pos > TIMELINE_FRAME_COUNT/2) - { - state->light_y_pos = TIMELINE_FRAME_COUNT/2; - state->light_y_dir = -state->light_y_dir; - } - else if (state->light_y_pos < 0) - { - state->light_y_pos = 0; - state->light_y_dir = 1; - } - -#define CI_F CLUTTER_INT_TO_FIXED - tex_coords[0] = (CI_F(1)/TIMELINE_FRAME_COUNT) * state->light_x_pos; - tex_coords[1] = (CI_F(1)/TIMELINE_FRAME_COUNT) * state->light_y_pos; - tex_coords[2] = tex_coords[0] + CI_F(1)/2; - tex_coords[3] = tex_coords[1] + CI_F(1)/2; -#undef CI_F - - state->last_frame_no = frame_no; -} - -static gboolean -multi_texture_paint (ClutterActor *actor, gpointer data) -{ - MultiTextureState *state = data; - - cogl_multi_texture_rectangle (state->multi_tex, - CLUTTER_INT_TO_FIXED(0), - CLUTTER_INT_TO_FIXED(0), - CLUTTER_INT_TO_FIXED(TIMELINE_FRAME_COUNT), - CLUTTER_INT_TO_FIXED(TIMELINE_FRAME_COUNT), - state->tex_coords); -} - -G_MODULE_EXPORT int -test_cogl_multi_texture_main (int argc, char *argv[]) -{ - ClutterTimeline *timeline; - ClutterAlpha *alpha; - ClutterBehaviour *r_behave; - ClutterActor *stage; - ClutterColor stage_color = { 0x15, 0x93, 0x15, 0xff }; - MultiTextureState *state = g_new0 (MultiTextureState, 1); - CoglHandle layer; - ClutterGeometry geom; - ClutterFixed tex_coords[] = - { - /* tx1 ty1 tx2 ty2 */ - 0, 0, CLUTTER_INT_TO_FIXED (1), CLUTTER_INT_TO_FIXED (1), - 0, 0, CLUTTER_INT_TO_FIXED (1), CLUTTER_INT_TO_FIXED (1), - 0, 0, CLUTTER_INT_TO_FIXED (1), CLUTTER_INT_TO_FIXED (1) - }; - - - clutter_init (&argc, &argv); - - stage = clutter_stage_get_default (); - clutter_actor_get_geometry (stage, &geom); - - clutter_stage_set_color (CLUTTER_STAGE (stage), - &stage_color); - - /* We create a non-descript actor that we know doesn't have a - * default paint handler, so that we can easily control - * painting in a paint signal handler, without having to - * sub-class anything etc. */ - state->group = clutter_group_new (); - clutter_actor_set_position (state->group, geom.width/2, geom.height/2); - g_signal_connect (state->group, "paint", - G_CALLBACK(multi_texture_paint), state); - - state->alpha_tex = - cogl_texture_new_from_file ("./redhand_alpha.png", - -1, /* disable slicing */ - TRUE, - COGL_PIXEL_FORMAT_ANY, - NULL); - state->redhand_tex = - cogl_texture_new_from_file ("./redhand.png", - -1, /* disable slicing */ - TRUE, - COGL_PIXEL_FORMAT_ANY, - NULL); - state->light_tex0 = - cogl_texture_new_from_file ("./light0.png", - -1, /* disable slicing */ - TRUE, - COGL_PIXEL_FORMAT_ANY, - NULL); - state->light_tex1 = - cogl_texture_new_from_file ("./light1.png", - -1, /* disable slicing */ - TRUE, - COGL_PIXEL_FORMAT_ANY, - NULL); - - state->multi_tex = cogl_multi_texture_new (); - - cogl_multi_texture_layer_set_texture (state->multi_tex, 0, - state->alpha_tex); - cogl_multi_texture_layer_set_texture (state->multi_tex, 1, - state->redhand_tex); - cogl_multi_texture_layer_set_texture (state->multi_tex, 2, - state->light_tex0); - - state->tex_coords = tex_coords; - - /* pick a random starting direction */ - state->light_x_dir = rand() % 5; - state->light_y_dir = rand() % 5; - - clutter_actor_set_anchor_point (state->group, 86, 125); - clutter_container_add_actor (CLUTTER_CONTAINER(stage), - state->group); - - - timeline = clutter_timeline_new (TIMELINE_FRAME_COUNT, 26); /* num frames, fps */ - g_object_set (timeline, "loop", TRUE, NULL); - - g_signal_connect (timeline, "new-frame", G_CALLBACK (frame_cb), state); - - /* Set an alpha func to power behaviour - ramp is constant rise/fall */ - alpha = clutter_alpha_new_for_mode (CLUTTER_LINEAR); - clutter_alpha_set_timeline (alpha, timeline); - - /* Create a behaviour for that alpha */ - r_behave = clutter_behaviour_rotate_new (alpha, - CLUTTER_Y_AXIS, - CLUTTER_ROTATE_CW, - 0.0, 360.0); - - /* Apply it to our actor */ - clutter_behaviour_apply (r_behave, state->group); - - /* start the timeline and thus the animations */ - clutter_timeline_start (timeline); - - clutter_actor_show_all (stage); - - clutter_main(); - - cogl_multi_texture_unref (state->multi_tex); - cogl_texture_unref (state->alpha_tex); - cogl_texture_unref (state->redhand_tex); - cogl_texture_unref (state->light_tex0); - cogl_texture_unref (state->light_tex1); - g_free (state); - - g_object_unref (r_behave); - - return 0; -}