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
This commit is contained in:
Robert Bragg 2008-12-18 19:12:09 +00:00
parent 61b8cc1874
commit 1a8a9c4bc8
4 changed files with 121 additions and 213 deletions

View File

@ -47,12 +47,14 @@ typedef enum _CoglMaterialBlendFactor
COGL_MATERIAL_BLEND_FACTOR_DST_ALPHA = GL_DST_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_ONE_MINUS_DST_ALPHA = GL_ONE_MINUS_DST_ALPHA,
COGL_MATERIAL_BLEND_FACTOR_SRC_ALPHA_SATURATE = GL_SRC_ALPHA_SATURATE, 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_CONSTANT_COLOR = GL_CONSTANT_COLOR,
COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR = COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR =
GL_ONE_MINUS_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR,
COGL_MATERIAL_BLEND_FACTOR_CONSTANT_ALPHA = GL_CONSTANT_ALPHA, COGL_MATERIAL_BLEND_FACTOR_CONSTANT_ALPHA = GL_CONSTANT_ALPHA,
COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA = COGL_MATERIAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA =
GL_ONE_MINUS_CONSTANT_ALPHA GL_ONE_MINUS_CONSTANT_ALPHA
#endif
} CoglMaterialBlendFactor; } CoglMaterialBlendFactor;
typedef enum _CoglMaterialLayerType typedef enum _CoglMaterialLayerType

View File

@ -61,8 +61,9 @@ cogl_create_context ()
_context->texture_handles = NULL; _context->texture_handles = NULL;
_context->texture_vertices_size = 0; _context->texture_vertices_size = 0;
_context->texture_vertices = NULL; _context->texture_vertices = NULL;
_context->multi_texture_handles = NULL; _context->material_handles = NULL;
_context->multi_texture_layer_handles = NULL; _context->material_layer_handles = NULL;
_context->source_material = COGL_INVALID_HANDLE;
_context->fbo_handles = NULL; _context->fbo_handles = NULL;
_context->program_handles = NULL; _context->program_handles = NULL;

View File

@ -68,11 +68,10 @@ typedef struct
CoglTextureGLVertex *texture_vertices; CoglTextureGLVertex *texture_vertices;
gulong texture_vertices_size; gulong texture_vertices_size;
/* Multi Textures */ /* Materials */
GArray *multi_texture_handles; GArray *material_handles;
GArray *material_layer_handles;
/* Multi Texture Layers */ CoglHandle source_material;
GArray *multi_texture_layer_handles;
/* Framebuffer objects */ /* Framebuffer objects */
GArray *fbo_handles; GArray *fbo_handles;

View File

