From 509928cc76e8e35e51eae8d6db10fe5763e40e4f Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Thu, 11 Dec 2008 15:33:38 +0000 Subject: [PATCH 01/16] [multi-texturing] This adds a new cogl_multi_texture API for GL,GLES1 + GLES2 Multitexturing allows blending multiple layers of texture data when texturing some geometry. A common use is for pre-baked light maps which can give nice lighting effects relativly cheaply. Another is for dot-3 bump mapping, and another is applying alpha channel masks. The dot-3 bump mapping would be really nice one day, but currently cogl doesn't support lighting so that's not dealt with in this patch. notable limitations: - It can only texture rectangles a.t.m - and like cogl_texture_rectangle there is no support for rotated texturing. - Sliced textures are not supported. I think I've figured out how to handle layers with different slice sizes at least for rectangular geometry, but I'm not sure how complex it becomes once rotations are possible and texturing arbitrary cogl_polygons. - Except for this new API, cogl still doesn't know about more than one texture unit, and so has no way of caching any enables related to other units. So that things don't break it's currently necessary to disable anything to do with additional units as soon as we are done with them which isn't ideal. - No clutter API yet. --- cogl-texture.h | 62 +++ common/cogl-handle.h | 6 + gl/cogl-context.c | 3 + gl/cogl-context.h | 6 + gl/cogl-defines.h.in | 1 + gl/cogl-texture-private.h | 27 +- gl/cogl-texture.c | 275 ++++++++++++- gles/cogl-context.c | 4 +- gles/cogl-context.h | 6 + gles/cogl-defines.h.in | 12 +- gles/cogl-fixed-fragment-shader.glsl | 33 +- gles/cogl-fixed-vertex-shader.glsl | 19 +- gles/cogl-gles2-wrapper.c | 552 ++++++++++++++++++++++----- gles/cogl-gles2-wrapper.h | 131 +++++-- gles/cogl-texture-private.h | 21 + gles/cogl-texture.c | 281 +++++++++++++- 16 files changed, 1260 insertions(+), 179 deletions(-) diff --git a/cogl-texture.h b/cogl-texture.h index 117a12b14..2289fdb8e 100644 --- a/cogl-texture.h +++ b/cogl-texture.h @@ -385,6 +385,68 @@ void cogl_texture_polygon (CoglHandle handle, CoglTextureVertex *vertices, gboolean use_color); +/** + * cogl_muti_texture_new: + * + * Creates a multi layered texture object. When first created it has + * zero layers. You must use cogl_multi_texture_layer_set_texture to + * define new layers. + */ +CoglHandle cogl_multi_texture_new (void); + +/** + * cogl_multi_texture_layer_set_texture: + * @multi_texture_handle: a @CoglHandle + * @layer: The index of the layer you want a handle for. + * + * A layer is implicitly created once you set a texture for a certain + * layer_index. The texture layers are blended together starting with + * the lowest index so the order is significant. It doesn't matter what + * order you create the layers in and you may use sparsely generated index + * values, it is only the relative index order that matters. + */ +void cogl_multi_texture_layer_set_texture (CoglHandle multi_texture_handle, + guint layer_index, + CoglHandle texture_handle); + +/** + * cogl_multi_texture_layer_remove: + * @multi_texture_handle: a @CoglHandle + * @index: The index of the layer you want to remove. + * + * Removes a single texture layer. + */ +void cogl_multi_texture_layer_remove (CoglHandle multi_texture_handle, + guint layer_index); + +/** + * cogl_multi_texture_rectangle: + * @handle: a @CoglHandle + * @x1: x coordinate upper left on screen. + * @y1: y coordinate upper left on screen. + * @x2: x coordinate lower right on screen. + * @y2: y coordinate lower right on screen. + * @texcoords: A multidimensional array containing sets of 4 texture + * coordinates - one set for each texture layer that has been created. + * + * Draw a rectangle combining multiple texture layers together + * where each layer can use different texture data and different texture + * coordinates. + * + * The texture coordinates are supplied as a contiguous array of + * CoglFixed items containing groups of [tx1, ty1, tx2, ty2] values + * that are interpreted in the same way as the corresponding arguments + * to cogl_texture_rectangle. The first group of coordinates are for the + * first layer (with the smallest layer_index) you _must_ supply as many + * groups of texture coordinates as you have layers. + */ +void cogl_multi_texture_rectangle (CoglHandle handle, + CoglFixed x1, + CoglFixed y1, + CoglFixed x2, + CoglFixed y2, + CoglFixed *tex_coords); + G_END_DECLS #endif /* __COGL_TEXTURE_H__ */ diff --git a/common/cogl-handle.h b/common/cogl-handle.h index 79deb7f8c..1cbb8a013 100644 --- a/common/cogl-handle.h +++ b/common/cogl-handle.h @@ -57,6 +57,12 @@ #define COGL_HANDLE_DEFINE(TypeName, type_name, handle_array) \ \ + static CoglHandle * \ + _cogl_##type_name##_handle_from_pointer (Cogl##TypeName *obj) \ + { \ + return (CoglHandle)obj; \ + } \ + \ static gint \ _cogl_##type_name##_handle_find (CoglHandle handle) \ { \ diff --git a/gl/cogl-context.c b/gl/cogl-context.c index d75086fbc..86a3d425a 100644 --- a/gl/cogl-context.c +++ b/gl/cogl-context.c @@ -58,6 +58,9 @@ cogl_create_context () _context->texture_handles = NULL; _context->texture_vertices_size = 0; _context->texture_vertices = NULL; + + _context->multi_texture_handles = NULL; + _context->multi_texture_layer_handles = NULL; _context->fbo_handles = NULL; _context->draw_buffer = COGL_WINDOW_BUFFER; diff --git a/gl/cogl-context.h b/gl/cogl-context.h index 8a2fc877d..afcf9c347 100644 --- a/gl/cogl-context.h +++ b/gl/cogl-context.h @@ -66,6 +66,12 @@ typedef struct CoglTextureGLVertex *texture_vertices; gulong texture_vertices_size; + /* Multi Textures */ + GArray *multi_texture_handles; + + /* Multi Texture Layers */ + GArray *multi_texture_layer_handles; + /* Framebuffer objects */ GArray *fbo_handles; CoglBufferTarget draw_buffer; diff --git a/gl/cogl-defines.h.in b/gl/cogl-defines.h.in index 480aafb0e..eea0f3d14 100644 --- a/gl/cogl-defines.h.in +++ b/gl/cogl-defines.h.in @@ -309,6 +309,7 @@ typedef GLuint COGLuint; #define CGL_MAX_TEXTURE_STACK_DEPTH GL_MAX_TEXTURE_STACK_DEPTH #define CGL_MAX_VIEWPORT_DIMS GL_MAX_VIEWPORT_DIMS #define CGL_MAX_CLIENT_ATTRIB_STACK_DEPTH GL_MAX_CLIENT_ATTRIB_STACK_DEPTH +#define CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS GL_MAX_TEXTURE_UNITS #define CGL_ATTRIB_STACK_DEPTH GL_ATTRIB_STACK_DEPTH #define CGL_CLIENT_ATTRIB_STACK_DEPTH GL_CLIENT_ATTRIB_STACK_DEPTH #define CGL_COLOR_CLEAR_VALUE GL_COLOR_CLEAR_VALUE diff --git a/gl/cogl-texture-private.h b/gl/cogl-texture-private.h index 117437458..b6c5af5ec 100644 --- a/gl/cogl-texture-private.h +++ b/gl/cogl-texture-private.h @@ -28,9 +28,11 @@ #include "cogl-bitmap.h" -typedef struct _CoglTexture CoglTexture; -typedef struct _CoglTexSliceSpan CoglTexSliceSpan; -typedef struct _CoglSpanIter CoglSpanIter; +typedef struct _CoglTexture CoglTexture; +typedef struct _CoglTexSliceSpan CoglTexSliceSpan; +typedef struct _CoglSpanIter CoglSpanIter; +typedef struct _CoglMultiTexture CoglMultiTexture; +typedef struct _CoglMultiTextureLayer CoglMultiTextureLayer; struct _CoglTexSliceSpan { @@ -59,6 +61,25 @@ struct _CoglTexture gboolean auto_mipmap; }; +struct _CoglMultiTextureLayer +{ + guint ref_count; + + guint index; /*!< lowest index is blended first then others + on top */ + CoglTexture *tex; /*!< The texture for this layer, or NULL + for an empty layer */ + + /* TODO: Add more control over the texture environment for each texture + * unit. For example we should support dot3 normal mapping. */ +}; + +struct _CoglMultiTexture +{ + guint ref_count; + GList *layers; +}; + CoglTexture* _cogl_texture_pointer_from_handle (CoglHandle handle); diff --git a/gl/cogl-texture.c b/gl/cogl-texture.c index 5a202ae6b..73478b8db 100644 --- a/gl/cogl-texture.c +++ b/gl/cogl-texture.c @@ -49,6 +49,16 @@ printf("err: 0x%x\n", err); \ } */ +static void _cogl_texture_free (CoglTexture *tex); +static void _cogl_multi_texture_free (CoglMultiTexture *multi_texture); +static void _cogl_multi_texture_layer_free (CoglMultiTextureLayer *layer); + +COGL_HANDLE_DEFINE (Texture, texture, texture_handles); +COGL_HANDLE_DEFINE (MultiTexture, multi_texture, multi_texture_handles); +COGL_HANDLE_DEFINE (MultiTextureLayer, + multi_texture_layer, + multi_texture_layer_handles); + struct _CoglSpanIter { gint index; @@ -66,11 +76,6 @@ struct _CoglSpanIter gboolean intersects; }; -static void _cogl_texture_free (CoglTexture *tex); - -COGL_HANDLE_DEFINE (Texture, texture, texture_handles); - - static void _cogl_texture_bitmap_free (CoglTexture *tex) { @@ -2405,3 +2410,263 @@ cogl_texture_polygon (CoglHandle handle, } } } + +CoglHandle +cogl_multi_texture_new (void) +{ + CoglMultiTexture *multi_tex = g_new0 (CoglMultiTexture, 1); + return _cogl_multi_texture_handle_new (multi_tex); +} + +static void +_cogl_multi_texture_free (CoglMultiTexture *multi_tex) +{ + g_list_foreach (multi_tex->layers, + (GFunc)cogl_multi_texture_layer_unref, NULL); + g_free (multi_tex); +} + +static CoglMultiTextureLayer * +_cogl_multi_texture_get_layer (CoglMultiTexture *multi_tex, guint index) +{ + CoglMultiTextureLayer *layer; + GList *tmp; + + for (tmp = multi_tex->layers; tmp != NULL; tmp = tmp->next) + { + layer = tmp->data; + if (layer->index == index) + return layer; + + /* The layers are always sorted, so we know this layer doesn't exists */ + if (layer->index > index) + break; + } + /* NB: if we now insert a new layer before tmp, that will maintain order. + */ + + layer = g_new (CoglMultiTextureLayer, 1); + + layer->ref_count = 1; + layer->index = index; + /* Note: comment after for() loop above */ + multi_tex->layers = g_list_insert_before (multi_tex->layers, tmp, layer); + + return layer; +} + +void +cogl_multi_texture_layer_set_texture (CoglHandle multi_texture_handle, + guint layer_index, + CoglHandle tex_handle) +{ + CoglMultiTexture *multi_tex; + CoglMultiTextureLayer *layer; + CoglTexture *tex; + + if (!cogl_is_multi_texture (multi_texture_handle) + || !cogl_is_texture (tex_handle)) + return; + + multi_tex = _cogl_multi_texture_pointer_from_handle (multi_texture_handle); + layer = _cogl_multi_texture_get_layer (multi_tex, layer_index); + tex = _cogl_texture_pointer_from_handle (tex_handle); + + cogl_texture_ref (tex_handle); + + layer->tex = tex; +} + +static void +_cogl_multi_texture_layer_free (CoglMultiTextureLayer *layer) +{ + cogl_texture_unref (layer->tex); + g_free (layer); +} + +void +cogl_multi_texture_layer_remove (CoglHandle multi_texture_handle, + guint layer_index) +{ + CoglMultiTexture *multi_tex; + CoglMultiTextureLayer *layer; + GList *tmp; + + /* Check if valid multi texture */ + if (!cogl_is_multi_texture (multi_texture_handle)) + return; + + multi_tex = _cogl_multi_texture_pointer_from_handle (multi_texture_handle); + for (tmp = multi_tex->layers; tmp != NULL; tmp = tmp->next) + { + layer = tmp->data; + if (layer->index == layer_index) + { + CoglHandle handle = + _cogl_multi_texture_layer_handle_from_pointer (layer); + cogl_multi_texture_layer_unref (handle); + multi_tex->layers = g_list_remove (multi_tex->layers, layer); + return; + } + } +} + +void +cogl_multi_texture_rectangle (CoglHandle multi_texture_handle, + CoglFixed x1, + CoglFixed y1, + CoglFixed x2, + CoglFixed y2, + CoglFixed *user_tex_coords) +{ + CoglMultiTexture *multi_tex; + GLfloat quad_coords[8]; + GList *tmp; + GList *valid_layers = NULL; + int count; + GLfloat *tex_coords_buff; + gulong enable_flags = 0; + /* FIXME - currently cogl deals with enabling texturing + * via enable flags, but that can't scale to n texture + * units. Currently we have to be carefull how we leave the + * environment so we don't break things. See the cleanup + * notes at the end of this function */ + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + /* Check if valid multi texture */ + if (!cogl_is_multi_texture (multi_texture_handle)) + return; + + multi_tex = _cogl_multi_texture_pointer_from_handle (multi_texture_handle); + +#define CFX_F COGL_FIXED_TO_FLOAT + quad_coords[0] = CFX_F (x1); + quad_coords[1] = CFX_F (y1); + quad_coords[2] = CFX_F (x2); + quad_coords[3] = CFX_F (y1); + quad_coords[4] = CFX_F (x1); + quad_coords[5] = CFX_F (y2); + quad_coords[6] = CFX_F (x2); + quad_coords[7] = CFX_F (y2); +#undef CFX_F + + enable_flags |= COGL_ENABLE_VERTEX_ARRAY; + GE( glVertexPointer (2, GL_FLOAT, 0, quad_coords)); + + for (count = 0, tmp = multi_tex->layers; + tmp != NULL; + count++, tmp = tmp->next) + { + CoglMultiTextureLayer *layer = tmp->data; + + /* Skip empty layers */ + if (!layer->tex) + { + count--; + continue; + } + + /* FIXME - currently we don't support sliced textures */ + if (layer->tex->slice_gl_handles == NULL + || layer->tex->slice_gl_handles->len < 1) + continue; + + if (count >= CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS) + { + static gboolean shown_warning = FALSE; + + if (!shown_warning) + { + g_warning ("Your driver does not support enough texture layers" + "to correctly handle this multi texturing"); + shown_warning = TRUE; + } + /* NB: We make a best effort attempt to display as many layers as + * possible. */ + break; + } + + if (layer->tex->bitmap.format & COGL_A_BIT) + enable_flags |= COGL_ENABLE_BLEND; + + valid_layers = g_list_prepend (valid_layers, layer); + } + valid_layers = g_list_reverse (valid_layers); + + /* Enable blending if the geometry has an associated alpha color, + * or - see above - we also check each layer texture and if any has + * an alpha channel also enable blending. */ + if (ctx->color_alpha < 255) + enable_flags |= COGL_ENABLE_BLEND; + cogl_enable (enable_flags); + + /* NB: It could be that no valid texture layers were found, but + * we will still submit a non-textured rectangle in that case. */ + if (count) + tex_coords_buff = alloca (sizeof(GLfloat) * 8 * count); + + /* NB: valid_layers is in order, sorted by index */ + for (count = 0, tmp = valid_layers; + tmp != NULL; + count++, tmp = tmp->next) + { + CoglMultiTextureLayer *layer = tmp->data; + CoglFixed *in_tex_coords = &user_tex_coords[count * 4]; + GLfloat *out_tex_coords = &tex_coords_buff[count * 8]; + GLenum gl_tex_handle; + +#define CFX_F COGL_FIXED_TO_FLOAT + /* IN LAYOUT: [ tx1:0, ty1:1, tx2:2, ty2:3 ] */ + out_tex_coords[0] = CFX_F (in_tex_coords[0]); /* tx1 */ + out_tex_coords[1] = CFX_F (in_tex_coords[1]); /* ty1 */ + out_tex_coords[2] = CFX_F (in_tex_coords[2]); /* tx2 */ + out_tex_coords[3] = CFX_F (in_tex_coords[1]); /* ty1 */ + out_tex_coords[4] = CFX_F (in_tex_coords[0]); /* tx1 */ + out_tex_coords[5] = CFX_F (in_tex_coords[3]); /* ty2 */ + out_tex_coords[6] = CFX_F (in_tex_coords[2]); /* tx2 */ + out_tex_coords[7] = CFX_F (in_tex_coords[3]); /* ty2 */ +#undef CFX_F + + /* TODO - support sliced textures */ + gl_tex_handle = g_array_index (layer->tex->slice_gl_handles, GLuint, 0); + + GE (glActiveTexture (GL_TEXTURE0 + count)); + GE (glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)); + GE (glBindTexture (GL_TEXTURE_2D, gl_tex_handle)); + /* GE (glEnable (GL_TEXTURE_2D)); */ + + GE (glClientActiveTexture (GL_TEXTURE0 + count)); + GE (glTexCoordPointer (2, GL_FLOAT, 0, out_tex_coords)); + /* GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY)); */ + + /* FIXME - cogl only knows about one texture unit a.t.m + * (Also see cleanup note below) */ + if (count == 0) + { + enable_flags |= COGL_ENABLE_TEXTURE_2D | COGL_ENABLE_TEXCOORD_ARRAY; + cogl_enable (enable_flags); + } + else + { + GE (glEnable (GL_TEXTURE_2D)); + GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY)); + } + } + + glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); + + /* FIXME - cogl doesn't currently have a way of caching the + * enable states for more than one texture unit so for now, + * we just disable anything relating to additional units once + * we are done with them. */ + while (--count > 0) + { + GE (glActiveTexture (GL_TEXTURE0 + count)); + GE (glClientActiveTexture (GL_TEXTURE0 + count)); + + GE (glDisable (GL_TEXTURE_2D)); + GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY)); + } +} + diff --git a/gles/cogl-context.c b/gles/cogl-context.c index c7c768dec..7b08576e7 100644 --- a/gles/cogl-context.c +++ b/gles/cogl-context.c @@ -61,7 +61,9 @@ cogl_create_context () _context->texture_handles = NULL; _context->texture_vertices_size = 0; _context->texture_vertices = NULL; - + _context->multi_texture_handles = NULL; + _context->multi_texture_layer_handles = NULL; + _context->fbo_handles = NULL; _context->program_handles = NULL; _context->shader_handles = NULL; diff --git a/gles/cogl-context.h b/gles/cogl-context.h index b62903efc..91fac2ee3 100644 --- a/gles/cogl-context.h +++ b/gles/cogl-context.h @@ -68,6 +68,12 @@ typedef struct CoglTextureGLVertex *texture_vertices; gulong texture_vertices_size; + /* Multi Textures */ + GArray *multi_texture_handles; + + /* Multi Texture Layers */ + GArray *multi_texture_layer_handles; + /* Framebuffer objects */ GArray *fbo_handles; CoglBufferTarget draw_buffer; diff --git a/gles/cogl-defines.h.in b/gles/cogl-defines.h.in index b3cd355d6..3d69a080e 100644 --- a/gles/cogl-defines.h.in +++ b/gles/cogl-defines.h.in @@ -162,7 +162,11 @@ G_BEGIN_DECLS #define CGL_STENCIL_PASS_DEPTH_PASS GL_STENCIL_PASS_DEPTH_PASS #define CGL_STENCIL_REF GL_STENCIL_REF #define CGL_STENCIL_WRITEMASK GL_STENCIL_WRITEMASK +#ifdef HAVE_COGL_GLES2 +#define CGL_MATRIX_MODE 0x0BA0 /* bad style but works for now */ +#else #define CGL_MATRIX_MODE GL_MATRIX_MODE +#endif #define CGL_VIEWPORT GL_VIEWPORT #define CGL_MODELVIEW_STACK_DEPTH GL_MODELVIEW_STACK_DEPTH #define CGL_PROJECTION_STACK_DEPTH GL_PROJECTION_STACK_DEPTH @@ -190,7 +194,11 @@ G_BEGIN_DECLS #define CGL_MAX_VIEWPORT_DIMS GL_MAX_VIEWPORT_DIMS #define CGL_MAX_ELEMENTS_VERTICES GL_MAX_ELEMENTS_VERTICES #define CGL_MAX_ELEMENTS_INDICES GL_MAX_ELEMENTS_INDICES -#define CGL_MAX_TEXTURE_UNITS GL_MAX_TEXTURE_UNITS +#ifdef HAVE_COGL_GLES2 +#define CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS +#else +#define CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS GL_MAX_TEXTURE_UNITS +#endif #define CGL_SUBPIXEL_BITS GL_SUBPIXEL_BITS #define CGL_RED_BITS GL_RED_BITS #define CGL_GREEN_BITS GL_GREEN_BITS @@ -315,7 +323,7 @@ G_BEGIN_DECLS /* PixelType */ /* GL_UNSIGNED_BYTE */ -#define CGL_UNSIGNED_SHORT_4_4_4_4 GL_UNSIGNED_SHORT_4_4_4_4 +#define CGL_UNSIGNED_SHORT_4_4_4_4 GL_UNSIGNED_SHORT_4_4_4_4 #define CGL_UNSIGNED_SHORT_5_5_5_1 GL_UNSIGNED_SHORT_5_5_5_1 #define CGL_UNSIGNED_SHORT_5_6_5 CGL_UNSIGNED_SHORT_5_6_5 diff --git a/gles/cogl-fixed-fragment-shader.glsl b/gles/cogl-fixed-fragment-shader.glsl index 2a5c7b676..128afb42e 100644 --- a/gles/cogl-fixed-fragment-shader.glsl +++ b/gles/cogl-fixed-fragment-shader.glsl @@ -1,16 +1,20 @@ -/*** cogl_fixed_fragment_shader_start ***/ +/*** cogl_fixed_fragment_shader_variables_start ***/ /* There is no default precision for floats in fragment shaders in GLES 2 so we need to define one */ -precision mediump float; +precision highp float; + +/*** cogl_fixed_fragment_shader_inputs ***/ /* Inputs from the vertex shader */ varying vec4 frag_color; -varying vec2 tex_coord; varying float fog_amount; +/*** cogl_fixed_fragment_shader_texturing_options ***/ + /* Texturing options */ -uniform sampler2D texture_unit; + +/*** cogl_fixed_fragment_shader_fogging_options ***/ /* Fogging options */ uniform vec4 fog_color; @@ -18,28 +22,13 @@ uniform vec4 fog_color; /* Alpha test options */ uniform float alpha_test_ref; +/*** cogl_fixed_fragment_shader_main_declare ***/ + void main (void) { - /*** cogl_fixed_fragment_shader_texture_alpha_only ***/ + /*** cogl_fixed_fragment_shader_main_start ***/ - /* If the texture only has an alpha channel (eg, with the textures - from the pango renderer) then the RGB components will be - black. We want to use the RGB from the current color in that - case */ - gl_FragColor = frag_color; - gl_FragColor.a *= texture2D (texture_unit, tex_coord).a; - - /*** cogl_fixed_fragment_shader_texture ***/ - - /* This pointless extra variable is needed to work around an - apparent bug in the PowerVR drivers. Without it the alpha - blending seems to stop working */ - vec4 frag_color_copy = frag_color; - gl_FragColor = frag_color_copy * texture2D (texture_unit, tex_coord); - - /*** cogl_fixed_fragment_shader_solid_color ***/ - gl_FragColor = frag_color; /*** cogl_fixed_fragment_shader_fog ***/ diff --git a/gles/cogl-fixed-vertex-shader.glsl b/gles/cogl-fixed-vertex-shader.glsl index 050f7dea4..e5d30a644 100644 --- a/gles/cogl-fixed-vertex-shader.glsl +++ b/gles/cogl-fixed-vertex-shader.glsl @@ -1,34 +1,41 @@ -/*** cogl_fixed_vertex_shader_start ***/ +/*** cogl_fixed_vertex_shader_per_vertex_attribs ***/ /* Per vertex attributes */ attribute vec4 vertex_attrib; -attribute vec4 tex_coord_attrib; attribute vec4 color_attrib; +/*** cogl_fixed_vertex_shader_transform_matrices ***/ + /* Transformation matrices */ uniform mat4 modelview_matrix; uniform mat4 mvp_matrix; /* combined modelview and projection matrix */ -uniform mat4 texture_matrix; + +/*** cogl_fixed_vertex_shader_output_variables ***/ /* Outputs to the fragment shader */ varying vec4 frag_color; -varying vec2 tex_coord; varying float fog_amount; +/*** cogl_fixed_vertex_shader_fogging_options ***/ + /* Fogging options */ uniform float fog_density; uniform float fog_start; uniform float fog_end; +/*** cogl_fixed_vertex_shader_main_start ***/ + void main (void) { + vec4 transformed_tex_coord; + /* Calculate the transformed position */ gl_Position = mvp_matrix * vertex_attrib; /* Calculate the transformed texture coordinate */ - vec4 transformed_tex_coord = texture_matrix * tex_coord_attrib; - tex_coord = transformed_tex_coord.st / transformed_tex_coord.q; + + /*** cogl_fixed_vertex_shader_frag_color_start ***/ /* Pass the interpolated vertex color on to the fragment shader */ frag_color = color_attrib; diff --git a/gles/cogl-gles2-wrapper.c b/gles/cogl-gles2-wrapper.c index fea76500e..f3ef6355b 100644 --- a/gles/cogl-gles2-wrapper.c +++ b/gles/cogl-gles2-wrapper.c @@ -38,6 +38,7 @@ #include "cogl-context.h" #include "cogl-shader-private.h" #include "cogl-program.h" +#include "cogl-internal.h" #define _COGL_GET_GLES2_WRAPPER(wvar, retval) \ CoglGles2Wrapper *wvar; \ @@ -66,9 +67,9 @@ while (0) #define COGL_GLES2_WRAPPER_VERTEX_ATTRIB 0 -#define COGL_GLES2_WRAPPER_TEX_COORD_ATTRIB 1 -#define COGL_GLES2_WRAPPER_COLOR_ATTRIB 2 -#define COGL_GLES2_WRAPPER_NORMAL_ATTRIB 3 +#define COGL_GLES2_WRAPPER_COLOR_ATTRIB 1 +#define COGL_GLES2_WRAPPER_NORMAL_ATTRIB 2 + static GLuint cogl_gles2_wrapper_create_shader (GLenum type, const char *source) @@ -109,13 +110,19 @@ cogl_gles2_wrapper_init (CoglGles2Wrapper *wrapper) memset (wrapper, 0, sizeof (CoglGles2Wrapper)); /* Initialize the stacks */ - cogl_wrap_glMatrixMode (GL_TEXTURE); - cogl_wrap_glLoadIdentity (); cogl_wrap_glMatrixMode (GL_PROJECTION); cogl_wrap_glLoadIdentity (); cogl_wrap_glMatrixMode (GL_MODELVIEW); cogl_wrap_glLoadIdentity (); + wrapper->texture_units = + g_array_new (FALSE, FALSE, sizeof (CoglGles2WrapperTextureUnit *)); + + /* The gl*ActiveTexture wrappers will initialise the texture + * stack for the texture unit when it's first activated */ + cogl_wrap_glActiveTexture (GL_TEXTURE0); + cogl_wrap_glClientActiveTexture (GL_TEXTURE0); + /* Initialize the fogging options */ cogl_wrap_glDisable (GL_FOG); cogl_wrap_glFogx (GL_FOG_MODE, GL_LINEAR); @@ -137,11 +144,14 @@ cogl_gles2_settings_equal (const CoglGles2WrapperSettings *a, { if (fragment_tests) { - if (a->texture_2d_enabled != b->texture_2d_enabled) - return FALSE; - - if (a->texture_2d_enabled && a->alpha_only != b->alpha_only) - return FALSE; + int i; + for (i = 0; i < a->n_texture_units; i++) + { + if (a->texture_units[i].enabled != b->texture_units[i].enabled) + return FALSE; + if (a->texture_units[i].alpha_only != b->texture_units[i].alpha_only) + return FALSE; + } if (a->alpha_test_enabled != b->alpha_test_enabled) return FALSE; @@ -165,6 +175,7 @@ cogl_gles2_get_vertex_shader (const CoglGles2WrapperSettings *settings) GLuint shader_obj; CoglGles2WrapperShader *shader; GSList *node; + int i; _COGL_GET_GLES2_WRAPPER (w, NULL); @@ -177,7 +188,47 @@ cogl_gles2_get_vertex_shader (const CoglGles2WrapperSettings *settings) return (CoglGles2WrapperShader *) node->data; /* Otherwise create a new shader */ - shader_source = g_string_new (cogl_fixed_vertex_shader_start); + shader_source = g_string_new (cogl_fixed_vertex_shader_per_vertex_attribs); + + for (i = 0; i < settings->n_texture_units; i++) + { + if (!settings->texture_units[i].enabled) + continue; + g_string_append_printf (shader_source, + "attribute vec4 multi_tex_coord_attrib%d;\n", + i); + } + + g_string_append (shader_source, cogl_fixed_vertex_shader_transform_matrices); + g_string_append_printf (shader_source, + "uniform mat4 texture_matrix[%d];\n", + settings->n_texture_units); + + g_string_append (shader_source, cogl_fixed_vertex_shader_output_variables); + g_string_append_printf (shader_source, + "varying vec2 tex_coord[%d];", + settings->n_texture_units); + + g_string_append (shader_source, cogl_fixed_vertex_shader_fogging_options); + g_string_append (shader_source, cogl_fixed_vertex_shader_main_start); + + for (i = 0; i < settings->n_texture_units; i++) + { + if (!settings->texture_units[i].enabled) + continue; + + g_string_append_printf (shader_source, + "transformed_tex_coord = " + "texture_matrix[%d] " + " * multi_tex_coord_attrib%d;\n", + i, i); + g_string_append_printf (shader_source, + "tex_coord[%d] = transformed_tex_coord.st " + " / transformed_tex_coord.q;\n", + i); + } + + g_string_append (shader_source, cogl_fixed_vertex_shader_frag_color_start); if (settings->fog_enabled) { @@ -207,10 +258,10 @@ cogl_gles2_get_vertex_shader (const CoglGles2WrapperSettings *settings) shader_source->str); g_string_free (shader_source, TRUE); - + if (shader_obj == 0) return NULL; - + shader = g_slice_new (CoglGles2WrapperShader); shader->shader = shader_obj; shader->settings = *settings; @@ -228,6 +279,7 @@ cogl_gles2_get_fragment_shader (const CoglGles2WrapperSettings *settings) GLuint shader_obj; CoglGles2WrapperShader *shader; GSList *node; + int i; _COGL_GET_GLES2_WRAPPER (w, NULL); @@ -240,18 +292,61 @@ cogl_gles2_get_fragment_shader (const CoglGles2WrapperSettings *settings) return (CoglGles2WrapperShader *) node->data; /* Otherwise create a new shader */ - shader_source = g_string_new (cogl_fixed_fragment_shader_start); - if (settings->texture_2d_enabled) + shader_source = g_string_new (cogl_fixed_fragment_shader_variables_start); + + g_string_append (shader_source, cogl_fixed_fragment_shader_inputs); + g_string_append_printf (shader_source, + "varying vec2 tex_coord[%d];\n", + settings->n_texture_units); + + g_string_append (shader_source, cogl_fixed_fragment_shader_texturing_options); + g_string_append_printf (shader_source, + "uniform sampler2D texture_unit[%d];\n", + settings->n_texture_units); + + g_string_append (shader_source, cogl_fixed_fragment_shader_fogging_options); + + g_string_append (shader_source, cogl_fixed_fragment_shader_main_declare); + + g_string_append (shader_source, cogl_fixed_fragment_shader_main_start); + + /* This pointless extra variable is needed to work around an + apparent bug in the PowerVR drivers. Without it the alpha + blending seems to stop working */ + /* g_string_append (shader_source, "gl_FragColor = frag_color;\n"); + */ + g_string_append (shader_source, + "vec4 frag_color_copy = frag_color;\n"); + g_string_append (shader_source, "gl_FragColor = frag_color;\n"); + + for (i = 0; i < settings->n_texture_units; i++) { - if (settings->alpha_only) - g_string_append (shader_source, - cogl_fixed_fragment_shader_texture_alpha_only); + if (settings->texture_units[i].alpha_only) + { + /* If the texture only has an alpha channel (eg, with the textures + from the pango renderer) then the RGB components will be + black. We want to use the RGB from the current color in that + case */ + g_string_append_printf ( + shader_source, + "gl_FragColor.a *= " + "texture2D (texture_unit[%d], tex_coord[%d]).a;\n", + i, i); + } else - g_string_append (shader_source, - cogl_fixed_fragment_shader_texture); + { + g_string_append_printf ( + shader_source, + "gl_FragColor *= " + "texture2D (texture_unit[%d], tex_coord[%d]);\n", + i, i); + } } - else - g_string_append (shader_source, cogl_fixed_fragment_shader_solid_color); + /* FIXME */ + g_string_append (shader_source, "gl_FragColor.r = 1.0;\n"); + g_string_append (shader_source, "gl_FragColor.g = 1.0;\n"); + if (i == 0) + g_string_append (shader_source, "gl_FragColor = frag_color;\n"); if (settings->fog_enabled) g_string_append (shader_source, cogl_fixed_fragment_shader_fog); @@ -294,10 +389,10 @@ cogl_gles2_get_fragment_shader (const CoglGles2WrapperSettings *settings) shader_source->str); g_string_free (shader_source, TRUE); - + if (shader_obj == 0) return NULL; - + shader = g_slice_new (CoglGles2WrapperShader); shader->shader = shader_obj; shader->settings = *settings; @@ -308,6 +403,69 @@ cogl_gles2_get_fragment_shader (const CoglGles2WrapperSettings *settings) return shader; } +static void +cogl_gles2_wrapper_get_locations (GLuint program, + CoglGles2WrapperSettings *settings, + CoglGles2WrapperUniforms *uniforms, + CoglGles2WrapperAttributes *attribs) +{ + int i; + + uniforms->mvp_matrix_uniform + = glGetUniformLocation (program, "mvp_matrix"); + uniforms->modelview_matrix_uniform + = glGetUniformLocation (program, "modelview_matrix"); + + uniforms->texture_matrix_uniforms = + g_array_new (FALSE, FALSE, sizeof (GLint)); + uniforms->texture_sampler_uniforms = + g_array_new (FALSE, FALSE, sizeof (GLint)); + attribs->multi_texture_coords = + g_array_new (FALSE, FALSE, sizeof (GLint)); + for (i = 0; i < settings->n_texture_units; i++) + { + char *matrix_var_name = g_strdup_printf ("texture_matrix[%d]", i); + char *sampler_var_name = g_strdup_printf ("texture_unit[%d]", i); + char *tex_coord_var_name = + g_strdup_printf ("multi_tex_coord_attrib%d", i); + GLint location; + + location = glGetUniformLocation (program, matrix_var_name); + g_array_append_val (uniforms->texture_matrix_uniforms, location); + location = glGetUniformLocation (program, sampler_var_name); + g_array_append_val (uniforms->texture_sampler_uniforms, location); + location = glGetAttribLocation (program, tex_coord_var_name); + g_array_append_val (attribs->multi_texture_coords, location); + + g_free (tex_coord_var_name); + g_free (sampler_var_name); + g_free (matrix_var_name); + } + + uniforms->fog_density_uniform + = glGetUniformLocation (program, "fog_density"); + uniforms->fog_start_uniform + = glGetUniformLocation (program, "fog_start"); + uniforms->fog_end_uniform + = glGetUniformLocation (program, "fog_end"); + uniforms->fog_color_uniform + = glGetUniformLocation (program, "fog_color"); + + uniforms->alpha_test_ref_uniform + = glGetUniformLocation (program, "alpha_test_ref"); +} + +static void +cogl_gles2_wrapper_bind_attributes (GLuint program) +{ + glBindAttribLocation (program, COGL_GLES2_WRAPPER_VERTEX_ATTRIB, + "vertex_attrib"); + glBindAttribLocation (program, COGL_GLES2_WRAPPER_COLOR_ATTRIB, + "color_attrib"); + glBindAttribLocation (program, COGL_GLES2_WRAPPER_NORMAL_ATTRIB, + "normal_attrib"); +} + static CoglGles2WrapperProgram * cogl_gles2_wrapper_get_program (const CoglGles2WrapperSettings *settings) { @@ -403,61 +561,22 @@ cogl_gles2_wrapper_get_program (const CoglGles2WrapperSettings *settings) } program->settings = *settings; - - cogl_gles2_wrapper_get_uniforms (program->program, &program->uniforms); + + cogl_gles2_wrapper_get_locations (program->program, + &program->settings, + &program->uniforms, + &program->attributes); /* We haven't tried to get a location for any of the custom uniforms yet */ for (i = 0; i < COGL_GLES2_NUM_CUSTOM_UNIFORMS; i++) program->custom_uniforms[i] = COGL_GLES2_UNBOUND_CUSTOM_UNIFORM; - + w->compiled_programs = g_slist_append (w->compiled_programs, program); - + return program; } -void -cogl_gles2_wrapper_bind_attributes (GLuint program) -{ - glBindAttribLocation (program, COGL_GLES2_WRAPPER_VERTEX_ATTRIB, - "vertex_attrib"); - glBindAttribLocation (program, COGL_GLES2_WRAPPER_TEX_COORD_ATTRIB, - "tex_coord_attrib"); - glBindAttribLocation (program, COGL_GLES2_WRAPPER_COLOR_ATTRIB, - "color_attrib"); - glBindAttribLocation (program, COGL_GLES2_WRAPPER_NORMAL_ATTRIB, - "normal_attrib"); -} - -void -cogl_gles2_wrapper_get_uniforms (GLuint program, - CoglGles2WrapperUniforms *uniforms) -{ - uniforms->mvp_matrix_uniform - = glGetUniformLocation (program, "mvp_matrix"); - uniforms->modelview_matrix_uniform - = glGetUniformLocation (program, "modelview_matrix"); - uniforms->texture_matrix_uniform - = glGetUniformLocation (program, "texture_matrix"); - uniforms->bound_texture_uniform - = glGetUniformLocation (program, "texture_unit"); - - uniforms->fog_density_uniform - = glGetUniformLocation (program, "fog_density"); - uniforms->fog_start_uniform - = glGetUniformLocation (program, "fog_start"); - uniforms->fog_end_uniform - = glGetUniformLocation (program, "fog_end"); - uniforms->fog_color_uniform - = glGetUniformLocation (program, "fog_color"); - - uniforms->alpha_test_ref_uniform - = glGetUniformLocation (program, "alpha_test_ref"); - - uniforms->texture_unit_uniform - = glGetUniformLocation (program, "texture_unit"); -} - void cogl_gles2_wrapper_deinit (CoglGles2Wrapper *wrapper) { @@ -493,9 +612,11 @@ cogl_gles2_wrapper_deinit (CoglGles2Wrapper *wrapper) g_free (wrapper->custom_uniforms[i].v.array); } -void +static void cogl_gles2_wrapper_update_matrix (CoglGles2Wrapper *wrapper, GLenum matrix_num) { + CoglGles2WrapperTextureUnit *texture_unit; + switch (matrix_num) { default: @@ -509,7 +630,11 @@ cogl_gles2_wrapper_update_matrix (CoglGles2Wrapper *wrapper, GLenum matrix_num) break; case GL_TEXTURE: - wrapper->dirty_uniforms |= COGL_GLES2_DIRTY_TEXTURE_MATRIX; + wrapper->dirty_uniforms |= COGL_GLES2_DIRTY_TEXTURE_MATRICES; + texture_unit = g_array_index (wrapper->texture_units, + CoglGles2WrapperTextureUnit *, + wrapper->active_texture_unit); + texture_unit->dirty_matrix = 1; break; } } @@ -551,11 +676,19 @@ cogl_wrap_glPushMatrix () break; case GL_TEXTURE: - src = w->texture_stack + w->texture_stack_pos * 16; - w->texture_stack_pos = (w->texture_stack_pos + 1) - & (COGL_GLES2_TEXTURE_STACK_SIZE - 1); - dst = w->texture_stack + w->texture_stack_pos * 16; - break; + { + CoglGles2WrapperTextureUnit *texture_unit; + texture_unit = g_array_index (w->texture_units, + CoglGles2WrapperTextureUnit *, + w->active_texture_unit); + src = texture_unit->texture_stack + + texture_unit->texture_stack_pos * 16; + texture_unit->texture_stack_pos = (texture_unit->texture_stack_pos + 1) + & (COGL_GLES2_TEXTURE_STACK_SIZE - 1); + dst = texture_unit->texture_stack + + texture_unit->texture_stack_pos * 16; + break; + } } /* Copy the old matrix to the new position */ @@ -565,6 +698,7 @@ cogl_wrap_glPushMatrix () void cogl_wrap_glPopMatrix () { + CoglGles2WrapperTextureUnit *texture_unit; _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL); /* Decrement the stack pointer */ @@ -582,7 +716,10 @@ cogl_wrap_glPopMatrix () break; case GL_TEXTURE: - w->texture_stack_pos = (w->texture_stack_pos - 1) + texture_unit = g_array_index (w->texture_units, + CoglGles2WrapperTextureUnit *, + w->active_texture_unit); + texture_unit->texture_stack_pos = (texture_unit->texture_stack_pos - 1) & (COGL_GLES2_TEXTURE_STACK_SIZE - 1); break; } @@ -602,6 +739,8 @@ cogl_wrap_glMatrixMode (GLenum mode) static float * cogl_gles2_get_matrix_stack_top (CoglGles2Wrapper *wrapper) { + CoglGles2WrapperTextureUnit *texture_unit; + switch (wrapper->matrix_mode) { default: @@ -612,7 +751,12 @@ cogl_gles2_get_matrix_stack_top (CoglGles2Wrapper *wrapper) return wrapper->projection_stack + wrapper->projection_stack_pos * 16; case GL_TEXTURE: - return wrapper->texture_stack + wrapper->texture_stack_pos * 16; + + texture_unit = g_array_index (wrapper->texture_units, + CoglGles2WrapperTextureUnit *, + wrapper->active_texture_unit); + return texture_unit->texture_stack + + texture_unit->texture_stack_pos * 16; } } @@ -743,7 +887,7 @@ cogl_wrap_glRotatex (GLfixed angle, GLfixed x, GLfixed y, GLfixed z) float anglef = COGL_FIXED_TO_FLOAT (angle) * G_PI / 180.0f; float c = cosf (anglef); float s = sinf (anglef); - + matrix[0] = xf * xf * (1.0f - c) + c; matrix[1] = yf * xf * (1.0f - c) + zf * s; matrix[2] = xf * zf * (1.0f - c) - yf * s; @@ -800,8 +944,22 @@ void cogl_wrap_glTexCoordPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) { - glVertexAttribPointer (COGL_GLES2_WRAPPER_TEX_COORD_ATTRIB, size, type, - GL_FALSE, stride, pointer); + int active_unit; + CoglGles2WrapperTextureUnit *texture_unit; + _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL); + + active_unit = w->active_client_texture_unit; + + texture_unit = g_array_index (w->texture_units, + CoglGles2WrapperTextureUnit *, + active_unit); + texture_unit->texture_coords_size = size; + texture_unit->texture_coords_type = type; + texture_unit->texture_coords_stride = stride; + texture_unit->texture_coords_pointer = pointer; + + w->dirty_attribute_pointers + |= COGL_GLES2_DIRTY_TEX_COORD_VERTEX_ATTRIB; } void @@ -935,7 +1093,7 @@ cogl_wrap_glDrawArrays (GLenum mode, GLint first, GLsizei count) cogl_gles2_wrapper_mult_matrix (mvp_matrix, w->projection_stack + w->projection_stack_pos * 16, - modelview_matrix); + modelview_matrix); if (program->uniforms.mvp_matrix_uniform != -1) glUniformMatrix4fv (program->uniforms.mvp_matrix_uniform, 1, @@ -944,11 +1102,28 @@ cogl_wrap_glDrawArrays (GLenum mode, GLint first, GLsizei count) glUniformMatrix4fv (program->uniforms.modelview_matrix_uniform, 1, GL_FALSE, modelview_matrix); } - if ((w->dirty_uniforms & COGL_GLES2_DIRTY_TEXTURE_MATRIX) - && program->uniforms.texture_matrix_uniform != -1) - glUniformMatrix4fv (program->uniforms.texture_matrix_uniform, 1, - GL_FALSE, - w->texture_stack + w->texture_stack_pos * 16); + if ((w->dirty_uniforms & COGL_GLES2_DIRTY_TEXTURE_MATRICES)) + { + int i; + + /* TODO - we should probably have a per unit dirty flag too */ + + for (i = 0; i < program->uniforms.texture_matrix_uniforms->len; i++) + { + CoglGles2WrapperTextureUnit *texture_unit; + GLint uniform = + g_array_index (program->uniforms.texture_matrix_uniforms, + GLint, i); + + texture_unit = g_array_index (w->texture_units, + CoglGles2WrapperTextureUnit *, + i); + if (uniform != -1) + glUniformMatrix4fv (uniform, 1, GL_FALSE, + texture_unit->texture_stack + + texture_unit->texture_stack_pos * 16); + } + } if ((w->dirty_uniforms & COGL_GLES2_DIRTY_FOG_DENSITY) && program->uniforms.fog_density_uniform != -1) @@ -965,9 +1140,22 @@ cogl_wrap_glDrawArrays (GLenum mode, GLint first, GLsizei count) glUniform1f (program->uniforms.alpha_test_ref_uniform, w->alpha_test_ref); - if ((w->dirty_uniforms & COGL_GLES2_DIRTY_TEXTURE_UNIT) - && program->uniforms.texture_unit_uniform != -1) - glUniform1i (program->uniforms.texture_unit_uniform, 0); + if ((w->dirty_uniforms & COGL_GLES2_DIRTY_TEXTURE_UNITS)) + { + int i; + + /* TODO - we should probably have a per unit dirty flag too */ + + for (i = 0; i < program->uniforms.texture_sampler_uniforms->len; i++) + { + GLint uniform = + g_array_index (program->uniforms.texture_sampler_uniforms, + GLint, i); + + if (uniform != -1) + glUniform1i (uniform, i); + } + } w->dirty_uniforms = 0; } @@ -995,10 +1183,70 @@ cogl_wrap_glDrawArrays (GLenum mode, GLint first, GLsizei count) &w->custom_uniforms[i]); } } - + w->dirty_custom_uniforms = 0; } + if (w->dirty_attribute_pointers + & COGL_GLES2_DIRTY_TEX_COORD_VERTEX_ATTRIB) + { + int i; + + /* TODO - coverage test */ + for (i = 0; i < w->settings.n_texture_units; i++) + { + GLint tex_coord_var_index; + CoglGles2WrapperTextureUnit *texture_unit; + + if (!w->settings.texture_units[i].enabled) + continue; + + texture_unit = g_array_index (w->texture_units, + CoglGles2WrapperTextureUnit *, + w->active_texture_unit); + if (!texture_unit->texture_coords_enabled) + continue; + + /* TODO - we should probably have a per unit dirty flag too */ + + /* TODO - coverage test */ + tex_coord_var_index = + g_array_index (program->attributes.multi_texture_coords, + GLint, i); + glVertexAttribPointer (tex_coord_var_index, + texture_unit->texture_coords_size, + texture_unit->texture_coords_type, + GL_FALSE, + texture_unit->texture_coords_stride, + texture_unit->texture_coords_pointer); + } + } + + if (w->dirty_vertex_attrib_enables) + { + int i; + + /* TODO - coverage test */ + + /* TODO - we should probably have a per unit dirty flag too */ + + for (i = 0; i < w->texture_units->len; i++) + { + CoglGles2WrapperTextureUnit *texture_unit = + g_array_index (w->texture_units, + CoglGles2WrapperTextureUnit *, + w->active_texture_unit); + if (texture_unit->texture_coords_enabled) + glEnableVertexAttribArray ( + g_array_index (program->attributes.multi_texture_coords, + GLint, i)); + else + glDisableVertexAttribArray ( + g_array_index (program->attributes.multi_texture_coords, + GLint, i)); + w->dirty_vertex_attrib_enables = 0; + } + } glDrawArrays (mode, first, count); } @@ -1013,7 +1261,10 @@ cogl_gles2_wrapper_bind_texture (GLenum target, GLuint texture, /* We need to keep track of whether the texture is alpha-only because the emulation of GL_MODULATE needs to work differently in that case */ - _COGL_GLES2_CHANGE_SETTING (w, alpha_only, internal_format == GL_ALPHA); + _COGL_GLES2_CHANGE_SETTING ( + w, texture_units[w->active_texture_unit].alpha_only, + internal_format == GL_ALPHA); + } void @@ -1024,6 +1275,79 @@ cogl_wrap_glTexEnvx (GLenum target, GLenum pname, GLfixed param) nothing needs to be done here. */ } +static void +realize_texture_units (CoglGles2Wrapper *w, int texture_unit_index) +{ + /* We save the active texture unit since we may need to temporarily + * change this to initialise each new texture unit and we want to + * restore the active unit afterwards */ + int initial_active_unit = w->active_texture_unit; + + if (texture_unit_index >= w->settings.n_texture_units) + { + int n_new_texture_units = + texture_unit_index + 1 - w->settings.n_texture_units; + GLint prev_mode; + int i; + + w->settings.texture_units = + g_realloc (w->settings.texture_units, + texture_unit_index + 1 + * sizeof (CoglGles2WrapperTextureUnitSettings)); + + /* We will need to set the matrix mode to GL_TEXTURE to + * initialise any new texture units, so we save the current + * mode for restoring afterwards */ + GE( cogl_wrap_glGetIntegerv (CGL_MATRIX_MODE, &prev_mode)); + + for (i = 0; i < n_new_texture_units; i++) + { + CoglGles2WrapperTextureUnit *new_unit; + CoglGles2WrapperTextureUnitSettings *new_unit_settings; + + new_unit = g_new0 (CoglGles2WrapperTextureUnit, 1); + g_array_append_val (w->texture_units, new_unit); + + w->active_texture_unit = i; + GE( cogl_wrap_glMatrixMode (GL_TEXTURE)); + GE( cogl_wrap_glLoadIdentity ()); + + new_unit_settings = + &w->settings.texture_units[w->settings.n_texture_units + i]; + new_unit_settings->enabled = FALSE; + new_unit_settings->alpha_only = FALSE; + } + + GE( cogl_wrap_glMatrixMode ((GLenum)prev_mode)); + + w->settings.n_texture_units = w->texture_units->len; + } + + w->active_texture_unit = initial_active_unit; +} + +void +cogl_wrap_glClientActiveTexture (GLenum texture) +{ + int texture_unit_index = texture - GL_TEXTURE0; + _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL); + + w->active_client_texture_unit = texture_unit_index; + + realize_texture_units (w, texture_unit_index); +} + +void +cogl_wrap_glActiveTexture (GLenum texture) +{ + int texture_unit_index = texture - GL_TEXTURE0; + _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL); + + w->active_texture_unit = texture_unit_index; + + realize_texture_units (w, texture_unit_index); +} + void cogl_wrap_glEnable (GLenum cap) { @@ -1032,7 +1356,8 @@ cogl_wrap_glEnable (GLenum cap) switch (cap) { case GL_TEXTURE_2D: - _COGL_GLES2_CHANGE_SETTING (w, texture_2d_enabled, TRUE); + _COGL_GLES2_CHANGE_SETTING ( + w, texture_units[w->active_texture_unit].enabled, TRUE); break; case GL_FOG: @@ -1056,7 +1381,8 @@ cogl_wrap_glDisable (GLenum cap) switch (cap) { case GL_TEXTURE_2D: - _COGL_GLES2_CHANGE_SETTING (w, texture_2d_enabled, FALSE); + _COGL_GLES2_CHANGE_SETTING ( + w, texture_units[w->active_texture_unit].enabled, FALSE); break; case GL_FOG: @@ -1075,13 +1401,26 @@ cogl_wrap_glDisable (GLenum cap) void cogl_wrap_glEnableClientState (GLenum array) { + CoglGles2WrapperTextureUnit *texture_unit; + _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL); + switch (array) { case GL_VERTEX_ARRAY: glEnableVertexAttribArray (COGL_GLES2_WRAPPER_VERTEX_ATTRIB); break; case GL_TEXTURE_COORD_ARRAY: - glEnableVertexAttribArray (COGL_GLES2_WRAPPER_TEX_COORD_ATTRIB); + /* TODO - review if this should be in w->settings? */ + + texture_unit = g_array_index (w->texture_units, + CoglGles2WrapperTextureUnit *, + w->active_texture_unit); + if (texture_unit->texture_coords_enabled != 1) + { + texture_unit->texture_coords_enabled = 1; + w->dirty_vertex_attrib_enables + |= COGL_GLES2_DIRTY_TEX_COORD_ATTRIB_ENABLES; + } break; case GL_COLOR_ARRAY: glEnableVertexAttribArray (COGL_GLES2_WRAPPER_COLOR_ATTRIB); @@ -1095,13 +1434,26 @@ cogl_wrap_glEnableClientState (GLenum array) void cogl_wrap_glDisableClientState (GLenum array) { + CoglGles2WrapperTextureUnit *texture_unit; + _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL); + switch (array) { case GL_VERTEX_ARRAY: glDisableVertexAttribArray (COGL_GLES2_WRAPPER_VERTEX_ATTRIB); break; case GL_TEXTURE_COORD_ARRAY: - glDisableVertexAttribArray (COGL_GLES2_WRAPPER_TEX_COORD_ATTRIB); + + texture_unit = g_array_index (w->texture_units, + CoglGles2WrapperTextureUnit *, + w->active_texture_unit); + /* TODO - review if this should be in w->settings? */ + if (texture_unit->texture_coords_enabled != 0) + { + texture_unit->texture_coords_enabled = 0; + w->dirty_vertex_attrib_enables + |= COGL_GLES2_DIRTY_TEX_COORD_ATTRIB_ENABLES; + } break; case GL_COLOR_ARRAY: glDisableVertexAttribArray (COGL_GLES2_WRAPPER_COLOR_ATTRIB); @@ -1162,6 +1514,10 @@ cogl_wrap_glGetIntegerv (GLenum pname, GLint *params) *params = 0; break; + case CGL_MATRIX_MODE: + *params = w->matrix_mode; + break; + default: glGetIntegerv (pname, params); break; @@ -1208,7 +1564,7 @@ cogl_wrap_glFogx (GLenum pname, GLfixed param) case GL_FOG_MODE: _COGL_GLES2_CHANGE_SETTING (w, fog_mode, param); break; - + case GL_FOG_DENSITY: _COGL_GLES2_CHANGE_UNIFORM (w, FOG_DENSITY, fog_density, COGL_FIXED_TO_FLOAT (param)); diff --git a/gles/cogl-gles2-wrapper.h b/gles/cogl-gles2-wrapper.h index ddf181e92..76100a842 100644 --- a/gles/cogl-gles2-wrapper.h +++ b/gles/cogl-gles2-wrapper.h @@ -32,11 +32,17 @@ G_BEGIN_DECLS #ifdef HAVE_COGL_GLES2 -typedef struct _CoglGles2Wrapper CoglGles2Wrapper; -typedef struct _CoglGles2WrapperUniforms CoglGles2WrapperUniforms; -typedef struct _CoglGles2WrapperSettings CoglGles2WrapperSettings; -typedef struct _CoglGles2WrapperProgram CoglGles2WrapperProgram; -typedef struct _CoglGles2WrapperShader CoglGles2WrapperShader; +typedef struct _CoglGles2Wrapper CoglGles2Wrapper; +typedef struct _CoglGles2WrapperTextureUnit + CoglGles2WrapperTextureUnit; + +typedef struct _CoglGles2WrapperAttributes CoglGles2WrapperAttributes; +typedef struct _CoglGles2WrapperUniforms CoglGles2WrapperUniforms; +typedef struct _CoglGles2WrapperTextureUnitSettings + CoglGles2WrapperTextureUnitSettings; +typedef struct _CoglGles2WrapperSettings CoglGles2WrapperSettings; +typedef struct _CoglGles2WrapperProgram CoglGles2WrapperProgram; +typedef struct _CoglGles2WrapperShader CoglGles2WrapperShader; #define COGL_GLES2_NUM_CUSTOM_UNIFORMS 16 #define COGL_GLES2_UNBOUND_CUSTOM_UNIFORM -2 @@ -46,78 +52,129 @@ typedef struct _CoglGles2WrapperShader CoglGles2WrapperShader; #define COGL_GLES2_PROJECTION_STACK_SIZE 2 #define COGL_GLES2_TEXTURE_STACK_SIZE 2 +/* Dirty flags for shader uniforms */ enum { COGL_GLES2_DIRTY_MVP_MATRIX = 1 << 0, COGL_GLES2_DIRTY_MODELVIEW_MATRIX = 1 << 1, - COGL_GLES2_DIRTY_TEXTURE_MATRIX = 1 << 2, + COGL_GLES2_DIRTY_TEXTURE_MATRICES = 1 << 2, COGL_GLES2_DIRTY_FOG_DENSITY = 1 << 3, COGL_GLES2_DIRTY_FOG_START = 1 << 4, COGL_GLES2_DIRTY_FOG_END = 1 << 5, COGL_GLES2_DIRTY_FOG_COLOR = 1 << 6, COGL_GLES2_DIRTY_ALPHA_TEST_REF = 1 << 7, - COGL_GLES2_DIRTY_TEXTURE_UNIT = 1 << 8, + COGL_GLES2_DIRTY_TEXTURE_UNITS = 1 << 8, COGL_GLES2_DIRTY_ALL = (1 << 9) - 1 }; +/* Dirty flags for shader vertex attribute pointers */ +enum + { + COGL_GLES2_DIRTY_TEX_COORD_VERTEX_ATTRIB = 1 << 0 + }; + +/* Dirty flags for shader vertex attributes enabled status */ +enum + { + COGL_GLES2_DIRTY_TEX_COORD_ATTRIB_ENABLES = 1 << 0 + }; + +struct _CoglGles2WrapperAttributes +{ + GArray *multi_texture_coords; +}; + struct _CoglGles2WrapperUniforms { - GLint mvp_matrix_uniform; - GLint modelview_matrix_uniform; - GLint texture_matrix_uniform; - GLint bound_texture_uniform; + GLint mvp_matrix_uniform; + GLint modelview_matrix_uniform; + GArray *texture_matrix_uniforms; - GLint fog_density_uniform; - GLint fog_start_uniform; - GLint fog_end_uniform; - GLint fog_color_uniform; + GArray *texture_sampler_uniforms; - GLint alpha_test_ref_uniform; + GLint fog_density_uniform; + GLint fog_start_uniform; + GLint fog_end_uniform; + GLint fog_color_uniform; + + GLint alpha_test_ref_uniform; GLint texture_unit_uniform; }; +struct _CoglGles2WrapperTextureUnitSettings +{ + guint enabled:1; + guint alpha_only:1; + /* TODO: blending state */ +}; + +/* NB: We get a copy of this for each fragment/vertex + * program varient we generate so we try to keep it + * fairly lean */ struct _CoglGles2WrapperSettings { - gboolean texture_2d_enabled; - gboolean alpha_only; + CoglGles2WrapperTextureUnitSettings *texture_units; + guint n_texture_units; - gboolean alpha_test_enabled; GLint alpha_test_func; - - gboolean fog_enabled; GLint fog_mode; /* The current in-use user program */ CoglHandle user_program; + + guint alpha_test_enabled:1; + guint fog_enabled:1; +}; + +struct _CoglGles2WrapperTextureUnit +{ + GLfloat texture_stack[COGL_GLES2_TEXTURE_STACK_SIZE * 16]; + GLuint texture_stack_pos; + + GLenum texture_coords_type; + GLint texture_coords_size; + GLsizei texture_coords_stride; + const void *texture_coords_pointer; + + guint texture_coords_enabled:1; + guint dirty_matrix:1; /*!< shader uniform needs updating */ }; struct _CoglGles2Wrapper { - GLuint matrix_mode; - GLfloat modelview_stack[COGL_GLES2_MODELVIEW_STACK_SIZE * 16]; - GLuint modelview_stack_pos; - GLfloat projection_stack[COGL_GLES2_PROJECTION_STACK_SIZE * 16]; - GLuint projection_stack_pos; - GLfloat texture_stack[COGL_GLES2_TEXTURE_STACK_SIZE * 16]; - GLuint texture_stack_pos; + GLuint matrix_mode; + GLfloat modelview_stack[COGL_GLES2_MODELVIEW_STACK_SIZE * 16]; + GLuint modelview_stack_pos; + GLfloat projection_stack[COGL_GLES2_PROJECTION_STACK_SIZE * 16]; + GLuint projection_stack_pos; + GArray *texture_units; + guint active_texture_unit; + guint active_client_texture_unit; /* The combined modelview and projection matrix is only updated at the last minute in glDrawArrays to avoid recalculating it for every change to the modelview matrix */ - GLboolean mvp_uptodate; + GLboolean mvp_uptodate; /* The currently bound program */ CoglGles2WrapperProgram *current_program; - /* The current settings */ + /* The current settings. Effectively these represent anything that + * will require a modified fixed function shader */ CoglGles2WrapperSettings settings; /* Whether the settings have changed since the last draw */ gboolean settings_dirty; /* Uniforms that have changed since the last draw */ int dirty_uniforms, dirty_custom_uniforms; + /* Attribute pointers that have changed since the last draw */ + int dirty_attribute_pointers; + + /* Vertex attribute pointer enables that have changed since the last draw */ + int dirty_vertex_attrib_enables; + /* List of all compiled program combinations */ GSList *compiled_programs; @@ -143,6 +200,10 @@ struct _CoglGles2WrapperProgram /* The settings that were used to generate this combination */ CoglGles2WrapperSettings settings; + /* The attributes for this program that are not bound up-front + * with constant indices */ + CoglGles2WrapperAttributes attributes; + /* The uniforms for this program */ CoglGles2WrapperUniforms uniforms; GLint custom_uniforms[COGL_GLES2_NUM_CUSTOM_UNIFORMS]; @@ -234,6 +295,9 @@ void cogl_wrap_glNormalPointer (GLenum type, GLsizei stride, void cogl_wrap_glTexEnvx (GLenum target, GLenum pname, GLfixed param); +void cogl_wrap_glClientActiveTexture (GLenum texture); +void cogl_wrap_glActiveTexture (GLenum texture); + void cogl_wrap_glEnableClientState (GLenum array); void cogl_wrap_glDisableClientState (GLenum array); @@ -259,12 +323,6 @@ void cogl_gles2_wrapper_bind_texture (GLenum target, GLuint texture, /* This function is only available on GLES 2 */ #define cogl_wrap_glGenerateMipmap glGenerateMipmap -void cogl_gles2_wrapper_bind_attributes (GLuint program); -void cogl_gles2_wrapper_get_uniforms (GLuint program, - CoglGles2WrapperUniforms *uniforms); -void cogl_gles2_wrapper_update_matrix (CoglGles2Wrapper *wrapper, - GLenum matrix_num); - void _cogl_gles2_clear_cache_for_program (CoglHandle program); #else /* HAVE_COGL_GLES2 */ @@ -291,6 +349,7 @@ void _cogl_gles2_clear_cache_for_program (CoglHandle program); #define cogl_wrap_glColorPointer glColorPointer #define cogl_wrap_glNormalPointer glNormalPointer #define cogl_wrap_glTexEnvx glTexEnvx +#define cogl_wrap_glActiveTexture glActiveTexture #define cogl_wrap_glEnableClientState glEnableClientState #define cogl_wrap_glDisableClientState glDisableClientState #define cogl_wrap_glAlphaFunc glAlphaFunc diff --git a/gles/cogl-texture-private.h b/gles/cogl-texture-private.h index 117437458..5174c3cde 100644 --- a/gles/cogl-texture-private.h +++ b/gles/cogl-texture-private.h @@ -31,6 +31,8 @@ typedef struct _CoglTexture CoglTexture; typedef struct _CoglTexSliceSpan CoglTexSliceSpan; typedef struct _CoglSpanIter CoglSpanIter; +typedef struct _CoglMultiTexture CoglMultiTexture; +typedef struct _CoglMultiTextureLayer CoglMultiTextureLayer; struct _CoglTexSliceSpan { @@ -59,7 +61,26 @@ struct _CoglTexture gboolean auto_mipmap; }; +struct _CoglMultiTextureLayer +{ + guint ref_count; + guint index; /*!< lowest index is blended first then others + on top */ + CoglTexture *tex; /*!< The texture for this layer, or NULL + for an empty layer */ + + /* TODO: Add more control over the texture environment for each texture + * unit. For example we should support dot3 normal mapping. */ +}; + +struct _CoglMultiTexture +{ + guint ref_count; + GList *layers; +}; + CoglTexture* _cogl_texture_pointer_from_handle (CoglHandle handle); #endif /* __COGL_TEXTURE_H */ + diff --git a/gles/cogl-texture.c b/gles/cogl-texture.c index 5a75eb389..ba1979e8f 100644 --- a/gles/cogl-texture.c +++ b/gles/cogl-texture.c @@ -40,11 +40,20 @@ #include #include +#if HAVE_COGL_GLES2 #define glVertexPointer cogl_wrap_glVertexPointer #define glTexCoordPointer cogl_wrap_glTexCoordPointer #define glColorPointer cogl_wrap_glColorPointer #define glDrawArrays cogl_wrap_glDrawArrays #define glTexParameteri cogl_wrap_glTexParameteri +#define glClientActiveTexture cogl_wrap_glClientActiveTexture +#define glActiveTexture cogl_wrap_glActiveTexture +#define glEnable cogl_wrap_glEnable +#define glEnableClientState cogl_wrap_glEnableClientState +#define glDisable cogl_wrap_glDisable +#define glDisableClientState cogl_wrap_glDisableClientState +#define glTexEnvx cogl_wrap_glTexEnvx +#endif /* #define COGL_DEBUG 1 @@ -75,14 +84,14 @@ struct _CoglSpanIter }; static void _cogl_texture_free (CoglTexture *tex); +static void _cogl_multi_texture_free (CoglMultiTexture *multi_texture); +static void _cogl_multi_texture_layer_free (CoglMultiTextureLayer *layer); COGL_HANDLE_DEFINE (Texture, texture, texture_handles); - -CoglHandle -_cogl_texture_handle_from_pointer (CoglTexture *tex) -{ - return (CoglHandle) tex; -} +COGL_HANDLE_DEFINE (MultiTexture, multi_texture, multi_texture_handles); +COGL_HANDLE_DEFINE (MultiTextureLayer, + multi_texture_layer, + multi_texture_layer_handles); static void _cogl_texture_bitmap_free (CoglTexture *tex) @@ -2493,3 +2502,263 @@ cogl_texture_polygon (CoglHandle handle, if (use_color && n_vertices > 0) cogl_set_source_color (&vertices[n_vertices - 1].color); } + +CoglHandle +cogl_multi_texture_new (void) +{ + CoglMultiTexture *multi_tex = g_new0 (CoglMultiTexture, 1); + return _cogl_multi_texture_handle_new (multi_tex); +} + +static void +_cogl_multi_texture_free (CoglMultiTexture *multi_tex) +{ + g_list_foreach (multi_tex->layers, + (GFunc)cogl_multi_texture_layer_unref, NULL); + g_free (multi_tex); +} + +static CoglMultiTextureLayer * +_cogl_multi_texture_get_layer (CoglMultiTexture *multi_tex, guint index) +{ + CoglMultiTextureLayer *layer; + GList *tmp; + + for (tmp = multi_tex->layers; tmp != NULL; tmp = tmp->next) + { + layer = tmp->data; + if (layer->index == index) + return layer; + + /* The layers are always sorted, so we know this layer doesn't exists */ + if (layer->index > index) + break; + } + /* NB: if we now insert a new layer before tmp, that will maintain order. + */ + + layer = g_new (CoglMultiTextureLayer, 1); + + layer->ref_count = 1; + layer->index = index; + /* Note: comment after for() loop above */ + multi_tex->layers = g_list_insert_before (multi_tex->layers, tmp, layer); + + return layer; +} + +void +cogl_multi_texture_layer_set_texture (CoglHandle multi_texture_handle, + guint layer_index, + CoglHandle tex_handle) +{ + CoglMultiTexture *multi_tex; + CoglMultiTextureLayer *layer; + CoglTexture *tex; + + if (!cogl_is_multi_texture (multi_texture_handle) + || !cogl_is_texture (tex_handle)) + return; + + multi_tex = _cogl_multi_texture_pointer_from_handle (multi_texture_handle); + layer = _cogl_multi_texture_get_layer (multi_tex, layer_index); + tex = _cogl_texture_pointer_from_handle (tex_handle); + + cogl_texture_ref (tex_handle); + + layer->tex = tex; +} + +static void +_cogl_multi_texture_layer_free (CoglMultiTextureLayer *layer) +{ + cogl_texture_unref (layer->tex); + g_free (layer); +} + +void +cogl_multi_texture_layer_remove (CoglHandle multi_texture_handle, + guint layer_index) +{ + CoglMultiTexture *multi_tex; + CoglMultiTextureLayer *layer; + GList *tmp; + + /* Check if valid multi texture */ + if (!cogl_is_multi_texture (multi_texture_handle)) + return; + + multi_tex = _cogl_multi_texture_pointer_from_handle (multi_texture_handle); + for (tmp = multi_tex->layers; tmp != NULL; tmp = tmp->next) + { + layer = tmp->data; + if (layer->index == layer_index) + { + CoglHandle handle = + _cogl_multi_texture_layer_handle_from_pointer (layer); + cogl_multi_texture_layer_unref (handle); + multi_tex->layers = g_list_remove (multi_tex->layers, layer); + return; + } + } +} + +void +cogl_multi_texture_rectangle (CoglHandle multi_texture_handle, + CoglFixed x1, + CoglFixed y1, + CoglFixed x2, + CoglFixed y2, + CoglFixed *user_tex_coords) +{ + CoglMultiTexture *multi_tex; + GLfixed quad_coords[8]; + GList *tmp; + GList *valid_layers = NULL; + int count; + GLfloat *tex_coords_buff; + gulong enable_flags = 0; + /* FIXME - currently cogl deals with enabling texturing + * via enable flags, but that can't scale to n texture + * units. Currently we have to be carefull how we leave the + * environment so we don't break things. See the cleanup + * notes at the end of this function */ + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + /* Check if valid multi texture */ + if (!cogl_is_multi_texture (multi_texture_handle)) + return; + + multi_tex = _cogl_multi_texture_pointer_from_handle (multi_texture_handle); + +#define CFX_F COGL_FIXED_TO_FLOAT + quad_coords[0] = CFX_F (x1); + quad_coords[1] = CFX_F (y1); + quad_coords[2] = CFX_F (x2); + quad_coords[3] = CFX_F (y1); + quad_coords[4] = CFX_F (x1); + quad_coords[5] = CFX_F (y2); + quad_coords[6] = CFX_F (x2); + quad_coords[7] = CFX_F (y2); +#undef CFX_F + + enable_flags |= COGL_ENABLE_VERTEX_ARRAY; + GE( glVertexPointer (2, GL_FIXED, 0, quad_coords) ); + + for (count = 0, tmp = multi_tex->layers; + tmp != NULL; + count++, tmp = tmp->next) + { + CoglMultiTextureLayer *layer = tmp->data; + + /* Skip empty layers */ + if (!layer->tex) + { + count--; + continue; + } + + /* FIXME - currently we don't support sliced textures */ + if (layer->tex->slice_gl_handles == NULL + || layer->tex->slice_gl_handles->len < 1) + continue; + + if (count >= CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS) + { + static gboolean shown_warning = FALSE; + + if (!shown_warning) + { + g_warning ("Your driver does not support enough texture layers" + "to correctly handle this multi texturing"); + shown_warning = TRUE; + } + /* NB: We make a best effort attempt to display as many layers as + * possible. */ + break; + } + + if (layer->tex->bitmap.format & COGL_A_BIT) + enable_flags |= COGL_ENABLE_BLEND; + + valid_layers = g_list_prepend (valid_layers, layer); + } + valid_layers = g_list_reverse (valid_layers); + + /* Enable blending if the geometry has an associated alpha color, + * or - see above - we also check each layer texture and if any has + * an alpha channel also enable blending. */ + if (ctx->color_alpha < 255) + enable_flags |= COGL_ENABLE_BLEND; + cogl_enable (enable_flags); + + /* NB: It could be that no valid texture layers were found, but + * we will still submit a non-textured rectangle in that case. */ + if (count) + tex_coords_buff = alloca (sizeof(GLfloat) * 8 * count); + + /* NB: valid_layers is in order, sorted by index */ + for (count = 0, tmp = valid_layers; + tmp != NULL; + count++, tmp = tmp->next) + { + CoglMultiTextureLayer *layer = tmp->data; + CoglFixed *in_tex_coords = &user_tex_coords[count * 4]; + GLfloat *out_tex_coords = &tex_coords_buff[count * 8]; + GLenum gl_tex_handle; + +#define CFX_F COGL_FIXED_TO_FLOAT + /* IN LAYOUT: [ tx1:0, ty1:1, tx2:2, ty2:3 ] */ + out_tex_coords[0] = CFX_F (in_tex_coords[0]); /* tx1 */ + out_tex_coords[1] = CFX_F (in_tex_coords[1]); /* ty1 */ + out_tex_coords[2] = CFX_F (in_tex_coords[2]); /* tx2 */ + out_tex_coords[3] = CFX_F (in_tex_coords[1]); /* ty1 */ + out_tex_coords[4] = CFX_F (in_tex_coords[0]); /* tx1 */ + out_tex_coords[5] = CFX_F (in_tex_coords[3]); /* ty2 */ + out_tex_coords[6] = CFX_F (in_tex_coords[2]); /* tx2 */ + out_tex_coords[7] = CFX_F (in_tex_coords[3]); /* ty2 */ +#undef CFX_F + + /* TODO - support sliced textures */ + gl_tex_handle = g_array_index (layer->tex->slice_gl_handles, GLuint, 0); + + GE (glActiveTexture (GL_TEXTURE0 + count)); + GE (glTexEnvx (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)); + GE( cogl_gles2_wrapper_bind_texture (layer->tex->gl_target, + gl_tex_handle, + layer->tex->gl_intformat)); + + GE (glClientActiveTexture (GL_TEXTURE0 + count)); + GE (glTexCoordPointer (2, GL_FLOAT, 0, out_tex_coords)); + + /* FIXME - cogl only knows about one texture unit a.t.m + * (Also see cleanup note below) */ + if (count == 0) + { + enable_flags |= COGL_ENABLE_TEXTURE_2D | COGL_ENABLE_TEXCOORD_ARRAY; + cogl_enable (enable_flags); + } + else + { + GE (glEnable (GL_TEXTURE_2D)); + GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY)); + } + } + + GE (glDrawArrays (GL_TRIANGLE_STRIP, 0, 4) ); + + /* FIXME - cogl doesn't currently have a way of caching the + * enable states for more than one texture unit so for now, + * we just disable anything relating to additional units once + * we are done with them. */ + while (--count > 0) + { + GE (glActiveTexture (GL_TEXTURE0 + count)); + GE (glClientActiveTexture (GL_TEXTURE0 + count)); + + GE (cogl_wrap_glDisable (GL_TEXTURE_2D)); + GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY)); + } +} + From af6c78e9b43a4739a39bbc4c740c2563af8a116a Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Thu, 11 Dec 2008 20:08:15 +0000 Subject: [PATCH 02/16] Adds CoglMatrix utility code --- cogl-matrix.h | 102 ++++++++++++++++++++++++++++++++ common/Makefile.am | 3 +- common/cogl-matrix.c | 138 +++++++++++++++++++++++++++++++++++++++++++ common/cogl-matrix.h | 57 ++++++++++++++++++ 4 files changed, 299 insertions(+), 1 deletion(-) create mode 100644 cogl-matrix.h create mode 100644 common/cogl-matrix.c create mode 100644 common/cogl-matrix.h diff --git a/cogl-matrix.h b/cogl-matrix.h new file mode 100644 index 000000000..44444691e --- /dev/null +++ b/cogl-matrix.h @@ -0,0 +1,102 @@ +#ifndef __COGL_MATRIX_H +#define __COGL_MATRIX_H + +/* Note: This is ordered according to how OpenGL expects to get 4x4 matrices */ +typedef struct { + /* column 0 */ + float xx; + float yx; + float zx; + float wx; + + /* column 1 */ + float xy; + float yy; + float zy; + float wy; + + /* column 2 */ + float xz; + float yz; + float zz; + float wz; + + /* column 3 */ + float xw; + float yw; + float zw; + float ww; + + /* Note: we may want to extend this later with private flags + * and a cache of the inverse transform matrix. */ +} CoglMatrix; + +/** + * cogl_matrix_init_identity: + * @matrix: A 4x4 transformation matrix + * + * Resets matrix to the identity matrix + */ +void cogl_matrix_init_identity (CoglMatrix *matrix); + +/** + * cogl_matrix_multiply: + * @result: The address of a 4x4 matrix to store the result in + * @a: A 4x4 transformation matrix + * @b: A 4x4 transformation matrix + * + * This function multiples the two supplied matricies together and stores + * the result in 'result' + */ +void cogl_matrix_multiply (CoglMatrix *result, + const CoglMatrix *a, + const CoglMatrix *b); + +/** + * cogl_matrix_rotate: + * @matrix: A 4x4 transformation matrix + * @angle: The angle you want to rotate in degrees + * @x: X component of your rotation vector + * @y: Y component of your rotation vector + * @z: Z component of your rotation vector + * + * This function multiples your matrix with a rotation matrix that applies + * a rotation of angle degrees around the specified 3D vector. + */ +void cogl_matrix_rotate (CoglMatrix *matrix, + float angle, + float x, + float y, + float z); + +/* cogl_matrix_translate: + * @matrix: A 4x4 transformation matrix + * @x: The X translation you want to apply + * @y: The Y translation you want to apply + * @z: The Z translation you want to apply + * + * This function multiples your matrix with a transform matrix that translates + * along the X, Y and Z axis. + */ +void cogl_matrix_translate (CoglMatrix *matrix, + float x, + float y, + float z); + +/** + * cogl_matrix_scale: + * @matrix: A 4x4 transformation matrix + * @sx: The X scale factor + * @sy: The Y scale factor + * @sz: The Z scale factor + * + * This function multiples your matrix with a transform matrix that scales + * along the X, Y and Z axis. + */ +void cogl_matrix_scale (CoglMatrix *matrix, + float sx, + float sy, + float sz); + +#endif /* __COGL_MATRIX_H */ + diff --git a/common/Makefile.am b/common/Makefile.am index db0f0b42d..755001e1f 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -29,4 +29,5 @@ libclutter_cogl_common_la_SOURCES = \ cogl-clip-stack.c \ cogl-fixed.c \ cogl-color.c \ - cogl-mesh.c + cogl-mesh.c \ + cogl-matrix.c diff --git a/common/cogl-matrix.c b/common/cogl-matrix.c new file mode 100644 index 000000000..8786da570 --- /dev/null +++ b/common/cogl-matrix.c @@ -0,0 +1,138 @@ +#include + +#include +#include + +void +cogl_matrix_init_identity (CoglMatrix *matrix) +{ + matrix->xx = 1; matrix->xy = 0; matrix->xz = 0; matrix->xw = 0; + matrix->yx = 0; matrix->yy = 1; matrix->yz = 0; matrix->yw = 0; + matrix->zx = 0; matrix->zy = 0; matrix->zz = 1; matrix->zw = 0; + matrix->wx = 0; matrix->wy = 0; matrix->wz = 0; matrix->ww = 1; +} + +void +cogl_matrix_multiply (CoglMatrix *result, + const CoglMatrix *a, + const CoglMatrix *b) +{ + CoglMatrix r; + + /* row 0 */ + r.xx = a->xx * b->xx + a->xy * b->yx + a->xz * b->zx + a->xw * b->wx; + r.xy = a->xx * b->xy + a->xy * b->yy + a->xz * b->zy + a->xw * b->wy; + r.xz = a->xx * b->xz + a->xy * b->yz + a->xz * b->zz + a->xw * b->wz; + r.xw = a->xx * b->xw + a->xy * b->yw + a->xz * b->zw + a->xw * b->ww; + + /* row 1 */ + r.yx = a->yx * b->xx + a->yy * b->yx + a->yz * b->zx + a->yw * b->wx; + r.yy = a->yx * b->xy + a->yy * b->yy + a->yz * b->zy + a->yw * b->wy; + r.yz = a->yx * b->xz + a->yy * b->yz + a->yz * b->zz + a->yw * b->wz; + r.yw = a->yx * b->xw + a->yy * b->yw + a->yz * b->zw + a->yw * b->ww; + + /* row 2 */ + r.zx = a->zx * b->xx + a->zy * b->yx + a->zz * b->zx + a->zw * b->wx; + r.zy = a->zx * b->xy + a->zy * b->yy + a->zz * b->zy + a->zw * b->wy; + r.zz = a->zx * b->xz + a->zy * b->yz + a->zz * b->zz + a->zw * b->wz; + r.zw = a->zx * b->xw + a->zy * b->yw + a->zz * b->zw + a->zw * b->ww; + + /* row 3 */ + r.wx = a->wx * b->xx + a->wy * b->yx + a->wz * b->zx + a->ww * b->wx; + r.wy = a->wx * b->xy + a->wy * b->yy + a->wz * b->zy + a->ww * b->wy; + r.wz = a->wx * b->xz + a->wy * b->yz + a->wz * b->zz + a->ww * b->wz; + r.ww = a->wx * b->xw + a->wy * b->yw + a->wz * b->zw + a->ww * b->ww; + + /* The idea was that having this unrolled; it might be easier for the + * compiler to vectorize, but that's probably not true. Mesa does it + * using a single for (i=0; i<4; i++) approach, may that's better... + */ + + *result = r; +} + +/** + * cogl_3dmatrix_rotate: + * matrix: A 3D Affine transformation matrix + * angle: The angle in degrees you want to rotate by + * x: The X component of your rotation vector + * y: The Y component of your rotation vector + * z: The Z component of your rotation vector + * + * The matrix is multiplied with a rotation matrix representing a rotation + * of angle degress around the vector (x,y,z) + */ +void +cogl_matrix_rotate (CoglMatrix *matrix, + float angle, + float x, + float y, + float z) +{ + CoglMatrix rotation; + CoglMatrix result; + angle *= G_PI / 180.0f; + float c = cosf (angle); + float s = sinf (angle); + + rotation.xx = x * x * (1.0f - c) + c; + rotation.yx = y * x * (1.0f - c) + z * s; + rotation.zx = x * z * (1.0f - c) - y * s; + rotation.wx = 0.0f; + + rotation.xy = x * y * (1.0f - c) - z * s; + rotation.yy = y * y * (1.0f - c) + c; + rotation.zy = y * z * (1.0f - c) + x * s; + rotation.wy = 0.0f; + + rotation.xz = x * z * (1.0f - c) + y * s; + rotation.yz = y * z * (1.0f - c) - x * s; + rotation.zz = z * z * (1.0f - c) + c; + rotation.wz = 0.0f; + + rotation.xw = 0.0f; + rotation.yw = 0.0f; + rotation.zw = 0.0f; + rotation.ww = 1.0f; + + cogl_matrix_multiply (&result, matrix, &rotation); + *matrix = result; +} + +void +cogl_matrix_translate (CoglMatrix *matrix, + float x, + float y, + float z) +{ + matrix->xw = matrix->xx * x + matrix->xy * y + matrix->xz * z + matrix->xw; + matrix->yw = matrix->yx * x + matrix->yy * y + matrix->yz * z + matrix->yw; + matrix->zw = matrix->zx * x + matrix->zy * y + matrix->zz * z + matrix->zw; + matrix->ww = matrix->wx * x + matrix->wy * y + matrix->wz * z + matrix->ww; +} + +void +cogl_matrix_scale (CoglMatrix *matrix, + float sx, + float sy, + float sz) +{ + matrix->xx *= sx; matrix->xy *= sy; matrix->xz *= sz; + matrix->yx *= sx; matrix->yy *= sy; matrix->yz *= sz; + matrix->zx *= sx; matrix->zy *= sy; matrix->zz *= sz; + matrix->wx *= sx; matrix->wy *= sy; matrix->wz *= sz; +} + +#if 0 +gboolean +cogl_matrix_invert (CoglMatrix *matrix) +{ + /* TODO */ + /* Note: It might be nice to also use the flag based tricks that mesa does + * to alow it to track the type of transformations a matrix represents + * so it can use various assumptions to optimise the inversion. + */ +} +#endif + + diff --git a/common/cogl-matrix.h b/common/cogl-matrix.h new file mode 100644 index 000000000..2f6874fae --- /dev/null +++ b/common/cogl-matrix.h @@ -0,0 +1,57 @@ +#ifndef __COGL_MATRIX_H +#define __COGL_MATRIX_H + +/* Note: This is ordered according to how OpenGL expects to get 4x4 matrices */ +typedef struct { + /* column 0 */ + float xx; + float yx; + float zx; + float wx; + + /* column 1 */ + float xy; + float yy; + float zy; + float wy; + + /* column 2 */ + float xz; + float yz; + float zz; + float wz; + + /* column 3 */ + float xw; + float yw; + float zw; + float ww; + + /* Note: we may want to extend this later with private flags + * and a cache of the inverse transform matrix. */ +} CoglMatrix; + +void cogl_matrix_init_identity (CoglMatrix *matrix); + +void cogl_matrix_multiply (CoglMatrix *result, + const CoglMatrix *a, + const CoglMatrix *b); + +void cogl_matrix_rotate (CoglMatrix *matrix, + float angle, + float x, + float y, + float z); + +void cogl_matrix_translate (CoglMatrix *matrix, + float x, + float y, + float z); + +void cogl_matrix_scale (CoglMatrix *matrix, + float sx, + float sy, + float sz); + +#endif /* __COGL_MATRIX_H */ + From cdf19f3281c92cb3cd46df165f8f15153ac1aa0f Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Mon, 22 Dec 2008 16:16:07 +0000 Subject: [PATCH 03/16] [doc] Hooks up cogl-matrix reference documentation Adds a few more gtk-doc notes to cogl-matrix.h, and adds a new section to cogl-sections.txt --- cogl-matrix.h | 54 +++++++++++++++++++++++++--- doc/reference/cogl/cogl-docs.sgml | 1 + doc/reference/cogl/cogl-sections.txt | 11 ++++++ 3 files changed, 61 insertions(+), 5 deletions(-) diff --git a/cogl-matrix.h b/cogl-matrix.h index 44444691e..08c4a7009 100644 --- a/cogl-matrix.h +++ b/cogl-matrix.h @@ -1,8 +1,42 @@ #ifndef __COGL_MATRIX_H #define __COGL_MATRIX_H -/* Note: This is ordered according to how OpenGL expects to get 4x4 matrices */ -typedef struct { +#include + +G_BEGIN_DECLS + +/** + * SECTION:cogl-matrix + * @short_description: Fuctions for initializing and manipulating 4x4 + * matrices. + * + * Matrices are used in Cogl to describe affine model-view transforms and + * texture transforms, and projective transforms. This exposes a utility API + * that can be used for direct manipulation of these matrices. + */ + + +/** + * CoglMatrix: + * + * A CoglMatrix holds a 4x4 transform matrix. This is a single precision, + * column-major matrix which means it is compatible with what OpenGL expects. + * + * A CoglMatix can represent transforms such as, rotations, scaling, + * translation, sheering, and linear projections. You can combine these + * transforms by multiplying multiple matrices in the order you want them + * applied. + * + * The transformation of a vertex (x, y, z, w) by a CoglMatrix is given by: + * + * x_new = xx * x + xy * y + xz * z + xw * w + * y_new = yx * x + yy * y + yz * z + yw * w + * z_new = zx * x + zy * y + zz * z + zw * w + * w_new = wx * x + wy * y + wz * z + ww * w + * + * Where w is normally 1 + */ +typedef struct _CoglMatrix { /* column 0 */ float xx; float yx; @@ -27,6 +61,8 @@ typedef struct { float zw; float ww; + /*< private >*/ + /* Note: we may want to extend this later with private flags * and a cache of the inverse transform matrix. */ } CoglMatrix; @@ -35,7 +71,13 @@ typedef struct { * cogl_matrix_init_identity: * @matrix: A 4x4 transformation matrix * - * Resets matrix to the identity matrix + * Resets matrix to the identity matrix: + * + * .xx=1; .xy=0; .xz=0; .xw=0; + * .yx=0; .yy=1; .yz=0; .yw=0; + * .zx=0; .zy=0; .zz=1; .zw=0; + * .wx=0; .wy=0; .wz=0; .ww=1; + * */ void cogl_matrix_init_identity (CoglMatrix *matrix); @@ -46,7 +88,7 @@ void cogl_matrix_init_identity (CoglMatrix *matrix); * @b: A 4x4 transformation matrix * * This function multiples the two supplied matricies together and stores - * the result in 'result' + * the result in #result */ void cogl_matrix_multiply (CoglMatrix *result, const CoglMatrix *a, @@ -61,7 +103,7 @@ void cogl_matrix_multiply (CoglMatrix *result, * @z: Z component of your rotation vector * * This function multiples your matrix with a rotation matrix that applies - * a rotation of angle degrees around the specified 3D vector. + * a rotation of #angle degrees around the specified 3D vector. */ void cogl_matrix_rotate (CoglMatrix *matrix, float angle, @@ -98,5 +140,7 @@ void cogl_matrix_scale (CoglMatrix *matrix, float sy, float sz); +G_END_DECLS + #endif /* __COGL_MATRIX_H */ diff --git a/doc/reference/cogl/cogl-docs.sgml b/doc/reference/cogl/cogl-docs.sgml index d1718437e..f872b0349 100644 --- a/doc/reference/cogl/cogl-docs.sgml +++ b/doc/reference/cogl/cogl-docs.sgml @@ -55,6 +55,7 @@ + diff --git a/doc/reference/cogl/cogl-sections.txt b/doc/reference/cogl/cogl-sections.txt index 03247ff3c..84c43dbf3 100644 --- a/doc/reference/cogl/cogl-sections.txt +++ b/doc/reference/cogl/cogl-sections.txt @@ -293,3 +293,14 @@ cogl_mesh_draw_range_elements cogl_mesh_submit +
+cogl-matrix +Matrices +CoglMatrix +cogl_matrix_init_identity +cogl_matrix_multiply +cogl_matrix_rotate +cogl_matrix_translate +cogl_matrix_scale +
+ From 61b8cc1874ebd5a25d6ffb49bf67c0aa29afb679 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Thu, 11 Dec 2008 20:11:30 +0000 Subject: [PATCH 04/16] Adds a CoglMaterial abstraction, which includes support for multi-texturing My previous work to provide muti-texturing support has been extended into a CoglMaterial abstraction that adds control over the texture combine functions (controlling how multiple texture layers are blended together), the gl blend function (used for blending the final primitive with the framebuffer), the alpha function (used to discard fragments based on their alpha channel), describing attributes such as a diffuse, ambient and specular color (for use with the standard OpenGL lighting model), and per layer rotations. (utilizing the new CoglMatrix utility API) For now the only way this abstraction is exposed is via a new cogl_material_rectangle function, that is similar to cogl_texture_rectangle but doesn't take a texture handle (the source material is pulled from the context), and the array of texture coordinates is extended to be able to supply coordinates for each layer. Note: this function doesn't support sliced textures; supporting sliced textures is a non trivial problem, considering the ability to rotate layers. Note: cogl_material_rectangle, has quite a few workarounds, for a number of other limitations within Cogl a.t.m. Note: The GLES1/2 multi-texturing support has yet to be updated to use the material abstraction. --- cogl-material.h | 481 +++++++++++++++++++++++ cogl.h.in | 2 + common/Makefile.am | 3 +- common/cogl-material-private.h | 72 ++++ common/cogl-material.c | 680 +++++++++++++++++++++++++++++++++ common/cogl-matrix.h | 57 --- gl/cogl-context.c | 5 +- gl/cogl-context.h | 9 +- gl/cogl-texture-private.h | 8 +- gl/cogl-texture.c | 305 +++++---------- 10 files changed, 1353 insertions(+), 269 deletions(-) create mode 100644 cogl-material.h create mode 100644 common/cogl-material-private.h create mode 100644 common/cogl-material.c delete mode 100644 common/cogl-matrix.h diff --git a/cogl-material.h b/cogl-material.h new file mode 100644 index 000000000..9a6f0eb10 --- /dev/null +++ b/cogl-material.h @@ -0,0 +1,481 @@ +#if !defined(__COGL_H_INSIDE__) && !defined(CLUTTER_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __COGL_MATERIAL_H__ +#define __COGL_MATERIAL_H__ + +G_BEGIN_DECLS + +#include +#include + +/** + * SECTION:cogl-material + * @short_description: Fuctions for creating and manipulating materials + * + * COGL allows creating and manipulating materials used to fill in + * geometry. Materials may simply be lighting attributes (such as an + * ambient and diffuse colour) or might represent one or more textures + * blended together. + */ + +G_END_DECLS + +typedef enum _CoglMaterialAlphaFunc +{ + COGL_MATERIAL_ALPHA_FUNC_NEVER = GL_NEVER, + COGL_MATERIAL_ALPHA_FUNC_LESS = GL_LESS, + COGL_MATERIAL_ALPHA_FUNC_EQUAL = GL_EQUAL, + COGL_MATERIAL_ALPHA_FUNC_LEQUAL = GL_LEQUAL, + COGL_MATERIAL_ALPHA_FUNC_GREATER = GL_GREATER, + COGL_MATERIAL_ALPHA_FUNC_NOTEQUAL = GL_NOTEQUAL, + COGL_MATERIAL_ALPHA_FUNC_GEQUAL = GL_GEQUAL, + COGL_MATERIAL_ALPHA_FUNC_ALWAYS = GL_ALWAYS +} CoglMaterialAlphaFunc; + +typedef enum _CoglMaterialBlendFactor +{ + COGL_MATERIAL_BLEND_FACTOR_ZERO = GL_ZERO, + COGL_MATERIAL_BLEND_FACTOR_ONE = GL_ONE, + COGL_MATERIAL_BLEND_FACTOR_DST_COLOR = GL_DST_COLOR, + COGL_MATERIAL_BLEND_FACTOR_SRC_COLOR = GL_SRC_COLOR, + COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_DST_COLOR = GL_ONE_MINUS_DST_COLOR, + COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_SRC_COLOR = GL_ONE_MINUS_SRC_COLOR, + COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA = GL_SRC_ALPHA, + COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA = GL_ONE_MINUS_SRC_ALPHA, + COGL_MATERIAL_BLEND_FACTOR_DST_ALPHA = GL_DST_ALPHA, + COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_DST_ALPHA = GL_ONE_MINUS_DST_ALPHA, + COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA_SATURATE = GL_SRC_ALPHA_SATURATE, + COGL_MATERIAL_BLEND_FACTOR_CONSTANT_COLOR = GL_CONSTANT_COLOR, + COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR = + GL_ONE_MINUS_CONSTANT_COLOR, + COGL_MATERIAL_BLEND_FACTOR_CONSTANT_ALPHA = GL_CONSTANT_ALPHA, + COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA = + GL_ONE_MINUS_CONSTANT_ALPHA +} CoglMaterialBlendFactor; + +typedef enum _CoglMaterialLayerType +{ + COGL_MATERIAL_LAYER_TYPE_TEXTURE +} CoglMaterialLayerType; + +typedef enum _CoglMaterialLayerCombineFunc +{ + COGL_MATERIAL_LAYER_COMBINE_FUNC_REPLACE = GL_REPLACE, + COGL_MATERIAL_LAYER_COMBINE_FUNC_MODULATE = GL_MODULATE, + COGL_MATERIAL_LAYER_COMBINE_FUNC_ADD = GL_ADD, + COGL_MATERIAL_LAYER_COMBINE_FUNC_ADD_SIGNED = GL_ADD_SIGNED, + COGL_MATERIAL_LAYER_COMBINE_FUNC_INTERPOLATE = GL_INTERPOLATE, + COGL_MATERIAL_LAYER_COMBINE_FUNC_SUBTRACT = GL_SUBTRACT, + COGL_MATERIAL_LAYER_COMBINE_FUNC_DOT3_RGB = GL_DOT3_RGB, + COGL_MATERIAL_LAYER_COMBINE_FUNC_DOT3_RGBA = GL_DOT3_RGBA +} CoglMaterialLayerCombineFunc; + +typedef enum _CoglMaterialLayerCombineChannels +{ + COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB, + COGL_MATERIAL_LAYER_COMBINE_CHANNELS_ALPHA, + COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA +} CoglMaterialLayerCombineChannels; + +typedef enum _CoglMaterialLayerCombineSrc +{ + COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE = GL_TEXTURE, + + /* Can we find a nicer way... */ + COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE0 = GL_TEXTURE0, + COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE1 = GL_TEXTURE1, + COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE2 = GL_TEXTURE2, + COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE3 = GL_TEXTURE3, + COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE4 = GL_TEXTURE4, + COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE5 = GL_TEXTURE5, + COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE6 = GL_TEXTURE6, + COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE7 = GL_TEXTURE7, + /* .. who would ever need more than 8 texture layers.. :-) */ + + COGL_MATERIAL_LAYER_COMBINE_SRC_CONSTANT = GL_CONSTANT, + COGL_MATERIAL_LAYER_COMBINE_SRC_PRIMARY_COLOR = GL_PRIMARY_COLOR, + COGL_MATERIAL_LAYER_COMBINE_SRC_PREVIOUS = GL_PREVIOUS +} CoglMaterialLayerCombineSrc; + +typedef enum _CoglMaterialLayerCombineOp +{ + COGL_MATERIAL_LAYER_COMBINE_OP_SRC_COLOR = GL_SRC_COLOR, + COGL_MATERIAL_LAYER_COMBINE_OP_ONE_MINUS_SRC_COLOR = GL_ONE_MINUS_SRC_COLOR, + + COGL_MATERIAL_LAYER_COMBINE_OP_SRC_ALPHA = GL_SRC_ALPHA, + COGL_MATERIAL_LAYER_COMBINE_OP_ONE_MINUS_SRC_ALPHA = GL_ONE_MINUS_SRC_ALPHA +} CoglMaterialLayerCombineOp; + +/** + * cogl_material_new: + * + * Allocates and initializes blank white material + */ +CoglHandle cogl_material_new (void); + +/** + * cogl_material_ref: + * @handle: a @CoglHandle. + * + * Increment the reference count for a cogl material. + * + * Returns: the @handle. + */ +CoglHandle cogl_material_ref (CoglHandle handle); + +/** + * cogl_material_unref: + * @handle: a @CoglHandle. + * + * Deccrement the reference count for a cogl material. + */ +void cogl_material_unref (CoglHandle handle); + +/** + * cogl_material_set_diffuse: + * @material: A CoglMaterial object + * @diffuse: The components of the desired diffuse color + * + * Exposing the standard OpenGL lighting model; this function sets + * the material's diffuse color. The diffuse color is most intense + * where the light hits the surface directly; perpendicular to the + * surface. + */ +void cogl_material_set_diffuse (CoglHandle material, + const CoglColor *diffuse); + +/** + * cogl_material_set_ambient: + * @material: A CoglMaterial object + * @ambient: The components of the desired ambient color + * + * Exposing the standard OpenGL lighting model; this function sets + * the material's ambient color. The ambient color affects the overall + * color of the object. Since the diffuse color will be intense when + * the light hits the surface directly, the ambient will most aparent + * where the light hits at a slant. + */ +void cogl_material_set_ambient (CoglHandle material, + const CoglColor *ambient); + +/** + * cogl_material_set_ambient_and_diffuse: + * @material: A CoglMaterial object + * @color: The components of the desired ambient and diffuse colors + * + * This is a convenience for setting the diffuse and ambient color + * of the material at the same time. + */ +void cogl_material_set_ambient_and_diffuse (CoglHandle material, + const CoglColor *color); + +/** + * cogl_material_set_specular: + * @material: A CoglMaterial object + * @specular: The components of the desired specular color + * + * Exposing the standard OpenGL lighting model; this function sets + * the material's specular color. The intensity of the specular color + * depends on the viewport position, and is brightest along the lines + * of reflection. + */ +void cogl_material_set_specular (CoglHandle material, + const CoglColor *specular); + +/** + * cogl_material_set_shininess: + * @material: A CoglMaterial object + * shininess: The desired shininess; range: [0.0, 1.0] + * + * This function sets the materials shininess which determines how + * specular highlights are calculated. A higher shininess will produce + * smaller brigher highlights. + */ +void cogl_material_set_shininess (CoglHandle material, + float shininess); + +/** + * cogl_material_set_emission: + * @material: A CoglMaterial object + * @emission: The components of the desired emissive color + * + * Exposing the standard OpenGL lighting model; this function sets + * the material's emissive color. It will look like the surface is + * a light source emitting this color. + */ +void cogl_material_set_emission (CoglHandle material, + const CoglColor *emission); + +/** + * cogl_set_source: + * @material: A CoglMaterial object + * + * This function sets the source material that will be used to fill + * subsequent geometry emitted via the cogl API. + * + * XXX: This doesn't really belong to the cogl-material API, it should + * move to cogl.h + */ +void cogl_set_source (CoglHandle material); + +/** + * cogl_material_set_alpha_test_func: + * @material: A CoglMaterial object + * + * Before a primitive is blended with the framebuffer, it goes through an + * alpha test stage which lets you discard fragments based on the current + * alpha value. This function lets you change the function used to evaluate + * the alpha channel, and thus determine which fragments are discarded + * and which continue on to the blending stage. + * TODO: expand on this + */ +void cogl_material_set_alpha_test_func (CoglHandle material, + CoglMaterialAlphaFunc alpha_func, + float alpha_reference); + +/** + * cogl_material_set_blend_function: + * @material: A CoglMaterial object + * @src_factor: Chooses the source factor you want plugged in to the blend + * equation. + * @dst_factor: Chooses the source factor you want plugged in to the blend + * equation. + * + * This function lets you control how primitives using this material will get + * blended with the contents of your framebuffer. The blended RGBA components + * are calculated like this: + * + * (RsSr+RdDr, GsSg+GdDg, BsSb+BsSb, AsSa+AdDa) + * + * Where (Rs,Gs,Bs,As) represents your source - material- color, + * (Rd,Gd,Bd,Ad) represents your destination - framebuffer - color, + * (Sr,Sg,Sb,Sa) represents your source blend factor and + * (Dr,Dg,Db,Da) represents you destination blend factor. + * + * All factors lie in the range [0,1] and incoming color components are also + * normalized to the range [0,1] + * + * The factors are selected with the following constants: + * + * COGL_MATERIAL_BLEND_FACTOR_ZERO: (0,0,0,0) + * COGL_MATERIAL_BLEND_FACTOR_ONE: (1,1,1,1) + * COGL_MATERIAL_BLEND_FACTOR_DST_COLOR: (Rd,Gd,Bd,Ad) + * COGL_MATERIAL_BLEND_FACTOR_SRC_COLOR: (Rs,Gs,Bs,As) + * COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_DST_COLOR: + * (1,1,1,1)-(Rd,Gd,Bd,Ad) [Only valid for src_factor] + * COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_SRC_COLOR: + * (1,1,1,1)-(Rs,Gs,Bs,As) + * COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA: (As,As,As,As) + * COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA: + * (1,1,1,1)-(As,As,As,As) [Only valid for dst_factor] + * COGL_MATERIAL_BLEND_FACTOR_DST_ALPHA: (Ad,Ad,Ad,Ad) + * COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_DST_ALPHA: + * (1,1,1,1)-(Ad,Ad,Ad,Ad) + * COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA_SATURATE: + * (f,f,f,1) where f=MIN(As,1-Ad) + * + */ +void cogl_material_set_blend_function (CoglHandle material, + CoglMaterialBlendFactor src_factor, + CoglMaterialBlendFactor dst_factor); + +/** + * cogl_material_set_layer: + * @material: A CoglMaterial object + * + * In addition to the standard OpenGL lighting model a Cogl material may have + * one or more layers comprised of textures that can be blended together in + * order with a number of different texture combine modes. This function + * defines a new texture layer. + * + * The index values of multiple layers do not have to be consecutive; it is + * only their relative order that is important. + * + * XXX: In the future, we may define other types of material layers, such + * as purely GLSL based layers. + */ +void cogl_material_set_layer (CoglHandle material, + gint layer_index, + CoglHandle texture); + +/** + * cogl_material_add_texture: + * @material: A CoglMaterial object + * + * + */ +void cogl_material_remove_layer (CoglHandle material, + gint layer_index); + +/** + * cogl_material_set_layer_alpha_combine_func: + * @material: A CoglMaterial object + * + * TODO: Brew, a nice hot cup of tea, and document these functions... + */ +void cogl_material_set_layer_combine_func ( + CoglHandle material, + gint layer_index, + CoglMaterialLayerCombineChannels channels, + CoglMaterialLayerCombineFunc func); + +void cogl_material_set_layer_combine_arg_src ( + CoglHandle material, + gint layer_index, + gint argument, + CoglMaterialLayerCombineChannels channels, + CoglMaterialLayerCombineSrc src); + +void cogl_material_set_layer_combine_arg_op ( + CoglHandle material, + gint layer_index, + gint argument, + CoglMaterialLayerCombineChannels channels, + CoglMaterialLayerCombineOp op); + +/* TODO: */ +#if 0 + I think it would be be really neat to support a simple string description + of the fixed function texture combine modes exposed above. I think we can + consider this stuff to be set in stone from the POV that more advanced + texture combine functions are catered for with GLSL, so it seems reasonable + to find a concise string representation that can represent all the above + modes in a *much* more readable/useable fashion. I think somthing like + this would be quite nice: + + "MODULATE(TEXTURE[RGB], PREVIOUS[A])" + "ADD(TEXTURE[A],PREVIOUS[RGB])" + "INTERPOLATE(TEXTURE[1-A], PREVIOUS[RGB])" + +void cogl_material_set_layer_rgb_combine (CoglHandle material + gint layer_index, + const char *combine_description); +void cogl_material_set_layer_alpha_combine (CoglHandle material + gint layer_index, + const char *combine_description); +#endif + +/** + * cogl_material_set_layer_matrix: + * @material: A CoglMaterial object + * + * This function lets you set a matrix that can be used to e.g. translate + * and rotate a single layer of a material used to fill your geometry. + */ +void cogl_material_set_layer_matrix (CoglHandle material, + gint layer_index, + CoglMatrix *matrix); + +/** + * cogl_material_get_cogl_enable_flags: + * @material: A CoglMaterial object + * + * This determines what flags need to be passed to cogl_enable before + * this material can be used. Normally you shouldn't need to use this + * function directly since Cogl will do this internally, but if you are + * developing custom primitives directly with OpenGL you may want to use + * this. + * + * Note: This API is hopfully just a stop-gap solution. Ideally + * cogl_enable will be replaced. + */ +gulong +cogl_material_get_cogl_enable_flags (CoglHandle handle); + +/** + * cogl_material_flush_gl_material_state: + * @material: A CoglMaterial object + * + * This commits the glMaterial state to the OpenGL driver. Normally you + * shouldn't need to use this function directly, since Cogl will do this + * internally, but if you are developing custom primitives directly with + * OpenGL you may want to use this. + */ +void cogl_material_flush_gl_material_state (CoglHandle material_handle); + +/** + * cogl_material_flush_gl_alpha_func: + * @material: A CoglMaterial object + * + */ +void cogl_material_flush_gl_alpha_func (CoglHandle material_handle); + +/** + * cogl_material_flush_gl_blend_func: + * @material: A CoglMaterial object + * + */ +void cogl_material_flush_gl_blend_func (CoglHandle material_handle); + +/** + * cogl_material_get_layers: + * @material: A CoglMaterial object + * + * This function lets you access a materials internal list of layers + * for iteration. + * + * Note: Normally you shouldn't need to use this function directly since + * Cogl will do this internally, but if you are developing custom primitives + * directly with OpenGL, you will need to iterate the layers that you want + * to texture with. + * + * Note: This function may return more layers than OpenGL can use at once + * so it's your responsability limit yourself to + * CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS. + * + * Note: It's a bit out of the ordinary to return a const GList *, but it + * was considered sensible to try and avoid list manipulation for every + * primitive emitted in a scene, every frame. + */ +const GList *cogl_material_get_layers (CoglHandle material_handle); + +/** + * cogl_material_layer_get_type: + * @material: A CoglMaterial object + * + * Currently there is only one type of layer defined: + * COGL_MATERIAL_LAYER_TYPE_TEXTURE, but considering we may add purely GLSL + * based layers in the future, you should write code that checks the type + * first. + * + * Note: Normally you shouldn't need to use this function directly since + * Cogl will do this internally, but if you are developing custom primitives + * directly with OpenGL, you will need to iterate the layers that you want + * to texture with, and thus should be checking the layer types. + */ +CoglMaterialLayerType cogl_material_layer_get_type (CoglHandle layer_handle); + +/** + * cogl_material_layer_get_texture: + * @material: A CoglMaterial object + * + * This lets you extract a CoglTexture handle for a specific layer. Normally + * you shouldn't need to use this function directly since Cogl will do this + * internally, but if you are developing custom primitives directly with + * OpenGL you may need this. + * + * Note: In the future, we may support purely GLSL based layers which will + * likley return COGL_INVALID_HANDLE if you try to get the texture. + * Considering this, you should always call cogl_material_layer_get_type + * first, to check it is of type COGL_MATERIAL_LAYER_TYPE_TEXTURE. + */ +CoglHandle cogl_material_layer_get_texture (CoglHandle layer_handle); + +/** + * cogl_material_layer_flush_gl_sampler_state: + * @material: A CoglMaterial object + * + * This commits the sampler state for a single material layer to the OpenGL + * driver. Normally you shouldn't need to use this function directly since + * Cogl will do this internally, but if you are developing custom primitives + * directly with OpenGL you may want to use this. + * + * Note: It assumes you have already activated the appropriate sampler + * by calling glActiveTexture (); + */ +void cogl_material_layer_flush_gl_sampler_state (CoglHandle layer_handle); + +#endif /* __COGL_MATERIAL_H__ */ + diff --git a/cogl.h.in b/cogl.h.in index ea81c7b2c..091770227 100644 --- a/cogl.h.in +++ b/cogl.h.in @@ -33,9 +33,11 @@ #include #include +#include #include #include #include +#include #include #include #include diff --git a/common/Makefile.am b/common/Makefile.am index 755001e1f..f78a2c645 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -30,4 +30,5 @@ libclutter_cogl_common_la_SOURCES = \ cogl-fixed.c \ cogl-color.c \ cogl-mesh.c \ - cogl-matrix.c + cogl-matrix.c \ + cogl-material.c diff --git a/common/cogl-material-private.h b/common/cogl-material-private.h new file mode 100644 index 000000000..d64d8485b --- /dev/null +++ b/common/cogl-material-private.h @@ -0,0 +1,72 @@ +#ifndef __COGL_MATERIAL_PRIVATE_H +#define __COGL_MATERIAL_PRIVATE_H + +#include "cogl-material.h" +#include "cogl-matrix.h" + +#include + +typedef struct _CoglMaterial CoglMaterial; +typedef struct _CoglMaterialLayer CoglMaterialLayer; + +typedef enum _CoglMaterialLayerFlags +{ + COGL_MATERIAL_LAYER_FLAG_USER_MATRIX = 1L<<0, +} CoglMaterialLayerFlags; + +struct _CoglMaterialLayer +{ + guint ref_count; + guint index; /*!< lowest index is blended first then others + on top */ + gulong flags; + CoglHandle texture; /*!< The texture for this layer, or COGL_INVALID_HANDLE + for an empty layer */ + + /* Determines how the color of individual texture fragments + * are calculated. */ + CoglMaterialLayerCombineFunc texture_combine_rgb_func; + CoglMaterialLayerCombineSrc texture_combine_rgb_src[3]; + CoglMaterialLayerCombineOp texture_combine_rgb_op[3]; + + CoglMaterialLayerCombineFunc texture_combine_alpha_func; + CoglMaterialLayerCombineSrc texture_combine_alpha_src[3]; + CoglMaterialLayerCombineOp texture_combine_alpha_op[3]; + + /* TODO: Support purely GLSL based material layers */ + + CoglMatrix matrix; +}; + +typedef enum _CoglMaterialFlags +{ + COGL_MATERIAL_FLAG_ENABLE_BLEND = 1L<<0, + COGL_MATERIAL_FLAG_SHOWN_SAMPLER_WARNING = 1L<<1 +} CoglMaterialFlags; + +struct _CoglMaterial +{ + guint ref_count; + + gulong flags; + + /* Standard OpenGL lighting model attributes */ + GLfloat ambient[4]; + GLfloat diffuse[4]; + GLfloat specular[4]; + GLfloat emission[4]; + GLfloat shininess; + + /* Determines what fragments are discarded based on their alpha */ + CoglMaterialAlphaFunc alpha_func; + GLfloat alpha_func_reference; + + /* Determines how this material is blended with other primitives */ + CoglMaterialBlendFactor blend_src_factor; + CoglMaterialBlendFactor blend_dst_factor; + + GList *layers; +}; + +#endif /* __COGL_MATERIAL_PRIVATE_H */ + diff --git a/common/cogl-material.c b/common/cogl-material.c new file mode 100644 index 000000000..d720c120f --- /dev/null +++ b/common/cogl-material.c @@ -0,0 +1,680 @@ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "cogl.h" +#include "cogl-internal.h" +#include "cogl-context.h" +#include "cogl-handle.h" + +#include "cogl-material-private.h" + +#include + +static void _cogl_material_free (CoglMaterial *tex); +static void _cogl_material_layer_free (CoglMaterialLayer *layer); + +COGL_HANDLE_DEFINE (Material, material, material_handles); +COGL_HANDLE_DEFINE (MaterialLayer, + material_layer, + material_layer_handles); + +CoglHandle +cogl_material_new (void) +{ + /* Create new - blank - material */ + CoglMaterial *material = g_new0 (CoglMaterial, 1); + GLfloat *ambient = material->ambient; + GLfloat *diffuse = material->diffuse; + GLfloat *specular = material->specular; + GLfloat *emission = material->emission; + + material->ref_count = 1; + COGL_HANDLE_DEBUG_NEW (material, material); + + /* Use the same defaults as the GL spec... */ + ambient[0] = 0.2; ambient[1] = 0.2; ambient[2] = 0.2; ambient[3] = 1.0; + diffuse[0] = 0.8; diffuse[1] = 0.8; diffuse[2] = 0.8; diffuse[3] = 1.0; + specular[0] = 0; specular[1] = 0; specular[2] = 0; specular[3] = 1.0; + emission[0] = 0; emission[1] = 0; emission[2] = 0; emission[3] = 1.0; + + /* Use the same defaults as the GL spec... */ + material->alpha_func = COGL_MATERIAL_ALPHA_FUNC_ALWAYS; + material->alpha_func_reference = 0.0; + + /* Not the same as the GL default, but seems saner... */ + material->blend_src_factor = COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA; + material->blend_dst_factor = COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + + material->layers = NULL; + + return _cogl_material_handle_new (material); +} + +static void +_cogl_material_free (CoglMaterial *material) +{ + /* Frees material resources but its handle is not + released! Do that separately before this! */ + + g_list_foreach (material->layers, + (GFunc)cogl_material_layer_unref, NULL); + g_free (material); +} + +void +cogl_material_set_ambient (CoglHandle handle, + const CoglColor *ambient_color) +{ + CoglMaterial *material; + GLfloat *ambient; + + g_return_if_fail (cogl_is_material (handle)); + + material = _cogl_material_pointer_from_handle (handle); + + ambient = material->ambient; + ambient[0] = cogl_color_get_red_float (ambient_color); + ambient[1] = cogl_color_get_green_float (ambient_color); + ambient[2] = cogl_color_get_blue_float (ambient_color); + ambient[3] = cogl_color_get_alpha_float (ambient_color); + /* material->ambient = *ambient_color; */ +} + +void +cogl_material_set_diffuse (CoglHandle handle, + const CoglColor *diffuse_color) +{ + CoglMaterial *material; + GLfloat *diffuse; + + g_return_if_fail (cogl_is_material (handle)); + + material = _cogl_material_pointer_from_handle (handle); + + diffuse = material->diffuse; + diffuse[0] = cogl_color_get_red_float (diffuse_color); + diffuse[1] = cogl_color_get_green_float (diffuse_color); + diffuse[2] = cogl_color_get_blue_float (diffuse_color); + diffuse[3] = cogl_color_get_alpha_float (diffuse_color); + /* material->diffuse = *diffuse_color; */ +} + +void +cogl_material_set_ambient_and_diffuse (CoglHandle handle, + const CoglColor *color) +{ + cogl_material_set_ambient (handle, color); + cogl_material_set_diffuse (handle, color); +} + +void +cogl_material_set_specular (CoglHandle handle, + const CoglColor *specular_color) +{ + CoglMaterial *material; + GLfloat *specular; + + g_return_if_fail (cogl_is_material (handle)); + + material = _cogl_material_pointer_from_handle (handle); + + specular = material->specular; + specular[0] = cogl_color_get_red_float (specular_color); + specular[1] = cogl_color_get_green_float (specular_color); + specular[2] = cogl_color_get_blue_float (specular_color); + specular[3] = cogl_color_get_alpha_float (specular_color); + /* material->specular = *specular_color; */ +} + +void +cogl_material_set_shininess (CoglHandle handle, + float shininess) +{ + CoglMaterial *material; + + g_return_if_fail (cogl_is_material (handle)); + + if (shininess < 0.0 || shininess > 1.0) + g_warning ("Out of range shininess %f supplied for material\n", + shininess); + + material = _cogl_material_pointer_from_handle (handle); + + material->shininess = (GLfloat)shininess * 128.0; +} + +void +cogl_material_set_emission (CoglHandle handle, + const CoglColor *emission_color) +{ + CoglMaterial *material; + GLfloat *emission; + + g_return_if_fail (cogl_is_material (handle)); + + material = _cogl_material_pointer_from_handle (handle); + + emission = material->emission; + emission[0] = cogl_color_get_red_float (emission_color); + emission[1] = cogl_color_get_green_float (emission_color); + emission[2] = cogl_color_get_blue_float (emission_color); + emission[3] = cogl_color_get_alpha_float (emission_color); + /* material->emission = *emission_color; */ +} + +/* TODO: Should go in cogl.c */ +void +cogl_set_source (CoglHandle material_handle) +{ + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + g_return_if_fail (cogl_is_material (material_handle)); + + if (ctx->source_material) + cogl_material_unref (ctx->source_material); + + cogl_material_ref (material_handle); + ctx->source_material = material_handle; +} + +void +cogl_material_set_alpha_test_func (CoglHandle handle, + CoglMaterialAlphaFunc alpha_func, + float alpha_reference) +{ + CoglMaterial *material; + + g_return_if_fail (cogl_is_material (handle)); + + material = _cogl_material_pointer_from_handle (handle); + material->alpha_func = alpha_func; + material->alpha_func_reference = (GLfloat)alpha_reference; +} + +void +cogl_material_set_blend_function (CoglHandle handle, + CoglMaterialBlendFactor src_factor, + CoglMaterialBlendFactor dst_factor) +{ + CoglMaterial *material; + + g_return_if_fail (cogl_is_material (handle)); + + material = _cogl_material_pointer_from_handle (handle); + material->blend_src_factor = src_factor; + material->blend_dst_factor = dst_factor; +} + +/* Asserts that a layer corresponding to the given index exists. If no + * match is found, then a new empty layer is added. + */ +static CoglMaterialLayer * +_cogl_material_get_layer (CoglMaterial *material, + gint index, + gboolean create_if_not_found) +{ + CoglMaterialLayer *layer; + GList *tmp; + CoglHandle layer_handle; + + for (tmp = material->layers; tmp != NULL; tmp = tmp->next) + { + layer = + _cogl_material_layer_pointer_from_handle ((CoglHandle)tmp->data); + if (layer->index == index) + return layer; + + /* The layers are always sorted, so at this point we know this layer + * doesn't exist */ + if (layer->index > index) + break; + } + /* NB: if we now insert a new layer before tmp, that will maintain order. + */ + + if (!create_if_not_found) + return NULL; + + layer = g_new0 (CoglMaterialLayer, 1); + + layer->ref_count = 1; + layer->index = index; + layer->texture = COGL_INVALID_HANDLE; + + /* Choose the same default combine mode as OpenGL: + * MODULATE(PREVIOUS[RGBA],TEXTURE[RGBA]) */ + layer->texture_combine_rgb_func = COGL_MATERIAL_LAYER_COMBINE_FUNC_MODULATE; + layer->texture_combine_rgb_src[0] = COGL_MATERIAL_LAYER_COMBINE_SRC_PREVIOUS; + layer->texture_combine_rgb_src[1] = COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE; + layer->texture_combine_rgb_op[0] = COGL_MATERIAL_LAYER_COMBINE_OP_SRC_COLOR; + layer->texture_combine_rgb_op[1] = COGL_MATERIAL_LAYER_COMBINE_OP_SRC_COLOR; + layer->texture_combine_alpha_func = + COGL_MATERIAL_LAYER_COMBINE_FUNC_MODULATE; + layer->texture_combine_alpha_src[0] = + COGL_MATERIAL_LAYER_COMBINE_SRC_PREVIOUS; + layer->texture_combine_alpha_src[1] = + COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE; + layer->texture_combine_alpha_op[0] = + COGL_MATERIAL_LAYER_COMBINE_OP_SRC_ALPHA; + layer->texture_combine_alpha_op[1] = + COGL_MATERIAL_LAYER_COMBINE_OP_SRC_ALPHA; + + layer_handle = _cogl_material_layer_handle_new (layer); + /* Note: see comment after for() loop above */ + material->layers = + g_list_insert_before (material->layers, tmp, layer_handle); + + return layer; +} + +void +cogl_material_set_layer (CoglHandle material_handle, + gint layer_index, + CoglHandle texture_handle) +{ + CoglMaterial *material; + CoglMaterialLayer *layer; + int n_layers; + + g_return_if_fail (cogl_is_material (material_handle)); + g_return_if_fail (cogl_is_texture (texture_handle)); + + material = _cogl_material_pointer_from_handle (material_handle); + layer = _cogl_material_get_layer (material_handle, layer_index, TRUE); + + /* XXX: If we expose manual control over ENABLE_BLEND, we'll add + * a flag to know when it's user configured, so we don't trash it */ + if (cogl_texture_get_format (texture_handle) & COGL_A_BIT) + material->flags |= COGL_MATERIAL_FLAG_ENABLE_BLEND; + + n_layers = g_list_length (material->layers); + if (n_layers >= CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS) + { + if (!(material->flags & COGL_MATERIAL_FLAG_SHOWN_SAMPLER_WARNING)) + { + g_warning ("Your hardware doesnot have enough texture samplers" + "to handle this many texture layers"); + material->flags |= COGL_MATERIAL_FLAG_SHOWN_SAMPLER_WARNING; + } + /* Note: We always make a best effort attempt to display as many + * layers as possible, so this isn't an _error_ */ + /* Note: in the future we may support enabling/disabling layers + * too, so it may become valid to add more than + * MAX_COMBINED_TEXTURE_IMAGE_UNITS layers. */ + } + + if (layer->texture) + cogl_texture_unref (layer->texture); + + cogl_texture_ref (texture_handle); + layer->texture = texture_handle; +} + +void +cogl_material_set_layer_combine_func ( + CoglHandle handle, + gint layer_index, + CoglMaterialLayerCombineChannels channels, + CoglMaterialLayerCombineFunc func) +{ + CoglMaterial *material; + CoglMaterialLayer *layer; + gboolean set_alpha_func = FALSE; + gboolean set_rgb_func = FALSE; + + g_return_if_fail (cogl_is_material (handle)); + + material = _cogl_material_pointer_from_handle (handle); + layer = _cogl_material_get_layer (material, layer_index, FALSE); + if (!layer) + return; + + if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA) + set_alpha_func = set_rgb_func = TRUE; + else if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB) + set_rgb_func = TRUE; + else if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_ALPHA) + set_alpha_func = TRUE; + + if (set_rgb_func) + layer->texture_combine_rgb_func = func; + if (set_alpha_func) + layer->texture_combine_alpha_func = func; +} + +void +cogl_material_set_layer_combine_arg_src ( + CoglHandle handle, + gint layer_index, + gint argument, + CoglMaterialLayerCombineChannels channels, + CoglMaterialLayerCombineSrc src) +{ + CoglMaterial *material; + CoglMaterialLayer *layer; + gboolean set_arg_alpha_src = FALSE; + gboolean set_arg_rgb_src = FALSE; + + g_return_if_fail (cogl_is_material (handle)); + g_return_if_fail (argument >=0 && argument <= 3); + + material = _cogl_material_pointer_from_handle (handle); + layer = _cogl_material_get_layer (material, layer_index, FALSE); + if (!layer) + return; + + if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA) + set_arg_alpha_src = set_arg_rgb_src = TRUE; + else if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB) + set_arg_rgb_src = TRUE; + else if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_ALPHA) + set_arg_alpha_src = TRUE; + + if (set_arg_rgb_src) + layer->texture_combine_rgb_src[argument] = src; + if (set_arg_alpha_src) + layer->texture_combine_alpha_src[argument] = src; +} + +void +cogl_material_set_layer_combine_arg_op ( + CoglHandle material_handle, + gint layer_index, + gint argument, + CoglMaterialLayerCombineChannels channels, + CoglMaterialLayerCombineOp op) +{ + CoglMaterial *material; + CoglMaterialLayer *layer; + gboolean set_arg_alpha_op = FALSE; + gboolean set_arg_rgb_op = FALSE; + + g_return_if_fail (cogl_is_material (material_handle)); + g_return_if_fail (argument >=0 && argument <= 3); + + material = _cogl_material_pointer_from_handle (material_handle); + layer = _cogl_material_get_layer (material, layer_index, FALSE); + if (!layer) + return; + + if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA) + set_arg_alpha_op = set_arg_rgb_op = TRUE; + else if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGB) + set_arg_rgb_op = TRUE; + else if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_ALPHA) + set_arg_alpha_op = TRUE; + + if (set_arg_rgb_op) + layer->texture_combine_rgb_op[argument] = op; + if (set_arg_alpha_op) + layer->texture_combine_alpha_op[argument] = op; +} + +void +cogl_material_set_layer_matrix (CoglHandle material_handle, + gint layer_index, + CoglMatrix *matrix) +{ + CoglMaterial *material; + CoglMaterialLayer *layer; + + g_return_if_fail (cogl_is_material (material_handle)); + + material = _cogl_material_pointer_from_handle (material_handle); + layer = _cogl_material_get_layer (material, layer_index, FALSE); + if (!layer) + return; + + layer->matrix = *matrix; + layer->flags |= COGL_MATERIAL_LAYER_FLAG_USER_MATRIX; +} + +static void +_cogl_material_layer_free (CoglMaterialLayer *layer) +{ + cogl_texture_unref (layer->texture); + g_free (layer); +} + +void +cogl_material_remove_layer (CoglHandle material_handle, + gint layer_index) +{ + CoglMaterial *material; + CoglMaterialLayer *layer; + GList *tmp; + + g_return_if_fail (cogl_is_material (material_handle)); + + material = _cogl_material_pointer_from_handle (material_handle); + material->flags &= ~COGL_MATERIAL_FLAG_ENABLE_BLEND; + for (tmp = material->layers; tmp != NULL; tmp = tmp->next) + { + layer = tmp->data; + if (layer->index == layer_index) + { + CoglHandle handle = + _cogl_material_layer_handle_from_pointer (layer); + cogl_material_layer_unref (handle); + material->layers = g_list_remove (material->layers, layer); + continue; + } + + /* XXX: If we expose manual control over ENABLE_BLEND, we'll add + * a flag to know when it's user configured, so we don't trash it */ + if (cogl_texture_get_format (layer->texture) & COGL_A_BIT) + material->flags |= COGL_MATERIAL_FLAG_ENABLE_BLEND; + } +} + +/* XXX: This API is hopfully just a stop-gap solution. Ideally cogl_enable + * will be replaced. */ +gulong +cogl_material_get_cogl_enable_flags (CoglHandle material_handle) +{ + CoglMaterial *material; + gulong enable_flags = 0; + + _COGL_GET_CONTEXT (ctx, 0); + + g_return_val_if_fail (cogl_is_material (material_handle), 0); + + material = _cogl_material_pointer_from_handle (material_handle); + + /* Enable blending if the geometry has an associated alpha color, + * or the material wants blending enabled. */ + if (material->flags & COGL_MATERIAL_FLAG_ENABLE_BLEND + || ctx->color_alpha < 255) + enable_flags |= COGL_ENABLE_BLEND; + + return enable_flags; +} + +void +cogl_material_flush_gl_material_state (CoglHandle material_handle) +{ + CoglMaterial *material; + + g_return_if_fail (cogl_is_material (material_handle)); + + material = _cogl_material_pointer_from_handle (material_handle); + + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, material->ambient)); + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, material->diffuse)); + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, material->specular)); + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, material->emission)); + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS, &material->shininess)); +} + +void +cogl_material_flush_gl_alpha_func (CoglHandle material_handle) +{ + CoglMaterial *material; + + g_return_if_fail (cogl_is_material (material_handle)); + + material = _cogl_material_pointer_from_handle (material_handle); + + /* NB: Currently the Cogl defines are compatible with the GL ones: */ + GE (glAlphaFunc (material->alpha_func, material->alpha_func_reference)); +} + +void +cogl_material_flush_gl_blend_func (CoglHandle material_handle) +{ + CoglMaterial *material; + + g_return_if_fail (cogl_is_material (material_handle)); + GE (glBlendFunc (material->blend_src_factor, material->blend_dst_factor)); +} + +/* It's a bit out of the ordinary to return a const GList *, but it's + * probably sensible to try and avoid list manipulation for every + * primitive emitted in a scene, every frame. + * + * Alternativly; we could either add a _foreach function, or maybe + * a function that gets a passed a buffer (that may be stack allocated) + * by the caller. + */ +const GList * +cogl_material_get_layers (CoglHandle material_handle) +{ + CoglMaterial *material; + + g_return_val_if_fail (cogl_is_material (material_handle), NULL); + + material = _cogl_material_pointer_from_handle (material_handle); + + return material->layers; +} + +CoglMaterialLayerType +cogl_material_layer_get_type (CoglHandle layer_handle) +{ + return COGL_MATERIAL_LAYER_TYPE_TEXTURE; +} + +CoglHandle +cogl_material_layer_get_texture (CoglHandle layer_handle) +{ + CoglMaterialLayer *layer; + + g_return_val_if_fail (cogl_is_material_layer (layer_handle), + COGL_INVALID_HANDLE); + + layer = _cogl_material_layer_pointer_from_handle (layer_handle); + return layer->texture; +} + +static guint +get_n_args_for_combine_func (CoglMaterialLayerCombineFunc func) +{ + switch (func) + { + case COGL_MATERIAL_LAYER_COMBINE_FUNC_REPLACE: + return 1; + case COGL_MATERIAL_LAYER_COMBINE_FUNC_MODULATE: + case COGL_MATERIAL_LAYER_COMBINE_FUNC_ADD: + case COGL_MATERIAL_LAYER_COMBINE_FUNC_ADD_SIGNED: + case COGL_MATERIAL_LAYER_COMBINE_FUNC_SUBTRACT: + case COGL_MATERIAL_LAYER_COMBINE_FUNC_DOT3_RGB: + case COGL_MATERIAL_LAYER_COMBINE_FUNC_DOT3_RGBA: + return 2; + case COGL_MATERIAL_LAYER_COMBINE_FUNC_INTERPOLATE: + return 3; + } + return 0; +} + +void +cogl_material_layer_flush_gl_sampler_state (CoglHandle layer_handle) +{ + CoglMaterialLayer *layer; + int n_rgb_func_args; + int n_alpha_func_args; + + g_return_if_fail (cogl_is_material_layer (layer_handle)); + + layer = _cogl_material_layer_pointer_from_handle (layer_handle); + + /* XXX: We really want some kind of cache/dirty flag mechanism + * somewhere here so we can avoid as much mucking about with + * the texture units per primitive as possible! + * + * E.g. some recent profiling of clutter-actor suggested that + * validating/updating the texture environment may currently + * be a significant bottleneck. Given that all the actors should + * have the same texture environment, that implies we could do a + * much better job of avoiding redundant glTexEnv calls. + */ + + GE (glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE)); + + /* Set the combiner functions... */ + GE (glTexEnvi (GL_TEXTURE_ENV, + GL_COMBINE_RGB, + layer->texture_combine_rgb_func)); + GE (glTexEnvi (GL_TEXTURE_ENV, + GL_COMBINE_ALPHA, + layer->texture_combine_alpha_func)); + + /* + * Setup the function arguments... + */ + + /* For the RGB components... */ + n_rgb_func_args = + get_n_args_for_combine_func (layer->texture_combine_rgb_func); + + GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, + layer->texture_combine_rgb_src[0])); + GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, + layer->texture_combine_rgb_op[0])); + if (n_rgb_func_args > 1) + { + GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, + layer->texture_combine_rgb_src[1])); + GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, + layer->texture_combine_rgb_op[1])); + } + if (n_rgb_func_args > 2) + { + GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC2_RGB, + layer->texture_combine_rgb_src[2])); + GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_RGB, + layer->texture_combine_rgb_op[2])); + } + + /* For the Alpha component */ + n_alpha_func_args = + get_n_args_for_combine_func (layer->texture_combine_alpha_func); + + GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, + layer->texture_combine_alpha_src[0])); + GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, + layer->texture_combine_alpha_op[0])); + if (n_alpha_func_args > 1) + { + GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, + layer->texture_combine_alpha_src[1])); + GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, + layer->texture_combine_alpha_op[1])); + } + if (n_alpha_func_args > 2) + { + GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC2_ALPHA, + layer->texture_combine_alpha_src[2])); + GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, + layer->texture_combine_alpha_op[2])); + } + + if (layer->flags & COGL_MATERIAL_LAYER_FLAG_USER_MATRIX) + { + GE (glMatrixMode (GL_TEXTURE)); + GE (glLoadMatrixf ((GLfloat *)&layer->matrix)); + GE (glMatrixMode (GL_MODELVIEW)); + } +} + diff --git a/common/cogl-matrix.h b/common/cogl-matrix.h deleted file mode 100644 index 2f6874fae..000000000 --- a/common/cogl-matrix.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef __COGL_MATRIX_H -#define __COGL_MATRIX_H - -/* Note: This is ordered according to how OpenGL expects to get 4x4 matrices */ -typedef struct { - /* column 0 */ - float xx; - float yx; - float zx; - float wx; - - /* column 1 */ - float xy; - float yy; - float zy; - float wy; - - /* column 2 */ - float xz; - float yz; - float zz; - float wz; - - /* column 3 */ - float xw; - float yw; - float zw; - float ww; - - /* Note: we may want to extend this later with private flags - * and a cache of the inverse transform matrix. */ -} CoglMatrix; - -void cogl_matrix_init_identity (CoglMatrix *matrix); - -void cogl_matrix_multiply (CoglMatrix *result, - const CoglMatrix *a, - const CoglMatrix *b); - -void cogl_matrix_rotate (CoglMatrix *matrix, - float angle, - float x, - float y, - float z); - -void cogl_matrix_translate (CoglMatrix *matrix, - float x, - float y, - float z); - -void cogl_matrix_scale (CoglMatrix *matrix, - float sx, - float sy, - float sz); - -#endif /* __COGL_MATRIX_H */ - diff --git a/gl/cogl-context.c b/gl/cogl-context.c index 86a3d425a..84e46bc92 100644 --- a/gl/cogl-context.c +++ b/gl/cogl-context.c @@ -59,8 +59,9 @@ cogl_create_context () _context->texture_vertices_size = 0; _context->texture_vertices = NULL; - _context->multi_texture_handles = NULL; - _context->multi_texture_layer_handles = NULL; + _context->material_handles = NULL; + _context->material_layer_handles = NULL; + _context->source_material = NULL; _context->fbo_handles = NULL; _context->draw_buffer = COGL_WINDOW_BUFFER; diff --git a/gl/cogl-context.h b/gl/cogl-context.h index afcf9c347..81ec93219 100644 --- a/gl/cogl-context.h +++ b/gl/cogl-context.h @@ -66,11 +66,10 @@ typedef struct CoglTextureGLVertex *texture_vertices; gulong texture_vertices_size; - /* Multi Textures */ - GArray *multi_texture_handles; - - /* Multi Texture Layers */ - GArray *multi_texture_layer_handles; + /* Materials */ + GArray *material_handles; + GArray *material_layer_handles; + CoglHandle source_material; /* Framebuffer objects */ GArray *fbo_handles; diff --git a/gl/cogl-texture-private.h b/gl/cogl-texture-private.h index b6c5af5ec..44fd7712e 100644 --- a/gl/cogl-texture-private.h +++ b/gl/cogl-texture-private.h @@ -31,8 +31,8 @@ typedef struct _CoglTexture CoglTexture; typedef struct _CoglTexSliceSpan CoglTexSliceSpan; typedef struct _CoglSpanIter CoglSpanIter; -typedef struct _CoglMultiTexture CoglMultiTexture; -typedef struct _CoglMultiTextureLayer CoglMultiTextureLayer; +typedef struct _CoglCompositeTexture CoglCompositeTexture; +typedef struct _CoglCompositeTextureLayer CoglCompositeTextureLayer; struct _CoglTexSliceSpan { @@ -61,7 +61,7 @@ struct _CoglTexture gboolean auto_mipmap; }; -struct _CoglMultiTextureLayer +struct _CoglCompositeTextureLayer { guint ref_count; @@ -74,7 +74,7 @@ struct _CoglMultiTextureLayer * unit. For example we should support dot3 normal mapping. */ }; -struct _CoglMultiTexture +struct _CoglCompositeTexture { guint ref_count; GList *layers; diff --git a/gl/cogl-texture.c b/gl/cogl-texture.c index 73478b8db..c1a8ab682 100644 --- a/gl/cogl-texture.c +++ b/gl/cogl-texture.c @@ -32,6 +32,7 @@ #include "cogl-util.h" #include "cogl-bitmap.h" #include "cogl-texture-private.h" +#include "cogl-material.h" #include "cogl-context.h" #include "cogl-handle.h" @@ -50,14 +51,8 @@ } */ static void _cogl_texture_free (CoglTexture *tex); -static void _cogl_multi_texture_free (CoglMultiTexture *multi_texture); -static void _cogl_multi_texture_layer_free (CoglMultiTextureLayer *layer); COGL_HANDLE_DEFINE (Texture, texture, texture_handles); -COGL_HANDLE_DEFINE (MultiTexture, multi_texture, multi_texture_handles); -COGL_HANDLE_DEFINE (MultiTextureLayer, - multi_texture_layer, - multi_texture_layer_handles); struct _CoglSpanIter { @@ -2411,210 +2406,79 @@ cogl_texture_polygon (CoglHandle handle, } } -CoglHandle -cogl_multi_texture_new (void) -{ - CoglMultiTexture *multi_tex = g_new0 (CoglMultiTexture, 1); - return _cogl_multi_texture_handle_new (multi_tex); -} - -static void -_cogl_multi_texture_free (CoglMultiTexture *multi_tex) -{ - g_list_foreach (multi_tex->layers, - (GFunc)cogl_multi_texture_layer_unref, NULL); - g_free (multi_tex); -} - -static CoglMultiTextureLayer * -_cogl_multi_texture_get_layer (CoglMultiTexture *multi_tex, guint index) -{ - CoglMultiTextureLayer *layer; - GList *tmp; - - for (tmp = multi_tex->layers; tmp != NULL; tmp = tmp->next) - { - layer = tmp->data; - if (layer->index == index) - return layer; - - /* The layers are always sorted, so we know this layer doesn't exists */ - if (layer->index > index) - break; - } - /* NB: if we now insert a new layer before tmp, that will maintain order. - */ - - layer = g_new (CoglMultiTextureLayer, 1); - - layer->ref_count = 1; - layer->index = index; - /* Note: comment after for() loop above */ - multi_tex->layers = g_list_insert_before (multi_tex->layers, tmp, layer); - - return layer; -} - void -cogl_multi_texture_layer_set_texture (CoglHandle multi_texture_handle, - guint layer_index, - CoglHandle tex_handle) +cogl_material_rectangle (CoglFixed x1, + CoglFixed y1, + CoglFixed x2, + CoglFixed y2, + CoglFixed *user_tex_coords) { - CoglMultiTexture *multi_tex; - CoglMultiTextureLayer *layer; - CoglTexture *tex; + CoglHandle material; + const GList *layers; + int n_layers; + const GList *tmp; + CoglHandle *valid_layers = NULL; + int n_valid_layers = 0; + gboolean handle_slicing = FALSE; + int i; + GLfloat *tex_coords_buff; + GLfloat quad_coords[8]; + gulong enable_flags = 0; + GLfloat values[4]; - if (!cogl_is_multi_texture (multi_texture_handle) - || !cogl_is_texture (tex_handle)) - return; - - multi_tex = _cogl_multi_texture_pointer_from_handle (multi_texture_handle); - layer = _cogl_multi_texture_get_layer (multi_tex, layer_index); - tex = _cogl_texture_pointer_from_handle (tex_handle); - - cogl_texture_ref (tex_handle); - - layer->tex = tex; -} - -static void -_cogl_multi_texture_layer_free (CoglMultiTextureLayer *layer) -{ - cogl_texture_unref (layer->tex); - g_free (layer); -} - -void -cogl_multi_texture_layer_remove (CoglHandle multi_texture_handle, - guint layer_index) -{ - CoglMultiTexture *multi_tex; - CoglMultiTextureLayer *layer; - GList *tmp; - - /* Check if valid multi texture */ - if (!cogl_is_multi_texture (multi_texture_handle)) - return; - - multi_tex = _cogl_multi_texture_pointer_from_handle (multi_texture_handle); - for (tmp = multi_tex->layers; tmp != NULL; tmp = tmp->next) - { - layer = tmp->data; - if (layer->index == layer_index) - { - CoglHandle handle = - _cogl_multi_texture_layer_handle_from_pointer (layer); - cogl_multi_texture_layer_unref (handle); - multi_tex->layers = g_list_remove (multi_tex->layers, layer); - return; - } - } -} - -void -cogl_multi_texture_rectangle (CoglHandle multi_texture_handle, - CoglFixed x1, - CoglFixed y1, - CoglFixed x2, - CoglFixed y2, - CoglFixed *user_tex_coords) -{ - CoglMultiTexture *multi_tex; - GLfloat quad_coords[8]; - GList *tmp; - GList *valid_layers = NULL; - int count; - GLfloat *tex_coords_buff; - gulong enable_flags = 0; - /* FIXME - currently cogl deals with enabling texturing - * via enable flags, but that can't scale to n texture - * units. Currently we have to be carefull how we leave the - * environment so we don't break things. See the cleanup + /* FIXME - currently cogl deals with enabling texturing via enable flags, + * but that can't scale to n texture units. Currently we have to be carefull + * how we leave the environment so we don't break things. See the cleanup * notes at the end of this function */ _COGL_GET_CONTEXT (ctx, NO_RETVAL); - /* Check if valid multi texture */ - if (!cogl_is_multi_texture (multi_texture_handle)) - return; + material = ctx->source_material; - multi_tex = _cogl_multi_texture_pointer_from_handle (multi_texture_handle); + layers = cogl_material_get_layers (material); + n_layers = g_list_length ((GList *)layers); + valid_layers = alloca (sizeof (CoglHandle) * n_layers); -#define CFX_F COGL_FIXED_TO_FLOAT - quad_coords[0] = CFX_F (x1); - quad_coords[1] = CFX_F (y1); - quad_coords[2] = CFX_F (x2); - quad_coords[3] = CFX_F (y1); - quad_coords[4] = CFX_F (x1); - quad_coords[5] = CFX_F (y2); - quad_coords[6] = CFX_F (x2); - quad_coords[7] = CFX_F (y2); -#undef CFX_F - - enable_flags |= COGL_ENABLE_VERTEX_ARRAY; - GE( glVertexPointer (2, GL_FLOAT, 0, quad_coords)); - - for (count = 0, tmp = multi_tex->layers; - tmp != NULL; - count++, tmp = tmp->next) + for (tmp = layers; tmp != NULL; tmp = tmp->next) { - CoglMultiTextureLayer *layer = tmp->data; - - /* Skip empty layers */ - if (!layer->tex) - { - count--; - continue; - } - - /* FIXME - currently we don't support sliced textures */ - if (layer->tex->slice_gl_handles == NULL - || layer->tex->slice_gl_handles->len < 1) + CoglHandle layer = tmp->data; + CoglHandle texture = cogl_material_layer_get_texture (layer); + + if (cogl_material_layer_get_type (layer) + != COGL_MATERIAL_LAYER_TYPE_TEXTURE) continue; - if (count >= CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS) + /* FIXME: support sliced textures. For now if the first layer is + * sliced then all other layers are ignored, or if the first layer + * is not sliced, we ignore sliced textures in other layers. */ + if (cogl_texture_is_sliced (texture)) { - static gboolean shown_warning = FALSE; - - if (!shown_warning) + if (n_valid_layers == 0) { - g_warning ("Your driver does not support enough texture layers" - "to correctly handle this multi texturing"); - shown_warning = TRUE; + valid_layers[n_valid_layers++] = layer; + handle_slicing = TRUE; + break; } - /* NB: We make a best effort attempt to display as many layers as - * possible. */ - break; + continue; } + valid_layers[n_valid_layers++] = tmp->data; - if (layer->tex->bitmap.format & COGL_A_BIT) - enable_flags |= COGL_ENABLE_BLEND; - - valid_layers = g_list_prepend (valid_layers, layer); + if (n_valid_layers >= CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS) + break; } - valid_layers = g_list_reverse (valid_layers); - - /* Enable blending if the geometry has an associated alpha color, - * or - see above - we also check each layer texture and if any has - * an alpha channel also enable blending. */ - if (ctx->color_alpha < 255) - enable_flags |= COGL_ENABLE_BLEND; - cogl_enable (enable_flags); - + /* NB: It could be that no valid texture layers were found, but * we will still submit a non-textured rectangle in that case. */ - if (count) - tex_coords_buff = alloca (sizeof(GLfloat) * 8 * count); + if (n_valid_layers) + tex_coords_buff = alloca (sizeof(GLfloat) * 8 * n_valid_layers); - /* NB: valid_layers is in order, sorted by index */ - for (count = 0, tmp = valid_layers; - tmp != NULL; - count++, tmp = tmp->next) + for (i = 0; i < n_valid_layers; i++) { - CoglMultiTextureLayer *layer = tmp->data; - CoglFixed *in_tex_coords = &user_tex_coords[count * 4]; - GLfloat *out_tex_coords = &tex_coords_buff[count * 8]; - GLenum gl_tex_handle; + CoglHandle layer = valid_layers[i]; + CoglHandle texture = cogl_material_layer_get_texture (layer); + CoglFixed *in_tex_coords = &user_tex_coords[i * 4]; + GLfloat *out_tex_coords = &tex_coords_buff[i * 8]; + GLuint gl_tex_handle; #define CFX_F COGL_FIXED_TO_FLOAT /* IN LAYOUT: [ tx1:0, ty1:1, tx2:2, ty2:3 ] */ @@ -2629,24 +2493,22 @@ cogl_multi_texture_rectangle (CoglHandle multi_texture_handle, #undef CFX_F /* TODO - support sliced textures */ - gl_tex_handle = g_array_index (layer->tex->slice_gl_handles, GLuint, 0); + cogl_texture_get_gl_texture (texture, &gl_tex_handle, NULL); + //gl_tex_handle = g_array_index (layer->tex->slice_gl_handles, GLuint, 0); - GE (glActiveTexture (GL_TEXTURE0 + count)); - GE (glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)); + GE (glActiveTexture (GL_TEXTURE0 + i)); + cogl_material_layer_flush_gl_sampler_state (layer); GE (glBindTexture (GL_TEXTURE_2D, gl_tex_handle)); /* GE (glEnable (GL_TEXTURE_2D)); */ - GE (glClientActiveTexture (GL_TEXTURE0 + count)); + GE (glClientActiveTexture (GL_TEXTURE0 + i)); GE (glTexCoordPointer (2, GL_FLOAT, 0, out_tex_coords)); /* GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY)); */ /* FIXME - cogl only knows about one texture unit a.t.m * (Also see cleanup note below) */ - if (count == 0) - { - enable_flags |= COGL_ENABLE_TEXTURE_2D | COGL_ENABLE_TEXCOORD_ARRAY; - cogl_enable (enable_flags); - } + if (i == 0) + enable_flags |= COGL_ENABLE_TEXTURE_2D | COGL_ENABLE_TEXCOORD_ARRAY; else { GE (glEnable (GL_TEXTURE_2D)); @@ -2654,19 +2516,62 @@ cogl_multi_texture_rectangle (CoglHandle multi_texture_handle, } } +#define CFX_F COGL_FIXED_TO_FLOAT + quad_coords[0] = CFX_F (x1); + quad_coords[1] = CFX_F (y1); + quad_coords[2] = CFX_F (x2); + quad_coords[3] = CFX_F (y1); + quad_coords[4] = CFX_F (x1); + quad_coords[5] = CFX_F (y2); + quad_coords[6] = CFX_F (x2); + quad_coords[7] = CFX_F (y2); +#undef CFX_F + + enable_flags |= COGL_ENABLE_VERTEX_ARRAY; + GE( glVertexPointer (2, GL_FLOAT, 0, quad_coords)); + + /* Setup the remaining GL state according to this material... */ + cogl_material_flush_gl_material_state (material); + cogl_material_flush_gl_alpha_func (material); + cogl_material_flush_gl_blend_func (material); + /* FIXME: This api is a bit yukky, ideally it will be removed if we + * re-work the cogl_enable mechanism */ + enable_flags |= cogl_material_get_cogl_enable_flags (material); + + /* FIXME - cogl only knows about one texture unit so assumes that unit 0 + * is always active...*/ + GE (glActiveTexture (GL_TEXTURE0)); + GE (glClientActiveTexture (GL_TEXTURE0)); + cogl_enable (enable_flags); glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); /* FIXME - cogl doesn't currently have a way of caching the * enable states for more than one texture unit so for now, * we just disable anything relating to additional units once * we are done with them. */ - while (--count > 0) + for (i = 1; i < n_valid_layers; i++) { - GE (glActiveTexture (GL_TEXTURE0 + count)); - GE (glClientActiveTexture (GL_TEXTURE0 + count)); + GE (glActiveTexture (GL_TEXTURE0 + i)); + GE (glClientActiveTexture (GL_TEXTURE0 + i)); GE (glDisable (GL_TEXTURE_2D)); GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY)); } + + /* FIXME - CoglMaterials aren't yet used pervasively throughout + * the cogl API, so we currently need to cleanup material state + * that will confuse other parts of the API. + * Other places to tweak, include the primitives API and lite + * GL wrappers like cogl_rectangle */ + values[0] = 0.2; values[1] = 0.2; values[2] = 0.2; values[3] = 1.0; + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, values)); + values[0] = 0.8; values[1] = 0.8; values[2] = 0.8; values[3] = 1.0; + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, values)); + values[0] = 0; values[1] = 0; values[2] = 0; values[3] = 1.0; + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, values)); + values[0] = 0; values[1] = 0; values[2] = 0; values[3] = 1.0; + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, values)); + values[0] = 0; + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS, values)); } From 1a8a9c4bc882a03074db782b54dc2ef8b2da21be Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Thu, 18 Dec 2008 19:12:09 +0000 Subject: [PATCH 05/16] Updates previous GLES multi-texturing code to use CoglMaterial test-cogl-material now runs on GLES 1 using the PVR GLES1 SDK (though since only 2 texture units are supported the third rotating light map doesn't show) Note: It currently doesn't build for GLES 2.0 --- cogl-material.h | 2 + gles/cogl-context.c | 5 +- gles/cogl-context.h | 9 +- gles/cogl-texture.c | 318 ++++++++++++++++---------------------------- 4 files changed, 121 insertions(+), 213 deletions(-) diff --git a/cogl-material.h b/cogl-material.h index 9a6f0eb10..973a9d7fb 100644 --- a/cogl-material.h +++ b/cogl-material.h @@ -47,12 +47,14 @@ typedef enum _CoglMaterialBlendFactor 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, +#if 0 COGL_MATERIAL_BLEND_FACTOR_CONSTANT_COLOR = GL_CONSTANT_COLOR, COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR = GL_ONE_MINUS_CONSTANT_COLOR, COGL_MATERIAL_BLEND_FACTOR_CONSTANT_ALPHA = GL_CONSTANT_ALPHA, COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA = GL_ONE_MINUS_CONSTANT_ALPHA +#endif } CoglMaterialBlendFactor; typedef enum _CoglMaterialLayerType diff --git a/gles/cogl-context.c b/gles/cogl-context.c index 7b08576e7..c6ac08809 100644 --- a/gles/cogl-context.c +++ b/gles/cogl-context.c @@ -61,8 +61,9 @@ cogl_create_context () _context->texture_handles = NULL; _context->texture_vertices_size = 0; _context->texture_vertices = NULL; - _context->multi_texture_handles = NULL; - _context->multi_texture_layer_handles = NULL; + _context->material_handles = NULL; + _context->material_layer_handles = NULL; + _context->source_material = COGL_INVALID_HANDLE; _context->fbo_handles = NULL; _context->program_handles = NULL; diff --git a/gles/cogl-context.h b/gles/cogl-context.h index 91fac2ee3..cc1abdd3e 100644 --- a/gles/cogl-context.h +++ b/gles/cogl-context.h @@ -68,11 +68,10 @@ typedef struct CoglTextureGLVertex *texture_vertices; gulong texture_vertices_size; - /* Multi Textures */ - GArray *multi_texture_handles; - - /* Multi Texture Layers */ - GArray *multi_texture_layer_handles; + /* Materials */ + GArray *material_handles; + GArray *material_layer_handles; + CoglHandle source_material; /* Framebuffer objects */ GArray *fbo_handles; diff --git a/gles/cogl-texture.c b/gles/cogl-texture.c index ba1979e8f..a745e3b31 100644 --- a/gles/cogl-texture.c +++ b/gles/cogl-texture.c @@ -32,6 +32,7 @@ #include "cogl-util.h" #include "cogl-bitmap.h" #include "cogl-texture-private.h" +#include "cogl-material.h" #include "cogl-context.h" #include "cogl-handle.h" @@ -52,7 +53,6 @@ #define glEnableClientState cogl_wrap_glEnableClientState #define glDisable cogl_wrap_glDisable #define glDisableClientState cogl_wrap_glDisableClientState -#define glTexEnvx cogl_wrap_glTexEnvx #endif /* @@ -84,14 +84,8 @@ struct _CoglSpanIter }; static void _cogl_texture_free (CoglTexture *tex); -static void _cogl_multi_texture_free (CoglMultiTexture *multi_texture); -static void _cogl_multi_texture_layer_free (CoglMultiTextureLayer *layer); COGL_HANDLE_DEFINE (Texture, texture, texture_handles); -COGL_HANDLE_DEFINE (MultiTexture, multi_texture, multi_texture_handles); -COGL_HANDLE_DEFINE (MultiTextureLayer, - multi_texture_layer, - multi_texture_layer_handles); static void _cogl_texture_bitmap_free (CoglTexture *tex) @@ -2503,210 +2497,81 @@ cogl_texture_polygon (CoglHandle handle, cogl_set_source_color (&vertices[n_vertices - 1].color); } -CoglHandle -cogl_multi_texture_new (void) -{ - CoglMultiTexture *multi_tex = g_new0 (CoglMultiTexture, 1); - return _cogl_multi_texture_handle_new (multi_tex); -} - -static void -_cogl_multi_texture_free (CoglMultiTexture *multi_tex) -{ - g_list_foreach (multi_tex->layers, - (GFunc)cogl_multi_texture_layer_unref, NULL); - g_free (multi_tex); -} - -static CoglMultiTextureLayer * -_cogl_multi_texture_get_layer (CoglMultiTexture *multi_tex, guint index) -{ - CoglMultiTextureLayer *layer; - GList *tmp; - - for (tmp = multi_tex->layers; tmp != NULL; tmp = tmp->next) - { - layer = tmp->data; - if (layer->index == index) - return layer; - - /* The layers are always sorted, so we know this layer doesn't exists */ - if (layer->index > index) - break; - } - /* NB: if we now insert a new layer before tmp, that will maintain order. - */ - - layer = g_new (CoglMultiTextureLayer, 1); - - layer->ref_count = 1; - layer->index = index; - /* Note: comment after for() loop above */ - multi_tex->layers = g_list_insert_before (multi_tex->layers, tmp, layer); - - return layer; -} - void -cogl_multi_texture_layer_set_texture (CoglHandle multi_texture_handle, - guint layer_index, - CoglHandle tex_handle) +cogl_material_rectangle (CoglFixed x1, + CoglFixed y1, + CoglFixed x2, + CoglFixed y2, + CoglFixed *user_tex_coords) { - CoglMultiTexture *multi_tex; - CoglMultiTextureLayer *layer; - CoglTexture *tex; + CoglHandle material; + const GList *layers; + int n_layers; + const GList *tmp; + CoglHandle *valid_layers = NULL; + int n_valid_layers = 0; + gboolean handle_slicing = FALSE; + int i; + GLfloat *tex_coords_buff; + GLfloat quad_coords[8]; + gulong enable_flags = 0; + GLfloat values[4]; - if (!cogl_is_multi_texture (multi_texture_handle) - || !cogl_is_texture (tex_handle)) - return; - - multi_tex = _cogl_multi_texture_pointer_from_handle (multi_texture_handle); - layer = _cogl_multi_texture_get_layer (multi_tex, layer_index); - tex = _cogl_texture_pointer_from_handle (tex_handle); - - cogl_texture_ref (tex_handle); - - layer->tex = tex; -} - -static void -_cogl_multi_texture_layer_free (CoglMultiTextureLayer *layer) -{ - cogl_texture_unref (layer->tex); - g_free (layer); -} - -void -cogl_multi_texture_layer_remove (CoglHandle multi_texture_handle, - guint layer_index) -{ - CoglMultiTexture *multi_tex; - CoglMultiTextureLayer *layer; - GList *tmp; - - /* Check if valid multi texture */ - if (!cogl_is_multi_texture (multi_texture_handle)) - return; - - multi_tex = _cogl_multi_texture_pointer_from_handle (multi_texture_handle); - for (tmp = multi_tex->layers; tmp != NULL; tmp = tmp->next) - { - layer = tmp->data; - if (layer->index == layer_index) - { - CoglHandle handle = - _cogl_multi_texture_layer_handle_from_pointer (layer); - cogl_multi_texture_layer_unref (handle); - multi_tex->layers = g_list_remove (multi_tex->layers, layer); - return; - } - } -} - -void -cogl_multi_texture_rectangle (CoglHandle multi_texture_handle, - CoglFixed x1, - CoglFixed y1, - CoglFixed x2, - CoglFixed y2, - CoglFixed *user_tex_coords) -{ - CoglMultiTexture *multi_tex; - GLfixed quad_coords[8]; - GList *tmp; - GList *valid_layers = NULL; - int count; - GLfloat *tex_coords_buff; - gulong enable_flags = 0; - /* FIXME - currently cogl deals with enabling texturing - * via enable flags, but that can't scale to n texture - * units. Currently we have to be carefull how we leave the - * environment so we don't break things. See the cleanup + /* FIXME - currently cogl deals with enabling texturing via enable flags, + * but that can't scale to n texture units. Currently we have to be carefull + * how we leave the environment so we don't break things. See the cleanup * notes at the end of this function */ _COGL_GET_CONTEXT (ctx, NO_RETVAL); - /* Check if valid multi texture */ - if (!cogl_is_multi_texture (multi_texture_handle)) - return; + material = ctx->source_material; - multi_tex = _cogl_multi_texture_pointer_from_handle (multi_texture_handle); + layers = cogl_material_get_layers (material); + n_layers = g_list_length ((GList *)layers); + valid_layers = alloca (sizeof (CoglHandle) * n_layers); -#define CFX_F COGL_FIXED_TO_FLOAT - quad_coords[0] = CFX_F (x1); - quad_coords[1] = CFX_F (y1); - quad_coords[2] = CFX_F (x2); - quad_coords[3] = CFX_F (y1); - quad_coords[4] = CFX_F (x1); - quad_coords[5] = CFX_F (y2); - quad_coords[6] = CFX_F (x2); - quad_coords[7] = CFX_F (y2); -#undef CFX_F - - enable_flags |= COGL_ENABLE_VERTEX_ARRAY; - GE( glVertexPointer (2, GL_FIXED, 0, quad_coords) ); - - for (count = 0, tmp = multi_tex->layers; - tmp != NULL; - count++, tmp = tmp->next) + for (tmp = layers; tmp != NULL; tmp = tmp->next) { - CoglMultiTextureLayer *layer = tmp->data; - - /* Skip empty layers */ - if (!layer->tex) - { - count--; - continue; - } - - /* FIXME - currently we don't support sliced textures */ - if (layer->tex->slice_gl_handles == NULL - || layer->tex->slice_gl_handles->len < 1) + CoglHandle layer = tmp->data; + CoglHandle texture = cogl_material_layer_get_texture (layer); + + if (cogl_material_layer_get_type (layer) + != COGL_MATERIAL_LAYER_TYPE_TEXTURE) continue; - if (count >= CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS) + /* FIXME: support sliced textures. For now if the first layer is + * sliced then all other layers are ignored, or if the first layer + * is not sliced, we ignore sliced textures in other layers. */ + if (cogl_texture_is_sliced (texture)) { - static gboolean shown_warning = FALSE; - - if (!shown_warning) + if (n_valid_layers == 0) { - g_warning ("Your driver does not support enough texture layers" - "to correctly handle this multi texturing"); - shown_warning = TRUE; + valid_layers[n_valid_layers++] = layer; + handle_slicing = TRUE; + break; } - /* NB: We make a best effort attempt to display as many layers as - * possible. */ - break; + continue; } + valid_layers[n_valid_layers++] = tmp->data; - if (layer->tex->bitmap.format & COGL_A_BIT) - enable_flags |= COGL_ENABLE_BLEND; - - valid_layers = g_list_prepend (valid_layers, layer); + if (n_valid_layers >= CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS) + break; } - valid_layers = g_list_reverse (valid_layers); - - /* Enable blending if the geometry has an associated alpha color, - * or - see above - we also check each layer texture and if any has - * an alpha channel also enable blending. */ - if (ctx->color_alpha < 255) - enable_flags |= COGL_ENABLE_BLEND; - cogl_enable (enable_flags); - + /* NB: It could be that no valid texture layers were found, but * we will still submit a non-textured rectangle in that case. */ - if (count) - tex_coords_buff = alloca (sizeof(GLfloat) * 8 * count); + if (n_valid_layers) + tex_coords_buff = alloca (sizeof(GLfloat) * 8 * n_valid_layers); - /* NB: valid_layers is in order, sorted by index */ - for (count = 0, tmp = valid_layers; - tmp != NULL; - count++, tmp = tmp->next) + for (i = 0; i < n_valid_layers; i++) { - CoglMultiTextureLayer *layer = tmp->data; - CoglFixed *in_tex_coords = &user_tex_coords[count * 4]; - GLfloat *out_tex_coords = &tex_coords_buff[count * 8]; - GLenum gl_tex_handle; + CoglHandle layer = valid_layers[i]; + CoglHandle texture_handle = cogl_material_layer_get_texture (layer); + CoglTexture *texture = _cogl_texture_pointer_from_handle (texture_handle); + CoglFixed *in_tex_coords = &user_tex_coords[i * 4]; + GLfloat *out_tex_coords = &tex_coords_buff[i * 8]; + GLuint gl_tex_handle; + GLenum gl_target; #define CFX_F COGL_FIXED_TO_FLOAT /* IN LAYOUT: [ tx1:0, ty1:1, tx2:2, ty2:3 ] */ @@ -2721,24 +2586,23 @@ cogl_multi_texture_rectangle (CoglHandle multi_texture_handle, #undef CFX_F /* TODO - support sliced textures */ - gl_tex_handle = g_array_index (layer->tex->slice_gl_handles, GLuint, 0); + cogl_texture_get_gl_texture (texture, &gl_tex_handle, &gl_target); - GE (glActiveTexture (GL_TEXTURE0 + count)); - GE (glTexEnvx (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)); - GE( cogl_gles2_wrapper_bind_texture (layer->tex->gl_target, + GE (glActiveTexture (GL_TEXTURE0 + i)); + cogl_material_layer_flush_gl_sampler_state (layer); + GE( cogl_gles2_wrapper_bind_texture (gl_target, gl_tex_handle, - layer->tex->gl_intformat)); + texure->gl_intformat)); + /* GE (glEnable (GL_TEXTURE_2D)); */ - GE (glClientActiveTexture (GL_TEXTURE0 + count)); + GE (glClientActiveTexture (GL_TEXTURE0 + i)); GE (glTexCoordPointer (2, GL_FLOAT, 0, out_tex_coords)); + /* GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY)); */ /* FIXME - cogl only knows about one texture unit a.t.m * (Also see cleanup note below) */ - if (count == 0) - { - enable_flags |= COGL_ENABLE_TEXTURE_2D | COGL_ENABLE_TEXCOORD_ARRAY; - cogl_enable (enable_flags); - } + if (i == 0) + enable_flags |= COGL_ENABLE_TEXTURE_2D | COGL_ENABLE_TEXCOORD_ARRAY; else { GE (glEnable (GL_TEXTURE_2D)); @@ -2746,19 +2610,61 @@ cogl_multi_texture_rectangle (CoglHandle multi_texture_handle, } } - GE (glDrawArrays (GL_TRIANGLE_STRIP, 0, 4) ); +#define CFX_F COGL_FIXED_TO_FLOAT + quad_coords[0] = CFX_F (x1); + quad_coords[1] = CFX_F (y1); + quad_coords[2] = CFX_F (x2); + quad_coords[3] = CFX_F (y1); + quad_coords[4] = CFX_F (x1); + quad_coords[5] = CFX_F (y2); + quad_coords[6] = CFX_F (x2); + quad_coords[7] = CFX_F (y2); +#undef CFX_F + + enable_flags |= COGL_ENABLE_VERTEX_ARRAY; + GE( glVertexPointer (2, GL_FLOAT, 0, quad_coords)); + + /* Setup the remaining GL state according to this material... */ + cogl_material_flush_gl_material_state (material); + cogl_material_flush_gl_alpha_func (material); + cogl_material_flush_gl_blend_func (material); + /* FIXME: This api is a bit yukky, ideally it will be removed if we + * re-work the cogl_enable mechanism */ + enable_flags |= cogl_material_get_cogl_enable_flags (material); + + /* FIXME - cogl only knows about one texture unit so assumes that unit 0 + * is always active...*/ + GE (glActiveTexture (GL_TEXTURE0)); + GE (glClientActiveTexture (GL_TEXTURE0)); + cogl_enable (enable_flags); + glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); /* FIXME - cogl doesn't currently have a way of caching the * enable states for more than one texture unit so for now, * we just disable anything relating to additional units once * we are done with them. */ - while (--count > 0) + for (i = 1; i < n_valid_layers; i++) { - GE (glActiveTexture (GL_TEXTURE0 + count)); - GE (glClientActiveTexture (GL_TEXTURE0 + count)); + GE (glActiveTexture (GL_TEXTURE0 + i)); + GE (glClientActiveTexture (GL_TEXTURE0 + i)); - GE (cogl_wrap_glDisable (GL_TEXTURE_2D)); + GE (glDisable (GL_TEXTURE_2D)); GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY)); } + + /* FIXME - CoglMaterials aren't yet used pervasively throughout + * the cogl API, so we currently need to cleanup material state + * that will confuse other parts of the API. + * Other places to tweak, include the primitives API and lite + * GL wrappers like cogl_rectangle */ + values[0] = 0.2; values[1] = 0.2; values[2] = 0.2; values[3] = 1.0; + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, values)); + values[0] = 0.8; values[1] = 0.8; values[2] = 0.8; values[3] = 1.0; + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, values)); + values[0] = 0; values[1] = 0; values[2] = 0; values[3] = 1.0; + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, values)); + values[0] = 0; values[1] = 0; values[2] = 0; values[3] = 1.0; + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, values)); + values[0] = 0; + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS, values)); } - From 5b61106684b931fba630993f859119a8632effde Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Mon, 22 Dec 2008 16:19:49 +0000 Subject: [PATCH 06/16] [doc] Hooks up cogl-material reference documentation Adds some more gtk-doc comments to cogl-material.h, and adds a new section to cogl-sections.txt --- cogl-material.h | 692 ++++++++++++++++++--------- common/cogl-material.c | 72 +-- doc/reference/cogl/cogl-docs.sgml | 1 + doc/reference/cogl/cogl-sections.txt | 38 ++ 4 files changed, 528 insertions(+), 275 deletions(-) diff --git a/cogl-material.h b/cogl-material.h index 973a9d7fb..43c603559 100644 --- a/cogl-material.h +++ b/cogl-material.h @@ -20,8 +20,180 @@ G_BEGIN_DECLS * blended together. */ -G_END_DECLS +/** + * cogl_material_new: + * + * Allocates and initializes a blank white material + * + * Returns: a handle to the new material + */ +CoglHandle cogl_material_new (void); + +/** + * cogl_material_ref: + * @handle: a @CoglHandle. + * + * Increment the reference count for a cogl material. + * + * Returns: the @handle. + * + * Since 1.0 + */ +CoglHandle cogl_material_ref (CoglHandle handle); + +/** + * cogl_material_unref: + * @handle: a @CoglHandle. + * + * Decrement the reference count for a cogl material. + * + * Since 1.0 + */ +void cogl_material_unref (CoglHandle handle); + +/** + * cogl_material_set_ambient: + * @material: A CoglMaterial object + * @ambient: The components of the desired ambient color + * + * Exposing the standard OpenGL lighting model; this function sets + * the material's ambient color. The ambient color affects the overall + * color of the object. Since the diffuse color will be intense when + * the light hits the surface directly, the ambient will most aparent + * where the light hits at a slant. + * + * The default value is (0.2, 0.2, 0.2, 1.0) + * + * Since 1.0 + */ +void cogl_material_set_ambient (CoglHandle material, + const CoglColor *ambient); + +/** + * cogl_material_set_diffuse: + * @material: A CoglMaterial object + * @diffuse: The components of the desired diffuse color + * + * Exposing the standard OpenGL lighting model; this function sets + * the material's diffuse color. The diffuse color is most intense + * where the light hits the surface directly; perpendicular to the + * surface. + * + * The default value is (0.8, 0.8, 0.8, 1.0) + * + * Since 1.0 + */ +void cogl_material_set_diffuse (CoglHandle material, + const CoglColor *diffuse); + +/** + * cogl_material_set_ambient_and_diffuse: + * @material: A CoglMaterial object + * @color: The components of the desired ambient and diffuse colors + * + * This is a convenience for setting the diffuse and ambient color + * of the material at the same time. + * + * The default ambient color is (0.2, 0.2, 0.2, 1.0) + * The default diffuse color is (0.8, 0.8, 0.8, 1.0) + * + * Since 1.0 + */ +void cogl_material_set_ambient_and_diffuse (CoglHandle material, + const CoglColor *color); + +/** + * cogl_material_set_specular: + * @material: A CoglMaterial object + * @specular: The components of the desired specular color + * + * Exposing the standard OpenGL lighting model; this function sets + * the material's specular color. The intensity of the specular color + * depends on the viewport position, and is brightest along the lines + * of reflection. + * + * The default value is (0.0, 0.0, 0.0, 1.0) + * + * Since 1.0 + */ +void cogl_material_set_specular (CoglHandle material, + const CoglColor *specular); + +/** + * cogl_material_set_shininess: + * @material: A CoglMaterial object + * shininess: The desired shininess; range: [0.0, 1.0] + * + * This function sets the materials shininess which determines how + * specular highlights are calculated. A higher shininess will produce + * smaller brigher highlights. + * + * The default value is 0.0 + * + * Since 1.0 + */ +void cogl_material_set_shininess (CoglHandle material, + float shininess); + +/** + * cogl_material_set_emission: + * @material: A CoglMaterial object + * @emission: The components of the desired emissive color + * + * Exposing the standard OpenGL lighting model; this function sets + * the material's emissive color. It will look like the surface is + * a light source emitting this color. + * + * The default value is (0.0, 0.0, 0.0, 1.0) + * + * Since 1.0 + */ +void cogl_material_set_emission (CoglHandle material, + const CoglColor *emission); + +/** + * cogl_set_source: + * @material: A CoglMaterial object + * + * This function sets the source material that will be used to fill + * subsequent geometry emitted via the cogl API. + * + * XXX: This doesn't really belong to the cogl-material API, it should + * move to cogl.h + * + * Since 1.0 + */ +void cogl_set_source (CoglHandle material); + +/** + * CoglMaterialAlphaFunc: + * @COGL_MATERIAL_ALPHA_FUNC_NEVER: Never let the fragment through. + * @COGL_MATERIAL_ALPHA_FUNC_LESS: Let the fragment through if the incoming + * alpha value is less than the reference alpha + * value. + * @COGL_MATERIAL_ALPHA_FUNC_EQUAL: Let the fragment through if the incoming + * alpha value equals the reference alpha + * value. + * @COGL_MATERIAL_ALPHA_FUNC_LEQUAL: Let the fragment through if the incoming + * alpha value is less than or equal to the + * reference alpha value. + * @COGL_MATERIAL_ALPHA_FUNC_GREATER: Let the fragment through if the incoming + * alpha value is greater than the reference + * alpha value. + * @COGL_MATERIAL_ALPHA_FUNC_NOTEQUAL: Let the fragment through if the incoming + * alpha value does not equal the reference + * alpha value. + * @COGL_MATERIAL_ALPHA_FUNC_GEQUAL: Let the fragment through if the incoming + * alpha value is greater than or equal to the + * reference alpha value. + * @COGL_MATERIAL_ALPHA_FUNC_ALWAYS: Always let the fragment through. + * + * Alpha testing happens before blending primitives with the framebuffer and + * gives an opportunity to discard fragments based on a comparison with the + * incoming alpha value and a reference alpha value. The #CoglMaterialAlphaFunc + * determines how the comparison is done. + */ typedef enum _CoglMaterialAlphaFunc { COGL_MATERIAL_ALPHA_FUNC_NEVER = GL_NEVER, @@ -34,34 +206,157 @@ typedef enum _CoglMaterialAlphaFunc COGL_MATERIAL_ALPHA_FUNC_ALWAYS = GL_ALWAYS } CoglMaterialAlphaFunc; +/** + * cogl_material_set_alpha_test_function: + * @material: A CoglMaterial object + * @alpha_func: A @CoglMaterialAlphaFunc constant + * @alpha_reference: A reference point that the chosen alpha function uses + * to compare incoming fragments to. + * + * Before a primitive is blended with the framebuffer, it goes through an + * alpha test stage which lets you discard fragments based on the current + * alpha value. This function lets you change the function used to evaluate + * the alpha channel, and thus determine which fragments are discarded + * and which continue on to the blending stage. + * + * The default is COGL_MATERIAL_ALPHA_FUNC_ALWAYS + * + * Since 1.0 + */ +void cogl_material_set_alpha_test_function (CoglHandle material, + CoglMaterialAlphaFunc alpha_func, + 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) + * + * 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: + * + * + * R = Rs*Sr + Rd*Dr + * G = Gs*Sg + Gd*Dg + * B = Bs*Sb + Bd*Db + * A = As*Sa + Ad*Da + * + * + * All factors have a range [0, 1] + * + * The factors are selected with the following constants: + */ typedef enum _CoglMaterialBlendFactor { COGL_MATERIAL_BLEND_FACTOR_ZERO = GL_ZERO, COGL_MATERIAL_BLEND_FACTOR_ONE = GL_ONE, - COGL_MATERIAL_BLEND_FACTOR_DST_COLOR = GL_DST_COLOR, COGL_MATERIAL_BLEND_FACTOR_SRC_COLOR = GL_SRC_COLOR, - COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_DST_COLOR = GL_ONE_MINUS_DST_COLOR, + COGL_MATERIAL_BLEND_FACTOR_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, -#if 0 - COGL_MATERIAL_BLEND_FACTOR_CONSTANT_COLOR = GL_CONSTANT_COLOR, - COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR = - GL_ONE_MINUS_CONSTANT_COLOR, - COGL_MATERIAL_BLEND_FACTOR_CONSTANT_ALPHA = GL_CONSTANT_ALPHA, - COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA = - GL_ONE_MINUS_CONSTANT_ALPHA -#endif } CoglMaterialBlendFactor; -typedef enum _CoglMaterialLayerType -{ - COGL_MATERIAL_LAYER_TYPE_TEXTURE -} CoglMaterialLayerType; +/** + * cogl_material_set_blend_factors: + * @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. + * + * This function lets you control how primitives using this material will get + * blended with the contents of your framebuffer. The blended RGBA components + * are calculated like this: + * + * (RsSr+RdDr, GsSg+GdDg, BsSb+BsSb, AsSa+AdDa) + * + * Where (Rs,Gs,Bs,As) represents your source - material- color, + * (Rd,Gd,Bd,Ad) represents your destination - framebuffer - color, + * (Sr,Sg,Sb,Sa) represents your source blend factor and + * (Dr,Dg,Db,Da) represents you destination blend factor. + * + * All factors lie in the range [0,1] and incoming color components are also + * normalized to the range [0,1] + * + * Since 1.0 + */ +void cogl_material_set_blend_factors (CoglHandle material, + CoglMaterialBlendFactor src_factor, + CoglMaterialBlendFactor dst_factor); +/** + * cogl_material_set_layer: + * @material: A CoglMaterial object + * + * In addition to the standard OpenGL lighting model a Cogl material may have + * one or more layers comprised of textures that can be blended together in + * order, with a number of different texture combine modes. This function + * defines a new texture layer. + * + * The index values of multiple layers do not have to be consecutive; it is + * only their relative order that is important. + * + * XXX: In the future, we may define other types of material layers, such + * as purely GLSL based layers. + * + * Since 1.0 + */ +void cogl_material_set_layer (CoglHandle material, + gint layer_index, + CoglHandle texture); + +/** + * cogl_material_add_texture: + * @material: A CoglMaterial object + * @layer_index: Specifies the layer you want to remove + * + * This function removes a layer from your 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)) + + * + * 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: + * + * + * (Rs*Rp, Gs*Gp, Bs*Bp, As*Ap) + * + * + * 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 = GL_REPLACE, @@ -74,6 +369,27 @@ typedef enum _CoglMaterialLayerCombineFunc COGL_MATERIAL_LAYER_COMBINE_FUNC_DOT3_RGBA = GL_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, @@ -81,6 +397,90 @@ typedef enum _CoglMaterialLayerCombineChannels 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: + * + * //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); + * + */ +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. + */ typedef enum _CoglMaterialLayerCombineSrc { COGL_MATERIAL_LAYER_COMBINE_SRC_TEXTURE = GL_TEXTURE, @@ -101,6 +501,21 @@ typedef enum _CoglMaterialLayerCombineSrc COGL_MATERIAL_LAYER_COMBINE_SRC_PREVIOUS = GL_PREVIOUS } CoglMaterialLayerCombineSrc; +/** + * cogl_material_set_layer_combine_arg_src: + * @material: A CoglMaterial object + * @layer_index: + * @argument: + * @channels: + * @src: + * + */ +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, @@ -111,231 +526,19 @@ typedef enum _CoglMaterialLayerCombineOp } CoglMaterialLayerCombineOp; /** - * cogl_material_new: - * - * Allocates and initializes blank white material - */ -CoglHandle cogl_material_new (void); - -/** - * cogl_material_ref: - * @handle: a @CoglHandle. - * - * Increment the reference count for a cogl material. - * - * Returns: the @handle. - */ -CoglHandle cogl_material_ref (CoglHandle handle); - -/** - * cogl_material_unref: - * @handle: a @CoglHandle. - * - * Deccrement the reference count for a cogl material. - */ -void cogl_material_unref (CoglHandle handle); - -/** - * cogl_material_set_diffuse: + * cogl_material_set_layer_combine_arg_op: * @material: A CoglMaterial object - * @diffuse: The components of the desired diffuse color - * - * Exposing the standard OpenGL lighting model; this function sets - * the material's diffuse color. The diffuse color is most intense - * where the light hits the surface directly; perpendicular to the - * surface. - */ -void cogl_material_set_diffuse (CoglHandle material, - const CoglColor *diffuse); - -/** - * cogl_material_set_ambient: - * @material: A CoglMaterial object - * @ambient: The components of the desired ambient color - * - * Exposing the standard OpenGL lighting model; this function sets - * the material's ambient color. The ambient color affects the overall - * color of the object. Since the diffuse color will be intense when - * the light hits the surface directly, the ambient will most aparent - * where the light hits at a slant. - */ -void cogl_material_set_ambient (CoglHandle material, - const CoglColor *ambient); - -/** - * cogl_material_set_ambient_and_diffuse: - * @material: A CoglMaterial object - * @color: The components of the desired ambient and diffuse colors - * - * This is a convenience for setting the diffuse and ambient color - * of the material at the same time. - */ -void cogl_material_set_ambient_and_diffuse (CoglHandle material, - const CoglColor *color); - -/** - * cogl_material_set_specular: - * @material: A CoglMaterial object - * @specular: The components of the desired specular color - * - * Exposing the standard OpenGL lighting model; this function sets - * the material's specular color. The intensity of the specular color - * depends on the viewport position, and is brightest along the lines - * of reflection. - */ -void cogl_material_set_specular (CoglHandle material, - const CoglColor *specular); - -/** - * cogl_material_set_shininess: - * @material: A CoglMaterial object - * shininess: The desired shininess; range: [0.0, 1.0] - * - * This function sets the materials shininess which determines how - * specular highlights are calculated. A higher shininess will produce - * smaller brigher highlights. - */ -void cogl_material_set_shininess (CoglHandle material, - float shininess); - -/** - * cogl_material_set_emission: - * @material: A CoglMaterial object - * @emission: The components of the desired emissive color - * - * Exposing the standard OpenGL lighting model; this function sets - * the material's emissive color. It will look like the surface is - * a light source emitting this color. - */ -void cogl_material_set_emission (CoglHandle material, - const CoglColor *emission); - -/** - * cogl_set_source: - * @material: A CoglMaterial object - * - * This function sets the source material that will be used to fill - * subsequent geometry emitted via the cogl API. - * - * XXX: This doesn't really belong to the cogl-material API, it should - * move to cogl.h - */ -void cogl_set_source (CoglHandle material); - -/** - * cogl_material_set_alpha_test_func: - * @material: A CoglMaterial object - * - * Before a primitive is blended with the framebuffer, it goes through an - * alpha test stage which lets you discard fragments based on the current - * alpha value. This function lets you change the function used to evaluate - * the alpha channel, and thus determine which fragments are discarded - * and which continue on to the blending stage. - * TODO: expand on this - */ -void cogl_material_set_alpha_test_func (CoglHandle material, - CoglMaterialAlphaFunc alpha_func, - float alpha_reference); - -/** - * cogl_material_set_blend_function: - * @material: A CoglMaterial object - * @src_factor: Chooses the source factor you want plugged in to the blend - * equation. - * @dst_factor: Chooses the source factor you want plugged in to the blend - * equation. - * - * This function lets you control how primitives using this material will get - * blended with the contents of your framebuffer. The blended RGBA components - * are calculated like this: - * - * (RsSr+RdDr, GsSg+GdDg, BsSb+BsSb, AsSa+AdDa) - * - * Where (Rs,Gs,Bs,As) represents your source - material- color, - * (Rd,Gd,Bd,Ad) represents your destination - framebuffer - color, - * (Sr,Sg,Sb,Sa) represents your source blend factor and - * (Dr,Dg,Db,Da) represents you destination blend factor. - * - * All factors lie in the range [0,1] and incoming color components are also - * normalized to the range [0,1] - * - * The factors are selected with the following constants: - * - * COGL_MATERIAL_BLEND_FACTOR_ZERO: (0,0,0,0) - * COGL_MATERIAL_BLEND_FACTOR_ONE: (1,1,1,1) - * COGL_MATERIAL_BLEND_FACTOR_DST_COLOR: (Rd,Gd,Bd,Ad) - * COGL_MATERIAL_BLEND_FACTOR_SRC_COLOR: (Rs,Gs,Bs,As) - * COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_DST_COLOR: - * (1,1,1,1)-(Rd,Gd,Bd,Ad) [Only valid for src_factor] - * COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_SRC_COLOR: - * (1,1,1,1)-(Rs,Gs,Bs,As) - * COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA: (As,As,As,As) - * COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA: - * (1,1,1,1)-(As,As,As,As) [Only valid for dst_factor] - * COGL_MATERIAL_BLEND_FACTOR_DST_ALPHA: (Ad,Ad,Ad,Ad) - * COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_DST_ALPHA: - * (1,1,1,1)-(Ad,Ad,Ad,Ad) - * COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA_SATURATE: - * (f,f,f,1) where f=MIN(As,1-Ad) - * - */ -void cogl_material_set_blend_function (CoglHandle material, - CoglMaterialBlendFactor src_factor, - CoglMaterialBlendFactor dst_factor); - -/** - * cogl_material_set_layer: - * @material: A CoglMaterial object - * - * In addition to the standard OpenGL lighting model a Cogl material may have - * one or more layers comprised of textures that can be blended together in - * order with a number of different texture combine modes. This function - * defines a new texture layer. - * - * The index values of multiple layers do not have to be consecutive; it is - * only their relative order that is important. - * - * XXX: In the future, we may define other types of material layers, such - * as purely GLSL based layers. - */ -void cogl_material_set_layer (CoglHandle material, - gint layer_index, - CoglHandle texture); - -/** - * cogl_material_add_texture: - * @material: A CoglMaterial object - * + * @layer_index: + * @argument: + * @channels: + * @op: * */ -void cogl_material_remove_layer (CoglHandle material, - gint layer_index); - -/** - * cogl_material_set_layer_alpha_combine_func: - * @material: A CoglMaterial object - * - * TODO: Brew, a nice hot cup of tea, and document these functions... - */ -void cogl_material_set_layer_combine_func ( - CoglHandle material, - gint layer_index, - CoglMaterialLayerCombineChannels channels, - CoglMaterialLayerCombineFunc func); - -void cogl_material_set_layer_combine_arg_src ( - CoglHandle material, - gint layer_index, - gint argument, - CoglMaterialLayerCombineChannels channels, - CoglMaterialLayerCombineSrc src); - -void cogl_material_set_layer_combine_arg_op ( - CoglHandle material, - gint layer_index, - gint argument, - CoglMaterialLayerCombineChannels channels, - CoglMaterialLayerCombineOp op); +void cogl_material_set_layer_combine_arg_op (CoglHandle material, + gint layer_index, + gint argument, + CoglMaterialLayerCombineChannels channels, + CoglMaterialLayerCombineOp op); /* TODO: */ #if 0 @@ -366,8 +569,8 @@ void cogl_material_set_layer_alpha_combine (CoglHandle material * This function lets you set a matrix that can be used to e.g. translate * and rotate a single layer of a material used to fill your geometry. */ -void cogl_material_set_layer_matrix (CoglHandle material, - gint layer_index, +void cogl_material_set_layer_matrix (CoglHandle material, + gint layer_index, CoglMatrix *matrix); /** @@ -433,6 +636,15 @@ void cogl_material_flush_gl_blend_func (CoglHandle material_handle); */ const GList *cogl_material_get_layers (CoglHandle material_handle); +/** + * CoglMaterialLayerType: + * @COGL_MATERIAL_LAYER_TYPE_TEXTURE: The layer represents a CoglTexture + */ +typedef enum _CoglMaterialLayerType +{ + COGL_MATERIAL_LAYER_TYPE_TEXTURE +} CoglMaterialLayerType; + /** * cogl_material_layer_get_type: * @material: A CoglMaterial object @@ -479,5 +691,7 @@ CoglHandle cogl_material_layer_get_texture (CoglHandle layer_handle); */ void cogl_material_layer_flush_gl_sampler_state (CoglHandle layer_handle); +G_END_DECLS + #endif /* __COGL_MATERIAL_H__ */ diff --git a/common/cogl-material.c b/common/cogl-material.c index d720c120f..7d98d3de1 100644 --- a/common/cogl-material.c +++ b/common/cogl-material.c @@ -29,10 +29,10 @@ cogl_material_new (void) GLfloat *diffuse = material->diffuse; GLfloat *specular = material->specular; GLfloat *emission = material->emission; - + material->ref_count = 1; COGL_HANDLE_DEBUG_NEW (material, material); - + /* Use the same defaults as the GL spec... */ ambient[0] = 0.2; ambient[1] = 0.2; ambient[2] = 0.2; ambient[3] = 1.0; diffuse[0] = 0.8; diffuse[1] = 0.8; diffuse[2] = 0.8; diffuse[3] = 1.0; @@ -42,7 +42,7 @@ cogl_material_new (void) /* Use the same defaults as the GL spec... */ material->alpha_func = COGL_MATERIAL_ALPHA_FUNC_ALWAYS; material->alpha_func_reference = 0.0; - + /* Not the same as the GL default, but seems saner... */ material->blend_src_factor = COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA; material->blend_dst_factor = COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; @@ -69,9 +69,9 @@ cogl_material_set_ambient (CoglHandle handle, { CoglMaterial *material; GLfloat *ambient; - + g_return_if_fail (cogl_is_material (handle)); - + material = _cogl_material_pointer_from_handle (handle); ambient = material->ambient; @@ -88,9 +88,9 @@ cogl_material_set_diffuse (CoglHandle handle, { CoglMaterial *material; GLfloat *diffuse; - + g_return_if_fail (cogl_is_material (handle)); - + material = _cogl_material_pointer_from_handle (handle); diffuse = material->diffuse; @@ -115,9 +115,9 @@ cogl_material_set_specular (CoglHandle handle, { CoglMaterial *material; GLfloat *specular; - + g_return_if_fail (cogl_is_material (handle)); - + material = _cogl_material_pointer_from_handle (handle); specular = material->specular; @@ -133,13 +133,13 @@ cogl_material_set_shininess (CoglHandle handle, float shininess) { CoglMaterial *material; - + g_return_if_fail (cogl_is_material (handle)); if (shininess < 0.0 || shininess > 1.0) g_warning ("Out of range shininess %f supplied for material\n", shininess); - + material = _cogl_material_pointer_from_handle (handle); material->shininess = (GLfloat)shininess * 128.0; @@ -151,9 +151,9 @@ cogl_material_set_emission (CoglHandle handle, { CoglMaterial *material; GLfloat *emission; - + g_return_if_fail (cogl_is_material (handle)); - + material = _cogl_material_pointer_from_handle (handle); emission = material->emission; @@ -169,9 +169,9 @@ void cogl_set_source (CoglHandle material_handle) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); - + g_return_if_fail (cogl_is_material (material_handle)); - + if (ctx->source_material) cogl_material_unref (ctx->source_material); @@ -180,28 +180,28 @@ cogl_set_source (CoglHandle material_handle) } void -cogl_material_set_alpha_test_func (CoglHandle handle, - CoglMaterialAlphaFunc alpha_func, - float alpha_reference) +cogl_material_set_alpha_test_function (CoglHandle handle, + CoglMaterialAlphaFunc alpha_func, + float alpha_reference) { CoglMaterial *material; g_return_if_fail (cogl_is_material (handle)); - + material = _cogl_material_pointer_from_handle (handle); material->alpha_func = alpha_func; material->alpha_func_reference = (GLfloat)alpha_reference; } void -cogl_material_set_blend_function (CoglHandle handle, - CoglMaterialBlendFactor src_factor, - CoglMaterialBlendFactor dst_factor) +cogl_material_set_blend_factors (CoglHandle handle, + CoglMaterialBlendFactor src_factor, + CoglMaterialBlendFactor dst_factor) { CoglMaterial *material; g_return_if_fail (cogl_is_material (handle)); - + material = _cogl_material_pointer_from_handle (handle); material->blend_src_factor = src_factor; material->blend_dst_factor = dst_factor; @@ -243,7 +243,7 @@ _cogl_material_get_layer (CoglMaterial *material, layer->index = index; layer->texture = COGL_INVALID_HANDLE; - /* Choose the same default combine mode as OpenGL: + /* 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; @@ -283,7 +283,7 @@ cogl_material_set_layer (CoglHandle material_handle, material = _cogl_material_pointer_from_handle (material_handle); layer = _cogl_material_get_layer (material_handle, layer_index, TRUE); - + /* XXX: If we expose manual control over ENABLE_BLEND, we'll add * a flag to know when it's user configured, so we don't trash it */ if (cogl_texture_get_format (texture_handle) & COGL_A_BIT) @@ -313,7 +313,7 @@ cogl_material_set_layer (CoglHandle material_handle, } void -cogl_material_set_layer_combine_func ( +cogl_material_set_layer_combine_function ( CoglHandle handle, gint layer_index, CoglMaterialLayerCombineChannels channels, @@ -323,7 +323,7 @@ cogl_material_set_layer_combine_func ( CoglMaterialLayer *layer; gboolean set_alpha_func = FALSE; gboolean set_rgb_func = FALSE; - + g_return_if_fail (cogl_is_material (handle)); material = _cogl_material_pointer_from_handle (handle); @@ -356,7 +356,7 @@ cogl_material_set_layer_combine_arg_src ( 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); @@ -371,7 +371,7 @@ cogl_material_set_layer_combine_arg_src ( 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) @@ -390,7 +390,7 @@ cogl_material_set_layer_combine_arg_op ( 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); @@ -405,7 +405,7 @@ cogl_material_set_layer_combine_arg_op ( 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) @@ -419,7 +419,7 @@ cogl_material_set_layer_matrix (CoglHandle material_handle, { CoglMaterial *material; CoglMaterialLayer *layer; - + g_return_if_fail (cogl_is_material (material_handle)); material = _cogl_material_pointer_from_handle (material_handle); @@ -500,7 +500,7 @@ cogl_material_flush_gl_material_state (CoglHandle material_handle) g_return_if_fail (cogl_is_material (material_handle)); material = _cogl_material_pointer_from_handle (material_handle); - + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, material->ambient)); GE (glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, material->diffuse)); GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, material->specular)); @@ -619,9 +619,9 @@ cogl_material_layer_flush_gl_sampler_state (CoglHandle layer_handle) GE (glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, layer->texture_combine_alpha_func)); - - /* - * Setup the function arguments... + + /* + * Setup the function arguments... */ /* For the RGB components... */ diff --git a/doc/reference/cogl/cogl-docs.sgml b/doc/reference/cogl/cogl-docs.sgml index f872b0349..7e2c0974c 100644 --- a/doc/reference/cogl/cogl-docs.sgml +++ b/doc/reference/cogl/cogl-docs.sgml @@ -57,6 +57,7 @@ + diff --git a/doc/reference/cogl/cogl-sections.txt b/doc/reference/cogl/cogl-sections.txt index 84c43dbf3..fe81ddab1 100644 --- a/doc/reference/cogl/cogl-sections.txt +++ b/doc/reference/cogl/cogl-sections.txt @@ -304,3 +304,41 @@ cogl_matrix_translate cogl_matrix_scale +
+cogl-material +Materials +cogl_material_new +cogl_material_ref +cogl_material_unref +cogl_material_set_diffuse +cogl_material_set_ambient +cogl_material_set_ambient_and_diffuse +cogl_material_set_specular +cogl_material_set_shininess +cogl_material_set_emission +cogl_set_source +CoglMaterialAlphaFunc +cogl_material_set_alpha_test_function +CoglMaterialBlendFactor +cogl_material_set_blend_factors +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_matrix +cogl_material_get_cogl_enable_flags +cogl_material_flush_gl_material_state +cogl_material_flush_gl_alpha_func +cogl_material_flush_gl_blend_func +cogl_material_get_layers +CoglMaterialLayerType +cogl_material_layer_get_type +cogl_material_layer_get_texture +cogl_material_layer_flush_gl_sampler_state +
+ From e4548bcdc59cf0720227fbc87ce1b48eb63fb003 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Tue, 23 Dec 2008 23:22:40 +0000 Subject: [PATCH 07/16] [cogl-material] Some improvements for how we sync CoglMaterial state with OpenGL This flattens the three functions: cogl_material_flush_gl_material_state, .._flush_gl_alpha_func and .._flush_gl_blend_func into one: cogl_flush_material_gl_state which doesn't takes a material handle. (the handle is instead taken from the context.) This has allows us to avoid re-submitting some state to OpenGL when the material has not been replaced. Note: Avoiding redundant state changes for material layers isn't dealt with in this patch. --- cogl-material.h | 72 ++++++++++++------------- common/cogl-material.c | 116 +++++++++++++++++++++-------------------- gl/cogl-context.c | 1 + gl/cogl-context.h | 1 + gl/cogl-texture.c | 5 +- 5 files changed, 97 insertions(+), 98 deletions(-) diff --git a/cogl-material.h b/cogl-material.h index 43c603559..2ad878551 100644 --- a/cogl-material.h +++ b/cogl-material.h @@ -152,20 +152,6 @@ void cogl_material_set_shininess (CoglHandle material, void cogl_material_set_emission (CoglHandle material, const CoglColor *emission); -/** - * cogl_set_source: - * @material: A CoglMaterial object - * - * This function sets the source material that will be used to fill - * subsequent geometry emitted via the cogl API. - * - * XXX: This doesn't really belong to the cogl-material API, it should - * move to cogl.h - * - * Since 1.0 - */ -void cogl_set_source (CoglHandle material); - /** * CoglMaterialAlphaFunc: * @COGL_MATERIAL_ALPHA_FUNC_NEVER: Never let the fragment through. @@ -586,34 +572,10 @@ void cogl_material_set_layer_matrix (CoglHandle material, * 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_flush_gl_material_state: - * @material: A CoglMaterial object - * - * This commits the glMaterial state to the OpenGL driver. Normally you - * shouldn't need to use this function directly, since Cogl will do this - * internally, but if you are developing custom primitives directly with - * OpenGL you may want to use this. - */ -void cogl_material_flush_gl_material_state (CoglHandle material_handle); - -/** - * cogl_material_flush_gl_alpha_func: - * @material: A CoglMaterial object - * - */ -void cogl_material_flush_gl_alpha_func (CoglHandle material_handle); - -/** - * cogl_material_flush_gl_blend_func: - * @material: A CoglMaterial object - * - */ -void cogl_material_flush_gl_blend_func (CoglHandle material_handle); - /** * cogl_material_get_layers: * @material: A CoglMaterial object @@ -691,6 +653,38 @@ CoglHandle cogl_material_layer_get_texture (CoglHandle layer_handle); */ void cogl_material_layer_flush_gl_sampler_state (CoglHandle layer_handle); +/** + * cogl_set_source: + * @material: A CoglMaterial object + * + * This function sets the source material that will be used to fill + * subsequent geometry emitted via the cogl API. + * + * Note: in the future we may add the ability to set a front facing + * material, and a back facing material, in which case this function + * will set both to the same. + * + * Since 1.0 + */ +/* XXX: This doesn't really belong to the cogl-material API, it should + * move to cogl.h */ +void cogl_set_source (CoglHandle material); + +/** + * cogl_flush_material_gl_state: + * + * This function commits all the state of the source CoglMaterial - not + * including the per-layer state - to the OpenGL[ES] driver. + * + * Normally you shouldn't need to use this function directly, but if you + * are developing a custom primitive using raw OpenGL that works with + * CoglMaterials, then you may want to use this function. + * + * Since 1.0 + */ +/* XXX: This should be moved with cogl_set_source to cogl.h */ +void cogl_flush_material_gl_state (void); + G_END_DECLS #endif /* __COGL_MATERIAL_H__ */ diff --git a/common/cogl-material.c b/common/cogl-material.c index 7d98d3de1..2e9f5a353 100644 --- a/common/cogl-material.c +++ b/common/cogl-material.c @@ -79,7 +79,8 @@ cogl_material_set_ambient (CoglHandle handle, ambient[1] = cogl_color_get_green_float (ambient_color); ambient[2] = cogl_color_get_blue_float (ambient_color); ambient[3] = cogl_color_get_alpha_float (ambient_color); - /* material->ambient = *ambient_color; */ + + material->flags |= COGL_MATERIAL_FLAG_DIRTY; } void @@ -98,7 +99,8 @@ cogl_material_set_diffuse (CoglHandle handle, diffuse[1] = cogl_color_get_green_float (diffuse_color); diffuse[2] = cogl_color_get_blue_float (diffuse_color); diffuse[3] = cogl_color_get_alpha_float (diffuse_color); - /* material->diffuse = *diffuse_color; */ + + material->flags |= COGL_MATERIAL_FLAG_DIRTY; } void @@ -125,7 +127,8 @@ cogl_material_set_specular (CoglHandle handle, specular[1] = cogl_color_get_green_float (specular_color); specular[2] = cogl_color_get_blue_float (specular_color); specular[3] = cogl_color_get_alpha_float (specular_color); - /* material->specular = *specular_color; */ + + material->flags |= COGL_MATERIAL_FLAG_DIRTY; } void @@ -143,6 +146,8 @@ cogl_material_set_shininess (CoglHandle handle, material = _cogl_material_pointer_from_handle (handle); material->shininess = (GLfloat)shininess * 128.0; + + material->flags |= COGL_MATERIAL_FLAG_DIRTY; } void @@ -161,22 +166,8 @@ cogl_material_set_emission (CoglHandle handle, emission[1] = cogl_color_get_green_float (emission_color); emission[2] = cogl_color_get_blue_float (emission_color); emission[3] = cogl_color_get_alpha_float (emission_color); - /* material->emission = *emission_color; */ -} -/* TODO: Should go in cogl.c */ -void -cogl_set_source (CoglHandle material_handle) -{ - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - g_return_if_fail (cogl_is_material (material_handle)); - - if (ctx->source_material) - cogl_material_unref (ctx->source_material); - - cogl_material_ref (material_handle); - ctx->source_material = material_handle; + material->flags |= COGL_MATERIAL_FLAG_DIRTY; } void @@ -191,6 +182,8 @@ cogl_material_set_alpha_test_function (CoglHandle handle, material = _cogl_material_pointer_from_handle (handle); material->alpha_func = alpha_func; material->alpha_func_reference = (GLfloat)alpha_reference; + + material->flags |= COGL_MATERIAL_FLAG_DIRTY; } void @@ -205,6 +198,8 @@ cogl_material_set_blend_factors (CoglHandle handle, material = _cogl_material_pointer_from_handle (handle); material->blend_src_factor = src_factor; material->blend_dst_factor = dst_factor; + + material->flags |= COGL_MATERIAL_FLAG_DIRTY; } /* Asserts that a layer corresponding to the given index exists. If no @@ -492,44 +487,6 @@ cogl_material_get_cogl_enable_flags (CoglHandle material_handle) return enable_flags; } -void -cogl_material_flush_gl_material_state (CoglHandle material_handle) -{ - CoglMaterial *material; - - g_return_if_fail (cogl_is_material (material_handle)); - - material = _cogl_material_pointer_from_handle (material_handle); - - GE (glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, material->ambient)); - GE (glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, material->diffuse)); - GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, material->specular)); - GE (glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, material->emission)); - GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS, &material->shininess)); -} - -void -cogl_material_flush_gl_alpha_func (CoglHandle material_handle) -{ - CoglMaterial *material; - - g_return_if_fail (cogl_is_material (material_handle)); - - material = _cogl_material_pointer_from_handle (material_handle); - - /* NB: Currently the Cogl defines are compatible with the GL ones: */ - GE (glAlphaFunc (material->alpha_func, material->alpha_func_reference)); -} - -void -cogl_material_flush_gl_blend_func (CoglHandle material_handle) -{ - CoglMaterial *material; - - g_return_if_fail (cogl_is_material (material_handle)); - GE (glBlendFunc (material->blend_src_factor, material->blend_dst_factor)); -} - /* It's a bit out of the ordinary to return a const GList *, but it's * probably sensible to try and avoid list manipulation for every * primitive emitted in a scene, every frame. @@ -678,3 +635,50 @@ cogl_material_layer_flush_gl_sampler_state (CoglHandle layer_handle) } } +/* TODO: Should go in cogl.c, but that implies duplication which is also + * not ideal. */ +void +cogl_set_source (CoglHandle material_handle) +{ + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + g_return_if_fail (cogl_is_material (material_handle)); + + if (ctx->source_material == material_handle) + return; + + if (ctx->source_material) + cogl_material_unref (ctx->source_material); + + cogl_material_ref (material_handle); + ctx->source_material = material_handle; +} +/* TODO: add cogl_set_front_source (), and cogl_set_back_source () */ + +void +cogl_flush_material_gl_state (void) +{ + CoglMaterial *material; + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + material = _cogl_material_pointer_from_handle (ctx->source_material); + + if (ctx->source_material == ctx->current_material + && !(material->flags & COGL_MATERIAL_FLAG_DIRTY)) + return; + + /* FIXME - we only need to set these if lighting is enabled... */ + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, material->ambient)); + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, material->diffuse)); + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, material->specular)); + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, material->emission)); + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS, &material->shininess)); + + /* NB: Currently the Cogl defines are compatible with the GL ones: */ + GE (glAlphaFunc (material->alpha_func, material->alpha_func_reference)); + + GE (glBlendFunc (material->blend_src_factor, material->blend_dst_factor)); + + ctx->current_material = ctx->source_material; +} + diff --git a/gl/cogl-context.c b/gl/cogl-context.c index 9283ad69d..f74df873a 100644 --- a/gl/cogl-context.c +++ b/gl/cogl-context.c @@ -62,6 +62,7 @@ cogl_create_context () _context->material_handles = NULL; _context->material_layer_handles = NULL; _context->source_material = NULL; + _context->current_material = NULL; _context->fbo_handles = NULL; _context->draw_buffer = COGL_WINDOW_BUFFER; diff --git a/gl/cogl-context.h b/gl/cogl-context.h index 3eb00e1b7..e54489d3c 100644 --- a/gl/cogl-context.h +++ b/gl/cogl-context.h @@ -70,6 +70,7 @@ typedef struct GArray *material_handles; GArray *material_layer_handles; CoglHandle source_material; + CoglHandle current_material; /* Framebuffer objects */ GArray *fbo_handles; diff --git a/gl/cogl-texture.c b/gl/cogl-texture.c index 54e6c5688..ab84c9543 100644 --- a/gl/cogl-texture.c +++ b/gl/cogl-texture.c @@ -2531,9 +2531,8 @@ cogl_material_rectangle (CoglFixed x1, GE( glVertexPointer (2, GL_FLOAT, 0, quad_coords)); /* Setup the remaining GL state according to this material... */ - cogl_material_flush_gl_material_state (material); - cogl_material_flush_gl_alpha_func (material); - cogl_material_flush_gl_blend_func (material); + cogl_flush_material_gl_state (); + /* FIXME: This api is a bit yukky, ideally it will be removed if we * re-work the cogl_enable mechanism */ enable_flags |= cogl_material_get_cogl_enable_flags (material); From 98bd85afaa8c79f9b20536b3f406bf55e5176840 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Tue, 23 Dec 2008 23:35:49 +0000 Subject: [PATCH 08/16] [cogl-material] Adds a cogl_material_set_color function The other colors of a material; such as the ambient and diffuse color are only relevent when we can enable lighting. This adds a basic unlit color property. Later cogl_set_source_color can be integrated to either modify the color of the current source material, or maintain a special singlton CoglMaterial that is modified by calls to cogl_set_source_color and implicitly made current. --- cogl-material.h | 13 +++++++++++++ common/cogl-material.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/cogl-material.h b/cogl-material.h index 2ad878551..59cb47d04 100644 --- a/cogl-material.h +++ b/cogl-material.h @@ -52,6 +52,19 @@ CoglHandle cogl_material_ref (CoglHandle handle); */ void cogl_material_unref (CoglHandle handle); +/** + * cogl_material_set_color: + * @material: A CoglMaterial object + * @color: The components of the color + * + * This is the basic color of the material, used when no lighting is enabled. + * + * The default value is (1.0, 1.0, 1.0, 1.0) + * + * Since 1.0 + */ +void cogl_material_set_color (CoglHandle material, const CoglColor *color); + /** * cogl_material_set_ambient: * @material: A CoglMaterial object diff --git a/common/cogl-material.c b/common/cogl-material.c index 2e9f5a353..b0b9fd955 100644 --- a/common/cogl-material.c +++ b/common/cogl-material.c @@ -11,6 +11,7 @@ #include "cogl-material-private.h" #include +#include static void _cogl_material_free (CoglMaterial *tex); static void _cogl_material_layer_free (CoglMaterialLayer *layer); @@ -25,6 +26,7 @@ cogl_material_new (void) { /* Create new - blank - material */ CoglMaterial *material = g_new0 (CoglMaterial, 1); + GLfloat *unlit = material->unlit; GLfloat *ambient = material->ambient; GLfloat *diffuse = material->diffuse; GLfloat *specular = material->specular; @@ -33,6 +35,9 @@ cogl_material_new (void) material->ref_count = 1; COGL_HANDLE_DEBUG_NEW (material, material); + /* Use the same defaults as the GL spec... */ + unlit[0] = 1.0; unlit[1] = 1.0; unlit[2] = 1.0; unlit[3] = 1.0; + /* Use the same defaults as the GL spec... */ ambient[0] = 0.2; ambient[1] = 0.2; ambient[2] = 0.2; ambient[3] = 1.0; diffuse[0] = 0.8; diffuse[1] = 0.8; diffuse[2] = 0.8; diffuse[3] = 1.0; @@ -63,6 +68,29 @@ _cogl_material_free (CoglMaterial *material) g_free (material); } +void +cogl_material_set_color (CoglHandle handle, + const CoglColor *unlit_color) +{ + CoglMaterial *material; + GLfloat unlit[4]; + + g_return_if_fail (cogl_is_material (handle)); + + material = _cogl_material_pointer_from_handle (handle); + + unlit[0] = cogl_color_get_red_float (unlit_color); + unlit[1] = cogl_color_get_green_float (unlit_color); + unlit[2] = cogl_color_get_blue_float (unlit_color); + unlit[3] = cogl_color_get_alpha_float (unlit_color); + if (memcmp (unlit, material->unlit, sizeof (unlit)) == 0) + return; + + memcpy (material->unlit, unlit, sizeof (unlit)); + + material->flags |= COGL_MATERIAL_FLAG_DIRTY; +} + void cogl_material_set_ambient (CoglHandle handle, const CoglColor *ambient_color) @@ -667,6 +695,8 @@ cogl_flush_material_gl_state (void) && !(material->flags & COGL_MATERIAL_FLAG_DIRTY)) return; + GE (glColor4fv (material->unlit)); + /* FIXME - we only need to set these if lighting is enabled... */ GE (glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, material->ambient)); GE (glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, material->diffuse)); From 0408a5d2c5d01035155dcd0cc0529e074361eb8a Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Tue, 23 Dec 2008 23:50:02 +0000 Subject: [PATCH 09/16] [cogl-material] improvements for cogl_material_rectangle The API has been changed to take an explicit length for the number of texture coordinates passed, and it's now documented that if there are more layers to the current material than the number of texture coords passed, then default coordinates will be generated for the other layers. cogl_material_rectangle should now handle the case where a single sliced texture is supplied as a material layer by falling back to cogl_texture_rectangle. We are nearly at the point that cogl_texture_rectangle could be deprecated. A few issues remain though, such as not considering waste in cogl_material_rectangle. --- cogl-texture.h | 73 ++++++++------------------ common/cogl-material-private.h | 14 +++-- gl/cogl-texture.c | 95 +++++++++++++++++++++++++++------- 3 files changed, 105 insertions(+), 77 deletions(-) diff --git a/cogl-texture.h b/cogl-texture.h index 475de2ac5..331407618 100644 --- a/cogl-texture.h +++ b/cogl-texture.h @@ -386,66 +386,35 @@ void cogl_texture_polygon (CoglHandle handle, gboolean use_color); /** - * cogl_muti_texture_new: - * - * Creates a multi layered texture object. When first created it has - * zero layers. You must use cogl_multi_texture_layer_set_texture to - * define new layers. - */ -CoglHandle cogl_multi_texture_new (void); - -/** - * cogl_multi_texture_layer_set_texture: - * @multi_texture_handle: a @CoglHandle - * @layer: The index of the layer you want a handle for. - * - * A layer is implicitly created once you set a texture for a certain - * layer_index. The texture layers are blended together starting with - * the lowest index so the order is significant. It doesn't matter what - * order you create the layers in and you may use sparsely generated index - * values, it is only the relative index order that matters. - */ -void cogl_multi_texture_layer_set_texture (CoglHandle multi_texture_handle, - guint layer_index, - CoglHandle texture_handle); - -/** - * cogl_multi_texture_layer_remove: - * @multi_texture_handle: a @CoglHandle - * @index: The index of the layer you want to remove. - * - * Removes a single texture layer. - */ -void cogl_multi_texture_layer_remove (CoglHandle multi_texture_handle, - guint layer_index); - -/** - * cogl_multi_texture_rectangle: - * @handle: a @CoglHandle + * cogl_material_rectangle: * @x1: x coordinate upper left on screen. * @y1: y coordinate upper left on screen. * @x2: x coordinate lower right on screen. * @y2: y coordinate lower right on screen. - * @texcoords: A multidimensional array containing sets of 4 texture - * coordinates - one set for each texture layer that has been created. + * @tex_coords_len: The length of the tex_coords array. (e.g. for one layer + * and one group of texture coordinates, this would be 4) + * @tex_coords: An array containing groups of 4 CoglFixed values: + * [tx1, ty1, tx2, ty2] that are interpreted as two texture coordinates; one + * for the upper left texel, and one for the lower right texel. Each value + * should be between 0.0 and 1.0, where the coordinate (0.0, 0.0) represents + * the top left of the texture, and (1.0, 1.0) the bottom right. * - * Draw a rectangle combining multiple texture layers together - * where each layer can use different texture data and different texture + * This function draws a rectangle using the current source material to + * texture or fill with. Since a material may contain multiple texture + * layers the interface lets you supply corresponding sets of texture * coordinates. * - * The texture coordinates are supplied as a contiguous array of - * CoglFixed items containing groups of [tx1, ty1, tx2, ty2] values - * that are interpreted in the same way as the corresponding arguments - * to cogl_texture_rectangle. The first group of coordinates are for the - * first layer (with the smallest layer_index) you _must_ supply as many - * groups of texture coordinates as you have layers. + * The first pair of coordinates are for the first layer (with the smallest + * layer index) and if you supply less texture coordinates than there are + * layers in the current source material then default texture coordinates + * [0.0, 0.0, 1.0, 1.0] are generated. */ -void cogl_multi_texture_rectangle (CoglHandle handle, - CoglFixed x1, - CoglFixed y1, - CoglFixed x2, - CoglFixed y2, - CoglFixed *tex_coords); +void cogl_material_rectangle (CoglFixed x1, + CoglFixed y1, + CoglFixed x2, + CoglFixed y2, + gint tex_coords_len, + CoglFixed *tex_coords); G_END_DECLS diff --git a/common/cogl-material-private.h b/common/cogl-material-private.h index d64d8485b..935e0ae79 100644 --- a/common/cogl-material-private.h +++ b/common/cogl-material-private.h @@ -22,8 +22,8 @@ struct _CoglMaterialLayer gulong flags; CoglHandle texture; /*!< The texture for this layer, or COGL_INVALID_HANDLE for an empty layer */ - - /* Determines how the color of individual texture fragments + + /* Determines how the color of individual texture fragments * are calculated. */ CoglMaterialLayerCombineFunc texture_combine_rgb_func; CoglMaterialLayerCombineSrc texture_combine_rgb_src[3]; @@ -32,7 +32,7 @@ struct _CoglMaterialLayer CoglMaterialLayerCombineFunc texture_combine_alpha_func; CoglMaterialLayerCombineSrc texture_combine_alpha_src[3]; CoglMaterialLayerCombineOp texture_combine_alpha_op[3]; - + /* TODO: Support purely GLSL based material layers */ CoglMatrix matrix; @@ -41,7 +41,8 @@ struct _CoglMaterialLayer typedef enum _CoglMaterialFlags { COGL_MATERIAL_FLAG_ENABLE_BLEND = 1L<<0, - COGL_MATERIAL_FLAG_SHOWN_SAMPLER_WARNING = 1L<<1 + COGL_MATERIAL_FLAG_SHOWN_SAMPLER_WARNING = 1L<<1, + COGL_MATERIAL_FLAG_DIRTY = 1L<<2 } CoglMaterialFlags; struct _CoglMaterial @@ -50,13 +51,16 @@ struct _CoglMaterial gulong flags; + /* If no lighting is enabled; this is the basic material color */ + GLfloat unlit[4]; + /* Standard OpenGL lighting model attributes */ GLfloat ambient[4]; GLfloat diffuse[4]; GLfloat specular[4]; GLfloat emission[4]; GLfloat shininess; - + /* Determines what fragments are discarded based on their alpha */ CoglMaterialAlphaFunc alpha_func; GLfloat alpha_func_reference; diff --git a/gl/cogl-texture.c b/gl/cogl-texture.c index ab84c9543..357fc2885 100644 --- a/gl/cogl-texture.c +++ b/gl/cogl-texture.c @@ -2411,6 +2411,7 @@ cogl_material_rectangle (CoglFixed x1, CoglFixed y1, CoglFixed x2, CoglFixed y2, + gint user_tex_coords_len, CoglFixed *user_tex_coords) { CoglHandle material; @@ -2424,7 +2425,6 @@ cogl_material_rectangle (CoglFixed x1, GLfloat *tex_coords_buff; GLfloat quad_coords[8]; gulong enable_flags = 0; - GLfloat values[4]; /* FIXME - currently cogl deals with enabling texturing via enable flags, * but that can't scale to n texture units. Currently we have to be carefull @@ -2443,7 +2443,7 @@ cogl_material_rectangle (CoglFixed x1, { CoglHandle layer = tmp->data; CoglHandle texture = cogl_material_layer_get_texture (layer); - + if (cogl_material_layer_get_type (layer) != COGL_MATERIAL_LAYER_TYPE_TEXTURE) continue; @@ -2466,7 +2466,18 @@ cogl_material_rectangle (CoglFixed x1, if (n_valid_layers >= CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS) break; } - + + /* We at least support slicing as much as cogl_texture_rectangle... */ + if (n_valid_layers == 1 && handle_slicing) + { + CoglHandle texture = cogl_material_layer_get_texture (valid_layers[0]); + cogl_texture_rectangle (texture, + x1, y1, x2, y2, + user_tex_coords[0], user_tex_coords[1], + user_tex_coords[2], user_tex_coords[3]); + return; + } + /* NB: It could be that no valid texture layers were found, but * we will still submit a non-textured rectangle in that case. */ if (n_valid_layers) @@ -2476,34 +2487,61 @@ cogl_material_rectangle (CoglFixed x1, { CoglHandle layer = valid_layers[i]; CoglHandle texture = cogl_material_layer_get_texture (layer); - CoglFixed *in_tex_coords = &user_tex_coords[i * 4]; + CoglFixed *in_tex_coords; GLfloat *out_tex_coords = &tex_coords_buff[i * 8]; GLuint gl_tex_handle; #define CFX_F COGL_FIXED_TO_FLOAT /* IN LAYOUT: [ tx1:0, ty1:1, tx2:2, ty2:3 ] */ - out_tex_coords[0] = CFX_F (in_tex_coords[0]); /* tx1 */ - out_tex_coords[1] = CFX_F (in_tex_coords[1]); /* ty1 */ - out_tex_coords[2] = CFX_F (in_tex_coords[2]); /* tx2 */ - out_tex_coords[3] = CFX_F (in_tex_coords[1]); /* ty1 */ - out_tex_coords[4] = CFX_F (in_tex_coords[0]); /* tx1 */ - out_tex_coords[5] = CFX_F (in_tex_coords[3]); /* ty2 */ - out_tex_coords[6] = CFX_F (in_tex_coords[2]); /* tx2 */ - out_tex_coords[7] = CFX_F (in_tex_coords[3]); /* ty2 */ + if (i < (user_tex_coords_len / 4)) + { + in_tex_coords = &user_tex_coords[i * 4]; + /* FIXME: don't include waste in the texture coordinates */ + out_tex_coords[0] = CFX_F (in_tex_coords[0]); /* tx1 */ + out_tex_coords[1] = CFX_F (in_tex_coords[1]); /* ty1 */ + out_tex_coords[2] = CFX_F (in_tex_coords[2]); /* tx2 */ + out_tex_coords[3] = CFX_F (in_tex_coords[1]); /* ty1 */ + out_tex_coords[4] = CFX_F (in_tex_coords[0]); /* tx1 */ + out_tex_coords[5] = CFX_F (in_tex_coords[3]); /* ty2 */ + out_tex_coords[6] = CFX_F (in_tex_coords[2]); /* tx2 */ + out_tex_coords[7] = CFX_F (in_tex_coords[3]); /* ty2 */ + } + else + { + out_tex_coords[0] = 0.0; /* tx1 */ + out_tex_coords[1] = 0.0; /* ty1 */ + out_tex_coords[2] = 1.0; /* tx2 */ + out_tex_coords[3] = 0.0; /* ty1 */ + out_tex_coords[4] = 0.0; /* tx1 */ + out_tex_coords[5] = 1.0; /* ty2 */ + out_tex_coords[6] = 1.0; /* tx2 */ + out_tex_coords[7] = 1.0; /* ty2 */ + } #undef CFX_F /* TODO - support sliced textures */ cogl_texture_get_gl_texture (texture, &gl_tex_handle, NULL); - //gl_tex_handle = g_array_index (layer->tex->slice_gl_handles, GLuint, 0); GE (glActiveTexture (GL_TEXTURE0 + i)); cogl_material_layer_flush_gl_sampler_state (layer); - GE (glBindTexture (GL_TEXTURE_2D, gl_tex_handle)); - /* GE (glEnable (GL_TEXTURE_2D)); */ + { + /* FIXME - we should avoid redundant calls to glBindTexture. + * Profiling test-actors, I've seen ~ 10% of the time spent in + * _mesa_UpdateTexEnvProgram, which the following simple test can + * show is as a result of these redundant glBindTexture calls. + */ +#if 0 + static int debug = 0; + if (!debug) + GE (glBindTexture (GL_TEXTURE_2D, gl_tex_handle)); + debug = 1; +#else + GE (glBindTexture (GL_TEXTURE_2D, gl_tex_handle)); +#endif + } GE (glClientActiveTexture (GL_TEXTURE0 + i)); GE (glTexCoordPointer (2, GL_FLOAT, 0, out_tex_coords)); - /* GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY)); */ /* FIXME - cogl only knows about one texture unit a.t.m * (Also see cleanup note below) */ @@ -2538,12 +2576,28 @@ cogl_material_rectangle (CoglFixed x1, enable_flags |= cogl_material_get_cogl_enable_flags (material); /* FIXME - cogl only knows about one texture unit so assumes that unit 0 - * is always active...*/ - GE (glActiveTexture (GL_TEXTURE0)); - GE (glClientActiveTexture (GL_TEXTURE0)); + * is always active... */ + if (n_valid_layers > 1) + { + GE (glActiveTexture (GL_TEXTURE0)); + GE (glClientActiveTexture (GL_TEXTURE0)); + } cogl_enable (enable_flags); glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); + /* FIXME - cogl doesn't currently have a way of caching the + * enable states for more than one texture unit so for now, + * we just disable anything relating to additional units once + * we are done with them. */ + for (i = 1; i < n_valid_layers; i++) + { + GE (glActiveTexture (GL_TEXTURE0 + i)); + GE (glDisable (GL_TEXTURE_2D)); + } + + /* XXX: a bit over precautious. For one we don't support lighting yet + * so there's no real need to reset the material properties. */ +#if 0 /* FIXME - cogl doesn't currently have a way of caching the * enable states for more than one texture unit so for now, * we just disable anything relating to additional units once @@ -2556,7 +2610,7 @@ cogl_material_rectangle (CoglFixed x1, GE (glDisable (GL_TEXTURE_2D)); GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY)); } - + /* FIXME - CoglMaterials aren't yet used pervasively throughout * the cogl API, so we currently need to cleanup material state * that will confuse other parts of the API. @@ -2572,5 +2626,6 @@ cogl_material_rectangle (CoglFixed x1, GE (glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, values)); values[0] = 0; GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS, values)); +#endif } From ba2257973eeb7114368e819a2bf4fdff606ba610 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Tue, 6 Jan 2009 15:53:35 +0000 Subject: [PATCH 10/16] Add cogl-material.h and cogl-matrix.h to libclutterinclude_HEADERS Otherwise they won't get installed --- gl/Makefile.am | 4 +++- gles/Makefile.am | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/gl/Makefile.am b/gl/Makefile.am index 2d90ba9c0..819675df7 100644 --- a/gl/Makefile.am +++ b/gl/Makefile.am @@ -10,7 +10,9 @@ libclutterinclude_HEADERS = \ $(top_builddir)/clutter/cogl/cogl-shader.h \ $(top_builddir)/clutter/cogl/cogl-texture.h \ $(top_builddir)/clutter/cogl/cogl-types.h \ - $(top_builddir)/clutter/cogl/cogl-mesh.h + $(top_builddir)/clutter/cogl/cogl-mesh.h \ + $(top_builddir)/clutter/cogl/cogl-material.h \ + $(top_builddir)/clutter/cogl/cogl-matrix.h INCLUDES = \ -I$(top_srcdir) \ diff --git a/gles/Makefile.am b/gles/Makefile.am index 19cf0a0d7..14f6a925b 100644 --- a/gles/Makefile.am +++ b/gles/Makefile.am @@ -10,7 +10,9 @@ libclutterinclude_HEADERS = \ $(top_builddir)/clutter/cogl/cogl-shader.h \ $(top_builddir)/clutter/cogl/cogl-texture.h \ $(top_builddir)/clutter/cogl/cogl-types.h \ - $(top_builddir)/clutter/cogl/cogl-mesh.h + $(top_builddir)/clutter/cogl/cogl-mesh.h \ + $(top_builddir)/clutter/cogl/cogl-material.h \ + $(top_builddir)/clutter/cogl/cogl-matrix.h INCLUDES = \ -I$(top_srcdir) \ From cd71b91440f53618e5ad2db7618a0c36466ac4ea Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Tue, 6 Jan 2009 16:09:55 +0000 Subject: [PATCH 11/16] [cogl-material] Make the user_tex_coords parameter of _rectangle const The array is only used for input so it should be const. --- cogl-texture.h | 12 ++++++------ gl/cogl-texture.c | 14 +++++++------- gles/cogl-texture.c | 12 ++++++------ 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/cogl-texture.h b/cogl-texture.h index 331407618..2780b5db2 100644 --- a/cogl-texture.h +++ b/cogl-texture.h @@ -409,12 +409,12 @@ void cogl_texture_polygon (CoglHandle handle, * layers in the current source material then default texture coordinates * [0.0, 0.0, 1.0, 1.0] are generated. */ -void cogl_material_rectangle (CoglFixed x1, - CoglFixed y1, - CoglFixed x2, - CoglFixed y2, - gint tex_coords_len, - CoglFixed *tex_coords); +void cogl_material_rectangle (CoglFixed x1, + CoglFixed y1, + CoglFixed x2, + CoglFixed y2, + gint tex_coords_len, + const CoglFixed *tex_coords); G_END_DECLS diff --git a/gl/cogl-texture.c b/gl/cogl-texture.c index 357fc2885..f80a54e52 100644 --- a/gl/cogl-texture.c +++ b/gl/cogl-texture.c @@ -2407,12 +2407,12 @@ cogl_texture_polygon (CoglHandle handle, } void -cogl_material_rectangle (CoglFixed x1, - CoglFixed y1, - CoglFixed x2, - CoglFixed y2, - gint user_tex_coords_len, - CoglFixed *user_tex_coords) +cogl_material_rectangle (CoglFixed x1, + CoglFixed y1, + CoglFixed x2, + CoglFixed y2, + gint user_tex_coords_len, + const CoglFixed *user_tex_coords) { CoglHandle material; const GList *layers; @@ -2487,7 +2487,7 @@ cogl_material_rectangle (CoglFixed x1, { CoglHandle layer = valid_layers[i]; CoglHandle texture = cogl_material_layer_get_texture (layer); - CoglFixed *in_tex_coords; + const CoglFixed *in_tex_coords; GLfloat *out_tex_coords = &tex_coords_buff[i * 8]; GLuint gl_tex_handle; diff --git a/gles/cogl-texture.c b/gles/cogl-texture.c index a745e3b31..1fbd6c9fb 100644 --- a/gles/cogl-texture.c +++ b/gles/cogl-texture.c @@ -2498,11 +2498,11 @@ cogl_texture_polygon (CoglHandle handle, } void -cogl_material_rectangle (CoglFixed x1, - CoglFixed y1, - CoglFixed x2, - CoglFixed y2, - CoglFixed *user_tex_coords) +cogl_material_rectangle (CoglFixed x1, + CoglFixed y1, + CoglFixed x2, + CoglFixed y2, + const CoglFixed *user_tex_coords) { CoglHandle material; const GList *layers; @@ -2568,7 +2568,7 @@ cogl_material_rectangle (CoglFixed x1, CoglHandle layer = valid_layers[i]; CoglHandle texture_handle = cogl_material_layer_get_texture (layer); CoglTexture *texture = _cogl_texture_pointer_from_handle (texture_handle); - CoglFixed *in_tex_coords = &user_tex_coords[i * 4]; + const CoglFixed *in_tex_coords = &user_tex_coords[i * 4]; GLfloat *out_tex_coords = &tex_coords_buff[i * 8]; GLuint gl_tex_handle; GLenum gl_target; From b6470ab900f42af1c778a7d77cc2de988825f756 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Tue, 6 Jan 2009 18:24:57 +0000 Subject: [PATCH 12/16] [cogl-material] Restore the GL_TEXTURE_ENV_MODE after material_rectangle The rest of Cogl expects the texture mode to be GL_MODULATE so it needs to be restored after calling cogl_material_rectangle. Otherwise cogl_texture_rectangle will fail to blend with the Cogl color properly and all of the labels will be black. --- gl/cogl-texture.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gl/cogl-texture.c b/gl/cogl-texture.c index f80a54e52..2d6d54778 100644 --- a/gl/cogl-texture.c +++ b/gl/cogl-texture.c @@ -2595,6 +2595,10 @@ cogl_material_rectangle (CoglFixed x1, GE (glDisable (GL_TEXTURE_2D)); } + /* The rest of Cogl expects the texture mode to be GL_MODULATE so we + need to restore that */ + GE( glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE) ); + /* XXX: a bit over precautious. For one we don't support lighting yet * so there's no real need to reset the material properties. */ #if 0 From 2503f7b32190312a7ded7d7ae227ee5e01e298c3 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Fri, 23 Jan 2009 16:15:40 +0000 Subject: [PATCH 13/16] Fully integrates CoglMaterial throughout the rest of Cogl This glues CoglMaterial in as the fundamental way that Cogl describes how to fill in geometry. It adds cogl_set_source (), which is used to set the material which will be used by all subsequent drawing functions It adds cogl_set_source_texture as a convenience for setting up a default material with a single texture layer, and cogl_set_source_color is now also a convenience for setting up a material with a solid fill. "drawing functions" include, cogl_rectangle, cogl_texture_rectangle, cogl_texture_multiple_rectangles, cogl_texture_polygon (though the cogl_texture_* funcs have been renamed; see below for details), cogl_path_fill/stroke and cogl_vertex_buffer_draw*. cogl_texture_rectangle, cogl_texture_multiple_rectangles and cogl_texture_polygon no longer take a texture handle; instead the current source material is referenced. The functions have also been renamed to: cogl_rectangle_with_texture_coords, cogl_rectangles_with_texture_coords and cogl_polygon respectivly. Most code that previously did: cogl_texture_rectangle (tex_handle, x, y,...); needs to be changed to now do: cogl_set_source_texture (tex_handle); cogl_rectangle_with_texture_coords (x, y,....); In the less likely case where you were blending your source texture with a color like: cogl_set_source_color4ub (r,g,b,a); /* where r,g,b,a isn't just white */ cogl_texture_rectangle (tex_handle, x, y,...); you will need your own material to do that: mat = cogl_material_new (); cogl_material_set_color4ub (r,g,b,a); cogl_material_set_layer (mat, 0, tex_handle)); cogl_set_source_material (mat); Code that uses the texture coordinates, 0, 0, 1, 1 don't need to use cog_rectangle_with_texure_coords since these are the coordinates that cogl_rectangle will use. For cogl_texture_polygon; as well as dropping the texture handle, the n_vertices and vertices arguments were transposed for consistency. So code previously written as: cogl_texture_polygon (tex_handle, 3, verts, TRUE); need to be written as: cogl_set_source_texture (tex_handle); cogl_polygon (verts, 3, TRUE); All of the unit tests have been updated to now use the material API and test-cogl-material has been renamed to test-cogl-multitexture since any textured quad is now technically a test of CoglMaterial but this test specifically creates a material with multiple texture layers. Note: The GLES backend has not been updated yet; that will be done in a following commit. --- cogl-material.h | 175 +++- cogl-path.h | 3 +- cogl-texture.h | 185 +++-- cogl.h.in | 2 +- common/cogl-material-private.h | 31 +- common/cogl-material.c | 641 +++++++++++--- common/cogl-primitives.c | 13 +- common/cogl-vertex-buffer.c | 80 +- gl/cogl-context.c | 91 +- gl/cogl-context.h | 44 +- gl/cogl-internal.h | 11 +- gl/cogl-primitives.c | 50 +- gl/cogl-texture-private.h | 39 +- gl/cogl-texture.c | 1424 ++++++++++++++++++++------------ gl/cogl.c | 128 ++- 15 files changed, 1957 insertions(+), 960 deletions(-) diff --git a/cogl-material.h b/cogl-material.h index 59cb47d04..915e447e5 100644 --- a/cogl-material.h +++ b/cogl-material.h @@ -52,6 +52,8 @@ CoglHandle cogl_material_ref (CoglHandle handle); */ void cogl_material_unref (CoglHandle handle); + + /** * cogl_material_set_color: * @material: A CoglMaterial object @@ -65,6 +67,37 @@ void cogl_material_unref (CoglHandle handle); */ void cogl_material_set_color (CoglHandle material, const CoglColor *color); +/** + * cogl_material_set_color: + * @material: A CoglMaterial object + * @red: The red component + * @green: The green component + * @blue: The blue component + * @alpha: The alpha component + * + * This is the basic color of the material, used when no lighting is enabled. + * + * The default value is (1.0, 1.0, 1.0, 1.0) + * + * Since 1.0 + */ +void cogl_material_set_color4ub (CoglHandle handle, + guint8 red, + guint8 green, + guint8 blue, + guint8 alpha); + +/** + * cogl_material_get_color: + * @material: A CoglMaterial object + * @color: The location to store the color + * + * This retrieves the current material color. + * + * Since 1.0 + */ +void cogl_material_get_color (CoglHandle handle, CoglColor *color); + /** * cogl_material_set_ambient: * @material: A CoglMaterial object @@ -83,6 +116,17 @@ void cogl_material_set_color (CoglHandle material, const CoglColor *color); void cogl_material_set_ambient (CoglHandle material, const CoglColor *ambient); +/** + * cogl_material_get_ambient: + * @material: A CoglMaterial object + * @ambient: The location to store the ambient color + * + * This retrieves the materials current ambient color. + * + * Since 1.0 + */ +void cogl_material_get_ambient (CoglHandle handle, CoglColor *ambient); + /** * cogl_material_set_diffuse: * @material: A CoglMaterial object @@ -100,6 +144,17 @@ void cogl_material_set_ambient (CoglHandle material, void cogl_material_set_diffuse (CoglHandle material, const CoglColor *diffuse); +/** + * cogl_material_get_diffuse: + * @material: A CoglMaterial object + * @diffuse: The location to store the diffuse color + * + * This retrieves the materials current diffuse color. + * + * Since 1.0 + */ +void cogl_material_get_diffuse (CoglHandle handle, CoglColor *diffuse); + /** * cogl_material_set_ambient_and_diffuse: * @material: A CoglMaterial object @@ -133,6 +188,17 @@ void cogl_material_set_ambient_and_diffuse (CoglHandle material, void cogl_material_set_specular (CoglHandle material, const CoglColor *specular); +/** + * cogl_material_get_specular: + * @material: A CoglMaterial object + * @specular: The location to store the specular color + * + * This retrieves the materials current specular color. + * + * Since 1.0 + */ +void cogl_material_get_specular (CoglHandle handle, CoglColor *specular); + /** * cogl_material_set_shininess: * @material: A CoglMaterial object @@ -148,6 +214,17 @@ void cogl_material_set_specular (CoglHandle material, */ void cogl_material_set_shininess (CoglHandle material, float shininess); +/** + * cogl_material_get_shininess: + * @material: A CoglMaterial object + * + * This retrieves the materials current emission color. + * + * Return value: The materials current shininess value + * + * Since 1.0 + */ +float cogl_material_get_shininess (CoglHandle handle); /** * cogl_material_set_emission: @@ -165,6 +242,17 @@ void cogl_material_set_shininess (CoglHandle material, void cogl_material_set_emission (CoglHandle material, const CoglColor *emission); +/** + * cogl_material_get_emission: + * @material: A CoglMaterial object + * @emission: The location to store the emission color + * + * This retrieves the materials current emission color. + * + * Since 1.0 + */ +void cogl_material_get_emission (CoglHandle handle, CoglColor *emission); + /** * CoglMaterialAlphaFunc: * @COGL_MATERIAL_ALPHA_FUNC_NEVER: Never let the fragment through. @@ -638,7 +726,7 @@ CoglMaterialLayerType cogl_material_layer_get_type (CoglHandle layer_handle); /** * cogl_material_layer_get_texture: - * @material: A CoglMaterial object + * @layer_handle: A CoglMaterial layer object * * This lets you extract a CoglTexture handle for a specific layer. Normally * you shouldn't need to use this function directly since Cogl will do this @@ -653,18 +741,66 @@ CoglMaterialLayerType cogl_material_layer_get_type (CoglHandle layer_handle); CoglHandle cogl_material_layer_get_texture (CoglHandle layer_handle); /** - * cogl_material_layer_flush_gl_sampler_state: - * @material: A CoglMaterial object - * - * This commits the sampler state for a single material layer to the OpenGL - * driver. Normally you shouldn't need to use this function directly since - * Cogl will do this internally, but if you are developing custom primitives - * directly with OpenGL you may want to use this. - * - * Note: It assumes you have already activated the appropriate sampler - * by calling glActiveTexture (); + * CoglMaterialLayerFlags: + * @COGL_MATERIAL_LAYER_FLAG_USER_MATRIX: Means the user has supplied a + * custom texture matrix. */ -void cogl_material_layer_flush_gl_sampler_state (CoglHandle layer_handle); +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 CoglMaterial layer object + * + * 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. + * + * Normally you shouldn't need to use this function directly, but if you + * are developing a custom primitive using raw OpenGL that works with + * CoglMaterials, then you may want to use this function. + * + * Since 1.0 + */ +void cogl_material_flush_gl_state (CoglHandle material, + ...) G_GNUC_NULL_TERMINATED; /** * cogl_set_source: @@ -684,19 +820,16 @@ void cogl_material_layer_flush_gl_sampler_state (CoglHandle layer_handle); void cogl_set_source (CoglHandle material); /** - * cogl_flush_material_gl_state: + * cogl_set_source_texture: + * @texture_handle: The Cogl texture you want as your source * - * This function commits all the state of the source CoglMaterial - not - * including the per-layer state - to the OpenGL[ES] driver. - * - * Normally you shouldn't need to use this function directly, but if you - * are developing a custom primitive using raw OpenGL that works with - * CoglMaterials, then you may want to use this function. + * This is a convenience function for creating a material with the first + * layer set to #texture_handle and setting that material as the source with + * cogl_set_source. * * Since 1.0 */ -/* XXX: This should be moved with cogl_set_source to cogl.h */ -void cogl_flush_material_gl_state (void); +void cogl_set_source_texture (CoglHandle texture_handle); G_END_DECLS diff --git a/cogl-path.h b/cogl-path.h index aa378647a..d1433fe4d 100644 --- a/cogl-path.h +++ b/cogl-path.h @@ -57,8 +57,7 @@ G_BEGIN_DECLS * @width: Width of the rectangle * @height: Height of the rectangle * - * Fills a rectangle at the given coordinates with the current - * drawing color in a highly optimizied fashion. + * Fills a rectangle at the given coordinates with the current source material **/ void cogl_rectangle (float x, float y, diff --git a/cogl-texture.h b/cogl-texture.h index d21265304..b35b22f36 100644 --- a/cogl-texture.h +++ b/cogl-texture.h @@ -359,90 +359,6 @@ CoglHandle cogl_texture_ref (CoglHandle handle); */ void cogl_texture_unref (CoglHandle handle); -/** - * cogl_texture_rectangle: - * @handle: a @CoglHandle. - * @x1: x coordinate upper left on screen. - * @y1: y coordinate upper left on screen. - * @x2: x coordinate lower right on screen. - * @y2: y coordinate lower right on screen. - * @tx1: x part of texture coordinate to use for upper left pixel - * @ty1: y part of texture coordinate to use for upper left pixel - * @tx2: x part of texture coordinate to use for lower right pixel - * @ty2: y part of texture coordinate to use for left pixel - * - * Draw a rectangle from a texture to the display, to draw the entire - * texture pass in @tx1=0.0 @ty1=0.0 @tx2=1.0 @ty2=1.0. - */ -void cogl_texture_rectangle (CoglHandle handle, - float x1, - float y1, - float x2, - float y2, - float tx1, - float ty1, - float tx2, - float ty2); - -/** - * cogl_texture_polygon: - * @handle: A CoglHandle for a texture - * @n_vertices: The length of the vertices array - * @vertices: An array of #CoglTextureVertex structs - * @use_color: %TRUE if the color member of #CoglTextureVertex should be used - * - * Draws a polygon from a texture with the given model and texture - * coordinates. This can be used to draw arbitrary shapes textured - * with a COGL texture. If @use_color is %TRUE then the current COGL - * color will be changed for each vertex using the value specified in - * the color member of #CoglTextureVertex. This can be used for - * example to make the texture fade out by setting the alpha value of - * the color. - * - * All of the texture coordinates must be in the range [0,1] and - * repeating the texture is not supported. - * - * Because of the way this function is implemented it will currently - * only work if either the texture is not sliced or the backend is not - * OpenGL ES and the minifying and magnifying functions are both set - * to CGL_NEAREST. - */ -void cogl_texture_polygon (CoglHandle handle, - guint n_vertices, - CoglTextureVertex *vertices, - gboolean use_color); - -/** - * cogl_material_rectangle: - * @x1: x coordinate upper left on screen. - * @y1: y coordinate upper left on screen. - * @x2: x coordinate lower right on screen. - * @y2: y coordinate lower right on screen. - * @tex_coords_len: The length of the tex_coords array. (e.g. for one layer - * and one group of texture coordinates, this would be 4) - * @tex_coords: An array containing groups of 4 CoglFixed values: - * [tx1, ty1, tx2, ty2] that are interpreted as two texture coordinates; one - * for the upper left texel, and one for the lower right texel. Each value - * should be between 0.0 and 1.0, where the coordinate (0.0, 0.0) represents - * the top left of the texture, and (1.0, 1.0) the bottom right. - * - * This function draws a rectangle using the current source material to - * texture or fill with. Since a material may contain multiple texture - * layers the interface lets you supply corresponding sets of texture - * coordinates. - * - * The first pair of coordinates are for the first layer (with the smallest - * layer index) and if you supply less texture coordinates than there are - * layers in the current source material then default texture coordinates - * [0.0, 0.0, 1.0, 1.0] are generated. - */ -void cogl_material_rectangle (CoglFixed x1, - CoglFixed y1, - CoglFixed x2, - CoglFixed y2, - gint tex_coords_len, - const CoglFixed *tex_coords); - /** * cogl_bitmap_new_from_file: * @filename: the file to load. @@ -483,27 +399,110 @@ gboolean cogl_bitmap_get_size_from_file (const gchar *filename, void cogl_bitmap_free (CoglBitmap *bmp); /** - * cogl_texture_multiple_rectangles: - * @handle: a @CoglHandle. + * cogl_rectangle_with_texture_coords: + * @x1: x coordinate upper left on screen. + * @y1: y coordinate upper left on screen. + * @x2: x coordinate lower right on screen. + * @y2: y coordinate lower right on screen. + * @tx1: x part of texture coordinate to use for upper left pixel + * @ty1: y part of texture coordinate to use for upper left pixel + * @tx2: x part of texture coordinate to use for lower right pixel + * @ty2: y part of texture coordinate to use for left pixel + * + * Draw a rectangle using the current material and supply texture coordinates + * to be used for the first texture layer of the material. To draw the entire + * texture pass in @tx1=0.0 @ty1=0.0 @tx2=1.0 @ty2=1.0. + * + * Since 1.0 + */ +void cogl_rectangle_with_texture_coords (float x1, + float y1, + float x2, + float y2, + float tx1, + float ty1, + float tx2, + float ty2); + +/** + * cogl_rectangle_with_multitexture_coords: + * @x1: x coordinate upper left on screen. + * @y1: y coordinate upper left on screen. + * @x2: x coordinate lower right on screen. + * @y2: y coordinate lower right on screen. + * @tex_coords: An array containing groups of 4 float values: + * [tx1, ty1, tx2, ty2] that are interpreted as two texture coordinates; one + * for the upper left texel, and one for the lower right texel. Each value + * should be between 0.0 and 1.0, where the coordinate (0.0, 0.0) represents + * the top left of the texture, and (1.0, 1.0) the bottom right. + * @tex_coords_len: The length of the tex_coords array. (e.g. for one layer + * and one group of texture coordinates, this would be 4) + * + * This function draws a rectangle using the current source material to + * texture or fill with. As a material may contain multiple texture layers + * this interface lets you supply texture coordinates for each layer of the + * material. + * + * The first pair of coordinates are for the first layer (with the smallest + * layer index) and if you supply less texture coordinates than there are + * layers in the current source material then default texture coordinates + * (0.0, 0.0, 1.0, 1.0) are generated. + * + * Since 1.0 + */ +void cogl_rectangle_with_multitexture_coords (float x1, + float y1, + float x2, + float y2, + const float *tex_coords, + gint tex_coords_len); + +/** + * cogl_rectangles_with_texture_coords: * @verts: an array of vertices * @n_rects: number of rectangles to draw * * Draws a series of rectangles in the same way that - * cogl_texture_rectangle() does. In some situations it can give a + * cogl_rectangle_with_texture_coords() does. In some situations it can give a * significant performance boost to use this function rather than - * calling cogl_texture_rectangle() separately for each rectangle. + * calling cogl_rectangle_with_texture_coords() separately for each rectangle. * * @verts should point to an array of #floats with * @n_rects * 8 elements. Each group of 8 values corresponds to the * parameters x1, y1, x2, y2, tx1, ty1, tx2 and ty2 and have the same - * meaning as in cogl_texture_rectangle(). + * meaning as in cogl_rectangle_with_texture_coords(). * * Since: 0.8.6 */ -void cogl_texture_multiple_rectangles - (CoglHandle handle, - const float *verts, - guint n_rects); +void cogl_rectangles_with_texture_coords (const float *verts, + guint n_rects); + +/** + * cogl_polygon: + * @vertices: An array of #CoglTextureVertex structs + * @n_vertices: The length of the vertices array + * @use_color: %TRUE if the color member of #CoglTextureVertex should be used + * + * Draws a convex polygon using the current source material to fill / texture + * with according to the texture coordinates passed. + * + * If @use_color is %TRUE then the color will be changed for each vertex using + * the value specified in the color member of #CoglTextureVertex. This can be + * used for example to make the texture fade out by setting the alpha value of + * the color. + * + * All of the texture coordinates must be in the range [0,1] and repeating the + * texture is not supported. + * + * Because of the way this function is implemented it will currently only work + * if either the texture is not sliced or the backend is not OpenGL ES and the + * minifying and magnifying functions are both set to CGL_NEAREST. + * + * Since 1.0 + */ +void cogl_polygon (CoglTextureVertex *vertices, + guint n_vertices, + gboolean use_color); G_END_DECLS diff --git a/cogl.h.in b/cogl.h.in index 18612aacc..e0cf44a82 100644 --- a/cogl.h.in +++ b/cogl.h.in @@ -32,7 +32,7 @@ #include -#include +#include #include #include #include diff --git a/common/cogl-material-private.h b/common/cogl-material-private.h index 935e0ae79..b4c36e78d 100644 --- a/common/cogl-material-private.h +++ b/common/cogl-material-private.h @@ -9,10 +9,28 @@ typedef struct _CoglMaterial CoglMaterial; typedef struct _CoglMaterialLayer CoglMaterialLayer; -typedef enum _CoglMaterialLayerFlags +/* XXX: I don't think gtk-doc supports having private enums so these aren't + * bundled in with CoglMaterialLayerFlags */ +typedef enum _CoglMaterialLayerPrivFlags { - COGL_MATERIAL_LAYER_FLAG_USER_MATRIX = 1L<<0, -} CoglMaterialLayerFlags; + /* Ref: CoglMaterialLayerFlags + COGL_MATERIAL_LAYER_FLAG_HAS_USER_MATRIX = 1L<<0 + */ + COGL_MATERIAL_LAYER_FLAG_DIRTY = 1L<<1, + COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE = 1L<<2 +} CoglMaterialLayerPrivFlags; + +/* For tracking the state of a layer that's been flushed to OpenGL */ +typedef struct _CoglLayerInfo +{ + CoglHandle handle; + gulong flags; + GLenum gl_target; + GLuint gl_texture; + gboolean fallback; + gboolean disabled; + gboolean layer0_overridden; +} CoglLayerInfo; struct _CoglMaterialLayer { @@ -42,7 +60,12 @@ typedef enum _CoglMaterialFlags { COGL_MATERIAL_FLAG_ENABLE_BLEND = 1L<<0, COGL_MATERIAL_FLAG_SHOWN_SAMPLER_WARNING = 1L<<1, - COGL_MATERIAL_FLAG_DIRTY = 1L<<2 + COGL_MATERIAL_FLAG_DIRTY = 1L<<2, + COGL_MATERIAL_FLAG_LAYERS_DIRTY = 1L<<3, + COGL_MATERIAL_FLAG_DEFAULT_COLOR = 1L<<4, + COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL = 1L<<5, + COGL_MATERIAL_FLAG_DEFAULT_ALPHA_FUNC = 1L<<6, + COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC = 1L<<7 } CoglMaterialFlags; struct _CoglMaterial diff --git a/common/cogl-material.c b/common/cogl-material.c index b0b9fd955..0b4b9dc6b 100644 --- a/common/cogl-material.c +++ b/common/cogl-material.c @@ -37,20 +37,24 @@ cogl_material_new (void) /* Use the same defaults as the GL spec... */ unlit[0] = 1.0; unlit[1] = 1.0; unlit[2] = 1.0; unlit[3] = 1.0; + material->flags |= COGL_MATERIAL_FLAG_DEFAULT_COLOR; /* Use the same defaults as the GL spec... */ ambient[0] = 0.2; ambient[1] = 0.2; ambient[2] = 0.2; ambient[3] = 1.0; diffuse[0] = 0.8; diffuse[1] = 0.8; diffuse[2] = 0.8; diffuse[3] = 1.0; specular[0] = 0; specular[1] = 0; specular[2] = 0; specular[3] = 1.0; emission[0] = 0; emission[1] = 0; emission[2] = 0; emission[3] = 1.0; + material->flags |= COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL; /* Use the same defaults as the GL spec... */ material->alpha_func = COGL_MATERIAL_ALPHA_FUNC_ALWAYS; material->alpha_func_reference = 0.0; + 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; + material->flags |= COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC; material->layers = NULL; @@ -69,7 +73,24 @@ _cogl_material_free (CoglMaterial *material) } void -cogl_material_set_color (CoglHandle handle, +cogl_material_get_color (CoglHandle handle, + CoglColor *color) +{ + CoglMaterial *material; + + g_return_if_fail (cogl_is_material (handle)); + + material = _cogl_material_pointer_from_handle (handle); + + cogl_color_set_from_4f (color, + material->unlit[0], + material->unlit[1], + material->unlit[2], + material->unlit[3]); +} + +void +cogl_material_set_color (CoglHandle handle, const CoglColor *unlit_color) { CoglMaterial *material; @@ -88,7 +109,46 @@ cogl_material_set_color (CoglHandle handle, memcpy (material->unlit, unlit, sizeof (unlit)); + if (unlit[0] == 1.0 && + unlit[1] == 1.0 && + unlit[2] == 1.0 && + unlit[3] == 1.0) + material->flags |= COGL_MATERIAL_FLAG_DEFAULT_COLOR; + + if (unlit[3] != 1.0) + material->flags |= COGL_MATERIAL_FLAG_ENABLE_BLEND; + material->flags |= COGL_MATERIAL_FLAG_DIRTY; + material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_COLOR; +} + +void +cogl_material_set_color4ub (CoglHandle handle, + guint8 red, + guint8 green, + guint8 blue, + guint8 alpha) +{ + CoglColor color; + cogl_color_set_from_4ub (&color, red, green, blue, alpha); + cogl_material_set_color (handle, &color); +} + +void +cogl_material_get_ambient (CoglHandle handle, + CoglColor *ambient) +{ + CoglMaterial *material; + + g_return_if_fail (cogl_is_material (handle)); + + material = _cogl_material_pointer_from_handle (handle); + + cogl_color_set_from_4f (ambient, + material->ambient[0], + material->ambient[1], + material->ambient[2], + material->ambient[3]); } void @@ -109,6 +169,24 @@ cogl_material_set_ambient (CoglHandle handle, ambient[3] = cogl_color_get_alpha_float (ambient_color); material->flags |= COGL_MATERIAL_FLAG_DIRTY; + material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL; +} + +void +cogl_material_get_diffuse (CoglHandle handle, + CoglColor *diffuse) +{ + CoglMaterial *material; + + g_return_if_fail (cogl_is_material (handle)); + + material = _cogl_material_pointer_from_handle (handle); + + cogl_color_set_from_4f (diffuse, + material->diffuse[0], + material->diffuse[1], + material->diffuse[2], + material->diffuse[3]); } void @@ -129,6 +207,7 @@ cogl_material_set_diffuse (CoglHandle handle, diffuse[3] = cogl_color_get_alpha_float (diffuse_color); material->flags |= COGL_MATERIAL_FLAG_DIRTY; + material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL; } void @@ -139,6 +218,23 @@ cogl_material_set_ambient_and_diffuse (CoglHandle handle, cogl_material_set_diffuse (handle, color); } +void +cogl_material_get_specular (CoglHandle handle, + CoglColor *specular) +{ + CoglMaterial *material; + + g_return_if_fail (cogl_is_material (handle)); + + material = _cogl_material_pointer_from_handle (handle); + + cogl_color_set_from_4f (specular, + material->specular[0], + material->specular[1], + material->specular[2], + material->specular[3]); +} + void cogl_material_set_specular (CoglHandle handle, const CoglColor *specular_color) @@ -157,6 +253,19 @@ cogl_material_set_specular (CoglHandle handle, specular[3] = cogl_color_get_alpha_float (specular_color); material->flags |= COGL_MATERIAL_FLAG_DIRTY; + material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL; +} + +float +cogl_material_get_shininess (CoglHandle handle) +{ + CoglMaterial *material; + + g_return_val_if_fail (cogl_is_material (handle), 0); + + material = _cogl_material_pointer_from_handle (handle); + + return material->shininess; } void @@ -176,6 +285,24 @@ cogl_material_set_shininess (CoglHandle handle, material->shininess = (GLfloat)shininess * 128.0; material->flags |= COGL_MATERIAL_FLAG_DIRTY; + material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL; +} + +void +cogl_material_get_emission (CoglHandle handle, + CoglColor *emission) +{ + CoglMaterial *material; + + g_return_if_fail (cogl_is_material (handle)); + + material = _cogl_material_pointer_from_handle (handle); + + cogl_color_set_from_4f (emission, + material->emission[0], + material->emission[1], + material->emission[2], + material->emission[3]); } void @@ -196,6 +323,7 @@ cogl_material_set_emission (CoglHandle handle, emission[3] = cogl_color_get_alpha_float (emission_color); material->flags |= COGL_MATERIAL_FLAG_DIRTY; + material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL; } void @@ -212,6 +340,7 @@ cogl_material_set_alpha_test_function (CoglHandle handle, material->alpha_func_reference = (GLfloat)alpha_reference; material->flags |= COGL_MATERIAL_FLAG_DIRTY; + material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_ALPHA_FUNC; } void @@ -228,6 +357,7 @@ cogl_material_set_blend_factors (CoglHandle handle, material->blend_dst_factor = dst_factor; material->flags |= COGL_MATERIAL_FLAG_DIRTY; + material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC; } /* Asserts that a layer corresponding to the given index exists. If no @@ -264,6 +394,7 @@ _cogl_material_get_layer (CoglMaterial *material, layer->ref_count = 1; layer->index = index; + layer->flags = COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE; layer->texture = COGL_INVALID_HANDLE; /* Choose the same default combine mode as OpenGL: @@ -284,6 +415,8 @@ _cogl_material_get_layer (CoglMaterial *material, layer->texture_combine_alpha_op[1] = COGL_MATERIAL_LAYER_COMBINE_OP_SRC_ALPHA; + cogl_matrix_init_identity (&layer->matrix); + layer_handle = _cogl_material_layer_handle_new (layer); /* Note: see comment after for() loop above */ material->layers = @@ -317,7 +450,7 @@ cogl_material_set_layer (CoglHandle material_handle, { if (!(material->flags & COGL_MATERIAL_FLAG_SHOWN_SAMPLER_WARNING)) { - g_warning ("Your hardware doesnot have enough texture samplers" + g_warning ("Your hardware does not have enough texture samplers" "to handle this many texture layers"); material->flags |= COGL_MATERIAL_FLAG_SHOWN_SAMPLER_WARNING; } @@ -328,11 +461,14 @@ cogl_material_set_layer (CoglHandle material_handle, * MAX_COMBINED_TEXTURE_IMAGE_UNITS layers. */ } + cogl_texture_ref (texture_handle); + if (layer->texture) cogl_texture_unref (layer->texture); - cogl_texture_ref (texture_handle); layer->texture = texture_handle; + layer->flags |= COGL_MATERIAL_LAYER_FLAG_DIRTY; + material->flags |= COGL_MATERIAL_FLAG_LAYERS_DIRTY; } void @@ -350,9 +486,7 @@ cogl_material_set_layer_combine_function ( g_return_if_fail (cogl_is_material (handle)); material = _cogl_material_pointer_from_handle (handle); - layer = _cogl_material_get_layer (material, layer_index, FALSE); - if (!layer) - return; + layer = _cogl_material_get_layer (material, layer_index, TRUE); if (channels == COGL_MATERIAL_LAYER_COMBINE_CHANNELS_RGBA) set_alpha_func = set_rgb_func = TRUE; @@ -365,6 +499,10 @@ cogl_material_set_layer_combine_function ( layer->texture_combine_rgb_func = func; if (set_alpha_func) layer->texture_combine_alpha_func = func; + + material->flags |= COGL_MATERIAL_FLAG_LAYERS_DIRTY; + layer->flags |= COGL_MATERIAL_LAYER_FLAG_DIRTY; + layer->flags &= ~COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE; } void @@ -377,16 +515,14 @@ cogl_material_set_layer_combine_arg_src ( { CoglMaterial *material; CoglMaterialLayer *layer; - gboolean set_arg_alpha_src = FALSE; - gboolean set_arg_rgb_src = FALSE; + gboolean set_arg_alpha_src = FALSE; + gboolean set_arg_rgb_src = FALSE; g_return_if_fail (cogl_is_material (handle)); g_return_if_fail (argument >=0 && argument <= 3); material = _cogl_material_pointer_from_handle (handle); - layer = _cogl_material_get_layer (material, layer_index, FALSE); - if (!layer) - return; + 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; @@ -399,6 +535,10 @@ cogl_material_set_layer_combine_arg_src ( layer->texture_combine_rgb_src[argument] = src; if (set_arg_alpha_src) layer->texture_combine_alpha_src[argument] = src; + + material->flags |= COGL_MATERIAL_FLAG_LAYERS_DIRTY; + layer->flags |= COGL_MATERIAL_LAYER_FLAG_DIRTY; + layer->flags &= ~COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE; } void @@ -418,9 +558,7 @@ cogl_material_set_layer_combine_arg_op ( g_return_if_fail (argument >=0 && argument <= 3); material = _cogl_material_pointer_from_handle (material_handle); - layer = _cogl_material_get_layer (material, layer_index, FALSE); - if (!layer) - return; + 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; @@ -433,6 +571,10 @@ cogl_material_set_layer_combine_arg_op ( layer->texture_combine_rgb_op[argument] = op; if (set_arg_alpha_op) layer->texture_combine_alpha_op[argument] = op; + + material->flags |= COGL_MATERIAL_FLAG_LAYERS_DIRTY; + layer->flags |= COGL_MATERIAL_LAYER_FLAG_DIRTY; + layer->flags &= ~COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE; } void @@ -446,12 +588,14 @@ cogl_material_set_layer_matrix (CoglHandle material_handle, g_return_if_fail (cogl_is_material (material_handle)); material = _cogl_material_pointer_from_handle (material_handle); - layer = _cogl_material_get_layer (material, layer_index, FALSE); - if (!layer) - return; + layer = _cogl_material_get_layer (material, layer_index, TRUE); layer->matrix = *matrix; - layer->flags |= COGL_MATERIAL_LAYER_FLAG_USER_MATRIX; + + material->flags |= COGL_MATERIAL_FLAG_LAYERS_DIRTY; + layer->flags |= COGL_MATERIAL_LAYER_FLAG_DIRTY; + layer->flags |= COGL_MATERIAL_LAYER_FLAG_HAS_USER_MATRIX; + layer->flags &= ~COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE; } static void @@ -490,6 +634,10 @@ cogl_material_remove_layer (CoglHandle material_handle, if (cogl_texture_get_format (layer->texture) & COGL_A_BIT) material->flags |= COGL_MATERIAL_FLAG_ENABLE_BLEND; } + + if (material->unlit[3] != 1.0) + material->flags |= COGL_MATERIAL_FLAG_ENABLE_BLEND; + material->flags |= COGL_MATERIAL_FLAG_LAYERS_DIRTY; } /* XXX: This API is hopfully just a stop-gap solution. Ideally cogl_enable @@ -553,6 +701,18 @@ cogl_material_layer_get_texture (CoglHandle layer_handle) return layer->texture; } +gulong +cogl_material_layer_get_flags (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->flags & COGL_MATERIAL_LAYER_FLAG_HAS_USER_MATRIX; +} + static guint get_n_args_for_combine_func (CoglMaterialLayerCombineFunc func) { @@ -573,89 +733,81 @@ get_n_args_for_combine_func (CoglMaterialLayerCombineFunc func) return 0; } -void -cogl_material_layer_flush_gl_sampler_state (CoglHandle layer_handle) +static void +_cogl_material_layer_flush_gl_sampler_state (CoglMaterialLayer *layer, + CoglLayerInfo *gl_layer_info) { - CoglMaterialLayer *layer; int n_rgb_func_args; int n_alpha_func_args; - g_return_if_fail (cogl_is_material_layer (layer_handle)); - - layer = _cogl_material_layer_pointer_from_handle (layer_handle); - - /* XXX: We really want some kind of cache/dirty flag mechanism - * somewhere here so we can avoid as much mucking about with - * the texture units per primitive as possible! - * - * E.g. some recent profiling of clutter-actor suggested that - * validating/updating the texture environment may currently - * be a significant bottleneck. Given that all the actors should - * have the same texture environment, that implies we could do a - * much better job of avoiding redundant glTexEnv calls. - */ - - GE (glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE)); - - /* Set the combiner functions... */ - GE (glTexEnvi (GL_TEXTURE_ENV, - GL_COMBINE_RGB, - layer->texture_combine_rgb_func)); - GE (glTexEnvi (GL_TEXTURE_ENV, - GL_COMBINE_ALPHA, - layer->texture_combine_alpha_func)); - - /* - * Setup the function arguments... - */ - - /* For the RGB components... */ - n_rgb_func_args = - get_n_args_for_combine_func (layer->texture_combine_rgb_func); - - GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, - layer->texture_combine_rgb_src[0])); - GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, - layer->texture_combine_rgb_op[0])); - if (n_rgb_func_args > 1) + if (!(gl_layer_info && + gl_layer_info->flags & COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE && + layer->flags & COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE)) { - GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, - layer->texture_combine_rgb_src[1])); - GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, - layer->texture_combine_rgb_op[1])); - } - if (n_rgb_func_args > 2) - { - GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC2_RGB, - layer->texture_combine_rgb_src[2])); - GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_RGB, - layer->texture_combine_rgb_op[2])); + GE (glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE)); + + /* Set the combiner functions... */ + GE (glTexEnvi (GL_TEXTURE_ENV, + GL_COMBINE_RGB, + layer->texture_combine_rgb_func)); + GE (glTexEnvi (GL_TEXTURE_ENV, + GL_COMBINE_ALPHA, + layer->texture_combine_alpha_func)); + + /* + * Setup the function arguments... + */ + + /* For the RGB components... */ + n_rgb_func_args = + get_n_args_for_combine_func (layer->texture_combine_rgb_func); + + GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, + layer->texture_combine_rgb_src[0])); + GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, + layer->texture_combine_rgb_op[0])); + if (n_rgb_func_args > 1) + { + GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, + layer->texture_combine_rgb_src[1])); + GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, + layer->texture_combine_rgb_op[1])); + } + if (n_rgb_func_args > 2) + { + GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC2_RGB, + layer->texture_combine_rgb_src[2])); + GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_RGB, + layer->texture_combine_rgb_op[2])); + } + + /* For the Alpha component */ + n_alpha_func_args = + get_n_args_for_combine_func (layer->texture_combine_alpha_func); + + GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, + layer->texture_combine_alpha_src[0])); + GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, + layer->texture_combine_alpha_op[0])); + if (n_alpha_func_args > 1) + { + GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, + layer->texture_combine_alpha_src[1])); + GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, + layer->texture_combine_alpha_op[1])); + } + if (n_alpha_func_args > 2) + { + GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC2_ALPHA, + layer->texture_combine_alpha_src[2])); + GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, + layer->texture_combine_alpha_op[2])); + } } - /* For the Alpha component */ - n_alpha_func_args = - get_n_args_for_combine_func (layer->texture_combine_alpha_func); - - GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, - layer->texture_combine_alpha_src[0])); - GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, - layer->texture_combine_alpha_op[0])); - if (n_alpha_func_args > 1) - { - GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, - layer->texture_combine_alpha_src[1])); - GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, - layer->texture_combine_alpha_op[1])); - } - if (n_alpha_func_args > 2) - { - GE (glTexEnvi (GL_TEXTURE_ENV, GL_SRC2_ALPHA, - layer->texture_combine_alpha_src[2])); - GE (glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, - layer->texture_combine_alpha_op[2])); - } - - if (layer->flags & COGL_MATERIAL_LAYER_FLAG_USER_MATRIX) + if (gl_layer_info && + (gl_layer_info->flags & COGL_MATERIAL_LAYER_FLAG_HAS_USER_MATRIX || + layer->flags & COGL_MATERIAL_LAYER_FLAG_HAS_USER_MATRIX)) { GE (glMatrixMode (GL_TEXTURE)); GE (glLoadMatrixf ((GLfloat *)&layer->matrix)); @@ -663,6 +815,275 @@ cogl_material_layer_flush_gl_sampler_state (CoglHandle layer_handle) } } +/** + * _cogl_material_flush_layers_gl_state: + * @fallback_mask: is a bitmask of the material layers that need to be + * replaced with the default, fallback textures. The fallback textures are + * fully transparent textures so they hopefully wont contribute to the + * texture combining. + * + * The intention of fallbacks is to try and preserve + * the number of layers the user is expecting so that texture coordinates + * they gave will mostly still correspond to the textures they intended, and + * have a fighting chance of looking close to their originally intended + * result. + * + * @disable_mask: is a bitmask of the material layers that will simply have + * texturing disabled. It's only really intended for disabling all layers + * > X; i.e. we'd expect to see a contiguous run of 0 starting from the LSB + * and at some point the remaining bits flip to 1. It might work to disable + * arbitrary layers; though I'm not sure a.t.m how OpenGL would take to + * that. + * + * The intention of the disable_mask is for emitting geometry when the user + * hasn't supplied enough texture coordinates for all the layers and it's + * not possible to auto generate default texture coordinates for those + * layers. + * + * @layer0_override_texture: forcibly tells us to bind this GL texture name for + * layer 0 instead of plucking the gl_texture from the CoglTexture of layer + * 0. + * + * The intention of this is for any geometry that supports sliced textures. + * The code will can iterate each of the slices and re-flush the material + * forcing the GL texture of each slice in turn. + * + * XXX: It might also help if we could specify a texture matrix for code + * dealing with slicing that would be multiplied with the users own matrix. + * + * Normaly texture coords in the range [0, 1] refer to the extents of the + * texture, but when your GL texture represents a slice of the real texture + * (from the users POV) then a texture matrix would be a neat way of + * transforming the mapping for each slice. + * + * Currently for textured rectangles we manually calculate the texture + * coords for each slice based on the users given coords, but this solution + * isn't ideal, and can't be used with CoglVertexBuffers. + */ +static void +_cogl_material_flush_layers_gl_state (CoglMaterial *material, + guint32 fallback_mask, + guint32 disable_mask, + GLuint layer0_override_texture) +{ + GList *tmp; + int i; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + for (tmp = material->layers, i = 0; tmp != NULL; tmp = tmp->next, i++) + { + CoglHandle layer_handle = (CoglHandle)tmp->data; + CoglMaterialLayer *layer = + _cogl_material_layer_pointer_from_handle (layer_handle); + CoglLayerInfo *gl_layer_info = NULL; + CoglLayerInfo new_gl_layer_info; + GLuint gl_texture; + GLenum gl_target; + + new_gl_layer_info.layer0_overridden = + layer0_override_texture ? TRUE : FALSE; + new_gl_layer_info.fallback = + (fallback_mask & (1<current_layers->len) + { + gl_layer_info = + &g_array_index (ctx->current_layers, CoglLayerInfo, i); + + if (gl_layer_info->handle == layer_handle && + !(layer->flags & COGL_MATERIAL_LAYER_FLAG_DIRTY) && + (gl_layer_info->layer0_overridden + == new_gl_layer_info.layer0_overridden) && + (gl_layer_info->fallback + == new_gl_layer_info.fallback) && + (gl_layer_info->disabled + == new_gl_layer_info.disabled)) + continue; + } + + cogl_texture_get_gl_texture (layer->texture, &gl_texture, &gl_target); + + if (new_gl_layer_info.layer0_overridden) + gl_texture = layer0_override_texture; + else if (new_gl_layer_info.fallback) + { + CoglHandle tex_handle; + + if (gl_target == GL_TEXTURE_2D) + tex_handle = ctx->default_gl_texture_2d_tex; + else if (gl_target == GL_TEXTURE_RECTANGLE_ARB) + tex_handle = ctx->default_gl_texture_rect_tex; + else + { + g_warning ("We don't have a default texture we can use to fill " + "in for an invalid material layer, since it was " + "using an unsupported texture target "); + /* might get away with this... */ + tex_handle = ctx->default_gl_texture_2d_tex; + } + cogl_texture_get_gl_texture (tex_handle, &gl_texture, NULL); + } + + GE (glActiveTexture (GL_TEXTURE0 + i)); + + if (!gl_layer_info + || gl_layer_info->gl_target != gl_target + || gl_layer_info->gl_texture != gl_texture) + GE (glBindTexture (gl_target, gl_texture)); + + /* Disable the previous target if it was different */ + if (gl_layer_info && + gl_layer_info->gl_target != gl_target && + !gl_layer_info->disabled) + GE (glDisable (gl_layer_info->gl_target)); + + /* Enable/Disable the new target */ + if (!new_gl_layer_info.disabled) + { + if (!(gl_layer_info && + gl_layer_info->gl_target == gl_target && + !gl_layer_info->disabled)) + GE (glEnable (gl_target)); + } + else + { + if (!(gl_layer_info && + gl_layer_info->gl_target == gl_target && + gl_layer_info->disabled)) + GE (glDisable (gl_target)); + } + + _cogl_material_layer_flush_gl_sampler_state (layer, gl_layer_info); + + new_gl_layer_info.handle = layer_handle; + new_gl_layer_info.flags = layer->flags; + new_gl_layer_info.gl_target = gl_target; + new_gl_layer_info.gl_texture = gl_texture; + + if (i < ctx->current_layers->len) + *gl_layer_info = new_gl_layer_info; + else + g_array_append_val (ctx->current_layers, new_gl_layer_info); + + layer->flags &= ~COGL_MATERIAL_LAYER_FLAG_DIRTY; + + if ((i+1) >= CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS) + break; + } + + /* Disable additional texture units that may have previously been in use.. */ + for (; i < ctx->current_layers->len; i++) + { + CoglLayerInfo *gl_layer_info = + &g_array_index (ctx->current_layers, CoglLayerInfo, i); + + if (!gl_layer_info->disabled) + { + GE (glActiveTexture (GL_TEXTURE0 + i)); + GE (glDisable (gl_layer_info->gl_target)); + gl_layer_info->disabled = TRUE; + } + } + + material->flags &= ~COGL_MATERIAL_FLAG_DIRTY; +} + +static void +_cogl_material_flush_base_gl_state (CoglMaterial *material) +{ + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + if (!(ctx->current_material_flags & COGL_MATERIAL_FLAG_DEFAULT_COLOR + && material->flags & COGL_MATERIAL_FLAG_DEFAULT_COLOR)) + { + GE (glColor4fv (material->unlit)); + } + + if (!(ctx->current_material_flags & COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL + && material->flags & COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL)) + { + /* FIXME - we only need to set these if lighting is enabled... */ + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, material->ambient)); + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, material->diffuse)); + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, material->specular)); + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, material->emission)); + GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS, &material->shininess)); + } + + if (!(ctx->current_material_flags & COGL_MATERIAL_FLAG_DEFAULT_ALPHA_FUNC + && material->flags & COGL_MATERIAL_FLAG_DEFAULT_ALPHA_FUNC)) + { + /* NB: Currently the Cogl defines are compatible with the GL ones: */ + GE (glAlphaFunc (material->alpha_func, material->alpha_func_reference)); + } + + 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)); + } +} + +void +cogl_material_flush_gl_state (CoglHandle handle, ...) +{ + CoglMaterial *material; + va_list ap; + CoglMaterialFlushOption option; + guint32 fallback_layers = 0; + guint32 disable_layers = 0; + GLuint layer0_override_texture = 0; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + material = _cogl_material_pointer_from_handle (handle); + + if (ctx->current_material == material && + !(material->flags & COGL_MATERIAL_FLAG_DIRTY) && + !(material->flags & COGL_MATERIAL_FLAG_LAYERS_DIRTY)) + return; + + if (ctx->current_material != material || + material->flags & COGL_MATERIAL_FLAG_DIRTY) + _cogl_material_flush_base_gl_state (material); + + if (ctx->current_material != material || + material->flags & COGL_MATERIAL_FLAG_LAYERS_DIRTY) + { + va_start (ap, handle); + while ((option = va_arg (ap, CoglMaterialFlushOption))) + { + if (option == COGL_MATERIAL_FLUSH_FALLBACK_MASK) + fallback_layers = va_arg (ap, guint32); + else if (option == COGL_MATERIAL_FLUSH_DISABLE_MASK) + disable_layers = va_arg (ap, guint32); + else if (option == COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE) + layer0_override_texture = va_arg (ap, GLuint); + } + va_end (ap); + + _cogl_material_flush_layers_gl_state (material, + fallback_layers, + disable_layers, + layer0_override_texture); + } + + /* NB: we have to take a reference so that next time + * cogl_material_flush_gl_state is called, we can compare the incomming + * material pointer with ctx->current_material + */ + cogl_material_ref (handle); + cogl_material_unref (ctx->current_material); + + ctx->current_material = handle; + ctx->current_material_flags = material->flags; +} + + + /* TODO: Should go in cogl.c, but that implies duplication which is also * not ideal. */ void @@ -675,40 +1096,24 @@ cogl_set_source (CoglHandle material_handle) if (ctx->source_material == material_handle) return; + cogl_material_ref (material_handle); + if (ctx->source_material) cogl_material_unref (ctx->source_material); - cogl_material_ref (material_handle); ctx->source_material = material_handle; } /* TODO: add cogl_set_front_source (), and cogl_set_back_source () */ void -cogl_flush_material_gl_state (void) +cogl_set_source_texture (CoglHandle texture_handle) { - CoglMaterial *material; _COGL_GET_CONTEXT (ctx, NO_RETVAL); + CoglColor white; - material = _cogl_material_pointer_from_handle (ctx->source_material); - - if (ctx->source_material == ctx->current_material - && !(material->flags & COGL_MATERIAL_FLAG_DIRTY)) - return; - - GE (glColor4fv (material->unlit)); - - /* FIXME - we only need to set these if lighting is enabled... */ - GE (glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, material->ambient)); - GE (glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, material->diffuse)); - GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, material->specular)); - GE (glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, material->emission)); - GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS, &material->shininess)); - - /* NB: Currently the Cogl defines are compatible with the GL ones: */ - GE (glAlphaFunc (material->alpha_func, material->alpha_func_reference)); - - GE (glBlendFunc (material->blend_src_factor, material->blend_dst_factor)); - - ctx->current_material = ctx->source_material; + cogl_material_set_layer (ctx->default_material, 0, texture_handle); + cogl_color_set_from_4ub (&white, 0xff, 0xff, 0xff, 0xff); + cogl_material_set_color (ctx->default_material, &white); + cogl_set_source (ctx->default_material); } diff --git a/common/cogl-primitives.c b/common/cogl-primitives.c index 7e9b1b94e..54111de50 100644 --- a/common/cogl-primitives.c +++ b/common/cogl-primitives.c @@ -43,19 +43,18 @@ void _cogl_path_add_node (gboolean new_sub_path, float y); void _cogl_path_fill_nodes (); void _cogl_path_stroke_nodes (); -void _cogl_rectangle (float x, - float y, - float width, - float height); + void cogl_rectangle (float x, float y, float width, float height) { - cogl_clip_ensure (); - - _cogl_rectangle (x, y, width, height); + cogl_rectangle_with_multitexture_coords (x, y, + x+width, + y+height, + NULL, + 0); } void diff --git a/common/cogl-vertex-buffer.c b/common/cogl-vertex-buffer.c index 45833cdd6..0b617244c 100644 --- a/common/cogl-vertex-buffer.c +++ b/common/cogl-vertex-buffer.c @@ -134,6 +134,7 @@ #include "cogl-context.h" #include "cogl-handle.h" #include "cogl-vertex-buffer-private.h" +#include "cogl-texture-private.h" #define PAD_FOR_ALIGNMENT(VAR, TYPE_SIZE) \ (VAR = TYPE_SIZE + ((VAR - 1) & ~(TYPE_SIZE - 1))) @@ -1416,12 +1417,15 @@ get_gl_type_from_attribute_flags (CoglVertexBufferAttribFlags flags) static void enable_state_for_drawing_attributes_buffer (CoglVertexBuffer *buffer) { - GList *tmp; - GLenum gl_type; - GLuint generic_index = 0; - gulong enable_flags = COGL_ENABLE_BLEND; - /* FIXME: I don't think it's appropriate to force enable - * GL_BLEND here. */ + GList *tmp; + GLenum gl_type; + GLuint generic_index = 0; + gulong enable_flags = 0; + guint max_texcoord_attrib_unit = 0; + const GList *layers; + guint32 fallback_mask = 0; + guint32 disable_mask = ~0; + int i; _COGL_GET_CONTEXT (ctx, NO_RETVAL); @@ -1460,17 +1464,16 @@ enable_state_for_drawing_attributes_buffer (CoglVertexBuffer *buffer) (const GLvoid *)attribute->u.vbo_offset)); break; case COGL_VERTEX_BUFFER_ATTRIB_FLAG_TEXTURE_COORD_ARRAY: - /* FIXME: set the active texture unit */ - /* NB: Cogl currently manages unit 0 */ - enable_flags |= (COGL_ENABLE_TEXCOORD_ARRAY - | COGL_ENABLE_TEXTURE_2D); - /* FIXME: I don't think it's appropriate to force enable - * GL_TEXTURE_2D here. */ - /* GE (glEnableClientState (GL_VERTEX_ARRAY)); */ + GE (glClientActiveTexture (GL_TEXTURE0 + + attribute->texture_unit)); + GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY)); GE (glTexCoordPointer (attribute->n_components, gl_type, attribute->stride, (const GLvoid *)attribute->u.vbo_offset)); + if (attribute->texture_unit > max_texcoord_attrib_unit) + max_texcoord_attrib_unit = attribute->texture_unit; + disable_mask &= ~(1 << attribute->texture_unit); break; case COGL_VERTEX_BUFFER_ATTRIB_FLAG_VERTEX_ARRAY: enable_flags |= COGL_ENABLE_VERTEX_ARRAY; @@ -1505,8 +1508,51 @@ enable_state_for_drawing_attributes_buffer (CoglVertexBuffer *buffer) } } - cogl_enable (enable_flags); + layers = cogl_material_get_layers (ctx->source_material); + for (tmp = (GList *)layers, i = 0; + tmp != NULL && i <= max_texcoord_attrib_unit; + tmp = tmp->next, i++) + { + CoglHandle layer = (CoglHandle)tmp->data; + CoglHandle tex_handle = cogl_material_layer_get_texture (layer); + CoglTexture *texture = + _cogl_texture_pointer_from_handle (tex_handle); + if (cogl_texture_is_sliced (tex_handle) + || _cogl_texture_span_has_waste (texture, 0, 0)) + { + g_warning ("Disabling layer %d of the current source material, " + "because texturing with the vertex buffer API is not " + "currently supported using sliced textures, or textures " + "with waste\n", i); + + /* XXX: maybe we can add a mechanism for users to forcibly use + * textures with waste where it would be their responsability to use + * texture coords in the range [0,1] such that sampling outside isn't + * required. We can then use a texture matrix (or a modification of + * the users own matrix) to map 1 to the edge of the texture data. + * + * Potentially, given the same guarantee as above we could also + * support a single sliced layer too. We would have to redraw the + * vertices once for each layer, each time with a fiddled texture + * matrix. + */ + fallback_mask |= (1 << i); + } + else if (!(disable_mask & (1 << i))) + fallback_mask |= (1 << i); + } + + 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); + + cogl_enable (enable_flags); } static void @@ -1550,9 +1596,9 @@ disable_state_for_drawing_buffer (CoglVertexBuffer *buffer) GE (glDisableClientState (GL_NORMAL_ARRAY)); break; case COGL_VERTEX_BUFFER_ATTRIB_FLAG_TEXTURE_COORD_ARRAY: - /* FIXME: set the active texture unit */ - /* NB: Cogl currently manages unit 0 */ - /* GE (glDisableClientState (GL_VERTEX_ARRAY)); */ + GE (glClientActiveTexture (GL_TEXTURE0 + + attribute->texture_unit)); + GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY)); break; case COGL_VERTEX_BUFFER_ATTRIB_FLAG_VERTEX_ARRAY: /* GE (glDisableClientState (GL_VERTEX_ARRAY)); */ diff --git a/gl/cogl-context.c b/gl/cogl-context.c index cd89fcf9a..6a3c032e4 100644 --- a/gl/cogl-context.c +++ b/gl/cogl-context.c @@ -31,6 +31,8 @@ #include "cogl-internal.h" #include "cogl-util.h" #include "cogl-context.h" +#include "cogl-texture-private.h" +#include "cogl-material-private.h" #include @@ -39,6 +41,9 @@ static CoglContext *_context = NULL; gboolean cogl_create_context () { + GLubyte default_texture_data[] = { 0xff, 0xff, 0xff, 0x0 }; + gulong enable_flags = 0; + if (_context != NULL) return FALSE; @@ -52,19 +57,26 @@ cogl_create_context () _context->enable_flags = 0; _context->color_alpha = 255; - _context->path_nodes = g_array_new (FALSE, FALSE, sizeof (CoglPathNode)); - _context->last_path = 0; - - _context->texture_handles = NULL; - _context->texture_vertices = g_array_new (FALSE, FALSE, - sizeof (CoglTextureGLVertex)); - _context->texture_indices = g_array_new (FALSE, FALSE, - sizeof (GLushort)); - _context->material_handles = NULL; _context->material_layer_handles = NULL; + _context->default_material = cogl_material_new (); _context->source_material = NULL; + + _context->texture_handles = NULL; + _context->default_gl_texture_2d_tex = COGL_INVALID_HANDLE; + _context->default_gl_texture_rect_tex = COGL_INVALID_HANDLE; + + _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)); + _context->current_material = NULL; + _context->current_material_flags = 0; + _context->current_layers = g_array_new (FALSE, FALSE, + sizeof (CoglLayerInfo)); + _context->n_texcoord_arrays_enabled = 0; _context->fbo_handles = NULL; _context->draw_buffer = COGL_WINDOW_BUFFER; @@ -78,6 +90,10 @@ cogl_create_context () _context->vertex_buffer_handles = NULL; + _context->path_nodes = g_array_new (FALSE, FALSE, sizeof (CoglPathNode)); + _context->last_path = 0; + _context->stencil_material = cogl_material_new (); + _context->pf_glGenRenderbuffersEXT = NULL; _context->pf_glBindRenderbufferEXT = NULL; _context->pf_glRenderbufferStorageEXT = NULL; @@ -123,15 +139,37 @@ cogl_create_context () _context->pf_glDrawRangeElements = NULL; - /* Init OpenGL state */ - GE( glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE) ); - GE( glColorMask (TRUE, TRUE, TRUE, FALSE) ); - GE( glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) ); - cogl_enable (0); - /* Initialise the clip stack */ _cogl_clip_stack_state_init (); + /* Create default textures used for fall backs */ + _context->default_gl_texture_2d_tex = + cogl_texture_new_from_data (1, /* width */ + 1, /* height */ + -1, /* max waste */ + FALSE, /* auto mipmap */ + COGL_PIXEL_FORMAT_RGBA_8888, /* data format */ + /* internal format */ + COGL_PIXEL_FORMAT_RGBA_8888, + 0, /* auto calc row stride */ + &default_texture_data); + _context->default_gl_texture_rect_tex = + cogl_texture_new_from_data (1, /* width */ + 1, /* height */ + -1, /* max waste */ + FALSE, /* auto mipmap */ + COGL_PIXEL_FORMAT_RGBA_8888, /* data format */ + /* internal format */ + COGL_PIXEL_FORMAT_RGBA_8888, + 0, /* auto calc row stride */ + &default_texture_data); + + cogl_set_source (_context->default_material); + cogl_material_flush_gl_state (_context->source_material, NULL); + enable_flags = + cogl_material_get_cogl_enable_flags (_context->source_material); + cogl_enable (enable_flags); + return TRUE; } @@ -155,10 +193,25 @@ cogl_destroy_context () if (_context->program_handles) g_array_free (_context->program_handles, TRUE); - if (_context->texture_vertices) - g_array_free (_context->texture_vertices, TRUE); - if (_context->texture_indices) - g_array_free (_context->texture_indices, TRUE); + if (_context->default_gl_texture_2d_tex) + cogl_texture_unref (_context->default_gl_texture_2d_tex); + if (_context->default_gl_texture_rect_tex) + cogl_texture_unref (_context->default_gl_texture_rect_tex); + + if (_context->default_material) + cogl_material_unref (_context->default_material); + + if (_context->journal) + g_array_free (_context->journal, TRUE); + 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); g_free (_context); } diff --git a/gl/cogl-context.h b/gl/cogl-context.h index ae1b80c85..db3a333a1 100644 --- a/gl/cogl-context.h +++ b/gl/cogl-context.h @@ -50,33 +50,34 @@ typedef struct gboolean enable_backface_culling; - /* Primitives */ - floatVec2 path_start; - floatVec2 path_pen; - GArray *path_nodes; - guint last_path; - floatVec2 path_nodes_min; - floatVec2 path_nodes_max; - /* Cache of inverse projection matrix */ GLfloat inverse_projection[16]; /* Textures */ - GArray *texture_handles; - GArray *texture_vertices; - GArray *texture_indices; - /* The gl texture number that the above vertices apply to. This to - detect when a different slice is encountered so that the vertices - can be flushed */ - GLuint texture_current; - GLenum texture_target; - GLenum texture_wrap_mode; + GArray *texture_handles; + CoglHandle default_gl_texture_2d_tex; + CoglHandle default_gl_texture_rect_tex; /* Materials */ GArray *material_handles; GArray *material_layer_handles; + CoglHandle default_material; CoglHandle source_material; + + /* Batching geometry... */ + /* We journal the texture rectangles we want to submit to OpenGL so + * we have an oppertunity to optimise the final order so that we + * can batch things together. */ + GArray *journal; + GArray *logged_vertices; + GArray *static_indices; + GArray *polygon_vertices; + + /* Some simple caching, to minimize state changes... */ CoglHandle current_material; + gulong current_material_flags; + GArray *current_layers; + guint n_texcoord_arrays_enabled; /* Framebuffer objects */ GArray *fbo_handles; @@ -94,6 +95,15 @@ typedef struct /* Vertex buffers */ GArray *vertex_buffer_handles; + /* Primitives */ + floatVec2 path_start; + floatVec2 path_pen; + GArray *path_nodes; + guint last_path; + floatVec2 path_nodes_min; + floatVec2 path_nodes_max; + CoglHandle stencil_material; + /* Relying on glext.h to define these */ COGL_PFNGLGENRENDERBUFFERSEXTPROC pf_glGenRenderbuffersEXT; COGL_PFNGLDELETERENDERBUFFERSEXTPROC pf_glDeleteRenderbuffersEXT; diff --git a/gl/cogl-internal.h b/gl/cogl-internal.h index 8887788c2..735e005ee 100644 --- a/gl/cogl-internal.h +++ b/gl/cogl-internal.h @@ -51,13 +51,10 @@ const char *_cogl_error_string(GLenum errorCode); #endif /* COGL_DEBUG */ #define COGL_ENABLE_BLEND (1<<1) -#define COGL_ENABLE_TEXTURE_2D (1<<2) -#define COGL_ENABLE_ALPHA_TEST (1<<3) -#define COGL_ENABLE_TEXTURE_RECT (1<<4) -#define COGL_ENABLE_VERTEX_ARRAY (1<<5) -#define COGL_ENABLE_TEXCOORD_ARRAY (1<<6) -#define COGL_ENABLE_COLOR_ARRAY (1<<7) -#define COGL_ENABLE_BACKFACE_CULLING (1<<8) +#define COGL_ENABLE_ALPHA_TEST (1<<2) +#define COGL_ENABLE_VERTEX_ARRAY (1<<3) +#define COGL_ENABLE_COLOR_ARRAY (1<<4) +#define COGL_ENABLE_BACKFACE_CULLING (1<<5) gint _cogl_get_format_bpp (CoglPixelFormat format); diff --git a/gl/cogl-primitives.c b/gl/cogl-primitives.c index e44565780..6c00ed193 100644 --- a/gl/cogl-primitives.c +++ b/gl/cogl-primitives.c @@ -38,27 +38,13 @@ #define _COGL_MAX_BEZ_RECURSE_DEPTH 16 -void -_cogl_rectangle (float x, - float y, - float width, - float height) -{ - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - cogl_enable (ctx->color_alpha < 255 - ? COGL_ENABLE_BLEND : 0); - - GE( glRectf (x, y, x + width, y + height) ); -} - void _cogl_path_add_node (gboolean new_sub_path, float x, float y) { CoglPathNode new_node; - + _COGL_GET_CONTEXT (ctx, NO_RETVAL); new_node.x = (x); @@ -89,13 +75,18 @@ _cogl_path_add_node (gboolean new_sub_path, void _cogl_path_stroke_nodes () { - guint path_start = 0; + guint path_start = 0; + gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY; _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - cogl_enable (COGL_ENABLE_VERTEX_ARRAY - | (ctx->color_alpha < 255 - ? COGL_ENABLE_BLEND : 0)); + + 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); while (path_start < ctx->path_nodes->len) { @@ -106,7 +97,7 @@ _cogl_path_stroke_nodes () (guchar *) path + G_STRUCT_OFFSET (CoglPathNode, x)) ); GE( glDrawArrays (GL_LINE_STRIP, 0, path->path_size) ); - + path_start += path->path_size; } } @@ -139,6 +130,8 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, float bounds_w; float bounds_h; + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + _cogl_path_get_bounds (nodes_min, nodes_max, &bounds_x, &bounds_y, &bounds_w, &bounds_h); @@ -159,10 +152,17 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, GE( glColorMask (FALSE, FALSE, FALSE, FALSE) ); GE( glDepthMask (FALSE) ); - + while (path_start < path_size) { - cogl_enable (COGL_ENABLE_VERTEX_ARRAY); + gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY; + + /* Just setup a simple material that doesn't use texturing... */ + cogl_material_flush_gl_state (ctx->stencil_material, NULL); + + enable_flags |= + cogl_material_get_cogl_enable_flags (ctx->source_material); + cogl_enable (enable_flags); GE( glVertexPointer (2, GL_FLOAT, sizeof (CoglPathNode), (guchar *) path @@ -207,11 +207,11 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, GE( glMatrixMode (GL_MODELVIEW) ); GE( glPopMatrix () ); } - + GE( glStencilMask (~(GLuint) 0) ); GE( glDepthMask (TRUE) ); GE( glColorMask (TRUE, TRUE, TRUE, TRUE) ); - + GE( glStencilFunc (GL_EQUAL, 0x1, 0x1) ); GE( glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) ); } diff --git a/gl/cogl-texture-private.h b/gl/cogl-texture-private.h index 44fd7712e..59bcad108 100644 --- a/gl/cogl-texture-private.h +++ b/gl/cogl-texture-private.h @@ -28,11 +28,9 @@ #include "cogl-bitmap.h" -typedef struct _CoglTexture CoglTexture; -typedef struct _CoglTexSliceSpan CoglTexSliceSpan; -typedef struct _CoglSpanIter CoglSpanIter; -typedef struct _CoglCompositeTexture CoglCompositeTexture; -typedef struct _CoglCompositeTextureLayer CoglCompositeTextureLayer; +typedef struct _CoglTexture CoglTexture; +typedef struct _CoglTexSliceSpan CoglTexSliceSpan; +typedef struct _CoglSpanIter CoglSpanIter; struct _CoglTexSliceSpan { @@ -61,26 +59,23 @@ struct _CoglTexture gboolean auto_mipmap; }; -struct _CoglCompositeTextureLayer +/* To improve batching of geometry when submitting vertices to OpenGL we + * log the texture rectangles we want to draw to a journal, so when we + * later flush the journal we aim to batch data, and gl draw calls. */ +typedef struct _CoglJournalEntry { - guint ref_count; - - guint index; /*!< lowest index is blended first then others - on top */ - CoglTexture *tex; /*!< The texture for this layer, or NULL - for an empty layer */ - - /* TODO: Add more control over the texture environment for each texture - * unit. For example we should support dot3 normal mapping. */ -}; - -struct _CoglCompositeTexture -{ - guint ref_count; - GList *layers; -}; + CoglHandle material; + gint n_layers; + guint32 fallback_mask; + GLuint layer0_override_texture; +} CoglJournalEntry; CoglTexture* _cogl_texture_pointer_from_handle (CoglHandle handle); +gboolean +_cogl_texture_span_has_waste (CoglTexture *tex, + gint x_span_index, + gint y_span_index); + #endif /* __COGL_TEXTURE_H */ diff --git a/gl/cogl-texture.c b/gl/cogl-texture.c index df85e9bf1..0a84457c5 100644 --- a/gl/cogl-texture.c +++ b/gl/cogl-texture.c @@ -51,6 +51,8 @@ printf("err: 0x%x\n", err); \ } */ +static void _cogl_journal_flush (void); + static void _cogl_texture_free (CoglTexture *tex); COGL_HANDLE_DEFINE (Texture, texture, texture_handles); @@ -774,6 +776,10 @@ _cogl_texture_set_wrap_mode_parameter (CoglTexture *tex, { int i; + /* Any queued texture rectangles may be depending on the previous + * wrap mode... */ + _cogl_journal_flush (); + for (i = 0; i < tex->slice_gl_handles->len; i++) { GLuint texnum = g_array_index (tex->slice_gl_handles, GLuint, i); @@ -990,6 +996,20 @@ _cogl_texture_slices_free (CoglTexture *tex) } } +gboolean +_cogl_texture_span_has_waste (CoglTexture *tex, + gint x_span_index, + gint y_span_index) +{ + CoglTexSliceSpan *x_span; + CoglTexSliceSpan *y_span; + + x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x_span_index); + y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, y_span_index); + + return (x_span->waste || y_span->waste) ? TRUE : FALSE; +} + static gboolean _cogl_pixel_format_from_gl_internal (GLenum gl_int_format, CoglPixelFormat *out_format) @@ -1392,12 +1412,12 @@ cogl_texture_new_from_file (const gchar *filename, { CoglBitmap *bmp; CoglHandle handle; - + g_return_val_if_fail (error == NULL || *error == NULL, COGL_INVALID_HANDLE); if (!(bmp = cogl_bitmap_new_from_file (filename, error))) return COGL_INVALID_HANDLE; - + handle = cogl_texture_new_from_bitmap (bmp, max_waste, flags, @@ -1920,130 +1940,307 @@ cogl_texture_get_data (CoglHandle handle, return byte_size; } + +/****************************************************************************** + * XXX: Here ends the code that strictly implements "CoglTextures". + * + * The following consists of code for rendering rectangles and polygons. It + * might be neater to move this code somewhere else. I think everything below + * here should be implementable without access to CoglTexture internals, but + * that will at least mean exposing the cogl_span_iter_* funcs. + */ + static void -_cogl_texture_flush_vertices (void) +_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; + guint32 disable_mask; + _COGL_GET_CONTEXT (ctx, NO_RETVAL); - if (ctx->texture_vertices->len > 0) + /* 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 needed_indices; - CoglTextureGLVertex *p - = (CoglTextureGLVertex *) ctx->texture_vertices->data; + int old_len = ctx->static_indices->len; + int vert_num = old_len / 6 * 4; + GLushort *q; - /* 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 = ctx->texture_vertices->len / 4 * 6; - if (needed_indices > ctx->texture_indices->len) + /* 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) { - int old_len = ctx->texture_indices->len; - int vert_num = old_len / 6 * 4; - int i; - GLushort *q; + *(q++) = vert_num + 0; + *(q++) = vert_num + 1; + *(q++) = vert_num + 3; - /* 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->texture_indices, needed_indices); - q = &g_array_index (ctx->texture_indices, GLushort, old_len); + *(q++) = vert_num + 1; + *(q++) = vert_num + 2; + *(q++) = vert_num + 3; + } + } - for (i = old_len; - i < ctx->texture_indices->len; - i += 6, vert_num += 4) - { - *(q++) = vert_num + 0; - *(q++) = vert_num + 1; - *(q++) = vert_num + 3; + /* XXX NB: + * Our vertex data is arranged as follows: + * 4 vertices per quad: 2 GLfloats per position, + * 2 GLfloats per tex coord * n_layers + */ + stride = 2 + 2 * batch_start->n_layers; + stride *= sizeof (GLfloat); - *(q++) = vert_num + 1; - *(q++) = vert_num + 2; - *(q++) = vert_num + 3; - } + 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); + + for (i = 0; i < batch_start->n_layers; i++) + { + GE (glClientActiveTexture (GL_TEXTURE0 + i)); + GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY)); + GE (glTexCoordPointer (2, GL_FLOAT, stride, vertex_pointer + 2 + 2 * i)); + } + for (; i < ctx->n_texcoord_arrays_enabled; i++) + { + GE (glClientActiveTexture (GL_TEXTURE0 + i)); + GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY)); + } + ctx->n_texcoord_arrays_enabled = 0; + + /* 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); + + if (ctx->enable_backface_culling) + enable_flags |= COGL_ENABLE_BACKFACE_CULLING; + + enable_flags |= COGL_ENABLE_VERTEX_ARRAY; + cogl_enable (enable_flags); + + GE (glVertexPointer (2, GL_FLOAT, stride, vertex_pointer)); + + GE (ctx->pf_glDrawRangeElements (GL_TRIANGLES, + 0, ctx->static_indices->len - 1, + 6 * batch_len, + GL_UNSIGNED_SHORT, + ctx->static_indices->data)); +} + +static void +_cogl_journal_flush (void) +{ + GLfloat *current_vertex_pointer; + GLfloat *batch_vertex_pointer; + CoglJournalEntry *batch_start; + guint batch_len; + int i; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + if (ctx->journal->len == 0) + return; + + /* Current non-variables / constraints: + * + * - We don't have to worry about much GL state changing between journal + * entries since currently the journal never out lasts a single call to + * _cogl_multitexture_multiple_rectangles. So the user doesn't get the + * chance to fiddle with anything. (XXX: later this will be extended at + * which point we can start logging certain state changes) + * + * - Implied from above: all entries will refer to the same material. + * + * - Although _cogl_multitexture_multiple_rectangles can cause the wrap mode + * of textures to be modified, the journal is flushed if a wrap mode is + * changed so we don't currently have to log wrap mode changes. + * + * - XXX - others? + */ + + /* TODO: "compile" the journal to find ways of batching draw calls and vertex + * data. + * + * Simple E.g. given current constraints... + * pass 0 - load all data into a single CoglVertexBuffer + * pass 1 - batch gl draw calls according to entries that use the same + * textures. + * + * We will be able to do cooler stuff here when we extend the life of + * journals beyond _cogl_multitexture_multiple_rectangles. + */ + + batch_vertex_pointer = (GLfloat *)ctx->logged_vertices->data; + batch_start = (CoglJournalEntry *)ctx->journal->data; + batch_len = 1; + + current_vertex_pointer = batch_vertex_pointer; + + for (i = 1; i < ctx->journal->len; i++) + { + CoglJournalEntry *prev_entry = + &g_array_index (ctx->journal, CoglJournalEntry, i - 1); + CoglJournalEntry *current_entry = prev_entry + 1; + gsize stride; + + /* Progress the vertex pointer */ + stride = 2 + current_entry->n_layers * 2; + current_vertex_pointer += stride; + + /* batch rectangles using the same textures */ + if (current_entry->material == prev_entry->material && + current_entry->n_layers == prev_entry->n_layers && + current_entry->fallback_mask == prev_entry->fallback_mask && + current_entry->layer0_override_texture + == prev_entry->layer0_override_texture) + { + batch_len++; + continue; } - GE( glVertexPointer (2, GL_FLOAT, - sizeof (CoglTextureGLVertex), p->v ) ); - GE( glTexCoordPointer (2, GL_FLOAT, - sizeof (CoglTextureGLVertex), p->t ) ); + _cogl_journal_flush_quad_batch (batch_start, + batch_len, + batch_vertex_pointer); - GE( glBindTexture (ctx->texture_target, ctx->texture_current) ); - GE( ctx->pf_glDrawRangeElements (GL_TRIANGLES, - 0, ctx->texture_vertices->len - 1, - needed_indices, - GL_UNSIGNED_SHORT, - ctx->texture_indices->data) ); - - g_array_set_size (ctx->texture_vertices, 0); + batch_start = current_entry; + batch_len = 1; + batch_vertex_pointer = current_vertex_pointer; } + + /* The last batch... */ + _cogl_journal_flush_quad_batch (batch_start, + batch_len, + batch_vertex_pointer); + + + g_array_set_size (ctx->journal, 0); + g_array_set_size (ctx->logged_vertices, 0); } static void -_cogl_texture_add_quad_vertices (GLfloat x1, GLfloat y1, - GLfloat x2, GLfloat y2, - GLfloat tx1, GLfloat ty1, - GLfloat tx2, GLfloat ty2) +_cogl_journal_log_quad (float x1, + float y1, + float x2, + float y2, + CoglHandle material, + gint n_layers, + guint32 fallback_mask, + GLuint layer0_override_texture, + float *tex_coords, + guint tex_coords_len) { - CoglTextureGLVertex *p; - GLushort first_vert; + int stride; + int next_vert; + GLfloat *v; + int i; + int next_entry; + CoglJournalEntry *entry; _COGL_GET_CONTEXT (ctx, NO_RETVAL); - /* Add the four vertices of the quad to the list of queued - vertices */ - first_vert = ctx->texture_vertices->len; - g_array_set_size (ctx->texture_vertices, first_vert + 4); - p = &g_array_index (ctx->texture_vertices, CoglTextureGLVertex, first_vert); + /* The vertex data is logged into a seperate array in a layout that can be + * directly passed to OpenGL + */ - p->v[0] = x1; p->v[1] = y1; - p->t[0] = tx1; p->t[1] = ty1; - p++; - p->v[0] = x1; p->v[1] = y2; - p->t[0] = tx1; p->t[1] = ty2; - p++; - p->v[0] = x2; p->v[1] = y2; - p->t[0] = tx2; p->t[1] = ty2; - p++; - p->v[0] = x2; p->v[1] = y1; - p->t[0] = tx2; p->t[1] = ty1; - p++; + /* We pack the vertex data as 2 (x,y) GLfloats folowed by 2 (tx,ty) GLfloats + * for each texture being used, E.g.: + * [X, Y, TX0, TY0, TX1, TY1, X, Y, TX0, TY0, X, Y, ...] + */ + stride = 2 + n_layers * 2; + + next_vert = ctx->logged_vertices->len; + g_array_set_size (ctx->logged_vertices, next_vert + 4 * stride); + v = &g_array_index (ctx->logged_vertices, GLfloat, next_vert); + + /* XXX: All the jumping around to fill in this strided buffer doesn't + * seem ideal. */ + + /* XXX: we could defer expanding the vertex data for GL until we come + * to flushing the journal. */ + + v[0] = x1; v[1] = y1; + v += stride; + v[0] = x1; v[1] = y2; + v += stride; + v[0] = x2; v[1] = y2; + v += stride; + v[0] = x2; v[1] = y1; + + for (i = 0; i < n_layers; i++) + { + GLfloat *t = + &g_array_index (ctx->logged_vertices, GLfloat, next_vert + 2 + 2 * i); + + t[0] = tex_coords[0]; t[1] = tex_coords[1]; + t += stride; + t[0] = tex_coords[0]; t[1] = tex_coords[3]; + t += stride; + t[0] = tex_coords[2]; t[1] = tex_coords[3]; + t += stride; + t[0] = tex_coords[2]; t[1] = tex_coords[1]; + } + + next_entry = ctx->journal->len; + g_array_set_size (ctx->journal, next_entry + 1); + entry = &g_array_index (ctx->journal, CoglJournalEntry, next_entry); + + entry->material = material; + entry->n_layers = n_layers; + entry->fallback_mask = fallback_mask; + entry->layer0_override_texture = layer0_override_texture; } static void -_cogl_texture_quad_sw (CoglTexture *tex, - float x1, - float y1, - float x2, - float y2, - float tx1, - float ty1, - float tx2, - float ty2) +_cogl_texture_sliced_quad (CoglTexture *tex, + CoglHandle material, + float x1, + float y1, + float x2, + float y2, + float tx1, + float ty1, + float tx2, + float ty2) { - CoglSpanIter iter_x , iter_y; - float tw , th; - float tqx , tqy; - float first_tx , first_ty; - float first_qx , first_qy; - float slice_tx1 , slice_ty1; - float slice_tx2 , slice_ty2; - float slice_qx1 , slice_qy1; - float slice_qx2 , slice_qy2; - GLuint gl_handle; + CoglSpanIter iter_x , iter_y; + float tw , th; + float tqx , tqy; + float first_tx , first_ty; + float first_qx , first_qy; + float slice_tx1 , slice_ty1; + float slice_tx2 , slice_ty2; + float slice_qx1 , slice_qy1; + float slice_qx2 , slice_qy2; + GLuint gl_handle; _COGL_GET_CONTEXT (ctx, NO_RETVAL); #if COGL_DEBUG - printf("=== Drawing Tex Quad (Software Tiling Mode) ===\n"); + printf("=== Drawing Tex Quad (Sliced Mode) ===\n"); #endif /* We can't use hardware repeat so we need to set clamp to edge otherwise it might pull in edge pixels from the other side */ - if (ctx->texture_vertices->len > 0 - && ctx->texture_wrap_mode != GL_CLAMP_TO_EDGE) - _cogl_texture_flush_vertices (); _cogl_texture_set_wrap_mode_parameter (tex, GL_CLAMP_TO_EDGE); - ctx->texture_wrap_mode = GL_CLAMP_TO_EDGE; /* If the texture coordinates are backwards then swap both the geometry and texture coordinates so that the texture will be @@ -2098,6 +2295,8 @@ _cogl_texture_quad_sw (CoglTexture *tex, !_cogl_span_iter_end (&iter_y) ; _cogl_span_iter_next (&iter_y) ) { + float tex_coords[4]; + /* Discard slices out of quad early */ if (!iter_y.intersects) continue; @@ -2161,183 +2360,358 @@ _cogl_texture_quad_sw (CoglTexture *tex, iter_y.index * iter_x.array->len + iter_x.index); - /* If we're using a different texture from the one already queued - then flush the vertices */ - if (ctx->texture_vertices->len > 0 - && gl_handle != ctx->texture_current) - _cogl_texture_flush_vertices (); - ctx->texture_target = tex->gl_target; - ctx->texture_current = gl_handle; - - _cogl_texture_add_quad_vertices ( (slice_qx1), - (slice_qy1), - (slice_qx2), - (slice_qy2), - (slice_tx1), - (slice_ty1), - (slice_tx2), - (slice_ty2)); + tex_coords[0] = slice_tx1; + tex_coords[1] = slice_ty1; + tex_coords[2] = slice_tx2; + tex_coords[3] = slice_ty2; + _cogl_journal_log_quad (slice_qx1, + slice_qy1, + slice_qx2, + slice_qy2, + material, + 1, /* one layer */ + 0, /* don't need to use fallbacks */ + gl_handle, /* replace the layer0 texture */ + tex_coords, + 4); } } } -static void -_cogl_texture_quad_hw (CoglTexture *tex, - float x1, - float y1, - float x2, - float y2, - float tx1, - float ty1, - float tx2, - float ty2) +static gboolean +_cogl_multitexture_unsliced_quad (float x1, + float y1, + float x2, + float y2, + CoglHandle material, + gint n_layers, + guint32 fallback_mask, + const float *user_tex_coords, + gint user_tex_coords_len) { - GLuint gl_handle; - CoglTexSliceSpan *x_span; - CoglTexSliceSpan *y_span; - GLenum wrap_mode; + float *final_tex_coords = alloca (sizeof (float) * 4 * n_layers); + const GList *layers; + GList *tmp; + int i; -#if COGL_DEBUG - printf("=== Drawing Tex Quad (Hardware Tiling Mode) ===\n"); -#endif + _COGL_GET_CONTEXT (ctx, FALSE); - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - /* If the texture coords are all in the range [0,1] then we want to - clamp the coords to the edge otherwise it can pull in edge pixels - from the wrong side when scaled */ - if (tx1 >= 0 && tx1 <= 1.0 - && tx2 >= 0 && tx2 <= 1.0 - && ty1 >= 0 && ty1 <= 1.0 - && ty2 >= 0 && ty2 <= 1.0) - wrap_mode = GL_CLAMP_TO_EDGE; - else - wrap_mode = GL_REPEAT; - - /* Pick and bind opengl texture object */ - gl_handle = g_array_index (tex->slice_gl_handles, GLuint, 0); - - /* If we're using a different texture from the one already queued - then flush the vertices */ - if (ctx->texture_vertices->len > 0 - && (gl_handle != ctx->texture_current - || ctx->texture_wrap_mode != wrap_mode)) - _cogl_texture_flush_vertices (); - ctx->texture_target = tex->gl_target; - ctx->texture_current = gl_handle; - ctx->texture_wrap_mode = wrap_mode; - - _cogl_texture_set_wrap_mode_parameter (tex, wrap_mode); - - /* Don't include the waste in the texture coordinates */ - x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0); - y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0); - - /* Don't include the waste in the texture coordinates */ - tx1 = tx1 * (x_span->size - x_span->waste) / x_span->size; - tx2 = tx2 * (x_span->size - x_span->waste) / x_span->size; - ty1 = ty1 * (y_span->size - y_span->waste) / y_span->size; - ty2 = ty2 * (y_span->size - y_span->waste) / y_span->size; - - /* Denormalize texture coordinates for rectangle textures */ - if (tex->gl_target == GL_TEXTURE_RECTANGLE_ARB) + /* + * Validate the texture coordinates for this rectangle. + */ + layers = cogl_material_get_layers (material); + for (tmp = (GList *)layers, i = 0; tmp != NULL; tmp = tmp->next, i++) { - tx1 *= x_span->size; - tx2 *= x_span->size; - ty1 *= y_span->size; - ty2 *= y_span->size; + CoglHandle layer = (CoglHandle)tmp->data; + /* CoglLayerInfo *layer_info; */ + CoglHandle tex_handle; + CoglTexture *tex; + const float *in_tex_coords; + float *out_tex_coords; + CoglTexSliceSpan *x_span; + CoglTexSliceSpan *y_span; + + /* layer_info = &layers[i]; */ + + /* FIXME - we shouldn't be checking this stuff if layer_info->gl_texture + * already == 0 */ + + tex_handle = cogl_material_layer_get_texture (layer); + tex = _cogl_texture_pointer_from_handle (tex_handle); + + in_tex_coords = &user_tex_coords[i * 4]; + out_tex_coords = &final_tex_coords[i * 4]; + + + /* If the texture has waste or we are using GL_TEXTURE_RECT we + * can't handle texture repeating so we check that the texture + * coords lie in the range [0,1]. + * + * NB: We already know that no texture matrix is being used + * if the texture has waste since we validated that early on. + * TODO: check for a texture matrix in the GL_TEXTURE_RECT + * case. + */ + if ((tex->gl_target == GL_TEXTURE_RECTANGLE_ARB + || _cogl_texture_span_has_waste (tex, 0, 0)) + && (in_tex_coords[0] < 0 || in_tex_coords[0] > 1.0 + || in_tex_coords[1] < 0 || in_tex_coords[1] > 1.0 + || in_tex_coords[2] < 0 || in_tex_coords[2] > 1.0 + || in_tex_coords[3] < 0 || in_tex_coords[3] > 1.0)) + { + if (i == 0) + { + if (n_layers > 1) + { + g_warning ("Skipping layers 1..n of your material since the " + "first layer has waste and you supplied texture " + "coordinates outside the range [0,1]. We don't " + "currently support any multi-texturing using " + "textures with waste when repeating is " + "necissary so we are falling back to sliced " + "textures assuming layer 0 is the most " + "important one keep"); + } + return FALSE; + } + else + { + g_warning ("Skipping layer %d of your material " + "consisting of a texture with waste since " + "you have supplied texture coords outside " + "the range [0,1] (unsupported when " + "multi-texturing)", i); + + /* NB: marking for fallback will replace the layer with + * a default transparent texture */ + fallback_mask |= (1 << i); + } + } + + + /* + * Setup the texture unit... + */ + + /* NB: The user might not have supplied texture coordinates for all + * layers... */ + if (i < (user_tex_coords_len / 4)) + { + GLenum wrap_mode; + + /* If the texture coords are all in the range [0,1] then we want to + clamp the coords to the edge otherwise it can pull in edge pixels + from the wrong side when scaled */ + if (in_tex_coords[0] >= 0 && in_tex_coords[0] <= 1.0 + && in_tex_coords[1] >= 0 && in_tex_coords[1] <= 1.0 + && in_tex_coords[2] >= 0 && in_tex_coords[2] <= 1.0 + && in_tex_coords[3] >= 0 && in_tex_coords[3] <= 1.0) + wrap_mode = GL_CLAMP_TO_EDGE; + else + wrap_mode = GL_REPEAT; + + _cogl_texture_set_wrap_mode_parameter (tex, wrap_mode); + } + else + { + out_tex_coords[0] = 0; /* tx1 */ + out_tex_coords[1] = 0; /* ty1 */ + out_tex_coords[2] = 1.0; /* tx2 */ + out_tex_coords[3] = 1.0; /* ty2 */ + + _cogl_texture_set_wrap_mode_parameter (tex, GL_CLAMP_TO_EDGE); + } + + /* Don't include the waste in the texture coordinates */ + x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0); + y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0); + + out_tex_coords[0] = + in_tex_coords[0] * (x_span->size - x_span->waste) / x_span->size; + out_tex_coords[1] = + in_tex_coords[1] * (x_span->size - x_span->waste) / x_span->size; + out_tex_coords[2] = + in_tex_coords[2] * (y_span->size - y_span->waste) / y_span->size; + out_tex_coords[3] = + in_tex_coords[3] * (y_span->size - y_span->waste) / y_span->size; + + /* Denormalize texture coordinates for rectangle textures */ + if (tex->gl_target == GL_TEXTURE_RECTANGLE_ARB) + { + out_tex_coords[0] *= x_span->size; + out_tex_coords[1] *= x_span->size; + out_tex_coords[2] *= y_span->size; + out_tex_coords[3] *= y_span->size; + } } - _cogl_texture_add_quad_vertices ( (x1), - (y1), - (x2), - (y2), - (tx1), - (ty1), - (tx2), - (ty2)); + _cogl_journal_log_quad (x1, + y1, + x2, + y2, + material, + n_layers, + fallback_mask, + 0, /* don't replace the layer0 texture */ + final_tex_coords, + n_layers * 4); + + return TRUE; } -void -cogl_texture_multiple_rectangles (CoglHandle handle, - const float *verts, - guint n_rects) +struct _CoglMutiTexturedRect { - CoglTexture *tex; - gulong enable_flags = (COGL_ENABLE_VERTEX_ARRAY - | COGL_ENABLE_TEXCOORD_ARRAY); + float x1; + float y1; + float x2; + float y2; + const float *tex_coords; + gint tex_coords_len; +}; + +static void +_cogl_rectangles_with_multitexture_coords ( + struct _CoglMutiTexturedRect *rects, + gint n_rects) +{ + CoglHandle material; + const GList *layers; + int n_layers; + const GList *tmp; + guint32 fallback_mask = 0; + gboolean all_use_sliced_quad_fallback = FALSE; + int i; _COGL_GET_CONTEXT (ctx, NO_RETVAL); - /* Check if valid texture */ - if (!cogl_is_texture (handle)) - return; - cogl_clip_ensure (); - tex = _cogl_texture_pointer_from_handle (handle); + material = ctx->source_material; - /* Make sure we got stuff to draw */ - if (tex->slice_gl_handles == NULL) - return; + layers = cogl_material_get_layers (material); + n_layers = g_list_length ((GList *)layers); - if (tex->slice_gl_handles->len == 0) - return; + /* + * Validate all the layers of the current source material... + */ - /* Prepare GL state */ - if (tex->gl_target == CGL_TEXTURE_RECTANGLE_ARB) - enable_flags |= COGL_ENABLE_TEXTURE_RECT; - else - enable_flags |= COGL_ENABLE_TEXTURE_2D; - - if (ctx->color_alpha < 255 - || tex->bitmap.format & COGL_A_BIT) - enable_flags |= COGL_ENABLE_BLEND; - - if (ctx->enable_backface_culling) - enable_flags |= COGL_ENABLE_BACKFACE_CULLING; - - cogl_enable (enable_flags); - - g_array_set_size (ctx->texture_vertices, 0); - - while (n_rects-- > 0) + for (tmp = layers, i = 0; tmp != NULL; tmp = tmp->next, i++) { - if (verts[4] != verts[6] && verts[5] != verts[7]) - { - /* If there is only one GL texture and either the texture is - NPOT (no waste) or all of the coordinates are in the - range [0,1] then we can use hardware tiling */ - if (tex->slice_gl_handles->len == 1 - && ((cogl_features_available (COGL_FEATURE_TEXTURE_NPOT) - && tex->gl_target == GL_TEXTURE_2D) - || (verts[4] >= 0 && verts[4] <= 1.0 - && verts[6] >= 0 && verts[6] <= 1.0 - && verts[5] >= 0 && verts[5] <= 1.0 - && verts[7] >= 0 && verts[7] <= 1.0))) - _cogl_texture_quad_hw (tex, verts[0],verts[1], verts[2],verts[3], - verts[4],verts[5], verts[6],verts[7]); - else - _cogl_texture_quad_sw (tex, verts[0],verts[1], verts[2],verts[3], - verts[4],verts[5], verts[6],verts[7]); - } + CoglHandle layer = tmp->data; + CoglHandle tex_handle = cogl_material_layer_get_texture (layer); + CoglTexture *texture = _cogl_texture_pointer_from_handle (tex_handle); + gulong flags; - verts += 8; + if (cogl_material_layer_get_type (layer) + != COGL_MATERIAL_LAYER_TYPE_TEXTURE) + continue; + + /* XXX: + * For now, if the first layer is sliced then all other layers are + * ignored since we currently don't support multi-texturing with + * sliced textures. If the first layer is not sliced then any other + * layers found to be sliced will be skipped. (with a warning) + * + * TODO: Add support for multi-texturing rectangles with sliced + * textures if no texture matrices are in use. + */ + if (cogl_texture_is_sliced (tex_handle)) + { + if (i == 0) + { + fallback_mask = ~1; /* fallback all except the first layer */ + all_use_sliced_quad_fallback = TRUE; + if (tmp->next) + { + g_warning ("Skipping layers 1..n of your material since the " + "first layer is sliced. We don't currently " + "support any multi-texturing with sliced " + "textures but assume layer 0 is the most " + "important to keep"); + } + break; + } + else + { + g_warning ("Skipping layer %d of your material consisting of a " + "sliced texture (unsuported for multi texturing)", + i); + + /* NB: marking for fallback will replace the layer with + * a default transparent texture */ + fallback_mask |= (1 << i); + continue; + } + } + + /* 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); + if (flags & COGL_MATERIAL_LAYER_FLAG_HAS_USER_MATRIX + && _cogl_texture_span_has_waste (texture, 0, 0)) + { + g_warning ("Skipping layer %d of your material consisting of a " + "texture with waste since you have supplied a custom " + "texture matrix and the result may try to sample from " + "the waste area of your texture.", i); + + /* NB: marking for fallback will replace the layer with + * a default transparent texture */ + fallback_mask |= (1 << i); + continue; + } } - _cogl_texture_flush_vertices (); + /* + * Emit geometry for each of the rectangles... + */ + + for (i = 0; i < n_rects; i++) + { + if (all_use_sliced_quad_fallback + || !_cogl_multitexture_unsliced_quad (rects[i].x1, rects[i].y1, + rects[i].x2, rects[i].y2, + material, + n_layers, + fallback_mask, + rects[i].tex_coords, + rects[i].tex_coords_len)) + { + const GList *layers; + CoglHandle tex_handle; + CoglTexture *texture; + + layers = cogl_material_get_layers (material); + tex_handle = + cogl_material_layer_get_texture ((CoglHandle)layers->data); + texture = _cogl_texture_pointer_from_handle (tex_handle); + _cogl_texture_sliced_quad (texture, + material, + rects[i].x1, rects[i].y1, + rects[i].x2, rects[i].y2, + rects[i].tex_coords[0], + rects[i].tex_coords[1], + rects[i].tex_coords[2], + rects[i].tex_coords[3]); + } + } + + _cogl_journal_flush (); } void -cogl_texture_rectangle (CoglHandle handle, - float x1, - float y1, - float x2, - float y2, - float tx1, - float ty1, - float tx2, - float ty2) +cogl_rectangles_with_texture_coords (const float *verts, + guint n_rects) +{ + struct _CoglMutiTexturedRect rects[n_rects]; + int i; + + for (i = 0; i < n_rects; i++) + { + rects[i].x1 = verts[i * 8]; + rects[i].y1 = verts[i * 8 + 1]; + rects[i].x2 = verts[i * 8 + 2]; + rects[i].y2 = verts[i * 8 + 3]; + /* FIXME: rect should be defined to have a const float *geom; + * instead, to avoid this copy + * rect[i].geom = &verts[n_rects * 8]; */ + rects[i].tex_coords = &verts[i * 8 + 4]; + rects[i].tex_coords_len = 4; + } + + _cogl_rectangles_with_multitexture_coords (rects, n_rects); +} + +void +cogl_rectangle_with_texture_coords (float x1, + float y1, + float x2, + float y2, + float tx1, + float ty1, + float tx2, + float ty2) { float verts[8]; @@ -2350,92 +2724,76 @@ cogl_texture_rectangle (CoglHandle handle, verts[6] = tx2; verts[7] = ty2; - cogl_texture_multiple_rectangles (handle, verts, 1); + cogl_rectangles_with_texture_coords (verts, 1); } void -cogl_texture_polygon (CoglHandle handle, - guint n_vertices, - CoglTextureVertex *vertices, - gboolean use_color) +cogl_rectangle_with_multitexture_coords (float x1, + float y1, + float x2, + float y2, + const float *user_tex_coords, + gint user_tex_coords_len) { - CoglTexture *tex; - int i, x, y, tex_num; - GLuint gl_handle; - CoglTexSliceSpan *y_span, *x_span; - gulong enable_flags; - CoglTextureGLVertex *p; + struct _CoglMutiTexturedRect rect; + + rect.x1 = x1; + rect.y1 = y1; + rect.x2 = x2; + rect.y2 = y2; + rect.tex_coords = user_tex_coords; + rect.tex_coords_len = user_tex_coords_len; + + _cogl_rectangles_with_multitexture_coords (&rect, 1); +} + +static void +_cogl_texture_sliced_polygon (CoglTextureVertex *vertices, + guint n_vertices, + guint stride, + gboolean use_color) +{ + const GList *layers; + CoglHandle layer0; + CoglHandle tex_handle; + CoglTexture *tex; + CoglTexSliceSpan *y_span, *x_span; + int x, y, tex_num, i; + GLuint gl_handle; + GLfloat *v; _COGL_GET_CONTEXT (ctx, NO_RETVAL); - /* Check if valid texture */ - if (!cogl_is_texture (handle)) - return; + /* We can assume in this case that we have at least one layer in the + * material that corresponds to a sliced cogl texture */ + layers = cogl_material_get_layers (ctx->source_material); + layer0 = (CoglHandle)layers->data; + tex_handle = cogl_material_layer_get_texture (layer0); + tex = _cogl_texture_pointer_from_handle (tex_handle); - cogl_clip_ensure (); - - tex = _cogl_texture_pointer_from_handle (handle); - - /* The polygon will have artifacts where the slices join if the wrap - mode is GL_LINEAR because the filtering will pull in pixels from - the transparent border. To make it clear that the function - shouldn't be used in these circumstances we just bail out and - draw nothing */ - if (tex->slice_gl_handles->len != 1 - && (tex->min_filter != GL_NEAREST || tex->mag_filter != GL_NEAREST)) + v = (GLfloat *)ctx->logged_vertices->data; + for (i = 0; i < n_vertices; i++) { - static gboolean shown_warning = FALSE; + GLfloat *c; - if (!shown_warning) - { - g_warning ("cogl_texture_polygon does not work for sliced textures " - "when the minification and magnification filters are not " - "CGL_NEAREST"); - shown_warning = TRUE; - } - return; + v[0] = vertices[i].x; + v[1] = vertices[i].y; + v[2] = vertices[i].z; + + /* NB: [X,Y,Z,TX,TY,R,G,B,A,...] */ + c = v + 5; + c[0] = cogl_color_get_red_byte (&vertices[i].color); + c[1] = cogl_color_get_green_byte (&vertices[i].color); + c[2] = cogl_color_get_blue_byte (&vertices[i].color); + c[3] = cogl_color_get_alpha_byte (&vertices[i].color); + + v += stride; } - /* Make sure there is enough space in the global texture vertex - array. This is used so we can render the polygon with a single - call to OpenGL but still support any number of vertices */ - g_array_set_size (ctx->texture_vertices, n_vertices); - p = (CoglTextureGLVertex *) ctx->texture_vertices->data; - - /* Prepare GL state */ - enable_flags = (COGL_ENABLE_VERTEX_ARRAY - | COGL_ENABLE_TEXCOORD_ARRAY - | COGL_ENABLE_BLEND); - - if (tex->gl_target == CGL_TEXTURE_RECTANGLE_ARB) - enable_flags |= COGL_ENABLE_TEXTURE_RECT; - else - enable_flags |= COGL_ENABLE_TEXTURE_2D; - - if (ctx->enable_backface_culling) - enable_flags |= COGL_ENABLE_BACKFACE_CULLING; - - if (use_color) - { - enable_flags |= COGL_ENABLE_COLOR_ARRAY; - GE( glColorPointer (4, GL_UNSIGNED_BYTE, - sizeof (CoglTextureGLVertex), p->c) ); - } - - GE( glVertexPointer (3, GL_FLOAT, sizeof (CoglTextureGLVertex), p->v ) ); - GE( glTexCoordPointer (2, GL_FLOAT, sizeof (CoglTextureGLVertex), p->t ) ); - - cogl_enable (enable_flags); - - /* Temporarily change the wrapping mode on all of the slices to use - a transparent border */ - _cogl_texture_set_wrap_mode_parameter (tex, GL_CLAMP_TO_BORDER); - - tex_num = 0; - /* Render all of the slices with the full geometry but use a transparent border color so that any part of the texture not covered by the slice will be ignored */ + tex_num = 0; for (y = 0; y < tex->slice_y_spans->len; y++) { y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, y); @@ -2446,15 +2804,13 @@ cogl_texture_polygon (CoglHandle handle, gl_handle = g_array_index (tex->slice_gl_handles, GLuint, tex_num++); - p = (CoglTextureGLVertex *) ctx->texture_vertices->data; - /* Convert the vertices into an array of GLfloats ready to pass to OpenGL */ - for (i = 0; i < n_vertices; i++, p++) + v = (GLfloat *)ctx->logged_vertices->data; + for (i = 0; i < n_vertices; i++) { - float tx, ty; - -#define CFX_F + GLfloat *t; + float tx, ty; tx = ((vertices[i].tx - ((float)(x_span->start) @@ -2472,250 +2828,248 @@ cogl_texture_polygon (CoglHandle handle, ty *= y_span->size; } - p->v[0] = CFX_F(vertices[i].x); - p->v[1] = CFX_F(vertices[i].y); - p->v[2] = CFX_F(vertices[i].z); - p->t[0] = CFX_F(tx); - p->t[1] = CFX_F(ty); - p->c[0] = cogl_color_get_red_byte(&vertices[i].color); - p->c[1] = cogl_color_get_green_byte(&vertices[i].color); - p->c[2] = cogl_color_get_blue_byte(&vertices[i].color); - p->c[3] = cogl_color_get_alpha_byte(&vertices[i].color); + /* NB: [X,Y,Z,TX,TY,R,G,B,A,...] */ + t = v + 3; + t[0] = tx; + t[1] = ty; -#undef CFX_F + v += stride; } - GE( glBindTexture (tex->gl_target, gl_handle) ); + 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); GE( glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices) ); } } } -void -cogl_material_rectangle (CoglFixed x1, - CoglFixed y1, - CoglFixed x2, - CoglFixed y2, - gint user_tex_coords_len, - const CoglFixed *user_tex_coords) -{ - CoglHandle material; - const GList *layers; - int n_layers; - const GList *tmp; - CoglHandle *valid_layers = NULL; - int n_valid_layers = 0; - gboolean handle_slicing = FALSE; - int i; - GLfloat *tex_coords_buff; - GLfloat quad_coords[8]; - gulong enable_flags = 0; - /* FIXME - currently cogl deals with enabling texturing via enable flags, - * but that can't scale to n texture units. Currently we have to be carefull - * how we leave the environment so we don't break things. See the cleanup - * notes at the end of this function */ +static void +_cogl_multitexture_unsliced_polygon (CoglTextureVertex *vertices, + guint n_vertices, + guint n_layers, + guint stride, + gboolean use_color, + guint32 fallback_mask) +{ + CoglHandle material; + const GList *layers; + int i; + GList *tmp; + CoglTexSliceSpan *y_span, *x_span; + GLfloat *v; _COGL_GET_CONTEXT (ctx, NO_RETVAL); + material = ctx->source_material; - layers = cogl_material_get_layers (material); - n_layers = g_list_length ((GList *)layers); - valid_layers = alloca (sizeof (CoglHandle) * n_layers); - for (tmp = layers; tmp != NULL; tmp = tmp->next) + /* Convert the vertices into an array of GLfloats ready to pass to + OpenGL */ + for (v = (GLfloat *)ctx->logged_vertices->data, i = 0; + i < n_vertices; + v += stride, i++) { - CoglHandle layer = tmp->data; - CoglHandle texture = cogl_material_layer_get_texture (layer); + GLfloat *c; + int j; - if (cogl_material_layer_get_type (layer) - != COGL_MATERIAL_LAYER_TYPE_TEXTURE) - continue; + /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ + v[0] = vertices[i].x; + v[1] = vertices[i].y; + v[2] = vertices[i].z; - /* FIXME: support sliced textures. For now if the first layer is - * sliced then all other layers are ignored, or if the first layer - * is not sliced, we ignore sliced textures in other layers. */ - if (cogl_texture_is_sliced (texture)) - { - if (n_valid_layers == 0) - { - valid_layers[n_valid_layers++] = layer; - handle_slicing = TRUE; - break; - } - continue; - } - valid_layers[n_valid_layers++] = tmp->data; - - if (n_valid_layers >= CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS) - break; - } - - /* We at least support slicing as much as cogl_texture_rectangle... */ - if (n_valid_layers == 1 && handle_slicing) - { - CoglHandle texture = cogl_material_layer_get_texture (valid_layers[0]); - cogl_texture_rectangle (texture, - x1, y1, x2, y2, - user_tex_coords[0], user_tex_coords[1], - user_tex_coords[2], user_tex_coords[3]); - return; - } - - /* NB: It could be that no valid texture layers were found, but - * we will still submit a non-textured rectangle in that case. */ - if (n_valid_layers) - tex_coords_buff = alloca (sizeof(GLfloat) * 8 * n_valid_layers); - - for (i = 0; i < n_valid_layers; i++) - { - CoglHandle layer = valid_layers[i]; - CoglHandle texture = cogl_material_layer_get_texture (layer); - const CoglFixed *in_tex_coords; - GLfloat *out_tex_coords = &tex_coords_buff[i * 8]; - GLuint gl_tex_handle; - -#define CFX_F COGL_FIXED_TO_FLOAT - /* IN LAYOUT: [ tx1:0, ty1:1, tx2:2, ty2:3 ] */ - if (i < (user_tex_coords_len / 4)) + for (tmp = (GList *)layers, j = 0; tmp != NULL; tmp = tmp->next, j++) { - in_tex_coords = &user_tex_coords[i * 4]; - /* FIXME: don't include waste in the texture coordinates */ - out_tex_coords[0] = CFX_F (in_tex_coords[0]); /* tx1 */ - out_tex_coords[1] = CFX_F (in_tex_coords[1]); /* ty1 */ - out_tex_coords[2] = CFX_F (in_tex_coords[2]); /* tx2 */ - out_tex_coords[3] = CFX_F (in_tex_coords[1]); /* ty1 */ - out_tex_coords[4] = CFX_F (in_tex_coords[0]); /* tx1 */ - out_tex_coords[5] = CFX_F (in_tex_coords[3]); /* ty2 */ - out_tex_coords[6] = CFX_F (in_tex_coords[2]); /* tx2 */ - out_tex_coords[7] = CFX_F (in_tex_coords[3]); /* ty2 */ - } - else - { - out_tex_coords[0] = 0.0; /* tx1 */ - out_tex_coords[1] = 0.0; /* ty1 */ - out_tex_coords[2] = 1.0; /* tx2 */ - out_tex_coords[3] = 0.0; /* ty1 */ - out_tex_coords[4] = 0.0; /* tx1 */ - out_tex_coords[5] = 1.0; /* ty2 */ - out_tex_coords[6] = 1.0; /* tx2 */ - out_tex_coords[7] = 1.0; /* ty2 */ - } -#undef CFX_F + CoglHandle layer = (CoglHandle)tmp->data; + CoglHandle tex_handle; + CoglTexture *tex; + GLfloat *t; + float tx, ty; - /* TODO - support sliced textures */ - cogl_texture_get_gl_texture (texture, &gl_tex_handle, NULL); + tex_handle = cogl_material_layer_get_texture (layer); + tex = _cogl_texture_pointer_from_handle (tex_handle); - GE (glActiveTexture (GL_TEXTURE0 + i)); - cogl_material_layer_flush_gl_sampler_state (layer); - { - /* FIXME - we should avoid redundant calls to glBindTexture. - * Profiling test-actors, I've seen ~ 10% of the time spent in - * _mesa_UpdateTexEnvProgram, which the following simple test can - * show is as a result of these redundant glBindTexture calls. - */ -#if 0 - static int debug = 0; - if (!debug) - GE (glBindTexture (GL_TEXTURE_2D, gl_tex_handle)); - debug = 1; -#else - GE (glBindTexture (GL_TEXTURE_2D, gl_tex_handle)); -#endif + y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0); + x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0); + + tx = ((vertices[i].tx + - ((float)(x_span->start) + / tex->bitmap.width)) + * tex->bitmap.width / x_span->size); + ty = ((vertices[i].ty + - ((float)(y_span->start) + / tex->bitmap.height)) + * tex->bitmap.height / y_span->size); + + /* Scale the coordinates up for rectangle textures */ + if (tex->gl_target == CGL_TEXTURE_RECTANGLE_ARB) + { + tx *= x_span->size; + ty *= y_span->size; + } + + /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ + t = v + 3 + 2 * j; + t[0] = tx; + t[1] = ty; } - GE (glClientActiveTexture (GL_TEXTURE0 + i)); - GE (glTexCoordPointer (2, GL_FLOAT, 0, out_tex_coords)); - - /* FIXME - cogl only knows about one texture unit a.t.m - * (Also see cleanup note below) */ - if (i == 0) - enable_flags |= COGL_ENABLE_TEXTURE_2D | COGL_ENABLE_TEXCOORD_ARRAY; - else - { - GE (glEnable (GL_TEXTURE_2D)); - GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY)); - } + /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ + c = v + 3 + 2 * n_layers; + c[0] = cogl_color_get_red_float (&vertices[i].color); + c[1] = cogl_color_get_green_float (&vertices[i].color); + c[2] = cogl_color_get_blue_float (&vertices[i].color); + c[3] = cogl_color_get_alpha_float (&vertices[i].color); } -#define CFX_F COGL_FIXED_TO_FLOAT - quad_coords[0] = CFX_F (x1); - quad_coords[1] = CFX_F (y1); - quad_coords[2] = CFX_F (x2); - quad_coords[3] = CFX_F (y1); - quad_coords[4] = CFX_F (x1); - quad_coords[5] = CFX_F (y2); - quad_coords[6] = CFX_F (x2); - quad_coords[7] = CFX_F (y2); -#undef CFX_F + cogl_material_flush_gl_state (ctx->source_material, + COGL_MATERIAL_FLUSH_FALLBACK_MASK, + fallback_mask, + NULL); - enable_flags |= COGL_ENABLE_VERTEX_ARRAY; - GE( glVertexPointer (2, GL_FLOAT, 0, quad_coords)); - - /* Setup the remaining GL state according to this material... */ - cogl_flush_material_gl_state (); - - /* FIXME: This api is a bit yukky, ideally it will be removed if we - * re-work the cogl_enable mechanism */ - enable_flags |= cogl_material_get_cogl_enable_flags (material); - - /* FIXME - cogl only knows about one texture unit so assumes that unit 0 - * is always active... */ - if (n_valid_layers > 1) - { - GE (glActiveTexture (GL_TEXTURE0)); - GE (glClientActiveTexture (GL_TEXTURE0)); - } - cogl_enable (enable_flags); - glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); - - /* FIXME - cogl doesn't currently have a way of caching the - * enable states for more than one texture unit so for now, - * we just disable anything relating to additional units once - * we are done with them. */ - for (i = 1; i < n_valid_layers; i++) - { - GE (glActiveTexture (GL_TEXTURE0 + i)); - GE (glDisable (GL_TEXTURE_2D)); - } - - /* The rest of Cogl expects the texture mode to be GL_MODULATE so we - need to restore that */ - GE( glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE) ); - - /* XXX: a bit over precautious. For one we don't support lighting yet - * so there's no real need to reset the material properties. */ -#if 0 - /* FIXME - cogl doesn't currently have a way of caching the - * enable states for more than one texture unit so for now, - * we just disable anything relating to additional units once - * we are done with them. */ - for (i = 1; i < n_valid_layers; i++) - { - GE (glActiveTexture (GL_TEXTURE0 + i)); - GE (glClientActiveTexture (GL_TEXTURE0 + i)); - - GE (glDisable (GL_TEXTURE_2D)); - GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY)); - } - - /* FIXME - CoglMaterials aren't yet used pervasively throughout - * the cogl API, so we currently need to cleanup material state - * that will confuse other parts of the API. - * Other places to tweak, include the primitives API and lite - * GL wrappers like cogl_rectangle */ - values[0] = 0.2; values[1] = 0.2; values[2] = 0.2; values[3] = 1.0; - GE (glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, values)); - values[0] = 0.8; values[1] = 0.8; values[2] = 0.8; values[3] = 1.0; - GE (glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, values)); - values[0] = 0; values[1] = 0; values[2] = 0; values[3] = 1.0; - GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, values)); - values[0] = 0; values[1] = 0; values[2] = 0; values[3] = 1.0; - GE (glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, values)); - values[0] = 0; - GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS, values)); -#endif + GE (glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices)); +} + +void +cogl_polygon (CoglTextureVertex *vertices, + guint n_vertices, + gboolean use_color) +{ + CoglHandle material; + const GList *layers; + int n_layers; + GList *tmp; + gboolean use_sliced_polygon_fallback = FALSE; + guint32 fallback_mask = 0; + int i; + gulong enable_flags; + guint stride; + gsize stride_bytes; + GLfloat *v; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + cogl_clip_ensure (); + + material = ctx->source_material; + layers = cogl_material_get_layers (ctx->source_material); + n_layers = g_list_length ((GList *)layers); + + for (tmp = (GList *)layers, i = 0; tmp != NULL; tmp = tmp->next, i++) + { + 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)) + { + if (n_layers > 1) + { + static gboolean shown_slicing_warning = FALSE; + if (!shown_slicing_warning) + { + g_warning ("Disabling layers 1..n since multi-texturing with " + "cogl_polygon isn't supported when using sliced " + "textures\n"); + shown_slicing_warning = TRUE; + } + } + use_sliced_polygon_fallback = TRUE; + n_layers = 1; + + if (tex->min_filter != GL_NEAREST || tex->mag_filter != GL_NEAREST) + { + static gboolean shown_filter_warning = FALSE; + if (!shown_filter_warning) + { + g_warning ("cogl_texture_polygon does not work for sliced textures " + "when the minification and magnification filters are not " + "CGL_NEAREST"); + shown_filter_warning = TRUE; + } + return; + } + + /* 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); + + break; + } + + if (cogl_texture_is_sliced (tex_handle)) + { + g_warning ("Disabling layer %d of the current source material, " + "because texturing with the vertex buffer API is not " + "currently supported using sliced textures, or textures " + "with waste\n", i); + + fallback_mask |= (1 << i); + continue; + } + } + + /* Our data is arranged like: + * [X, Y, Z, TX0, TY0, TX1, TY1..., R, G, B, A,...] */ + stride = 3 + (2 * n_layers) + (use_color ? 4 : 0); + stride_bytes = stride * sizeof (GLfloat); + + /* Make sure there is enough space in the global vertex + array. This is used so we can render the polygon with a single + call to OpenGL but still support any number of vertices */ + g_array_set_size (ctx->logged_vertices, n_vertices * stride); + v = (GLfloat *)ctx->logged_vertices->data; + + /* Prepare GL state */ + enable_flags = COGL_ENABLE_VERTEX_ARRAY; + enable_flags |= cogl_material_get_cogl_enable_flags (ctx->source_material); + + if (ctx->enable_backface_culling) + enable_flags |= COGL_ENABLE_BACKFACE_CULLING; + + if (use_color) + { + enable_flags |= COGL_ENABLE_COLOR_ARRAY; + GE( glColorPointer (4, GL_FLOAT, + stride_bytes, + /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ + v + 3 + 2 * n_layers) ); + } + + cogl_enable (enable_flags); + + GE (glVertexPointer (3, GL_FLOAT, stride_bytes, v)); + + for (i = 0; i < n_layers; i++) + { + GE (glClientActiveTexture (GL_TEXTURE0 + i)); + GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY)); + GE (glTexCoordPointer (2, GL_FLOAT, + stride_bytes, + /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ + v + 3 + 2 * i)); + } + + if (use_sliced_polygon_fallback) + _cogl_texture_sliced_polygon (vertices, + n_vertices, + stride, + use_color); + else + _cogl_multitexture_unsliced_polygon (vertices, + n_vertices, + n_layers, + stride, + use_color, + fallback_mask); } diff --git a/gl/cogl.c b/gl/cogl.c index 78b2a908c..3568493b9 100644 --- a/gl/cogl.c +++ b/gl/cogl.c @@ -180,16 +180,16 @@ cogl_paint_init (const CoglColor *color) glDisable (GL_LIGHTING); glDisable (GL_FOG); - /* + /* * Disable the depth test for now as has some strange side effects, - * mainly on x/y axis rotation with multiple layers at same depth - * (eg rotating text on a bg has very strange effect). Seems no clean - * 100% effective way to fix without other odd issues.. So for now + * mainly on x/y axis rotation with multiple layers at same depth + * (eg rotating text on a bg has very strange effect). Seems no clean + * 100% effective way to fix without other odd issues.. So for now * move to application to handle and add cogl_enable_depth_test() * as for custom actors (i.e groups) to enable if need be. * - * glEnable (GL_DEPTH_TEST); - * glEnable (GL_ALPHA_TEST) + * glEnable (GL_DEPTH_TEST); + * glEnable (GL_ALPHA_TEST) * glDepthFunc (GL_LEQUAL); * glAlphaFunc (GL_GREATER, 0.1); */ @@ -251,7 +251,7 @@ cogl_toggle_flag (CoglContext *ctx, GE( glDisable (gl_flag) ); ctx->enable_flags &= ~flag; } - + return FALSE; } @@ -278,7 +278,7 @@ cogl_toggle_client_flag (CoglContext *ctx, GE( glDisableClientState (gl_flag) ); ctx->enable_flags &= ~flag; } - + return FALSE; } @@ -289,33 +289,19 @@ cogl_enable (gulong flags) * hope of lessening number GL traffic. */ _COGL_GET_CONTEXT (ctx, NO_RETVAL); - + cogl_toggle_flag (ctx, flags, COGL_ENABLE_BLEND, GL_BLEND); - - cogl_toggle_flag (ctx, flags, - COGL_ENABLE_TEXTURE_2D, - GL_TEXTURE_2D); cogl_toggle_flag (ctx, flags, COGL_ENABLE_BACKFACE_CULLING, GL_CULL_FACE); -#ifdef GL_TEXTURE_RECTANGLE_ARB - cogl_toggle_flag (ctx, flags, - COGL_ENABLE_TEXTURE_RECT, - GL_TEXTURE_RECTANGLE_ARB); -#endif - cogl_toggle_client_flag (ctx, flags, COGL_ENABLE_VERTEX_ARRAY, GL_VERTEX_ARRAY); - - cogl_toggle_client_flag (ctx, flags, - COGL_ENABLE_TEXCOORD_ARRAY, - GL_TEXTURE_COORD_ARRAY); - + cogl_toggle_client_flag (ctx, flags, COGL_ENABLE_COLOR_ARRAY, GL_COLOR_ARRAY); @@ -325,7 +311,7 @@ gulong cogl_get_enable () { _COGL_GET_CONTEXT (ctx, 0); - + return ctx->enable_flags; } @@ -336,7 +322,7 @@ cogl_blend_func (COGLenum src_factor, COGLenum dst_factor) * hope of lessening GL traffic. */ _COGL_GET_CONTEXT (ctx, NO_RETVAL); - + if (ctx->blend_src_factor != src_factor || ctx->blend_dst_factor != dst_factor) { @@ -351,14 +337,14 @@ cogl_enable_depth_test (gboolean setting) { if (setting) { - glEnable (GL_DEPTH_TEST); + glEnable (GL_DEPTH_TEST); glEnable (GL_ALPHA_TEST); glDepthFunc (GL_LEQUAL); glAlphaFunc (GL_GREATER, 0.1); } else { - glDisable (GL_DEPTH_TEST); + glDisable (GL_DEPTH_TEST); glDisable (GL_ALPHA_TEST); } } @@ -375,14 +361,12 @@ void cogl_set_source_color (const CoglColor *color) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - glColor4ub (cogl_color_get_red_byte (color), - cogl_color_get_green_byte (color), - cogl_color_get_blue_byte (color), - cogl_color_get_alpha_byte (color)); - - /* Store alpha for proper blending enables */ - ctx->color_alpha = cogl_color_get_alpha_byte (color); + + /* In case cogl_set_source_texture was previously used... */ + cogl_material_remove_layer (ctx->default_material, 0); + + cogl_material_set_color (ctx->default_material, color); + cogl_set_source (ctx->default_material); } static void @@ -512,7 +496,7 @@ _cogl_add_stencil_clip (float x_offset, if (first) { GE( glEnable (GL_STENCIL_TEST) ); - + /* Initially disallow everything */ GE( glClearStencil (0) ); GE( glClear (GL_STENCIL_BUFFER_BIT) ); @@ -815,7 +799,7 @@ _cogl_features_init () GLint num_stencil_bits = 0; _COGL_GET_CONTEXT (ctx, NO_RETVAL); - + flags = COGL_FEATURE_TEXTURE_READ_PIXELS; gl_extensions = (const gchar*) glGetString (GL_EXTENSIONS); @@ -827,7 +811,7 @@ _cogl_features_init () #endif flags |= COGL_FEATURE_TEXTURE_NPOT; } - + #ifdef GL_YCBCR_MESA if (cogl_check_extension ("GL_MESA_ycbcr_texture", gl_extensions)) { @@ -842,47 +826,47 @@ _cogl_features_init () ctx->pf_glCreateProgramObjectARB = (COGL_PFNGLCREATEPROGRAMOBJECTARBPROC) cogl_get_proc_address ("glCreateProgramObjectARB"); - + ctx->pf_glCreateShaderObjectARB = (COGL_PFNGLCREATESHADEROBJECTARBPROC) cogl_get_proc_address ("glCreateShaderObjectARB"); - + ctx->pf_glShaderSourceARB = (COGL_PFNGLSHADERSOURCEARBPROC) cogl_get_proc_address ("glShaderSourceARB"); - + ctx->pf_glCompileShaderARB = (COGL_PFNGLCOMPILESHADERARBPROC) cogl_get_proc_address ("glCompileShaderARB"); - + ctx->pf_glAttachObjectARB = (COGL_PFNGLATTACHOBJECTARBPROC) cogl_get_proc_address ("glAttachObjectARB"); - + ctx->pf_glLinkProgramARB = (COGL_PFNGLLINKPROGRAMARBPROC) cogl_get_proc_address ("glLinkProgramARB"); - + ctx->pf_glUseProgramObjectARB = (COGL_PFNGLUSEPROGRAMOBJECTARBPROC) cogl_get_proc_address ("glUseProgramObjectARB"); - + ctx->pf_glGetUniformLocationARB = (COGL_PFNGLGETUNIFORMLOCATIONARBPROC) cogl_get_proc_address ("glGetUniformLocationARB"); - + ctx->pf_glDeleteObjectARB = (COGL_PFNGLDELETEOBJECTARBPROC) cogl_get_proc_address ("glDeleteObjectARB"); - + ctx->pf_glGetInfoLogARB = (COGL_PFNGLGETINFOLOGARBPROC) cogl_get_proc_address ("glGetInfoLogARB"); - + ctx->pf_glGetObjectParameterivARB = (COGL_PFNGLGETOBJECTPARAMETERIVARBPROC) cogl_get_proc_address ("glGetObjectParameterivARB"); - + ctx->pf_glUniform1fARB = (COGL_PFNGLUNIFORM1FARBPROC) cogl_get_proc_address ("glUniform1fARB"); @@ -898,7 +882,7 @@ _cogl_features_init () ctx->pf_glDisableVertexAttribArrayARB = (COGL_PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) cogl_get_proc_address ("glDisableVertexAttribArrayARB"); - + ctx->pf_glUniform2fARB = (COGL_PFNGLUNIFORM2FARBPROC) cogl_get_proc_address ("glUniform2fARB"); @@ -962,7 +946,7 @@ _cogl_features_init () ctx->pf_glUniformMatrix2fvARB = (COGL_PFNGLUNIFORMMATRIX2FVARBPROC) cogl_get_proc_address ("glUniformMatrix2fvARB"); - + ctx->pf_glUniformMatrix3fvARB = (COGL_PFNGLUNIFORMMATRIX3FVARBPROC) cogl_get_proc_address ("glUniformMatrix3fvARB"); @@ -1006,50 +990,50 @@ _cogl_features_init () ctx->pf_glDisableVertexAttribArrayARB) flags |= COGL_FEATURE_SHADERS_GLSL; } - + if (cogl_check_extension ("GL_EXT_framebuffer_object", gl_extensions) || cogl_check_extension ("GL_ARB_framebuffer_object", gl_extensions)) - { + { ctx->pf_glGenRenderbuffersEXT = (COGL_PFNGLGENRENDERBUFFERSEXTPROC) cogl_get_proc_address ("glGenRenderbuffersEXT"); - + ctx->pf_glDeleteRenderbuffersEXT = (COGL_PFNGLDELETERENDERBUFFERSEXTPROC) cogl_get_proc_address ("glDeleteRenderbuffersEXT"); - + ctx->pf_glBindRenderbufferEXT = (COGL_PFNGLBINDRENDERBUFFEREXTPROC) cogl_get_proc_address ("glBindRenderbufferEXT"); - + ctx->pf_glRenderbufferStorageEXT = (COGL_PFNGLRENDERBUFFERSTORAGEEXTPROC) cogl_get_proc_address ("glRenderbufferStorageEXT"); - + ctx->pf_glGenFramebuffersEXT = (COGL_PFNGLGENFRAMEBUFFERSEXTPROC) cogl_get_proc_address ("glGenFramebuffersEXT"); - + ctx->pf_glBindFramebufferEXT = (COGL_PFNGLBINDFRAMEBUFFEREXTPROC) cogl_get_proc_address ("glBindFramebufferEXT"); - + ctx->pf_glFramebufferTexture2DEXT = (COGL_PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) cogl_get_proc_address ("glFramebufferTexture2DEXT"); - + ctx->pf_glFramebufferRenderbufferEXT = (COGL_PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) cogl_get_proc_address ("glFramebufferRenderbufferEXT"); - + ctx->pf_glCheckFramebufferStatusEXT = (COGL_PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) cogl_get_proc_address ("glCheckFramebufferStatusEXT"); - + ctx->pf_glDeleteFramebuffersEXT = (COGL_PFNGLDELETEFRAMEBUFFERSEXTPROC) cogl_get_proc_address ("glDeleteFramebuffersEXT"); - + if (ctx->pf_glGenRenderbuffersEXT && ctx->pf_glBindRenderbufferEXT && ctx->pf_glRenderbufferStorageEXT && @@ -1061,23 +1045,23 @@ _cogl_features_init () ctx->pf_glDeleteFramebuffersEXT) flags |= COGL_FEATURE_OFFSCREEN; } - + if (cogl_check_extension ("GL_EXT_framebuffer_blit", gl_extensions)) { ctx->pf_glBlitFramebufferEXT = (COGL_PFNGLBLITFRAMEBUFFEREXTPROC) cogl_get_proc_address ("glBlitFramebufferEXT"); - + if (ctx->pf_glBlitFramebufferEXT) flags |= COGL_FEATURE_OFFSCREEN_BLIT; } - + if (cogl_check_extension ("GL_EXT_framebuffer_multisample", gl_extensions)) { ctx->pf_glRenderbufferStorageMultisampleEXT = (COGL_PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) cogl_get_proc_address ("glRenderbufferStorageMultisampleEXT"); - + if (ctx->pf_glRenderbufferStorageMultisampleEXT) flags |= COGL_FEATURE_OFFSCREEN_MULTISAMPLE; } @@ -1140,10 +1124,10 @@ CoglFeatureFlags cogl_get_features () { _COGL_GET_CONTEXT (ctx, 0); - + if (!ctx->features_cached) _cogl_features_init (); - + return ctx->feature_flags; } @@ -1151,10 +1135,10 @@ gboolean cogl_features_available (CoglFeatureFlags features) { _COGL_GET_CONTEXT (ctx, 0); - + if (!ctx->features_cached) _cogl_features_init (); - + return (ctx->feature_flags & features) == features; } From 94077997a767de39fc9b2bc088e27054a5d73c4a Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Sat, 24 Jan 2009 15:09:43 +0000 Subject: [PATCH 14/16] Removes cogl_blend_func and cogl_alpha_func The GL blend function and alpha function are now controlled by the material code, and even internally Cogl should now be using the material API when it needs control of these. --- cogl.h.in | 13 ------------- common/cogl-material.c | 8 ++++++++ gl/cogl-context.c | 3 --- gl/cogl-context.h | 2 -- gl/cogl.c | 24 ------------------------ gles/cogl.c | 24 ------------------------ 6 files changed, 8 insertions(+), 66 deletions(-) diff --git a/cogl.h.in b/cogl.h.in index e0cf44a82..ff35f33d6 100644 --- a/cogl.h.in +++ b/cogl.h.in @@ -405,19 +405,6 @@ void cogl_enable_depth_test (gboolean setting); */ void cogl_enable_backface_culling (gboolean setting); -/** - * cogl_alpha_func: - * @func: the comparison function to use, one of CGL_NEVER, CGL_LESS, - * CGL_EQUAL, CGL_LEQUAL, CGL_GREATER, CGL_NOTEQUAL, CGL_GEQUAL and GL_ALWAYS. - * @ref: reference value. - * - * Changes the alpha test to use the specified function specified in @func, - * comparing with the value in @ref. The default function is CGL_ALWAYS the - * initial reference value is 1.0. - */ -void cogl_alpha_func (COGLenum func, - float ref); - /** * cogl_fog_set: * @fog_color: The color of the fog diff --git a/common/cogl-material.c b/common/cogl-material.c index 0b4b9dc6b..5b3c7490e 100644 --- a/common/cogl-material.c +++ b/common/cogl-material.c @@ -13,6 +13,14 @@ #include #include +/* + * GL/GLES compatability defines for material thingies: + */ + +#ifdef HAVE_COGL_GLES2 +#define glAlphaFunc cogl_wrap_glAlphaFunc +#endif + static void _cogl_material_free (CoglMaterial *tex); static void _cogl_material_layer_free (CoglMaterialLayer *layer); diff --git a/gl/cogl-context.c b/gl/cogl-context.c index 6a3c032e4..252f3d294 100644 --- a/gl/cogl-context.c +++ b/gl/cogl-context.c @@ -81,9 +81,6 @@ cogl_create_context () _context->fbo_handles = NULL; _context->draw_buffer = COGL_WINDOW_BUFFER; - _context->blend_src_factor = CGL_SRC_ALPHA; - _context->blend_dst_factor = CGL_ONE_MINUS_SRC_ALPHA; - _context->shader_handles = NULL; _context->program_handles = NULL; diff --git a/gl/cogl-context.h b/gl/cogl-context.h index db3a333a1..2f0dd0817 100644 --- a/gl/cogl-context.h +++ b/gl/cogl-context.h @@ -45,8 +45,6 @@ typedef struct /* Enable cache */ gulong enable_flags; guint8 color_alpha; - COGLenum blend_src_factor; - COGLenum blend_dst_factor; gboolean enable_backface_culling; diff --git a/gl/cogl.c b/gl/cogl.c index 3568493b9..47358502d 100644 --- a/gl/cogl.c +++ b/gl/cogl.c @@ -315,23 +315,6 @@ cogl_get_enable () return ctx->enable_flags; } -void -cogl_blend_func (COGLenum src_factor, COGLenum dst_factor) -{ - /* This function caches the blending setup in the - * hope of lessening GL traffic. - */ - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - if (ctx->blend_src_factor != src_factor || - ctx->blend_dst_factor != dst_factor) - { - glBlendFunc (src_factor, dst_factor); - ctx->blend_src_factor = src_factor; - ctx->blend_dst_factor = dst_factor; - } -} - void cogl_enable_depth_test (gboolean setting) { @@ -577,13 +560,6 @@ _cogl_disable_clip_planes (void) GE( glDisable (GL_CLIP_PLANE0) ); } -void -cogl_alpha_func (COGLenum func, - float ref) -{ - GE( glAlphaFunc (func, (ref)) ); -} - void cogl_perspective (float fovy, float aspect, diff --git a/gles/cogl.c b/gles/cogl.c index 717b1e13f..373072d28 100644 --- a/gles/cogl.c +++ b/gles/cogl.c @@ -229,23 +229,6 @@ cogl_get_enable () return ctx->enable_flags; } -void -cogl_blend_func (COGLenum src_factor, COGLenum dst_factor) -{ - /* This function caches the blending setup in the - * hope of lessening GL traffic. - */ - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - if (ctx->blend_src_factor != src_factor || - ctx->blend_dst_factor != dst_factor) - { - glBlendFunc (src_factor, dst_factor); - ctx->blend_src_factor = src_factor; - ctx->blend_dst_factor = dst_factor; - } -} - void cogl_enable_depth_test (gboolean setting) { @@ -498,13 +481,6 @@ _cogl_disable_clip_planes (void) GE( cogl_wrap_glDisable (GL_CLIP_PLANE0) ); } -void -cogl_alpha_func (COGLenum func, - float ref) -{ - GE( cogl_wrap_glAlphaFunc (func, (ref)) ); -} - /* * Fixed point implementation of the perspective function */ From e9a9acd28db9331e4b02c4a3721e9e80756b7076 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Sat, 24 Jan 2009 16:55:04 +0000 Subject: [PATCH 15/16] Normalizes gl vs gles code in preperation for synching material changes This changes all GLES code to use the OpenGL function names instead of the cogl_wrap_* names. For GLES2 we now define the OpenGL name to point to the wrapper, as opposed to defining the wrapper to point to the OpenGL name for GLES1. I've also done a quick pass through gl/cogl.c and gles/cogl.c to make them more easily comparable. (most of the code is now identical) --- gl/cogl-primitives.c | 43 ++- gl/cogl.c | 144 +++++----- gles/cogl-context.c | 2 +- gles/cogl-fbo.c | 32 +-- gles/cogl-primitives.c | 34 +-- gles/cogl-texture.c | 585 ++++++++++++++++++++--------------------- gles/cogl.c | 286 +++++++++++--------- 7 files changed, 561 insertions(+), 565 deletions(-) diff --git a/gl/cogl-primitives.c b/gl/cogl-primitives.c index 6c00ed193..ddb3bcc5e 100644 --- a/gl/cogl-primitives.c +++ b/gl/cogl-primitives.c @@ -47,8 +47,8 @@ _cogl_path_add_node (gboolean new_sub_path, _COGL_GET_CONTEXT (ctx, NO_RETVAL); - new_node.x = (x); - new_node.y = (y); + new_node.x = x; + new_node.y = y; new_node.path_size = 0; if (new_sub_path || ctx->path_nodes->len == 0) @@ -123,15 +123,23 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, CoglPathNode *path, gboolean merge) { - guint path_start = 0; - guint sub_path_num = 0; - float bounds_x; - float bounds_y; - float bounds_w; - float bounds_h; + guint path_start = 0; + guint sub_path_num = 0; + float bounds_x; + float bounds_y; + float bounds_w; + float bounds_h; + gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY; _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); + + enable_flags |= + cogl_material_get_cogl_enable_flags (ctx->source_material); + cogl_enable (enable_flags); + _cogl_path_get_bounds (nodes_min, nodes_max, &bounds_x, &bounds_y, &bounds_w, &bounds_h); @@ -155,15 +163,6 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, while (path_start < path_size) { - gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY; - - /* Just setup a simple material that doesn't use texturing... */ - cogl_material_flush_gl_state (ctx->stencil_material, NULL); - - enable_flags |= - cogl_material_get_cogl_enable_flags (ctx->source_material); - cogl_enable (enable_flags); - GE( glVertexPointer (2, GL_FLOAT, sizeof (CoglPathNode), (guchar *) path + G_STRUCT_OFFSET (CoglPathNode, x)) ); @@ -201,8 +200,8 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, GE( glMatrixMode (GL_PROJECTION) ); GE( glPushMatrix () ); GE( glLoadIdentity () ); - GE( glRecti (-1, 1, 1, -1) ); - GE( glRecti (-1, 1, 1, -1) ); + cogl_rectangle (-1.0, -1.0, 2, 2); + cogl_rectangle (-1.0, -1.0, 2, 2); GE( glPopMatrix () ); GE( glMatrixMode (GL_MODELVIEW) ); GE( glPopMatrix () ); @@ -226,6 +225,9 @@ _cogl_path_fill_nodes () _COGL_GET_CONTEXT (ctx, NO_RETVAL); + _cogl_path_get_bounds (ctx->path_nodes_min, ctx->path_nodes_max, + &bounds_x, &bounds_y, &bounds_w, &bounds_h); + _cogl_add_path_to_stencil_buffer (ctx->path_nodes_min, ctx->path_nodes_max, ctx->path_nodes->len, @@ -233,9 +235,6 @@ _cogl_path_fill_nodes () CoglPathNode, 0), ctx->clip.stencil_used); - _cogl_path_get_bounds (ctx->path_nodes_min, ctx->path_nodes_max, - &bounds_x, &bounds_y, &bounds_w, &bounds_h); - cogl_rectangle (bounds_x, bounds_y, bounds_w, bounds_h); /* The stencil buffer now contains garbage so the clip area needs to diff --git a/gl/cogl.c b/gl/cogl.c index 47358502d..e82bd9fea 100644 --- a/gl/cogl.c +++ b/gl/cogl.c @@ -171,6 +171,10 @@ cogl_check_extension (const gchar *name, const gchar *ext) void cogl_paint_init (const CoglColor *color) { +#if COGL_DEBUG + fprintf(stderr, "\n ============== Paint Start ================ \n"); +#endif + GE( glClearColor (cogl_color_get_red_float (color), cogl_color_get_green_float (color), cogl_color_get_blue_float (color), @@ -199,33 +203,31 @@ cogl_paint_init (const CoglColor *color) void cogl_push_matrix (void) { - glPushMatrix(); + GE( glPushMatrix() ); } void cogl_pop_matrix (void) { - glPopMatrix(); + GE( glPopMatrix() ); } void cogl_scale (float x, float y) { - glScalef ((float)(x), - (float)(y), - 1.0); + GE( glScalef (x, y, 1.0) ); } void cogl_translate (float x, float y, float z) { - glTranslatef (x, y, z); + GE( glTranslatef (x, y, z) ); } void cogl_rotate (float angle, float x, float y, float z) { - glRotatef (angle, x, y, z); + GE( glRotatef (angle, x, y, z) ); } static inline gboolean @@ -353,10 +355,10 @@ cogl_set_source_color (const CoglColor *color) } static void -apply_matrix (const GLfloat *matrix, GLfloat *vertex) +apply_matrix (const float *matrix, float *vertex) { int x, y; - GLfloat vertex_out[4] = { 0 }; + float vertex_out[4] = { 0 }; for (y = 0; y < 4; y++) for (x = 0; x < 4; x++) @@ -366,7 +368,9 @@ apply_matrix (const GLfloat *matrix, GLfloat *vertex) } static void -project_vertex (GLfloat *modelview, GLfloat *project, GLfloat *vertex) +project_vertex (float *modelview, + float *project, + float *vertex) { int i; @@ -381,8 +385,8 @@ project_vertex (GLfloat *modelview, GLfloat *project, GLfloat *vertex) static void set_clip_plane (GLint plane_num, - const GLfloat *vertex_a, - const GLfloat *vertex_b) + const float *vertex_a, + const float *vertex_b) { GLdouble plane[4]; GLfloat angle; @@ -390,15 +394,15 @@ set_clip_plane (GLint plane_num, /* Calculate the angle between the axes and the line crossing the two points */ - angle = atan2f ((vertex_b[1] - vertex_a[1]), - (vertex_b[0] - vertex_a[0])) * 180.0f / G_PI; + angle = atan2f (vertex_b[1] - vertex_a[1], + vertex_b[0] - vertex_a[0]) * (180.0/G_PI); GE( glPushMatrix () ); /* Load the identity matrix and multiply by the reverse of the projection matrix so we can specify the plane in screen coordinates */ GE( glLoadIdentity () ); - GE( glMultMatrixf (ctx->inverse_projection) ); + GE( glMultMatrixf ((GLfloat *) ctx->inverse_projection) ); /* Rotate about point a */ GE( glTranslatef (vertex_a[0], vertex_a[1], vertex_a[2]) ); /* Rotate the plane by the calculated angle so that it will connect @@ -406,9 +410,9 @@ set_clip_plane (GLint plane_num, GE( glRotatef (angle, 0.0f, 0.0f, 1.0f) ); GE( glTranslatef (-vertex_a[0], -vertex_a[1], -vertex_a[2]) ); - plane[0] = 0.0f; - plane[1] = -1.0f; - plane[2] = 0.0f; + plane[0] = 0; + plane[1] = -1.0; + plane[2] = 0; plane[3] = vertex_a[1]; GE( glClipPlane (plane_num, plane) ); @@ -423,18 +427,11 @@ _cogl_set_clip_planes (float x_offset, { GLfloat modelview[16], projection[16]; - GLfloat vertex_tl[4] = { (x_offset), - (y_offset), - 0.0f, 1.0f }; - GLfloat vertex_tr[4] = { (x_offset + width), - (y_offset), - 0.0f, 1.0f }; - GLfloat vertex_bl[4] = { (x_offset), - (y_offset + height), - 0.0f, 1.0f }; - GLfloat vertex_br[4] = { (x_offset + width), - (y_offset + height), - 0.0f, 1.0f }; + float vertex_tl[4] = { x_offset, y_offset, 0, 1.0 }; + float vertex_tr[4] = { x_offset + width, y_offset, 0, 1.0 }; + float vertex_bl[4] = { x_offset, y_offset + height, 0, 1.0 }; + float vertex_br[4] = { x_offset + width, y_offset + height, + 0, 1.0 }; GE( glGetFloatv (GL_MODELVIEW_MATRIX, modelview) ); GE( glGetFloatv (GL_PROJECTION_MATRIX, projection) ); @@ -452,7 +449,7 @@ _cogl_set_clip_planes (float x_offset, if ((vertex_tl[0] < vertex_tr[0] ? 1 : 0) != (vertex_bl[1] < vertex_tl[1] ? 1 : 0)) { - GLfloat temp[4]; + float temp[4]; memcpy (temp, vertex_tl, sizeof (temp)); memcpy (vertex_tl, vertex_tr, sizeof (temp)); memcpy (vertex_tr, temp, sizeof (temp)); @@ -512,7 +509,7 @@ _cogl_add_stencil_clip (float x_offset, GE( glMatrixMode (GL_PROJECTION) ); GE( glPushMatrix () ); GE( glLoadIdentity () ); - GE( glRecti (-1, 1, 1, -1) ); + GE( glRectf (-1, 1, 1, -1) ); GE( glPopMatrix () ); GE( glMatrixMode (GL_MODELVIEW) ); GE( glPopMatrix () ); @@ -526,14 +523,8 @@ _cogl_add_stencil_clip (float x_offset, void _cogl_set_matrix (const float *matrix) { - float float_matrix[16]; - int i; - - for (i = 0; i < 16; i++) - float_matrix[i] = (matrix[i]); - GE( glLoadIdentity () ); - GE( glMultMatrixf (float_matrix) ); + GE( glMultMatrixf (matrix) ); } void @@ -597,26 +588,27 @@ cogl_perspective (float fovy, 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.0F; + M(0,0) = x; + M(1,1) = y; + M(2,2) = c; + M(2,3) = d; + M(3,2) = -1.0; GE( glMultMatrixf (m) ); GE( glMatrixMode (GL_MODELVIEW) ); /* Calculate and store the inverse of the matrix */ - memset (ctx->inverse_projection, 0, sizeof (GLfloat) * 16); + memset (ctx->inverse_projection, 0, sizeof (float) * 16); #define m ctx->inverse_projection - M(0, 0) = 1.0f / (x); - M(1, 1) = 1.0f / (y); - M(2, 3) = -1.0f; - M(3, 2) = 1.0f / (d); - M(3, 3) = (c) / (d); + 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 } @@ -628,7 +620,7 @@ cogl_frustum (float left, float z_near, float z_far) { - GLfloat c, d; + float c, d; _COGL_GET_CONTEXT (ctx, NO_RETVAL); @@ -645,24 +637,18 @@ cogl_frustum (float left, GE( glMatrixMode (GL_MODELVIEW) ); /* Calculate and store the inverse of the matrix */ - memset (ctx->inverse_projection, 0, sizeof (GLfloat) * 16); + memset (ctx->inverse_projection, 0, sizeof (float) * 16); - c = - (z_far + z_near) - / (z_far - z_near); - d = - (2 * (z_far * z_near)) - / (z_far - z_near); + c = - (z_far + z_near) / (z_far - z_near); + d = - (2 * (z_far * z_near)) / (z_far - z_near); #define M(row,col) ctx->inverse_projection[col*4+row] - M(0,0) = (right - left) - / (2 * z_near); - M(0,3) = (right + left) - / (2 * z_near); - M(1,1) = (top - bottom) - / (2 * z_near); - M(1,3) = (top + bottom) - / (2 * z_near); - M(2,3) = -1.0f; - M(3,2) = 1.0f / d; + M(0,0) = (right - left) / (2 * z_near); + M(0,3) = (right + left) / (2 * z_near); + M(1,1) = (top - bottom) / (2 * z_near); + M(1,3) = (top + bottom) / (2 * z_near); + M(2,3) = -1.0; + M(3,2) = 1.0 / d; M(3,3) = c / d; #undef M } @@ -675,18 +661,22 @@ cogl_viewport (guint width, } void -cogl_setup_viewport (guint width, - guint height, +cogl_setup_viewport (guint width, + guint height, float fovy, float aspect, float z_near, float z_far) { - GLfloat z_camera; - GLfloat projection_matrix[16]; + float z_camera; + float projection_matrix[16]; GE( glViewport (0, 0, width, height) ); + /* For Ortho projection. + * glOrthof (0, width << 16, 0, height << 16, -1 << 16, 1 << 16); + */ + cogl_perspective (fovy, aspect, z_near, z_far); /* @@ -734,9 +724,7 @@ cogl_setup_viewport (guint width, GE( glLoadIdentity () ); GE( glTranslatef (-0.5f, -0.5f, -z_camera) ); - GE( glScalef ( 1.0f / width, - -1.0f / height, - 1.0f / width) ); + GE( glScalef (1.0f / width, -1.0f / height, 1.0f / width) ); GE( glTranslatef (0.0f, -1.0 * height, 0.0f) ); } @@ -1165,8 +1153,8 @@ cogl_get_bitmasks (gint *red, gint *green, gint *blue, gint *alpha) void cogl_fog_set (const CoglColor *fog_color, float density, - float start, - float stop) + float z_near, + float z_far) { GLfloat fogColor[4]; @@ -1182,8 +1170,8 @@ cogl_fog_set (const CoglColor *fog_color, glFogi (GL_FOG_MODE, GL_LINEAR); glHint (GL_FOG_HINT, GL_NICEST); - glFogf (GL_FOG_DENSITY, (density)); - glFogf (GL_FOG_START, (start)); - glFogf (GL_FOG_END, (stop)); + glFogf (GL_FOG_DENSITY, (GLfloat) density); + glFogf (GL_FOG_START, (GLfloat) z_near); + glFogf (GL_FOG_END, (GLfloat) z_far); } diff --git a/gles/cogl-context.c b/gles/cogl-context.c index 496969ae2..995068817 100644 --- a/gles/cogl-context.c +++ b/gles/cogl-context.c @@ -84,7 +84,7 @@ cogl_create_context () #endif /* Init OpenGL state */ - GE( cogl_wrap_glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE) ); + GE( glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE) ); GE( glColorMask (TRUE, TRUE, TRUE, FALSE) ); GE( glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) ); cogl_enable (0); diff --git a/gles/cogl-fbo.c b/gles/cogl-fbo.c index 3b1099e26..3cf523a00 100644 --- a/gles/cogl-fbo.c +++ b/gles/cogl-fbo.c @@ -206,29 +206,29 @@ cogl_draw_buffer (CoglBufferTarget target, CoglHandle offscreen) from a non-screen buffer */ GE( glGetIntegerv (GL_VIEWPORT, ctx->viewport_store) ); - GE( cogl_wrap_glMatrixMode (GL_PROJECTION) ); - GE( cogl_wrap_glPushMatrix () ); - GE( cogl_wrap_glLoadIdentity () ); + GE( glMatrixMode (GL_PROJECTION) ); + GE( glPushMatrix () ); + GE( glLoadIdentity () ); - GE( cogl_wrap_glMatrixMode (GL_MODELVIEW) ); - GE( cogl_wrap_glPushMatrix () ); - GE( cogl_wrap_glLoadIdentity () ); + GE( glMatrixMode (GL_MODELVIEW) ); + GE( glPushMatrix () ); + GE( glLoadIdentity () ); } else { /* Override viewport and matrix setup if redirecting from another offscreen buffer */ - GE( cogl_wrap_glMatrixMode (GL_PROJECTION) ); - GE( cogl_wrap_glLoadIdentity () ); + GE( glMatrixMode (GL_PROJECTION) ); + GE( glLoadIdentity () ); - GE( cogl_wrap_glMatrixMode (GL_MODELVIEW) ); - GE( cogl_wrap_glLoadIdentity () ); + GE( glMatrixMode (GL_MODELVIEW) ); + GE( glLoadIdentity () ); } /* Setup new viewport and matrices */ GE( glViewport (0, 0, fbo->width, fbo->height) ); - GE( cogl_wrap_glTranslatef (-1.0, -1.0, 0) ); - GE( cogl_wrap_glScalef (((float)(2) / + GE( glTranslatef (-1.0, -1.0, 0) ); + GE( glScalef (((float)(2) / (float)(fbo->width)), ((float)(2) / (float)(fbo->height)), @@ -265,11 +265,11 @@ cogl_draw_buffer (CoglBufferTarget target, CoglHandle offscreen) GE( glViewport (ctx->viewport_store[0], ctx->viewport_store[1], ctx->viewport_store[2], ctx->viewport_store[3]) ); - GE( cogl_wrap_glMatrixMode (GL_PROJECTION) ); - GE( cogl_wrap_glPopMatrix () ); + GE( glMatrixMode (GL_PROJECTION) ); + GE( glPopMatrix () ); - GE( cogl_wrap_glMatrixMode (GL_MODELVIEW) ); - GE( cogl_wrap_glPopMatrix () ); + GE( glMatrixMode (GL_MODELVIEW) ); + GE( glPopMatrix () ); } /* Bind window framebuffer object */ diff --git a/gles/cogl-primitives.c b/gles/cogl-primitives.c index 1a588056d..dad130f53 100644 --- a/gles/cogl-primitives.c +++ b/gles/cogl-primitives.c @@ -55,8 +55,8 @@ _cogl_rectangle (float x, cogl_enable (COGL_ENABLE_VERTEX_ARRAY | (ctx->color_alpha < 255 ? COGL_ENABLE_BLEND : 0)); - GE ( cogl_wrap_glVertexPointer (2, GL_FLOAT, 0, rect_verts ) ); - GE ( cogl_wrap_glDrawArrays (GL_TRIANGLE_STRIP, 0, 4) ); + GE ( glVertexPointer (2, GL_FLOAT, 0, rect_verts ) ); + GE ( glDrawArrays (GL_TRIANGLE_STRIP, 0, 4) ); } void @@ -109,10 +109,10 @@ _cogl_path_stroke_nodes () CoglPathNode *path = &g_array_index (ctx->path_nodes, CoglPathNode, path_start); - GE( cogl_wrap_glVertexPointer (2, GL_FIXED, sizeof (CoglPathNode), + GE( glVertexPointer (2, GL_FIXED, sizeof (CoglPathNode), (guchar *) path + G_STRUCT_OFFSET (CoglPathNode, x)) ); - GE( cogl_wrap_glDrawArrays (GL_LINE_STRIP, 0, path->path_size) ); + GE( glDrawArrays (GL_LINE_STRIP, 0, path->path_size) ); path_start += path->path_size; } @@ -167,7 +167,7 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, GE( glStencilFunc (GL_LEQUAL, 0x1, 0x3) ); } - GE( cogl_wrap_glEnable (GL_STENCIL_TEST) ); + GE( glEnable (GL_STENCIL_TEST) ); GE( glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT) ); GE( glColorMask (FALSE, FALSE, FALSE, FALSE) ); @@ -177,10 +177,10 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, { cogl_enable (COGL_ENABLE_VERTEX_ARRAY); - GE( cogl_wrap_glVertexPointer (2, GL_FIXED, sizeof (CoglPathNode), + GE( glVertexPointer (2, GL_FIXED, sizeof (CoglPathNode), (guchar *) path + G_STRUCT_OFFSET (CoglPathNode, x)) ); - GE( cogl_wrap_glDrawArrays (GL_TRIANGLE_FAN, 0, path->path_size) ); + GE( glDrawArrays (GL_TRIANGLE_FAN, 0, path->path_size) ); if (sub_path_num > 0) { @@ -209,16 +209,16 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, GE( glStencilOp (GL_DECR, GL_DECR, GL_DECR) ); /* Decrement all of the bits twice so that only pixels where the value is 3 will remain */ - GE( cogl_wrap_glPushMatrix () ); - GE( cogl_wrap_glLoadIdentity () ); - GE( cogl_wrap_glMatrixMode (GL_PROJECTION) ); - GE( cogl_wrap_glPushMatrix () ); - GE( cogl_wrap_glLoadIdentity () ); + GE( glPushMatrix () ); + GE( glLoadIdentity () ); + GE( glMatrixMode (GL_PROJECTION) ); + GE( glPushMatrix () ); + GE( glLoadIdentity () ); cogl_rectangle (-1.0, -1.0, 2, 2); cogl_rectangle (-1.0, -1.0, 2, 2); - GE( cogl_wrap_glPopMatrix () ); - GE( cogl_wrap_glMatrixMode (GL_MODELVIEW) ); - GE( cogl_wrap_glPopMatrix () ); + GE( glPopMatrix () ); + GE( glMatrixMode (GL_MODELVIEW) ); + GE( glPopMatrix () ); } GE( glStencilMask (~(GLuint) 0) ); @@ -392,8 +392,8 @@ _cogl_path_fill_nodes_scanlines (CoglPathNode *path, /* render triangles */ cogl_enable (COGL_ENABLE_VERTEX_ARRAY | (ctx->color_alpha < 255 ? COGL_ENABLE_BLEND : 0)); - GE ( cogl_wrap_glVertexPointer (2, GL_FIXED, 0, coords ) ); - GE ( cogl_wrap_glDrawArrays (GL_TRIANGLES, 0, spans * 2 * 3)); + GE ( glVertexPointer (2, GL_FIXED, 0, coords ) ); + GE ( glDrawArrays (GL_TRIANGLES, 0, spans * 2 * 3)); g_free (coords); } } diff --git a/gles/cogl-texture.c b/gles/cogl-texture.c index 90152a762..e461dbcf0 100644 --- a/gles/cogl-texture.c +++ b/gles/cogl-texture.c @@ -42,21 +42,6 @@ #include #include -#if HAVE_COGL_GLES2 -#define glVertexPointer cogl_wrap_glVertexPointer -#define glTexCoordPointer cogl_wrap_glTexCoordPointer -#define glColorPointer cogl_wrap_glColorPointer -#define glDrawArrays cogl_wrap_glDrawArrays -#define glDrawElements cogl_wrap_glDrawElements -#define glTexParameteri cogl_wrap_glTexParameteri -#define glClientActiveTexture cogl_wrap_glClientActiveTexture -#define glActiveTexture cogl_wrap_glActiveTexture -#define glEnable cogl_wrap_glEnable -#define glEnableClientState cogl_wrap_glEnableClientState -#define glDisable cogl_wrap_glDisable -#define glDisableClientState cogl_wrap_glDisableClientState -#endif - /* #define COGL_DEBUG 1 @@ -94,7 +79,7 @@ _cogl_texture_bitmap_free (CoglTexture *tex) { if (tex->bitmap.data != NULL && tex->bitmap_owner) g_free (tex->bitmap.data); - + tex->bitmap.data = NULL; tex->bitmap_owner = FALSE; } @@ -105,7 +90,7 @@ _cogl_texture_bitmap_swap (CoglTexture *tex, { if (tex->bitmap.data != NULL && tex->bitmap_owner) g_free (tex->bitmap.data); - + tex->bitmap = *new_bitmap; tex->bitmap_owner = TRUE; } @@ -117,11 +102,11 @@ _cogl_span_iter_update (CoglSpanIter *iter) iter->span = &g_array_index (iter->array, CoglTexSliceSpan, iter->index); - + /* Offset next position by span size */ iter->next_pos = iter->pos + (float)(iter->span->size - iter->span->waste); - + /* Check if span intersects the area to cover */ if (iter->next_pos <= iter->cover_start || iter->pos >= iter->cover_end) @@ -130,15 +115,15 @@ _cogl_span_iter_update (CoglSpanIter *iter) iter->intersects = FALSE; return; } - + iter->intersects = TRUE; - + /* Clip start position to coverage area */ if (iter->pos < iter->cover_start) iter->intersect_start = iter->cover_start; else iter->intersect_start = iter->pos; - + /* Clip end position to coverage area */ if (iter->next_pos > iter->cover_end) iter->intersect_end = iter->cover_end; @@ -161,7 +146,7 @@ _cogl_span_iter_begin (CoglSpanIter *iter, iter->cover_start = cover_start; iter->cover_end = cover_end; iter->pos = iter->origin; - + /* Update intersection */ _cogl_span_iter_update (iter); } @@ -171,10 +156,10 @@ _cogl_span_iter_next (CoglSpanIter *iter) { /* Move current position */ iter->pos = iter->next_pos; - + /* Pick next slice (wrap when last reached) */ iter->index = (iter->index + 1) % iter->array->len; - + /* Update intersection */ _cogl_span_iter_update (iter); } @@ -192,7 +177,7 @@ prep_for_gl_pixels_upload (gint pixels_rowstride, gint pixels_src_y, gint pixels_bpp) { - + if (!(pixels_rowstride & 0x7)) GE( glPixelStorei (GL_UNPACK_ALIGNMENT, 8) ); else if (!(pixels_rowstride & 0x3)) @@ -255,7 +240,7 @@ _cogl_texture_upload_to_gl (CoglTexture *tex) gint x,y; guchar *waste_buf; CoglBitmap slice_bmp; - + bpp = _cogl_get_format_bpp (tex->bitmap.format); waste_buf = _cogl_texture_allocate_waste_buffer (tex); @@ -264,16 +249,16 @@ _cogl_texture_upload_to_gl (CoglTexture *tex) for (y = 0; y < tex->slice_y_spans->len; ++y) { y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, y); - + /* Iterate horizontal slices */ for (x = 0; x < 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); - + /* FIXME: might optimize by not copying to intermediate slice bitmap when source rowstride = bpp * width and the texture image is not sliced */ @@ -291,7 +276,7 @@ _cogl_texture_upload_to_gl (CoglTexture *tex) 0, 0, bpp); - + /* Copy subregion data */ _cogl_bitmap_copy_subregion (&tex->bitmap, &slice_bmp, @@ -300,7 +285,7 @@ _cogl_texture_upload_to_gl (CoglTexture *tex) 0, 0, slice_bmp.width, slice_bmp.height); - + /* Upload new image data */ GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, gl_handle, tex->gl_intformat) ); @@ -383,7 +368,7 @@ _cogl_texture_upload_to_gl (CoglTexture *tex) if (tex->auto_mipmap) cogl_wrap_glGenerateMipmap (tex->gl_target); - + /* Free temp bitmap */ g_free (slice_bmp.data); } @@ -409,10 +394,10 @@ _cogl_texture_draw_and_read (CoglTexture *tex, int bw, bh; CoglBitmap rect_bmp; CoglHandle handle; - + handle = _cogl_texture_handle_from_pointer (tex); bpp = _cogl_get_format_bpp (COGL_PIXEL_FORMAT_RGBA_8888); - + /* If whole image fits into the viewport and target buffer has got no special rowstride, we can do it in one pass */ if (tex->bitmap.width < viewport[2] - viewport[0] && @@ -422,14 +407,14 @@ _cogl_texture_draw_and_read (CoglTexture *tex, /* Clear buffer with transparent black, draw with white for direct copy to framebuffer */ cogl_paint_init (back_color); - + /* Draw the texture image */ cogl_texture_rectangle (handle, 0, 0, (float)(tex->bitmap.width), (float)(tex->bitmap.height), 0, 0, 1.0, 1.0); - + /* Read into target bitmap */ prep_for_gl_pixels_download (tex->bitmap.rowstride); GE( glReadPixels (viewport[0], viewport[1], @@ -442,38 +427,38 @@ _cogl_texture_draw_and_read (CoglTexture *tex, { ry1 = 0; ry2 = 0; ty1 = 0; ty2 = 0; - + #define CFIX (float) - + /* Walk Y axis until whole bitmap height consumed */ for (bh = tex->bitmap.height; bh > 0; bh -= viewport[3]) { /* Rectangle Y coords */ ry1 = ry2; ry2 += (bh < viewport[3]) ? bh : viewport[3]; - + /* Normalized texture Y coords */ ty1 = ty2; ty2 = (CFIX (ry2) / CFIX (tex->bitmap.height)); - + rx1 = 0; rx2 = 0; tx1 = 0; tx2 = 0; - + /* Walk X axis until whole bitmap width consumed */ for (bw = tex->bitmap.width; bw > 0; bw-=viewport[2]) { /* Rectangle X coords */ rx1 = rx2; rx2 += (bw < viewport[2]) ? bw : viewport[2]; - + /* Normalized texture X coords */ tx1 = tx2; tx2 = (CFIX (rx2) / CFIX (tex->bitmap.width)); - + /* Clear buffer with transparent black, draw with white for direct copy to framebuffer */ cogl_paint_init (back_color); - + /* Draw a portion of texture */ cogl_texture_rectangle (handle, 0, 0, @@ -481,7 +466,7 @@ _cogl_texture_draw_and_read (CoglTexture *tex, CFIX (ry2 - ry1), tx1, ty1, tx2, ty2); - + /* Read into a temporary bitmap */ rect_bmp.format = COGL_PIXEL_FORMAT_RGBA_8888; rect_bmp.width = rx2 - rx1; @@ -489,14 +474,14 @@ _cogl_texture_draw_and_read (CoglTexture *tex, rect_bmp.rowstride = bpp * rect_bmp.width; rect_bmp.data = (guchar*) g_malloc (rect_bmp.rowstride * rect_bmp.height); - + prep_for_gl_pixels_download (rect_bmp.rowstride); GE( glReadPixels (viewport[0], viewport[1], rect_bmp.width, rect_bmp.height, GL_RGBA, GL_UNSIGNED_BYTE, rect_bmp.data) ); - + /* Copy to target bitmap */ _cogl_bitmap_copy_subregion (&rect_bmp, target_bmp, @@ -504,12 +489,12 @@ _cogl_texture_draw_and_read (CoglTexture *tex, rx1,ry1, rect_bmp.width, rect_bmp.height); - + /* Free temp bitmap */ g_free (rect_bmp.data); } } - + #undef CFIX } } @@ -532,53 +517,53 @@ _cogl_texture_download_from_gl (CoglTexture *tex, cogl_color_set_from_4ub (&cwhite, 0xff, 0xff, 0xff, 0xff); bpp = _cogl_get_format_bpp (COGL_PIXEL_FORMAT_RGBA_8888); - + /* Viewport needs to have some size and be inside the window for this */ - GE( cogl_wrap_glGetIntegerv (GL_VIEWPORT, viewport) ); - + GE( glGetIntegerv (GL_VIEWPORT, viewport) ); + if (viewport[0] < 0 || viewport[1] < 0 || viewport[2] <= 0 || viewport[3] <= 0) return FALSE; - + /* Setup orthographic projection into current viewport (0,0 in bottom-left corner to draw the texture upside-down so we match the way glReadPixels works) */ - - GE( cogl_wrap_glMatrixMode (GL_PROJECTION) ); - GE( cogl_wrap_glPushMatrix () ); - GE( cogl_wrap_glLoadIdentity () ); - - GE( cogl_wrap_glOrthof (0, (float)(viewport[2]), + + GE( glMatrixMode (GL_PROJECTION) ); + GE( glPushMatrix () ); + GE( glLoadIdentity () ); + + GE( glOrthof (0, (float)(viewport[2]), 0, (float)(viewport[3]), (float)(0), (float)(100)) ); - - GE( cogl_wrap_glMatrixMode (GL_MODELVIEW) ); - GE( cogl_wrap_glPushMatrix () ); - GE( cogl_wrap_glLoadIdentity () ); - + + GE( glMatrixMode (GL_MODELVIEW) ); + GE( glPushMatrix () ); + GE( glLoadIdentity () ); + /* Draw to all channels */ cogl_draw_buffer (COGL_WINDOW_BUFFER | COGL_MASK_BUFFER, 0); - + /* Store old blending factors */ old_src_factor = ctx->blend_src_factor; old_dst_factor = ctx->blend_dst_factor; - + /* Direct copy operation */ cogl_set_source_color (&cwhite); cogl_blend_func (CGL_ONE, CGL_ZERO); _cogl_texture_draw_and_read (tex, target_bmp, &cwhite, viewport); - + /* Check whether texture has alpha and framebuffer not */ /* FIXME: For some reason even if ALPHA_BITS is 8, the framebuffer still doesn't seem to have an alpha buffer. This might be just a PowerVR issue. GLint r_bits, g_bits, b_bits, a_bits; - GE( cogl_wrap_glGetIntegerv (GL_ALPHA_BITS, &a_bits) ); - GE( cogl_wrap_glGetIntegerv (GL_RED_BITS, &r_bits) ); - GE( cogl_wrap_glGetIntegerv (GL_GREEN_BITS, &g_bits) ); - GE( cogl_wrap_glGetIntegerv (GL_BLUE_BITS, &b_bits) ); + GE( glGetIntegerv (GL_ALPHA_BITS, &a_bits) ); + GE( glGetIntegerv (GL_RED_BITS, &r_bits) ); + GE( glGetIntegerv (GL_GREEN_BITS, &g_bits) ); + GE( glGetIntegerv (GL_BLUE_BITS, &b_bits) ); printf ("R bits: %d\n", r_bits); printf ("G bits: %d\n", g_bits); printf ("B bits: %d\n", b_bits); @@ -590,7 +575,7 @@ _cogl_texture_download_from_gl (CoglTexture *tex, guchar *srcpixel; guchar *dstpixel; gint x,y; - + /* Create temp bitmap for alpha values */ alpha_bmp.format = COGL_PIXEL_FORMAT_RGBA_8888; alpha_bmp.width = target_bmp->width; @@ -598,16 +583,16 @@ _cogl_texture_download_from_gl (CoglTexture *tex, alpha_bmp.rowstride = bpp * alpha_bmp.width; alpha_bmp.data = (guchar*) g_malloc (alpha_bmp.rowstride * alpha_bmp.height); - + /* Draw alpha values into RGB channels */ cogl_blend_func (CGL_ZERO, CGL_SRC_ALPHA); _cogl_texture_draw_and_read (tex, &alpha_bmp, &cwhite, viewport); - + /* Copy temp R to target A */ srcdata = alpha_bmp.data; dstdata = target_bmp->data; - + for (y=0; yheight; ++y) { for (x=0; xwidth; ++x) @@ -619,19 +604,19 @@ _cogl_texture_download_from_gl (CoglTexture *tex, srcdata += alpha_bmp.rowstride; dstdata += target_bmp->rowstride; } - + g_free (alpha_bmp.data); } - + /* Restore old state */ - cogl_wrap_glMatrixMode (GL_PROJECTION); - cogl_wrap_glPopMatrix (); - cogl_wrap_glMatrixMode (GL_MODELVIEW); - cogl_wrap_glPopMatrix (); - + glMatrixMode (GL_PROJECTION); + glPopMatrix (); + glMatrixMode (GL_MODELVIEW); + glPopMatrix (); + cogl_draw_buffer (COGL_WINDOW_BUFFER, 0); cogl_blend_func (old_src_factor, old_dst_factor); - + return TRUE; } @@ -658,7 +643,7 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, gint local_x = 0, local_y = 0; guchar *waste_buf; CoglBitmap slice_bmp; - + bpp = _cogl_get_format_bpp (source_bmp->format); waste_buf = _cogl_texture_allocate_waste_buffer (tex); @@ -668,9 +653,9 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, _cogl_span_iter_begin (&y_iter, tex->slice_y_spans, 0, (float)(dst_y), (float)(dst_y + height)); - + !_cogl_span_iter_end (&y_iter); - + _cogl_span_iter_next (&y_iter), source_y += inter_h ) { @@ -689,9 +674,9 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, _cogl_span_iter_begin (&x_iter, tex->slice_x_spans, 0, (float)(dst_x), (float)(dst_x + width)); - + !_cogl_span_iter_end (&x_iter); - + _cogl_span_iter_next (&x_iter), source_x += inter_w ) { @@ -710,22 +695,22 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, x_iter.intersect_start); inter_h = (y_iter.intersect_end - y_iter.intersect_start); - + /* Localize intersection top-left corner to slice*/ local_x = (x_iter.intersect_start - x_iter.pos); local_y = (y_iter.intersect_start - y_iter.pos); - + /* 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); - + /* FIXME: might optimize by not copying to intermediate slice bitmap when source rowstride = bpp * width and the texture image is not sliced */ - + /* Setup temp bitmap for slice subregion */ slice_bmp.format = tex->bitmap.format; slice_bmp.width = inter_w; @@ -733,13 +718,13 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, slice_bmp.rowstride = bpp * slice_bmp.width; slice_bmp.data = (guchar*) g_malloc (slice_bmp.rowstride * slice_bmp.height); - + /* Setup gl alignment to match rowstride and top-left corner */ prep_for_gl_pixels_upload (slice_bmp.rowstride, 0, /* src x */ 0, /* src y */ bpp); - + /* Copy subregion data */ _cogl_bitmap_copy_subregion (source_bmp, &slice_bmp, @@ -748,11 +733,11 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex, 0, 0, slice_bmp.width, slice_bmp.height); - + /* Upload new image data */ GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, gl_handle, tex->gl_intformat) ); - + GE( glTexSubImage2D (tex->gl_target, 0, local_x, local_y, inter_w, inter_h, @@ -880,12 +865,12 @@ _cogl_rect_slices_for_size (gint size_to_fill, { gint n_spans = 0; CoglTexSliceSpan span; - + /* Init first slice span */ span.start = 0; span.size = max_span_size; span.waste = 0; - + /* Repeat until whole area covered */ while (size_to_fill >= span.size) { @@ -895,7 +880,7 @@ _cogl_rect_slices_for_size (gint size_to_fill, size_to_fill -= span.size; n_spans++; } - + /* Add one last smaller slice span */ if (size_to_fill > 0) { @@ -903,7 +888,7 @@ _cogl_rect_slices_for_size (gint size_to_fill, if (out_spans) g_array_append_val (out_spans, span); n_spans++; } - + return n_spans; } @@ -915,15 +900,15 @@ _cogl_pot_slices_for_size (gint size_to_fill, { gint n_spans = 0; CoglTexSliceSpan span; - + /* Init first slice span */ span.start = 0; span.size = max_span_size; span.waste = 0; - + /* Fix invalid max_waste */ if (max_waste < 0) max_waste = 0; - + while (TRUE) { /* Is the whole area covered? */ @@ -952,7 +937,7 @@ _cogl_pot_slices_for_size (gint size_to_fill, } } } - + /* Can't get here */ return 0; } @@ -969,7 +954,7 @@ _cogl_texture_size_supported (GLenum gl_target, static gboolean _cogl_texture_slices_create (CoglTexture *tex) -{ +{ gint bpp; gint max_width; gint max_height; @@ -980,11 +965,11 @@ _cogl_texture_slices_create (CoglTexture *tex) gint x, y; CoglTexSliceSpan *x_span; CoglTexSliceSpan *y_span; - + gint (*slices_for_size) (gint, gint, gint, GArray*); - + bpp = _cogl_get_format_bpp (tex->bitmap.format); - + /* Initialize size of largest slice according to supported features */ if (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT)) { @@ -1000,12 +985,12 @@ _cogl_texture_slices_create (CoglTexture *tex) tex->gl_target = GL_TEXTURE_2D; slices_for_size = _cogl_pot_slices_for_size; } - + /* Negative number means no slicing forced by the user */ if (tex->max_waste <= -1) { CoglTexSliceSpan span; - + /* Check if size supported else bail out */ if (!_cogl_texture_size_supported (tex->gl_target, tex->gl_format, @@ -1015,25 +1000,25 @@ _cogl_texture_slices_create (CoglTexture *tex) { return FALSE; } - + n_x_slices = 1; n_y_slices = 1; - - /* Init span arrays */ + + /* Init span arrays */ tex->slice_x_spans = g_array_sized_new (FALSE, FALSE, sizeof (CoglTexSliceSpan), 1); - + tex->slice_y_spans = g_array_sized_new (FALSE, FALSE, sizeof (CoglTexSliceSpan), 1); - + /* Add a single span for width and height */ span.start = 0; span.size = max_width; span.waste = max_width - tex->bitmap.width; g_array_append_val (tex->slice_x_spans, span); - + span.size = max_height; span.waste = max_height - tex->bitmap.height; g_array_append_val (tex->slice_y_spans, span); @@ -1052,73 +1037,73 @@ _cogl_texture_slices_create (CoglTexture *tex) max_width /= 2; else max_height /= 2; - + if (max_width == 0 || max_height == 0) return FALSE; } - + /* Determine the slices required to cover the bitmap area */ n_x_slices = slices_for_size (tex->bitmap.width, max_width, tex->max_waste, NULL); - + n_y_slices = slices_for_size (tex->bitmap.height, max_height, tex->max_waste, NULL); - + /* Init span arrays with reserved size */ tex->slice_x_spans = g_array_sized_new (FALSE, FALSE, sizeof (CoglTexSliceSpan), n_x_slices); - + tex->slice_y_spans = g_array_sized_new (FALSE, FALSE, sizeof (CoglTexSliceSpan), n_y_slices); - + /* Fill span arrays with info */ slices_for_size (tex->bitmap.width, max_width, tex->max_waste, tex->slice_x_spans); - + slices_for_size (tex->bitmap.height, max_height, tex->max_waste, tex->slice_y_spans); } - + /* Init and resize GL handle array */ n_slices = n_x_slices * n_y_slices; - + tex->slice_gl_handles = g_array_sized_new (FALSE, FALSE, sizeof (GLuint), n_slices); - + g_array_set_size (tex->slice_gl_handles, n_slices); - - + + /* Hardware repeated tiling if supported, else tile in software*/ if (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT) && n_slices == 1) tex->wrap_mode = GL_REPEAT; else tex->wrap_mode = GL_CLAMP_TO_EDGE; - + /* Generate a "working set" of GL texture objects * (some implementations might supported faster * re-binding between textures inside a set) */ gl_handles = (GLuint*) tex->slice_gl_handles->data; - + GE( glGenTextures (n_slices, gl_handles) ); - - + + /* Init each GL texture object */ for (y = 0; y < n_y_slices; ++y) { y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, y); - + for (x = 0; x < n_x_slices; ++x) { x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x); - + #if COGL_DEBUG printf ("CREATE SLICE (%d,%d)\n", x,y); printf ("size: (%d x %d)\n", @@ -1138,7 +1123,7 @@ _cogl_texture_slices_create (CoglTexture *tex) 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) ); @@ -1149,19 +1134,19 @@ _cogl_texture_slices_create (CoglTexture *tex) tex->gl_format, tex->gl_type, 0) ); } } - + return TRUE; } static void _cogl_texture_slices_free (CoglTexture *tex) -{ +{ if (tex->slice_x_spans != NULL) g_array_free (tex->slice_x_spans, TRUE); - + if (tex->slice_y_spans != NULL) g_array_free (tex->slice_y_spans, TRUE); - + if (tex->slice_gl_handles != NULL) { if (tex->is_foreign == FALSE) @@ -1169,7 +1154,7 @@ _cogl_texture_slices_free (CoglTexture *tex) GE( glDeleteTextures (tex->slice_gl_handles->len, (GLuint*) tex->slice_gl_handles->data) ); } - + g_array_free (tex->slice_gl_handles, TRUE); } } @@ -1191,17 +1176,17 @@ _cogl_pixel_format_to_gl (CoglPixelFormat format, GLenum glintformat = 0; GLenum glformat = 0; GLenum gltype = 0; - + /* No premultiplied formats accepted by GL * (FIXME: latest hardware?) */ - + if (format & COGL_PREMULT_BIT) format = (format & COGL_UNPREMULT_MASK); - + /* Everything else accepted * (FIXME: check YUV support) */ required_format = format; - + /* Find GL equivalents */ switch (format) { @@ -1215,7 +1200,7 @@ _cogl_pixel_format_to_gl (CoglPixelFormat format, glformat = GL_LUMINANCE; gltype = GL_UNSIGNED_BYTE; break; - + /* Just one 24-bit ordering supported */ case COGL_PIXEL_FORMAT_RGB_888: case COGL_PIXEL_FORMAT_BGR_888: @@ -1224,7 +1209,7 @@ _cogl_pixel_format_to_gl (CoglPixelFormat format, gltype = GL_UNSIGNED_BYTE; required_format = COGL_PIXEL_FORMAT_RGB_888; break; - + /* Just one 32-bit ordering supported */ case COGL_PIXEL_FORMAT_RGBA_8888: case COGL_PIXEL_FORMAT_BGRA_8888: @@ -1235,7 +1220,7 @@ _cogl_pixel_format_to_gl (CoglPixelFormat format, gltype = GL_UNSIGNED_BYTE; required_format = COGL_PIXEL_FORMAT_RGBA_8888; break; - + /* The following three types of channel ordering * are always defined using system word byte * ordering (even according to GLES spec) */ @@ -1254,19 +1239,19 @@ _cogl_pixel_format_to_gl (CoglPixelFormat format, glformat = GL_RGBA; gltype = GL_UNSIGNED_SHORT_5_5_5_1; break; - + /* FIXME: check extensions for YUV support */ default: break; } - + if (out_glintformat != NULL) *out_glintformat = glintformat; if (out_glformat != NULL) *out_glformat = glformat; if (out_gltype != NULL) *out_gltype = gltype; - + return required_format; } @@ -1277,7 +1262,7 @@ _cogl_texture_bitmap_prepare (CoglTexture *tex, CoglBitmap new_bitmap; CoglPixelFormat new_data_format; gboolean success; - + /* Was there any internal conversion requested? */ if (internal_format == COGL_PIXEL_FORMAT_ANY) internal_format = tex->bitmap.format; @@ -1287,21 +1272,21 @@ _cogl_texture_bitmap_prepare (CoglTexture *tex, &tex->gl_intformat, &tex->gl_format, &tex->gl_type); - + /* Convert to internal format */ if (new_data_format != tex->bitmap.format) { success = _cogl_bitmap_convert_and_premult (&tex->bitmap, &new_bitmap, new_data_format); - + if (!success) return FALSE; - + /* Update texture with new data */ _cogl_texture_bitmap_swap (tex, &new_bitmap); } - + return TRUE; } @@ -1325,15 +1310,15 @@ cogl_texture_new_with_size (guint width, CoglTexture *tex; gint bpp; gint rowstride; - + /* Since no data, we need some internal format */ if (internal_format == COGL_PIXEL_FORMAT_ANY) return COGL_INVALID_HANDLE; - + /* Rowstride from width */ bpp = _cogl_get_format_bpp (internal_format); rowstride = width * bpp; - + /* Init texture with empty bitmap */ tex = (CoglTexture*) g_malloc (sizeof (CoglTexture)); @@ -1342,36 +1327,36 @@ cogl_texture_new_with_size (guint width, tex->is_foreign = FALSE; tex->auto_mipmap = ((flags & COGL_TEXTURE_AUTO_MIPMAP) != 0); - + tex->bitmap.width = width; tex->bitmap.height = height; tex->bitmap.format = internal_format; tex->bitmap.rowstride = rowstride; tex->bitmap.data = NULL; tex->bitmap_owner = FALSE; - + tex->slice_x_spans = NULL; 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; - + /* Find closest GL format match */ tex->bitmap.format = _cogl_pixel_format_to_gl (internal_format, &tex->gl_intformat, &tex->gl_format, &tex->gl_type); - + /* Create slices for the given format and size */ if (!_cogl_texture_slices_create (tex)) { _cogl_texture_free (tex); return COGL_INVALID_HANDLE; } - + return _cogl_texture_handle_new (tex); } @@ -1387,20 +1372,20 @@ cogl_texture_new_from_data (guint width, { CoglTexture *tex; gint bpp; - + if (format == COGL_PIXEL_FORMAT_ANY) return COGL_INVALID_HANDLE; - + if (data == NULL) return COGL_INVALID_HANDLE; - + /* Rowstride from width if not given */ bpp = _cogl_get_format_bpp (format); if (rowstride == 0) rowstride = width * bpp; - + /* Create new texture and fill with given data */ tex = (CoglTexture*) g_malloc (sizeof (CoglTexture)); - + tex->ref_count = 1; COGL_HANDLE_DEBUG_NEW (texture, tex); @@ -1413,40 +1398,40 @@ cogl_texture_new_from_data (guint width, tex->bitmap.format = format; tex->bitmap.rowstride = rowstride; tex->bitmap_owner = FALSE; - + tex->slice_x_spans = NULL; 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; - + /* FIXME: If upload fails we should set some kind of * error flag but still return texture handle (this * is to keep the behavior equal to _new_from_file; * see below) */ - + if (!_cogl_texture_bitmap_prepare (tex, internal_format)) { _cogl_texture_free (tex); return COGL_INVALID_HANDLE; } - + if (!_cogl_texture_slices_create (tex)) { _cogl_texture_free (tex); return COGL_INVALID_HANDLE; } - + if (!_cogl_texture_upload_to_gl (tex)) { _cogl_texture_free (tex); return COGL_INVALID_HANDLE; } - + _cogl_texture_bitmap_free (tex); - + return _cogl_texture_handle_new (tex); } @@ -1460,25 +1445,25 @@ cogl_texture_new_from_bitmap (CoglBitmap *bmp, /* Create new texture and fill with loaded data */ tex = (CoglTexture*) g_malloc ( sizeof (CoglTexture)); - + tex->ref_count = 1; COGL_HANDLE_DEBUG_NEW (texture, tex); - + tex->is_foreign = FALSE; tex->auto_mipmap = ((flags & COGL_TEXTURE_AUTO_MIPMAP) != 0); tex->bitmap = *bmp; tex->bitmap_owner = TRUE; bmp->data = NULL; - + tex->slice_x_spans = NULL; 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; - + /* FIXME: If upload fails we should set some kind of * error flag but still return texture handle if the * user decides to destroy another texture and upload @@ -1486,27 +1471,27 @@ cogl_texture_new_from_bitmap (CoglBitmap *bmp, * in that case). As a rule then, everytime a valid * CoglHandle is returned, it should also be destroyed * with cogl_texture_unref at some point! */ - + if (!_cogl_texture_bitmap_prepare (tex, internal_format)) { _cogl_texture_free (tex); return COGL_INVALID_HANDLE; } - + if (!_cogl_texture_slices_create (tex)) { _cogl_texture_free (tex); return COGL_INVALID_HANDLE; } - + if (!_cogl_texture_upload_to_gl (tex)) { _cogl_texture_free (tex); return COGL_INVALID_HANDLE; } - + _cogl_texture_bitmap_free (tex); - + return _cogl_texture_handle_new (tex); } @@ -1519,7 +1504,7 @@ cogl_texture_new_from_file (const gchar *filename, { CoglBitmap *bmp; CoglHandle handle; - + g_return_val_if_fail (error == NULL || *error == NULL, COGL_INVALID_HANDLE); if (!(bmp = cogl_bitmap_new_from_file (filename, error))) @@ -1549,7 +1534,7 @@ cogl_texture_new_from_foreign (GLuint gl_handle, robustness and for completeness in case one day GLES gains support for them. */ - + GLenum gl_error = 0; GLboolean gl_istexture; GLint gl_compressed = GL_FALSE; @@ -1563,39 +1548,39 @@ cogl_texture_new_from_foreign (GLuint gl_handle, CoglTexture *tex; CoglTexSliceSpan x_span; CoglTexSliceSpan y_span; - + /* Allow 2-dimensional textures only */ if (gl_target != GL_TEXTURE_2D) return COGL_INVALID_HANDLE; - + /* Make sure it is a valid GL texture object */ gl_istexture = glIsTexture (gl_handle); if (gl_istexture == GL_FALSE) return COGL_INVALID_HANDLE; - + /* Make sure binding succeeds */ gl_error = glGetError (); glBindTexture (gl_target, gl_handle); if (glGetError () != GL_NO_ERROR) return COGL_INVALID_HANDLE; - + /* Obtain texture parameters (only level 0 we are interested in) */ - + #if HAVE_COGL_GL GE( glGetTexLevelParameteriv (gl_target, 0, GL_TEXTURE_COMPRESSED, &gl_compressed) ); - + GE( glGetTexLevelParameteriv (gl_target, 0, GL_TEXTURE_INTERNAL_FORMAT, &gl_int_format) ); - + GE( glGetTexLevelParameteriv (gl_target, 0, GL_TEXTURE_WIDTH, &gl_width) ); - + GE( glGetTexLevelParameteriv (gl_target, 0, GL_TEXTURE_HEIGHT, &gl_height) ); @@ -1607,87 +1592,87 @@ cogl_texture_new_from_foreign (GLuint gl_handle, 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) ); - + /* Validate width and height */ if (gl_width <= 0 || gl_height <= 0) return COGL_INVALID_HANDLE; - + /* Validate pot waste */ if (x_pot_waste < 0 || x_pot_waste >= gl_width || y_pot_waste < 0 || y_pot_waste >= gl_height) return COGL_INVALID_HANDLE; - + /* Compressed texture images not supported */ if (gl_compressed == GL_TRUE) 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; } - + /* Create new texture */ tex = (CoglTexture*) g_malloc ( sizeof (CoglTexture)); - + tex->ref_count = 1; COGL_HANDLE_DEBUG_NEW (texture, tex); - + /* Setup bitmap info */ tex->is_foreign = TRUE; tex->auto_mipmap = (gl_gen_mipmap == GL_TRUE) ? TRUE : FALSE; - + bpp = _cogl_get_format_bpp (format); tex->bitmap.format = format; tex->bitmap.width = gl_width - x_pot_waste; tex->bitmap.height = gl_height - y_pot_waste; tex->bitmap.rowstride = tex->bitmap.width * bpp; tex->bitmap_owner = FALSE; - + tex->gl_target = gl_target; tex->gl_intformat = gl_int_format; tex->gl_format = gl_int_format; tex->gl_type = GL_UNSIGNED_BYTE; - + tex->min_filter = gl_min_filter; tex->mag_filter = gl_mag_filter; tex->max_waste = 0; - + /* Create slice arrays */ tex->slice_x_spans = g_array_sized_new (FALSE, FALSE, sizeof (CoglTexSliceSpan), 1); - + tex->slice_y_spans = g_array_sized_new (FALSE, FALSE, sizeof (CoglTexSliceSpan), 1); - + tex->slice_gl_handles = g_array_sized_new (FALSE, FALSE, sizeof (GLuint), 1); - + /* Store info for a single slice */ x_span.start = 0; x_span.size = gl_width; x_span.waste = x_pot_waste; g_array_append_val (tex->slice_x_spans, x_span); - + y_span.start = 0; y_span.size = gl_height; y_span.waste = y_pot_waste; g_array_append_val (tex->slice_y_spans, y_span); - + g_array_append_val (tex->slice_gl_handles, gl_handle); - + /* Force appropriate wrap parameter */ if (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT) && gl_target == GL_TEXTURE_2D) @@ -1704,7 +1689,7 @@ cogl_texture_new_from_foreign (GLuint gl_handle, GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) ); GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) ); } - + return _cogl_texture_handle_new (tex); } @@ -1712,12 +1697,12 @@ guint cogl_texture_get_width (CoglHandle handle) { CoglTexture *tex; - + if (!cogl_is_texture (handle)) return 0; - + tex = _cogl_texture_pointer_from_handle (handle); - + return tex->bitmap.width; } @@ -1725,12 +1710,12 @@ guint cogl_texture_get_height (CoglHandle handle) { CoglTexture *tex; - + if (!cogl_is_texture (handle)) return 0; - + tex = _cogl_texture_pointer_from_handle (handle); - + return tex->bitmap.height; } @@ -1738,12 +1723,12 @@ CoglPixelFormat cogl_texture_get_format (CoglHandle handle) { CoglTexture *tex; - + if (!cogl_is_texture (handle)) return COGL_PIXEL_FORMAT_ANY; - + tex = _cogl_texture_pointer_from_handle (handle); - + return tex->bitmap.format; } @@ -1751,12 +1736,12 @@ guint cogl_texture_get_rowstride (CoglHandle handle) { CoglTexture *tex; - + if (!cogl_is_texture (handle)) return 0; - + tex = _cogl_texture_pointer_from_handle (handle); - + return tex->bitmap.rowstride; } @@ -1764,12 +1749,12 @@ gint cogl_texture_get_max_waste (CoglHandle handle) { CoglTexture *tex; - + if (!cogl_is_texture (handle)) return 0; - + tex = _cogl_texture_pointer_from_handle (handle); - + return tex->max_waste; } @@ -1777,18 +1762,18 @@ gboolean cogl_texture_is_sliced (CoglHandle handle) { CoglTexture *tex; - + if (!cogl_is_texture (handle)) return FALSE; - + tex = _cogl_texture_pointer_from_handle (handle); - + if (tex->slice_gl_handles == NULL) return FALSE; - + if (tex->slice_gl_handles->len <= 1) return FALSE; - + return TRUE; } @@ -1798,24 +1783,24 @@ cogl_texture_get_gl_texture (CoglHandle handle, GLenum *out_gl_target) { CoglTexture *tex; - + if (!cogl_is_texture (handle)) return FALSE; - + tex = _cogl_texture_pointer_from_handle (handle); - + if (tex->slice_gl_handles == NULL) return FALSE; - + if (tex->slice_gl_handles->len < 1) return FALSE; - + if (out_gl_handle != NULL) *out_gl_handle = g_array_index (tex->slice_gl_handles, GLuint, 0); - + if (out_gl_target != NULL) *out_gl_target = tex->gl_target; - + return TRUE; } @@ -1823,12 +1808,12 @@ COGLenum 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; } @@ -1836,12 +1821,12 @@ COGLenum 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; } @@ -1853,20 +1838,20 @@ cogl_texture_set_filters (CoglHandle handle, CoglTexture *tex; GLuint gl_handle; int i; - + if (!cogl_is_texture (handle)) return; - + 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; - + /* Apply new filters to every slice */ for (i=0; islice_gl_handles->len; ++i) { @@ -1902,37 +1887,37 @@ cogl_texture_set_region (CoglHandle handle, GLenum closest_gl_format; GLenum closest_gl_type; gboolean success; - + /* Check if valid texture handle */ if (!cogl_is_texture (handle)) return FALSE; - + tex = _cogl_texture_pointer_from_handle (handle); - + /* Check for valid format */ if (format == COGL_PIXEL_FORMAT_ANY) return FALSE; - + /* Shortcut out early if the image is empty */ if (width == 0 || height == 0) return TRUE; - + /* Init source bitmap */ source_bmp.width = width; source_bmp.height = height; source_bmp.format = format; source_bmp.data = (guchar*)data; - + /* Rowstride from width if none specified */ bpp = _cogl_get_format_bpp (format); source_bmp.rowstride = (rowstride == 0) ? width * bpp : rowstride; - + /* Find closest format to internal that's supported by GL */ closest_format = _cogl_pixel_format_to_gl (tex->bitmap.format, NULL, /* don't need */ &closest_gl_format, &closest_gl_type); - + /* If no direct match, convert */ if (closest_format != format) { @@ -1940,13 +1925,13 @@ cogl_texture_set_region (CoglHandle handle, success = _cogl_bitmap_convert_and_premult (&source_bmp, &temp_bmp, closest_format); - + /* Swap bitmaps if succeeded */ if (!success) return FALSE; source_bmp = temp_bmp; source_bmp_owner = TRUE; } - + /* Send data to GL */ _cogl_texture_upload_subregion_to_gl (tex, src_x, src_y, @@ -1955,11 +1940,11 @@ cogl_texture_set_region (CoglHandle handle, &source_bmp, closest_gl_format, closest_gl_type); - + /* Free data if owner */ if (source_bmp_owner) g_free (source_bmp.data); - + return TRUE; } @@ -1982,25 +1967,25 @@ cogl_texture_get_data (CoglHandle handle, guchar *src; guchar *dst; gint y; - + /* Check if valid texture handle */ if (!cogl_is_texture (handle)) return 0; - + tex = _cogl_texture_pointer_from_handle (handle); - + /* Default to internal format if none specified */ if (format == COGL_PIXEL_FORMAT_ANY) format = tex->bitmap.format; - + /* Rowstride from texture width if none specified */ bpp = _cogl_get_format_bpp (format); if (rowstride == 0) rowstride = tex->bitmap.width * bpp; - + /* Return byte size if only that requested */ byte_size = tex->bitmap.height * rowstride; if (data == NULL) return byte_size; - + /* Find closest format that's supported by GL (Can't use _cogl_pixel_format_to_gl since available formats when reading pixels on GLES are severely limited) */ @@ -2008,7 +1993,7 @@ cogl_texture_get_data (CoglHandle handle, closest_gl_format = GL_RGBA; closest_gl_type = GL_UNSIGNED_BYTE; closest_bpp = _cogl_get_format_bpp (closest_format); - + /* Is the requested format supported? */ if (closest_format == format) { @@ -2027,12 +2012,12 @@ cogl_texture_get_data (CoglHandle handle, target_bmp.data = (guchar*) g_malloc (target_bmp.height * target_bmp.rowstride); } - + /* Retrieve data from slices */ _cogl_texture_download_from_gl (tex, &target_bmp, closest_gl_format, closest_gl_type); - + /* Was intermediate used? */ if (closest_format != format) { @@ -2040,11 +2025,11 @@ cogl_texture_get_data (CoglHandle handle, success = _cogl_bitmap_convert_and_premult (&target_bmp, &new_bmp, format); - + /* Free intermediate data and return if failed */ g_free (target_bmp.data); if (!success) return 0; - + /* Copy to user buffer */ for (y = 0; y < new_bmp.height; ++y) { @@ -2052,11 +2037,11 @@ cogl_texture_get_data (CoglHandle handle, dst = data + y * rowstride; memcpy (dst, src, new_bmp.width); } - + /* Free converted data */ g_free (new_bmp.data); } - + return byte_size; } @@ -2204,14 +2189,14 @@ _cogl_texture_quad_sw (CoglTexture *tex, /* Scale ratio from texture to quad widths */ tw = (float)(tex->bitmap.width); th = (float)(tex->bitmap.height); - + tqx = (x2 - x1) / (tw * (tx2 - tx1)); tqy = (y2 - y1) / (th * (ty2 - ty1)); /* Integral texture coordinate for first tile */ first_tx = (float)(floorf (tx1)); first_ty = (float)(floorf (ty1)); - + /* Denormalize texture coordinates */ first_tx = (first_tx * tw); first_ty = (first_ty * th); @@ -2223,20 +2208,20 @@ _cogl_texture_quad_sw (CoglTexture *tex, /* Quad coordinate of the first tile */ first_qx = x1 - (tx1 - first_tx) * tqx; first_qy = y1 - (ty1 - first_ty) * tqy; - - + + /* Iterate until whole quad height covered */ for (_cogl_span_iter_begin (&iter_y, tex->slice_y_spans, first_ty, ty1, ty2) ; !_cogl_span_iter_end (&iter_y) ; _cogl_span_iter_next (&iter_y) ) - { + { /* Discard slices out of quad early */ if (!iter_y.intersects) continue; - + /* Span-quad intersection in quad coordinates */ slice_qy1 = first_qy + (iter_y.intersect_start - first_ty) * tqy; - + slice_qy2 = first_qy + (iter_y.intersect_end - first_ty) * tqy; /* Localize slice texture coordinates */ @@ -2256,12 +2241,12 @@ _cogl_texture_quad_sw (CoglTexture *tex, { /* Discard slices out of quad early */ if (!iter_x.intersects) continue; - + /* Span-quad intersection in quad coordinates */ slice_qx1 = first_qx + (iter_x.intersect_start - first_tx) * tqx; - + slice_qx2 = first_qx + (iter_x.intersect_end - first_tx) * tqx; - + /* Localize slice texture coordinates */ slice_tx1 = iter_x.intersect_start - iter_x.pos; slice_tx2 = iter_x.intersect_end - iter_x.pos; @@ -2282,7 +2267,7 @@ _cogl_texture_quad_sw (CoglTexture *tex, printf("tx2: %f\n", (slice_tx2)); printf("ty2: %f\n", (slice_ty2)); #endif - + /* Pick and bind opengl texture object */ gl_handle = g_array_index (tex->slice_gl_handles, GLuint, iter_y.index * iter_x.array->len + @@ -2377,15 +2362,15 @@ cogl_texture_multiple_rectangles (CoglHandle handle, /* Check if valid texture */ if (!cogl_is_texture (handle)) return; - + cogl_clip_ensure (); tex = _cogl_texture_pointer_from_handle (handle); - + /* Make sure we got stuff to draw */ if (tex->slice_gl_handles == NULL) return; - + if (tex->slice_gl_handles->len == 0) return; @@ -2532,7 +2517,7 @@ cogl_texture_polygon (CoglHandle handle, GE( glTexCoordPointer (2, GL_FLOAT, sizeof (CoglTextureGLVertex), p->t ) ); cogl_enable (enable_flags); - + gl_handle = g_array_index (tex->slice_gl_handles, GLuint, 0); x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0); y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0); @@ -2541,7 +2526,7 @@ cogl_texture_polygon (CoglHandle handle, OpenGL */ for (i = 0; i < n_vertices; i++, p++) { -#define CFX_F +#define CFX_F p->v[0] = CFX_F(vertices[i].x); p->v[1] = CFX_F(vertices[i].y); @@ -2606,7 +2591,7 @@ cogl_material_rectangle (CoglFixed x1, { CoglHandle layer = tmp->data; CoglHandle texture = cogl_material_layer_get_texture (layer); - + if (cogl_material_layer_get_type (layer) != COGL_MATERIAL_LAYER_TYPE_TEXTURE) continue; @@ -2629,7 +2614,7 @@ cogl_material_rectangle (CoglFixed x1, if (n_valid_layers >= CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS) break; } - + /* NB: It could be that no valid texture layers were found, but * we will still submit a non-textured rectangle in that case. */ if (n_valid_layers) @@ -2723,7 +2708,7 @@ cogl_material_rectangle (CoglFixed x1, GE (glDisable (GL_TEXTURE_2D)); GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY)); } - + /* FIXME - CoglMaterials aren't yet used pervasively throughout * the cogl API, so we currently need to cleanup material state * that will confuse other parts of the API. diff --git a/gles/cogl.c b/gles/cogl.c index 373072d28..bcdd18cfb 100644 --- a/gles/cogl.c +++ b/gles/cogl.c @@ -73,14 +73,13 @@ _cogl_error_string(GLenum errorCode) } #endif - CoglFuncPtr cogl_get_proc_address (const gchar* name) { return NULL; } -gboolean +gboolean cogl_check_extension (const gchar *name, const gchar *ext) { return FALSE; @@ -99,39 +98,53 @@ cogl_paint_init (const CoglColor *color) 0); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - cogl_wrap_glDisable (GL_LIGHTING); - cogl_wrap_glDisable (GL_FOG); + glDisable (GL_LIGHTING); + glDisable (GL_FOG); + + /* + * Disable the depth test for now as has some strange side effects, + * mainly on x/y axis rotation with multiple layers at same depth + * (eg rotating text on a bg has very strange effect). Seems no clean + * 100% effective way to fix without other odd issues.. So for now + * move to application to handle and add cogl_enable_depth_test() + * as for custom actors (i.e groups) to enable if need be. + * + * glEnable (GL_DEPTH_TEST); + * glEnable (GL_ALPHA_TEST) + * glDepthFunc (GL_LEQUAL); + * glAlphaFunc (GL_GREATER, 0.1); + */ } /* FIXME: inline most of these */ void cogl_push_matrix (void) { - GE( cogl_wrap_glPushMatrix() ); + GE( glPushMatrix() ); } void cogl_pop_matrix (void) { - GE( cogl_wrap_glPopMatrix() ); + GE( glPopMatrix() ); } void cogl_scale (float x, float y) { - GE( cogl_wrap_glScalef (x, y, 1.0) ); + GE( glScalef (x, y, 1.0) ); } void cogl_translate (float x, float y, float z) { - GE( cogl_wrap_glTranslatef (x, y, z) ); + GE( glTranslatef (x, y, z) ); } void cogl_rotate (float angle, float x, float y, float z) { - GE( cogl_wrap_glRotatef (angle, x, y, z) ); + GE( glRotatef (angle, x, y, z) ); } static inline gboolean @@ -147,17 +160,17 @@ cogl_toggle_flag (CoglContext *ctx, { if (!(ctx->enable_flags & flag)) { - GE( cogl_wrap_glEnable (gl_flag) ); + GE( glEnable (gl_flag) ); ctx->enable_flags |= flag; return TRUE; } } else if (ctx->enable_flags & flag) { - GE( cogl_wrap_glDisable (gl_flag) ); + GE( glDisable (gl_flag) ); ctx->enable_flags &= ~flag; } - + return FALSE; } @@ -174,17 +187,17 @@ cogl_toggle_client_flag (CoglContext *ctx, { if (!(ctx->enable_flags & flag)) { - GE( cogl_wrap_glEnableClientState (gl_flag) ); + GE( glEnableClientState (gl_flag) ); ctx->enable_flags |= flag; return TRUE; } } else if (ctx->enable_flags & flag) { - GE( cogl_wrap_glDisableClientState (gl_flag) ); + GE( glDisableClientState (gl_flag) ); ctx->enable_flags &= ~flag; } - + return FALSE; } @@ -195,11 +208,11 @@ cogl_enable (gulong flags) * hope of lessening number GL traffic. */ _COGL_GET_CONTEXT (ctx, NO_RETVAL); - + cogl_toggle_flag (ctx, flags, COGL_ENABLE_BLEND, GL_BLEND); - + cogl_toggle_flag (ctx, flags, COGL_ENABLE_TEXTURE_2D, GL_TEXTURE_2D); @@ -211,7 +224,7 @@ cogl_enable (gulong flags) cogl_toggle_client_flag (ctx, flags, COGL_ENABLE_VERTEX_ARRAY, GL_VERTEX_ARRAY); - + cogl_toggle_client_flag (ctx, flags, COGL_ENABLE_TEXCOORD_ARRAY, GL_TEXTURE_COORD_ARRAY); @@ -225,7 +238,7 @@ gulong cogl_get_enable () { _COGL_GET_CONTEXT (ctx, 0); - + return ctx->enable_flags; } @@ -234,15 +247,15 @@ cogl_enable_depth_test (gboolean setting) { if (setting) { - cogl_wrap_glEnable (GL_DEPTH_TEST); - cogl_wrap_glEnable (GL_ALPHA_TEST); + glEnable (GL_DEPTH_TEST); + glEnable (GL_ALPHA_TEST); glDepthFunc (GL_LEQUAL); - cogl_wrap_glAlphaFunc (GL_GREATER, 0.1); + glAlphaFunc (GL_GREATER, 0.1); } else { - cogl_wrap_glDisable (GL_DEPTH_TEST); - cogl_wrap_glDisable (GL_ALPHA_TEST); + glDisable (GL_DEPTH_TEST); + glDisable (GL_ALPHA_TEST); } } @@ -258,14 +271,14 @@ void cogl_set_source_color (const CoglColor *color) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); - + #if 0 /*HAVE_GLES_COLOR4UB*/ - /* NOTE: seems SDK_OGLES-1.1_LINUX_PCEMULATION_2.02.22.0756 has this call - * but is broken - see #857. Therefor disabling. + /* NOTE: seems SDK_OGLES-1.1_LINUX_PCEMULATION_2.02.22.0756 has this call + * but is broken - see #857. Therefor disabling. */ - /* + /* * GLES 1.1 does actually have this function, it's in the header file but * missing in the reference manual (and SDK): * @@ -279,12 +292,12 @@ cogl_set_source_color (const CoglColor *color) #else /* conversion can cause issues with picking on some gles implementations */ - GE( cogl_wrap_glColor4f (cogl_color_get_red (color), + GE( glColor4f (cogl_color_get_red (color), cogl_color_get_green (color), cogl_color_get_blue (color), cogl_color_get_alpha (color)) ); #endif - + /* Store alpha for proper blending enables */ ctx->color_alpha = cogl_color_get_alpha_byte (color); } @@ -297,7 +310,7 @@ apply_matrix (const float *matrix, float *vertex) for (y = 0; y < 4; y++) for (x = 0; x < 4; x++) - vertex_out[y] += (vertex[x] * matrix[y + x * 4]); + vertex_out[y] += vertex[x] * matrix[y + x * 4]; memcpy (vertex, vertex_out, sizeof (vertex_out)); } @@ -315,7 +328,7 @@ project_vertex (float *modelview, apply_matrix (project, vertex); /* Convert from homogenized coordinates */ for (i = 0; i < 4; i++) - vertex[i] = (vertex[i] / vertex[3]); + vertex[i] /= vertex[3]; } static void @@ -332,26 +345,26 @@ set_clip_plane (GLint plane_num, angle = atan2f (vertex_b[1] - vertex_a[1], vertex_b[0] - vertex_a[0]) * (180.0/G_PI); - GE( cogl_wrap_glPushMatrix () ); + GE( glPushMatrix () ); /* Load the identity matrix and multiply by the reverse of the projection matrix so we can specify the plane in screen coordinates */ - GE( cogl_wrap_glLoadIdentity () ); - GE( cogl_wrap_glMultMatrixf ((GLfloat *) ctx->inverse_projection) ); + GE( glLoadIdentity () ); + GE( glMultMatrixf ((GLfloat *) ctx->inverse_projection) ); /* Rotate about point a */ - GE( cogl_wrap_glTranslatef (vertex_a[0], vertex_a[1], vertex_a[2]) ); + GE( glTranslatef (vertex_a[0], vertex_a[1], vertex_a[2]) ); /* Rotate the plane by the calculated angle so that it will connect the two points */ - GE( cogl_wrap_glRotatef (angle, 0.0f, 0.0f, 1.0f) ); - GE( cogl_wrap_glTranslatef (-vertex_a[0], -vertex_a[1], -vertex_a[2]) ); + GE( glRotatef (angle, 0.0f, 0.0f, 1.0f) ); + GE( glTranslatef (-vertex_a[0], -vertex_a[1], -vertex_a[2]) ); plane[0] = 0; plane[1] = -1.0; plane[2] = 0; plane[3] = vertex_a[1]; - GE( cogl_wrap_glClipPlanef (plane_num, plane) ); + GE( glClipPlanef (plane_num, plane) ); - GE( cogl_wrap_glPopMatrix () ); + GE( glPopMatrix () ); } void @@ -366,21 +379,21 @@ _cogl_set_clip_planes (float x_offset, float vertex_tr[4] = { x_offset + width, y_offset, 0, 1.0 }; float vertex_bl[4] = { x_offset, y_offset + height, 0, 1.0 }; float vertex_br[4] = { x_offset + width, y_offset + height, - 0, 1.0 }; + 0, 1.0 }; - GE( cogl_wrap_glGetFloatv (GL_MODELVIEW_MATRIX, modelview) ); - GE( cogl_wrap_glGetFloatv (GL_PROJECTION_MATRIX, projection) ); + GE( glGetFloatv (GL_MODELVIEW_MATRIX, modelview) ); + GE( glGetFloatv (GL_PROJECTION_MATRIX, projection) ); project_vertex (modelview, projection, vertex_tl); project_vertex (modelview, projection, vertex_tr); project_vertex (modelview, projection, vertex_bl); project_vertex (modelview, projection, vertex_br); - /* If the order of the top and bottom lines is different from - the order of the left and right lines then the clip rect must - have been transformed so that the back is visible. We - therefore need to swap one pair of vertices otherwise all of - the planes will be the wrong way around */ + /* If the order of the top and bottom lines is different from the + order of the left and right lines then the clip rect must have + been transformed so that the back is visible. We therefore need + to swap one pair of vertices otherwise all of the planes will be + the wrong way around */ if ((vertex_tl[0] < vertex_tr[0] ? 1 : 0) != (vertex_bl[1] < vertex_tl[1] ? 1 : 0)) { @@ -410,8 +423,8 @@ _cogl_add_stencil_clip (float x_offset, if (first) { - GE( cogl_wrap_glEnable (GL_STENCIL_TEST) ); - + GE( glEnable (GL_STENCIL_TEST) ); + /* Initially disallow everything */ GE( glClearStencil (0) ); GE( glClear (GL_STENCIL_BUFFER_BIT) ); @@ -434,15 +447,15 @@ _cogl_add_stencil_clip (float x_offset, only pixels where both the original stencil buffer and the rectangle are set will be valid */ GE( glStencilOp (GL_DECR, GL_DECR, GL_DECR) ); - GE( cogl_wrap_glPushMatrix () ); - GE( cogl_wrap_glLoadIdentity () ); - GE( cogl_wrap_glMatrixMode (GL_PROJECTION) ); - GE( cogl_wrap_glPushMatrix () ); - GE( cogl_wrap_glLoadIdentity () ); + GE( glPushMatrix () ); + GE( glLoadIdentity () ); + GE( glMatrixMode (GL_PROJECTION) ); + GE( glPushMatrix () ); + GE( glLoadIdentity () ); cogl_rectangle (-1.0, -1.0, 2, 2); - GE( cogl_wrap_glPopMatrix () ); - GE( cogl_wrap_glMatrixMode (GL_MODELVIEW) ); - GE( cogl_wrap_glPopMatrix () ); + GE( glPopMatrix () ); + GE( glMatrixMode (GL_MODELVIEW) ); + GE( glPopMatrix () ); } /* Restore the stencil mode */ @@ -453,37 +466,34 @@ _cogl_add_stencil_clip (float x_offset, void _cogl_set_matrix (const float *matrix) { - GE( cogl_wrap_glLoadIdentity () ); - GE( cogl_wrap_glMultMatrixf (matrix) ); + GE( glLoadIdentity () ); + GE( glMultMatrixf (matrix) ); } void _cogl_disable_stencil_buffer (void) { - GE( cogl_wrap_glDisable (GL_STENCIL_TEST) ); + GE( glDisable (GL_STENCIL_TEST) ); } void _cogl_enable_clip_planes (void) { - GE( cogl_wrap_glEnable (GL_CLIP_PLANE0) ); - GE( cogl_wrap_glEnable (GL_CLIP_PLANE1) ); - GE( cogl_wrap_glEnable (GL_CLIP_PLANE2) ); - GE( cogl_wrap_glEnable (GL_CLIP_PLANE3) ); + GE( glEnable (GL_CLIP_PLANE0) ); + GE( glEnable (GL_CLIP_PLANE1) ); + GE( glEnable (GL_CLIP_PLANE2) ); + GE( glEnable (GL_CLIP_PLANE3) ); } void _cogl_disable_clip_planes (void) { - GE( cogl_wrap_glDisable (GL_CLIP_PLANE3) ); - GE( cogl_wrap_glDisable (GL_CLIP_PLANE2) ); - GE( cogl_wrap_glDisable (GL_CLIP_PLANE1) ); - GE( cogl_wrap_glDisable (GL_CLIP_PLANE0) ); + GE( glDisable (GL_CLIP_PLANE3) ); + GE( glDisable (GL_CLIP_PLANE2) ); + GE( glDisable (GL_CLIP_PLANE1) ); + GE( glDisable (GL_CLIP_PLANE0) ); } -/* - * Fixed point implementation of the perspective function - */ void cogl_perspective (float fovy, float aspect, @@ -495,21 +505,21 @@ cogl_perspective (float fovy, float fovy_rad_half = (fovy * G_PI) / 360; GLfloat m[16]; - + _COGL_GET_CONTEXT (ctx, NO_RETVAL); memset (&m[0], 0, sizeof (m)); - GE( cogl_wrap_glMatrixMode (GL_PROJECTION) ); - GE( cogl_wrap_glLoadIdentity () ); + GE( glMatrixMode (GL_PROJECTION) ); + GE( glLoadIdentity () ); - /* + /* * 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 can are loosing significant + * 2) When working with small numbers, we are loosing significant * precision */ ymax = (zNear * (sinf (fovy_rad_half) / cosf (fovy_rad_half))); @@ -527,9 +537,9 @@ cogl_perspective (float fovy, M(2,3) = d; M(3,2) = -1.0; - GE( cogl_wrap_glMultMatrixf (m) ); + GE( glMultMatrixf (m) ); - GE( cogl_wrap_glMatrixMode (GL_MODELVIEW) ); + GE( glMatrixMode (GL_MODELVIEW) ); /* Calculate and store the inverse of the matrix */ memset (ctx->inverse_projection, 0, sizeof (float) * 16); @@ -557,30 +567,33 @@ cogl_frustum (float left, _COGL_GET_CONTEXT (ctx, NO_RETVAL); - GE( cogl_wrap_glMatrixMode (GL_PROJECTION) ); - GE( cogl_wrap_glLoadIdentity () ); + GE( glMatrixMode (GL_PROJECTION) ); + GE( glLoadIdentity () ); - GE( cogl_wrap_glFrustumf (left, right, - bottom, top, - z_near, z_far) ); + GE( glFrustumf (left, + right, + bottom, + top, + z_near, + z_far) ); - GE( cogl_wrap_glMatrixMode (GL_MODELVIEW) ); + GE( glMatrixMode (GL_MODELVIEW) ); /* Calculate and store the inverse of the matrix */ memset (ctx->inverse_projection, 0, sizeof (float) * 16); - c = -(z_far + z_near / z_far - z_near); - d = -(2 * (z_far * z_near) / z_far - z_near); + c = - (z_far + z_near) / (z_far - z_near); + d = - (2 * (z_far * z_near)) / (z_far - z_near); #define M(row,col) ctx->inverse_projection[col*4+row] - M(0,0) = (right - left / 2 * z_near); - M(0,3) = (right + left / 2 * z_near); - M(1,1) = (top - bottom / 2 * z_near); - M(1,3) = (top + bottom / 2 * z_near); + M(0,0) = (right - left) / (2 * z_near); + M(0,3) = (right + left) / (2 * z_near); + M(1,1) = (top - bottom) / (2 * z_near); + M(1,3) = (top + bottom) / (2 * z_near); M(2,3) = -1.0; - M(3,2) = (1.0 / d); - M(3,3) = (c / d); -#undef M + M(3,2) = 1.0 / d; + M(3,3) = c / d; +#undef M } void @@ -591,26 +604,24 @@ cogl_viewport (guint width, } void -cogl_setup_viewport (guint w, - guint h, +cogl_setup_viewport (guint width, + guint height, float fovy, float aspect, float z_near, float z_far) { - gint width = (gint) w; - gint height = (gint) h; float z_camera; float projection_matrix[16]; - + GE( glViewport (0, 0, width, height) ); /* For Ortho projection. - * cogl_wrap_glOrthof (0, width << 16, 0, height << 16, -1 << 16, 1 << 16); + * glOrthof (0, width << 16, 0, height << 16, -1 << 16, 1 << 16); */ cogl_perspective (fovy, aspect, z_near, z_far); - + /* * camera distance from screen * @@ -620,15 +631,13 @@ cogl_setup_viewport (guint w, cogl_get_projection_matrix (projection_matrix); z_camera = 0.5 * projection_matrix[0]; - GE( cogl_wrap_glLoadIdentity () ); + GE( glLoadIdentity () ); - GE( cogl_wrap_glTranslatef (-0.5f, -0.5f, -z_camera) ); + GE( glTranslatef (-0.5f, -0.5f, -z_camera) ); - GE( cogl_wrap_glScalef ( 1.0 / width, - -1.0 / height, - 1.0 / width) ); + GE( glScalef (1.0f / width, -1.0f / height, 1.0f / width) ); - GE( cogl_wrap_glTranslatef (0, -1.0 * height, 0) ); + GE( glTranslatef (0.0f, -1.0 * height, 0.0f) ); } static void @@ -640,12 +649,12 @@ _cogl_features_init () _COGL_GET_CONTEXT (ctx, NO_RETVAL); - GE( cogl_wrap_glGetIntegerv (GL_STENCIL_BITS, &num_stencil_bits) ); + GE( glGetIntegerv (GL_STENCIL_BITS, &num_stencil_bits) ); /* We need at least three stencil bits to combine clips */ if (num_stencil_bits > 2) flags |= COGL_FEATURE_STENCIL_BUFFER; - GE( cogl_wrap_glGetIntegerv (GL_MAX_CLIP_PLANES, &max_clip_planes) ); + GE( glGetIntegerv (GL_MAX_CLIP_PLANES, &max_clip_planes) ); if (max_clip_planes >= 4) flags |= COGL_FEATURE_FOUR_CLIP_PLANES; @@ -653,6 +662,7 @@ _cogl_features_init () flags |= COGL_FEATURE_SHADERS_GLSL | COGL_FEATURE_OFFSCREEN; #endif + /* Cache features */ ctx->feature_flags = flags; ctx->features_cached = TRUE; } @@ -661,10 +671,10 @@ CoglFeatureFlags cogl_get_features () { _COGL_GET_CONTEXT (ctx, 0); - + if (!ctx->features_cached) _cogl_features_init (); - + return ctx->feature_flags; } @@ -672,23 +682,23 @@ gboolean cogl_features_available (CoglFeatureFlags features) { _COGL_GET_CONTEXT (ctx, 0); - + if (!ctx->features_cached) _cogl_features_init (); - + return (ctx->feature_flags & features) == features; } void cogl_get_modelview_matrix (float m[16]) { - cogl_wrap_glGetFloatv (GL_MODELVIEW_MATRIX, m); + glGetFloatv (GL_MODELVIEW_MATRIX, m); } void cogl_get_projection_matrix (float m[16]) { - cogl_wrap_glGetFloatv (GL_PROJECTION_MATRIX, m); + glGetFloatv (GL_PROJECTION_MATRIX, m); } void @@ -697,7 +707,7 @@ cogl_get_viewport (float v[4]) GLint viewport[4]; int i; - cogl_wrap_glGetIntegerv (GL_VIEWPORT, viewport); + glGetIntegerv (GL_VIEWPORT, viewport); for (i = 0; i < 4; i++) v[i] = (float)(viewport[i]); @@ -706,14 +716,27 @@ cogl_get_viewport (float v[4]) void cogl_get_bitmasks (gint *red, gint *green, gint *blue, gint *alpha) { + GLint value; if (red) - GE( cogl_wrap_glGetIntegerv(GL_RED_BITS, red) ); + { + GE( glGetIntegerv(GL_RED_BITS, &value) ); + *red = value; + } if (green) - GE( cogl_wrap_glGetIntegerv(GL_GREEN_BITS, green) ); + { + GE( glGetIntegerv(GL_GREEN_BITS, &value) ); + *green = value; + } if (blue) - GE( cogl_wrap_glGetIntegerv(GL_BLUE_BITS, blue) ); + { + GE( glGetIntegerv(GL_BLUE_BITS, &value) ); + *blue = value; + } if (alpha) - GE( cogl_wrap_glGetIntegerv(GL_ALPHA_BITS, alpha ) ); + { + GE( glGetIntegerv(GL_ALPHA_BITS, &value ) ); + *alpha = value; + } } void @@ -724,19 +747,20 @@ cogl_fog_set (const CoglColor *fog_color, { GLfloat fogColor[4]; - fogColor[0] = cogl_color_get_red (fog_color); - fogColor[1] = cogl_color_get_green (fog_color); - fogColor[2] = cogl_color_get_blue (fog_color); - fogColor[3] = cogl_color_get_alpha (fog_color); + fogColor[0] = cogl_color_get_red_float (fog_color); + fogColor[1] = cogl_color_get_green_float (fog_color); + fogColor[2] = cogl_color_get_blue_float (fog_color); + fogColor[3] = cogl_color_get_alpha_float (fog_color); - cogl_wrap_glEnable (GL_FOG); + glEnable (GL_FOG); - cogl_wrap_glFogfv (GL_FOG_COLOR, fogColor); + glFogfv (GL_FOG_COLOR, fogColor); - cogl_wrap_glFogf (GL_FOG_MODE, GL_LINEAR); + glFogf (GL_FOG_MODE, GL_LINEAR); glHint (GL_FOG_HINT, GL_NICEST); - cogl_wrap_glFogf (GL_FOG_DENSITY, (GLfloat) density); - cogl_wrap_glFogf (GL_FOG_START, (GLfloat) z_near); - cogl_wrap_glFogf (GL_FOG_END, (GLfloat) z_far); + glFogf (GL_FOG_DENSITY, (GLfloat) density); + glFogf (GL_FOG_START, (GLfloat) z_near); + glFogf (GL_FOG_END, (GLfloat) z_far); } + From 9abf44eac312bcc3038e77c060a17af0d51c8ad7 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Mon, 26 Jan 2009 11:07:35 +0000 Subject: [PATCH 16/16] Updates GLES1 support for CoglMaterial This updates cogl/gles in line with the integration of CoglMaterial throughout Cogl that has been done for cogl/gl. Note: This is still buggy, but at least it builds again and test-actors works. Some GLES2 specific changes were made, but these haven't been tested yet. --- common/cogl-material.c | 35 +- gl/cogl-texture.c | 25 +- gles/cogl-context.c | 130 ++- gles/cogl-context.h | 94 +- gles/cogl-gles2-wrapper.h | 5 + gles/cogl-internal.h | 11 +- gles/cogl-primitives.c | 75 +- gles/cogl-texture-private.h | 39 +- gles/cogl-texture.c | 1680 ++++++++++++++++++++++------------- gles/cogl.c | 49 +- 10 files changed, 1333 insertions(+), 810 deletions(-) diff --git a/common/cogl-material.c b/common/cogl-material.c index 5b3c7490e..925e77af6 100644 --- a/common/cogl-material.c +++ b/common/cogl-material.c @@ -886,8 +886,12 @@ _cogl_material_flush_layers_gl_state (CoglMaterial *material, _cogl_material_layer_pointer_from_handle (layer_handle); CoglLayerInfo *gl_layer_info = NULL; CoglLayerInfo new_gl_layer_info; + CoglHandle tex_handle; GLuint gl_texture; GLenum gl_target; +#ifdef HAVE_COGL_GLES2 + GLenum gl_internal_format; +#endif new_gl_layer_info.layer0_overridden = layer0_override_texture ? TRUE : FALSE; @@ -912,18 +916,19 @@ _cogl_material_flush_layers_gl_state (CoglMaterial *material, continue; } - cogl_texture_get_gl_texture (layer->texture, &gl_texture, &gl_target); + tex_handle = layer->texture; + cogl_texture_get_gl_texture (tex_handle, &gl_texture, &gl_target); if (new_gl_layer_info.layer0_overridden) gl_texture = layer0_override_texture; else if (new_gl_layer_info.fallback) { - CoglHandle tex_handle; - if (gl_target == GL_TEXTURE_2D) tex_handle = ctx->default_gl_texture_2d_tex; +#ifdef HAVE_COGL_GL else if (gl_target == GL_TEXTURE_RECTANGLE_ARB) tex_handle = ctx->default_gl_texture_rect_tex; +#endif else { g_warning ("We don't have a default texture we can use to fill " @@ -935,12 +940,28 @@ _cogl_material_flush_layers_gl_state (CoglMaterial *material, cogl_texture_get_gl_texture (tex_handle, &gl_texture, NULL); } +#ifdef HAVE_COGL_GLES2 + { + CoglTexture *tex = + _cogl_texture_pointer_from_handle (tex_handle); + gl_internal_format = tex->gl_intformat; + } +#endif + GE (glActiveTexture (GL_TEXTURE0 + i)); if (!gl_layer_info || gl_layer_info->gl_target != gl_target || gl_layer_info->gl_texture != gl_texture) - GE (glBindTexture (gl_target, gl_texture)); + { +#ifdef HAVE_COGL_GLES2 + cogl_gles2_wrapper_bind_texture (gl_target, + gl_texture, + gl_internal_format); +#else + GE (glBindTexture (gl_target, gl_texture)); +#endif + } /* Disable the previous target if it was different */ if (gl_layer_info && @@ -1007,7 +1028,11 @@ _cogl_material_flush_base_gl_state (CoglMaterial *material) if (!(ctx->current_material_flags & COGL_MATERIAL_FLAG_DEFAULT_COLOR && material->flags & COGL_MATERIAL_FLAG_DEFAULT_COLOR)) { - GE (glColor4fv (material->unlit)); + /* GLES doesn't have glColor4fv... */ + GE (glColor4f (material->unlit[0], + material->unlit[1], + material->unlit[2], + material->unlit[3])); } if (!(ctx->current_material_flags & COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL diff --git a/gl/cogl-texture.c b/gl/cogl-texture.c index 0a84457c5..fba290dd3 100644 --- a/gl/cogl-texture.c +++ b/gl/cogl-texture.c @@ -51,6 +51,13 @@ printf("err: 0x%x\n", err); \ } */ +#ifdef HAVE_COGL_GL +#ifdef glDrawRangeElements +#undef glDrawRangeElements +#endif +#define glDrawRangeElements ctx->pf_glDrawRangeElements +#endif + static void _cogl_journal_flush (void); static void _cogl_texture_free (CoglTexture *tex); @@ -2040,10 +2047,10 @@ _cogl_journal_flush_quad_batch (CoglJournalEntry *batch_start, GE (glVertexPointer (2, GL_FLOAT, stride, vertex_pointer)); GE (ctx->pf_glDrawRangeElements (GL_TRIANGLES, - 0, ctx->static_indices->len - 1, - 6 * batch_len, - GL_UNSIGNED_SHORT, - ctx->static_indices->data)); + 0, ctx->static_indices->len - 1, + 6 * batch_len, + GL_UNSIGNED_SHORT, + ctx->static_indices->data)); } static void @@ -2970,6 +2977,16 @@ cogl_polygon (CoglTextureVertex *vertices, if (i == 0 && cogl_texture_is_sliced (tex_handle)) { +#if defined (HAVE_COGL_GLES) || defined (HAVE_COGL_GLES2) + { + static gboolean shown_gles_slicing_warning = FALSE; + if (!shown_gles_slicing_warning) + g_warning ("cogl_polygon does not work for sliced textures " + "on GL ES"); + shown_gles_slicing_warning = TRUE; + return; + } +#endif if (n_layers > 1) { static gboolean shown_slicing_warning = FALSE; diff --git a/gles/cogl-context.c b/gles/cogl-context.c index 995068817..9d874d78f 100644 --- a/gles/cogl-context.c +++ b/gles/cogl-context.c @@ -28,69 +28,108 @@ #endif #include "cogl.h" - -#include - #include "cogl-internal.h" #include "cogl-util.h" #include "cogl-context.h" +#include "cogl-texture-private.h" +#include "cogl-material-private.h" #include "cogl-gles2-wrapper.h" +#include + static CoglContext *_context = NULL; gboolean cogl_create_context () { + GLubyte default_texture_data[] = { 0xff, 0xff, 0xff, 0x0 }; + gulong enable_flags = 0; + if (_context != NULL) return FALSE; - + /* Allocate context memory */ _context = (CoglContext*) g_malloc (sizeof (CoglContext)); - + /* Init default values */ _context->feature_flags = 0; _context->features_cached = FALSE; - + _context->enable_flags = 0; _context->color_alpha = 255; - - _context->path_nodes = g_array_new (FALSE, FALSE, sizeof (CoglPathNode)); - _context->last_path = 0; - - _context->texture_handles = NULL; - _context->texture_vertices = g_array_new (FALSE, FALSE, - sizeof (CoglTextureGLVertex)); - _context->texture_indices = g_array_new (FALSE, FALSE, - sizeof (GLushort)); _context->material_handles = NULL; _context->material_layer_handles = NULL; - _context->source_material = COGL_INVALID_HANDLE; + _context->default_material = cogl_material_new (); + _context->source_material = NULL; + + _context->texture_handles = NULL; + _context->default_gl_texture_2d_tex = COGL_INVALID_HANDLE; + _context->default_gl_texture_rect_tex = COGL_INVALID_HANDLE; + _context->texture_download_material = COGL_INVALID_HANDLE; + + _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)); + + _context->current_material = NULL; + _context->current_material_flags = 0; + _context->current_layers = g_array_new (FALSE, FALSE, + sizeof (CoglLayerInfo)); + _context->n_texcoord_arrays_enabled = 0; _context->fbo_handles = NULL; - _context->program_handles = NULL; - _context->shader_handles = NULL; _context->draw_buffer = COGL_WINDOW_BUFFER; + _context->shader_handles = NULL; + + _context->program_handles = NULL; + _context->vertex_buffer_handles = NULL; - - _context->blend_src_factor = CGL_SRC_ALPHA; - _context->blend_dst_factor = CGL_ONE_MINUS_SRC_ALPHA; + + _context->path_nodes = g_array_new (FALSE, FALSE, sizeof (CoglPathNode)); + _context->last_path = 0; + _context->stencil_material = cogl_material_new (); /* Init the GLES2 wrapper */ #ifdef HAVE_COGL_GLES2 cogl_gles2_wrapper_init (&_context->gles2); #endif - - /* Init OpenGL state */ - GE( glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE) ); - GE( glColorMask (TRUE, TRUE, TRUE, FALSE) ); - GE( glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) ); - cogl_enable (0); + /* Initialise the clip stack */ _cogl_clip_stack_state_init (); - + + /* Create default textures used for fall backs */ + _context->default_gl_texture_2d_tex = + cogl_texture_new_from_data (1, /* width */ + 1, /* height */ + -1, /* max waste */ + FALSE, /* auto mipmap */ + COGL_PIXEL_FORMAT_RGBA_8888, /* data format */ + /* internal format */ + COGL_PIXEL_FORMAT_RGBA_8888, + 0, /* auto calc row stride */ + &default_texture_data); + _context->default_gl_texture_rect_tex = + cogl_texture_new_from_data (1, /* width */ + 1, /* height */ + -1, /* max waste */ + FALSE, /* auto mipmap */ + COGL_PIXEL_FORMAT_RGBA_8888, /* data format */ + /* internal format */ + COGL_PIXEL_FORMAT_RGBA_8888, + 0, /* auto calc row stride */ + &default_texture_data); + + cogl_set_source (_context->default_material); + cogl_material_flush_gl_state (_context->source_material, NULL); + enable_flags = + cogl_material_get_cogl_enable_flags (_context->source_material); + cogl_enable (enable_flags); + return TRUE; } @@ -105,15 +144,6 @@ cogl_destroy_context () if (_context->path_nodes) g_array_free (_context->path_nodes, TRUE); -#ifdef HAVE_COGL_GLES2 - cogl_gles2_wrapper_deinit (&_context->gles2); -#endif - - if (_context->texture_vertices) - g_array_free (_context->texture_vertices, TRUE); - if (_context->texture_indices) - g_array_free (_context->texture_indices, TRUE); - if (_context->texture_handles) g_array_free (_context->texture_handles, TRUE); if (_context->fbo_handles) @@ -122,16 +152,36 @@ cogl_destroy_context () g_array_free (_context->shader_handles, TRUE); if (_context->program_handles) g_array_free (_context->program_handles, TRUE); - + + if (_context->default_gl_texture_2d_tex) + cogl_texture_unref (_context->default_gl_texture_2d_tex); + if (_context->default_gl_texture_rect_tex) + cogl_texture_unref (_context->default_gl_texture_rect_tex); + + if (_context->default_material) + cogl_material_unref (_context->default_material); + + if (_context->journal) + g_array_free (_context->journal, TRUE); + 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); + g_free (_context); } CoglContext * _cogl_context_get_default () { - /* Create if doesn't exists yet */ + /* Create if doesn't exist yet */ if (_context == NULL) cogl_create_context (); - + return _context; } diff --git a/gles/cogl-context.h b/gles/cogl-context.h index c1d107270..041587c56 100644 --- a/gles/cogl-context.h +++ b/gles/cogl-context.h @@ -41,57 +41,69 @@ typedef struct typedef struct { /* Features cache */ - CoglFeatureFlags feature_flags; - gboolean features_cached; - - /* Enable cache */ - gulong enable_flags; - guint8 color_alpha; - COGLenum blend_src_factor; - COGLenum blend_dst_factor; + CoglFeatureFlags feature_flags; + gboolean features_cached; + + /* Enable cache */ + gulong enable_flags; + guint8 color_alpha; + + gboolean enable_backface_culling; - gboolean enable_backface_culling; - - /* Primitives */ - floatVec2 path_start; - floatVec2 path_pen; - GArray *path_nodes; - guint last_path; - floatVec2 path_nodes_min; - floatVec2 path_nodes_max; - /* Cache of inverse projection matrix */ float inverse_projection[16]; - /* Textures */ - GArray *texture_handles; - GArray *texture_vertices; - GArray *texture_indices; - /* The gl texture number that the above vertices apply to. This to - detect when a different slice is encountered so that the vertices - can be flushed */ - GLuint texture_current; - GLenum texture_target; - GLenum texture_format; - /* Materials */ - GArray *material_handles; - GArray *material_layer_handles; - CoglHandle source_material; + GArray *material_handles; + GArray *material_layer_handles; + CoglHandle default_material; + CoglHandle source_material; + + /* Textures */ + GArray *texture_handles; + CoglHandle default_gl_texture_2d_tex; + CoglHandle default_gl_texture_rect_tex; + CoglHandle texture_download_material; + + /* Batching geometry... */ + /* We journal the texture rectangles we want to submit to OpenGL so + * we have an oppertunity to optimise the final order so that we + * can batch things together. */ + GArray *journal; + GArray *logged_vertices; + GArray *static_indices; + GArray *polygon_vertices; + + /* Some simple caching, to minimize state changes... */ + CoglHandle current_material; + gulong current_material_flags; + GArray *current_layers; + guint n_texcoord_arrays_enabled; /* Framebuffer objects */ - GArray *fbo_handles; - CoglBufferTarget draw_buffer; + GArray *fbo_handles; + CoglBufferTarget draw_buffer; /* Shaders */ - GArray *program_handles; - GArray *shader_handles; + GArray *shader_handles; - /* Vertex buffers */ - GArray *vertex_buffer_handles; + /* Programs */ + GArray *program_handles; /* Clip stack */ - CoglClipStackState clip; + CoglClipStackState clip; + + /* Vertex buffers */ + GArray *vertex_buffer_handles; + + /* Primitives */ + floatVec2 path_start; + floatVec2 path_pen; + GArray *path_nodes; + guint last_path; + floatVec2 path_nodes_min; + floatVec2 path_nodes_max; + CoglHandle stencil_material; #ifdef HAVE_COGL_GLES2 CoglGles2Wrapper gles2; @@ -100,7 +112,7 @@ typedef struct supported */ GLint viewport_store[4]; #endif - + } CoglContext; CoglContext * @@ -111,6 +123,6 @@ _cogl_context_get_default (); CoglContext *ctxvar = _cogl_context_get_default (); \ if (ctxvar == NULL) return retval; -#define NO_RETVAL +#define NO_RETVAL #endif /* __COGL_CONTEXT_H */ diff --git a/gles/cogl-gles2-wrapper.h b/gles/cogl-gles2-wrapper.h index 5cbad279d..f45b8e635 100644 --- a/gles/cogl-gles2-wrapper.h +++ b/gles/cogl-gles2-wrapper.h @@ -369,6 +369,11 @@ void _cogl_gles2_clear_cache_for_program (CoglHandle program); glGenerateMipmap doesn't need to do anything */ #define cogl_wrap_glGenerateMipmap(x) ((void) 0) +/* 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 /* HAVE_COGL_GLES2 */ G_END_DECLS diff --git a/gles/cogl-internal.h b/gles/cogl-internal.h index c17c5e24f..786e80f84 100644 --- a/gles/cogl-internal.h +++ b/gles/cogl-internal.h @@ -75,13 +75,10 @@ const char *_cogl_error_string(GLenum errorCode); #endif /* COGL_DEBUG */ #define COGL_ENABLE_BLEND (1<<1) -#define COGL_ENABLE_TEXTURE_2D (1<<2) -#define COGL_ENABLE_ALPHA_TEST (1<<3) -#define COGL_ENABLE_TEXTURE_RECT (1<<4) -#define COGL_ENABLE_VERTEX_ARRAY (1<<5) -#define COGL_ENABLE_TEXCOORD_ARRAY (1<<6) -#define COGL_ENABLE_COLOR_ARRAY (1<<7) -#define COGL_ENABLE_BACKFACE_CULLING (1<<8) +#define COGL_ENABLE_ALPHA_TEST (1<<2) +#define COGL_ENABLE_VERTEX_ARRAY (1<<3) +#define COGL_ENABLE_COLOR_ARRAY (1<<4) +#define COGL_ENABLE_BACKFACE_CULLING (1<<5) gint _cogl_get_format_bpp (CoglPixelFormat format); diff --git a/gles/cogl-primitives.c b/gles/cogl-primitives.c index dad130f53..b17cd389d 100644 --- a/gles/cogl-primitives.c +++ b/gles/cogl-primitives.c @@ -38,30 +38,9 @@ #define _COGL_MAX_BEZ_RECURSE_DEPTH 16 -void -_cogl_rectangle (float x, - float y, - float width, - float height) -{ - GLfloat rect_verts[8] = { - (GLfloat) x, (GLfloat) y, - (GLfloat) (x + width), (GLfloat) y, - (GLfloat) x, (GLfloat) (y + height), - (GLfloat) (x + width), (GLfloat) (y + height) - }; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - cogl_enable (COGL_ENABLE_VERTEX_ARRAY - | (ctx->color_alpha < 255 ? COGL_ENABLE_BLEND : 0)); - GE ( glVertexPointer (2, GL_FLOAT, 0, rect_verts ) ); - GE ( glDrawArrays (GL_TRIANGLE_STRIP, 0, 4) ); -} - void _cogl_path_add_node (gboolean new_sub_path, - float x, + float x, float y) { CoglPathNode new_node; @@ -96,22 +75,27 @@ _cogl_path_add_node (gboolean new_sub_path, void _cogl_path_stroke_nodes () { - guint path_start = 0; + guint path_start = 0; + gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY; _COGL_GET_CONTEXT (ctx, NO_RETVAL); - cogl_enable (COGL_ENABLE_VERTEX_ARRAY - | (ctx->color_alpha < 255 - ? COGL_ENABLE_BLEND : 0)); + 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); while (path_start < ctx->path_nodes->len) { CoglPathNode *path = &g_array_index (ctx->path_nodes, CoglPathNode, path_start); - GE( glVertexPointer (2, GL_FIXED, sizeof (CoglPathNode), - (guchar *) path - + G_STRUCT_OFFSET (CoglPathNode, x)) ); + GE( glVertexPointer (2, GL_FLOAT, sizeof (CoglPathNode), + (guchar *) path + + G_STRUCT_OFFSET (CoglPathNode, x)) ); GE( glDrawArrays (GL_LINE_STRIP, 0, path->path_size) ); path_start += path->path_size; @@ -145,12 +129,22 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, CoglPathNode *path, gboolean merge) { - guint path_start = 0; - guint sub_path_num = 0; - float bounds_x; - float bounds_y; - float bounds_w; - float bounds_h; + guint path_start = 0; + guint sub_path_num = 0; + float bounds_x; + float bounds_y; + float bounds_w; + float bounds_h; + gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY; + + _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); + + enable_flags |= + cogl_material_get_cogl_enable_flags (ctx->source_material); + cogl_enable (enable_flags); _cogl_path_get_bounds (nodes_min, nodes_max, &bounds_x, &bounds_y, &bounds_w, &bounds_h); @@ -175,11 +169,9 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, while (path_start < path_size) { - cogl_enable (COGL_ENABLE_VERTEX_ARRAY); - - GE( glVertexPointer (2, GL_FIXED, sizeof (CoglPathNode), - (guchar *) path - + G_STRUCT_OFFSET (CoglPathNode, x)) ); + GE( glVertexPointer (2, GL_FLOAT, sizeof (CoglPathNode), + (guchar *) path + + G_STRUCT_OFFSET (CoglPathNode, x)) ); GE( glDrawArrays (GL_TRIANGLE_FAN, 0, path->path_size) ); if (sub_path_num > 0) @@ -255,7 +247,7 @@ _cogl_path_fill_nodes_scanlines (CoglPathNode *path, _COGL_GET_CONTEXT (ctx, NO_RETVAL); /* clear scanline intersection lists */ - for (i=0; i < bounds_h; i++) + for (i=0; i < bounds_h; i++) scanlines[i]=NULL; first_x = prev_x = (path->x); @@ -444,4 +436,3 @@ _cogl_path_fill_nodes () } } } - diff --git a/gles/cogl-texture-private.h b/gles/cogl-texture-private.h index 5174c3cde..59bcad108 100644 --- a/gles/cogl-texture-private.h +++ b/gles/cogl-texture-private.h @@ -28,11 +28,9 @@ #include "cogl-bitmap.h" -typedef struct _CoglTexture CoglTexture; -typedef struct _CoglTexSliceSpan CoglTexSliceSpan; -typedef struct _CoglSpanIter CoglSpanIter; -typedef struct _CoglMultiTexture CoglMultiTexture; -typedef struct _CoglMultiTextureLayer CoglMultiTextureLayer; +typedef struct _CoglTexture CoglTexture; +typedef struct _CoglTexSliceSpan CoglTexSliceSpan; +typedef struct _CoglSpanIter CoglSpanIter; struct _CoglTexSliceSpan { @@ -61,26 +59,23 @@ struct _CoglTexture gboolean auto_mipmap; }; -struct _CoglMultiTextureLayer +/* To improve batching of geometry when submitting vertices to OpenGL we + * log the texture rectangles we want to draw to a journal, so when we + * later flush the journal we aim to batch data, and gl draw calls. */ +typedef struct _CoglJournalEntry { - guint ref_count; - guint index; /*!< lowest index is blended first then others - on top */ - CoglTexture *tex; /*!< The texture for this layer, or NULL - for an empty layer */ - - /* TODO: Add more control over the texture environment for each texture - * unit. For example we should support dot3 normal mapping. */ -}; - -struct _CoglMultiTexture -{ - guint ref_count; - GList *layers; -}; + CoglHandle material; + gint n_layers; + guint32 fallback_mask; + GLuint layer0_override_texture; +} CoglJournalEntry; CoglTexture* _cogl_texture_pointer_from_handle (CoglHandle handle); -#endif /* __COGL_TEXTURE_H */ +gboolean +_cogl_texture_span_has_waste (CoglTexture *tex, + gint x_span_index, + gint y_span_index); +#endif /* __COGL_TEXTURE_H */ diff --git a/gles/cogl-texture.c b/gles/cogl-texture.c index e461dbcf0..ec51c6382 100644 --- a/gles/cogl-texture.c +++ b/gles/cogl-texture.c @@ -53,6 +53,25 @@ printf("err: 0x%x\n", err); \ } */ +#ifdef HAVE_COGL_GL + +#define glDrawRangeElements ctx->pf_glDrawRangeElements + +#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 + +static void _cogl_journal_flush (void); + +static void _cogl_texture_free (CoglTexture *tex); + +COGL_HANDLE_DEFINE (Texture, texture, texture_handles); + struct _CoglSpanIter { gint index; @@ -70,10 +89,6 @@ struct _CoglSpanIter gboolean intersects; }; -static void _cogl_texture_free (CoglTexture *tex); - -COGL_HANDLE_DEFINE (Texture, texture, texture_handles); - static void _cogl_texture_bitmap_free (CoglTexture *tex) { @@ -383,119 +398,81 @@ _cogl_texture_upload_to_gl (CoglTexture *tex) static void _cogl_texture_draw_and_read (CoglTexture *tex, CoglBitmap *target_bmp, - CoglColor *back_color, GLint *viewport) { - gint bpp; + gint bpp; float rx1, ry1; float rx2, ry2; float tx1, ty1; float tx2, ty2; - int bw, bh; - CoglBitmap rect_bmp; - CoglHandle handle; + int bw, bh; + CoglBitmap rect_bmp; + CoglHandle handle; handle = _cogl_texture_handle_from_pointer (tex); bpp = _cogl_get_format_bpp (COGL_PIXEL_FORMAT_RGBA_8888); - /* If whole image fits into the viewport and target buffer - has got no special rowstride, we can do it in one pass */ - if (tex->bitmap.width < viewport[2] - viewport[0] && - tex->bitmap.height < viewport[3] - viewport[1] && - tex->bitmap.rowstride == bpp * tex->bitmap.width) + ry1 = 0; ry2 = 0; + ty1 = 0; ty2 = 0; + + /* Walk Y axis until whole bitmap height consumed */ + for (bh = tex->bitmap.height; bh > 0; bh -= viewport[3]) { - /* Clear buffer with transparent black, draw with white - for direct copy to framebuffer */ - cogl_paint_init (back_color); + /* Rectangle Y coords */ + ry1 = ry2; + ry2 += (bh < viewport[3]) ? bh : viewport[3]; - /* Draw the texture image */ - cogl_texture_rectangle (handle, - 0, 0, - (float)(tex->bitmap.width), - (float)(tex->bitmap.height), - 0, 0, 1.0, 1.0); + /* Normalized texture Y coords */ + ty1 = ty2; + ty2 = (ry2 / (float)tex->bitmap.height); - /* Read into target bitmap */ - prep_for_gl_pixels_download (tex->bitmap.rowstride); - GE( glReadPixels (viewport[0], viewport[1], - tex->bitmap.width, - tex->bitmap.height, - GL_RGBA, GL_UNSIGNED_BYTE, - target_bmp->data) ); - } - else - { - ry1 = 0; ry2 = 0; - ty1 = 0; ty2 = 0; + rx1 = 0; rx2 = 0; + tx1 = 0; tx2 = 0; -#define CFIX (float) - - /* Walk Y axis until whole bitmap height consumed */ - for (bh = tex->bitmap.height; bh > 0; bh -= viewport[3]) + /* Walk X axis until whole bitmap width consumed */ + for (bw = tex->bitmap.width; bw > 0; bw-=viewport[2]) { - /* Rectangle Y coords */ - ry1 = ry2; - ry2 += (bh < viewport[3]) ? bh : viewport[3]; + /* Rectangle X coords */ + rx1 = rx2; + rx2 += (bw < viewport[2]) ? bw : viewport[2]; - /* Normalized texture Y coords */ - ty1 = ty2; - ty2 = (CFIX (ry2) / CFIX (tex->bitmap.height)); + /* Normalized texture X coords */ + tx1 = tx2; + tx2 = (rx2 / (float)tex->bitmap.width); - rx1 = 0; rx2 = 0; - tx1 = 0; tx2 = 0; + /* Draw a portion of texture */ + cogl_rectangle_with_texture_coords (0, 0, + rx2 - rx1, + ry2 - ry1, + tx1, ty1, + tx2, ty2); - /* Walk X axis until whole bitmap width consumed */ - for (bw = tex->bitmap.width; bw > 0; bw-=viewport[2]) - { - /* Rectangle X coords */ - rx1 = rx2; - rx2 += (bw < viewport[2]) ? bw : viewport[2]; + /* Read into a temporary bitmap */ + rect_bmp.format = COGL_PIXEL_FORMAT_RGBA_8888; + rect_bmp.width = rx2 - rx1; + rect_bmp.height = ry2 - ry1; + rect_bmp.rowstride = bpp * rect_bmp.width; + rect_bmp.data = (guchar*) g_malloc (rect_bmp.rowstride * + rect_bmp.height); - /* Normalized texture X coords */ - tx1 = tx2; - tx2 = (CFIX (rx2) / CFIX (tex->bitmap.width)); + prep_for_gl_pixels_download (rect_bmp.rowstride); + GE( glReadPixels (viewport[0], viewport[1], + rect_bmp.width, + rect_bmp.height, + GL_RGBA, GL_UNSIGNED_BYTE, + rect_bmp.data) ); - /* Clear buffer with transparent black, draw with white - for direct copy to framebuffer */ - cogl_paint_init (back_color); + /* Copy to target bitmap */ + _cogl_bitmap_copy_subregion (&rect_bmp, + target_bmp, + 0,0, + rx1,ry1, + rect_bmp.width, + rect_bmp.height); - /* Draw a portion of texture */ - cogl_texture_rectangle (handle, - 0, 0, - CFIX (rx2 - rx1), - CFIX (ry2 - ry1), - tx1, ty1, - tx2, ty2); - - /* Read into a temporary bitmap */ - rect_bmp.format = COGL_PIXEL_FORMAT_RGBA_8888; - rect_bmp.width = rx2 - rx1; - rect_bmp.height = ry2 - ry1; - rect_bmp.rowstride = bpp * rect_bmp.width; - rect_bmp.data = (guchar*) g_malloc (rect_bmp.rowstride * - rect_bmp.height); - - prep_for_gl_pixels_download (rect_bmp.rowstride); - GE( glReadPixels (viewport[0], viewport[1], - rect_bmp.width, - rect_bmp.height, - GL_RGBA, GL_UNSIGNED_BYTE, - rect_bmp.data) ); - - /* Copy to target bitmap */ - _cogl_bitmap_copy_subregion (&rect_bmp, - target_bmp, - 0,0, - rx1,ry1, - rect_bmp.width, - rect_bmp.height); - - /* Free temp bitmap */ - g_free (rect_bmp.data); - } + /* Free temp bitmap */ + g_free (rect_bmp.data); } - -#undef CFIX } } @@ -507,14 +484,10 @@ _cogl_texture_download_from_gl (CoglTexture *tex, { gint bpp; GLint viewport[4]; - CoglColor cwhite; CoglBitmap alpha_bmp; - COGLenum old_src_factor; - COGLenum old_dst_factor; _COGL_GET_CONTEXT (ctx, FALSE); - cogl_color_set_from_4ub (&cwhite, 0xff, 0xff, 0xff, 0xff); bpp = _cogl_get_format_bpp (COGL_PIXEL_FORMAT_RGBA_8888); @@ -545,15 +518,37 @@ _cogl_texture_download_from_gl (CoglTexture *tex, /* Draw to all channels */ cogl_draw_buffer (COGL_WINDOW_BUFFER | COGL_MASK_BUFFER, 0); - /* Store old blending factors */ - old_src_factor = ctx->blend_src_factor; - old_dst_factor = ctx->blend_dst_factor; - /* Direct copy operation */ - cogl_set_source_color (&cwhite); - cogl_blend_func (CGL_ONE, CGL_ZERO); - _cogl_texture_draw_and_read (tex, target_bmp, - &cwhite, viewport); + + 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_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_texture_draw_and_read (tex, target_bmp, viewport); /* Check whether texture has alpha and framebuffer not */ /* FIXME: For some reason even if ALPHA_BITS is 8, the framebuffer @@ -585,9 +580,14 @@ _cogl_texture_download_from_gl (CoglTexture *tex, alpha_bmp.height); /* Draw alpha values into RGB channels */ - cogl_blend_func (CGL_ZERO, CGL_SRC_ALPHA); - _cogl_texture_draw_and_read (tex, &alpha_bmp, - &cwhite, viewport); + 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_texture_draw_and_read (tex, &alpha_bmp, viewport); /* Copy temp R to target A */ srcdata = alpha_bmp.data; @@ -615,7 +615,6 @@ _cogl_texture_download_from_gl (CoglTexture *tex, glPopMatrix (); cogl_draw_buffer (COGL_WINDOW_BUFFER, 0); - cogl_blend_func (old_src_factor, old_dst_factor); return TRUE; } @@ -952,6 +951,33 @@ _cogl_texture_size_supported (GLenum gl_target, return TRUE; } +static void +_cogl_texture_set_wrap_mode_parameter (CoglTexture *tex, + GLenum wrap_mode) +{ + /* Only set the wrap mode if it's different from the current + value to avoid too many GL calls */ + if (tex->wrap_mode != wrap_mode) + { + int i; + + /* Any queued texture rectangles may be depending on the previous + * wrap mode... */ + _cogl_journal_flush (); + + for (i = 0; i < tex->slice_gl_handles->len; i++) + { + GLuint texnum = g_array_index (tex->slice_gl_handles, GLuint, i); + + GE( glBindTexture (tex->gl_target, texnum) ); + GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S, wrap_mode) ); + GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_T, wrap_mode) ); + } + + tex->wrap_mode = wrap_mode; + } +} + static gboolean _cogl_texture_slices_create (CoglTexture *tex) { @@ -1079,13 +1105,8 @@ _cogl_texture_slices_create (CoglTexture *tex) g_array_set_size (tex->slice_gl_handles, n_slices); - - /* Hardware repeated tiling if supported, else tile in software*/ - if (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT) - && n_slices == 1) - tex->wrap_mode = GL_REPEAT; - else - tex->wrap_mode = GL_CLAMP_TO_EDGE; + /* Wrap mode not yet set */ + tex->wrap_mode = GL_FALSE; /* Generate a "working set" of GL texture objects * (some implementations might supported faster @@ -1159,6 +1180,20 @@ _cogl_texture_slices_free (CoglTexture *tex) } } +gboolean +_cogl_texture_span_has_waste (CoglTexture *tex, + gint x_span_index, + gint y_span_index) +{ + CoglTexSliceSpan *x_span; + CoglTexSliceSpan *y_span; + + x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x_span_index); + y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, y_span_index); + + return (x_span->waste || y_span->waste) ? TRUE : FALSE; +} + static gboolean _cogl_pixel_format_from_gl_internal (GLenum gl_int_format, CoglPixelFormat *out_format) @@ -1301,11 +1336,11 @@ _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, + gint max_waste, + CoglTextureFlags flags, + CoglPixelFormat internal_format) { CoglTexture *tex; gint bpp; @@ -1497,10 +1532,10 @@ cogl_texture_new_from_bitmap (CoglBitmap *bmp, CoglHandle cogl_texture_new_from_file (const gchar *filename, - gint max_waste, + gint max_waste, CoglTextureFlags flags, - CoglPixelFormat internal_format, - GError **error) + CoglPixelFormat internal_format, + GError **error) { CoglBitmap *bmp; CoglHandle handle; @@ -1647,6 +1682,9 @@ cogl_texture_new_from_foreign (GLuint gl_handle, tex->mag_filter = gl_mag_filter; tex->max_waste = 0; + /* Wrap mode not yet set */ + tex->wrap_mode = GL_FALSE; + /* Create slice arrays */ tex->slice_x_spans = g_array_sized_new (FALSE, FALSE, @@ -1673,23 +1711,6 @@ cogl_texture_new_from_foreign (GLuint gl_handle, g_array_append_val (tex->slice_gl_handles, gl_handle); - /* Force appropriate wrap parameter */ - if (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT) && - gl_target == GL_TEXTURE_2D) - { - /* Hardware repeated tiling */ - tex->wrap_mode = GL_REPEAT; - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S, GL_REPEAT) ); - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_T, GL_REPEAT) ); - } - else - { - /* Any tiling will be done in software */ - tex->wrap_mode = GL_CLAMP_TO_EDGE; - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) ); - GE( glTexParameteri (tex->gl_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) ); - } - return _cogl_texture_handle_new (tex); } @@ -2045,124 +2066,313 @@ cogl_texture_get_data (CoglHandle handle, return byte_size; } + +/****************************************************************************** + * XXX: Here ends the code that strictly implements "CoglTextures". + * + * The following consists of code for rendering rectangles and polygons. It + * might be neater to move this code somewhere else. I think everything below + * here should be implementable without access to CoglTexture internals, but + * that will at least mean exposing the cogl_span_iter_* funcs. + */ + static void -_cogl_texture_flush_vertices (void) +_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; + guint32 disable_mask; + _COGL_GET_CONTEXT (ctx, NO_RETVAL); - if (ctx->texture_vertices->len > 0) + /* 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 needed_indices; - CoglTextureGLVertex *p - = (CoglTextureGLVertex *) ctx->texture_vertices->data; + int old_len = ctx->static_indices->len; + int vert_num = old_len / 6 * 4; + GLushort *q; - /* 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 = ctx->texture_vertices->len / 4 * 6; - if (needed_indices > ctx->texture_indices->len) + /* 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) { - int old_len = ctx->texture_indices->len; - int vert_num = old_len / 6 * 4; - int i; - GLushort *q; + *(q++) = vert_num + 0; + *(q++) = vert_num + 1; + *(q++) = vert_num + 3; - /* 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->texture_indices, needed_indices); - q = &g_array_index (ctx->texture_indices, GLushort, old_len); - - for (i = old_len; - i < ctx->texture_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; - } + *(q++) = vert_num + 1; + *(q++) = vert_num + 2; + *(q++) = vert_num + 3; } - - GE( glVertexPointer (2, GL_FLOAT, - sizeof (CoglTextureGLVertex), p->v ) ); - GE( glTexCoordPointer (2, GL_FLOAT, - sizeof (CoglTextureGLVertex), p->t ) ); - - GE( cogl_gles2_wrapper_bind_texture (ctx->texture_target, - ctx->texture_current, - ctx->texture_format) ); - GE( glDrawElements (GL_TRIANGLES, - needed_indices, - GL_UNSIGNED_SHORT, - ctx->texture_indices->data) ); - - g_array_set_size (ctx->texture_vertices, 0); } + + /* XXX NB: + * Our vertex data is arranged as follows: + * 4 vertices per quad: 2 GLfloats per position, + * 2 GLfloats per tex coord * n_layers + */ + stride = 2 + 2 * batch_start->n_layers; + stride *= sizeof (GLfloat); + + 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); + + for (i = 0; i < batch_start->n_layers; i++) + { + GE (glClientActiveTexture (GL_TEXTURE0 + i)); + GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY)); + GE (glTexCoordPointer (2, GL_FLOAT, stride, vertex_pointer + 2 + 2 * i)); + } + /* XXX: Without this we get a segfault with the PVR SDK. + * We should probably be doing this for cogl/gl too though. */ + for (; i < ctx->n_texcoord_arrays_enabled; i++) + { + GE (glClientActiveTexture (GL_TEXTURE0 + i)); + GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY)); + } + ctx->n_texcoord_arrays_enabled = i + 1; + + /* 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); + + if (ctx->enable_backface_culling) + enable_flags |= COGL_ENABLE_BACKFACE_CULLING; + + enable_flags |= COGL_ENABLE_VERTEX_ARRAY; + cogl_enable (enable_flags); + + GE (glVertexPointer (2, GL_FLOAT, stride, vertex_pointer)); + + GE (glDrawRangeElements (GL_TRIANGLES, + 0, ctx->static_indices->len - 1, + 6 * batch_len, + GL_UNSIGNED_SHORT, + ctx->static_indices->data)); } static void -_cogl_texture_add_quad_vertices (GLfloat x1, GLfloat y1, - GLfloat x2, GLfloat y2, - GLfloat tx1, GLfloat ty1, - GLfloat tx2, GLfloat ty2) +_cogl_journal_flush (void) { - CoglTextureGLVertex *p; - GLushort first_vert; + GLfloat *current_vertex_pointer; + GLfloat *batch_vertex_pointer; + CoglJournalEntry *batch_start; + guint batch_len; + int i; _COGL_GET_CONTEXT (ctx, NO_RETVAL); - /* Add the four vertices of the quad to the list of queued - vertices */ - first_vert = ctx->texture_vertices->len; - g_array_set_size (ctx->texture_vertices, first_vert + 4); - p = &g_array_index (ctx->texture_vertices, CoglTextureGLVertex, first_vert); + if (ctx->journal->len == 0) + return; - p->v[0] = x1; p->v[1] = y1; - p->t[0] = tx1; p->t[1] = ty1; - p++; - p->v[0] = x1; p->v[1] = y2; - p->t[0] = tx1; p->t[1] = ty2; - p++; - p->v[0] = x2; p->v[1] = y2; - p->t[0] = tx2; p->t[1] = ty2; - p++; - p->v[0] = x2; p->v[1] = y1; - p->t[0] = tx2; p->t[1] = ty1; - p++; + /* Current non-variables / constraints: + * + * - We don't have to worry about much GL state changing between journal + * entries since currently the journal never out lasts a single call to + * _cogl_multitexture_multiple_rectangles. So the user doesn't get the + * chance to fiddle with anything. (XXX: later this will be extended at + * which point we can start logging certain state changes) + * + * - Implied from above: all entries will refer to the same material. + * + * - Although _cogl_multitexture_multiple_rectangles can cause the wrap mode + * of textures to be modified, the journal is flushed if a wrap mode is + * changed so we don't currently have to log wrap mode changes. + * + * - XXX - others? + */ + + /* TODO: "compile" the journal to find ways of batching draw calls and vertex + * data. + * + * Simple E.g. given current constraints... + * pass 0 - load all data into a single CoglVertexBuffer + * pass 1 - batch gl draw calls according to entries that use the same + * textures. + * + * We will be able to do cooler stuff here when we extend the life of + * journals beyond _cogl_multitexture_multiple_rectangles. + */ + + batch_vertex_pointer = (GLfloat *)ctx->logged_vertices->data; + batch_start = (CoglJournalEntry *)ctx->journal->data; + batch_len = 1; + + current_vertex_pointer = batch_vertex_pointer; + + for (i = 1; i < ctx->journal->len; i++) + { + CoglJournalEntry *prev_entry = + &g_array_index (ctx->journal, CoglJournalEntry, i - 1); + CoglJournalEntry *current_entry = prev_entry + 1; + gsize stride; + + /* Progress the vertex pointer */ + stride = 2 + current_entry->n_layers * 2; + current_vertex_pointer += stride; + +#warning "NB: re-enable batching" +#if 1 + /* batch rectangles using the same textures */ + if (current_entry->material == prev_entry->material && + current_entry->n_layers == prev_entry->n_layers && + current_entry->fallback_mask == prev_entry->fallback_mask && + current_entry->layer0_override_texture + == prev_entry->layer0_override_texture) + { + batch_len++; + continue; + } +#endif + + _cogl_journal_flush_quad_batch (batch_start, + batch_len, + batch_vertex_pointer); + + batch_start = current_entry; + batch_len = 1; + batch_vertex_pointer = current_vertex_pointer; + } + + /* The last batch... */ + _cogl_journal_flush_quad_batch (batch_start, + batch_len, + batch_vertex_pointer); + + + g_array_set_size (ctx->journal, 0); + g_array_set_size (ctx->logged_vertices, 0); } static void -_cogl_texture_quad_sw (CoglTexture *tex, - float x1, - float y1, - float x2, - float y2, - float tx1, - float ty1, - float tx2, - float ty2) +_cogl_journal_log_quad (float x1, + float y1, + float x2, + float y2, + CoglHandle material, + gint n_layers, + guint32 fallback_mask, + GLuint layer0_override_texture, + float *tex_coords, + guint tex_coords_len) { - CoglSpanIter iter_x , iter_y; - float tw , th; - float tqx , tqy; - float first_tx , first_ty; - float first_qx , first_qy; - float slice_tx1 , slice_ty1; - float slice_tx2 , slice_ty2; - float slice_qx1 , slice_qy1; - float slice_qx2 , slice_qy2; - GLuint gl_handle; + int stride; + int next_vert; + GLfloat *v; + int i; + int next_entry; + CoglJournalEntry *entry; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + /* The vertex data is logged into a seperate array in a layout that can be + * directly passed to OpenGL + */ + + /* We pack the vertex data as 2 (x,y) GLfloats folowed by 2 (tx,ty) GLfloats + * for each texture being used, E.g.: + * [X, Y, TX0, TY0, TX1, TY1, X, Y, TX0, TY0, X, Y, ...] + */ + stride = 2 + n_layers * 2; + + next_vert = ctx->logged_vertices->len; + g_array_set_size (ctx->logged_vertices, next_vert + 4 * stride); + v = &g_array_index (ctx->logged_vertices, GLfloat, next_vert); + + /* XXX: All the jumping around to fill in this strided buffer doesn't + * seem ideal. */ + + /* XXX: we could defer expanding the vertex data for GL until we come + * to flushing the journal. */ + + v[0] = x1; v[1] = y1; + v += stride; + v[0] = x1; v[1] = y2; + v += stride; + v[0] = x2; v[1] = y2; + v += stride; + v[0] = x2; v[1] = y1; + + for (i = 0; i < n_layers; i++) + { + GLfloat *t = + &g_array_index (ctx->logged_vertices, GLfloat, next_vert + 2 + 2 * i); + + t[0] = tex_coords[0]; t[1] = tex_coords[1]; + t += stride; + t[0] = tex_coords[0]; t[1] = tex_coords[3]; + t += stride; + t[0] = tex_coords[2]; t[1] = tex_coords[3]; + t += stride; + t[0] = tex_coords[2]; t[1] = tex_coords[1]; + } + + next_entry = ctx->journal->len; + g_array_set_size (ctx->journal, next_entry + 1); + entry = &g_array_index (ctx->journal, CoglJournalEntry, next_entry); + + entry->material = material; + entry->n_layers = n_layers; + entry->fallback_mask = fallback_mask; + entry->layer0_override_texture = layer0_override_texture; +} + +static void +_cogl_texture_sliced_quad (CoglTexture *tex, + CoglHandle material, + float x1, + float y1, + float x2, + float y2, + float tx1, + float ty1, + float tx2, + float ty2) +{ + CoglSpanIter iter_x , iter_y; + float tw , th; + float tqx , tqy; + float first_tx , first_ty; + float first_qx , first_qy; + float slice_tx1 , slice_ty1; + float slice_tx2 , slice_ty2; + float slice_qx1 , slice_qy1; + float slice_qx2 , slice_qy2; + GLuint gl_handle; _COGL_GET_CONTEXT (ctx, NO_RETVAL); #if COGL_DEBUG - printf("=== Drawing Tex Quad (Software Tiling Mode) ===\n"); + printf("=== Drawing Tex Quad (Sliced Mode) ===\n"); #endif + /* We can't use hardware repeat so we need to set clamp to edge + otherwise it might pull in edge pixels from the other side */ + _cogl_texture_set_wrap_mode_parameter (tex, GL_CLAMP_TO_EDGE); + /* If the texture coordinates are backwards then swap both the geometry and texture coordinates so that the texture will be flipped but we can still use the same algorithm to iterate the @@ -2216,6 +2426,8 @@ _cogl_texture_quad_sw (CoglTexture *tex, !_cogl_span_iter_end (&iter_y) ; _cogl_span_iter_next (&iter_y) ) { + float tex_coords[4]; + /* Discard slices out of quad early */ if (!iter_y.intersects) continue; @@ -2228,8 +2440,6 @@ _cogl_texture_quad_sw (CoglTexture *tex, slice_ty1 = iter_y.intersect_start - iter_y.pos; slice_ty2 = iter_y.intersect_end - iter_y.pos; - /* Normalize texture coordinates to current slice - (rectangle texture targets take denormalized) */ slice_ty1 /= iter_y.span->size; slice_ty2 /= iter_y.span->size; @@ -2273,156 +2483,350 @@ _cogl_texture_quad_sw (CoglTexture *tex, iter_y.index * iter_x.array->len + iter_x.index); - /* If we're using a different texture from the one already queued - then flush the vertices */ - if (ctx->texture_vertices->len > 0 - && gl_handle != ctx->texture_current) - _cogl_texture_flush_vertices (); - ctx->texture_target = tex->gl_target; - ctx->texture_current = gl_handle; - ctx->texture_format = tex->gl_intformat; - - _cogl_texture_add_quad_vertices ( (slice_qx1), - (slice_qy1), - (slice_qx2), - (slice_qy2), - (slice_tx1), - (slice_ty1), - (slice_tx2), - (slice_ty2)); + tex_coords[0] = slice_tx1; + tex_coords[1] = slice_ty1; + tex_coords[2] = slice_tx2; + tex_coords[3] = slice_ty2; + _cogl_journal_log_quad (slice_qx1, + slice_qy1, + slice_qx2, + slice_qy2, + material, + 1, /* one layer */ + 0, /* don't need to use fallbacks */ + gl_handle, /* replace the layer0 texture */ + tex_coords, + 4); } } } -static void -_cogl_texture_quad_hw (CoglTexture *tex, - float x1, - float y1, - float x2, - float y2, - float tx1, - float ty1, - float tx2, - float ty2) +static gboolean +_cogl_multitexture_unsliced_quad (float x1, + float y1, + float x2, + float y2, + CoglHandle material, + gint n_layers, + guint32 fallback_mask, + const float *user_tex_coords, + gint user_tex_coords_len) { - GLuint gl_handle; - CoglTexSliceSpan *x_span; - CoglTexSliceSpan *y_span; + float *final_tex_coords = alloca (sizeof (float) * 4 * n_layers); + const GList *layers; + GList *tmp; + int i; -#if COGL_DEBUG - printf("=== Drawing Tex Quad (Hardware Tiling Mode) ===\n"); -#endif + _COGL_GET_CONTEXT (ctx, FALSE); - _COGL_GET_CONTEXT (ctx, NO_RETVAL); + /* + * Validate the texture coordinates for this rectangle. + */ + layers = cogl_material_get_layers (material); + for (tmp = (GList *)layers, i = 0; tmp != NULL; tmp = tmp->next, i++) + { + CoglHandle layer = (CoglHandle)tmp->data; + /* CoglLayerInfo *layer_info; */ + CoglHandle tex_handle; + CoglTexture *tex; + const float *in_tex_coords; + float *out_tex_coords; + CoglTexSliceSpan *x_span; + CoglTexSliceSpan *y_span; - /* Pick and bind opengl texture object */ - gl_handle = g_array_index (tex->slice_gl_handles, GLuint, 0); + /* layer_info = &layers[i]; */ - /* If we're using a different texture from the one already queued - then flush the vertices */ - if (ctx->texture_vertices->len > 0 - && gl_handle != ctx->texture_current) - _cogl_texture_flush_vertices (); - ctx->texture_target = tex->gl_target; - ctx->texture_current = gl_handle; - ctx->texture_format = tex->gl_intformat; + /* FIXME - we shouldn't be checking this stuff if layer_info->gl_texture + * already == 0 */ - /* Don't include the waste in the texture coordinates */ - x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0); - y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0); + tex_handle = cogl_material_layer_get_texture (layer); + tex = _cogl_texture_pointer_from_handle (tex_handle); - /* Don't include the waste in the texture coordinates */ - tx1 = tx1 * (x_span->size - x_span->waste) / x_span->size; - tx2 = tx2 * (x_span->size - x_span->waste) / x_span->size; - ty1 = ty1 * (y_span->size - y_span->waste) / y_span->size; - ty2 = ty2 * (y_span->size - y_span->waste) / y_span->size; + in_tex_coords = &user_tex_coords[i * 4]; + out_tex_coords = &final_tex_coords[i * 4]; - _cogl_texture_add_quad_vertices ( (x1), - (y1), - (x2), - (y2), - (tx1), - (ty1), - (tx2), - (ty2)); + + /* If the texture has waste or we are using GL_TEXTURE_RECT we + * can't handle texture repeating so we check that the texture + * coords lie in the range [0,1]. + * + * NB: We already know that no texture matrix is being used + * if the texture has waste since we validated that early on. + * TODO: check for a texture matrix in the GL_TEXTURE_RECT + * case. + */ + if (_cogl_texture_span_has_waste (tex, 0, 0) + && (in_tex_coords[0] < 0 || in_tex_coords[0] > 1.0 + || in_tex_coords[1] < 0 || in_tex_coords[1] > 1.0 + || in_tex_coords[2] < 0 || in_tex_coords[2] > 1.0 + || in_tex_coords[3] < 0 || in_tex_coords[3] > 1.0)) + { + if (i == 0) + { + if (n_layers > 1) + { + g_warning ("Skipping layers 1..n of your material since the " + "first layer has waste and you supplied texture " + "coordinates outside the range [0,1]. We don't " + "currently support any multi-texturing using " + "textures with waste when repeating is " + "necissary so we are falling back to sliced " + "textures assuming layer 0 is the most " + "important one keep"); + } + return FALSE; + } + else + { + g_warning ("Skipping layer %d of your material " + "consisting of a texture with waste since " + "you have supplied texture coords outside " + "the range [0,1] (unsupported when " + "multi-texturing)", i); + + /* NB: marking for fallback will replace the layer with + * a default transparent texture */ + fallback_mask |= (1 << i); + } + } + + + /* + * Setup the texture unit... + */ + + /* NB: The user might not have supplied texture coordinates for all + * layers... */ + if (i < (user_tex_coords_len / 4)) + { + GLenum wrap_mode; + + /* If the texture coords are all in the range [0,1] then we want to + clamp the coords to the edge otherwise it can pull in edge pixels + from the wrong side when scaled */ + if (in_tex_coords[0] >= 0 && in_tex_coords[0] <= 1.0 + && in_tex_coords[1] >= 0 && in_tex_coords[1] <= 1.0 + && in_tex_coords[2] >= 0 && in_tex_coords[2] <= 1.0 + && in_tex_coords[3] >= 0 && in_tex_coords[3] <= 1.0) + wrap_mode = GL_CLAMP_TO_EDGE; + else + wrap_mode = GL_REPEAT; + + _cogl_texture_set_wrap_mode_parameter (tex, wrap_mode); + } + else + { + out_tex_coords[0] = 0; /* tx1 */ + out_tex_coords[1] = 0; /* ty1 */ + out_tex_coords[2] = 1.0; /* tx2 */ + out_tex_coords[3] = 1.0; /* ty2 */ + + _cogl_texture_set_wrap_mode_parameter (tex, GL_CLAMP_TO_EDGE); + } + + /* Don't include the waste in the texture coordinates */ + x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0); + y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0); + + out_tex_coords[0] = + in_tex_coords[0] * (x_span->size - x_span->waste) / x_span->size; + out_tex_coords[1] = + in_tex_coords[1] * (x_span->size - x_span->waste) / x_span->size; + out_tex_coords[2] = + in_tex_coords[2] * (y_span->size - y_span->waste) / y_span->size; + out_tex_coords[3] = + in_tex_coords[3] * (y_span->size - y_span->waste) / y_span->size; + } + + _cogl_journal_log_quad (x1, + y1, + x2, + y2, + material, + n_layers, + fallback_mask, + 0, /* don't replace the layer0 texture */ + final_tex_coords, + n_layers * 4); + + return TRUE; } -void -cogl_texture_multiple_rectangles (CoglHandle handle, - const float *verts, - guint n_rects) +struct _CoglMutiTexturedRect { - CoglTexture *tex; - gulong enable_flags = (COGL_ENABLE_VERTEX_ARRAY - | COGL_ENABLE_TEXCOORD_ARRAY - | COGL_ENABLE_TEXTURE_2D); + float x1; + float y1; + float x2; + float y2; + const float *tex_coords; + gint tex_coords_len; +}; + +static void +_cogl_rectangles_with_multitexture_coords ( + struct _CoglMutiTexturedRect *rects, + gint n_rects) +{ + CoglHandle material; + const GList *layers; + int n_layers; + const GList *tmp; + guint32 fallback_mask = 0; + gboolean all_use_sliced_quad_fallback = FALSE; + int i; _COGL_GET_CONTEXT (ctx, NO_RETVAL); - /* Check if valid texture */ - if (!cogl_is_texture (handle)) - return; - cogl_clip_ensure (); - tex = _cogl_texture_pointer_from_handle (handle); + material = ctx->source_material; - /* Make sure we got stuff to draw */ - if (tex->slice_gl_handles == NULL) - return; + layers = cogl_material_get_layers (material); + n_layers = g_list_length ((GList *)layers); - if (tex->slice_gl_handles->len == 0) - return; + /* + * Validate all the layers of the current source material... + */ - /* Prepare GL state */ - if (ctx->color_alpha < 255 - || tex->bitmap.format & COGL_A_BIT) - enable_flags |= COGL_ENABLE_BLEND; - - if (ctx->enable_backface_culling) - enable_flags |= COGL_ENABLE_BACKFACE_CULLING; - - cogl_enable (enable_flags); - - g_array_set_size (ctx->texture_vertices, 0); - - while (n_rects-- > 0) + for (tmp = layers, i = 0; tmp != NULL; tmp = tmp->next, i++) { - if (verts[4] != verts[6] && verts[5] != verts[7]) - { - /* If there is only one GL texture and either the texture is - NPOT (no waste) or all of the coordinates are in the - range [0,1] then we can use hardware tiling */ - if (tex->slice_gl_handles->len == 1 - && ((cogl_features_available (COGL_FEATURE_TEXTURE_NPOT) - && tex->gl_target == GL_TEXTURE_2D) - || (verts[4] >= 0 && verts[4] <= 1.0 - && verts[6] >= 0 && verts[6] <= 1.0 - && verts[5] >= 0 && verts[5] <= 1.0 - && verts[7] >= 0 && verts[7] <= 1.0))) - _cogl_texture_quad_hw (tex, verts[0],verts[1], verts[2],verts[3], - verts[4],verts[5], verts[6],verts[7]); - else - _cogl_texture_quad_sw (tex, verts[0],verts[1], verts[2],verts[3], - verts[4],verts[5], verts[6],verts[7]); - } + CoglHandle layer = tmp->data; + CoglHandle tex_handle = cogl_material_layer_get_texture (layer); + CoglTexture *texture = _cogl_texture_pointer_from_handle (tex_handle); + gulong flags; - verts += 8; + if (cogl_material_layer_get_type (layer) + != COGL_MATERIAL_LAYER_TYPE_TEXTURE) + continue; + + /* XXX: + * For now, if the first layer is sliced then all other layers are + * ignored since we currently don't support multi-texturing with + * sliced textures. If the first layer is not sliced then any other + * layers found to be sliced will be skipped. (with a warning) + * + * TODO: Add support for multi-texturing rectangles with sliced + * textures if no texture matrices are in use. + */ + if (cogl_texture_is_sliced (tex_handle)) + { + if (i == 0) + { + fallback_mask = ~1; /* fallback all except the first layer */ + all_use_sliced_quad_fallback = TRUE; + if (tmp->next) + { + g_warning ("Skipping layers 1..n of your material since the " + "first layer is sliced. We don't currently " + "support any multi-texturing with sliced " + "textures but assume layer 0 is the most " + "important to keep"); + } + break; + } + else + { + g_warning ("Skipping layer %d of your material consisting of a " + "sliced texture (unsuported for multi texturing)", + i); + + /* NB: marking for fallback will replace the layer with + * a default transparent texture */ + fallback_mask |= (1 << i); + continue; + } + } + + /* 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); + if (flags & COGL_MATERIAL_LAYER_FLAG_HAS_USER_MATRIX + && _cogl_texture_span_has_waste (texture, 0, 0)) + { + static gboolean shown_warning = FALSE; + if (!shown_warning) + g_warning ("Skipping layer %d of your material consisting of a " + "texture with waste since you have supplied a custom " + "texture matrix and the result may try to sample from " + "the waste area of your texture.", i); + shown_warning = TRUE; + /* NB: marking for fallback will replace the layer with + * a default transparent texture */ + fallback_mask |= (1 << i); + continue; + } } - _cogl_texture_flush_vertices (); + /* + * Emit geometry for each of the rectangles... + */ + + for (i = 0; i < n_rects; i++) + { + if (all_use_sliced_quad_fallback + || !_cogl_multitexture_unsliced_quad (rects[i].x1, rects[i].y1, + rects[i].x2, rects[i].y2, + material, + n_layers, + fallback_mask, + rects[i].tex_coords, + rects[i].tex_coords_len)) + { + const GList *layers; + CoglHandle tex_handle; + CoglTexture *texture; + + layers = cogl_material_get_layers (material); + tex_handle = + cogl_material_layer_get_texture ((CoglHandle)layers->data); + texture = _cogl_texture_pointer_from_handle (tex_handle); + _cogl_texture_sliced_quad (texture, + material, + rects[i].x1, rects[i].y1, + rects[i].x2, rects[i].y2, + rects[i].tex_coords[0], + rects[i].tex_coords[1], + rects[i].tex_coords[2], + rects[i].tex_coords[3]); + } + } + + _cogl_journal_flush (); } void -cogl_texture_rectangle (CoglHandle handle, - float x1, - float y1, - float x2, - float y2, - float tx1, - float ty1, - float tx2, - float ty2) +cogl_rectangles_with_texture_coords (const float *verts, + guint n_rects) +{ + struct _CoglMutiTexturedRect rects[n_rects]; + int i; + + for (i = 0; i < n_rects; i++) + { + rects[i].x1 = verts[i * 8]; + rects[i].y1 = verts[i * 8 + 1]; + rects[i].x2 = verts[i * 8 + 2]; + rects[i].y2 = verts[i * 8 + 3]; + /* FIXME: rect should be defined to have a const float *geom; + * instead, to avoid this copy + * rect[i].geom = &verts[n_rects * 8]; */ + rects[i].tex_coords = &verts[i * 8 + 4]; + rects[i].tex_coords_len = 4; + } + + _cogl_rectangles_with_multitexture_coords (rects, n_rects); +} + +void +cogl_rectangle_with_texture_coords (float x1, + float y1, + float x2, + float y2, + float tx1, + float ty1, + float tx2, + float ty2) { float verts[8]; @@ -2435,73 +2839,312 @@ cogl_texture_rectangle (CoglHandle handle, verts[6] = tx2; verts[7] = ty2; - cogl_texture_multiple_rectangles (handle, verts, 1); + cogl_rectangles_with_texture_coords (verts, 1); } void -cogl_texture_polygon (CoglHandle handle, - guint n_vertices, - CoglTextureVertex *vertices, - gboolean use_color) +cogl_rectangle_with_multitexture_coords (float x1, + float y1, + float x2, + float y2, + const float *user_tex_coords, + gint user_tex_coords_len) { - CoglTexture *tex; - int i; - GLuint gl_handle; - CoglTexSliceSpan *y_span, *x_span; - gulong enable_flags; - CoglTextureGLVertex *p; + struct _CoglMutiTexturedRect rect; + + rect.x1 = x1; + rect.y1 = y1; + rect.x2 = x2; + rect.y2 = y2; + rect.tex_coords = user_tex_coords; + rect.tex_coords_len = user_tex_coords_len; + + _cogl_rectangles_with_multitexture_coords (&rect, 1); +} + +static void +_cogl_texture_sliced_polygon (CoglTextureVertex *vertices, + guint n_vertices, + guint stride, + gboolean use_color) +{ + const GList *layers; + CoglHandle layer0; + CoglHandle tex_handle; + CoglTexture *tex; + CoglTexSliceSpan *y_span, *x_span; + int x, y, tex_num, i; + GLuint gl_handle; + GLfloat *v; _COGL_GET_CONTEXT (ctx, NO_RETVAL); - /* Check if valid texture */ - if (!cogl_is_texture (handle)) - return; + /* We can assume in this case that we have at least one layer in the + * material that corresponds to a sliced cogl texture */ + layers = cogl_material_get_layers (ctx->source_material); + layer0 = (CoglHandle)layers->data; + tex_handle = cogl_material_layer_get_texture (layer0); + tex = _cogl_texture_pointer_from_handle (tex_handle); + + v = (GLfloat *)ctx->logged_vertices->data; + for (i = 0; i < n_vertices; i++) + { + GLfloat *c; + + v[0] = vertices[i].x; + v[1] = vertices[i].y; + v[2] = vertices[i].z; + + /* NB: [X,Y,Z,TX,TY,R,G,B,A,...] */ + c = v + 5; + c[0] = cogl_color_get_red_byte (&vertices[i].color); + c[1] = cogl_color_get_green_byte (&vertices[i].color); + c[2] = cogl_color_get_blue_byte (&vertices[i].color); + c[3] = cogl_color_get_alpha_byte (&vertices[i].color); + + v += stride; + } + + /* Render all of the slices with the full geometry but use a + transparent border color so that any part of the texture not + covered by the slice will be ignored */ + tex_num = 0; + for (y = 0; y < tex->slice_y_spans->len; y++) + { + y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, y); + + for (x = 0; x < tex->slice_x_spans->len; x++) + { + x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x); + + gl_handle = g_array_index (tex->slice_gl_handles, GLuint, tex_num++); + + /* Convert the vertices into an array of GLfloats ready to pass to + OpenGL */ + v = (GLfloat *)ctx->logged_vertices->data; + for (i = 0; i < n_vertices; i++) + { + GLfloat *t; + float tx, ty; + + tx = ((vertices[i].tx + - ((float)(x_span->start) + / tex->bitmap.width)) + * tex->bitmap.width / x_span->size); + ty = ((vertices[i].ty + - ((float)(y_span->start) + / tex->bitmap.height)) + * tex->bitmap.height / y_span->size); + + /* NB: [X,Y,Z,TX,TY,R,G,B,A,...] */ + t = v + 3; + t[0] = tx; + t[1] = ty; + + v += stride; + } + + 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); + + GE( glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices) ); + } + } +} + + +static void +_cogl_multitexture_unsliced_polygon (CoglTextureVertex *vertices, + guint n_vertices, + guint n_layers, + guint stride, + gboolean use_color, + guint32 fallback_mask) +{ + CoglHandle material; + const GList *layers; + int i; + GList *tmp; + CoglTexSliceSpan *y_span, *x_span; + GLfloat *v; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + v = (GLfloat *)ctx->logged_vertices->data; + + material = ctx->source_material; + layers = cogl_material_get_layers (material); + + /* Convert the vertices into an array of GLfloats ready to pass to + OpenGL */ + for (v = (GLfloat *)ctx->logged_vertices->data, i = 0; + i < n_vertices; + v += stride, i++) + { + GLfloat *c; + int j; + + /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ + v[0] = vertices[i].x; + v[1] = vertices[i].y; + v[2] = vertices[i].z; + + for (tmp = (GList *)layers, j = 0; tmp != NULL; tmp = tmp->next, j++) + { + CoglHandle layer = (CoglHandle)tmp->data; + CoglHandle tex_handle; + CoglTexture *tex; + GLfloat *t; + float tx, ty; + + tex_handle = cogl_material_layer_get_texture (layer); + tex = _cogl_texture_pointer_from_handle (tex_handle); + + y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0); + x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0); + + tx = ((vertices[i].tx + - ((float)(x_span->start) + / tex->bitmap.width)) + * tex->bitmap.width / x_span->size); + ty = ((vertices[i].ty + - ((float)(y_span->start) + / tex->bitmap.height)) + * tex->bitmap.height / y_span->size); + + /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ + t = v + 3 + 2 * j; + t[0] = tx; + t[1] = ty; + } + + /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ + c = v + 3 + 2 * n_layers; + c[0] = cogl_color_get_red_float (&vertices[i].color); + c[1] = cogl_color_get_green_float (&vertices[i].color); + c[2] = cogl_color_get_blue_float (&vertices[i].color); + 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); + + GE (glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices)); +} + +void +cogl_polygon (CoglTextureVertex *vertices, + guint n_vertices, + gboolean use_color) +{ + CoglHandle material; + const GList *layers; + int n_layers; + GList *tmp; + gboolean use_sliced_polygon_fallback = FALSE; + guint32 fallback_mask = 0; + int i; + gulong enable_flags; + guint stride; + gsize stride_bytes; + GLfloat *v; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); cogl_clip_ensure (); - tex = _cogl_texture_pointer_from_handle (handle); + material = ctx->source_material; + layers = cogl_material_get_layers (ctx->source_material); + n_layers = g_list_length ((GList *)layers); - /* GL ES has no GL_CLAMP_TO_BORDER wrap mode so the method used to - render sliced textures in the GL backend will not work. Therefore - cogl_texture_polygon is only supported if the texture is not - sliced */ - if (tex->slice_gl_handles->len != 1) + for (tmp = (GList *)layers, i = 0; tmp != NULL; tmp = tmp->next, i++) { - static gboolean shown_warning = FALSE; + CoglHandle layer = (CoglHandle)tmp->data; + CoglHandle tex_handle = cogl_material_layer_get_texture (layer); + CoglTexture *tex = _cogl_texture_pointer_from_handle (tex_handle); - if (!shown_warning) - { - g_warning ("cogl_texture_polygon does not work for " - "sliced textures on GL ES"); - shown_warning = TRUE; - } - return; + if (i == 0 && cogl_texture_is_sliced (tex_handle)) + { +#if defined (HAVE_COGL_GLES) || defined (HAVE_COGL_GLES2) + { + static gboolean shown_gles_slicing_warning = FALSE; + if (!shown_gles_slicing_warning) + g_warning ("cogl_polygon does not work for sliced textures " + "on GL ES"); + shown_gles_slicing_warning = TRUE; + return; + } +#endif + if (n_layers > 1) + { + static gboolean shown_slicing_warning = FALSE; + if (!shown_slicing_warning) + { + g_warning ("Disabling layers 1..n since multi-texturing with " + "cogl_polygon isn't supported when using sliced " + "textures\n"); + shown_slicing_warning = TRUE; + } + } + use_sliced_polygon_fallback = TRUE; + n_layers = 1; + + if (tex->min_filter != GL_NEAREST || tex->mag_filter != GL_NEAREST) + { + static gboolean shown_filter_warning = FALSE; + if (!shown_filter_warning) + { + g_warning ("cogl_texture_polygon does not work for sliced textures " + "when the minification and magnification filters are not " + "CGL_NEAREST"); + shown_filter_warning = TRUE; + } + return; + } + +#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); +#endif + break; + } + + if (cogl_texture_is_sliced (tex_handle)) + { + g_warning ("Disabling layer %d of the current source material, " + "because texturing with the vertex buffer API is not " + "currently supported using sliced textures, or textures " + "with waste\n", i); + + fallback_mask |= (1 << i); + continue; + } } - /* Make sure there is enough space in the global texture vertex + /* Our data is arranged like: + * [X, Y, Z, TX0, TY0, TX1, TY1..., R, G, B, A,...] */ + stride = 3 + (2 * n_layers) + (use_color ? 4 : 0); + stride_bytes = stride * sizeof (GLfloat); + + /* Make sure there is enough space in the global vertex array. This is used so we can render the polygon with a single call to OpenGL but still support any number of vertices */ - g_array_set_size (ctx->texture_vertices, n_vertices); - p = (CoglTextureGLVertex *) ctx->texture_vertices->data; + g_array_set_size (ctx->logged_vertices, n_vertices * stride); + v = (GLfloat *)ctx->logged_vertices->data; /* Prepare GL state */ - enable_flags = (COGL_ENABLE_TEXTURE_2D - | COGL_ENABLE_VERTEX_ARRAY - | COGL_ENABLE_TEXCOORD_ARRAY); - - if ((tex->bitmap.format & COGL_A_BIT)) - enable_flags |= COGL_ENABLE_BLEND; - else if (use_color) - { - for (i = 0; i < n_vertices; i++) - if (cogl_color_get_alpha_byte(&vertices[i].color) < 255) - { - enable_flags |= COGL_ENABLE_BLEND; - break; - } - } - else if (ctx->color_alpha < 255) - enable_flags |= COGL_ENABLE_BLEND; + enable_flags = COGL_ENABLE_VERTEX_ARRAY; + enable_flags |= cogl_material_get_cogl_enable_flags (ctx->source_material); if (ctx->enable_backface_culling) enable_flags |= COGL_ENABLE_BACKFACE_CULLING; @@ -2509,219 +3152,36 @@ cogl_texture_polygon (CoglHandle handle, if (use_color) { enable_flags |= COGL_ENABLE_COLOR_ARRAY; - GE( glColorPointer (4, GL_UNSIGNED_BYTE, - sizeof (CoglTextureGLVertex), p->c) ); - } - - GE( glVertexPointer (3, GL_FLOAT, sizeof (CoglTextureGLVertex), p->v ) ); - GE( glTexCoordPointer (2, GL_FLOAT, sizeof (CoglTextureGLVertex), p->t ) ); + GE( glColorPointer (4, GL_FLOAT, + stride_bytes, + /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ + v + 3 + 2 * n_layers) ); + } cogl_enable (enable_flags); - gl_handle = g_array_index (tex->slice_gl_handles, GLuint, 0); - x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0); - y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0); + GE (glVertexPointer (3, GL_FLOAT, stride_bytes, v)); - /* Convert the vertices into an array of GLfloats ready to pass to - OpenGL */ - for (i = 0; i < n_vertices; i++, p++) + for (i = 0; i < n_layers; i++) { -#define CFX_F - - p->v[0] = CFX_F(vertices[i].x); - p->v[1] = CFX_F(vertices[i].y); - p->v[2] = CFX_F(vertices[i].z); - p->t[0] = CFX_F(vertices[i].tx - * (x_span->size - x_span->waste) / x_span->size); - p->t[1] = CFX_F(vertices[i].ty - * (y_span->size - y_span->waste) / y_span->size); - p->c[0] = cogl_color_get_red_byte(&vertices[i].color); - p->c[1] = cogl_color_get_green_byte(&vertices[i].color); - p->c[2] = cogl_color_get_blue_byte(&vertices[i].color); - p->c[3] = cogl_color_get_alpha_byte(&vertices[i].color); - -#undef CFX_F + GE (glClientActiveTexture (GL_TEXTURE0 + i)); + GE (glTexCoordPointer (2, GL_FLOAT, + stride_bytes, + /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */ + v + 3 + 2 * i)); } - GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, gl_handle, - tex->gl_intformat) ); - - GE( glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices) ); - - /* Set the last color so that the cache of the alpha value will work - properly */ - if (use_color && n_vertices > 0) - cogl_set_source_color (&vertices[n_vertices - 1].color); + if (use_sliced_polygon_fallback) + _cogl_texture_sliced_polygon (vertices, + n_vertices, + stride, + use_color); + else + _cogl_multitexture_unsliced_polygon (vertices, + n_vertices, + n_layers, + stride, + use_color, + fallback_mask); } -void -cogl_material_rectangle (CoglFixed x1, - CoglFixed y1, - CoglFixed x2, - CoglFixed y2, - const CoglFixed *user_tex_coords) -{ - CoglHandle material; - const GList *layers; - int n_layers; - const GList *tmp; - CoglHandle *valid_layers = NULL; - int n_valid_layers = 0; - gboolean handle_slicing = FALSE; - int i; - GLfloat *tex_coords_buff; - GLfloat quad_coords[8]; - gulong enable_flags = 0; - GLfloat values[4]; - - /* FIXME - currently cogl deals with enabling texturing via enable flags, - * but that can't scale to n texture units. Currently we have to be carefull - * how we leave the environment so we don't break things. See the cleanup - * notes at the end of this function */ - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - material = ctx->source_material; - - layers = cogl_material_get_layers (material); - n_layers = g_list_length ((GList *)layers); - valid_layers = alloca (sizeof (CoglHandle) * n_layers); - - for (tmp = layers; tmp != NULL; tmp = tmp->next) - { - CoglHandle layer = tmp->data; - CoglHandle texture = cogl_material_layer_get_texture (layer); - - if (cogl_material_layer_get_type (layer) - != COGL_MATERIAL_LAYER_TYPE_TEXTURE) - continue; - - /* FIXME: support sliced textures. For now if the first layer is - * sliced then all other layers are ignored, or if the first layer - * is not sliced, we ignore sliced textures in other layers. */ - if (cogl_texture_is_sliced (texture)) - { - if (n_valid_layers == 0) - { - valid_layers[n_valid_layers++] = layer; - handle_slicing = TRUE; - break; - } - continue; - } - valid_layers[n_valid_layers++] = tmp->data; - - if (n_valid_layers >= CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS) - break; - } - - /* NB: It could be that no valid texture layers were found, but - * we will still submit a non-textured rectangle in that case. */ - if (n_valid_layers) - tex_coords_buff = alloca (sizeof(GLfloat) * 8 * n_valid_layers); - - for (i = 0; i < n_valid_layers; i++) - { - CoglHandle layer = valid_layers[i]; - CoglHandle texture_handle = cogl_material_layer_get_texture (layer); - CoglTexture *texture = _cogl_texture_pointer_from_handle (texture_handle); - const CoglFixed *in_tex_coords = &user_tex_coords[i * 4]; - GLfloat *out_tex_coords = &tex_coords_buff[i * 8]; - GLuint gl_tex_handle; - GLenum gl_target; - -#define CFX_F COGL_FIXED_TO_FLOAT - /* IN LAYOUT: [ tx1:0, ty1:1, tx2:2, ty2:3 ] */ - out_tex_coords[0] = CFX_F (in_tex_coords[0]); /* tx1 */ - out_tex_coords[1] = CFX_F (in_tex_coords[1]); /* ty1 */ - out_tex_coords[2] = CFX_F (in_tex_coords[2]); /* tx2 */ - out_tex_coords[3] = CFX_F (in_tex_coords[1]); /* ty1 */ - out_tex_coords[4] = CFX_F (in_tex_coords[0]); /* tx1 */ - out_tex_coords[5] = CFX_F (in_tex_coords[3]); /* ty2 */ - out_tex_coords[6] = CFX_F (in_tex_coords[2]); /* tx2 */ - out_tex_coords[7] = CFX_F (in_tex_coords[3]); /* ty2 */ -#undef CFX_F - - /* TODO - support sliced textures */ - cogl_texture_get_gl_texture (texture, &gl_tex_handle, &gl_target); - - GE (glActiveTexture (GL_TEXTURE0 + i)); - cogl_material_layer_flush_gl_sampler_state (layer); - GE( cogl_gles2_wrapper_bind_texture (gl_target, - gl_tex_handle, - texure->gl_intformat)); - /* GE (glEnable (GL_TEXTURE_2D)); */ - - GE (glClientActiveTexture (GL_TEXTURE0 + i)); - GE (glTexCoordPointer (2, GL_FLOAT, 0, out_tex_coords)); - /* GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY)); */ - - /* FIXME - cogl only knows about one texture unit a.t.m - * (Also see cleanup note below) */ - if (i == 0) - enable_flags |= COGL_ENABLE_TEXTURE_2D | COGL_ENABLE_TEXCOORD_ARRAY; - else - { - GE (glEnable (GL_TEXTURE_2D)); - GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY)); - } - } - -#define CFX_F COGL_FIXED_TO_FLOAT - quad_coords[0] = CFX_F (x1); - quad_coords[1] = CFX_F (y1); - quad_coords[2] = CFX_F (x2); - quad_coords[3] = CFX_F (y1); - quad_coords[4] = CFX_F (x1); - quad_coords[5] = CFX_F (y2); - quad_coords[6] = CFX_F (x2); - quad_coords[7] = CFX_F (y2); -#undef CFX_F - - enable_flags |= COGL_ENABLE_VERTEX_ARRAY; - GE( glVertexPointer (2, GL_FLOAT, 0, quad_coords)); - - /* Setup the remaining GL state according to this material... */ - cogl_material_flush_gl_material_state (material); - cogl_material_flush_gl_alpha_func (material); - cogl_material_flush_gl_blend_func (material); - /* FIXME: This api is a bit yukky, ideally it will be removed if we - * re-work the cogl_enable mechanism */ - enable_flags |= cogl_material_get_cogl_enable_flags (material); - - /* FIXME - cogl only knows about one texture unit so assumes that unit 0 - * is always active...*/ - GE (glActiveTexture (GL_TEXTURE0)); - GE (glClientActiveTexture (GL_TEXTURE0)); - cogl_enable (enable_flags); - glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); - - /* FIXME - cogl doesn't currently have a way of caching the - * enable states for more than one texture unit so for now, - * we just disable anything relating to additional units once - * we are done with them. */ - for (i = 1; i < n_valid_layers; i++) - { - GE (glActiveTexture (GL_TEXTURE0 + i)); - GE (glClientActiveTexture (GL_TEXTURE0 + i)); - - GE (glDisable (GL_TEXTURE_2D)); - GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY)); - } - - /* FIXME - CoglMaterials aren't yet used pervasively throughout - * the cogl API, so we currently need to cleanup material state - * that will confuse other parts of the API. - * Other places to tweak, include the primitives API and lite - * GL wrappers like cogl_rectangle */ - values[0] = 0.2; values[1] = 0.2; values[2] = 0.2; values[3] = 1.0; - GE (glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, values)); - values[0] = 0.8; values[1] = 0.8; values[2] = 0.8; values[3] = 1.0; - GE (glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, values)); - values[0] = 0; values[1] = 0; values[2] = 0; values[3] = 1.0; - GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, values)); - values[0] = 0; values[1] = 0; values[2] = 0; values[3] = 1.0; - GE (glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, values)); - values[0] = 0; - GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS, values)); -} diff --git a/gles/cogl.c b/gles/cogl.c index bcdd18cfb..32f4c71dd 100644 --- a/gles/cogl.c +++ b/gles/cogl.c @@ -92,10 +92,10 @@ cogl_paint_init (const CoglColor *color) fprintf(stderr, "\n ============== Paint Start ================ \n"); #endif - glClearColor (cogl_color_get_red (color), - cogl_color_get_green (color), - cogl_color_get_blue (color), - 0); + GE( glClearColor (cogl_color_get_red_float (color), + cogl_color_get_green_float (color), + cogl_color_get_blue_float (color), + 0.0) ); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glDisable (GL_LIGHTING); @@ -213,10 +213,6 @@ cogl_enable (gulong flags) COGL_ENABLE_BLEND, GL_BLEND); - cogl_toggle_flag (ctx, flags, - COGL_ENABLE_TEXTURE_2D, - GL_TEXTURE_2D); - cogl_toggle_flag (ctx, flags, COGL_ENABLE_BACKFACE_CULLING, GL_CULL_FACE); @@ -225,10 +221,6 @@ cogl_enable (gulong flags) COGL_ENABLE_VERTEX_ARRAY, GL_VERTEX_ARRAY); - cogl_toggle_client_flag (ctx, flags, - COGL_ENABLE_TEXCOORD_ARRAY, - GL_TEXTURE_COORD_ARRAY); - cogl_toggle_client_flag (ctx, flags, COGL_ENABLE_COLOR_ARRAY, GL_COLOR_ARRAY); @@ -272,34 +264,11 @@ cogl_set_source_color (const CoglColor *color) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); -#if 0 /*HAVE_GLES_COLOR4UB*/ + /* In case cogl_set_source_texture was previously used... */ + cogl_material_remove_layer (ctx->default_material, 0); - /* NOTE: seems SDK_OGLES-1.1_LINUX_PCEMULATION_2.02.22.0756 has this call - * but is broken - see #857. Therefor disabling. - */ - - /* - * GLES 1.1 does actually have this function, it's in the header file but - * missing in the reference manual (and SDK): - * - * http://www.khronos.org/egl/headers/1_1/gl.h - */ - GE( glColor4ub (color->red, - color->green, - color->blue, - color->alpha) ); - - -#else - /* conversion can cause issues with picking on some gles implementations */ - GE( glColor4f (cogl_color_get_red (color), - cogl_color_get_green (color), - cogl_color_get_blue (color), - cogl_color_get_alpha (color)) ); -#endif - - /* Store alpha for proper blending enables */ - ctx->color_alpha = cogl_color_get_alpha_byte (color); + cogl_material_set_color (ctx->default_material, color); + cogl_set_source (ctx->default_material); } static void @@ -421,6 +390,8 @@ _cogl_add_stencil_clip (float x_offset, { _COGL_GET_CONTEXT (ctx, NO_RETVAL); + cogl_material_flush_gl_state (ctx->stencil_material); + if (first) { GE( glEnable (GL_STENCIL_TEST) );