diff --git a/Makefile.am b/Makefile.am index 225b66100..cae798703 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,3 +1,9 @@ +NULL = + +V = @ +Q = $(V:1=) +QUIET_GEN = $(Q:@=@echo ' GEN '$@;) + SUBDIRS = common $(CLUTTER_COGL) BUILT_SOURCES = cogl.h @@ -23,29 +29,42 @@ CLEANFILES = $(pc_files) AM_CPPFLAGS = $(CLUTTER_CFLAGS) $(CLUTTER_DEBUG_CFLAGS) $(MAINTAINER_CFLAGS) +# COGL installed headers cogl_headers = \ - $(top_srcdir)/clutter/cogl/cogl-bitmap.h \ - $(top_srcdir)/clutter/cogl/cogl-color.h \ - $(top_srcdir)/clutter/cogl/cogl-debug.h \ - $(top_srcdir)/clutter/cogl/cogl-fixed.h \ - $(top_srcdir)/clutter/cogl/cogl-material.h \ - $(top_srcdir)/clutter/cogl/cogl-matrix.h \ - $(top_srcdir)/clutter/cogl/cogl-offscreen.h \ - $(top_srcdir)/clutter/cogl/cogl-path.h \ - $(top_srcdir)/clutter/cogl/cogl-shader.h \ - $(top_srcdir)/clutter/cogl/cogl-texture.h \ - $(top_srcdir)/clutter/cogl/cogl-types.h \ - $(top_srcdir)/clutter/cogl/cogl-vertex-buffer.h + $(top_srcdir)/clutter/cogl/cogl-bitmap.h \ + $(top_srcdir)/clutter/cogl/cogl-color.h \ + $(top_srcdir)/clutter/cogl/cogl-debug.h \ + $(top_srcdir)/clutter/cogl/cogl-deprecated.h \ + $(top_srcdir)/clutter/cogl/cogl-fixed.h \ + $(top_srcdir)/clutter/cogl/cogl-material.h \ + $(top_srcdir)/clutter/cogl/cogl-matrix.h \ + $(top_srcdir)/clutter/cogl/cogl-offscreen.h \ + $(top_srcdir)/clutter/cogl/cogl-path.h \ + $(top_srcdir)/clutter/cogl/cogl-shader.h \ + $(top_srcdir)/clutter/cogl/cogl-texture.h \ + $(top_srcdir)/clutter/cogl/cogl-types.h \ + $(top_srcdir)/clutter/cogl/cogl-vertex-buffer.h \ + $(top_builddir)/clutter/cogl/cogl-defines-@CLUTTER_COGL@.h \ + $(top_builddir)/clutter/cogl/cogl-enum-types.h \ + $(top_builddir)/clutter/cogl/cogl.h \ + $(NULL) + +# this is copied in from common/ to make cogl.h work, but we +# need to clean it up ourselves once we're done +DISTCLEANFILES = cogl-enum-types.h # HACK - gobject-introspection can't scan a library in another directory # so we create a libclutter-cogl.la that's just identical to the one # in the subdir noinst_LTLIBRARIES = libclutter-cogl.la -libclutter_cogl_la_LIBADD = $(CLUTTER_COGL)/libclutter-cogl.la +libclutter_cogl_la_LIBADD = $(CLUTTER_COGL)/libclutter-cogl-$(CLUTTER_COGL).la libclutter_cogl_la_SOURCES = $(cogl_headers) +coglincludedir = $(includedir)/clutter-@CLUTTER_API_VERSION@/cogl +coglinclude_HEADERS = $(cogl_headers) + if HAVE_INTROSPECTION -Cogl-@CLUTTER_API_VERSION@.gir: $(INTROSPECTION_SCANNER) $(CLUTTER_COGL)/libclutter-cogl.la +Cogl-@CLUTTER_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libclutter-cogl.la $(QUIET_GEN)$(INTROSPECTION_SCANNER) -v \ --namespace Cogl --nsversion=@CLUTTER_API_VERSION@ \ -I$(top_srcdir)/clutter/cogl \ @@ -59,8 +78,6 @@ Cogl-@CLUTTER_API_VERSION@.gir: $(INTROSPECTION_SCANNER) $(CLUTTER_COGL)/libclut --libtool="$(top_builddir)/doltlibtool" \ --pkg gobject-2.0 \ --output $@ \ - $(top_builddir)/clutter/cogl/cogl-defines-@CLUTTER_COGL@.h \ - $(top_builddir)/clutter/cogl/cogl.h \ $(cogl_headers) BUILT_GIRSOURCES = Cogl-@CLUTTER_API_VERSION@.gir diff --git a/cogl-debug.h b/cogl-debug.h index b31a36c52..8aa1e8f87 100644 --- a/cogl-debug.h +++ b/cogl-debug.h @@ -29,15 +29,16 @@ G_BEGIN_DECLS typedef enum { - COGL_DEBUG_MISC = 1 << 0, - COGL_DEBUG_TEXTURE = 1 << 1, - COGL_DEBUG_MATERIAL = 1 << 2, - COGL_DEBUG_SHADER = 1 << 3, - COGL_DEBUG_OFFSCREEN = 1 << 4, - COGL_DEBUG_DRAW = 1 << 5, - COGL_DEBUG_PANGO = 1 << 6, - COGL_DEBUG_RECTANGLES = 1 << 7, - COGL_DEBUG_HANDLE = 1 << 8 + COGL_DEBUG_MISC = 1 << 0, + COGL_DEBUG_TEXTURE = 1 << 1, + COGL_DEBUG_MATERIAL = 1 << 2, + COGL_DEBUG_SHADER = 1 << 3, + COGL_DEBUG_OFFSCREEN = 1 << 4, + COGL_DEBUG_DRAW = 1 << 5, + COGL_DEBUG_PANGO = 1 << 6, + COGL_DEBUG_RECTANGLES = 1 << 7, + COGL_DEBUG_HANDLE = 1 << 8, + COGL_DEBUG_BLEND_STRINGS = 1 << 9 } CoglDebugFlags; #ifdef COGL_ENABLE_DEBUG @@ -69,3 +70,4 @@ extern guint cogl_debug_flags; G_END_DECLS #endif /* __COGL_DEBUG_H__ */ + diff --git a/cogl-deprecated.h b/cogl-deprecated.h index 2111e48b4..24dc5b28b 100644 --- a/cogl-deprecated.h +++ b/cogl-deprecated.h @@ -23,6 +23,14 @@ #ifndef COGL_DEPRECATED_H -#define cogl_color cogl_color_REPLACED_BY_cogl_set_source_color +#define cogl_color cogl_color_REPLACED_BY_cogl_set_source_color +#define cogl_enable_depth_test cogl_enable_depth_test_RENAMED_TO_cogl_set_depth_test_enabled +#define cogl_enable_backface_culling cogl_enable_backface_culling_RENAMED_TO_cogl_set_backface_culling_enabled + +#define cogl_texture_rectangle cogl_texture_rectangle_REPLACE_BY_cogl_set_source_texture_AND_cogl_rectangle_with_texture_coords + +#define cogl_texture_multiple_rectangles cogl_texture_multiple_rectangles_REPLACED_BY_cogl_set_source_texture_AND_cogl_rectangles_with_texture_coords + +#define cogl_texture_polygon cogl_texture_polygon_REPLACED_BY_cogl_set_source_texture_AND_cogl_polygon #endif diff --git a/cogl-material.h b/cogl-material.h index 95a474831..66fbd8d5c 100644 --- a/cogl-material.h +++ b/cogl-material.h @@ -43,6 +43,51 @@ G_BEGIN_DECLS * blended together. */ +/** + * CoglMaterialFilter: + * @COGL_MATERIAL_FILTER_NEAREST: Measuring in manhatten distance from the, + * current pixel center, use the nearest texture + * texel. + * @COGL_MATERIAL_FILTER_LINEAR: Use the weighted average of the 4 texels + * nearest the current pixel center. + * @COGL_MATERIAL_FILTER_NEAREST_MIPMAP_NEAREST: Select the mimap level whose + * texel size most closely matches + * the current pixel, and use the + * COGL_MATERIAL_FILTER_NEAREST + * criterion. + * @COGL_MATERIAL_FILTER_LINEAR_MIPMAP_NEAREST: Select the mimap level whose + * texel size most closely matches + * the current pixel, and use the + * COGL_MATERIAL_FILTER_LINEAR + * criterion. + * @COGL_MATERIAL_FILTER_NEAREST_MIPMAP_LINEAR: Select the two mimap levels + * whose texel size most closely + * matches the current pixel, use + * the COGL_MATERIAL_FILTER_NEAREST + * criterion on each one and take + * their weighted average. + * @COGL_MATERIAL_FILTER_LINEAR_MIPMAP_LINEAR: Select the two mimap levels + * whose texel size most closely + * matches the current pixel, use + * the COGL_MATERIAL_FILTER_LINEAR + * criterion on each one and take + * their weighted average. + * + * Texture filtering is used whenever the current pixel maps either to more + * than one texture element (texel) or less than one. These filter enums + * correspond to different strategies used to come up with a pixel color, by + * possibly referring to multiple neighbouring texels and taking a weighted + * average or simply using the nearest texel. + */ +typedef enum _CoglMaterialFilter +{ + COGL_MATERIAL_FILTER_NEAREST = GL_NEAREST, + COGL_MATERIAL_FILTER_LINEAR = GL_LINEAR, + COGL_MATERIAL_FILTER_NEAREST_MIPMAP_NEAREST = GL_NEAREST_MIPMAP_NEAREST, + COGL_MATERIAL_FILTER_LINEAR_MIPMAP_NEAREST = GL_LINEAR_MIPMAP_NEAREST, + COGL_MATERIAL_FILTER_NEAREST_MIPMAP_LINEAR = GL_NEAREST_MIPMAP_LINEAR, + COGL_MATERIAL_FILTER_LINEAR_MIPMAP_LINEAR = GL_LINEAR_MIPMAP_LINEAR +} CoglMaterialFilter; /** * cogl_material_new: @@ -367,80 +412,90 @@ void cogl_material_set_alpha_test_function (CoglHandle material, float alpha_reference); /** - * CoglMaterialBlendFactor: - * @COGL_MATERIAL_BLEND_FACTOR_ZERO: (0, 0, 0, 0) - * @COGL_MATERIAL_BLEND_FACTOR_ONE: (1, 1, 1, 1) - * @COGL_MATERIAL_BLEND_FACTOR_SRC_COLOR: (Rs, Gs, Bs, As) - * @COGL_MATERIAL_BLEND_FACTOR_DST_COLOR: (Rd, Gd, Bd, Ad) - * @COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_SRC_COLOR: (1-Rs, 1-Gs, 1-Bs, 1-As) - * @COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_DST_COLOR: (1-Rd, 1-Gd, 1-Bd, 1-Ad) - * @COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA: (As, As, As, As) - * @COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA: (1-As, 1-As, 1-As, 1-As) - * @COGL_MATERIAL_BLEND_FACTOR_DST_ALPHA: (Ad, Ad, Ad, Ad) - * @COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_DST_ALPHA: (1-Ad, 1-Ad, 1-Ad, 1-Ad) - * @COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA_SATURATE: (f,f,f,1) where f=MIN(As,1-Ad) + * cogl_material_set_blend: + * @material: A CoglMaterial object + * @blend_string: A Cogl blend string + * describing the desired blend function. + * @error: A GError that may report lack of driver support if you give + * separate blend string statements for the alpha channel and RGB + * channels since some drivers or backends such as GLES 1.1 dont + * support this. + * + * If not already familiar; please refer + * here for an overview of what blend + * strings are and there syntax. * * Blending occurs after the alpha test function, and combines fragments with * the framebuffer. - * - * A fixed function is used to determine the blended color, which is based on - * the incoming source color of your fragment (Rs, Gs, Bs, As), a source - * factor (Sr, Sg, Sb, Sa), a destination color (Rd, Rg, Rb, Ra) and - * a destination factor (Dr, Dg, Db, Da), and is given by these equations: - * + + * Currently the only blend function Cogl exposes is ADD(). So any valid + * blend statements will be of the form: + * * - * R = Rs*Sr + Rd*Dr - * G = Gs*Sg + Gd*Dg - * B = Bs*Sb + Bd*Db - * A = As*Sa + Ad*Da + * <channel-mask>=ADD(SRC_COLOR*(<factor>), DST_COLOR*(<factor>)) * * - * All factors have a range [0, 1] + * NOTE: The brackets around blend factors are currently not optional! * - * The factors are selected with the following constants: + * This is the list of source-names usable as blend factors: + * + * SRC_COLOR: The color of the in comming fragment + * DST_COLOR: The color of the framebuffer + * + * CONSTANT: The constant set via cogl_material_set_blend_constant() + * + * The source names can be used according to the + * color-source and factor syntax, + * so for example "(1-SRC_COLOR[A])" would be a valid factor, as would + * "(CONSTANT[RGB])" + * + * These can also be used as factors: + * + * 0: (0, 0, 0, 0) + * 1: (1, 1, 1, 1) + * SRC_ALPHA_SATURATE_FACTOR: (f,f,f,1) + * where f=MIN(SRC_COLOR[A],1-DST_COLOR[A]) + * + * + * Remember; all color components are normalized to the range [0, 1] before + * computing the result of blending. + * + *
+ * Examples + * Blend a non-premultiplied source over a destination with + * premultiplied alpha: + * + * "RGB = ADD(SRC_COLOR*(SRC_COLOR[A]), DST_COLOR*(1-SRC_COLOR[A]))" + * "A = ADD(SRC_COLOR, DST_COLOR*(1-SRC_COLOR[A]))" + * + * Blend a premultiplied source over a destination with premultiplied alpha: + * + * "RGBA = ADD(SRC_COLOR, DST_COLOR*(1-SRC_COLOR[A]))" + * + *
+ * + * Returns: TRUE if the blend string was successfully parsed, and the described + * blending is supported by the underlying driver/hardware. If there + * was an error, it returns FALSE. + * + * Since: 1.0 */ -typedef enum _CoglMaterialBlendFactor -{ - COGL_MATERIAL_BLEND_FACTOR_ZERO = GL_ZERO, - COGL_MATERIAL_BLEND_FACTOR_ONE = GL_ONE, - COGL_MATERIAL_BLEND_FACTOR_SRC_COLOR = GL_SRC_COLOR, - COGL_MATERIAL_BLEND_FACTOR_DST_COLOR = GL_DST_COLOR, - COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_SRC_COLOR = GL_ONE_MINUS_SRC_COLOR, - COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_DST_COLOR = GL_ONE_MINUS_DST_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, -} CoglMaterialBlendFactor; +gboolean cogl_material_set_blend (CoglHandle material, + const char *blend_string, + GError **error); /** - * cogl_material_set_blend_factors: + * cogl_material_set_blend_constant: * @material: A CoglMaterial object - * @src_factor: Chooses the @CoglMaterialBlendFactor you want plugged in to - * the blend equation. - * @dst_factor: Chooses the @CoglMaterialBlendFactor you want plugged in to - * the blend equation. + * @constant_color: The constant color you want * - * 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: + * When blending is setup to reference a CONSTANT blend factor then + * blending will depend on the constant set with this function. * - * (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] - * - * Since 1.0 + * Since: 1.0 */ -void cogl_material_set_blend_factors (CoglHandle material, - CoglMaterialBlendFactor src_factor, - CoglMaterialBlendFactor dst_factor); +void cogl_material_set_blend_constant (CoglHandle material, + CoglColor *constant_color); /** * cogl_material_set_layer: @@ -460,7 +515,7 @@ void cogl_material_set_blend_factors (CoglHandle material, * Since 1.0 */ void cogl_material_set_layer (CoglHandle material, - gint layer_index, + int layer_index, CoglHandle texture); /** @@ -473,233 +528,112 @@ void cogl_material_set_layer (CoglHandle material, void cogl_material_remove_layer (CoglHandle material, gint layer_index); + /** - * CoglMaterialLayerCombineFunc: - * @COGL_MATERIAL_LAYER_COMBINE_FUNC_REPLACE: Arg0 - * @COGL_MATERIAL_LAYER_COMBINE_FUNC_MODULATE: Arg0 x Arg1 - * @COGL_MATERIAL_LAYER_COMBINE_FUNC_ADD: Arg0 + Arg1 - * @COGL_MATERIAL_LAYER_COMBINE_FUNC_ADD_SIGNED: Arg0 + Arg1 - 0.5 - * @COGL_MATERIAL_LAYER_COMBINE_FUNC_INTERPOLATE: Arg0 x Arg + Arg1 x (1-Arg2) - * @COGL_MATERIAL_LAYER_COMBINE_FUNC_SUBTRACT: Arg0 - Arg1 - * @COGL_MATERIAL_LAYER_COMBINE_FUNC_DOT3_RGB: 4 x ((Arg0r - 0.5) x (Arg1r - 0.5)) + - * @COGL_MATERIAL_LAYER_COMBINE_FUNC_DOT3_RGBA: ((Arg0b - 0.5) x (Arg1b - 0.5)) + + * cogl_material_set_layer_combine: + * @material: A CoglMaterial object + * @layer_index: Specifies the layer you want define a combine function for + * @blend_string: A Cogl blend string + * describing the desired texture combine function. + * @error: A GError that may report parse errors or lack of GPU/driver support. * - * A material may comprise of 1 or more layers that can be combined using a - * number of different functions. By default layers are modulated, which is - * to say the components of the current source layer S are simply multipled - * together with the combined results of the previous layer P like this: + * If not already familiar; you can refer + * here for an overview of what blend + * strings are and there syntax. * + * These are all the functions available for texture combining: + * + * REPLACE(arg0) = arg0 + * MODULATE(arg0, arg1) = arg0 x arg1 + * ADD(arg0, arg1) = arg0 + arg1 + * ADD_SIGNED(arg0, arg1) = arg0 + arg1 - 0.5 + * INTERPOLATE(arg0, arg1, arg2) = + * arg0 x arg2 + arg1 x (1 - arg2) + * SUBTRACT(arg0, arg1) = arg0 - arg1 + * + * DOT3_RGB(arg0, arg1) = * - * (Rs*Rp, Gs*Gp, Bs*Bp, As*Ap) + * 4 x ((arg0[R] - 0.5)) * (arg1[R] - 0.5) + + * (arg0[G] - 0.5)) * (arg1[G] - 0.5) + + * (arg0[B] - 0.5)) * (arg1[B] - 0.5)) * - * - * For more advanced techniques, Cogl exposes the fixed function texture - * combining capabilities of your GPU to give you greater control. - */ -typedef enum _CoglMaterialLayerCombineFunc -{ - COGL_MATERIAL_LAYER_COMBINE_FUNC_REPLACE = CGL_REPLACE, - COGL_MATERIAL_LAYER_COMBINE_FUNC_MODULATE = CGL_MODULATE, - COGL_MATERIAL_LAYER_COMBINE_FUNC_ADD = CGL_ADD, - COGL_MATERIAL_LAYER_COMBINE_FUNC_ADD_SIGNED = CGL_ADD_SIGNED, - COGL_MATERIAL_LAYER_COMBINE_FUNC_INTERPOLATE = CGL_INTERPOLATE, - COGL_MATERIAL_LAYER_COMBINE_FUNC_SUBTRACT = CGL_SUBTRACT, - COGL_MATERIAL_LAYER_COMBINE_FUNC_DOT3_RGB = CGL_DOT3_RGB, - COGL_MATERIAL_LAYER_COMBINE_FUNC_DOT3_RGBA = CGL_DOT3_RGBA -} CoglMaterialLayerCombineFunc; - -/** - * CoglMaterialLayerCombineChannels: - * @COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB: Modify the function or argument - * src/op for the RGB components of a - * layer - * @COGL_MATERIAL_LAYER_COMBINE_CHANNELS_ALPHA: Modify the function or argument - * src/op for the Alpha component of a - * layer - * @COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA: Modify the function or argument - * src/op for all the components of a - * layer - * - * Cogl optionally lets you describe 2 seperate combine modes for a single - * layer; 1 for the RGB components, and 1 for the Alpha component, so in this - * case you would repeat the 3 steps documented with the - * @cogl_material_set_layer_combine_function function for each channel - * selector. - * - * (Note: you can't have different modes for each channel, so if you need more - * control you will need to use a glsl fragment shader) - */ -typedef enum _CoglMaterialLayerCombineChannels -{ - COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB, - COGL_MATERIAL_LAYER_COMBINE_CHANNELS_ALPHA, - COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA -} CoglMaterialLayerCombineChannels; - -/** - * cogl_material_set_layer_combine_function: - * @material: A CoglMaterial object - * @layer_index: Specifies the layer whos combine mode you want to modify - * @channels: Specifies which channels combine mode you want to modify - * (RGB, ALPHA, or RGBA) - * @func: Specifies the function you want to use for combining fragments - * of the specified layer with the results of previously combined - * layers. - * - * There are three basic steps to describing how a layer should be combined: - * - * - * Choose a function. * - * - * Specify the source color for each argument of the chosen function. (Note - * the functions don't all take the same number of arguments) - * - * - * Specify an operator for each argument that can modify the corresponding - * source color before the function is applied. - * - * - * - * Cogl optionally lets you describe 2 seperate combine modes for a single - * layer; 1 for the RGB components, and 1 for the Alpha component, so in this - * case you would repeat the 3 steps for each channel selector. - * - * (Note: you can't have different modes for each channel, so if you need more - * control you will need to use a glsl fragment shader) - * - * For example here is how you could elect to use the ADD function for all - * components of layer 1 in your material: + * DOT3_RGBA(arg0, arg1) = * - * //Step 1: Choose a function. Note the ADD function takes 2 arguments... - * cogl_material_set_layer_combine_function (material, - * 1, - * COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA) - * COGL_MATERIAL_LAYER_COMBINE_FUNC_ADD); - * //Step 2: Specify the source color for the 2 ADD function arguments... - * cogl_material_set_layer_combine_arg_src (material, - * 1,//layer index - * 0,//argument index - * COGL_MATERIAL_LAYER_COMBINE_SRC_PREVIOUS); - * cogl_material_set_layer_combine_arg_src (material, - * 1,//layer index - * 1,//argument index - * COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA) - * COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE); - * //Step 3: Specify the operators used to modify the arguments... - * cogl_material_set_layer_combine_arg_op (material, - * 1,//layer index - * 0,//argument index - * COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA, - * COGL_MATERIAL_LAYER_COMBINE_OP_SRC_COLOR); - * cogl_material_set_layer_combine_arg_op (material, - * 1,//layer index - * 1,//argument index - * COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA, - * COGL_MATERIAL_LAYER_COMBINE_OP_SRC_COLOR); + * 4 x ((arg0[R] - 0.5)) * (arg1[R] - 0.5) + + * (arg0[G] - 0.5)) * (arg1[G] - 0.5) + + * (arg0[B] - 0.5)) * (arg1[B] - 0.5)) * - */ -void cogl_material_set_layer_combine_function (CoglHandle material, - gint layer_index, - CoglMaterialLayerCombineChannels channels, - CoglMaterialLayerCombineFunc func); - -/** - * CoglMaterialLayerCombineSrc: - * @COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE: The fragment color of the current texture layer - * @COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE0: The fragment color of texture unit 0 - * @COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE1: The fragment color of texture unit 1 - * @COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE2: The fragment color of texture unit 2..7 - * @COGL_MATERIAL_LAYER_COMBINE_SRC_CONSTANT: A fixed constant color (TODO: no API yet to specify the actual color!) - * @COGL_MATERIAL_LAYER_COMBINE_SRC_PRIMARY_COLOR: The basic color of the primitive ignoring texturing - * @COGL_MATERIAL_LAYER_COMBINE_SRC_PREVIOUS: The result of combining all previous layers + * + * * - * Note for the constants @COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE0..n the - * numbers may not correspond to the indices you choose for your layers since - * your layer indices don't need to be contiguous. If you need to use these - * it would probably be sensible to ensure the layer indices do infact - * correspond. + * Refer to the + * color-source syntax for + * describing the arguments. The valid source names for texture combining + * are: + * + * + * TEXTURE: Use the color from the current texture layer + * + * + * TEXTURE_0, TEXTURE_1, etc: Use the color from the specified texture layer + * + * + * CONSTANT: Use the color from the constant given with + * cogl_material_set_layer_constant() + * + * + * PRIMARY: Use the color of the material as set with cogl_material_set_color() + * + * + * PREVIOUS: Either use the texture color from the previous layer, or if this + * is layer 0, use the color of the material as set with + * cogl_material_set_color() + * + * + *
+ * Example + * This is effectively what the default blending is: + * + * "RGBA = MODULATE (PREVIOUS, TEXTURE)" + * + * This could be used to cross-fade between two images, using the alpha + * component of a constant as the interpolator. The constant color + * is given by calling cogl_material_set_layer_constant. + * + * RGBA = INTERPOLATE (PREVIOUS, TEXTURE, CONSTANT[A]) + * + *
+ * Note: you can't give a multiplication factor for arguments as you can + * with blending. + * + * Returns: TRUE if the blend string was successfully parsed, and the described + * texture combining is supported by the underlying driver/hardware. + * If there was an error, it returns FALSE. + * + * Since: 1.0 */ -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 = CGL_CONSTANT, - COGL_MATERIAL_LAYER_COMBINE_SRC_PRIMARY_COLOR = CGL_PRIMARY_COLOR, - COGL_MATERIAL_LAYER_COMBINE_SRC_PREVIOUS = CGL_PREVIOUS -} CoglMaterialLayerCombineSrc; +gboolean +cogl_material_set_layer_combine (CoglHandle material, + gint layer_index, + const char *blend_string, + GError **error); /** - * cogl_material_set_layer_combine_arg_src: + * cogl_material_set_layer_combine_constant: * @material: A CoglMaterial object - * @layer_index: - * @argument: - * @channels: - * @src: + * @layer_index: Specifies the layer you want to specify a constant used + * for texture combining + * @color_constant: The constant color you want * - */ -void cogl_material_set_layer_combine_arg_src (CoglHandle material, - gint layer_index, - gint argument, - CoglMaterialLayerCombineChannels channels, - CoglMaterialLayerCombineSrc src); - -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_set_layer_combine_arg_op: - * @material: A CoglMaterial object - * @layer_index: - * @argument: - * @channels: - * @op: + * When you are using the 'CONSTANT' color source in a layer combine + * description then you can use this function to define its value. * + * Since 1.0 */ -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 +void cogl_material_set_layer_combine_constant (CoglHandle material, + int layer_index, + CoglColor *constant); /** * cogl_material_set_layer_matrix: @@ -709,38 +643,9 @@ void cogl_material_set_layer_alpha_combine (CoglHandle material * and rotate a single layer of a material used to fill your geometry. */ void cogl_material_set_layer_matrix (CoglHandle material, - gint layer_index, + int layer_index, CoglMatrix *matrix); - -/** - * SECTION:cogl-material-internals - * @short_description: Functions for creating custom primitives that make use - * of Cogl materials for filling. - * - * Normally you shouldn't need to use this API directly, but if you need to - * developing a custom/specialised primitive - probably using raw OpenGL - then - * this API aims to expose enough of the material internals to support being - * able to fill your geometry according to a given Cogl material. - */ - - -/** - * 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. - */ -/* TODO: find a nicer solution! */ -gulong -cogl_material_get_cogl_enable_flags (CoglHandle handle); - /** * cogl_material_get_layers: * @material: A CoglMaterial object @@ -748,24 +653,20 @@ cogl_material_get_cogl_enable_flags (CoglHandle handle); * 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. + * Returns: A list of #CoglHandle's that can be passed to the + * cogl_material_layer_* functions. */ const GList *cogl_material_get_layers (CoglHandle material_handle); /** * CoglMaterialLayerType: - * @COGL_MATERIAL_LAYER_TYPE_TEXTURE: The layer represents a CoglTexture + * @COGL_MATERIAL_LAYER_TYPE_TEXTURE: The layer represents a + * Cogl texture + * + * Available types of layers for a #CoglMaterial. This enumeration + * might be expanded in later versions. + * + * Since: 1.0 */ typedef enum _CoglMaterialLayerType { @@ -774,17 +675,12 @@ typedef enum _CoglMaterialLayerType /** * cogl_material_layer_get_type: - * @layer_handle: A CoglMaterialLayer handle + * @layer_handle: A Cogl material layer handle * * 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); @@ -792,75 +688,58 @@ CoglMaterialLayerType cogl_material_layer_get_type (CoglHandle layer_handle); * cogl_material_layer_get_texture: * @layer_handle: A CoglMaterialLayer handle * - * 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. + * This lets you extract a CoglTexture handle for a specific layer. * * 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. + * likely return COGL_INVALID_HANDLE if you try to get the texture. + * Considering this, you can call cogl_material_layer_get_type first, + * to check it is of type COGL_MATERIAL_LAYER_TYPE_TEXTURE. + * + * Note: It is possible for a layer object of type + * COGL_MATERIAL_LAYER_TYPE_TEXTURE to be realized before a texture + * object has been associated with the layer. For example this happens + * if you setup layer combining for a given layer index before calling + * cogl_material_set_layer for that index. + * + * Returns: A CoglHandle to the layers texture object or COGL_INVALID_HANDLE + * if a texture has not been set yet. */ CoglHandle cogl_material_layer_get_texture (CoglHandle layer_handle); /** - * CoglMaterialLayerFlags: - * @COGL_MATERIAL_LAYER_FLAG_USER_MATRIX: Means the user has supplied a - * custom texture matrix. + * cogl_material_layer_get_min_filter: + * @layer_handle: a #CoglHandle for a material layer. + * + * Query the currently set downscaling filter for a cogl material layer. + * + * Returns: the current downscaling filter for a cogl material layer. */ -typedef enum _CoglMaterialLayerFlags -{ - COGL_MATERIAL_LAYER_FLAG_HAS_USER_MATRIX = 1L<<0 -} CoglMaterialLayerFlags; -/* XXX: NB: if you add flags here you will need to update - * CoglMaterialLayerPrivFlags!!! */ +CoglMaterialFilter cogl_material_layer_get_min_filter (CoglHandle layer_handle); /** - * cogl_material_layer_get_flags: - * @layer_handle: A CoglMaterialLayer layer handle + * cogl_material_layer_get_mag_filter: + * @layer_handle: a #CoglHandle for a material layer. * - * This lets you get a number of flag attributes about the 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. + * Query the currently set downscaling filter for a cogl material layer. + * + * Returns: the current downscaling filter for a cogl material layer. */ -gulong cogl_material_layer_get_flags (CoglHandle layer_handle); +CoglMaterialFilter cogl_material_layer_get_mag_filter (CoglHandle layer_handle); /** - * CoglMaterialFlushOption: - * @COGL_MATERIAL_FLUSH_FALLBACK_MASK: Follow this by a guin32 mask - * of the layers that can't be supported with the user supplied texture - * and need to be replaced with fallback textures. (1 = fallback, and the - * least significant bit = layer 0) - * @COGL_MATERIAL_FLUSH_DISABLE_MASK: Follow this by a guint32 mask - * of the layers that you want to completly disable texturing for - * (1 = fallback, and the least significant bit = layer 0) - * @COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE: Follow this by a GLuint OpenGL texture - * name to override the texture used for layer 0 of the material. This is - * intended for dealing with sliced textures where you will need to point - * to each of the texture slices in turn when drawing your geometry. - * Passing a value of 0 is the same as not passing the option at all. - */ -typedef enum _CoglMaterialFlushOption -{ - COGL_MATERIAL_FLUSH_FALLBACK_MASK = 1, - COGL_MATERIAL_FLUSH_DISABLE_MASK, - COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE, -} CoglMaterialFlushOption; - -/** - * cogl_material_flush_gl_state: - * @material: A CoglMaterial object - * @...: A NULL terminated list of (CoglMaterialFlushOption, data) pairs + * cogl_material_set_layer_filters: + * @handle: a #CoglHandle to a material. + * @layer_index: the layer number to change. + * @min_filter: the filter used when scaling a texture down. + * @mag_filter: the filter used when magnifying a texture. * - * This function commits the state of the specified CoglMaterial - including - * the texture state for all the layers - to the OpenGL[ES] driver. - * - * Since 1.0 + * Changes the decimation and interpolation filters used when a texture is + * drawn at other scales than 100%. */ -void cogl_material_flush_gl_state (CoglHandle material, - ...) G_GNUC_NULL_TERMINATED; +void cogl_material_set_layer_filters (CoglHandle handle, + gint layer_index, + CoglMaterialFilter min_filter, + CoglMaterialFilter mag_filter); G_END_DECLS diff --git a/cogl-matrix.h b/cogl-matrix.h index ca643f146..3ee94aeb5 100644 --- a/cogl-matrix.h +++ b/cogl-matrix.h @@ -199,22 +199,50 @@ void cogl_matrix_frustum (CoglMatrix *matrix, float z_far); /** - * cogl_matrix_transform_point: + * cogl_matrix_perspective: * @matrix: A 4x4 transformation matrix - * @x: The X component of your points position [in:out] - * @y: The Y component of your points position [in:out] - * @z: The Z component of your points position [in:out] - * @w: The W component of your points position [in:out] + * @fov_y: A field of view angle for the Y axis + * @aspect: The ratio of width to height determining the field of view angle + * for the x axis. + * @z_near: The distance to the near clip plane. + * Never pass 0 and always pass a positive number. + * @z_far: The distance to the far clip plane. (Should always be positive) * - * This transforms a point whos position is given and returned - * as four float components. + * Multiplies the matrix by the described perspective matrix + * + * Note: you should be careful not to have to great a z_far / z_near ratio + * since that will reduce the effectiveness of depth testing since there wont + * be enough precision to identify the depth of objects near to each other. */ void -cogl_matrix_transform_point (const CoglMatrix *matrix, - float *x, - float *y, - float *z, - float *w); +cogl_matrix_perspective (CoglMatrix *matrix, + float fov_y, + float aspect, + float z_near, + float z_far); + +/** + * cogl_matrix_ortho: + * @matrix: A 4x4 transformation matrix + * @left: The coordinate for the left clipping plane + * @right: The coordinate for the right clipping plane + * @bottom: The coordinate for the bottom clipping plane + * @top: The coordinate for the top clipping plane + * @z_near: The coordinate for the near clipping plane (may be negative if + * the plane is behind the viewer) + * @z_far: The coordinate for the far clipping plane (may be negative if + * the plane is behind the viewer) + * + * Multiples the matrix by a parallel projection matrix. + */ +void +cogl_matrix_ortho (CoglMatrix *matrix, + float left, + float right, + float bottom, + float top, + float z_near, + float z_far); /** * cogl_matrix_init_from_array: @@ -234,6 +262,24 @@ void cogl_matrix_init_from_array (CoglMatrix *matrix, const float *array); */ const float *cogl_matrix_get_array (const CoglMatrix *matrix); +/** + * cogl_matrix_transform_point: + * @matrix: A 4x4 transformation matrix + * @x: The X component of your points position [in:out] + * @y: The Y component of your points position [in:out] + * @z: The Z component of your points position [in:out] + * @w: The W component of your points position [in:out] + * + * This transforms a point whos position is given and returned + * as four float components. + */ +void +cogl_matrix_transform_point (const CoglMatrix *matrix, + float *x, + float *y, + float *z, + float *w); + G_END_DECLS #endif /* __COGL_MATRIX_H */ diff --git a/cogl-shader.h b/cogl-shader.h index 59c75ede6..9eec9bb40 100644 --- a/cogl-shader.h +++ b/cogl-shader.h @@ -46,9 +46,12 @@ G_BEGIN_DECLS * CoglShaderType: * @COGL_SHADER_TYPE_VERTEX: A program for proccessing vertices * @COGL_SHADER_TYPE_FRAGMENT: A program for processing fragments + * + * Types of shaders + * + * Since: 1.0 */ -typedef enum _CoglShaderType -{ +typedef enum { COGL_SHADER_TYPE_VERTEX, COGL_SHADER_TYPE_FRAGMENT } CoglShaderType; @@ -103,7 +106,7 @@ gboolean cogl_is_shader (CoglHandle handle); * one. */ void cogl_shader_source (CoglHandle shader, - const char *source); + const gchar *source); /** * cogl_shader_compile: * @handle: #CoglHandle for a shader. @@ -111,29 +114,30 @@ void cogl_shader_source (CoglHandle shader, * Compiles the shader, no return value, but the shader is now ready for * linking into a program. */ -void cogl_shader_compile (CoglHandle handle); +void cogl_shader_compile (CoglHandle handle); /** * cogl_shader_get_info_log: * @handle: #CoglHandle for a shader. - * @size: maximum number of bytes to retrieve. - * @buffer: location for info log. * * Retrieves the information log for a coglobject, can be used in conjunction - * with #cogl_shader_get_parameteriv to retrieve the compiler warnings/error + * with cogl_shader_get_parameteriv() to retrieve the compiler warnings/error * messages that caused a shader to not compile correctly, mainly useful for * debugging purposes. + * + * Return value: a newly allocated string containing the info log. Use + * g_free() to free it */ -void cogl_shader_get_info_log (CoglHandle handle, - size_t size, - char *buffer); +gchar * cogl_shader_get_info_log (CoglHandle handle); /** * cogl_shader_get_type: * @handle: #CoglHandle for a shader. * - * Returns: COGL_SHADER_TYPE_VERTEX if the shader is a vertex processor - * or COGL_SHADER_TYPE_FRAGMENT if the shader is a frament processor + * Retrieves the type of a shader #CoglHandle + * + * Return value: %COGL_SHADER_TYPE_VERTEX if the shader is a vertex processor + * or %COGL_SHADER_TYPE_FRAGMENT if the shader is a frament processor */ CoglShaderType cogl_shader_get_type (CoglHandle handle); @@ -141,7 +145,9 @@ CoglShaderType cogl_shader_get_type (CoglHandle handle); * cogl_shader_is_compiled: * @handle: #CoglHandle for a shader. * - * Returns: TRUE if the shader object has sucessfully be compiled else FALSE + * Retrieves whether a shader #CoglHandle has been compiled + * + * Return value: %TRUE if the shader object has sucessfully be compiled */ gboolean cogl_shader_is_compiled (CoglHandle handle); diff --git a/cogl-texture.h b/cogl-texture.h index 6a8b00a01..15cadc879 100644 --- a/cogl-texture.h +++ b/cogl-texture.h @@ -41,12 +41,12 @@ G_BEGIN_DECLS * loading and manipulating textures. */ +#define COGL_TEXTURE_MAX_WASTE 127 + /** * cogl_texture_new_with_size: * @width: width of texture in pixels. * @height: height of texture in pixels. - * @max_waste: maximum extra horizontal and|or vertical margin pixels - * to make the texture fit GPU limitations * @flags: Optional flags for the texture, or %COGL_TEXTURE_NONE * @internal_format: the #CoglPixelFormat to use for the GPU storage of the * texture. @@ -60,15 +60,12 @@ G_BEGIN_DECLS */ CoglHandle cogl_texture_new_with_size (guint width, guint height, - gint max_waste, CoglTextureFlags flags, CoglPixelFormat internal_format); /** * cogl_texture_new_from_file: * @filename: the file to load - * @max_waste: maximum extra horizontal and|or vertical margin pixels - * to make the texture fit GPU limitations * @flags: Optional flags for the texture, or %COGL_TEXTURE_NONE * @internal_format: the #CoglPixelFormat to use for the GPU storage of the * texture @@ -82,7 +79,6 @@ CoglHandle cogl_texture_new_with_size (guint width, * Since: 0.8 */ CoglHandle cogl_texture_new_from_file (const gchar *filename, - gint max_waste, CoglTextureFlags flags, CoglPixelFormat internal_format, GError **error); @@ -91,8 +87,6 @@ CoglHandle cogl_texture_new_from_file (const gchar *filename, * cogl_texture_new_from_data: * @width: width of texture in pixels * @height: height of texture in pixels - * @max_waste: maximum extra horizontal and|or vertical margin pixels - * to make the texture fit GPU limitations * @flags: Optional flags for the texture, or %COGL_TEXTURE_NONE * @format: the #CoglPixelFormat the buffer is stored in in RAM * @internal_format: the #CoglPixelFormat that will be used for storing @@ -110,7 +104,6 @@ CoglHandle cogl_texture_new_from_file (const gchar *filename, */ CoglHandle cogl_texture_new_from_data (guint width, guint height, - gint max_waste, CoglTextureFlags flags, CoglPixelFormat format, CoglPixelFormat internal_format, @@ -136,19 +129,17 @@ CoglHandle cogl_texture_new_from_data (guint width, * * Since: 0.8 */ -CoglHandle cogl_texture_new_from_foreign (GLuint gl_handle, - GLenum gl_target, - GLuint width, - GLuint height, - GLuint x_pot_waste, - GLuint y_pot_waste, - CoglPixelFormat format); +CoglHandle cogl_texture_new_from_foreign (GLuint gl_handle, + GLenum gl_target, + GLuint width, + GLuint height, + GLuint x_pot_waste, + GLuint y_pot_waste, + CoglPixelFormat format); /** * cogl_texture_new_from_bitmap: * @bmp_handle: A CoglBitmap handle - * @max_waste: maximum extra horizontal and|or vertical margin pixels - * to make the texture fit GPU limitations * @flags: Optional flags for the texture, or %COGL_TEXTURE_NONE * @internal_format: the #CoglPixelFormat to use for the GPU storage of the * texture @@ -160,10 +151,9 @@ CoglHandle cogl_texture_new_from_foreign (GLuint gl_handle, * * Since: 1.0 */ -CoglHandle cogl_texture_new_from_bitmap (CoglHandle bmp_handle, - gint max_waste, - CoglTextureFlags flags, - CoglPixelFormat internal_format); +CoglHandle cogl_texture_new_from_bitmap (CoglHandle bmp_handle, + CoglTextureFlags flags, + CoglPixelFormat internal_format); /** * cogl_is_texture: @@ -228,72 +218,6 @@ guint cogl_texture_get_rowstride (CoglHandle handle); */ gint cogl_texture_get_max_waste (CoglHandle handle); -/** - * CoglTextureFilter: - * @COGL_TEXTURE_FILTER_NEAREST: Measuring in manhatten distance from the, - * current pixel center, use the nearest texture - * texel. - * @COGL_TEXTURE_FILTER_LINEAR: Use the weighted average of the 4 texels - * nearest the current pixel center. - * @COGL_TEXTURE_FILTER_NEAREST_MIPMAP_NEAREST: Select the mimap level whose - * texel size most closely matches - * the current pixel, and use the - * COGL_TEXTURE_FILTER_NEAREST - * criterion. - * @COGL_TEXTURE_FILTER_LINEAR_MIPMAP_NEAREST: Select the mimap level whose - * texel size most closely matches - * the current pixel, and use the - * COGL_TEXTURE_FILTER_LINEAR - * criterion. - * @COGL_TEXTURE_FILTER_NEAREST_MIPMAP_LINEAR: Select the two mimap levels - * whose texel size most closely - * matches the current pixel, use - * the COGL_TEXTURE_FILTER_NEAREST - * criterion on each one and take - * their weighted average. - * @COGL_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR: Select the two mimap levels - * whose texel size most closely - * matches the current pixel, use - * the COGL_TEXTURE_FILTER_LINEAR - * criterion on each one and take - * their weighted average. - * - * Texture filtering is used whenever the current pixel maps either to more - * than one texture element (texel) or less than one. These filter enums - * correspond to different strategies used to come up with a pixel color, by - * possibly referring to multiple neighbouring texels and taking a weighted - * average or simply using the nearest texel. - */ -typedef enum _CoglTextureFilter -{ - COGL_TEXTURE_FILTER_NEAREST = GL_NEAREST, - COGL_TEXTURE_FILTER_LINEAR = GL_LINEAR, - COGL_TEXTURE_FILTER_NEAREST_MIPMAP_NEAREST = GL_NEAREST_MIPMAP_NEAREST, - COGL_TEXTURE_FILTER_LINEAR_MIPMAP_NEAREST = GL_LINEAR_MIPMAP_NEAREST, - COGL_TEXTURE_FILTER_NEAREST_MIPMAP_LINEAR = GL_NEAREST_MIPMAP_LINEAR, - COGL_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR = GL_LINEAR_MIPMAP_LINEAR -} CoglTextureFilter; - -/** - * cogl_texture_get_min_filter: - * @handle: a #CoglHandle for a texture. - * - * Query the currently set downscaling filter for a cogl texture. - * - * Returns: the current downscaling filter for a cogl texture. - */ -CoglTextureFilter cogl_texture_get_min_filter (CoglHandle handle); - -/** - * cogl_texture_get_mag_filter: - * @handle: a #CoglHandle for a texture. - * - * Query the currently set downscaling filter for a cogl texture. - * - * Returns: the current downscaling filter for a cogl texture. - */ -CoglTextureFilter cogl_texture_get_mag_filter (CoglHandle handle); - /** * cogl_texture_is_sliced: * @handle: a #CoglHandle for a texture. @@ -343,20 +267,6 @@ gint cogl_texture_get_data (CoglHandle handle, guint rowstride, guchar *data); -/** - * cogl_texture_set_filters: - * @handle: a #CoglHandle. - * @min_filter: the filter used when scaling the texture down. - * @mag_filter: the filter used when magnifying the texture. - * - * Changes the decimation and interpolation filters used when the texture is - * drawn at other scales than 100%. - */ -void cogl_texture_set_filters (CoglHandle handle, - CoglTextureFilter min_filter, - CoglTextureFilter mag_filter); - - /** * cogl_texture_set_region: * @handle: a #CoglHandle. diff --git a/cogl-types.h b/cogl-types.h index a4ecd4193..0a1360dde 100644 --- a/cogl-types.h +++ b/cogl-types.h @@ -123,8 +123,7 @@ typedef struct _CoglTextureVertex CoglTextureVertex; * * Since: 0.8 */ -typedef enum -{ +typedef enum { /*< prefix=COGL_PIXEL_FORMAT >*/ COGL_PIXEL_FORMAT_ANY = 0, COGL_PIXEL_FORMAT_A_8 = 1 | COGL_A_BIT, @@ -135,60 +134,21 @@ typedef enum COGL_PIXEL_FORMAT_G_8 = 8, COGL_PIXEL_FORMAT_RGB_888 = COGL_PIXEL_FORMAT_24, + COGL_PIXEL_FORMAT_BGR_888 = (COGL_PIXEL_FORMAT_24 | COGL_BGR_BIT), - COGL_PIXEL_FORMAT_BGR_888 = (COGL_PIXEL_FORMAT_24 | - COGL_BGR_BIT), - - COGL_PIXEL_FORMAT_RGBA_8888 = COGL_PIXEL_FORMAT_32 | - COGL_A_BIT, - - COGL_PIXEL_FORMAT_BGRA_8888 = (COGL_PIXEL_FORMAT_32 | - COGL_A_BIT | - COGL_BGR_BIT), - - COGL_PIXEL_FORMAT_ARGB_8888 = (COGL_PIXEL_FORMAT_32 | - COGL_A_BIT | - COGL_AFIRST_BIT), - - COGL_PIXEL_FORMAT_ABGR_8888 = (COGL_PIXEL_FORMAT_32 | - COGL_A_BIT | - COGL_BGR_BIT | - COGL_AFIRST_BIT), - - COGL_PIXEL_FORMAT_RGBA_8888_PRE = (COGL_PIXEL_FORMAT_32 | - COGL_A_BIT | - COGL_PREMULT_BIT), - - COGL_PIXEL_FORMAT_BGRA_8888_PRE = (COGL_PIXEL_FORMAT_32 | - COGL_A_BIT | - COGL_PREMULT_BIT | - COGL_BGR_BIT), - - COGL_PIXEL_FORMAT_ARGB_8888_PRE = (COGL_PIXEL_FORMAT_32 | - COGL_A_BIT | - COGL_PREMULT_BIT | - COGL_AFIRST_BIT), - - COGL_PIXEL_FORMAT_ABGR_8888_PRE = (COGL_PIXEL_FORMAT_32 | - COGL_A_BIT | - COGL_PREMULT_BIT | - COGL_BGR_BIT | - COGL_AFIRST_BIT), - - COGL_PIXEL_FORMAT_RGBA_4444_PRE = (COGL_PIXEL_FORMAT_RGBA_4444 | - COGL_A_BIT | - COGL_PREMULT_BIT), - - COGL_PIXEL_FORMAT_RGBA_5551_PRE = (COGL_PIXEL_FORMAT_RGBA_5551 | - COGL_A_BIT | - COGL_PREMULT_BIT), - + COGL_PIXEL_FORMAT_RGBA_8888 = (COGL_PIXEL_FORMAT_32 | COGL_A_BIT), + COGL_PIXEL_FORMAT_BGRA_8888 = (COGL_PIXEL_FORMAT_32 | COGL_A_BIT | COGL_BGR_BIT), + COGL_PIXEL_FORMAT_ARGB_8888 = (COGL_PIXEL_FORMAT_32 | COGL_A_BIT | COGL_AFIRST_BIT), + COGL_PIXEL_FORMAT_ABGR_8888 = (COGL_PIXEL_FORMAT_32 | COGL_A_BIT | COGL_BGR_BIT | COGL_AFIRST_BIT), + COGL_PIXEL_FORMAT_RGBA_8888_PRE = (COGL_PIXEL_FORMAT_32 | COGL_A_BIT | COGL_PREMULT_BIT), + COGL_PIXEL_FORMAT_BGRA_8888_PRE = (COGL_PIXEL_FORMAT_32 | COGL_A_BIT | COGL_PREMULT_BIT | COGL_BGR_BIT), + COGL_PIXEL_FORMAT_ARGB_8888_PRE = (COGL_PIXEL_FORMAT_32 | COGL_A_BIT | COGL_PREMULT_BIT | COGL_AFIRST_BIT), + COGL_PIXEL_FORMAT_ABGR_8888_PRE = (COGL_PIXEL_FORMAT_32 | COGL_A_BIT | COGL_PREMULT_BIT | COGL_BGR_BIT | COGL_AFIRST_BIT), + COGL_PIXEL_FORMAT_RGBA_4444_PRE = (COGL_PIXEL_FORMAT_RGBA_4444 | COGL_A_BIT | COGL_PREMULT_BIT), + COGL_PIXEL_FORMAT_RGBA_5551_PRE = (COGL_PIXEL_FORMAT_RGBA_5551 | COGL_A_BIT | COGL_PREMULT_BIT), } CoglPixelFormat; -#define COGL_TYPE_PIXEL_FORMAT (cogl_pixel_format_get_type ()) -GType cogl_pixel_format_get_type (void) G_GNUC_CONST; - /** * CoglFeatureFlags: * @COGL_FEATURE_TEXTURE_RECTANGLE: ARB_texture_rectangle support @@ -222,9 +182,6 @@ typedef enum COGL_FEATURE_VBOS = (1 << 11) } CoglFeatureFlags; -#define COGL_TYPE_FEATURE_FLAGS (cogl_feature_flags_get_type ()) -GType cogl_feature_flags_get_type (void) G_GNUC_CONST; - /** * CoglBufferTarget: * @COGL_WINDOW_BUFFER: FIXME @@ -240,9 +197,6 @@ typedef enum COGL_OFFSCREEN_BUFFER = (1 << 2) } CoglBufferTarget; -#define COGL_TYPE_BUFFER_TARGET (cogl_buffer_target_get_type ()) -GType cogl_buffer_target_get_type (void) G_GNUC_CONST; - /** * CoglColor: * @@ -290,21 +244,23 @@ struct _CoglTextureVertex /** * CoglTextureFlags: * @COGL_TEXTURE_NONE: No flags specified - * @COGL_TEXTURE_AUTO_MIPMAP: Enables the automatic generation of the - * mipmap pyramid from the base level image whenever it is updated + * @COGL_TEXTURE_NO_AUTO_MIPMAP: Disables the automatic generation of + * the mipmap pyramid from the base level image whenever it is + * updated. The mipmaps are only generated when the texture is + * rendered with a mipmap filter so it should be free to leave out + * this flag when using other filtering modes. + * @COGL_TEXTURE_NO_SLICING: Disables the slicing of the texture * * Flags to pass to the cogl_texture_new_* family of functions. * * Since: 1.0 */ typedef enum { - COGL_TEXTURE_NONE = 0, - COGL_TEXTURE_AUTO_MIPMAP = 1 << 0 + COGL_TEXTURE_NONE = 0, + COGL_TEXTURE_NO_AUTO_MIPMAP = 1 << 0, + COGL_TEXTURE_NO_SLICING = 1 << 1 } CoglTextureFlags; -#define COGL_TYPE_TEXTURE_FLAGS (cogl_texture_flags_get_type ()) -GType cogl_texture_flags_get_type (void) G_GNUC_CONST; - /** * CoglFogMode: * @COGL_FOG_MODE_LINEAR: Calculates the fog blend factor as: @@ -333,16 +289,12 @@ GType cogl_texture_flags_get_type (void) G_GNUC_CONST; * * Since: 1.0 */ -typedef enum _CoglFogMode -{ +typedef enum { COGL_FOG_MODE_LINEAR, COGL_FOG_MODE_EXPONENTIAL, COGL_FOG_MODE_EXPONENTIAL_SQUARED } CoglFogMode; -#define COGL_TYPE_FOG_MODE (cogl_fog_mode_get_type ()) -GType cogl_fog_mode_get_type (void) G_GNUC_CONST; - G_END_DECLS #endif /* __COGL_TYPES_H__ */ diff --git a/cogl-vertex-buffer.h b/cogl-vertex-buffer.h index 717281db0..f01b5d3dd 100644 --- a/cogl-vertex-buffer.h +++ b/cogl-vertex-buffer.h @@ -94,6 +94,29 @@ cogl_vertex_buffer_new (guint n_vertices); guint cogl_vertex_buffer_get_n_vertices (CoglHandle handle); +/** + * CoglAttributeType: + * @COGL_ATTRIBUTE_TYPE_BYTE: Data is the same size of a byte + * @COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE: Data is the same size of an + * unsigned byte + * @COGL_ATTRIBUTE_TYPE_SHORT: Data is the same size of a short integer + * @COGL_ATTRIBUTE_TYPE_UNSIGNED_SHORT: Data is the same size of + * an unsigned short integer + * @COGL_ATTRIBUTE_TYPE_FLOAT: Data is the same size of a float + * + * Data types for the components of cogl_vertex_buffer_add() + * + * Since: 1.0 + */ +typedef enum _CoglAttributeType +{ + COGL_ATTRIBUTE_TYPE_BYTE = GL_BYTE, + COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE = GL_UNSIGNED_BYTE, + COGL_ATTRIBUTE_TYPE_SHORT = GL_SHORT, + COGL_ATTRIBUTE_TYPE_UNSIGNED_SHORT = GL_UNSIGNED_SHORT, + COGL_ATTRIBUTE_TYPE_FLOAT = GL_FLOAT +} CoglAttributeType; + /** * cogl_vertex_buffer_add: * @handle: A vertex buffer handle @@ -111,10 +134,9 @@ cogl_vertex_buffer_get_n_vertices (CoglHandle handle); * the name can have a detail component, E.g. * "gl_Color::active" or "gl_Color::inactive" * @n_components: The number of components per attribute and must be 1,2,3 or 4 - * @gl_type: Specifies the data type of each component (GL_BYTE, GL_UNSIGNED_BYTE, - * GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, GL_UNSIGNED_INT or GL_FLOAT) + * @type: a #CoglAttributeType specifying the data type of each component. * @normalized: If GL_TRUE, this specifies that values stored in an integer - * format should be mapped into the range [-1.0, 1.0] or [0.1, 1.0] + * format should be mapped into the range [-1.0, 1.0] or [0.0, 1.0] * for unsigned values. If GL_FALSE they are converted to floats * directly. * @stride: This specifies the number of bytes from the start of one attribute @@ -156,13 +178,13 @@ cogl_vertex_buffer_get_n_vertices (CoglHandle handle); * (Though you can have multiple groups of interleved attributes) */ void -cogl_vertex_buffer_add (CoglHandle handle, - const char *attribute_name, - guint8 n_components, - GLenum gl_type, - gboolean normalized, - guint16 stride, - const void *pointer); +cogl_vertex_buffer_add (CoglHandle handle, + const char *attribute_name, + guint8 n_components, + CoglAttributeType type, + gboolean normalized, + guint16 stride, + const void *pointer); /** * cogl_vertex_buffer_delete: @@ -226,21 +248,37 @@ void cogl_vertex_buffer_enable (CoglHandle handle, const char *attribute_name); +/** + * CoglVerticesMode: + * @COGL_VERTICES_MODE_POINTS: FIXME, equivalent to %GL_POINTS + * @COGL_VERTICES_MODE_LINE_STRIP: FIXME, equivalent to %GL_LINE_STRIP + * @COGL_VERTICES_MODE_LINE_LOOP: FIXME, equivalent to %GL_LINE_LOOP + * @COGL_VERTICES_MODE_LINES: FIXME, equivalent to %GL_LINES + * @COGL_VERTICES_MODE_TRIANGLE_STRIP: FIXME, equivalent to %GL_TRIANGLE_STRIP + * @COGL_VERTICES_MODE_TRIANGLE_FAN: FIXME, equivalent to %GL_TRIANGLE_FAN + * @COGL_VERTICES_MODE_TRIANGLES: FIXME, equivalent to %GL_TRIANGLES + * + * How vertices passed to cogl_vertex_buffer_draw() and + * cogl_vertex_buffer_draw_elements() should be interpreted + * + * Since: 1.0 + */ +typedef enum _CoglVerticesMode +{ + COGL_VERTICES_MODE_POINTS = GL_POINTS, + COGL_VERTICES_MODE_LINE_STRIP = GL_LINE_STRIP, + COGL_VERTICES_MODE_LINE_LOOP = GL_LINE_LOOP, + COGL_VERTICES_MODE_LINES = GL_LINES, + COGL_VERTICES_MODE_TRIANGLE_STRIP = GL_TRIANGLE_STRIP, + COGL_VERTICES_MODE_TRIANGLE_FAN = GL_TRIANGLE_FAN, + COGL_VERTICES_MODE_TRIANGLES = GL_TRIANGLES +} CoglVerticesMode; + /** * cogl_vertex_buffer_draw: * @handle: A vertex buffer handle - * @mode: Specifies how the vertices should be interpreted, and should be - * a valid GL primitive type: - * - * GL_POINTS - * GL_LINE_STRIP - * GL_LINE_LOOP - * GL_LINES - * GL_TRIANGLE_STRIP - * GL_TRIANGLE_FAN - * GL_TRIANGLES - * - * (Note: only types available in GLES are listed) + * @mode: A #CoglVerticesMode specifying how the vertices should be + * interpreted. * @first: Specifies the index of the first vertex you want to draw with * @count: Specifies the number of vertices you want to draw. * @@ -251,52 +289,90 @@ cogl_vertex_buffer_enable (CoglHandle handle, * drawing. */ void -cogl_vertex_buffer_draw (CoglHandle handle, - GLenum mode, - GLint first, - GLsizei count); +cogl_vertex_buffer_draw (CoglHandle handle, + CoglVerticesMode mode, + int first, + int count); + +/** + * CoglIndicesType: + * @COGL_INDICES_TYPE_UNSIGNED_BYTE: Your indices are unsigned bytes + * @COGL_INDICES_TYPE_UNSIGNED_SHORT: Your indices are unsigned shorts + * @COGL_INDICES_TYPE_UNSIGNED_INT: You indices are unsigned integers + * + * You should aim to use the smallest data type that gives you enough + * range, since it reduces the size of your index array and can help + * reduce the demand on memory bandwidth. + */ +typedef enum _CoglIndicesType +{ + COGL_INDICES_TYPE_UNSIGNED_BYTE, + COGL_INDICES_TYPE_UNSIGNED_SHORT, + COGL_INDICES_TYPE_UNSIGNED_INT +} CoglIndicesType; + +/** + * cogl_vertex_buffer_indices_new: + * @indices_type: a #CoglIndicesType specifying the data type used for + * the indices. + * @indices_array: Specifies the address of your array of indices + * @indices_len: The number of indices in indices_array + * + * Depending on how much geometry you are submitting it can be worthwhile + * optimizing the number of redundant vertices you submit. Using an index + * array allows you to reference vertices multiple times, for example + * during triangle strips. + * + * Returns: A CoglHandle for the indices which you can pass to + * cogl_vertex_buffer_draw_elements(). + */ +CoglHandle +cogl_vertex_buffer_indices_new (CoglIndicesType indices_type, + const void *indices_array, + int indices_len); + +/** + * cogl_vertex_buffer_delete_indices: + * @handle: A vertex buffer handle + * @indices_id: The identifier for a an array of indices previously added to + * the given Cogl vertex buffer using + * cogl_vertex_buffer_add_indices(). + * + * Frees the resources associated with a previously added array of vertex + * indices. + */ +void +cogl_vertex_buffer_delete_indices (CoglHandle handle, + int indices_id); /** * cogl_vertex_buffer_draw_elements: * @handle: A vertex buffer handle - * @mode: Specifies how the vertices should be interpreted, and should be - * a valid GL primitive type: - * - * GL_POINTS - * GL_LINE_STRIP - * GL_LINE_LOOP - * GL_LINES - * GL_TRIANGLE_STRIP - * GL_TRIANGLE_FAN - * GL_TRIANGLES - * - * (Note: only types available in GLES are listed) + * @mode: A #CoglVerticesMode specifying how the vertices should be + * interpreted. + * @indices: A CoglHandle for a set of indices allocated via + * cogl_vertex_buffer_indices_new () * @min_index: Specifies the minimum vertex index contained in indices * @max_index: Specifies the maximum vertex index contained in indices + * @indices_offset: An offset into named indices. The offset marks the first + * index to use for drawing. * @count: Specifies the number of vertices you want to draw. - * @indices_type: Specifies the data type used for the indices, and must be - * one of: - * - * GL_UNSIGNED_BYTE - * GL_UNSIGNED_SHORT - * GL_UNSIGNED_INT - * - * @indices: Specifies the address of your array of indices * * This function lets you use an array of indices to specify the vertices - * within your vertex buffer that you want to draw. + * within your vertex buffer that you want to draw. The indices themselves + * are created by calling cogl_vertex_buffer_indices_new () * * Any un-submitted attribute changes are automatically submitted before * drawing. */ void -cogl_vertex_buffer_draw_elements (CoglHandle handle, - GLenum mode, - GLuint min_index, - GLuint max_index, - GLsizei count, - GLenum indices_type, - const GLvoid *indices); +cogl_vertex_buffer_draw_elements (CoglHandle handle, + CoglVerticesMode mode, + CoglHandle indices, + int min_index, + int max_index, + int indices_offset, + int count); /** * cogl_vertex_buffer_ref: @@ -318,6 +394,46 @@ cogl_vertex_buffer_ref (CoglHandle handle); void cogl_vertex_buffer_unref (CoglHandle handle); +/** + * cogl_vertex_buffer_indices_get_for_quads: + * @n_indices: the number of indices in the vertex buffer. + * + * Creates a vertex buffer containing the indices needed to draw pairs + * of triangles from a list of vertices grouped as quads. There will + * be at least @n_indices entries in the buffer (but there may be + * more). + * + * The indices will follow this pattern: + * + * 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7 ... etc + * + * For example, if you submit vertices for a quad like this: + * + * |[ + * 0 3 + * ######## + * # # + * # # + * ######## + * 1 2 + * ]| + * + * Then you can request 6 indices to render two triangles like this: + * + * |[ + * 0 0 3 + * ## ######## + * # ## ## # + * # ## ## # + * ######## ## + * 1 2 2 + * ]| + * + * Returns: A %CoglHandle containing the indices. The handled is + * owned by Cogl and should not be modified or unref'd. + */ +CoglHandle +cogl_vertex_buffer_indices_get_for_quads (guint n_indices); G_END_DECLS diff --git a/cogl.h.in b/cogl.h.in index bd3698312..a468cf717 100644 --- a/cogl.h.in +++ b/cogl.h.in @@ -45,6 +45,7 @@ #include #include #include +#include G_BEGIN_DECLS @@ -55,22 +56,6 @@ G_BEGIN_DECLS * General utility functions for COGL. */ -/* Context manipulation */ - -/** - * cogl_create_context: - * - * FIXME - */ -gboolean cogl_create_context (void); - -/** - * cogl_destroy_context: - * - * FIXME - */ -void cogl_destroy_context (void); - /** * cogl_get_option_group: * @@ -187,7 +172,30 @@ void cogl_frustum (float left, float z_far); /** - * cogl_setup_viewport: + * cogl_ortho: + * @left: The coordinate for the left clipping plane + * @right: The coordinate for the right clipping plane + * @bottom: The coordinate for the bottom clipping plane + * @top: The coordinate for the top clipping plane + * @near: The coordinate for the near clipping plane (may be negative if + * the plane is behind the viewer) + * @far: The coordinate for the far clipping plane (may be negative if + * the plane is behind the viewer) + * + * Replaces the current projection matrix with a parallel projection + * matrix. + * + * Since: 1.0 + */ +void cogl_ortho (float left, + float right, + float bottom, + float top, + float near, + float far); + +/* + * _cogl_setup_viewport: * @width: Width of the viewport * @height: Height of the viewport * @fovy: Field of view angle in degrees @@ -201,9 +209,11 @@ void cogl_frustum (float left, * with one that has a viewing angle of @fovy along the y-axis and a * view scaled according to @aspect along the x-axis. The view is * clipped according to @z_near and @z_far on the z-axis. + * + * This function is used only by Clutter. */ -void cogl_setup_viewport (guint width, - guint height, +void _cogl_setup_viewport (guint width, + guint height, float fovy, float aspect, float z_near, @@ -288,6 +298,14 @@ void cogl_rotate (float angle, */ void cogl_get_modelview_matrix (CoglMatrix *matrix); +/** + * cogl_set_modelview_matrix: + * @matrix: pointer to a CoglMatrix to set as the new model-view matrix + * + * Loads matrix as the new model-view matrix. + */ +void cogl_set_modelview_matrix (CoglMatrix *matrix); + /** * cogl_get_projection_matrix: * @matrix: pointer to a CoglMatrix to recieve the matrix @@ -296,6 +314,14 @@ void cogl_get_modelview_matrix (CoglMatrix *matrix); */ void cogl_get_projection_matrix (CoglMatrix *matrix); +/** + * cogl_set_projection_matrix: + * @matrix: pointer to a CoglMatrix to set as the new projection matrix + * + * Loads matrix as the new projection matrix. + */ +void cogl_set_projection_matrix (CoglMatrix *matrix); + /** * cogl_get_viewport: * @v: pointer to a 4 element array of #floats to @@ -308,7 +334,7 @@ void cogl_get_projection_matrix (CoglMatrix *matrix); void cogl_get_viewport (float v[4]); /** - * cogl_enable_depth_test: + * cogl_set_depth_test_enable: * @setting: %TRUE to enable depth testing or %FALSE to disable. * * Sets whether depth testing is enabled. If it is disabled then the @@ -317,10 +343,19 @@ void cogl_get_viewport (float v[4]); * clutter_actor_lower(), otherwise it will also take into account the * actor's depth. Depth testing is disabled by default. */ -void cogl_enable_depth_test (gboolean setting); +void cogl_set_depth_test_enable (gboolean setting); /** - * cogl_enable_backface_culling: + * cogl_get_depth_test_enable: + * + * Queries if depth testing has been enabled via cogl_set_depth_test_enable() + * + * Returns: TRUE if depth testing is enabled else FALSE + */ +gboolean cogl_get_depth_test_enable (void); + +/** + * cogl_set_backface_culling_enabled: * @setting: %TRUE to enable backface culling or %FALSE to disable. * * Sets whether textures positioned so that their backface is showing @@ -329,7 +364,17 @@ void cogl_enable_depth_test (gboolean setting); * only affects calls to the cogl_rectangle* family of functions and * cogl_vertex_buffer_draw*. Backface culling is disabled by default. */ -void cogl_enable_backface_culling (gboolean setting); +void cogl_set_backface_culling_enabled (gboolean setting); + +/** + * cogl_get_backface_culling_enabled: + * + * Queries if backface culling has been enabled via + * cogl_set_backface_culling_enabled() + * + * Returns: TRUE if backface culling is enabled else FALSE + */ +gboolean cogl_get_backface_culling_enabled (void); /** * cogl_set_fog: @@ -368,9 +413,12 @@ void cogl_disable_fog (void); * @COGL_BUFFER_BIT_COLOR: Selects the primary color buffer * @COGL_BUFFER_BIT_DEPTH: Selects the depth buffer * @COGL_BUFFER_BIT_STENCIL: Selects the stencil buffer + * + * Types of auxiliary buffers + * + * Since: 1.0 */ -typedef enum _CoglBufferBit -{ +typedef enum { COGL_BUFFER_BIT_COLOR = 1L<<0, COGL_BUFFER_BIT_DEPTH = 1L<<1, COGL_BUFFER_BIT_STENCIL = 1L<<2 @@ -379,13 +427,14 @@ typedef enum _CoglBufferBit /** * cogl_clear: * @color: Background color to clear to - * @buffers: A mask of @CoglBufferBit's identifying which auxiliary - * buffers to clear + * @buffers: A mask of #CoglBufferBit's identifying which auxiliary + * buffers to clear * * Clears all the auxiliary buffers identified in the @buffers mask, and if * that includes the color buffer then the specified @color is used. */ -void cogl_clear (const CoglColor *color, gulong buffers); +void cogl_clear (const CoglColor *color, + gulong buffers); /** * cogl_set_source: @@ -628,7 +677,24 @@ void cogl_push_draw_buffer (void); */ void cogl_pop_draw_buffer (void); -/** + +/* + * Internal API available only to Clutter. + * + * These are typically only to deal with the poor seperation of + * responsabilities that currently exists between Clutter and Cogl. + * Eventually a lot of the backend code currently in Clutter will + * move down into Cogl and these functions will be removed. + */ + +void _cogl_destroy_context (void); + +/* XXX: Removed before we release Clutter 1.0 since the implementation + * wasn't complete, and so we assume no one is using this yet. Util we + * have some one with a good usecase, we can't pretend to support breaking + * out into raw OpenGL. */ +#if 0 +/* * cogl_flush_gl_state: * @flags: flags controlling what is flushed; currently unused, pass in 0 * @@ -642,6 +708,7 @@ void cogl_pop_draw_buffer (void); * Since: 1.0 */ void cogl_flush_gl_state (int flags); +#endif /* private */ void _cogl_set_indirect_context (gboolean indirect); diff --git a/common/Makefile.am b/common/Makefile.am index 138893a14..7a7dd8232 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -1,3 +1,10 @@ +NULL = + +V = @ +Q = $(V:1=) +QUIET_GEN = $(Q:@=@echo ' GEN '$@;) +QUIET_CP = $(Q:@=@echo ' CP '$@;) + INCLUDES = \ -I$(top_srcdir) \ -I$(top_srcdir)/clutter \ @@ -9,12 +16,49 @@ INCLUDES = \ -DG_LOG_DOMAIN=\"Cogl-Common\" \ -DCLUTTER_COMPILATION +cogl_public_h = \ + $(top_srcdir)/clutter/cogl/cogl-bitmap.h \ + $(top_srcdir)/clutter/cogl/cogl-color.h \ + $(top_srcdir)/clutter/cogl/cogl-debug.h \ + $(top_srcdir)/clutter/cogl/cogl-fixed.h \ + $(top_srcdir)/clutter/cogl/cogl-material.h \ + $(top_srcdir)/clutter/cogl/cogl-matrix.h \ + $(top_srcdir)/clutter/cogl/cogl-offscreen.h \ + $(top_srcdir)/clutter/cogl/cogl-path.h \ + $(top_srcdir)/clutter/cogl/cogl-shader.h \ + $(top_srcdir)/clutter/cogl/cogl-texture.h \ + $(top_srcdir)/clutter/cogl/cogl-types.h \ + $(top_srcdir)/clutter/cogl/cogl-vertex-buffer.h \ + $(top_builddir)/clutter/cogl/cogl.h \ + $(NULL) + noinst_LTLIBRARIES = libclutter-cogl-common.la -EXTRA_DIST = stb_image.c + +cogl-enum-types.h: stamp-cogl-enum-types.h + @true +stamp-cogl-enum-types.h: $(cogl_public_h) Makefile + $(QUIET_GEN)( $(GLIB_MKENUMS) \ + --template $(srcdir)/cogl-enum-types.h.in \ + $(cogl_public_h) ) > xgen-ceth \ + && (cmp -s xgen-ceth cogl-enum-types.h || cp -f xgen-ceth cogl-enum-types.h) \ + && cp -f cogl-enum-types.h $(top_builddir)/clutter/cogl/cogl-enum-types.h \ + && rm -f xgen-ceth \ + && echo timestamp > $(@F) + +cogl-enum-types.c: cogl-enum-types.h + $(QUIET_GEN)( $(GLIB_MKENUMS) \ + --template $(srcdir)/cogl-enum-types.c.in \ + $(cogl_public_h) ) > xgen-cetc \ + && cp -f xgen-cetc cogl-enum-types.c \ + && rm -f xgen-cetc + +BUILT_SOURCES = cogl-enum-types.h cogl-enum-types.c libclutter_cogl_common_la_CPPFLAGS = $(CLUTTER_CFLAGS) $(COGL_DEBUG_CFLAGS) $(CLUTTER_DEBUG_CFLAGS) $(MAINTAINER_CFLAGS) libclutter_cogl_common_la_LIBADD = -lm $(CLUTTER_LIBS) libclutter_cogl_common_la_SOURCES = \ + $(top_builddir)/clutter/cogl/common/cogl-enum-types.h \ + $(top_builddir)/clutter/cogl/common/cogl-enum-types.c \ cogl-handle.h \ cogl-internal.h \ cogl.c \ @@ -39,4 +83,11 @@ libclutter_cogl_common_la_SOURCES = \ cogl-matrix-stack.h \ cogl-material.c \ cogl-material-private.h \ - cogl-debug.c + cogl-blend-string.c \ + cogl-blend-string.h \ + cogl-debug.c \ + $(NULL) + +EXTRA_DIST = stb_image.c cogl-enum-types.h.in cogl-enum-types.c.in +CLEANFILES = stamp-cogl-enum-types.h +DISTCLEANFILES = cogl-enum-types.h cogl-enum-types.c diff --git a/common/cogl-blend-string.c b/common/cogl-blend-string.c new file mode 100644 index 000000000..2e7bdd8d3 --- /dev/null +++ b/common/cogl-blend-string.c @@ -0,0 +1,999 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2009 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * Robert Bragg + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include + +#include "cogl.h" +#include "cogl-internal.h" +#include "cogl-context.h" +#include "cogl-debug.h" +#include "cogl-blend-string.h" + +typedef enum _ParserState +{ + PARSER_STATE_EXPECT_DEST_CHANNELS, + PARSER_STATE_SCRAPING_DEST_CHANNELS, + PARSER_STATE_EXPECT_FUNCTION_NAME, + PARSER_STATE_SCRAPING_FUNCTION_NAME, + PARSER_STATE_EXPECT_ARG_START, + PARSER_STATE_EXPECT_STATEMENT_END +} ParserState; + +typedef enum _ParserArgState +{ + PARSER_ARG_STATE_START, + PARSER_ARG_STATE_EXPECT_MINUS, + PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME, + PARSER_ARG_STATE_SCRAPING_COLOR_SRC_NAME, + PARSER_ARG_STATE_MAYBE_COLOR_MASK, + PARSER_ARG_STATE_SCRAPING_MASK, + PARSER_ARG_STATE_MAYBE_MULT, + PARSER_ARG_STATE_EXPECT_OPEN_PAREN, + PARSER_ARG_STATE_EXPECT_FACTOR, + PARSER_ARG_STATE_MAYBE_SRC_ALPHA_SATURATE, + PARSER_ARG_STATE_MAYBE_MINUS, + PARSER_ARG_STATE_EXPECT_CLOSE_PAREN, + PARSER_ARG_STATE_EXPECT_END +} ParserArgState; + + +#define DEFINE_COLOR_SOURCE(NAME, NAME_LEN) \ + {.type = COGL_BLEND_STRING_COLOR_SOURCE_ ## NAME, \ + .name = #NAME, \ + .name_len = NAME_LEN} + +static CoglBlendStringColorSourceInfo blending_color_sources[] = { + DEFINE_COLOR_SOURCE (SRC_COLOR, 9), + DEFINE_COLOR_SOURCE (DST_COLOR, 9), + DEFINE_COLOR_SOURCE (CONSTANT, 8) +}; + +static CoglBlendStringColorSourceInfo tex_combine_color_sources[] = { + DEFINE_COLOR_SOURCE (TEXTURE, 7), + /* DEFINE_COLOR_SOURCE (TEXTURE_N, *) - handled manually */ + DEFINE_COLOR_SOURCE (PRIMARY, 7), + DEFINE_COLOR_SOURCE (CONSTANT, 8), + DEFINE_COLOR_SOURCE (PREVIOUS, 8) +}; + +static CoglBlendStringColorSourceInfo tex_combine_texture_n_color_source = { + .type = COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE_N, + .name = "TEXTURE_N", + .name_len = 0 +}; + +#undef DEFINE_COLOR_SOURCE + +#define DEFINE_FUNCTION(NAME, NAME_LEN, ARGC) \ + { .type = COGL_BLEND_STRING_FUNCTION_ ## NAME, \ + .name = #NAME, \ + .name_len = NAME_LEN, \ + .argc = ARGC } + +/* NB: These must be sorted so any name that's a subset of another + * comes later than the longer name. */ +static CoglBlendStringFunctionInfo tex_combine_functions[] = { + DEFINE_FUNCTION (AUTO_COMPOSITE, 14, 0), + DEFINE_FUNCTION (REPLACE, 7, 1), + DEFINE_FUNCTION (MODULATE, 8, 2), + DEFINE_FUNCTION (ADD_SIGNED, 10, 2), + DEFINE_FUNCTION (ADD, 3, 2), + DEFINE_FUNCTION (INTERPOLATE, 11, 3), + DEFINE_FUNCTION (SUBTRACT, 8, 2), + DEFINE_FUNCTION (DOT3_RGBA, 9, 2), + DEFINE_FUNCTION (DOT3_RGB, 8, 2) +}; + +static CoglBlendStringFunctionInfo blend_functions[] = { + DEFINE_FUNCTION (AUTO_COMPOSITE, 14, 0), + DEFINE_FUNCTION (ADD, 3, 2) +}; + +#undef DEFINE_FUNCTION + +GQuark +_cogl_blend_string_error_quark (void) +{ + return g_quark_from_static_string ("cogl-blend-string-error-quark"); +} + +void +_cogl_blend_string_split_rgba_statement (CoglBlendStringStatement *statement, + CoglBlendStringStatement *rgb, + CoglBlendStringStatement *a) +{ + int i; + + memcpy (rgb, statement, sizeof (CoglBlendStringStatement)); + memcpy (a, statement, sizeof (CoglBlendStringStatement)); + + rgb->mask = COGL_BLEND_STRING_CHANNEL_MASK_RGB; + a->mask = COGL_BLEND_STRING_CHANNEL_MASK_ALPHA; + + for (i = 0; i < statement->function->argc; i++) + { + CoglBlendStringArgument *arg = &statement->args[i]; + CoglBlendStringArgument *rgb_arg = &rgb->args[i]; + CoglBlendStringArgument *a_arg = &a->args[i]; + + if (arg->source.mask == COGL_BLEND_STRING_CHANNEL_MASK_RGBA) + { + rgb_arg->source.mask = COGL_BLEND_STRING_CHANNEL_MASK_RGB; + a_arg->source.mask = COGL_BLEND_STRING_CHANNEL_MASK_ALPHA; + } + + if (arg->factor.is_color && + arg->factor.source.mask == COGL_BLEND_STRING_CHANNEL_MASK_RGBA) + { + rgb_arg->factor.source.mask = COGL_BLEND_STRING_CHANNEL_MASK_RGB; + a_arg->factor.source.mask = COGL_BLEND_STRING_CHANNEL_MASK_ALPHA; + } + } +} + +static gboolean +validate_tex_combine_statements (CoglBlendStringStatement *statements, + int n_statements, + GError **error) +{ + int i, j; + const char *error_string; + CoglBlendStringError detail = COGL_BLEND_STRING_ERROR_INVALID_ERROR; + + for (i = 0; i < n_statements; i++) + { +#ifdef HAVE_COGL_GLES2 + if (statements[i].function->type != COGL_BLEND_STRING_FUNCTION_MODULATE) + { + error_string = "Using anything but MODULATE() for texture combining" + " under GLES 2 is currently unsupported"; + detail = COGL_BLEND_STRING_ERROR_GPU_UNSUPPORTED_ERROR; + goto error; + } +#endif + for (j = 0; j < statements[i].function->argc; j++) + { + CoglBlendStringArgument *arg = &statements[i].args[j]; + if (arg->source.is_zero) + { + error_string = "You can't use the constant '0' as a texture " + "combine argument"; + goto error; + } + if (!arg->factor.is_one) + { + error_string = "Argument factors are only relevant to blending " + "not texture combining"; + goto error; + } +#ifdef HAVE_COGL_GLES2 + if (arg->source.info->type == COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT) + { + error_string = "Using a constant for texture combining isn't " + "currently supported with GLES 2 " + "(TODO: glTexEnvf)"; + detail = COGL_BLEND_STRING_ERROR_GPU_UNSUPPORTED_ERROR; + goto error; + } +#endif + } + } + + return TRUE; + +error: + g_set_error (error, + COGL_BLEND_STRING_ERROR, + detail, + "Invalid texture combine string: %s", + error_string); + + if (cogl_debug_flags & COGL_DEBUG_BLEND_STRINGS) + { + g_debug ("Invalid texture combine string: %s", + error_string); + } + return FALSE; +} + +static gboolean +validate_blend_statements (CoglBlendStringStatement *statements, + int n_statements, + GError **error) +{ + int i, j; + const char *error_string; + CoglBlendStringError detail = COGL_BLEND_STRING_ERROR_INVALID_ERROR; + +#ifdef HAVE_COGL_GL + _COGL_GET_CONTEXT (ctx, 0); +#endif + +#ifdef HAVE_COGL_GL + if (n_statements == 2) + { + /* glBlendEquationSeperate is GL 2.0 only */ + if (!ctx->pf_glBlendEquationSeparate && + statements[0].function->type != statements[1].function->type) + { + error_string = "Separate blend functions for the RGB an A " + "channels isn't supported by the driver"; + detail = COGL_BLEND_STRING_ERROR_GPU_UNSUPPORTED_ERROR; + goto error; + } + } +#elif defined(HAVE_COGL_GLES) + if (n_statements != 1) + { + error_string = "Separate blend functions for the RGB an A " + "channels isn't supported by the GLES 1"; + detail = COGL_BLEND_STRING_ERROR_GPU_UNSUPPORTED_ERROR; + goto error; + } +#endif + + for (i = 0; i < n_statements; i++) + for (j = 0; j < statements[i].function->argc; j++) + { + CoglBlendStringArgument *arg = &statements[i].args[j]; + + if (arg->source.is_zero) + continue; + + if ((j == 0 && + arg->source.info->type != + COGL_BLEND_STRING_COLOR_SOURCE_SRC_COLOR) + || (j == 1 && + arg->source.info->type != + COGL_BLEND_STRING_COLOR_SOURCE_DST_COLOR)) + { + error_string = "For blending you must always use SRC_COLOR " + "for arg0 and DST_COLOR for arg1"; + goto error; + } + +#ifdef HAVE_COGL_GLES + if (arg->factor.is_color && + arg->factor.source.info->type == COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT) + { + error_string = "GLES Doesn't support constant blend factors"; + detail = COGL_BLEND_STRING_ERROR_GPU_UNSUPPORTED_ERROR; + goto error; + } +#endif + } + + return TRUE; + +error: + g_set_error (error, + COGL_BLEND_STRING_ERROR, + detail, + "Invalid blend string: %s", + error_string); + return FALSE; +} + +static gboolean +validate_statements_for_context (CoglBlendStringStatement *statements, + int n_statements, + CoglBlendStringContext context, + GError **error) +{ + const char *error_string; + + if (n_statements == 1) + { + if (statements[0].mask == COGL_BLEND_STRING_CHANNEL_MASK_ALPHA) + { + error_string = "You need to also give a blend statement for the RGB" + "channels"; + goto error; + } + else if (statements[0].mask == COGL_BLEND_STRING_CHANNEL_MASK_RGB) + { + error_string = "You need to also give a blend statement for the " + "Alpha channel"; + goto error; + } + } + + if (context == COGL_BLEND_STRING_CONTEXT_BLENDING) + return validate_blend_statements (statements, n_statements, error); + else + return validate_tex_combine_statements (statements, n_statements, error); + +error: + g_set_error (error, + COGL_BLEND_STRING_ERROR, + COGL_BLEND_STRING_ERROR_INVALID_ERROR, + "Invalid %s string: %s", + context == COGL_BLEND_STRING_CONTEXT_BLENDING ? + "blend" : "texture combine", + error_string); + + if (cogl_debug_flags & COGL_DEBUG_BLEND_STRINGS) + { + g_debug ("Invalid %s string: %s", + context == COGL_BLEND_STRING_CONTEXT_BLENDING ? + "blend" : "texture combine", + error_string); + } + + return FALSE; +} + +static void +print_argument (CoglBlendStringArgument *arg) +{ + const char *mask_names[] = { + "RGB", + "A", + "RGBA" + }; + + g_print (" Arg:\n"); + g_print (" is zero = %s\n", arg->source.is_zero ? "yes" : "no"); + if (!arg->source.is_zero) + { + g_print (" color source = %s\n", arg->source.info->name); + g_print (" one minus = %s\n", arg->source.one_minus ? "yes" : "no"); + g_print (" mask = %s\n", mask_names[arg->source.mask]); + g_print (" texture = %d\n", arg->source.texture); + g_print ("\n"); + g_print (" factor is_one = %s\n", arg->factor.is_one ? "yes" : "no"); + g_print (" factor is_src_alpha_saturate = %s\n", + arg->factor.is_src_alpha_saturate ? "yes" : "no"); + g_print (" factor is_color = %s\n", arg->factor.is_color ? "yes" : "no"); + if (arg->factor.is_color) + { + g_print (" factor color:is zero = %s\n", + arg->factor.source.is_zero ? "yes" : "no"); + g_print (" factor color:color source = %s\n", + arg->factor.source.info->name); + g_print (" factor color:one minus = %s\n", + arg->factor.source.one_minus ? "yes" : "no"); + g_print (" factor color:mask = %s\n", + mask_names[arg->factor.source.mask]); + g_print (" factor color:texture = %d\n", + arg->factor.source.texture); + } + } +} + +static void +print_statement (int num, CoglBlendStringStatement *statement) +{ + const char *mask_names[] = { + "RGB", + "A", + "RGBA" + }; + int i; + g_print ("Statement %d:\n", num); + g_print (" Destination channel mask = %s\n", + mask_names[statement->mask]); + g_print (" Function = %s\n", statement->function->name); + for (i = 0; i < statement->function->argc; i++) + print_argument (&statement->args[i]); +} + +static const CoglBlendStringFunctionInfo * +get_function_info (const char *mark, + const char *p, + CoglBlendStringContext context) +{ + size_t len = p - mark; + CoglBlendStringFunctionInfo *functions; + size_t array_len; + int i; + + if (context == COGL_BLEND_STRING_CONTEXT_BLENDING) + { + functions = blend_functions; + array_len = G_N_ELEMENTS (blend_functions); + } + else + { + functions = tex_combine_functions; + array_len = G_N_ELEMENTS (tex_combine_functions); + } + + for (i = 0; i < array_len; i++) + { + if (len >= functions[i].name_len + && strncmp (mark, functions[i].name, functions[i].name_len) == 0) + return &functions[i]; + } + return NULL; +} + +static const CoglBlendStringColorSourceInfo * +get_color_src_info (const char *mark, + const char *p, + CoglBlendStringContext context) +{ + size_t len = p - mark; + CoglBlendStringColorSourceInfo *sources; + size_t array_len; + int i; + + if (context == COGL_BLEND_STRING_CONTEXT_BLENDING) + { + sources = blending_color_sources; + array_len = G_N_ELEMENTS (blending_color_sources); + } + else + { + sources = tex_combine_color_sources; + array_len = G_N_ELEMENTS (tex_combine_color_sources); + } + + for (i = 0; i < array_len; i++) + { + if (len >= sources[i].name_len + && strncmp (mark, sources[i].name, sources[i].name_len) == 0) + return &sources[i]; + } + + if (len >= 9 && + strncmp (mark, "TEXTURE_", 8) == 0 && + g_ascii_isdigit (mark[8])) + { + return &tex_combine_texture_n_color_source; + } + + return NULL; +} + +static gboolean +is_symbol_char (const char c) +{ + return (g_ascii_isalpha (c) || c == '_') ? TRUE : FALSE; +} + +static gboolean +parse_argument (const char *string, /* original user string */ + const char **ret_p, /* start of argument IN:OUT */ + const CoglBlendStringStatement *statement, + int current_arg, + CoglBlendStringArgument *arg, /* OUT */ + CoglBlendStringContext context, + GError **error) +{ + const char *p = *ret_p; + const char *mark; + const char *error_string; + ParserArgState state = PARSER_ARG_STATE_START; + gboolean parsing_factor = FALSE; + + arg->source.is_zero = FALSE; + arg->source.info = NULL; + arg->source.texture = 0; + arg->source.one_minus = FALSE; + arg->source.mask = statement->mask; + + arg->factor.is_one = FALSE; + arg->factor.is_color = FALSE; + arg->factor.is_src_alpha_saturate = FALSE; + + arg->factor.source.is_zero = FALSE; + arg->factor.source.info = NULL; + arg->factor.source.texture = 0; + arg->factor.source.one_minus = FALSE; + arg->factor.source.mask = statement->mask; + + do + { + if (g_ascii_isspace (*p)) + continue; + + if (*p == '\0') + { + error_string = "Unexpected end of string while parsing argument"; + goto error; + } + + switch (state) + { + case PARSER_ARG_STATE_START: + if (*p == '1') + state = PARSER_ARG_STATE_EXPECT_MINUS; + else if (*p == '0') + { + arg->source.is_zero = TRUE; + state = PARSER_ARG_STATE_EXPECT_END; + } + else + { + p--; /* backtrack */ + state = PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME; + } + continue; + + case PARSER_ARG_STATE_EXPECT_MINUS: + if (*p != '-') + { + error_string = "expected a '-' following the 1"; + goto error; + } + arg->source.one_minus = TRUE; + state = PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME; + continue; + + case PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME: + if (!is_symbol_char (*p)) + { + error_string = "expected a color source name"; + goto error; + } + state = PARSER_ARG_STATE_SCRAPING_COLOR_SRC_NAME; + mark = p; + if (parsing_factor) + arg->factor.is_color = TRUE; + + /* fall through */ + case PARSER_ARG_STATE_SCRAPING_COLOR_SRC_NAME: + if (!is_symbol_char (*p)) + { + CoglBlendStringColorSource *source = + parsing_factor ? &arg->factor.source : &arg->source; + source->info = get_color_src_info (mark, p, context); + if (!source->info) + { + error_string = "Unknown color source name"; + goto error; + } + if (source->info->type == + COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE_N) + { + char *endp; + source->texture = + strtoul (&mark[strlen ("TEXTURE_")], &endp, 10); + if (mark == endp) + { + error_string = "invalid texture number given with " + "TEXTURE_N color source"; + goto error; + } + p = endp; + } + state = PARSER_ARG_STATE_MAYBE_COLOR_MASK; + } + else + continue; + + /* fall through */ + case PARSER_ARG_STATE_MAYBE_COLOR_MASK: + if (*p != '[') + { + p--; /* backtrack */ + if (!parsing_factor) + state = PARSER_ARG_STATE_MAYBE_MULT; + else + state = PARSER_ARG_STATE_EXPECT_END; + continue; + } + state = PARSER_ARG_STATE_SCRAPING_MASK; + mark = p; + + /* fall through */ + case PARSER_ARG_STATE_SCRAPING_MASK: + if (*p == ']') + { + size_t len = p - mark; + CoglBlendStringColorSource *source = + parsing_factor ? &arg->factor.source : &arg->source; + + if (len == 5 && strncmp (mark, "[RGBA", len) == 0) + { + if (statement->mask != COGL_BLEND_STRING_CHANNEL_MASK_RGBA) + { + error_string = "You can't use an RGBA color mask if the " + "statement hasn't also got an RGBA= mask"; + goto error; + } + source->mask = COGL_BLEND_STRING_CHANNEL_MASK_RGBA; + } + else if (len == 4 && strncmp (mark, "[RGB", len) == 0) + source->mask = COGL_BLEND_STRING_CHANNEL_MASK_RGB; + else if (len == 2 && strncmp (mark, "[A", len) == 0) + source->mask = COGL_BLEND_STRING_CHANNEL_MASK_ALPHA; + else + { + error_string = "Expected a channel mask of [RGBA]" + "[RGB] or [A]"; + goto error; + } + if (parsing_factor) + state = PARSER_ARG_STATE_EXPECT_CLOSE_PAREN; + else + state = PARSER_ARG_STATE_MAYBE_MULT; + } + continue; + + case PARSER_ARG_STATE_EXPECT_OPEN_PAREN: + if (*p != '(') + { + error_string = "Expected '(' before blend factor - the parser " + "currently requires that all blend factors " + "following a '*' be surrounded in brackets"; + goto error; + } + parsing_factor = TRUE; + state = PARSER_ARG_STATE_EXPECT_FACTOR; + continue; + + case PARSER_ARG_STATE_EXPECT_FACTOR: + if (*p == '1') + state = PARSER_ARG_STATE_MAYBE_MINUS; + else if (*p == '0') + { + arg->source.is_zero = TRUE; + state = PARSER_ARG_STATE_EXPECT_CLOSE_PAREN; + } + else + { + state = PARSER_ARG_STATE_MAYBE_SRC_ALPHA_SATURATE; + mark = p; + } + continue; + + case PARSER_ARG_STATE_MAYBE_SRC_ALPHA_SATURATE: + if (!is_symbol_char (*p)) + { + size_t len = p - mark; + if (len >= strlen ("SRC_ALPHA_SATURATE") && + strncmp (mark, "SRC_ALPHA_SATURATE", len) == 0) + { + arg->factor.is_src_alpha_saturate = TRUE; + state = PARSER_ARG_STATE_EXPECT_CLOSE_PAREN; + } + else + { + state = PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME; + p = mark - 1; /* backtrack */ + } + } + continue; + + case PARSER_ARG_STATE_MAYBE_MINUS: + if (*p == '-') + { + arg->factor.source.one_minus = TRUE; + state = PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME; + } + else + { + arg->factor.is_one = TRUE; + state = PARSER_ARG_STATE_EXPECT_CLOSE_PAREN; + } + continue; + + case PARSER_ARG_STATE_EXPECT_CLOSE_PAREN: + if (*p != ')') + { + error_string = "Expected closing parenthesis after blend factor"; + goto error; + } + state = PARSER_ARG_STATE_EXPECT_END; + continue; + + case PARSER_ARG_STATE_MAYBE_MULT: + if (*p == '*') + { + state = PARSER_ARG_STATE_EXPECT_OPEN_PAREN; + continue; + } + arg->factor.is_one = TRUE; + state = PARSER_ARG_STATE_EXPECT_END; + + /* fall through */ + case PARSER_ARG_STATE_EXPECT_END: + if (*p != ',' && *p != ')') + { + error_string = "expected , or )"; + goto error; + } + + *ret_p = p - 1; + return TRUE; + } + } + while (p++); + +error: + { + int offset = p - string; + g_set_error (error, + COGL_BLEND_STRING_ERROR, + COGL_BLEND_STRING_ERROR_ARGUMENT_PARSE_ERROR, + "Syntax error for argument %d at offset %d: %s", + current_arg, + offset, + error_string); + + if (cogl_debug_flags & COGL_DEBUG_BLEND_STRINGS) + { + g_debug ("Syntax error for argument %d at offset %d: %s", + current_arg, offset, error_string); + } + return FALSE; + } +} + +int +_cogl_blend_string_compile (const char *string, + CoglBlendStringContext context, + CoglBlendStringStatement *statements, + GError **error) +{ + const char *p = string; + const char *mark; + const char *error_string; + ParserState state = PARSER_STATE_EXPECT_DEST_CHANNELS; + CoglBlendStringStatement *statement = statements; + int current_statement = 0; + int current_arg = 0; + int remaining_argc; + +#if 0 + cogl_debug_flags |= COGL_DEBUG_BLEND_STRINGS; +#endif + + if (cogl_debug_flags & COGL_DEBUG_BLEND_STRINGS) + { + COGL_NOTE (BLEND_STRINGS, "Compiling %s string:\n%s\n", + context == COGL_BLEND_STRING_CONTEXT_BLENDING ? + "blend" : "texture combine", + string); + } + + do + { + if (g_ascii_isspace (*p)) + continue; + + if (*p == '\0') + { + switch (state) + { + case PARSER_STATE_EXPECT_DEST_CHANNELS: + if (current_statement != 0) + goto finished; + error_string = "Empty statement"; + goto error; + case PARSER_STATE_SCRAPING_DEST_CHANNELS: + error_string = "Expected an '=' following the destination " + "channel mask"; + goto error; + case PARSER_STATE_EXPECT_FUNCTION_NAME: + error_string = "Expected a function name"; + goto error; + case PARSER_STATE_SCRAPING_FUNCTION_NAME: + error_string = "Expected parenthesis after the function name"; + goto error; + case PARSER_STATE_EXPECT_ARG_START: + error_string = "Expected to find the start of an argument"; + goto error; + case PARSER_STATE_EXPECT_STATEMENT_END: + error_string = "Expected closing parenthesis for statement"; + goto error; + } + } + + switch (state) + { + case PARSER_STATE_EXPECT_DEST_CHANNELS: + mark = p; + state = PARSER_STATE_SCRAPING_DEST_CHANNELS; + + /* fall through */ + case PARSER_STATE_SCRAPING_DEST_CHANNELS: + if (*p != '=') + continue; + if (strncmp (mark, "RGBA", 4) == 0) + statement->mask = COGL_BLEND_STRING_CHANNEL_MASK_RGBA; + else if (strncmp (mark, "RGB", 3) == 0) + statement->mask = COGL_BLEND_STRING_CHANNEL_MASK_RGB; + else if (strncmp (mark, "A", 1) == 0) + statement->mask = COGL_BLEND_STRING_CHANNEL_MASK_ALPHA; + else + { + error_string = "Unknown destination channel mask; " + "expected RGBA=, RGB= or A="; + goto error; + } + state = PARSER_STATE_EXPECT_FUNCTION_NAME; + continue; + + case PARSER_STATE_EXPECT_FUNCTION_NAME: + mark = p; + state = PARSER_STATE_SCRAPING_FUNCTION_NAME; + + /* fall through */ + case PARSER_STATE_SCRAPING_FUNCTION_NAME: + if (*p != '(') + { + if (!is_symbol_char (*p)) + { + error_string = "non alpha numeric character in function" + "name"; + goto error; + } + continue; + } + statement->function = get_function_info (mark, p, context); + if (!statement->function) + { + error_string = "Unknown function name"; + goto error; + } + remaining_argc = statement->function->argc; + current_arg = 0; + state = PARSER_STATE_EXPECT_ARG_START; + + /* fall through */ + case PARSER_STATE_EXPECT_ARG_START: + if (*p != '(' && *p != ',') + continue; + if (remaining_argc) + { + p++; /* parse_argument expects to see the first char of the arg */ + if (!parse_argument (string, &p, statement, + current_arg, &statement->args[current_arg], + context, error)) + return 0; + current_arg++; + remaining_argc--; + } + if (!remaining_argc) + state = PARSER_STATE_EXPECT_STATEMENT_END; + continue; + + case PARSER_STATE_EXPECT_STATEMENT_END: + if (*p != ')') + { + error_string = "Expected end of statement"; + goto error; + } + state = PARSER_STATE_EXPECT_DEST_CHANNELS; + if (current_statement++ == 1) + goto finished; + statement = &statements[current_statement]; + } + } + while (p++); + +finished: + + if (cogl_debug_flags & COGL_DEBUG_BLEND_STRINGS) + { + if (current_statement > 0) + print_statement (0, &statements[0]); + if (current_statement > 1) + print_statement (1, &statements[1]); + } + + if (!validate_statements_for_context (statements, + current_statement, + context, + error)) + return 0; + + return current_statement; + +error: + { + int offset = p - string; + g_set_error (error, + COGL_BLEND_STRING_ERROR, + COGL_BLEND_STRING_ERROR_PARSE_ERROR, + "Syntax error at offset %d: %s", + offset, + error_string); + + if (cogl_debug_flags & COGL_DEBUG_BLEND_STRINGS) + { + g_debug ("Syntax error at offset %d: %s", + offset, error_string); + } + return 0; + } +} + +/* + * INTERNAL TESTING CODE ... + */ + +struct _TestString +{ + const char *string; + CoglBlendStringContext context; +}; + +int +_cogl_blend_string_test (void) +{ + struct _TestString strings[] = { + {" A = MODULATE ( TEXTURE[RGB], PREVIOUS[A], PREVIOUS[A] ) ", + COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE }, + {" RGB = MODULATE ( TEXTURE[RGB], PREVIOUS[A] ) ", + COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE }, + {"A=ADD(TEXTURE[A],PREVIOUS[RGB])", + COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE }, + {"A=ADD(TEXTURE[A],PREVIOUS[RGB])", + COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE }, + + {"RGBA = ADD(SRC_COLOR*(SRC_COLOR[A]), DST_COLOR*(1-SRC_COLOR[A]))", + COGL_BLEND_STRING_CONTEXT_BLENDING }, + {"RGB = ADD(SRC_COLOR, DST_COLOR*(0))", + COGL_BLEND_STRING_CONTEXT_BLENDING }, + {"RGB = ADD(SRC_COLOR, 0)", + COGL_BLEND_STRING_CONTEXT_BLENDING }, + {"RGB = ADD()", + COGL_BLEND_STRING_CONTEXT_BLENDING }, + {"RGB = ADD(SRC_COLOR, 0, DST_COLOR)", + COGL_BLEND_STRING_CONTEXT_BLENDING }, + {NULL} + }; + int i; + + GError *error = NULL; + for (i = 0; strings[i].string; i++) + { + CoglBlendStringStatement statements[2]; + int count = _cogl_blend_string_compile (strings[i].string, + strings[i].context, + statements, + &error); + if (!count) + { + g_print ("Failed to parse string:\n%s\n%s\n", + strings[i].string, + error->message); + g_error_free (error); + error = NULL; + continue; + } + g_print ("Original:\n"); + g_print ("%s\n", strings[i].string); + if (count > 0) + print_statement (0, &statements[0]); + if (count > 1) + print_statement (1, &statements[1]); + } + + return 0; +} + diff --git a/common/cogl-blend-string.h b/common/cogl-blend-string.h new file mode 100644 index 000000000..a3e3888f8 --- /dev/null +++ b/common/cogl-blend-string.h @@ -0,0 +1,151 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2009 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * Robert Bragg + */ + +#ifndef COGL_BLEND_STRING_H +#define COGL_BLEND_STRING_H + +#include +#include + +typedef enum _CoglBlendStringContext +{ + COGL_BLEND_STRING_CONTEXT_BLENDING, + COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE +} CoglBlendStringContext; + +#define COGL_BLEND_STRING_ERROR _cogl_blend_string_error_quark () + +typedef enum _CoglBlendStringError +{ + COGL_BLEND_STRING_ERROR_PARSE_ERROR, + COGL_BLEND_STRING_ERROR_ARGUMENT_PARSE_ERROR, + COGL_BLEND_STRING_ERROR_INVALID_ERROR, + COGL_BLEND_STRING_ERROR_GPU_UNSUPPORTED_ERROR +} CoglBlendStringError; + +/* NB: debug stringify code will get upset if these + * are re-ordered */ +typedef enum _CoglBlendStringChannelMask +{ + COGL_BLEND_STRING_CHANNEL_MASK_RGB, + COGL_BLEND_STRING_CHANNEL_MASK_ALPHA, + COGL_BLEND_STRING_CHANNEL_MASK_RGBA +} CoglBlendStringChannelMask; + +typedef enum _CoglBlendStringColorSourceType +{ + /* blending */ + COGL_BLEND_STRING_COLOR_SOURCE_SRC_COLOR, + COGL_BLEND_STRING_COLOR_SOURCE_DST_COLOR, + + /* shared */ + COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT, + + /* texture combining */ + COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE, + COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE_N, + COGL_BLEND_STRING_COLOR_SOURCE_PRIMARY, + COGL_BLEND_STRING_COLOR_SOURCE_PREVIOUS +} CoglBlendStringColorSourceType; + +typedef struct _CoglBlendStringColorSourceInfo +{ + CoglBlendStringColorSourceType type; + const char *name; + size_t name_len; +} CoglBlendStringColorSourceInfo; + +typedef struct _CoglBlendStringColorSource +{ + gboolean is_zero; + const CoglBlendStringColorSourceInfo *info; + int texture; /* for the TEXTURE_N color source */ + gboolean one_minus; + CoglBlendStringChannelMask mask; +} CoglBlendStringColorSource; + +typedef struct _CoglBlendStringFactor +{ + gboolean is_one; + gboolean is_src_alpha_saturate; + gboolean is_color; + CoglBlendStringColorSource source; +} CoglBlendStringFactor; + +typedef struct _CoglBlendStringArgument +{ + CoglBlendStringColorSource source; + CoglBlendStringFactor factor; +} CoglBlendStringArgument; + +typedef enum _CoglBlendStringFunctionType +{ + /* shared */ + COGL_BLEND_STRING_FUNCTION_AUTO_COMPOSITE, + COGL_BLEND_STRING_FUNCTION_ADD, + + /* texture combine only */ + COGL_BLEND_STRING_FUNCTION_REPLACE, + COGL_BLEND_STRING_FUNCTION_MODULATE, + COGL_BLEND_STRING_FUNCTION_ADD_SIGNED, + COGL_BLEND_STRING_FUNCTION_INTERPOLATE, + COGL_BLEND_STRING_FUNCTION_SUBTRACT, + COGL_BLEND_STRING_FUNCTION_DOT3_RGB, + COGL_BLEND_STRING_FUNCTION_DOT3_RGBA +} CoglBlendStringFunctionType; + +typedef struct _CoglBlendStringFunctionInfo +{ + enum _CoglBlendStringFunctionType type; + const char *name; + size_t name_len; + int argc; +} CoglBlendStringFunctionInfo; + +typedef struct _CoglBlendStringStatement +{ + CoglBlendStringChannelMask mask; + const CoglBlendStringFunctionInfo *function; + CoglBlendStringArgument args[3]; +} CoglBlendStringStatement; + + +gboolean +_cogl_blend_string_compile (const char *string, + CoglBlendStringContext context, + CoglBlendStringStatement *statements, + GError **error); + +void +_cogl_blend_string_split_rgba_statement (CoglBlendStringStatement *statement, + CoglBlendStringStatement *rgb, + CoglBlendStringStatement *a); + +GQuark +_cogl_blend_string_error_quark (void); + +#endif /* COGL_BLEND_STRING_H */ + diff --git a/common/cogl-current-matrix.c b/common/cogl-current-matrix.c index 0080af0d1..6d069bc66 100644 --- a/common/cogl-current-matrix.c +++ b/common/cogl-current-matrix.c @@ -45,6 +45,9 @@ #define glFrustum(L,R,B,T,N,F) \ glFrustumf((GLfloat)L, (GLfloat)R, (GLfloat)B, \ (GLfloat)T, (GLfloat)N, (GLfloat)F) + +#define glOrtho glOrthof + #endif #include @@ -209,30 +212,57 @@ _cogl_current_matrix_frustum (float left, } void -_cogl_current_matrix_ortho (float left, - float right, - float bottom, - float top, - float near_val, - float far_val) +_cogl_current_matrix_perspective (float fov_y, + float aspect, + float z_near, + float z_far) +{ + _COGL_GET_CONTEXT_AND_STACK (ctx, current_stack, NO_RETVAL); + + if (current_stack != NULL) + _cogl_matrix_stack_perspective (current_stack, + fov_y, aspect, z_near, z_far); + else + { + /* NB: There is no glPerspective() (only gluPerspective()) so we use + * cogl_matrix_perspective: */ + CoglMatrix matrix; + _cogl_get_matrix (ctx->matrix_mode, &matrix); + cogl_matrix_perspective (&matrix, + fov_y, aspect, z_near, z_far); + _cogl_current_matrix_load (&matrix); + } +} + +void +_cogl_current_matrix_ortho (float left, + float right, + float bottom, + float top, + float near_val, + float far_val) { -#if 0 _COGL_GET_CONTEXT_AND_STACK (ctx, current_stack, NO_RETVAL); if (current_stack != NULL) _cogl_matrix_stack_ortho (current_stack, left, right, - top, bottom, + bottom, top, near_val, far_val); else - GE (glOrtho (left, right, bottom, top, near_val, far_val)); + { +#ifdef HAVE_COGL_GLES2 + /* NB: GLES 2 has no glOrtho(): */ + CoglMatrix matrix; + _cogl_get_matrix (ctx->matrix_mode, &matrix); + cogl_matrix_ortho (&matrix, + left, right, bottom, top, near_val, far_val); + _cogl_current_matrix_load (&matrix); #else - /* Nobody is using glOrtho right now anyway, so not bothering */ - g_warning ("%s not implemented, need to code cogl_matrix_ortho() if you need" - " this function", - G_STRFUNC); + GE (glOrtho (left, right, bottom, top, near_val, far_val)); #endif + } } void @@ -276,6 +306,12 @@ _cogl_get_matrix (CoglMatrixMode mode, } } +void +_cogl_set_matrix (const CoglMatrix *matrix) +{ + _cogl_current_matrix_load (matrix); +} + void _cogl_current_matrix_state_init (void) { @@ -354,85 +390,19 @@ cogl_rotate (float angle, float x, float y, float z) } void -_cogl_set_matrix (const CoglMatrix *matrix) -{ - _cogl_current_matrix_load (matrix); -} - -void -cogl_get_modelview_matrix (CoglMatrix *matrix) -{ - _cogl_get_matrix (COGL_MATRIX_MODELVIEW, - matrix); -} - -void -cogl_get_projection_matrix (CoglMatrix *matrix) -{ - _cogl_get_matrix (COGL_MATRIX_PROJECTION, - matrix); -} - -void -cogl_perspective (float fovy, +cogl_perspective (float fov_y, float aspect, - float zNear, - float zFar) + float z_near, + float z_far) { - float xmax, ymax; - float x, y, c, d; - float fovy_rad_half = (fovy * G_PI) / 360; - CoglMatrix perspective; - GLfloat m[16]; + float ymax = z_near * tanf (fov_y * G_PI / 360.0); - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - memset (&m[0], 0, sizeof (m)); - - _cogl_set_current_matrix (COGL_MATRIX_PROJECTION); - _cogl_current_matrix_identity (); - - /* - * Based on the original algorithm in perspective(): - * - * 1) xmin = -xmax => xmax + xmin == 0 && xmax - xmin == 2 * xmax - * same true for y, hence: a == 0 && b == 0; - * - * 2) When working with small numbers, we are loosing significant - * precision - */ - ymax = (zNear * (sinf (fovy_rad_half) / cosf (fovy_rad_half))); - xmax = (ymax * aspect); - - x = (zNear / xmax); - y = (zNear / ymax); - c = (-(zFar + zNear) / ( zFar - zNear)); - d = (-(2 * zFar) * zNear) / (zFar - zNear); - -#define M(row,col) m[col*4+row] - M(0,0) = x; - M(1,1) = y; - M(2,2) = c; - M(2,3) = d; - M(3,2) = -1.0; - - cogl_matrix_init_from_array (&perspective, m); - _cogl_current_matrix_multiply (&perspective); - - _cogl_set_current_matrix (COGL_MATRIX_MODELVIEW); - - /* Calculate and store the inverse of the matrix */ - memset (ctx->inverse_projection, 0, sizeof (float) * 16); - -#define m ctx->inverse_projection - M(0, 0) = (1.0 / x); - M(1, 1) = (1.0 / y); - M(2, 3) = -1.0; - M(3, 2) = (1.0 / d); - M(3, 3) = (c / d); -#undef m - -#undef M + cogl_frustum (-ymax * aspect, /* left */ + ymax * aspect, /* right */ + -ymax, /* bottom */ + ymax, /* top */ + z_near, + z_far); } void @@ -474,4 +444,65 @@ cogl_frustum (float left, M(3,2) = 1.0 / d; M(3,3) = c / d; #undef M + + _cogl_set_current_matrix (COGL_MATRIX_MODELVIEW); } + +void +cogl_ortho (float left, + float right, + float bottom, + float top, + float z_near, + float z_far) +{ + CoglMatrix ortho; + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + cogl_matrix_init_identity (&ortho); + cogl_matrix_ortho (&ortho, left, right, bottom, top, z_near, z_far); + _cogl_set_current_matrix (COGL_MATRIX_PROJECTION); + _cogl_current_matrix_load (&ortho); + + /* Calculate and store the inverse of the matrix */ + memset (ctx->inverse_projection, 0, sizeof (float) * 16); + +#define M(row,col) ctx->inverse_projection[col*4+row] + M(0,0) = 1.0 / ortho.xx; + M(0,3) = -ortho.xw; + M(1,1) = 1.0 / ortho.yy; + M(1,3) = -ortho.yw; + M(2,2) = 1.0 / ortho.zz; + M(2,3) = -ortho.zw; + M(3,3) = 1.0; +#undef M +} + +void +cogl_get_modelview_matrix (CoglMatrix *matrix) +{ + _cogl_get_matrix (COGL_MATRIX_MODELVIEW, + matrix); +} + +void +cogl_set_modelview_matrix (CoglMatrix *matrix) +{ + _cogl_set_current_matrix (COGL_MATRIX_MODELVIEW); + _cogl_current_matrix_load (matrix); +} + +void +cogl_get_projection_matrix (CoglMatrix *matrix) +{ + _cogl_get_matrix (COGL_MATRIX_PROJECTION, + matrix); +} + +void +cogl_set_projection_matrix (CoglMatrix *matrix) +{ + _cogl_set_current_matrix (COGL_MATRIX_PROJECTION); + _cogl_current_matrix_load (matrix); +} + diff --git a/common/cogl-debug.c b/common/cogl-debug.c index 85721fc22..b6dfd7559 100644 --- a/common/cogl-debug.c +++ b/common/cogl-debug.c @@ -39,7 +39,8 @@ static const GDebugKey cogl_debug_keys[] = { { "draw", COGL_DEBUG_DRAW }, { "pango", COGL_DEBUG_PANGO }, { "rectangles", COGL_DEBUG_RECTANGLES }, - { "handle", COGL_DEBUG_HANDLE } + { "handle", COGL_DEBUG_HANDLE }, + { "blend-strings", COGL_DEBUG_BLEND_STRINGS } }; static const gint n_cogl_debug_keys = G_N_ELEMENTS (cogl_debug_keys); diff --git a/common/cogl-enum-types.c.in b/common/cogl-enum-types.c.in new file mode 100644 index 000000000..157180dfe --- /dev/null +++ b/common/cogl-enum-types.c.in @@ -0,0 +1,41 @@ +/*** BEGIN file-header ***/ +#include "cogl-enum-types.h" +#include "cogl.h" +/*** END file-header ***/ + +/*** BEGIN file-production ***/ + +/* enumerations from "@filename@" */ +#include "@filename@" + +/*** END file-production ***/ + +/*** BEGIN value-header ***/ +GType +@enum_name@_get_type (void) +{ + static volatile gsize g_enum_type_id__volatile = 0; + + if (g_once_init_enter (&g_enum_type_id__volatile)) + { + static const G@Type@Value values[] = { +/*** END value-header ***/ + +/*** BEGIN value-production ***/ + { @VALUENAME@, "@VALUENAME@", "@valuenick@" }, +/*** END value-production ***/ + +/*** BEGIN value-tail ***/ + { 0, NULL, NULL } + }; + GType g_enum_type_id; + + g_enum_type_id = + g_@type@_register_static (g_intern_static_string ("@EnumName@"), values); + + g_once_init_leave (&g_enum_type_id__volatile, g_enum_type_id); + } + + return g_enum_type_id__volatile; +} +/*** END value-tail ***/ diff --git a/common/cogl-enum-types.h.in b/common/cogl-enum-types.h.in new file mode 100644 index 000000000..23d705dee --- /dev/null +++ b/common/cogl-enum-types.h.in @@ -0,0 +1,25 @@ +/*** BEGIN file-header ***/ +#ifndef __COGL_ENUM_TYPES_H__ +#define __COGL_ENUM_TYPES_H__ + +#include + +G_BEGIN_DECLS + +/*** END file-header ***/ + +/*** BEGIN file-production ***/ +/* enumerations from "@filename@" */ +/*** END file-production ***/ + +/*** BEGIN file-tail ***/ +G_END_DECLS + +#endif /* !__CLUTTER_ENUM_TYPES_H__ */ +/*** END file-tail ***/ + +/*** BEGIN value-header ***/ +GType @enum_name@_get_type (void) G_GNUC_CONST; +#define COGL_TYPE_@ENUMSHORT@ (@enum_name@_get_type()) + +/*** END value-header ***/ diff --git a/common/cogl-handle.h b/common/cogl-handle.h index 7851932db..6caee0e71 100644 --- a/common/cogl-handle.h +++ b/common/cogl-handle.h @@ -82,7 +82,7 @@ typedef struct _CoglHandleObject static CoglHandleClass _cogl_##type_name##_class; \ \ static GQuark \ -_cogl_##type_name##_get_type (void) \ +_cogl_handle_##type_name##_get_type (void) \ { \ static GQuark type = 0; \ if (!type) \ @@ -99,13 +99,13 @@ _cogl_##type_name##_handle_new (Cogl##TypeName *new_obj) \ obj->klass = &_cogl_##type_name##_class; \ if (!obj->klass->type) \ { \ - obj->klass->type = _cogl_##type_name##_get_type (); \ - obj->klass->virt_free = _cogl_##type_name##_free; \ - } \ + obj->klass->type = _cogl_handle_##type_name##_get_type ();\ + obj->klass->virt_free = _cogl_##type_name##_free; \ + } \ \ - _COGL_HANDLE_DEBUG_NEW (TypeName, obj); \ - return (CoglHandle) new_obj; \ - } \ + _COGL_HANDLE_DEBUG_NEW (TypeName, obj); \ + return (CoglHandle) new_obj; \ +} \ \ Cogl##TypeName * \ _cogl_##type_name##_pointer_from_handle (CoglHandle handle) \ @@ -121,7 +121,8 @@ cogl_is_##type_name (CoglHandle handle) \ if (handle == COGL_INVALID_HANDLE) \ return FALSE; \ \ - return (obj->klass->type == _cogl_##type_name##_get_type ()); \ + return (obj->klass->type == \ + _cogl_handle_##type_name##_get_type ()); \ } \ \ CoglHandle G_GNUC_DEPRECATED \ diff --git a/common/cogl-material-private.h b/common/cogl-material-private.h index 05d4242dd..e61ab97bd 100644 --- a/common/cogl-material-private.h +++ b/common/cogl-material-private.h @@ -68,15 +68,20 @@ struct _CoglMaterialLayer CoglHandle texture; /*!< The texture for this layer, or COGL_INVALID_HANDLE for an empty layer */ + CoglMaterialFilter mag_filter; + CoglMaterialFilter min_filter; + /* 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]; + GLint texture_combine_rgb_func; + GLint texture_combine_rgb_src[3]; + GLint texture_combine_rgb_op[3]; - CoglMaterialLayerCombineFunc texture_combine_alpha_func; - CoglMaterialLayerCombineSrc texture_combine_alpha_src[3]; - CoglMaterialLayerCombineOp texture_combine_alpha_op[3]; + GLint texture_combine_alpha_func; + GLint texture_combine_alpha_src[3]; + GLint texture_combine_alpha_op[3]; + + GLfloat texture_combine_constant[4]; /* TODO: Support purely GLSL based material layers */ @@ -114,11 +119,104 @@ struct _CoglMaterial GLfloat alpha_func_reference; /* Determines how this material is blended with other primitives */ - CoglMaterialBlendFactor blend_src_factor; - CoglMaterialBlendFactor blend_dst_factor; +#ifndef HAVE_COGL_GLES + GLenum blend_equation_rgb; + GLenum blend_equation_alpha; + GLint blend_src_factor_alpha; + GLint blend_dst_factor_alpha; + GLfloat blend_constant[4]; +#endif + GLint blend_src_factor_rgb; + GLint blend_dst_factor_rgb; GList *layers; }; +/* + * SECTION:cogl-material-internals + * @short_description: Functions for creating custom primitives that make use + * of Cogl materials for filling. + * + * Normally you shouldn't need to use this API directly, but if you need to + * developing a custom/specialised primitive - probably using raw OpenGL - then + * this API aims to expose enough of the material internals to support being + * able to fill your geometry according to a given Cogl material. + */ + + +/* + * 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. + */ +/* TODO: find a nicer solution! */ +gulong _cogl_material_get_cogl_enable_flags (CoglHandle handle); + +/* + * CoglMaterialLayerFlags: + * @COGL_MATERIAL_LAYER_FLAG_USER_MATRIX: Means the user has supplied a + * custom texture matrix. + */ +typedef enum _CoglMaterialLayerFlags +{ + COGL_MATERIAL_LAYER_FLAG_HAS_USER_MATRIX = 1L<<0 +} CoglMaterialLayerFlags; +/* XXX: NB: if you add flags here you will need to update + * CoglMaterialLayerPrivFlags!!! */ + +/* + * cogl_material_layer_get_flags: + * @layer_handle: A CoglMaterialLayer layer handle + * + * This lets you get a number of flag attributes about the 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. + */ +gulong _cogl_material_layer_get_flags (CoglHandle layer_handle); + +/* + * CoglMaterialFlushOption: + * @COGL_MATERIAL_FLUSH_FALLBACK_MASK: Follow this by a guin32 mask + * of the layers that can't be supported with the user supplied texture + * and need to be replaced with fallback textures. (1 = fallback, and the + * least significant bit = layer 0) + * @COGL_MATERIAL_FLUSH_DISABLE_MASK: Follow this by a guint32 mask + * of the layers that you want to completly disable texturing for + * (1 = fallback, and the least significant bit = layer 0) + * @COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE: Follow this by a GLuint OpenGL texture + * name to override the texture used for layer 0 of the material. This is + * intended for dealing with sliced textures where you will need to point + * to each of the texture slices in turn when drawing your geometry. + * Passing a value of 0 is the same as not passing the option at all. + */ +typedef enum _CoglMaterialFlushOption +{ + COGL_MATERIAL_FLUSH_FALLBACK_MASK = 1, + COGL_MATERIAL_FLUSH_DISABLE_MASK, + COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE, +} CoglMaterialFlushOption; + +/* + * cogl_material_flush_gl_state: + * @material: A CoglMaterial object + * @...: A NULL terminated list of (CoglMaterialFlushOption, data) pairs + * + * This function commits the state of the specified CoglMaterial - including + * the texture state for all the layers - to the OpenGL[ES] driver. + * + * Since 1.0 + */ +void _cogl_material_flush_gl_state (CoglHandle material, + ...) G_GNUC_NULL_TERMINATED; + + #endif /* __COGL_MATERIAL_PRIVATE_H */ diff --git a/common/cogl-material.c b/common/cogl-material.c index c456cac6a..66a4b0c96 100644 --- a/common/cogl-material.c +++ b/common/cogl-material.c @@ -35,6 +35,7 @@ #include "cogl-material-private.h" #include "cogl-texture-private.h" +#include "cogl-blend-string.h" #include #include @@ -50,6 +51,10 @@ #ifdef HAVE_COGL_GL #define glActiveTexture ctx->pf_glActiveTexture #define glClientActiveTexture ctx->pf_glClientActiveTexture +#define glBlendFuncSeparate ctx->pf_glBlendFuncSeparate +#define glBlendEquation ctx->pf_glBlendEquation +#define glBlendColor ctx->pf_glBlendColor +#define glBlendEquationSeparate ctx->pf_glBlendEquationSeparate #endif static void _cogl_material_free (CoglMaterial *tex); @@ -60,6 +65,12 @@ COGL_HANDLE_DEFINE (MaterialLayer, material_layer); /* #define DISABLE_MATERIAL_CACHE 1 */ +GQuark +_cogl_material_error_quark (void) +{ + return g_quark_from_static_string ("cogl-material-error-quark"); +} + CoglHandle cogl_material_new (void) { @@ -88,8 +99,18 @@ cogl_material_new (void) material->flags |= COGL_MATERIAL_FLAG_DEFAULT_ALPHA_FUNC; /* 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; +#ifndef HAVE_COGL_GLES + material->blend_equation_rgb = GL_FUNC_ADD; + material->blend_equation_alpha = GL_FUNC_ADD; + material->blend_src_factor_alpha = GL_SRC_ALPHA; + material->blend_dst_factor_alpha = GL_ONE_MINUS_SRC_ALPHA; + material->blend_constant[0] = 0; + material->blend_constant[1] = 0; + material->blend_constant[2] = 0; + material->blend_constant[3] = 0; +#endif + material->blend_src_factor_rgb = GL_SRC_ALPHA; + material->blend_dst_factor_rgb = GL_ONE_MINUS_SRC_ALPHA; material->flags |= COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC; material->layers = NULL; @@ -408,20 +429,177 @@ cogl_material_set_alpha_test_function (CoglHandle handle, material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_ALPHA_FUNC; } +GLenum +arg_to_gl_blend_factor (CoglBlendStringArgument *arg) +{ + if (arg->source.is_zero) + return GL_ZERO; + if (arg->factor.is_one) + return GL_ONE; + else if (arg->factor.is_src_alpha_saturate) + return GL_SRC_ALPHA_SATURATE; + else if (arg->factor.source.info->type == + COGL_BLEND_STRING_COLOR_SOURCE_SRC_COLOR) + { + if (arg->factor.source.mask == COGL_BLEND_STRING_CHANNEL_MASK_RGB) + { + if (arg->factor.source.one_minus) + return GL_ONE_MINUS_SRC_COLOR; + else + return GL_SRC_COLOR; + } + else + { + if (arg->factor.source.one_minus) + return GL_ONE_MINUS_SRC_ALPHA; + else + return GL_SRC_ALPHA; + } + } + else if (arg->factor.source.info->type == + COGL_BLEND_STRING_COLOR_SOURCE_DST_COLOR) + { + if (arg->factor.source.mask == COGL_BLEND_STRING_CHANNEL_MASK_RGB) + { + if (arg->factor.source.one_minus) + return GL_ONE_MINUS_DST_COLOR; + else + return GL_DST_COLOR; + } + else + { + if (arg->factor.source.one_minus) + return GL_ONE_MINUS_DST_ALPHA; + else + return GL_DST_ALPHA; + } + } +#ifndef HAVE_COGL_GLES + else if (arg->factor.source.info->type == + COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT) + { + if (arg->factor.source.mask == COGL_BLEND_STRING_CHANNEL_MASK_RGB) + { + if (arg->factor.source.one_minus) + return GL_ONE_MINUS_CONSTANT_COLOR; + else + return GL_CONSTANT_COLOR; + } + else + { + if (arg->factor.source.one_minus) + return GL_ONE_MINUS_CONSTANT_ALPHA; + else + return GL_CONSTANT_ALPHA; + } + } +#endif + + g_warning ("Unable to determine valid blend factor from blend string\n"); + return GL_ONE; +} + void -cogl_material_set_blend_factors (CoglHandle handle, - CoglMaterialBlendFactor src_factor, - CoglMaterialBlendFactor dst_factor) +setup_blend_state (CoglBlendStringStatement *statement, + GLenum *blend_equation, + GLint *blend_src_factor, + GLint *blend_dst_factor) +{ +#ifndef HAVE_COGL_GLES + switch (statement->function->type) + { + case COGL_BLEND_STRING_FUNCTION_ADD: + *blend_equation = GL_FUNC_ADD; + break; + /* TODO - add more */ + default: + g_warning ("Unsupported blend function given"); + *blend_equation = GL_FUNC_ADD; + } +#endif + + *blend_src_factor = arg_to_gl_blend_factor (&statement->args[0]); + *blend_dst_factor = arg_to_gl_blend_factor (&statement->args[1]); +} + +gboolean +cogl_material_set_blend (CoglHandle handle, + const char *blend_description, + GError **error) { CoglMaterial *material; + CoglBlendStringStatement statements[2]; + CoglBlendStringStatement split[2]; + CoglBlendStringStatement *rgb; + CoglBlendStringStatement *a; + int count; + + g_return_val_if_fail (cogl_is_material (handle), FALSE); + + material = _cogl_material_pointer_from_handle (handle); + + count = + _cogl_blend_string_compile (blend_description, + COGL_BLEND_STRING_CONTEXT_BLENDING, + statements, + error); + if (!count) + return FALSE; + + if (statements[0].mask == COGL_BLEND_STRING_CHANNEL_MASK_RGBA) + { + _cogl_blend_string_split_rgba_statement (statements, + &split[0], &split[1]); + rgb = &split[0]; + a = &split[1]; + } + else + { + rgb = &statements[0]; + a = &statements[1]; + } + +#ifndef HAVE_COGL_GLES + setup_blend_state (rgb, + &material->blend_equation_rgb, + &material->blend_src_factor_rgb, + &material->blend_dst_factor_rgb); + setup_blend_state (a, + &material->blend_equation_alpha, + &material->blend_src_factor_alpha, + &material->blend_dst_factor_alpha); +#else + setup_blend_state (rgb, + NULL, + &material->blend_src_factor_rgb, + &material->blend_dst_factor_rgb); +#endif + + material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC; + + return TRUE; +} + +void +cogl_material_set_blend_constant (CoglHandle handle, + CoglColor *constant_color) +{ +#ifndef HAVE_COGL_GLES + CoglMaterial *material; + GLfloat *constant; 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; + + constant = material->blend_constant; + constant[0] = cogl_color_get_red_float (constant_color); + constant[1] = cogl_color_get_green_float (constant_color); + constant[2] = cogl_color_get_blue_float (constant_color); + constant[3] = cogl_color_get_alpha_float (constant_color); material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC; +#endif } /* Asserts that a layer corresponding to the given index exists. If no @@ -459,25 +637,22 @@ _cogl_material_get_layer (CoglMaterial *material, layer_handle = _cogl_material_layer_handle_new (layer); layer->index = index_; layer->flags = COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE; + layer->mag_filter = COGL_MATERIAL_FILTER_LINEAR; + layer->min_filter = COGL_MATERIAL_FILTER_LINEAR; 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->texture_combine_rgb_func = GL_MODULATE; + layer->texture_combine_rgb_src[0] = GL_PREVIOUS; + layer->texture_combine_rgb_src[1] = GL_TEXTURE; + layer->texture_combine_rgb_op[0] = GL_SRC_COLOR; + layer->texture_combine_rgb_op[1] = GL_SRC_COLOR; + layer->texture_combine_alpha_func = GL_MODULATE; + layer->texture_combine_alpha_src[0] = GL_PREVIOUS; + layer->texture_combine_alpha_src[1] = GL_TEXTURE; + layer->texture_combine_alpha_op[0] = GL_SRC_ALPHA; + layer->texture_combine_alpha_op[1] = GL_SRC_ALPHA; cogl_matrix_init_identity (&layer->matrix); @@ -498,7 +673,8 @@ cogl_material_set_layer (CoglHandle material_handle, int n_layers; g_return_if_fail (cogl_is_material (material_handle)); - g_return_if_fail (cogl_is_texture (texture_handle)); + g_return_if_fail (texture_handle == COGL_INVALID_HANDLE + || cogl_is_texture (texture_handle)); material = _cogl_material_pointer_from_handle (material_handle); layer = _cogl_material_get_layer (material_handle, layer_index, TRUE); @@ -519,7 +695,8 @@ cogl_material_set_layer (CoglHandle material_handle, * MAX_COMBINED_TEXTURE_IMAGE_UNITS layers. */ } - cogl_handle_ref (texture_handle); + if (texture_handle) + cogl_handle_ref (texture_handle); if (layer->texture) cogl_handle_unref (layer->texture); @@ -530,104 +707,164 @@ cogl_material_set_layer (CoglHandle material_handle, layer->flags |= COGL_MATERIAL_LAYER_FLAG_DIRTY; } -void -cogl_material_set_layer_combine_function ( - CoglHandle handle, - gint layer_index, - CoglMaterialLayerCombineChannels channels, - CoglMaterialLayerCombineFunc func) +static void +setup_texture_combine_state (CoglBlendStringStatement *statement, + GLint *texture_combine_func, + GLint *texture_combine_src, + GLint *texture_combine_op) +{ + int i; + + switch (statement->function->type) + { + case COGL_BLEND_STRING_FUNCTION_AUTO_COMPOSITE: + *texture_combine_func = GL_MODULATE; /* FIXME */ + break; + case COGL_BLEND_STRING_FUNCTION_REPLACE: + *texture_combine_func = GL_REPLACE; + break; + case COGL_BLEND_STRING_FUNCTION_MODULATE: + *texture_combine_func = GL_MODULATE; + break; + case COGL_BLEND_STRING_FUNCTION_ADD: + *texture_combine_func = GL_ADD; + break; + case COGL_BLEND_STRING_FUNCTION_ADD_SIGNED: + *texture_combine_func = GL_ADD_SIGNED; + break; + case COGL_BLEND_STRING_FUNCTION_INTERPOLATE: + *texture_combine_func = GL_INTERPOLATE; + break; + case COGL_BLEND_STRING_FUNCTION_SUBTRACT: + *texture_combine_func = GL_SUBTRACT; + break; + case COGL_BLEND_STRING_FUNCTION_DOT3_RGB: + *texture_combine_func = GL_DOT3_RGB; + break; + case COGL_BLEND_STRING_FUNCTION_DOT3_RGBA: + *texture_combine_func = GL_DOT3_RGBA; + break; + } + + for (i = 0; i < statement->function->argc; i++) + { + CoglBlendStringArgument *arg = &statement->args[i]; + + switch (arg->source.info->type) + { + case COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT: + texture_combine_src[i] = GL_CONSTANT; + break; + case COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE: + texture_combine_src[i] = GL_TEXTURE; + break; + case COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE_N: + texture_combine_src[i] = + GL_TEXTURE0 + arg->source.texture; + break; + case COGL_BLEND_STRING_COLOR_SOURCE_PRIMARY: + texture_combine_src[i] = GL_PRIMARY_COLOR; + break; + case COGL_BLEND_STRING_COLOR_SOURCE_PREVIOUS: + texture_combine_src[i] = GL_PREVIOUS; + break; + default: + g_warning ("Unexpected texture combine source"); + texture_combine_src[i] = GL_TEXTURE; + } + + if (arg->source.mask == COGL_BLEND_STRING_CHANNEL_MASK_RGB) + { + if (statement->args[i].source.one_minus) + texture_combine_op[i] = GL_ONE_MINUS_SRC_COLOR; + else + texture_combine_op[i] = GL_SRC_COLOR; + } + else + { + if (statement->args[i].source.one_minus) + texture_combine_op[i] = GL_ONE_MINUS_SRC_ALPHA; + else + texture_combine_op[i] = GL_SRC_ALPHA; + } + } +} + +gboolean +cogl_material_set_layer_combine (CoglHandle handle, + gint layer_index, + const char *combine_description, + GError **error) { CoglMaterial *material; CoglMaterialLayer *layer; - gboolean set_alpha_func = FALSE; - gboolean set_rgb_func = FALSE; + CoglBlendStringStatement statements[2]; + CoglBlendStringStatement split[2]; + CoglBlendStringStatement *rgb; + CoglBlendStringStatement *a; + int count; + + g_return_val_if_fail (cogl_is_material (handle), FALSE); + + material = _cogl_material_pointer_from_handle (handle); + layer = _cogl_material_get_layer (material, layer_index, TRUE); + + count = + _cogl_blend_string_compile (combine_description, + COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE, + statements, + error); + if (!count) + return FALSE; + + if (statements[0].mask == COGL_BLEND_STRING_CHANNEL_MASK_RGBA) + { + _cogl_blend_string_split_rgba_statement (statements, + &split[0], &split[1]); + rgb = &split[0]; + a = &split[1]; + } + else + { + rgb = &statements[0]; + a = &statements[1]; + } + + setup_texture_combine_state (rgb, + &layer->texture_combine_rgb_func, + layer->texture_combine_rgb_src, + layer->texture_combine_rgb_op); + + setup_texture_combine_state (a, + &layer->texture_combine_alpha_func, + layer->texture_combine_alpha_src, + layer->texture_combine_alpha_op); + + + layer->flags |= COGL_MATERIAL_LAYER_FLAG_DIRTY; + layer->flags &= ~COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE; + return TRUE; +} + +void +cogl_material_set_layer_combine_constant (CoglHandle handle, + gint layer_index, + CoglColor *constant_color) +{ + CoglMaterial *material; + CoglMaterialLayer *layer; + GLfloat *constant; g_return_if_fail (cogl_is_material (handle)); material = _cogl_material_pointer_from_handle (handle); layer = _cogl_material_get_layer (material, layer_index, TRUE); - 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; - - layer->flags |= COGL_MATERIAL_LAYER_FLAG_DIRTY; - layer->flags &= ~COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE; -} - -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, TRUE); - - 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; - - layer->flags |= COGL_MATERIAL_LAYER_FLAG_DIRTY; - layer->flags &= ~COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE; -} - -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, TRUE); - - 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; + constant = layer->texture_combine_constant; + constant[0] = cogl_color_get_red_float (constant_color); + constant[1] = cogl_color_get_green_float (constant_color); + constant[2] = cogl_color_get_blue_float (constant_color); + constant[3] = cogl_color_get_alpha_float (constant_color); layer->flags |= COGL_MATERIAL_LAYER_FLAG_DIRTY; layer->flags &= ~COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE; @@ -690,7 +927,7 @@ cogl_material_remove_layer (CoglHandle material_handle, /* 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) +_cogl_material_get_cogl_enable_flags (CoglHandle material_handle) { CoglMaterial *material; gulong enable_flags = 0; @@ -713,7 +950,7 @@ cogl_material_get_cogl_enable_flags (CoglHandle material_handle) * 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 + * Alternatively; 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. */ @@ -748,7 +985,7 @@ cogl_material_layer_get_texture (CoglHandle layer_handle) } gulong -cogl_material_layer_get_flags (CoglHandle layer_handle) +_cogl_material_layer_get_flags (CoglHandle layer_handle) { CoglMaterialLayer *layer; @@ -760,25 +997,34 @@ cogl_material_layer_get_flags (CoglHandle layer_handle) } static guint -get_n_args_for_combine_func (CoglMaterialLayerCombineFunc func) +get_n_args_for_combine_func (GLint func) { switch (func) { - case COGL_MATERIAL_LAYER_COMBINE_FUNC_REPLACE: + case GL_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: + case GL_MODULATE: + case GL_ADD: + case GL_ADD_SIGNED: + case GL_SUBTRACT: + case GL_DOT3_RGB: + case GL_DOT3_RGBA: return 2; - case COGL_MATERIAL_LAYER_COMBINE_FUNC_INTERPOLATE: + case GL_INTERPOLATE: return 3; } return 0; } +static gboolean +is_mipmap_filter (CoglMaterialFilter filter) +{ + return (filter == COGL_MATERIAL_FILTER_NEAREST_MIPMAP_NEAREST + || filter == COGL_MATERIAL_FILTER_LINEAR_MIPMAP_NEAREST + || filter == COGL_MATERIAL_FILTER_NEAREST_MIPMAP_LINEAR + || filter == COGL_MATERIAL_FILTER_LINEAR_MIPMAP_LINEAR); +} + static void _cogl_material_layer_flush_gl_sampler_state (CoglMaterialLayer *layer, CoglLayerInfo *gl_layer_info) @@ -851,6 +1097,9 @@ _cogl_material_layer_flush_gl_sampler_state (CoglMaterialLayer *layer, GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, layer->texture_combine_alpha_op[2])); } + + GE (glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, + layer->texture_combine_constant)); } #ifndef DISABLE_MATERIAL_CACHE @@ -976,6 +1225,13 @@ _cogl_material_flush_layers_gl_state (CoglMaterial *material, GE (glActiveTexture (GL_TEXTURE0 + i)); + _cogl_texture_set_filters (layer->texture, + layer->min_filter, + layer->mag_filter); + if (is_mipmap_filter (layer->min_filter) + || is_mipmap_filter (layer->mag_filter)) + _cogl_texture_ensure_mipmaps (layer->texture); + /* FIXME: We could be more clever here and only bind the texture if it is different from gl_layer_info->gl_texture to avoid redundant GL calls. However a few other places in Cogl and @@ -1122,12 +1378,44 @@ _cogl_material_flush_base_gl_state (CoglMaterial *material) if (!(ctx->current_material_flags & COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC && material->flags & COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC)) { - GE (glBlendFunc (material->blend_src_factor, material->blend_dst_factor)); +#if defined (HAVE_COGL_GLES2) + gboolean have_blend_equation_seperate = TRUE; +#elif defined (HAVE_COGL_GL) + gboolean have_blend_equation_seperate = FALSE; + if (ctx->pf_glBlendEquationSeparate) /* Only GL 2.0 + */ + have_blend_equation_seperate = TRUE; +#endif + +#ifndef HAVE_COGL_GLES /* GLES 1 only has glBlendFunc */ + if (material->blend_src_factor_rgb != material->blend_src_factor_alpha + || (material->blend_src_factor_rgb != + material->blend_src_factor_alpha)) + { + if (have_blend_equation_seperate && + material->blend_equation_rgb != material->blend_equation_alpha) + GE (glBlendEquationSeparate (material->blend_equation_rgb, + material->blend_equation_alpha)); + else + GE (glBlendEquation (material->blend_equation_rgb)); + + GE (glBlendFuncSeparate (material->blend_src_factor_rgb, + material->blend_dst_factor_rgb, + material->blend_src_factor_alpha, + material->blend_dst_factor_alpha)); + GE (glBlendColor (material->blend_constant[0], + material->blend_constant[1], + material->blend_constant[2], + material->blend_constant[3])); + } + else +#endif + GE (glBlendFunc (material->blend_src_factor_rgb, + material->blend_dst_factor_rgb)); } } void -cogl_material_flush_gl_state (CoglHandle handle, ...) +_cogl_material_flush_gl_state (CoglHandle handle, ...) { CoglMaterial *material; va_list ap; @@ -1204,3 +1492,44 @@ cogl_set_source_texture (CoglHandle texture_handle) cogl_set_source (ctx->default_material); } +CoglMaterialFilter +cogl_material_layer_get_min_filter (CoglHandle layer_handle) +{ + CoglMaterialLayer *layer; + + g_return_val_if_fail (cogl_is_material_layer (layer_handle), 0); + + layer = _cogl_material_layer_pointer_from_handle (layer_handle); + + return layer->min_filter; +} + +CoglMaterialFilter +cogl_material_layer_get_mag_filter (CoglHandle layer_handle) +{ + CoglMaterialLayer *layer; + + g_return_val_if_fail (cogl_is_material_layer (layer_handle), 0); + + layer = _cogl_material_layer_pointer_from_handle (layer_handle); + + return layer->mag_filter; +} + +void +cogl_material_set_layer_filters (CoglHandle handle, + gint layer_index, + CoglMaterialFilter min_filter, + CoglMaterialFilter mag_filter) +{ + CoglMaterial *material; + CoglMaterialLayer *layer; + + g_return_if_fail (cogl_is_material (handle)); + + material = _cogl_material_pointer_from_handle (handle); + layer = _cogl_material_get_layer (material, layer_index, TRUE); + + layer->min_filter = min_filter; + layer->mag_filter = mag_filter; +} diff --git a/common/cogl-matrix-stack.c b/common/cogl-matrix-stack.c index a72af000d..6ba909840 100644 --- a/common/cogl-matrix-stack.c +++ b/common/cogl-matrix-stack.c @@ -257,6 +257,59 @@ _cogl_matrix_stack_multiply (CoglMatrixStack *stack, stack->flushed_state = NULL; } +void +_cogl_matrix_stack_frustum (CoglMatrixStack *stack, + float left, + float right, + float bottom, + float top, + float z_near, + float z_far) +{ + CoglMatrixState *state; + + state = _cogl_matrix_stack_top_mutable (stack); + cogl_matrix_frustum (&state->matrix, + left, right, bottom, top, + z_near, z_far); + /* mark dirty */ + stack->flushed_state = NULL; +} + +void +_cogl_matrix_stack_perspective (CoglMatrixStack *stack, + float fov_y, + float aspect, + float z_near, + float z_far) +{ + CoglMatrixState *state; + + state = _cogl_matrix_stack_top_mutable (stack); + cogl_matrix_perspective (&state->matrix, + fov_y, aspect, z_near, z_far); + /* mark dirty */ + stack->flushed_state = NULL; +} + +void +_cogl_matrix_stack_ortho (CoglMatrixStack *stack, + float left, + float right, + float bottom, + float top, + float z_near, + float z_far) +{ + CoglMatrixState *state; + + state = _cogl_matrix_stack_top_mutable (stack); + cogl_matrix_ortho (&state->matrix, + left, right, bottom, top, z_near, z_far); + /* mark dirty */ + stack->flushed_state = NULL; +} + void _cogl_matrix_stack_get (CoglMatrixStack *stack, CoglMatrix *matrix) @@ -280,25 +333,6 @@ _cogl_matrix_stack_set (CoglMatrixStack *stack, stack->flushed_state = NULL; } -void -_cogl_matrix_stack_frustum (CoglMatrixStack *stack, - float left, - float right, - float bottom, - float top, - float z_near, - float z_far) -{ - CoglMatrixState *state; - - state = _cogl_matrix_stack_top_mutable (stack); - cogl_matrix_frustum (&state->matrix, - left, right, bottom, top, - z_near, z_far); - /* mark dirty */ - stack->flushed_state = NULL; -} - void _cogl_matrix_stack_flush_to_gl (CoglMatrixStack *stack, GLenum gl_mode) diff --git a/common/cogl-matrix-stack.h b/common/cogl-matrix-stack.h index 00db51685..a766f4bbc 100644 --- a/common/cogl-matrix-stack.h +++ b/common/cogl-matrix-stack.h @@ -51,10 +51,6 @@ void _cogl_matrix_stack_rotate (CoglMatrixStack *stack, float z); void _cogl_matrix_stack_multiply (CoglMatrixStack *stack, const CoglMatrix *matrix); -void _cogl_matrix_stack_get (CoglMatrixStack *stack, - CoglMatrix *matrix); -void _cogl_matrix_stack_set (CoglMatrixStack *stack, - const CoglMatrix *matrix); void _cogl_matrix_stack_frustum (CoglMatrixStack *stack, float left, float right, @@ -62,6 +58,22 @@ void _cogl_matrix_stack_frustum (CoglMatrixStack *stack, float top, float z_near, float z_far); +void _cogl_matrix_stack_perspective (CoglMatrixStack *stack, + float fov_y, + float aspect, + float z_near, + float z_far); +void _cogl_matrix_stack_ortho (CoglMatrixStack *stack, + float left, + float right, + float bottom, + float top, + float z_near, + float z_far); +void _cogl_matrix_stack_get (CoglMatrixStack *stack, + CoglMatrix *matrix); +void _cogl_matrix_stack_set (CoglMatrixStack *stack, + const CoglMatrix *matrix); void _cogl_matrix_stack_flush_to_gl (CoglMatrixStack *stack, GLenum gl_mode); diff --git a/common/cogl-matrix.c b/common/cogl-matrix.c index 6b6f20fae..45f367d73 100644 --- a/common/cogl-matrix.c +++ b/common/cogl-matrix.c @@ -151,21 +151,6 @@ cogl_matrix_invert (CoglMatrix *matrix) } #endif -void -cogl_matrix_transform_point (const CoglMatrix *matrix, - float *x, - float *y, - float *z, - float *w) -{ - float _x = *x, _y = *y, _z = *z, _w = *w; - - *x = matrix->xx * _x + matrix->xy * _y + matrix->xz * _z + matrix->xw * _w; - *y = matrix->yx * _x + matrix->yy * _y + matrix->yz * _z + matrix->yw * _w; - *z = matrix->zx * _x + matrix->zy * _y + matrix->zz * _z + matrix->zw * _w; - *w = matrix->wx * _x + matrix->wy * _y + matrix->wz * _z + matrix->ww * _w; -} - void cogl_matrix_frustum (CoglMatrix *matrix, float left, @@ -208,6 +193,62 @@ cogl_matrix_frustum (CoglMatrix *matrix, cogl_matrix_multiply (matrix, matrix, &frustum); } +void +cogl_matrix_perspective (CoglMatrix *matrix, + float fov_y, + float aspect, + float z_near, + float z_far) +{ + float ymax = z_near * tan (fov_y * G_PI / 360.0); + + cogl_matrix_frustum (matrix, + -ymax * aspect, /* left */ + ymax * aspect, /* right */ + -ymax, /* bottom */ + ymax, /* top */ + z_near, + z_far); +} + +void +cogl_matrix_ortho (CoglMatrix *matrix, + float left, + float right, + float bottom, + float top, + float near, + float far) +{ + CoglMatrix ortho; + + /* column 0 */ + ortho.xx = 2.0 / (right - left); + ortho.yx = 0.0; + ortho.zx = 0.0; + ortho.wx = 0.0; + + /* column 1 */ + ortho.xy = 0.0; + ortho.yy = 2.0 / (top - bottom); + ortho.zy = 0.0; + ortho.wy = 0.0; + + /* column 2 */ + ortho.xz = 0.0; + ortho.yz = 0.0; + ortho.zz = -2.0 / (far - near); + ortho.wz = 0.0; + + /* column 3 */ + ortho.xw = -(right + left) / (right - left); + ortho.yw = -(top + bottom) / (top - bottom); + ortho.zw = -(far + near) / (far - near); + ortho.ww = 1.0; + + cogl_matrix_multiply (matrix, matrix, &ortho); +} + void cogl_matrix_init_from_array (CoglMatrix *matrix, const float *array) { @@ -220,3 +261,19 @@ cogl_matrix_get_array (const CoglMatrix *matrix) return (float *)matrix; } +void +cogl_matrix_transform_point (const CoglMatrix *matrix, + float *x, + float *y, + float *z, + float *w) +{ + float _x = *x, _y = *y, _z = *z, _w = *w; + + *x = matrix->xx * _x + matrix->xy * _y + matrix->xz * _z + matrix->xw * _w; + *y = matrix->yx * _x + matrix->yy * _y + matrix->yz * _z + matrix->yw * _w; + *z = matrix->zx * _x + matrix->zy * _y + matrix->zz * _z + matrix->zw * _w; + *w = matrix->wx * _x + matrix->wy * _y + matrix->wz * _z + matrix->ww * _w; +} + + diff --git a/common/cogl-primitives.c b/common/cogl-primitives.c index 224769ca2..598015521 100644 --- a/common/cogl-primitives.c +++ b/common/cogl-primitives.c @@ -29,7 +29,8 @@ #include "cogl-internal.h" #include "cogl-context.h" #include "cogl-texture-private.h" -#include "cogl-material.h" +#include "cogl-material-private.h" +#include "cogl-vertex-buffer-private.h" #include #include @@ -39,16 +40,8 @@ #ifdef HAVE_COGL_GL -#define glDrawRangeElements ctx->pf_glDrawRangeElements #define glClientActiveTexture ctx->pf_glClientActiveTexture -#else - -/* GLES doesn't have glDrawRangeElements, so we simply pretend it does - * but that it makes no use of the start, end constraints: */ -#define glDrawRangeElements(mode, start, end, count, type, indices) \ - glDrawElements (mode, count, type, indices) - #endif /* these are defined in the particular backend */ @@ -63,7 +56,6 @@ _cogl_journal_flush_quad_batch (CoglJournalEntry *batch_start, gint batch_len, GLfloat *vertex_pointer) { - int needed_indices; gsize stride; int i; gulong enable_flags = 0; @@ -72,35 +64,6 @@ _cogl_journal_flush_quad_batch (CoglJournalEntry *batch_start, _COGL_GET_CONTEXT (ctx, NO_RETVAL); - /* The indices are always the same sequence regardless of the vertices so we - * only need to change it if there are more vertices than ever before. */ - needed_indices = batch_len * 6; - if (needed_indices > ctx->static_indices->len) - { - int old_len = ctx->static_indices->len; - int vert_num = old_len / 6 * 4; - GLushort *q; - - /* Add two triangles for each quad to the list of - indices. That makes six new indices but two of the - vertices in the triangles are shared. */ - g_array_set_size (ctx->static_indices, needed_indices); - q = &g_array_index (ctx->static_indices, GLushort, old_len); - - for (i = old_len; - i < ctx->static_indices->len; - i += 6, vert_num += 4) - { - *(q++) = vert_num + 0; - *(q++) = vert_num + 1; - *(q++) = vert_num + 3; - - *(q++) = vert_num + 1; - *(q++) = vert_num + 2; - *(q++) = vert_num + 3; - } - } - /* XXX NB: * Our vertex data is arranged as follows: * 4 vertices per quad: 2 GLfloats per position, @@ -112,16 +75,16 @@ _cogl_journal_flush_quad_batch (CoglJournalEntry *batch_start, disable_mask = (1 << batch_start->n_layers) - 1; disable_mask = ~disable_mask; - cogl_material_flush_gl_state (ctx->source_material, - COGL_MATERIAL_FLUSH_FALLBACK_MASK, - batch_start->fallback_mask, - COGL_MATERIAL_FLUSH_DISABLE_MASK, - disable_mask, - /* Redundant when dealing with unsliced - * textures but does no harm... */ - COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE, - batch_start->layer0_override_texture, - NULL); + _cogl_material_flush_gl_state (ctx->source_material, + COGL_MATERIAL_FLUSH_FALLBACK_MASK, + batch_start->fallback_mask, + COGL_MATERIAL_FLUSH_DISABLE_MASK, + disable_mask, + /* Redundant when dealing with unsliced + * textures but does no harm... */ + COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE, + batch_start->layer0_override_texture, + NULL); for (i = 0; i < batch_start->n_layers; i++) { @@ -140,7 +103,7 @@ _cogl_journal_flush_quad_batch (CoglJournalEntry *batch_start, /* 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 (ctx->source_material); + enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material); if (ctx->enable_backface_culling) enable_flags |= COGL_ENABLE_BACKFACE_CULLING; @@ -150,12 +113,32 @@ _cogl_journal_flush_quad_batch (CoglJournalEntry *batch_start, GE (glVertexPointer (2, GL_FLOAT, stride, vertex_pointer)); _cogl_current_matrix_state_flush (); - GE (glDrawRangeElements (GL_TRIANGLES, - 0, ctx->static_indices->len - 1, - 6 * batch_len, - GL_UNSIGNED_SHORT, - ctx->static_indices->data)); +#ifdef HAVE_COGL_GL + + GE( glDrawArrays (GL_QUADS, 0, batch_len * 4) ); + +#else /* HAVE_COGL_GL */ + + /* GLES doesn't support GL_QUADS so we will use GL_TRIANGLES and + indices */ + { + int needed_indices = batch_len * 6; + CoglHandle indices_handle + = cogl_vertex_buffer_indices_get_for_quads (needed_indices); + CoglVertexBufferIndices *indices + = _cogl_vertex_buffer_indices_pointer_from_handle (indices_handle); + + GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, + GPOINTER_TO_UINT (indices->vbo_name))); + GE (glDrawElements (GL_TRIANGLES, + 6 * batch_len, + indices->type, + NULL)); + GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0)); + } + +#endif /* HAVE_COGL_GL */ /* DEBUGGING CODE XXX: * This path will cause all rectangles to be drawn with a red, green @@ -177,7 +160,7 @@ _cogl_journal_flush_quad_batch (CoglJournalEntry *batch_start, color == 1 ? 0xff : 0x00, color == 2 ? 0xff : 0x00, 0xff); - cogl_material_flush_gl_state (outline, NULL); + _cogl_material_flush_gl_state (outline, NULL); _cogl_current_matrix_state_flush (); GE( glDrawArrays (GL_LINE_LOOP, 4 * i, 4) ); } @@ -791,7 +774,7 @@ _cogl_rectangles_with_multitexture_coords ( /* We don't support multi texturing using textures with any waste if the * user has supplied a custom texture matrix, since we don't know if * the result will end up trying to texture from the waste area. */ - flags = cogl_material_layer_get_flags (layer); + flags = _cogl_material_layer_get_flags (layer); if (flags & COGL_MATERIAL_LAYER_FLAG_HAS_USER_MATRIX && _cogl_texture_span_has_waste (texture, 0, 0)) { @@ -1041,13 +1024,13 @@ _cogl_texture_sliced_polygon (CoglTextureVertex *vertices, v += stride; } - cogl_material_flush_gl_state (ctx->source_material, - COGL_MATERIAL_FLUSH_DISABLE_MASK, - (guint32)~1, /* disable all except the + _cogl_material_flush_gl_state (ctx->source_material, + COGL_MATERIAL_FLUSH_DISABLE_MASK, + (guint32)~1, /* disable all except the first layer */ - COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE, - gl_handle, - NULL); + COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE, + gl_handle, + NULL); _cogl_current_matrix_state_flush (); GE( glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices) ); @@ -1136,10 +1119,10 @@ _cogl_multitexture_unsliced_polygon (CoglTextureVertex *vertices, c[3] = cogl_color_get_alpha_float (&vertices[i].color); } - cogl_material_flush_gl_state (ctx->source_material, - COGL_MATERIAL_FLUSH_FALLBACK_MASK, - fallback_mask, - NULL); + _cogl_material_flush_gl_state (ctx->source_material, + COGL_MATERIAL_FLUSH_FALLBACK_MASK, + fallback_mask, + NULL); _cogl_current_matrix_state_flush (); GE (glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices)); @@ -1175,7 +1158,6 @@ cogl_polygon (CoglTextureVertex *vertices, { CoglHandle layer = (CoglHandle)tmp->data; CoglHandle tex_handle = cogl_material_layer_get_texture (layer); - CoglTexture *tex = _cogl_texture_pointer_from_handle (tex_handle); if (i == 0 && cogl_texture_is_sliced (tex_handle)) { @@ -1203,7 +1185,8 @@ cogl_polygon (CoglTextureVertex *vertices, use_sliced_polygon_fallback = TRUE; n_layers = 1; - if (tex->min_filter != GL_NEAREST || tex->mag_filter != GL_NEAREST) + if (cogl_material_layer_get_min_filter (layer) != GL_NEAREST + || cogl_material_layer_get_mag_filter (layer) != GL_NEAREST) { static gboolean warning_seen = FALSE; if (!warning_seen) @@ -1217,11 +1200,14 @@ cogl_polygon (CoglTextureVertex *vertices, } #ifdef HAVE_COGL_GL - /* Temporarily change the wrapping mode on all of the slices to use - * a transparent border - * XXX: it's doesn't look like we save/restore this, like the comment - * implies? */ - _cogl_texture_set_wrap_mode_parameter (tex, GL_CLAMP_TO_BORDER); + { + CoglTexture *tex = _cogl_texture_pointer_from_handle (tex_handle); + /* Temporarily change the wrapping mode on all of the slices to use + * a transparent border + * XXX: it's doesn't look like we save/restore this, like + * the comment implies? */ + _cogl_texture_set_wrap_mode_parameter (tex, GL_CLAMP_TO_BORDER); + } #endif break; } @@ -1254,7 +1240,7 @@ cogl_polygon (CoglTextureVertex *vertices, /* Prepare GL state */ enable_flags = COGL_ENABLE_VERTEX_ARRAY; - enable_flags |= cogl_material_get_cogl_enable_flags (ctx->source_material); + enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material); if (ctx->enable_backface_culling) enable_flags |= COGL_ENABLE_BACKFACE_CULLING; diff --git a/common/cogl-util.c b/common/cogl-util.c index d71b9ffd8..2d86f73f3 100644 --- a/common/cogl-util.c +++ b/common/cogl-util.c @@ -103,159 +103,6 @@ cogl_handle_get_type (void) return our_type; } -GType -cogl_pixel_format_get_type (void) -{ - static GType gtype = 0; - - if (G_UNLIKELY (gtype == 0)) - { - static const GEnumValue values[] = { - { COGL_PIXEL_FORMAT_ANY, "COGL_PIXEL_FORMAT_ANY", "any" }, - { COGL_PIXEL_FORMAT_A_8, "COGL_PIXEL_FORMAT_A_8", "a-8" }, - { COGL_PIXEL_FORMAT_RGB_565, "COGL_PIXEL_FORMAT_RGB_565", "rgb-565" }, - { COGL_PIXEL_FORMAT_RGBA_4444, "COGL_PIXEL_FORMAT_RGBA_4444", "rgba-4444" }, - { COGL_PIXEL_FORMAT_RGBA_5551, "COGL_PIXEL_FORMAT_RGBA_5551", "rgba-5551" }, - { COGL_PIXEL_FORMAT_YUV, "COGL_PIXEL_FORMAT_YUV", "yuv" }, - { COGL_PIXEL_FORMAT_G_8, "COGL_PIXEL_FORMAT_G_8", "g-8" }, - { COGL_PIXEL_FORMAT_RGB_888, "COGL_PIXEL_FORMAT_RGB_888", "rgb-888" }, - { COGL_PIXEL_FORMAT_BGR_888, "COGL_PIXEL_FORMAT_BGR_888", "bgr-888" }, - { COGL_PIXEL_FORMAT_RGBA_8888, "COGL_PIXEL_FORMAT_RGBA_8888", "rgba-8888" }, - { COGL_PIXEL_FORMAT_BGRA_8888, "COGL_PIXEL_FORMAT_BGRA_8888", "bgra-8888" }, - { COGL_PIXEL_FORMAT_ARGB_8888, "COGL_PIXEL_FORMAT_ARGB_8888", "argb-8888" }, - { COGL_PIXEL_FORMAT_ABGR_8888, "COGL_PIXEL_FORMAT_ABGR_8888", "abgr-8888" }, - { COGL_PIXEL_FORMAT_RGBA_8888_PRE, "COGL_PIXEL_FORMAT_RGBA_8888_PRE", "rgba-8888-pre" }, - { COGL_PIXEL_FORMAT_BGRA_8888_PRE, "COGL_PIXEL_FORMAT_BGRA_8888_PRE", "bgra-8888-pre" }, - { COGL_PIXEL_FORMAT_ARGB_8888_PRE, "COGL_PIXEL_FORMAT_ARGB_8888_PRE", "argb-8888-pre" }, - { COGL_PIXEL_FORMAT_ABGR_8888_PRE, "COGL_PIXEL_FORMAT_ABGR_8888_PRE", "abgr-8888-pre" }, - { COGL_PIXEL_FORMAT_RGBA_4444_PRE, "COGL_PIXEL_FORMAT_RGBA_4444_PRE", "rgba-4444-pre" }, - { COGL_PIXEL_FORMAT_RGBA_5551_PRE, "COGL_PIXEL_FORMAT_RGBA_5551_PRE", "rgba-5551-pre" }, - { 0, NULL, NULL } - }; - - gtype = - g_enum_register_static (g_intern_static_string ("CoglPixelFormat"), - values); - } - - return gtype; -} - -GType -cogl_feature_flags_get_type (void) -{ - static GType gtype = 0; - - if (G_UNLIKELY (gtype == 0)) - { - static const GFlagsValue values[] = { - { COGL_FEATURE_TEXTURE_RECTANGLE, "COGL_FEATURE_TEXTURE_RECTANGLE", "texture-rectangle" }, - { COGL_FEATURE_TEXTURE_NPOT, "COGL_FEATURE_TEXTURE_NPOT", "texture-npot" }, - { COGL_FEATURE_TEXTURE_YUV, "COGL_FEATURE_TEXTURE_YUV", "yuv" }, - { COGL_FEATURE_TEXTURE_READ_PIXELS, "COGL_FEATURE_TEXTURE_READ_PIXELS", "read-pixels" }, - { COGL_FEATURE_SHADERS_GLSL, "COGL_FEATURE_SHADERS_GLSL", "shaders-glsl" }, - { COGL_FEATURE_OFFSCREEN, "COGL_FEATURE_OFFSCREEN", "offscreen" }, - { COGL_FEATURE_OFFSCREEN_MULTISAMPLE, "COGL_FEATURE_OFFSCREEN_MULTISAMPLE", "offscreen-multisample" }, - { COGL_FEATURE_OFFSCREEN_BLIT, "COGL_FEATURE_OFFSCREEN_BLIT", "offscreen-blit" }, - { COGL_FEATURE_FOUR_CLIP_PLANES, "COGL_FEATURE_FOUR_CLIP_PLANES", "four-clip-planes" }, - { COGL_FEATURE_STENCIL_BUFFER, "COGL_FEATURE_STENCIL_BUFFER", "stencil-buffer" }, - { 0, NULL, NULL } - }; - - gtype = - g_flags_register_static (g_intern_static_string ("CoglFeatureFlags"), - values); - } - - return gtype; -} - -GType -cogl_buffer_target_get_type (void) -{ - static GType gtype = 0; - - if (G_UNLIKELY (gtype == 0)) - { - static const GFlagsValue values[] = { - { COGL_WINDOW_BUFFER, "COGL_WINDOW_BUFFER", "window-buffer" }, - { COGL_OFFSCREEN_BUFFER, "COGL_OFFSCREEN_BUFFER", "offscreen-buffer" }, - { 0, NULL, NULL } - }; - - gtype = - g_flags_register_static (g_intern_static_string ("CoglBufferTarget"), - values); - } - - return gtype; -} - -GType -cogl_matrix_mode_get_type (void) -{ - static GType gtype = 0; - - if (G_UNLIKELY (gtype == 0)) - { - static const GEnumValue values[] = { - { COGL_MATRIX_MODELVIEW, "COGL_MATRIX_MODELVIEW", "modelview" }, - { COGL_MATRIX_PROJECTION, "COGL_MATRIX_PROJECTION", "projection" }, - { COGL_MATRIX_TEXTURE, "COGL_MATRIX_TEXTURE", "texture" }, - { 0, NULL, NULL } - }; - - gtype = - g_enum_register_static (g_intern_static_string ("CoglMatrixMode"), - values); - } - - return gtype; -} - -GType -cogl_texture_flags_get_type (void) -{ - static GType gtype = 0; - - if (G_UNLIKELY (gtype == 0)) - { - static const GFlagsValue values[] = { - { COGL_TEXTURE_NONE, "COGL_TEXTURE_NONE", "none" }, - { COGL_TEXTURE_AUTO_MIPMAP, "COGL_TEXTURE_AUTO_MIPMAP", "auto-mipmap" }, - { 0, NULL, NULL } - }; - - gtype = - g_flags_register_static (g_intern_static_string ("CoglTextureFlags"), - values); - } - - return gtype; -} - -GType -cogl_fog_mode_get_type (void) -{ - static GType gtype = 0; - - if (G_UNLIKELY (gtype == 0)) - { - static const GEnumValue values[] = { - { COGL_FOG_MODE_LINEAR, "COGL_FOG_MODE_LINEAR", "linear" }, - { COGL_FOG_MODE_EXPONENTIAL, "COGL_FOG_MODE_EXPONENTIAL", "exponential" }, - { COGL_FOG_MODE_EXPONENTIAL_SQUARED, "COGL_FOG_MODE_EXPONENTIAL_SQUARED", "exponential-squared" }, - { 0, NULL, NULL } - }; - - gtype = - g_enum_register_static (g_intern_static_string ("CoglFogMode"), - values); - } - - return gtype; -} - /* * CoglFixed */ diff --git a/common/cogl-vertex-buffer-private.h b/common/cogl-vertex-buffer-private.h index 68a709b54..558765303 100644 --- a/common/cogl-vertex-buffer-private.h +++ b/common/cogl-vertex-buffer-private.h @@ -99,9 +99,9 @@ typedef struct _CoglVertexBufferAttrib union _u { const void *pointer; - gsize vbo_offset; + size_t vbo_offset; } u; - gsize span_bytes; + size_t span_bytes; guint16 stride; guint8 n_components; guint8 texture_unit; @@ -129,25 +129,41 @@ typedef struct _CoglVertexBufferVBO { CoglVertexBufferVBOFlags flags; - /* Note: this is a pointer to handle fallbacks, and normally holds - * a GLuint value */ - gpointer vbo_name; /*!< The name of the corresponding buffer object */ - gsize vbo_bytes; /*!< The lengh of the allocated buffer object in bytes */ + /* Note: this is a pointer to handle fallbacks. It normally holds + * a GLuint VBO name, but when the driver doesn't support VBOs then + * this simply points to an malloc'd buffer. */ + void *vbo_name; /*!< The name of the corresponding buffer object */ + size_t vbo_bytes; /*!< The lengh of the allocated buffer object in bytes */ GList *attributes; } CoglVertexBufferVBO; +typedef struct _CoglVertexBufferIndices +{ + CoglHandleObject _parent; + + /* Note: this is a pointer to handle fallbacks. It normally holds + * a GLuint VBO name, but when the driver doesn't support VBOs then + * this simply points to an malloc'd buffer. */ + void *vbo_name; + GLenum type; +} CoglVertexBufferIndices; typedef struct _CoglVertexBuffer { CoglHandleObject _parent; - guint n_vertices; /*!< The number of vertices in the buffer */ - GList *submitted_vbos; /* The VBOs currently submitted to the GPU */ + int n_vertices; /*!< The number of vertices in the buffer */ + GList *submitted_vbos; /* The VBOs currently submitted to the GPU */ /* Note: new_attributes is normally NULL and only valid while * modifying a buffer. */ - GList *new_attributes; /*!< attributes pending submission */ + GList *new_attributes; /*!< attributes pending submission */ + } CoglVertexBuffer; +CoglVertexBuffer *_cogl_vertex_buffer_pointer_from_handle (CoglHandle handle); +CoglVertexBufferIndices * + _cogl_vertex_buffer_indices_pointer_from_handle (CoglHandle handle); + #endif /* __COGL_VERTEX_BUFFER_H */ diff --git a/common/cogl-vertex-buffer.c b/common/cogl-vertex-buffer.c index f6fa6ba89..a36bb1cec 100644 --- a/common/cogl-vertex-buffer.c +++ b/common/cogl-vertex-buffer.c @@ -136,6 +136,7 @@ #include "cogl-handle.h" #include "cogl-vertex-buffer-private.h" #include "cogl-texture-private.h" +#include "cogl-material-private.h" #define PAD_FOR_ALIGNMENT(VAR, TYPE_SIZE) \ (VAR = TYPE_SIZE + ((VAR - 1) & ~(TYPE_SIZE - 1))) @@ -200,8 +201,10 @@ #endif /* HAVE_COGL_GL */ static void _cogl_vertex_buffer_free (CoglVertexBuffer *buffer); +static void _cogl_vertex_buffer_indices_free (CoglVertexBufferIndices *buffer_indices); COGL_HANDLE_DEFINE (VertexBuffer, vertex_buffer); +COGL_HANDLE_DEFINE (VertexBufferIndices, vertex_buffer_indices); CoglHandle cogl_vertex_buffer_new (guint n_vertices) @@ -411,13 +414,13 @@ get_gl_type_size (CoglVertexBufferAttribFlags flags) } void -cogl_vertex_buffer_add (CoglHandle handle, - const char *attribute_name, - guint8 n_components, - GLenum gl_type, - gboolean normalized, - guint16 stride, - const void *pointer) +cogl_vertex_buffer_add (CoglHandle handle, + const char *attribute_name, + guint8 n_components, + CoglAttributeType type, + gboolean normalized, + guint16 stride, + const void *pointer) { CoglVertexBuffer *buffer; GQuark name_quark = g_quark_from_string (attribute_name); @@ -485,7 +488,7 @@ cogl_vertex_buffer_add (CoglHandle handle, attribute->u.pointer = pointer; attribute->texture_unit = texture_unit; - flags |= get_attribute_gl_type_flag_from_gl_type (gl_type); + flags |= get_attribute_gl_type_flag_from_gl_type (type); flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_ENABLED; /* Note: We currently just assume, if an attribute is *ever* updated @@ -1638,14 +1641,14 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer) } } - cogl_material_flush_gl_state (ctx->source_material, - COGL_MATERIAL_FLUSH_FALLBACK_MASK, - fallback_mask, - COGL_MATERIAL_FLUSH_DISABLE_MASK, - disable_mask, - NULL); + _cogl_material_flush_gl_state (ctx->source_material, + COGL_MATERIAL_FLUSH_FALLBACK_MASK, + fallback_mask, + COGL_MATERIAL_FLUSH_DISABLE_MASK, + disable_mask, + NULL); - enable_flags |= cogl_material_get_cogl_enable_flags (ctx->source_material); + enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material); if (ctx->enable_backface_culling) enable_flags |= COGL_ENABLE_BACKFACE_CULLING; @@ -1716,23 +1719,21 @@ disable_state_for_drawing_buffer (CoglVertexBuffer *buffer) } void -cogl_vertex_buffer_draw (CoglHandle handle, - GLenum mode, - GLint first, - GLsizei count) +cogl_vertex_buffer_draw (CoglHandle handle, + CoglVerticesMode mode, + int first, + int count) { CoglVertexBuffer *buffer; if (!cogl_is_vertex_buffer (handle)) return; - cogl_clip_ensure (); - buffer = _cogl_vertex_buffer_pointer_from_handle (handle); - enable_state_for_drawing_buffer (buffer); - + cogl_clip_ensure (); _cogl_current_matrix_state_flush (); + enable_state_for_drawing_buffer (buffer); /* FIXME: flush cogl cache */ GE (glDrawArrays (mode, first, count)); @@ -1740,35 +1741,127 @@ cogl_vertex_buffer_draw (CoglHandle handle, disable_state_for_drawing_buffer (buffer); } +static int +get_indices_type_size (GLuint indices_type) +{ + if (indices_type == GL_UNSIGNED_BYTE) + return sizeof (GLubyte); + if (indices_type == GL_UNSIGNED_SHORT) + return sizeof (GLushort); + else + { + g_critical ("Unknown indices type %d\n", indices_type); + return 0; + } +} + +CoglHandle +cogl_vertex_buffer_indices_new (CoglIndicesType indices_type, + const void *indices_array, + int indices_len) +{ + gboolean fallback = + (cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE; + size_t indices_bytes; + CoglVertexBufferIndices *indices; + + _COGL_GET_CONTEXT (ctx, 0); + + indices = g_slice_alloc (sizeof (CoglVertexBufferIndices)); + + if (indices_type == COGL_INDICES_TYPE_UNSIGNED_BYTE) + indices->type = GL_UNSIGNED_BYTE; + else if (indices_type == COGL_INDICES_TYPE_UNSIGNED_SHORT) + indices->type = GL_UNSIGNED_SHORT; + else + { + g_critical ("unknown indices type %d", indices_type); + g_slice_free (CoglVertexBufferIndices, indices); + return 0; + } + + indices_bytes = get_indices_type_size (indices->type) * indices_len; + if (fallback) + { + indices->vbo_name = g_malloc (indices_len); + memcpy (indices->vbo_name, indices_array, indices_bytes); + } + else + { + GE (glGenBuffers (1, (GLuint *)&indices->vbo_name)); + GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, + GPOINTER_TO_UINT (indices->vbo_name))); + GE (glBufferData (GL_ELEMENT_ARRAY_BUFFER, + indices_bytes, + indices_array, + GL_STATIC_DRAW)); + GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0)); + } + + return _cogl_vertex_buffer_indices_handle_new (indices); +} + void -cogl_vertex_buffer_draw_elements (CoglHandle handle, - GLenum mode, - GLuint min_index, - GLuint max_index, - GLsizei count, - GLenum indices_type, - const GLvoid *indices) +_cogl_vertex_buffer_indices_free (CoglVertexBufferIndices *indices) +{ + gboolean fallback = + (cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + if (fallback) + g_free (indices->vbo_name); + else + GE (glDeleteBuffers (1, (GLuint *)&indices->vbo_name)); + + g_slice_free (CoglVertexBufferIndices, indices); +} + +void +cogl_vertex_buffer_draw_elements (CoglHandle handle, + CoglVerticesMode mode, + CoglHandle indices_handle, + int min_index, + int max_index, + int indices_offset, + int count) { CoglVertexBuffer *buffer; + gboolean fallback = + (cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE; + size_t byte_offset; + CoglVertexBufferIndices *indices = NULL; _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (!cogl_is_vertex_buffer (handle)) return; - cogl_clip_ensure (); - buffer = _cogl_vertex_buffer_pointer_from_handle (handle); + if (!cogl_is_vertex_buffer_indices (indices_handle)) + return; + + indices = _cogl_vertex_buffer_indices_pointer_from_handle (indices_handle); + + cogl_clip_ensure (); + _cogl_current_matrix_state_flush (); enable_state_for_drawing_buffer (buffer); - _cogl_current_matrix_state_flush (); + byte_offset = indices_offset * get_indices_type_size (indices->type); + if (fallback) + byte_offset = (size_t)(((char *)indices->vbo_name) + byte_offset); + else + GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, + GPOINTER_TO_UINT (indices->vbo_name))); /* FIXME: flush cogl cache */ GE (glDrawRangeElements (mode, min_index, max_index, - count, indices_type, indices)); + count, indices->type, (void *)byte_offset)); disable_state_for_drawing_buffer (buffer); + + GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0)); } static void @@ -1778,8 +1871,92 @@ _cogl_vertex_buffer_free (CoglVertexBuffer *buffer) for (tmp = buffer->submitted_vbos; tmp != NULL; tmp = tmp->next) cogl_vertex_buffer_vbo_free (tmp->data, TRUE); + g_list_free (buffer->submitted_vbos); + for (tmp = buffer->new_attributes; tmp != NULL; tmp = tmp->next) cogl_vertex_buffer_attribute_free (tmp->data); + g_list_free (buffer->new_attributes); g_slice_free (CoglVertexBuffer, buffer); } + +CoglHandle +cogl_vertex_buffer_indices_get_for_quads (guint n_indices) +{ + _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE); + + /* Check if the indices would fit in a byte array */ + if (n_indices <= 256 / 4 * 6) + { + /* Generate the byte array if we haven't already */ + if (ctx->quad_indices_byte == COGL_INVALID_HANDLE) + { + guint8 *byte_array = g_malloc (256 / 4 * 6 * sizeof (guint8)); + guint8 *p = byte_array; + int i, vert_num = 0; + + for (i = 0; i < 256 / 4; i++) + { + *(p++) = vert_num + 0; + *(p++) = vert_num + 1; + *(p++) = vert_num + 2; + *(p++) = vert_num + 0; + *(p++) = vert_num + 2; + *(p++) = vert_num + 3; + vert_num += 4; + } + + ctx->quad_indices_byte + = cogl_vertex_buffer_indices_new (COGL_INDICES_TYPE_UNSIGNED_BYTE, + byte_array, + 256 / 4 * 6); + + g_free (byte_array); + } + + return ctx->quad_indices_byte; + } + else + { + if (ctx->quad_indices_short_len < n_indices) + { + guint16 *short_array; + guint16 *p; + int i, vert_num = 0; + + if (ctx->quad_indices_short != COGL_INVALID_HANDLE) + cogl_handle_unref (ctx->quad_indices_short); + /* Pick a power of two >= MAX (512, n_indices) */ + if (ctx->quad_indices_short_len == 0) + ctx->quad_indices_short_len = 512; + while (ctx->quad_indices_short_len < n_indices) + ctx->quad_indices_short_len *= 2; + + /* Over-allocate to generate a whole number of quads */ + p = short_array = g_malloc ((ctx->quad_indices_short_len + + 5) / 6 * 6 + * sizeof (guint16)); + + /* Fill in the complete quads */ + for (i = 0; i < ctx->quad_indices_short_len; i += 6) + { + *(p++) = vert_num + 0; + *(p++) = vert_num + 1; + *(p++) = vert_num + 2; + *(p++) = vert_num + 0; + *(p++) = vert_num + 2; + *(p++) = vert_num + 3; + vert_num += 4; + } + + ctx->quad_indices_short + = cogl_vertex_buffer_indices_new (COGL_INDICES_TYPE_UNSIGNED_SHORT, + short_array, + ctx->quad_indices_short_len); + + g_free (short_array); + } + + return ctx->quad_indices_short; + } +} diff --git a/common/cogl.c b/common/cogl.c index 2495d8172..336303917 100644 --- a/common/cogl.c +++ b/common/cogl.c @@ -42,6 +42,7 @@ typedef CoglFuncPtr (*GLXGetProcAddressProc) (const guint8 *procName); #include "cogl-internal.h" #include "cogl-util.h" #include "cogl-context.h" +#include "cogl-material-private.h" #if defined (HAVE_COGL_GLES2) || defined (HAVE_COGL_GLES) #include "cogl-gles2-wrapper.h" @@ -213,30 +214,39 @@ cogl_get_enable () } void -cogl_enable_depth_test (gboolean setting) +cogl_set_depth_test_enabled (gboolean setting) { if (setting) { glEnable (GL_DEPTH_TEST); - glEnable (GL_ALPHA_TEST); glDepthFunc (GL_LEQUAL); - glAlphaFunc (GL_GREATER, 0.1); } else - { - glDisable (GL_DEPTH_TEST); - glDisable (GL_ALPHA_TEST); - } + glDisable (GL_DEPTH_TEST); +} + +gboolean +cogl_get_depth_test_enabled (void) +{ + return glIsEnabled (GL_DEPTH_TEST) == GL_TRUE ? TRUE : FALSE; } void -cogl_enable_backface_culling (gboolean setting) +cogl_set_backface_culling_enabled (gboolean setting) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); ctx->enable_backface_culling = setting; } +gboolean +cogl_get_backface_culling_enabled (void) +{ + _COGL_GET_CONTEXT (ctx, FALSE); + + return ctx->enable_backface_culling; +} + void cogl_set_source_color (const CoglColor *color) { @@ -375,7 +385,7 @@ _cogl_add_stencil_clip (float x_offset, { _COGL_GET_CONTEXT (ctx, NO_RETVAL); - cogl_material_flush_gl_state (ctx->stencil_material, NULL); + _cogl_material_flush_gl_state (ctx->stencil_material, NULL); if (first) { @@ -465,12 +475,12 @@ cogl_viewport (guint width, } void -cogl_setup_viewport (guint width, - guint height, - float fovy, - float aspect, - float z_near, - float z_far) +_cogl_setup_viewport (guint width, + guint height, + float fovy, + float aspect, + float z_near, + float z_far) { float z_camera; CoglMatrix projection_matrix; @@ -478,7 +488,7 @@ cogl_setup_viewport (guint width, GE( glViewport (0, 0, width, height) ); /* For Ortho projection. - * _cogl_current_matrix_ortho (0, width << 16, 0, height << 16, -1 << 16, 1 << 16); + * _cogl_current_matrix_ortho (0, width, 0, height, -1, 1); */ cogl_perspective (fovy, aspect, z_near, z_far); @@ -532,7 +542,7 @@ cogl_setup_viewport (guint width, } CoglFeatureFlags -cogl_get_features () +cogl_get_features (void) { _COGL_GET_CONTEXT (ctx, 0); @@ -653,9 +663,11 @@ cogl_disable_fog (void) glDisable (GL_FOG); } +#if 0 void cogl_flush_gl_state (int flags) { _cogl_current_matrix_state_flush (); } +#endif diff --git a/doc/reference/cogl/Makefile.am b/doc/reference/cogl/Makefile.am index 82b96928f..9888caaa3 100644 --- a/doc/reference/cogl/Makefile.am +++ b/doc/reference/cogl/Makefile.am @@ -24,7 +24,7 @@ DOC_SOURCE_DIR=../../../clutter/cogl SCANGOBJ_OPTIONS=--type-init-func="g_type_init()" # Extra options to supply to gtkdoc-scan. -# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" +# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" SCAN_OPTIONS=--deprecated-guards="COGL_DISABLE_DEPRECATED" # Extra options to supply to gtkdoc-mkdb. @@ -70,12 +70,14 @@ HTML_IMAGES= # Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). # e.g. content_files=running.sgml building.sgml changes-2.0.sgml -content_files= version.xml +content_files = \ + blend-strings.xml # SGML files where gtk-doc abbrevations (#GtkWidget) are expanded # These files must be listed here *and* in content_files # e.g. expand_content_files=running.sgml -expand_content_files= +expand_content_files = \ + blend-strings.xml # CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library. # Only needed if you are using gtkdoc-scangobj to dynamically query widget @@ -91,4 +93,3 @@ include $(top_srcdir)/gtk-doc.make # Other files to distribute # e.g. EXTRA_DIST += version.xml.in -EXTRA_DIST += version.xml.in diff --git a/doc/reference/cogl/blend-strings.xml b/doc/reference/cogl/blend-strings.xml new file mode 100644 index 000000000..9c3c8d3c9 --- /dev/null +++ b/doc/reference/cogl/blend-strings.xml @@ -0,0 +1,130 @@ + + +]> + + + +Material Blend Strings +3 +COGL Library + + + +Material Blend Strings +A simple syntax and grammar for describing blending and texture +combining functions. + + + +Cogl Blend Strings + +Describing GPU blending and texture combining states is rather awkward to do +in a consise but also readable fashion. Cogl helps by supporting +string based descriptions using a simple syntax. + + +
+Some examples + +Here is an example used for blending: + +"RGBA = ADD (SRC_COLOR * (SRC_COLOR[A]), DST_COLOR * (1-SRC_COLOR[A]))" + +In OpenGL terms this replaces glBlendFunc[Separate] and +glBlendEquation[Separate] + +Actually in this case it's more verbose than the GL equivalent: + + +glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + +But unless you are familiar with OpenGL or refer to its API documentation +you wouldn't know that the default function used by OpenGL is GL_FUNC_ADD +nor would you know that the above arguments determine what the source color +and destination color will be multiplied by before being adding. + + +Here is an example used for texture combining: + +"RGB = REPLACE (PREVIOUS)" +"A = MODULATE (PREVIOUS, TEXTURE)" + + +In OpenGL terms this replaces glTexEnv, and the above example is equivalent +to this OpenGL code: + + + glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE); + glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); + glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); + glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); + glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); + glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); + glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); + glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE); + glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); + + +
+ +
+Here's the syntax + + +<statement>: + <channel-mask>=<function-name>(<arg-list>) + + You can either use a single statement with an RGBA channel-mask or you can use + two statements; one with an A channel-mask and the other with an RGB + channel-mask. + +<channel-mask>: + A or RGB or RGBA + +<function-name>: + [A-Za-z_]* + +<arg-list>: + <arg>,<arg> + or <arg> + or "" + + I.e. functions may take 0 or more arguments + +<arg>: + <color-source> + 1 - <color-source> : Only intended for texture combining + <color-source> * ( <factor> ) : Only intended for blending + 0 : Only intended for blending + + See the blending or texture combining sections for further notes and examples. + +<color-source>: + <source-name>[<channel-mask>] + <source-name> + + See the blending or texture combining sections for the list of source-names + valid in each context. + + If a channel mask is not given then the channel mask of the statement + is assumed instead. + +<factor>: + 0 + 1 + <color-source> + 1-<color-source> + SRC_ALPHA_SATURATE + + +
+ + +
+ + +
diff --git a/doc/reference/cogl/cogl-docs.xml b/doc/reference/cogl/cogl-docs.xml.in similarity index 97% rename from doc/reference/cogl/cogl-docs.xml rename to doc/reference/cogl/cogl-docs.xml.in index ba5d2cf89..7f9c1c26b 100644 --- a/doc/reference/cogl/cogl-docs.xml +++ b/doc/reference/cogl/cogl-docs.xml.in @@ -1,7 +1,7 @@ + ]> @@ -55,6 +55,7 @@ + diff --git a/doc/reference/cogl/cogl-sections.txt b/doc/reference/cogl/cogl-sections.txt index 3032a6863..872e02d11 100644 --- a/doc/reference/cogl/cogl-sections.txt +++ b/doc/reference/cogl/cogl-sections.txt @@ -15,33 +15,35 @@ COGL_UNPREMULT_MASK CoglPixelFormat CoglBufferTarget -cogl_create_context -cogl_destroy_context - CoglFeatureFlags cogl_get_features cogl_features_available cogl_check_extension cogl_get_proc_address -cogl_perspective -cogl_frustum -cogl_setup_viewport -cogl_viewport -cogl_get_modelview_matrix -cogl_get_projection_matrix -cogl_get_viewport - cogl_push_matrix cogl_pop_matrix cogl_scale cogl_translate cogl_rotate +cogl_frustum +cogl_perspective +cogl_ortho + +cogl_get_modelview_matrix +cogl_set_modelview_matrix +cogl_get_projection_matrix +cogl_set_projection_matrix +cogl_viewport +cogl_setup_viewport +cogl_get_viewport cogl_clear cogl_get_bitmasks -cogl_enable_depth_test -cogl_enable_backface_culling +cogl_set_depth_test_enabled +cogl_get_depth_test_enabled +cogl_set_backface_culling_enabled +cogl_get_backface_culling_enabled CoglFogMode cogl_set_fog @@ -130,12 +132,9 @@ cogl_texture_get_height cogl_texture_get_format cogl_texture_get_rowstride cogl_texture_get_max_waste -cogl_texture_get_min_filter -cogl_texture_get_mag_filter cogl_texture_is_sliced cogl_texture_get_gl_texture cogl_texture_get_data -cogl_texture_set_filters cogl_texture_set_region @@ -307,7 +306,11 @@ cogl_vertex_buffer_submit cogl_vertex_buffer_disable cogl_vertex_buffer_enable cogl_vertex_buffer_draw +CoglIndicesType +cogl_vertex_buffer_add_indices +cogl_vertex_buffer_delete_indices cogl_vertex_buffer_draw_elements +cogl_vertex_buffer_indices_get_for_quads CoglVertexBufferAttribFlags COGL_VERTEX_BUFFER_ATTRIB_FLAG_GL_TYPE_MASK @@ -349,41 +352,35 @@ cogl_material_set_specular cogl_material_get_specular cogl_material_set_shininess cogl_material_get_shininess - CoglMaterialAlphaFunc cogl_material_set_alpha_test_function CoglMaterialBlendFactor -cogl_material_set_blend_factors +cogl_material_set_blend +cogl_material_set_blend_constant cogl_material_set_layer cogl_material_remove_layer -CoglMaterialLayerCombineFunc -cogl_material_set_layer_combine_function -CoglMaterialLayerCombineChannels -CoglMaterialLayerCombineSrc -cogl_material_set_layer_combine_arg_src -CoglMaterialLayerCombineOp -cogl_material_set_layer_combine_arg_op +cogl_material_set_layer_combine +cogl_material_set_layer_combine_constant cogl_material_set_layer_matrix +cogl_material_get_layers +CoglMaterialFilter +cogl_material_set_layer_filters +cogl_material_layer_get_type +cogl_material_layer_get_texture +cogl_material_layer_get_min_filter +cogl_material_layer_get_mag_filter CoglMaterial CoglMaterialFlags CoglMaterialLayerPrivFlags -cogl_material_set_layer_alpha_combine -cogl_material_set_layer_rgb_combine
cogl-material-internals Material Internals -cogl_material_get_cogl_enable_flags -CoglMaterialFlushOption -cogl_material_flush_gl_state CoglMaterialLayer cogl_material_get_layers CoglMaterialLayerType cogl_material_layer_get_type -CoglMaterialLayerFlags -cogl_material_layer_get_flags cogl_material_layer_get_texture -cogl_material_layer_flush_gl_sampler_state
diff --git a/doc/reference/cogl/version.xml.in b/doc/reference/cogl/version.xml.in deleted file mode 100644 index 7fc1bf340..000000000 --- a/doc/reference/cogl/version.xml.in +++ /dev/null @@ -1 +0,0 @@ -@CLUTTER_VERSION@ \ No newline at end of file diff --git a/gl/Makefile.am b/gl/Makefile.am index 367f674f2..1aab5b649 100644 --- a/gl/Makefile.am +++ b/gl/Makefile.am @@ -35,11 +35,6 @@ cogl_sources = \ cogl-context.c \ $(NULL) -coglincludedir = $(includedir)/clutter-@CLUTTER_API_VERSION@/cogl -coglinclude_HEADERS = \ - $(cogl_headers) \ - $(top_builddir)/clutter/cogl/cogl.h - INCLUDES = \ -I$(top_srcdir)/clutter/cogl \ -I$(top_srcdir)/clutter/cogl/common \ @@ -50,12 +45,12 @@ INCLUDES = \ -DG_LOG_DOMAIN=\"Cogl-GL\" \ -DCLUTTER_COMPILATION -noinst_LTLIBRARIES = libclutter-cogl.la +noinst_LTLIBRARIES = libclutter-cogl-gl.la -libclutter_cogl_la_CPPFLAGS = $(CLUTTER_CFLAGS) $(COGL_DEBUG_CFLAGS) $(CLUTTER_DEBUG_CFLAGS) $(MAINTAINER_CFLAGS) -libclutter_cogl_la_LIBADD = -lm $(CLUTTER_LIBS) $(top_builddir)/clutter/cogl/common/libclutter-cogl-common.la -libclutter_cogl_la_DEPENDENCIES = $(top_builddir)/clutter/cogl/common/libclutter-cogl-common.la -libclutter_cogl_la_SOURCES = \ +libclutter_cogl_gl_la_CPPFLAGS = $(CLUTTER_CFLAGS) $(COGL_DEBUG_CFLAGS) $(CLUTTER_DEBUG_CFLAGS) $(MAINTAINER_CFLAGS) +libclutter_cogl_gl_la_LIBADD = -lm $(CLUTTER_LIBS) $(top_builddir)/clutter/cogl/common/libclutter-cogl-common.la +libclutter_cogl_gl_la_DEPENDENCIES = $(top_builddir)/clutter/cogl/common/libclutter-cogl-common.la +libclutter_cogl_gl_la_SOURCES = \ $(top_builddir)/clutter/cogl/cogl.h \ $(cogl_headers) \ $(cogl_priv_headers) \ diff --git a/gl/cogl-context.c b/gl/cogl-context.c index 986da8aa8..201e05db7 100644 --- a/gl/cogl-context.c +++ b/gl/cogl-context.c @@ -37,7 +37,7 @@ static CoglContext *_context = NULL; static gboolean gl_is_indirect = FALSE; -gboolean +static gboolean cogl_create_context () { GLubyte default_texture_data[] = { 0xff, 0xff, 0xff, 0x0 }; @@ -69,7 +69,6 @@ cogl_create_context () _context->journal = g_array_new (FALSE, FALSE, sizeof (CoglJournalEntry)); _context->logged_vertices = g_array_new (FALSE, FALSE, sizeof (GLfloat)); - _context->static_indices = g_array_new (FALSE, FALSE, sizeof (GLushort)); _context->polygon_vertices = g_array_new (FALSE, FALSE, sizeof (CoglTextureGLVertex)); @@ -136,6 +135,9 @@ cogl_create_context () _context->pf_glActiveTexture = NULL; _context->pf_glClientActiveTexture = NULL; + _context->pf_glBlendFuncSeparate = NULL; + _context->pf_glBlendEquationSeparate = NULL; + /* Initialise the clip stack */ _cogl_clip_stack_state_init (); @@ -146,8 +148,7 @@ cogl_create_context () _context->default_gl_texture_2d_tex = cogl_texture_new_from_data (1, /* width */ 1, /* height */ - -1, /* max waste */ - COGL_TEXTURE_NONE, /* flags */ + COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_RGBA_8888, /* data format */ /* internal format */ COGL_PIXEL_FORMAT_RGBA_8888, @@ -156,8 +157,7 @@ cogl_create_context () _context->default_gl_texture_rect_tex = cogl_texture_new_from_data (1, /* width */ 1, /* height */ - -1, /* max waste */ - COGL_TEXTURE_NONE, /* flags */ + COGL_TEXTURE_NO_SLICING, COGL_PIXEL_FORMAT_RGBA_8888, /* data format */ /* internal format */ COGL_PIXEL_FORMAT_RGBA_8888, @@ -165,16 +165,20 @@ cogl_create_context () default_texture_data); cogl_set_source (_context->default_material); - cogl_material_flush_gl_state (_context->source_material, NULL); + _cogl_material_flush_gl_state (_context->source_material, NULL); enable_flags = - cogl_material_get_cogl_enable_flags (_context->source_material); + _cogl_material_get_cogl_enable_flags (_context->source_material); cogl_enable (enable_flags); + _context->quad_indices_byte = COGL_INVALID_HANDLE; + _context->quad_indices_short = COGL_INVALID_HANDLE; + _context->quad_indices_short_len = 0; + return TRUE; } void -cogl_destroy_context () +_cogl_destroy_context () { if (_context == NULL) return; @@ -199,13 +203,16 @@ cogl_destroy_context () if (_context->logged_vertices) g_array_free (_context->logged_vertices, TRUE); - if (_context->static_indices) - g_array_free (_context->static_indices, TRUE); if (_context->polygon_vertices) g_array_free (_context->polygon_vertices, TRUE); if (_context->current_layers) g_array_free (_context->current_layers, TRUE); + if (_context->quad_indices_byte) + cogl_handle_unref (_context->quad_indices_byte); + if (_context->quad_indices_short) + cogl_handle_unref (_context->quad_indices_short); + g_free (_context); } diff --git a/gl/cogl-context.h b/gl/cogl-context.h index 2660ed812..d845a6c12 100644 --- a/gl/cogl-context.h +++ b/gl/cogl-context.h @@ -78,7 +78,6 @@ typedef struct * can batch things together. */ GArray *journal; GArray *logged_vertices; - GArray *static_indices; GArray *polygon_vertices; /* Some simple caching, to minimize state changes... */ @@ -102,6 +101,12 @@ typedef struct floatVec2 path_nodes_max; CoglHandle stencil_material; + /* Pre-generated VBOs containing indices to generate GL_TRIANGLES + out of a vertex array of quads */ + CoglHandle quad_indices_byte; + guint quad_indices_short_len; + CoglHandle quad_indices_short; + /* Relying on glext.h to define these */ COGL_PFNGLGENRENDERBUFFERSEXTPROC pf_glGenRenderbuffersEXT; COGL_PFNGLDELETERENDERBUFFERSEXTPROC pf_glDeleteRenderbuffersEXT; @@ -115,6 +120,7 @@ typedef struct COGL_PFNGLDELETEFRAMEBUFFERSEXTPROC pf_glDeleteFramebuffersEXT; COGL_PFNGLBLITFRAMEBUFFEREXTPROC pf_glBlitFramebufferEXT; COGL_PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC pf_glRenderbufferStorageMultisampleEXT; + COGL_PFNGLGENERATEMIPMAPEXTPROC pf_glGenerateMipmapEXT; COGL_PFNGLCREATEPROGRAMOBJECTARBPROC pf_glCreateProgramObjectARB; COGL_PFNGLCREATESHADEROBJECTARBPROC pf_glCreateShaderObjectARB; @@ -164,6 +170,11 @@ typedef struct COGL_PFNGLACTIVETEXTUREPROC pf_glActiveTexture; COGL_PFNGLCLIENTACTIVETEXTUREPROC pf_glClientActiveTexture; + + COGL_PFNGLBLENDEQUATIONPROC pf_glBlendEquation; + COGL_PFNGLBLENDCOLORPROC pf_glBlendColor; + COGL_PFNGLBLENDFUNCSEPARATEPROC pf_glBlendFuncSeparate; + COGL_PFNGLBLENDEQUATIONSEPARATEPROC pf_glBlendEquationSeparate; } CoglContext; CoglContext * diff --git a/gl/cogl-defines.h.in b/gl/cogl-defines.h.in index 8e2df9ec3..025b4cad0 100644 --- a/gl/cogl-defines.h.in +++ b/gl/cogl-defines.h.in @@ -773,6 +773,10 @@ typedef void GLsizei width, GLsizei height); +typedef void + (APIENTRYP COGL_PFNGLGENERATEMIPMAPEXTPROC) + (GLenum target); + typedef GLhandleARB (APIENTRYP COGL_PFNGLCREATEPROGRAMOBJECTARBPROC) (void); @@ -1020,6 +1024,29 @@ typedef void (APIENTRYP COGL_PFNGLCLIENTACTIVETEXTUREPROC) (GLenum texture); +typedef void + (APIENTRYP COGL_PFNGLBLENDFUNCSEPARATEPROC) + (GLenum srcRGB, + GLenum dstRGB, + GLenum srcAlpha, + GLenum dstAlpha); + +typedef void + (APIENTRYP COGL_PFNGLBLENDEQUATIONSEPARATEPROC) + (GLenum modeRGB, + GLenum modeAlpha); + +typedef void + (APIENTRYP COGL_PFNGLBLENDEQUATIONPROC) + (GLenum mode); + +typedef void + (APIENTRYP COGL_PFNGLBLENDCOLORPROC) + (GLclampf red, + GLclampf green, + GLclampf blue, + GLclampf alpha); + G_END_DECLS #endif diff --git a/gl/cogl-primitives.c b/gl/cogl-primitives.c index f3c11c134..6c106f9ec 100644 --- a/gl/cogl-primitives.c +++ b/gl/cogl-primitives.c @@ -29,6 +29,7 @@ #include "cogl-internal.h" #include "cogl-context.h" #include "cogl-clip-stack.h" +#include "cogl-material-private.h" #include #include @@ -78,13 +79,13 @@ _cogl_path_stroke_nodes () _COGL_GET_CONTEXT (ctx, NO_RETVAL); - enable_flags |= cogl_material_get_cogl_enable_flags (ctx->source_material); + enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material); cogl_enable (enable_flags); - cogl_material_flush_gl_state (ctx->source_material, - COGL_MATERIAL_FLUSH_DISABLE_MASK, - (guint32)~0, /* disable all texture layers */ - NULL); + _cogl_material_flush_gl_state (ctx->source_material, + COGL_MATERIAL_FLUSH_DISABLE_MASK, + (guint32)~0, /* disable all texture layers */ + NULL); _cogl_current_matrix_state_flush (); while (path_start < ctx->path_nodes->len) @@ -133,10 +134,10 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, _COGL_GET_CONTEXT (ctx, NO_RETVAL); /* Just setup a simple material that doesn't use texturing... */ - cogl_material_flush_gl_state (ctx->stencil_material, NULL); + _cogl_material_flush_gl_state (ctx->stencil_material, NULL); enable_flags |= - cogl_material_get_cogl_enable_flags (ctx->source_material); + _cogl_material_get_cogl_enable_flags (ctx->source_material); cogl_enable (enable_flags); _cogl_path_get_bounds (nodes_min, nodes_max, diff --git a/gl/cogl-shader.c b/gl/cogl-shader.c index 944e6736f..de3302e6a 100644 --- a/gl/cogl-shader.c +++ b/gl/cogl-shader.c @@ -108,22 +108,23 @@ cogl_shader_compile (CoglHandle handle) glCompileShaderARB (shader->gl_handle); } -void -cogl_shader_get_info_log (CoglHandle handle, - size_t size, - char *buffer) +gchar * +cogl_shader_get_info_log (CoglHandle handle) { CoglShader *shader; + char buffer[512]; int len; - _COGL_GET_CONTEXT (ctx, NO_RETVAL); + _COGL_GET_CONTEXT (ctx, NULL); if (!cogl_is_shader (handle)) - return; + return NULL; shader = _cogl_shader_pointer_from_handle (handle); - glGetInfoLogARB (shader->gl_handle, size-1, &len, buffer); + glGetInfoLogARB (shader->gl_handle, 511, &len, buffer); buffer[len]='\0'; + + return g_strdup (buffer); } CoglShaderType diff --git a/gl/cogl-texture-private.h b/gl/cogl-texture-private.h index 7cf6fe951..365a47921 100644 --- a/gl/cogl-texture-private.h +++ b/gl/cogl-texture-private.h @@ -30,6 +30,7 @@ typedef struct _CoglTexture CoglTexture; typedef struct _CoglTexSliceSpan CoglTexSliceSpan; typedef struct _CoglSpanIter CoglSpanIter; +typedef struct _CoglTexturePixel CoglTexturePixel; struct _CoglTexSliceSpan { @@ -55,6 +56,18 @@ struct _CoglSpanIter gboolean intersects; }; +/* This is used to store the first pixel of each slice. This is only + used when glGenerateMipmap is not available */ +struct _CoglTexturePixel +{ + /* We need to store the format of the pixel because we store the + data in the source format which might end up being different for + each slice if a subregion is updated with a different format */ + GLenum gl_format; + GLenum gl_type; + guint8 data[4]; +}; + struct _CoglTexture { CoglHandleObject _parent; @@ -68,11 +81,17 @@ struct _CoglTexture GArray *slice_y_spans; GArray *slice_gl_handles; gint max_waste; - CoglTextureFilter min_filter; - CoglTextureFilter mag_filter; + GLenum min_filter; + GLenum mag_filter; gboolean is_foreign; GLint wrap_mode; gboolean auto_mipmap; + gboolean mipmaps_dirty; + + /* This holds a copy of the first pixel in each slice. It is only + used to force an automatic update of the mipmaps when + glGenerateMipmap is not available. */ + CoglTexturePixel *first_pixels; }; /* To improve batching of geometry when submitting vertices to OpenGL we @@ -93,6 +112,14 @@ void _cogl_texture_set_wrap_mode_parameter (CoglTexture *tex, GLenum wrap_mode); +void +_cogl_texture_set_filters (CoglHandle handle, + GLenum min_filter, + GLenum mag_filter); + +void +_cogl_texture_ensure_mipmaps (CoglHandle handle); + gboolean _cogl_texture_span_has_waste (CoglTexture *tex, gint x_span_index, diff --git a/gl/cogl-texture.c b/gl/cogl-texture.c index 643b11899..215e14c78 100644 --- a/gl/cogl-texture.c +++ b/gl/cogl-texture.c @@ -49,6 +49,7 @@ #define glDrawRangeElements ctx->pf_glDrawRangeElements #define glActiveTexture ctx->pf_glActiveTexture #define glClientActiveTexture ctx->pf_glClientActiveTexture +#define glGenerateMipmap ctx->pf_glGenerateMipmapEXT #else @@ -247,11 +248,12 @@ _cogl_texture_upload_to_gl (CoglTexture *tex) /* Iterate horizontal slices */ for (x = 0; x < tex->slice_x_spans->len; ++x) { + gint slice_num = y * tex->slice_x_spans->len + x; + x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x); /* Pick the gl texture object handle */ - gl_handle = g_array_index (tex->slice_gl_handles, GLuint, - y * tex->slice_x_spans->len + x); + gl_handle = g_array_index (tex->slice_gl_handles, GLuint, slice_num); /* Setup gl alignment to match rowstride and top-left corner */ prep_for_gl_pixels_upload (tex->bitmap.rowstride, @@ -259,6 +261,17 @@ _cogl_texture_upload_to_gl (CoglTexture *tex) y_span->start, bpp); + /* Keep a copy of the first pixel if needed */ + if (tex->first_pixels) + { + memcpy (tex->first_pixels[slice_num].data, + tex->bitmap.data + x_span->start * bpp + + y_span->start * tex->bitmap.rowstride, + bpp); + tex->first_pixels[slice_num].gl_format = tex->gl_format; + tex->first_pixels[slice_num].gl_type = tex->gl_type; + } + /* Upload new image data */ GE( glBindTexture (tex->gl_target, gl_handle) ); @@ -343,6 +356,8 @@ _cogl_texture_upload_to_gl (CoglTexture *tex) if (waste_buf) g_free (waste_buf); + tex->mipmaps_dirty = TRUE; + return TRUE; } @@ -494,6 +509,8 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, _cogl_span_iter_next (&x_iter), source_x += inter_w ) { + gint slice_num; + /* Discard slices out of the subregion early */ if (!x_iter.intersects) { @@ -516,10 +533,10 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, local_y = (y_iter.intersect_start - y_iter.pos); + slice_num = y_iter.index * tex->slice_x_spans->len + x_iter.index; + /* Pick slice GL handle */ - gl_handle = g_array_index (tex->slice_gl_handles, GLuint, - y_iter.index * tex->slice_x_spans->len + - x_iter.index); + gl_handle = g_array_index (tex->slice_gl_handles, GLuint, slice_num); /* Setup gl alignment to match rowstride and top-left corner */ prep_for_gl_pixels_upload (source_bmp->rowstride, @@ -527,6 +544,17 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, source_y, bpp); + /* Keep a copy of the first pixel if needed */ + if (tex->first_pixels && local_x == 0 && local_y == 0) + { + memcpy (tex->first_pixels[slice_num].data, + source_bmp->data + source_x * bpp + + source_y * source_bmp->rowstride, + bpp); + tex->first_pixels[slice_num].gl_format = source_gl_format; + tex->first_pixels[slice_num].gl_type = source_gl_type; + } + /* Upload new image data */ GE( glBindTexture (tex->gl_target, gl_handle) ); @@ -640,14 +668,16 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, if (waste_buf) g_free (waste_buf); + tex->mipmaps_dirty = TRUE; + return TRUE; } static gint -_cogl_rect_slices_for_size (gint size_to_fill, - gint max_span_size, - gint max_waste, - GArray *out_spans) +_cogl_rect_slices_for_size (gint size_to_fill, + gint max_span_size, + gint max_waste, + GArray *out_spans) { gint n_spans = 0; CoglTexSliceSpan span; @@ -679,10 +709,10 @@ _cogl_rect_slices_for_size (gint size_to_fill, } static gint -_cogl_pot_slices_for_size (gint size_to_fill, - gint max_span_size, - gint max_waste, - GArray *out_spans) +_cogl_pot_slices_for_size (gint size_to_fill, + gint max_span_size, + gint max_waste, + GArray *out_spans) { gint n_spans = 0; CoglTexSliceSpan span; @@ -693,7 +723,8 @@ _cogl_pot_slices_for_size (gint size_to_fill, span.waste = 0; /* Fix invalid max_waste */ - if (max_waste < 0) max_waste = 0; + if (max_waste < 0) + max_waste = 0; while (TRUE) { @@ -826,10 +857,10 @@ _cogl_texture_slices_create (CoglTexture *tex) /* Check if size supported else bail out */ if (!_cogl_texture_size_supported (tex->gl_target, - tex->gl_format, - tex->gl_type, - max_width, - max_height)) + tex->gl_format, + tex->gl_type, + max_width, + max_height)) { return FALSE; } @@ -912,6 +943,14 @@ _cogl_texture_slices_create (CoglTexture *tex) g_array_set_size (tex->slice_gl_handles, n_slices); + /* Allocate some space to store a copy of the first pixel of each + slice. This is only needed to glGenerateMipmap (which is part of + the FBO extension) is not available */ + if (cogl_features_available (COGL_FEATURE_OFFSCREEN)) + tex->first_pixels = NULL; + else + tex->first_pixels = g_new (CoglTexturePixel, n_slices); + /* Wrap mode not yet set */ tex->wrap_mode = GL_FALSE; @@ -940,14 +979,6 @@ _cogl_texture_slices_create (CoglTexture *tex) /* Setup texture parameters */ GE( glBindTexture (tex->gl_target, gl_handles[y * n_x_slices + x]) ); - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MAG_FILTER, - tex->mag_filter) ); - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MIN_FILTER, - tex->min_filter) ); - - if (tex->auto_mipmap) - GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP, - GL_TRUE) ); /* Use a transparent border color so that we can leave the color buffer alone when using texture co-ordinates @@ -984,6 +1015,9 @@ _cogl_texture_slices_free (CoglTexture *tex) g_array_free (tex->slice_gl_handles, TRUE); } + + if (tex->first_pixels != NULL) + g_free (tex->first_pixels); } gboolean @@ -1199,11 +1233,10 @@ _cogl_texture_free (CoglTexture *tex) } CoglHandle -cogl_texture_new_with_size (guint width, - guint height, - gint max_waste, - CoglTextureFlags flags, - CoglPixelFormat internal_format) +cogl_texture_new_with_size (guint width, + guint height, + CoglTextureFlags flags, + CoglPixelFormat internal_format) { CoglTexture *tex; gint bpp; @@ -1221,7 +1254,8 @@ cogl_texture_new_with_size (guint width, tex = (CoglTexture*) g_malloc (sizeof (CoglTexture)); tex->is_foreign = FALSE; - tex->auto_mipmap = ((flags & COGL_TEXTURE_AUTO_MIPMAP) != 0); + tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0; + tex->mipmaps_dirty = TRUE; tex->bitmap.width = width; tex->bitmap.height = height; @@ -1234,9 +1268,14 @@ cogl_texture_new_with_size (guint width, tex->slice_y_spans = NULL; tex->slice_gl_handles = NULL; - tex->max_waste = max_waste; - tex->min_filter = COGL_TEXTURE_FILTER_NEAREST; - tex->mag_filter = COGL_TEXTURE_FILTER_NEAREST; + if (flags & COGL_TEXTURE_NO_SLICING) + tex->max_waste = -1; + else + tex->max_waste = COGL_TEXTURE_MAX_WASTE; + + /* Unknown filter */ + tex->min_filter = GL_FALSE; + tex->mag_filter = GL_FALSE; /* Find closest GL format match */ tex->bitmap.format = @@ -1258,7 +1297,6 @@ cogl_texture_new_with_size (guint width, CoglHandle cogl_texture_new_from_data (guint width, guint height, - gint max_waste, CoglTextureFlags flags, CoglPixelFormat format, CoglPixelFormat internal_format, @@ -1282,7 +1320,8 @@ cogl_texture_new_from_data (guint width, tex = (CoglTexture*) g_malloc (sizeof (CoglTexture)); tex->is_foreign = FALSE; - tex->auto_mipmap = ((flags & COGL_TEXTURE_AUTO_MIPMAP) != 0); + tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0; + tex->mipmaps_dirty = TRUE; tex->bitmap.width = width; tex->bitmap.height = height; @@ -1295,9 +1334,14 @@ cogl_texture_new_from_data (guint width, tex->slice_y_spans = NULL; tex->slice_gl_handles = NULL; - tex->max_waste = max_waste; - tex->min_filter = COGL_TEXTURE_FILTER_NEAREST; - tex->mag_filter = COGL_TEXTURE_FILTER_NEAREST; + if (flags & COGL_TEXTURE_NO_SLICING) + tex->max_waste = -1; + else + tex->max_waste = COGL_TEXTURE_MAX_WASTE; + + /* Unknown filter */ + tex->min_filter = GL_FALSE; + tex->mag_filter = GL_FALSE; /* FIXME: If upload fails we should set some kind of * error flag but still return texture handle (this @@ -1328,10 +1372,9 @@ cogl_texture_new_from_data (guint width, } CoglHandle -cogl_texture_new_from_bitmap (CoglHandle bmp_handle, - gint max_waste, - CoglTextureFlags flags, - CoglPixelFormat internal_format) +cogl_texture_new_from_bitmap (CoglHandle bmp_handle, + CoglTextureFlags flags, + CoglPixelFormat internal_format) { CoglTexture *tex; CoglBitmap *bmp = (CoglBitmap *)bmp_handle; @@ -1342,7 +1385,8 @@ cogl_texture_new_from_bitmap (CoglHandle bmp_handle, tex = (CoglTexture*) g_malloc ( sizeof (CoglTexture)); tex->is_foreign = FALSE; - tex->auto_mipmap = ((flags & COGL_TEXTURE_AUTO_MIPMAP) != 0); + tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0; + tex->mipmaps_dirty = TRUE; tex->bitmap = *bmp; tex->bitmap_owner = FALSE; @@ -1351,9 +1395,14 @@ cogl_texture_new_from_bitmap (CoglHandle bmp_handle, tex->slice_y_spans = NULL; tex->slice_gl_handles = NULL; - tex->max_waste = max_waste; - tex->min_filter = COGL_TEXTURE_FILTER_NEAREST; - tex->mag_filter = COGL_TEXTURE_FILTER_NEAREST; + if (flags & COGL_TEXTURE_NO_SLICING) + tex->max_waste = -1; + else + tex->max_waste = COGL_TEXTURE_MAX_WASTE; + + /* Unknown filter */ + tex->min_filter = GL_FALSE; + tex->mag_filter = GL_FALSE; /* FIXME: If upload fails we should set some kind of * error flag but still return texture handle if the @@ -1388,13 +1437,12 @@ cogl_texture_new_from_bitmap (CoglHandle bmp_handle, CoglHandle cogl_texture_new_from_file (const gchar *filename, - gint max_waste, CoglTextureFlags flags, CoglPixelFormat internal_format, GError **error) { - CoglHandle bmp; - CoglHandle handle; + CoglHandle bmp; + CoglHandle handle; g_return_val_if_fail (error == NULL || *error == NULL, COGL_INVALID_HANDLE); @@ -1402,10 +1450,7 @@ cogl_texture_new_from_file (const gchar *filename, if (bmp == COGL_INVALID_HANDLE) return COGL_INVALID_HANDLE; - handle = cogl_texture_new_from_bitmap (bmp, - max_waste, - flags, - internal_format); + handle = cogl_texture_new_from_bitmap (bmp, flags, internal_format); cogl_handle_unref (bmp); return handle; @@ -1433,8 +1478,6 @@ cogl_texture_new_from_foreign (GLuint gl_handle, GLint gl_int_format = 0; GLint gl_width = 0; GLint gl_height = 0; - GLint gl_min_filter; - GLint gl_mag_filter; GLint gl_gen_mipmap; guint bpp; CoglTexture *tex; @@ -1482,14 +1525,6 @@ cogl_texture_new_from_foreign (GLuint gl_handle, GL_TEXTURE_HEIGHT, &gl_height) ); - GE( glGetTexParameteriv (gl_target, - GL_TEXTURE_MIN_FILTER, - &gl_min_filter) ); - - GE( glGetTexParameteriv (gl_target, - GL_TEXTURE_MAG_FILTER, - &gl_mag_filter) ); - GE( glGetTexParameteriv (gl_target, GL_GENERATE_MIPMAP, &gl_gen_mipmap) ); @@ -1508,18 +1543,16 @@ cogl_texture_new_from_foreign (GLuint gl_handle, return COGL_INVALID_HANDLE; /* Try and match to a cogl format */ - if (!_cogl_pixel_format_from_gl_internal (gl_int_format, - &format)) - { - return COGL_INVALID_HANDLE; - } + if (!_cogl_pixel_format_from_gl_internal (gl_int_format, &format)) + return COGL_INVALID_HANDLE; /* Create new texture */ - tex = (CoglTexture*) g_malloc ( sizeof (CoglTexture)); + tex = (CoglTexture *) g_malloc (sizeof (CoglTexture)); /* Setup bitmap info */ tex->is_foreign = TRUE; tex->auto_mipmap = (gl_gen_mipmap == GL_TRUE) ? TRUE : FALSE; + tex->mipmaps_dirty = TRUE; bpp = _cogl_get_format_bpp (format); tex->bitmap.format = format; @@ -1533,8 +1566,9 @@ cogl_texture_new_from_foreign (GLuint gl_handle, tex->gl_format = gl_int_format; tex->gl_type = GL_UNSIGNED_BYTE; - tex->min_filter = gl_min_filter; - tex->mag_filter = gl_mag_filter; + /* Unknown filter */ + tex->min_filter = GL_FALSE; + tex->mag_filter = GL_FALSE; tex->max_waste = 0; /* Wrap mode not yet set */ @@ -1680,36 +1714,10 @@ cogl_texture_get_gl_texture (CoglHandle handle, return TRUE; } -CoglTextureFilter -cogl_texture_get_min_filter (CoglHandle handle) -{ - CoglTexture *tex; - - if (!cogl_is_texture (handle)) - return 0; - - tex = _cogl_texture_pointer_from_handle (handle); - - return tex->min_filter; -} - -CoglTextureFilter -cogl_texture_get_mag_filter (CoglHandle handle) -{ - CoglTexture *tex; - - if (!cogl_is_texture (handle)) - return 0; - - tex = _cogl_texture_pointer_from_handle (handle); - - return tex->mag_filter; -} - void -cogl_texture_set_filters (CoglHandle handle, - CoglTextureFilter min_filter, - CoglTextureFilter mag_filter) +_cogl_texture_set_filters (CoglHandle handle, + GLenum min_filter, + GLenum mag_filter) { CoglTexture *tex; GLuint gl_handle; @@ -1720,14 +1728,18 @@ cogl_texture_set_filters (CoglHandle handle, tex = _cogl_texture_pointer_from_handle (handle); - /* Store new values */ - tex->min_filter = min_filter; - tex->mag_filter = mag_filter; - /* Make sure slices were created */ if (tex->slice_gl_handles == NULL) return; + if (min_filter == tex->min_filter + && mag_filter == tex->mag_filter) + return; + + /* Store new values */ + tex->min_filter = min_filter; + tex->mag_filter = mag_filter; + /* Apply new filters to every slice */ for (i=0; islice_gl_handles->len; ++i) { @@ -1740,6 +1752,52 @@ cogl_texture_set_filters (CoglHandle handle, } } +void +_cogl_texture_ensure_mipmaps (CoglHandle handle) +{ + CoglTexture *tex; + int i; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + if (!cogl_is_texture (handle)) + return; + + tex = _cogl_texture_pointer_from_handle (handle); + + /* Only update if the mipmaps are dirty */ + if (!tex->auto_mipmap || !tex->mipmaps_dirty) + return; + + /* Make sure slices were created */ + if (tex->slice_gl_handles == NULL) + return; + + /* Regenerate the mipmaps on every slice */ + for (i = 0; i < tex->slice_gl_handles->len; i++) + { + GLuint gl_handle = g_array_index (tex->slice_gl_handles, GLuint, i); + GE( glBindTexture (tex->gl_target, gl_handle) ); + + /* glGenerateMipmap is defined in the FBO extension */ + if (cogl_features_available (COGL_FEATURE_OFFSCREEN)) + GE( glGenerateMipmap (tex->gl_target) ); + else + { + CoglTexturePixel *pixel = tex->first_pixels + i; + /* Temporarily enable automatic mipmap generation and + re-upload the first pixel to cause a regeneration */ + GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP, GL_TRUE) ); + GE( glTexSubImage2D (tex->gl_target, 0, 0, 0, 1, 1, + pixel->gl_format, pixel->gl_type, + pixel->data) ); + GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP, GL_FALSE) ); + } + } + + tex->mipmaps_dirty = FALSE; +} + gboolean cogl_texture_set_region (CoglHandle handle, gint src_x, diff --git a/gl/cogl.c b/gl/cogl.c index b2c5417e7..748c082ac 100644 --- a/gl/cogl.c +++ b/gl/cogl.c @@ -399,6 +399,10 @@ _cogl_features_init (void) (COGL_PFNGLDELETEFRAMEBUFFERSEXTPROC) cogl_get_proc_address ("glDeleteFramebuffersEXT"); + ctx->pf_glGenerateMipmapEXT = + (COGL_PFNGLGENERATEMIPMAPEXTPROC) + cogl_get_proc_address ("glGenerateMipmapEXT"); + if (ctx->pf_glGenRenderbuffersEXT && ctx->pf_glBindRenderbufferEXT && ctx->pf_glRenderbufferStorageEXT && @@ -407,7 +411,8 @@ _cogl_features_init (void) ctx->pf_glFramebufferTexture2DEXT && ctx->pf_glFramebufferRenderbufferEXT && ctx->pf_glCheckFramebufferStatusEXT && - ctx->pf_glDeleteFramebuffersEXT) + ctx->pf_glDeleteFramebuffersEXT && + ctx->pf_glGenerateMipmapEXT) flags |= COGL_FEATURE_OFFSCREEN; } @@ -486,6 +491,23 @@ _cogl_features_init (void) (COGL_PFNGLCLIENTACTIVETEXTUREPROC) cogl_get_proc_address ("glClientActiveTexture"); + ctx->pf_glBlendEquation = + (COGL_PFNGLBLENDEQUATIONPROC) + cogl_get_proc_address ("glBlendEquation"); + ctx->pf_glBlendColor = + (COGL_PFNGLBLENDCOLORPROC) + cogl_get_proc_address ("glBlendColor"); + + /* Available in 1.4 */ + ctx->pf_glBlendFuncSeparate = + (COGL_PFNGLBLENDFUNCSEPARATEPROC) + cogl_get_proc_address ("glBlendFuncSeparate"); + + /* Available in 2.0 */ + ctx->pf_glBlendEquationSeparate = + (COGL_PFNGLBLENDEQUATIONSEPARATEPROC) + cogl_get_proc_address ("glBlendEquationSeparate"); + /* Cache features */ ctx->feature_flags = flags; ctx->features_cached = TRUE; diff --git a/gles/Makefile.am b/gles/Makefile.am index 3f84b4b2f..3ce5365a7 100644 --- a/gles/Makefile.am +++ b/gles/Makefile.am @@ -27,12 +27,12 @@ INCLUDES = \ -DG_LOG_DOMAIN=\"Cogl-GLES\" \ -DCLUTTER_COMPILATION -noinst_LTLIBRARIES = libclutter-cogl.la +noinst_LTLIBRARIES = libclutter-cogl-gles.la -libclutter_cogl_la_CPPFLAGS = $(CLUTTER_CFLAGS) $(COGL_DEBUG_CFLAGS) $(CLUTTER_DEBUG_CFLAGS) $(MAINTAINER_CFLAGS) -libclutter_cogl_la_LIBADD = -lm $(CLUTTER_LIBS) $(top_builddir)/clutter/cogl/common/libclutter-cogl-common.la -libclutter_cogl_la_DEPENDENCIES = $(top_builddir)/clutter/cogl/common/libclutter-cogl-common.la -libclutter_cogl_la_SOURCES = \ +libclutter_cogl_gles_la_CPPFLAGS = $(CLUTTER_CFLAGS) $(COGL_DEBUG_CFLAGS) $(CLUTTER_DEBUG_CFLAGS) $(MAINTAINER_CFLAGS) +libclutter_cogl_gles_la_LIBADD = -lm $(CLUTTER_LIBS) $(top_builddir)/clutter/cogl/common/libclutter-cogl-common.la +libclutter_cogl_gles_la_DEPENDENCIES = $(top_builddir)/clutter/cogl/common/libclutter-cogl-common.la +libclutter_cogl_gles_la_SOURCES = \ $(top_builddir)/clutter/cogl/cogl.h \ $(top_builddir)/clutter/cogl/cogl-defines-gles.h \ $(top_builddir)/clutter/cogl/cogl-color.h \ @@ -60,7 +60,7 @@ libclutter_cogl_la_SOURCES = \ cogl-shader.c if USE_GLES2_WRAPPER -libclutter_cogl_la_SOURCES += \ +libclutter_cogl_gles_la_SOURCES += \ cogl-gles2-wrapper.c \ cogl-fixed-vertex-shader.h \ cogl-fixed-vertex-shader.c \ diff --git a/gles/cogl-context.c b/gles/cogl-context.c index d70d59d35..293ac4689 100644 --- a/gles/cogl-context.c +++ b/gles/cogl-context.c @@ -39,7 +39,7 @@ static CoglContext *_context = NULL; static gboolean gl_is_indirect = FALSE; -gboolean +static gboolean cogl_create_context () { GLubyte default_texture_data[] = { 0xff, 0xff, 0xff, 0x0 }; @@ -72,7 +72,6 @@ cogl_create_context () _context->journal = g_array_new (FALSE, FALSE, sizeof (CoglJournalEntry)); _context->logged_vertices = g_array_new (FALSE, FALSE, sizeof (GLfloat)); - _context->static_indices = g_array_new (FALSE, FALSE, sizeof (GLushort)); _context->polygon_vertices = g_array_new (FALSE, FALSE, sizeof (CoglTextureGLVertex)); @@ -107,8 +106,7 @@ cogl_create_context () _context->default_gl_texture_2d_tex = cogl_texture_new_from_data (1, /* width */ 1, /* height */ - -1, /* max waste */ - COGL_TEXTURE_NONE, /* flags */ + COGL_TEXTURE_NO_SLICING, /* flags */ COGL_PIXEL_FORMAT_RGBA_8888, /* data format */ /* internal format */ COGL_PIXEL_FORMAT_RGBA_8888, @@ -117,8 +115,7 @@ cogl_create_context () _context->default_gl_texture_rect_tex = cogl_texture_new_from_data (1, /* width */ 1, /* height */ - -1, /* max waste */ - COGL_TEXTURE_NONE, /* flags */ + COGL_TEXTURE_NO_SLICING, /* flags */ COGL_PIXEL_FORMAT_RGBA_8888, /* data format */ /* internal format */ COGL_PIXEL_FORMAT_RGBA_8888, @@ -126,16 +123,20 @@ cogl_create_context () default_texture_data); cogl_set_source (_context->default_material); - cogl_material_flush_gl_state (_context->source_material, NULL); + _cogl_material_flush_gl_state (_context->source_material, NULL); enable_flags = - cogl_material_get_cogl_enable_flags (_context->source_material); + _cogl_material_get_cogl_enable_flags (_context->source_material); cogl_enable (enable_flags); + _context->quad_indices_byte = COGL_INVALID_HANDLE; + _context->quad_indices_short = COGL_INVALID_HANDLE; + _context->quad_indices_short_len = 0; + return TRUE; } void -cogl_destroy_context () +_cogl_destroy_context () { if (_context == NULL) return; @@ -160,13 +161,16 @@ cogl_destroy_context () if (_context->logged_vertices) g_array_free (_context->logged_vertices, TRUE); - if (_context->static_indices) - g_array_free (_context->static_indices, TRUE); if (_context->polygon_vertices) g_array_free (_context->polygon_vertices, TRUE); if (_context->current_layers) g_array_free (_context->current_layers, TRUE); + if (_context->quad_indices_byte) + cogl_handle_unref (_context->quad_indices_byte); + if (_context->quad_indices_short) + cogl_handle_unref (_context->quad_indices_short); + g_free (_context); } diff --git a/gles/cogl-context.h b/gles/cogl-context.h index 3542e038d..2e39f2bc0 100644 --- a/gles/cogl-context.h +++ b/gles/cogl-context.h @@ -80,7 +80,6 @@ typedef struct * can batch things together. */ GArray *journal; GArray *logged_vertices; - GArray *static_indices; GArray *polygon_vertices; /* Some simple caching, to minimize state changes... */ @@ -104,6 +103,12 @@ typedef struct floatVec2 path_nodes_max; CoglHandle stencil_material; + /* Pre-generated VBOs containing indices to generate GL_TRIANGLES + out of a vertex array of quads */ + CoglHandle quad_indices_byte; + guint quad_indices_short_len; + CoglHandle quad_indices_short; + #ifdef HAVE_COGL_GLES2 CoglGles2Wrapper gles2; @@ -111,7 +116,6 @@ typedef struct supported */ GLint viewport_store[4]; #endif - } CoglContext; CoglContext * diff --git a/gles/cogl-gles2-wrapper.c b/gles/cogl-gles2-wrapper.c index 523676dd2..979ade598 100644 --- a/gles/cogl-gles2-wrapper.c +++ b/gles/cogl-gles2-wrapper.c @@ -89,13 +89,13 @@ cogl_gles2_wrapper_create_shader (GLenum type, const char *source) if (!status) { - char log[1024]; + char shader_log[1024]; GLint len; - glGetShaderInfoLog (shader, sizeof (log) - 1, &len, log); - log[len] = '\0'; + glGetShaderInfoLog (shader, sizeof (shader_log) - 1, &len, shader_log); + shader_log[len] = '\0'; - g_critical ("%s", log); + g_critical ("%s", shader_log); glDeleteShader (shader); @@ -538,9 +538,9 @@ cogl_gles2_wrapper_get_program (const CoglGles2WrapperSettings *settings) CoglShader *shader = _cogl_shader_pointer_from_handle ((CoglHandle) node->data); - if (shader->type == CGL_VERTEX_SHADER) + if (shader->type == COGL_SHADER_TYPE_VERTEX) custom_vertex_shader = TRUE; - else if (shader->type == CGL_FRAGMENT_SHADER) + else if (shader->type == COGL_SHADER_TYPE_FRAGMENT) custom_fragment_shader = TRUE; } } @@ -581,13 +581,13 @@ cogl_gles2_wrapper_get_program (const CoglGles2WrapperSettings *settings) if (!status) { - char log[1024]; + char shader_log[1024]; GLint len; - glGetProgramInfoLog (program->program, sizeof (log) - 1, &len, log); - log[len] = '\0'; + glGetProgramInfoLog (program->program, sizeof (shader_log) - 1, &len, shader_log); + shader_log[len] = '\0'; - g_critical ("%s", log); + g_critical ("%s", shader_log); glDeleteProgram (program->program); g_slice_free (CoglGles2WrapperProgram, program); @@ -1300,13 +1300,20 @@ cogl_gles2_wrapper_bind_texture (GLenum target, GLuint texture, } void -cogl_wrap_glTexEnvi (GLenum target, GLenum pname, GLfloat param) +cogl_wrap_glTexEnvi (GLenum target, GLenum pname, GLint param) { /* This function is only used to set the texture mode once to GL_MODULATE. The shader is hard-coded to modulate the texture so nothing needs to be done here. */ } +void +cogl_wrap_glTexEnvfv (GLenum target, GLenum pname, const GLfloat *params) +{ + /* FIXME: Currently needed to support texture combining using + * COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT */ +} + void cogl_wrap_glClientActiveTexture (GLenum texture) { diff --git a/gles/cogl-gles2-wrapper.h b/gles/cogl-gles2-wrapper.h index bd7f6d978..51bee2d5c 100644 --- a/gles/cogl-gles2-wrapper.h +++ b/gles/cogl-gles2-wrapper.h @@ -259,6 +259,7 @@ struct _CoglGles2WrapperShader #define GL_TEXTURE_ENV 0x2300 #define GL_TEXTURE_ENV_MODE 0x2200 +#define GL_TEXTURE_ENV_COLOR 0x2201 #define GL_MODULATE 0x2100 #define GL_EXP 0x8000 @@ -327,7 +328,8 @@ void cogl_wrap_glColorPointer (GLint size, GLenum type, GLsizei stride, void cogl_wrap_glNormalPointer (GLenum type, GLsizei stride, const GLvoid *pointer); -void cogl_wrap_glTexEnvi (GLenum target, GLenum pname, GLfloat param); +void cogl_wrap_glTexEnvi (GLenum target, GLenum pname, GLint param); +void cogl_wrap_glTexEnvfv (GLenum target, GLenum pname, const GLfloat *params); void cogl_wrap_glClientActiveTexture (GLenum texture); void cogl_wrap_glActiveTexture (GLenum texture); @@ -384,6 +386,7 @@ void _cogl_gles2_clear_cache_for_program (CoglHandle program); #define glColorPointer cogl_wrap_glColorPointer #define glNormalPointer cogl_wrap_glNormalPointer #define glTexEnvi cogl_wrap_glTexEnvi +#define glTexEnvfv cogl_wrap_glTexEnvfv #define glActiveTexture cogl_wrap_glActiveTexture #define glClientActiveTexture cogl_wrap_glClientActiveTexture #define glEnableClientState cogl_wrap_glEnableClientState diff --git a/gles/cogl-primitives.c b/gles/cogl-primitives.c index 1e03e1ea2..d8dee0ba6 100644 --- a/gles/cogl-primitives.c +++ b/gles/cogl-primitives.c @@ -29,6 +29,7 @@ #include "cogl-internal.h" #include "cogl-context.h" #include "cogl-clip-stack.h" +#include "cogl-material-private.h" #include #include @@ -78,13 +79,13 @@ _cogl_path_stroke_nodes () _COGL_GET_CONTEXT (ctx, NO_RETVAL); - enable_flags |= cogl_material_get_cogl_enable_flags (ctx->source_material); + enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material); cogl_enable (enable_flags); - cogl_material_flush_gl_state (ctx->source_material, - COGL_MATERIAL_FLUSH_DISABLE_MASK, - (guint32)~0, /* disable all texture layers */ - NULL); + _cogl_material_flush_gl_state (ctx->source_material, + COGL_MATERIAL_FLUSH_DISABLE_MASK, + (guint32)~0, /* disable all texture layers */ + NULL); _cogl_current_matrix_state_flush (); while (path_start < ctx->path_nodes->len) @@ -139,10 +140,10 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, _COGL_GET_CONTEXT (ctx, NO_RETVAL); /* Just setup a simple material that doesn't use texturing... */ - cogl_material_flush_gl_state (ctx->stencil_material, NULL); + _cogl_material_flush_gl_state (ctx->stencil_material, NULL); enable_flags |= - cogl_material_get_cogl_enable_flags (ctx->source_material); + _cogl_material_get_cogl_enable_flags (ctx->source_material); cogl_enable (enable_flags); _cogl_path_get_bounds (nodes_min, nodes_max, @@ -361,30 +362,30 @@ _cogl_path_fill_nodes_scanlines (CoglPathNode *path, while (iter) { GSList *next = iter->next; - GLfloat x0, x1; - GLfloat y0, y1; + GLfloat x_0, x_1; + GLfloat y_0, y_1; if (!next) break; - x0 = GPOINTER_TO_INT (iter->data); - x1 = GPOINTER_TO_INT (next->data); - y0 = bounds_y + i; - y1 = bounds_y + i + 1.0625f; + x_0 = GPOINTER_TO_INT (iter->data); + x_1 = GPOINTER_TO_INT (next->data); + y_0 = bounds_y + i; + y_1 = bounds_y + i + 1.0625f; /* render scanlines 1.0625 high to avoid gaps when transformed */ - coords[span_no * 12 + 0] = x0; - coords[span_no * 12 + 1] = y0; - coords[span_no * 12 + 2] = x1; - coords[span_no * 12 + 3] = y0; - coords[span_no * 12 + 4] = x1; - coords[span_no * 12 + 5] = y1; - coords[span_no * 12 + 6] = x0; - coords[span_no * 12 + 7] = y0; - coords[span_no * 12 + 8] = x0; - coords[span_no * 12 + 9] = y1; - coords[span_no * 12 + 10] = x1; - coords[span_no * 12 + 11] = y1; + coords[span_no * 12 + 0] = x_0; + coords[span_no * 12 + 1] = y_0; + coords[span_no * 12 + 2] = x_1; + coords[span_no * 12 + 3] = y_0; + coords[span_no * 12 + 4] = x_1; + coords[span_no * 12 + 5] = y_1; + coords[span_no * 12 + 6] = x_0; + coords[span_no * 12 + 7] = y_0; + coords[span_no * 12 + 8] = x_0; + coords[span_no * 12 + 9] = y_1; + coords[span_no * 12 + 10] = x_1; + coords[span_no * 12 + 11] = y_1; span_no ++; iter = next->next; } diff --git a/gles/cogl-shader.c b/gles/cogl-shader.c index ff5f0c58a..23109be34 100644 --- a/gles/cogl-shader.c +++ b/gles/cogl-shader.c @@ -99,22 +99,23 @@ cogl_shader_compile (CoglHandle handle) glCompileShader (shader->gl_handle); } -void -cogl_shader_get_info_log (CoglHandle handle, - size_t size, - char *buffer) +gchar * +cogl_shader_get_info_log (CoglHandle handle) { CoglShader *shader; + char buffer[512]; int len = 0; - _COGL_GET_CONTEXT (ctx, NO_RETVAL); + _COGL_GET_CONTEXT (ctx, NULL); if (!cogl_is_shader (handle)) - return; + return NULL; shader = _cogl_shader_pointer_from_handle (handle); - glGetShaderInfoLog (shader->gl_handle, size - 1, &len, buffer); + glGetShaderInfoLog (shader->gl_handle, 511, &len, buffer); buffer[len] = '\0'; + + return g_strdup (buffer); } CoglShaderType @@ -199,11 +200,10 @@ cogl_shader_compile (CoglHandle shader_handle) { } -void -cogl_shader_get_info_log (CoglHandle handle, - size_t size, - char *buffer) +gchar * +cogl_shader_get_info_log (CoglHandle handle) { + return NULL; } CoglShaderType diff --git a/gles/cogl-texture-private.h b/gles/cogl-texture-private.h index 7cf6fe951..365a47921 100644 --- a/gles/cogl-texture-private.h +++ b/gles/cogl-texture-private.h @@ -30,6 +30,7 @@ typedef struct _CoglTexture CoglTexture; typedef struct _CoglTexSliceSpan CoglTexSliceSpan; typedef struct _CoglSpanIter CoglSpanIter; +typedef struct _CoglTexturePixel CoglTexturePixel; struct _CoglTexSliceSpan { @@ -55,6 +56,18 @@ struct _CoglSpanIter gboolean intersects; }; +/* This is used to store the first pixel of each slice. This is only + used when glGenerateMipmap is not available */ +struct _CoglTexturePixel +{ + /* We need to store the format of the pixel because we store the + data in the source format which might end up being different for + each slice if a subregion is updated with a different format */ + GLenum gl_format; + GLenum gl_type; + guint8 data[4]; +}; + struct _CoglTexture { CoglHandleObject _parent; @@ -68,11 +81,17 @@ struct _CoglTexture GArray *slice_y_spans; GArray *slice_gl_handles; gint max_waste; - CoglTextureFilter min_filter; - CoglTextureFilter mag_filter; + GLenum min_filter; + GLenum mag_filter; gboolean is_foreign; GLint wrap_mode; gboolean auto_mipmap; + gboolean mipmaps_dirty; + + /* This holds a copy of the first pixel in each slice. It is only + used to force an automatic update of the mipmaps when + glGenerateMipmap is not available. */ + CoglTexturePixel *first_pixels; }; /* To improve batching of geometry when submitting vertices to OpenGL we @@ -93,6 +112,14 @@ void _cogl_texture_set_wrap_mode_parameter (CoglTexture *tex, GLenum wrap_mode); +void +_cogl_texture_set_filters (CoglHandle handle, + GLenum min_filter, + GLenum mag_filter); + +void +_cogl_texture_ensure_mipmaps (CoglHandle handle); + gboolean _cogl_texture_span_has_waste (CoglTexture *tex, gint x_span_index, diff --git a/gles/cogl-texture.c b/gles/cogl-texture.c index 1564faf2a..1929184c0 100644 --- a/gles/cogl-texture.c +++ b/gles/cogl-texture.c @@ -225,11 +225,12 @@ _cogl_texture_upload_to_gl (CoglTexture *tex) /* Iterate horizontal slices */ for (x = 0; x < tex->slice_x_spans->len; ++x) { + gint slice_num = y * tex->slice_x_spans->len + x; + x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x); /* Pick the gl texture object handle */ - gl_handle = g_array_index (tex->slice_gl_handles, GLuint, - y * tex->slice_x_spans->len + x); + gl_handle = g_array_index (tex->slice_gl_handles, GLuint, slice_num); /* FIXME: might optimize by not copying to intermediate slice bitmap when source rowstride = bpp * width and the texture @@ -258,6 +259,16 @@ _cogl_texture_upload_to_gl (CoglTexture *tex) slice_bmp.width, slice_bmp.height); + /* Keep a copy of the first pixel if needed */ + if (tex->first_pixels) + { + memcpy (tex->first_pixels[slice_num].data, + slice_bmp.data, + bpp); + tex->first_pixels[slice_num].gl_format = tex->gl_format; + tex->first_pixels[slice_num].gl_type = tex->gl_type; + } + /* Upload new image data */ GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, gl_handle, tex->gl_intformat) ); @@ -338,9 +349,6 @@ _cogl_texture_upload_to_gl (CoglTexture *tex) waste_buf) ); } - if (tex->auto_mipmap) - cogl_wrap_glGenerateMipmap (tex->gl_target); - /* Free temp bitmap */ g_free (slice_bmp.data); } @@ -349,6 +357,8 @@ _cogl_texture_upload_to_gl (CoglTexture *tex) if (waste_buf) g_free (waste_buf); + tex->mipmaps_dirty = TRUE; + return TRUE; } @@ -442,6 +452,7 @@ _cogl_texture_download_from_gl (CoglTexture *tex, gint bpp; GLint viewport[4]; CoglBitmap alpha_bmp; + CoglHandle prev_source; _COGL_GET_CONTEXT (ctx, FALSE); @@ -477,31 +488,21 @@ _cogl_texture_download_from_gl (CoglTexture *tex, if (ctx->texture_download_material == COGL_INVALID_HANDLE) { ctx->texture_download_material = cogl_material_new (); - cogl_material_set_layer_combine_function ( - ctx->texture_download_material, - 0, /* layer */ - COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB, - COGL_MATERIAL_LAYER_COMBINE_FUNC_REPLACE); - cogl_material_set_layer_combine_arg_src ( - ctx->texture_download_material, - 0, /* layer */ - 0, /* arg */ - COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB, - COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE); - cogl_material_set_blend_factors (ctx->texture_download_material, - COGL_MATERIAL_BLEND_FACTOR_ONE, - COGL_MATERIAL_BLEND_FACTOR_ZERO); + cogl_material_set_blend (ctx->texture_download_material, + "RGBA = ADD (SRC_COLOR, 0)", + NULL); } + prev_source = cogl_handle_ref (ctx->source_material); + cogl_set_source (ctx->texture_download_material); + cogl_material_set_layer (ctx->texture_download_material, 0, tex); - cogl_material_set_layer_combine_arg_op ( - ctx->texture_download_material, - 0, /* layer */ - 0, /* arg */ - COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB, - COGL_MATERIAL_LAYER_COMBINE_OP_SRC_COLOR); - cogl_material_flush_gl_state (ctx->texture_download_material, NULL); + cogl_material_set_layer_combine (ctx->texture_download_material, + 0, /* layer */ + "RGBA = REPLACE (TEXTURE)", + NULL); + _cogl_texture_draw_and_read (tex, target_bmp, viewport); /* Check whether texture has alpha and framebuffer not */ @@ -534,13 +535,11 @@ _cogl_texture_download_from_gl (CoglTexture *tex, alpha_bmp.height); /* Draw alpha values into RGB channels */ - cogl_material_set_layer_combine_arg_op ( - ctx->texture_download_material, - 0, /* layer */ - 0, /* arg */ - COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB, - COGL_MATERIAL_LAYER_COMBINE_OP_SRC_ALPHA); - cogl_material_flush_gl_state (ctx->texture_download_material, NULL); + cogl_material_set_layer_combine (ctx->texture_download_material, + 0, /* layer */ + "RGBA = REPLACE (TEXTURE[A])", + NULL); + _cogl_texture_draw_and_read (tex, &alpha_bmp, viewport); /* Copy temp R to target A */ @@ -568,6 +567,10 @@ _cogl_texture_download_from_gl (CoglTexture *tex, _cogl_set_current_matrix (COGL_MATRIX_MODELVIEW); _cogl_current_matrix_pop (); + /* restore the original material */ + cogl_set_source (prev_source); + cogl_handle_unref (prev_source); + return TRUE; } @@ -631,6 +634,8 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, _cogl_span_iter_next (&x_iter), source_x += inter_w ) { + gint slice_num; + /* Discard slices out of the subregion early */ if (!x_iter.intersects) { @@ -653,10 +658,10 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, local_y = (y_iter.intersect_start - y_iter.pos); + slice_num = y_iter.index * tex->slice_x_spans->len + x_iter.index; + /* Pick slice GL handle */ - gl_handle = g_array_index (tex->slice_gl_handles, GLuint, - y_iter.index * tex->slice_x_spans->len + - x_iter.index); + gl_handle = g_array_index (tex->slice_gl_handles, GLuint, slice_num); /* FIXME: might optimize by not copying to intermediate slice bitmap when source rowstride = bpp * width and the texture @@ -685,6 +690,15 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, slice_bmp.width, slice_bmp.height); + /* Keep a copy of the first pixel if needed */ + if (tex->first_pixels && local_x == 0 && local_y == 0) + { + memcpy (tex->first_pixels[slice_num].data, + slice_bmp.data, bpp); + tex->first_pixels[slice_num].gl_format = source_gl_format; + tex->first_pixels[slice_num].gl_type = source_gl_type; + } + /* Upload new image data */ GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, gl_handle, tex->gl_intformat) ); @@ -794,9 +808,6 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, waste_buf) ); } - if (tex->auto_mipmap) - cogl_wrap_glGenerateMipmap (tex->gl_target); - /* Free temp bitmap */ g_free (slice_bmp.data); } @@ -805,6 +816,8 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, if (waste_buf) g_free (waste_buf); + tex->mipmaps_dirty = TRUE; + return TRUE; } @@ -858,7 +871,8 @@ _cogl_pot_slices_for_size (gint size_to_fill, span.waste = 0; /* Fix invalid max_waste */ - if (max_waste < 0) max_waste = 0; + if (max_waste < 0) + max_waste = 0; while (TRUE) { @@ -866,7 +880,9 @@ _cogl_pot_slices_for_size (gint size_to_fill, if (size_to_fill > span.size) { /* Not yet - add a span of this size */ - if (out_spans) g_array_append_val (out_spans, span); + if (out_spans) + g_array_append_val (out_spans, span); + span.start += span.size; size_to_fill -= span.size; n_spans++; @@ -875,7 +891,9 @@ _cogl_pot_slices_for_size (gint size_to_fill, { /* Yes and waste is small enough */ span.waste = span.size - size_to_fill; - if (out_spans) g_array_append_val (out_spans, span); + if (out_spans) + g_array_append_val (out_spans, span); + return ++n_spans; } else @@ -971,10 +989,10 @@ _cogl_texture_slices_create (CoglTexture *tex) /* Check if size supported else bail out */ if (!_cogl_texture_size_supported (tex->gl_target, - tex->gl_format, - tex->gl_type, - max_width, - max_height)) + tex->gl_format, + tex->gl_type, + max_width, + max_height)) { return FALSE; } @@ -1057,6 +1075,14 @@ _cogl_texture_slices_create (CoglTexture *tex) g_array_set_size (tex->slice_gl_handles, n_slices); + /* Allocate some space to store a copy of the first pixel of each + slice. This is only needed to glGenerateMipmap (which is part of + the FBO extension) is not available */ + if (cogl_features_available (COGL_FEATURE_OFFSCREEN)) + tex->first_pixels = NULL; + else + tex->first_pixels = g_new (CoglTexturePixel, n_slices); + /* Wrap mode not yet set */ tex->wrap_mode = GL_FALSE; @@ -1087,20 +1113,11 @@ _cogl_texture_slices_create (CoglTexture *tex) GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, gl_handles[y * n_x_slices + x], tex->gl_intformat) ); - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MAG_FILTER, - tex->mag_filter) ); - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_MIN_FILTER, - tex->min_filter) ); - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S, tex->wrap_mode) ); GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_T, tex->wrap_mode) ); - if (tex->auto_mipmap) - GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP, - GL_TRUE) ); - /* Pass NULL data to init size and internal format */ GE( glTexImage2D (tex->gl_target, 0, tex->gl_intformat, x_span->size, y_span->size, 0, @@ -1130,6 +1147,9 @@ _cogl_texture_slices_free (CoglTexture *tex) g_array_free (tex->slice_gl_handles, TRUE); } + + if (tex->first_pixels != NULL) + g_free (tex->first_pixels); } gboolean @@ -1288,11 +1308,10 @@ _cogl_texture_free (CoglTexture *tex) } CoglHandle -cogl_texture_new_with_size (guint width, - guint height, - gint max_waste, - CoglTextureFlags flags, - CoglPixelFormat internal_format) +cogl_texture_new_with_size (guint width, + guint height, + CoglTextureFlags flags, + CoglPixelFormat internal_format) { CoglTexture *tex; gint bpp; @@ -1310,7 +1329,8 @@ cogl_texture_new_with_size (guint width, tex = (CoglTexture*) g_malloc (sizeof (CoglTexture)); tex->is_foreign = FALSE; - tex->auto_mipmap = ((flags & COGL_TEXTURE_AUTO_MIPMAP) != 0); + tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0; + tex->mipmaps_dirty = TRUE; tex->bitmap.width = width; tex->bitmap.height = height; @@ -1323,9 +1343,14 @@ cogl_texture_new_with_size (guint width, tex->slice_y_spans = NULL; tex->slice_gl_handles = NULL; - tex->max_waste = max_waste; - tex->min_filter = CGL_NEAREST; - tex->mag_filter = CGL_NEAREST; + if (flags & COGL_TEXTURE_NO_SLICING) + tex->max_waste = -1; + else + tex->max_waste = COGL_TEXTURE_MAX_WASTE; + + /* Unknown filter */ + tex->min_filter = GL_FALSE; + tex->mag_filter = GL_FALSE; /* Find closest GL format match */ tex->bitmap.format = @@ -1347,7 +1372,6 @@ cogl_texture_new_with_size (guint width, CoglHandle cogl_texture_new_from_data (guint width, guint height, - gint max_waste, CoglTextureFlags flags, CoglPixelFormat format, CoglPixelFormat internal_format, @@ -1371,7 +1395,8 @@ cogl_texture_new_from_data (guint width, tex = (CoglTexture*) g_malloc (sizeof (CoglTexture)); tex->is_foreign = FALSE; - tex->auto_mipmap = ((flags & COGL_TEXTURE_AUTO_MIPMAP) != 0); + tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0; + tex->mipmaps_dirty = TRUE; tex->bitmap.width = width; tex->bitmap.height = height; @@ -1384,9 +1409,14 @@ cogl_texture_new_from_data (guint width, tex->slice_y_spans = NULL; tex->slice_gl_handles = NULL; - tex->max_waste = max_waste; - tex->min_filter = CGL_NEAREST; - tex->mag_filter = CGL_NEAREST; + if (flags & COGL_TEXTURE_NO_SLICING) + tex->max_waste = -1; + else + tex->max_waste = COGL_TEXTURE_MAX_WASTE; + + /* Unknown filter */ + tex->min_filter = GL_FALSE; + tex->mag_filter = GL_FALSE; /* FIXME: If upload fails we should set some kind of * error flag but still return texture handle (this @@ -1417,10 +1447,9 @@ cogl_texture_new_from_data (guint width, } CoglHandle -cogl_texture_new_from_bitmap (CoglHandle bmp_handle, - gint max_waste, - CoglTextureFlags flags, - CoglPixelFormat internal_format) +cogl_texture_new_from_bitmap (CoglHandle bmp_handle, + CoglTextureFlags flags, + CoglPixelFormat internal_format) { CoglTexture *tex; CoglBitmap *bmp = (CoglBitmap *)bmp_handle; @@ -1429,7 +1458,8 @@ cogl_texture_new_from_bitmap (CoglHandle bmp_handle, tex = (CoglTexture*) g_malloc ( sizeof (CoglTexture)); tex->is_foreign = FALSE; - tex->auto_mipmap = ((flags & COGL_TEXTURE_AUTO_MIPMAP) != 0); + tex->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0; + tex->mipmaps_dirty = TRUE; tex->bitmap = *bmp; tex->bitmap_owner = TRUE; @@ -1439,9 +1469,14 @@ cogl_texture_new_from_bitmap (CoglHandle bmp_handle, tex->slice_y_spans = NULL; tex->slice_gl_handles = NULL; - tex->max_waste = max_waste; - tex->min_filter = CGL_NEAREST; - tex->mag_filter = CGL_NEAREST; + if (flags & COGL_TEXTURE_NO_SLICING) + tex->max_waste = -1; + else + tex->max_waste = COGL_TEXTURE_MAX_WASTE; + + /* Unknown filter */ + tex->min_filter = GL_FALSE; + tex->mag_filter = GL_FALSE; /* FIXME: If upload fails we should set some kind of * error flag but still return texture handle if the @@ -1476,7 +1511,6 @@ cogl_texture_new_from_bitmap (CoglHandle bmp_handle, CoglHandle cogl_texture_new_from_file (const gchar *filename, - gint max_waste, CoglTextureFlags flags, CoglPixelFormat internal_format, GError **error) @@ -1490,10 +1524,7 @@ cogl_texture_new_from_file (const gchar *filename, if (bmp == COGL_INVALID_HANDLE) return COGL_INVALID_HANDLE; - handle = cogl_texture_new_from_bitmap (bmp, - max_waste, - flags, - internal_format); + handle = cogl_texture_new_from_bitmap (bmp, flags, internal_format); cogl_handle_unref (bmp); return handle; @@ -1521,8 +1552,6 @@ cogl_texture_new_from_foreign (GLuint gl_handle, GLint gl_int_format = 0; GLint gl_width = 0; GLint gl_height = 0; - GLint gl_min_filter; - GLint gl_mag_filter; GLint gl_gen_mipmap; guint bpp; CoglTexture *tex; @@ -1569,14 +1598,6 @@ cogl_texture_new_from_foreign (GLuint gl_handle, gl_height = height + y_pot_waste; #endif - GE( glGetTexParameteriv (gl_target, - GL_TEXTURE_MIN_FILTER, - &gl_min_filter) ); - - GE( glGetTexParameteriv (gl_target, - GL_TEXTURE_MAG_FILTER, - &gl_mag_filter) ); - GE( glGetTexParameteriv (gl_target, GL_GENERATE_MIPMAP, &gl_gen_mipmap) ); @@ -1607,6 +1628,7 @@ cogl_texture_new_from_foreign (GLuint gl_handle, /* Setup bitmap info */ tex->is_foreign = TRUE; tex->auto_mipmap = (gl_gen_mipmap == GL_TRUE) ? TRUE : FALSE; + tex->mipmaps_dirty = TRUE; bpp = _cogl_get_format_bpp (format); tex->bitmap.format = format; @@ -1620,8 +1642,9 @@ cogl_texture_new_from_foreign (GLuint gl_handle, tex->gl_format = gl_int_format; tex->gl_type = GL_UNSIGNED_BYTE; - tex->min_filter = gl_min_filter; - tex->mag_filter = gl_mag_filter; + /* Unknown filter */ + tex->min_filter = GL_FALSE; + tex->mag_filter = GL_FALSE; tex->max_waste = 0; /* Wrap mode not yet set */ @@ -1767,36 +1790,10 @@ cogl_texture_get_gl_texture (CoglHandle handle, return TRUE; } -CoglTextureFilter -cogl_texture_get_min_filter (CoglHandle handle) -{ - CoglTexture *tex; - - if (!cogl_is_texture (handle)) - return 0; - - tex = _cogl_texture_pointer_from_handle (handle); - - return tex->min_filter; -} - -CoglTextureFilter -cogl_texture_get_mag_filter (CoglHandle handle) -{ - CoglTexture *tex; - - if (!cogl_is_texture (handle)) - return 0; - - tex = _cogl_texture_pointer_from_handle (handle); - - return tex->mag_filter; -} - void -cogl_texture_set_filters (CoglHandle handle, - CoglTextureFilter min_filter, - CoglTextureFilter mag_filter) +_cogl_texture_set_filters (CoglHandle handle, + GLenum min_filter, + GLenum mag_filter) { CoglTexture *tex; GLuint gl_handle; @@ -1807,14 +1804,18 @@ cogl_texture_set_filters (CoglHandle handle, tex = _cogl_texture_pointer_from_handle (handle); - /* Store new values */ - tex->min_filter = min_filter; - tex->mag_filter = mag_filter; - /* Make sure slices were created */ if (tex->slice_gl_handles == NULL) return; + if (min_filter == tex->min_filter + && mag_filter == tex->mag_filter) + return; + + /* Store new values */ + tex->min_filter = min_filter; + tex->mag_filter = mag_filter; + /* Apply new filters to every slice */ for (i=0; islice_gl_handles->len; ++i) { @@ -1827,6 +1828,52 @@ cogl_texture_set_filters (CoglHandle handle, } } +void +_cogl_texture_ensure_mipmaps (CoglHandle handle) +{ + CoglTexture *tex; + int i; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + if (!cogl_is_texture (handle)) + return; + + tex = _cogl_texture_pointer_from_handle (handle); + + /* Only update if the mipmaps are dirty */ + if (!tex->auto_mipmap || !tex->mipmaps_dirty) + return; + + /* Make sure slices were created */ + if (tex->slice_gl_handles == NULL) + return; + + /* Regenerate the mipmaps on every slice */ + for (i = 0; i < tex->slice_gl_handles->len; i++) + { + GLuint gl_handle = g_array_index (tex->slice_gl_handles, GLuint, i); + GE( glBindTexture (tex->gl_target, gl_handle) ); + + /* glGenerateMipmap is defined in the FBO extension */ + if (cogl_features_available (COGL_FEATURE_OFFSCREEN)) + GE( cogl_wrap_glGenerateMipmap (tex->gl_target) ); + else + { + CoglTexturePixel *pixel = tex->first_pixels + i; + /* Temporarily enable automatic mipmap generation and + re-upload the first pixel to cause a regeneration */ + GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP, GL_TRUE) ); + GE( glTexSubImage2D (tex->gl_target, 0, 0, 0, 1, 1, + pixel->gl_format, pixel->gl_type, + pixel->data) ); + GE( glTexParameteri (tex->gl_target, GL_GENERATE_MIPMAP, GL_FALSE) ); + } + } + + tex->mipmaps_dirty = FALSE; +} + gboolean cogl_texture_set_region (CoglHandle handle, gint src_x,