@ -32,6 +32,7 @@
#include "cogl-util.h" #include "cogl-util.h"
#include "cogl-bitmap.h" #include "cogl-bitmap.h"
#include "cogl-texture-private.h" #include "cogl-texture-private.h"
#include "cogl-material.h"
#include "cogl-context.h" #include "cogl-context.h"
#include "cogl-handle.h" #include "cogl-handle.h"
@ -52,7 +53,6 @@
#define glEnableClientState cogl_wrap_glEnableClientState #define glEnableClientState cogl_wrap_glEnableClientState
#define glDisable cogl_wrap_glDisable #define glDisable cogl_wrap_glDisable
#define glDisableClientState cogl_wrap_glDisableClientState #define glDisableClientState cogl_wrap_glDisableClientState
#define glTexEnvx cogl_wrap_glTexEnvx
#endif #endif
/* /*
@ -84,14 +84,8 @@ struct _CoglSpanIter
}; };
static void _cogl_texture_free (CoglTexture *tex); 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 (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 static void
_cogl_texture_bitmap_free (CoglTexture *tex) _cogl_texture_bitmap_free (CoglTexture *tex)
@ -2503,210 +2497,81 @@ cogl_texture_polygon (CoglHandle handle,
cogl_set_source_color (&vertices[n_vertices - 1].color); 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 void
cogl_multi_texture_layer_set_texture (CoglHandle multi_texture_handle, cogl_material_rectangle (CoglFixed x1,
guint layer_index, CoglFixed y1,
CoglHandle tex_handle) CoglFixed x2,
CoglFixed y2,
CoglFixed *user_tex_coords)
{ {
CoglMultiTexture *multi_tex; CoglHandle material;
CoglMultiTextureLayer *layer; const GList *layers;
CoglTexture *tex; 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) /* FIXME - currently cogl deals with enabling texturing via enable flags,
|| !cogl_is_texture (tex_handle)) * but that can't scale to n texture units. Currently we have to be carefull
return; * how we leave the environment so we don't break things. See the cleanup
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 */ * notes at the end of this function */
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* Check if valid multi texture */ material = ctx->source_material;
if (!cogl_is_multi_texture (multi_texture_handle))
return;
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 for (tmp = layers; tmp != NULL; tmp = tmp->next)
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; CoglHandle layer = tmp->data;
CoglHandle texture = cogl_material_layer_get_texture (layer);
/* Skip empty layers */ if (cogl_material_layer_get_type (layer)
if (!layer->tex) != COGL_MATERIAL_LAYER_TYPE_TEXTURE)
{
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; 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 (n_valid_layers == 0)
if (!shown_warning)
{ {
g_warning ("Your driver does not support enough texture layers" valid_layers[n_valid_layers++] = layer;
"to correctly handle this multi texturing"); handle_slicing = TRUE;
shown_warning = TRUE; break;
} }
/* NB: We make a best effort attempt to display as many layers as continue;
* possible. */
break;
} }
valid_layers[n_valid_layers++] = tmp->data;
if (layer->tex->bitmap.format & COGL_A_BIT) if (n_valid_layers >= CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS)
enable_flags |= COGL_ENABLE_BLEND; break;
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 /* NB: It could be that no valid texture layers were found, but
* we will still submit a non-textured rectangle in that case. */ * we will still submit a non-textured rectangle in that case. */
if (count) if (n_valid_layers)
tex_coords_buff = alloca (sizeof(GLfloat) * 8 * count); tex_coords_buff = alloca (sizeof(GLfloat) * 8 * n_valid_layers);
/* NB: valid_layers is in order, sorted by index */ for (i = 0; i < n_valid_layers; i++)
for (count = 0, tmp = valid_layers;
tmp != NULL;
count++, tmp = tmp->next)
{ {
CoglMultiTextureLayer *layer = tmp->data; CoglHandle layer = valid_layers[i];
CoglFixed *in_tex_coords = &user_tex_coords[count * 4]; CoglHandle texture_handle = cogl_material_layer_get_texture (layer);
GLfloat *out_tex_coords = &tex_coords_buff[count * 8]; CoglTexture *texture = _cogl_texture_pointer_from_handle (texture_handle);
GLenum gl_tex_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 #define CFX_F COGL_FIXED_TO_FLOAT
/* IN LAYOUT: [ tx1:0, ty1:1, tx2:2, ty2:3 ] */ /* 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 #undef CFX_F
/* TODO - support sliced textures */ /* 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 (glActiveTexture (GL_TEXTURE0 + i));
GE (glTexEnvx (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)); cogl_material_layer_flush_gl_sampler_state (layer);
GE( cogl_gles2_wrapper_bind_texture (layer->tex->gl_target, GE( cogl_gles2_wrapper_bind_texture (gl_target,
gl_tex_handle, 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 (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 /* FIXME - cogl only knows about one texture unit a.t.m
* (Also see cleanup note below) */ * (Also see cleanup note below) */
if (count == 0) if (i == 0)
{ enable_flags |= COGL_ENABLE_TEXTURE_2D | COGL_ENABLE_TEXCOORD_ARRAY;
enable_flags |= COGL_ENABLE_TEXTURE_2D | COGL_ENABLE_TEXCOORD_ARRAY;
cogl_enable (enable_flags);
}
else else
{ {
GE (glEnable (GL_TEXTURE_2D)); 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 /* FIXME - cogl doesn't currently have a way of caching the
* enable states for more than one texture unit so for now, * enable states for more than one texture unit so for now,
* we just disable anything relating to additional units once * we just disable anything relating to additional units once
* we are done with them. */ * we are done with them. */
while (--count > 0) for (i = 1; i < n_valid_layers; i++)
{ {
GE (glActiveTexture (GL_TEXTURE0 + count)); GE (glActiveTexture (GL_TEXTURE0 + i));
GE (glClientActiveTexture (GL_TEXTURE0 + count)); GE (glClientActiveTexture (GL_TEXTURE0 + i));
GE (cogl_wrap_glDisable (GL_TEXTURE_2D)); GE (glDisable (GL_TEXTURE_2D));
GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY)); 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));
}