cogl-material: Add support for point sprites

This adds a new API call to enable point sprite coordinate generation
for a material layer:

void
cogl_material_set_layer_point_sprite_coords_enabled (CoglHandle material,
                                                     int layer_index,
                                                     gboolean enable);

There is also a corresponding get function.

Enabling point sprite coords simply sets the GL_COORD_REPLACE of the
GL_POINT_SPRITE glTexEnv when flusing the material. There is no
separate application control for glEnable(GL_POINT_SPRITE). Instead it
is left permanently enabled under the assumption that it has no affect
unless GL_COORD_REPLACE is enabled for a texture unit.

http://bugzilla.openedhand.com/show_bug.cgi?id=2047
This commit is contained in:
Neil Roberts 2010-03-22 13:33:55 +00:00 committed by Robert Bragg
parent 06b58baa10
commit da3be3df6b
10 changed files with 306 additions and 31 deletions

View File

@ -41,6 +41,11 @@
#define glActiveTexture _context->drv.pf_glActiveTexture
#endif
/* This isn't defined in the GLES headers */
#ifndef GL_POINT_SPRITE
#define GL_POINT_SPRITE 0x8861
#endif
extern void
_cogl_create_context_driver (CoglContext *context);
extern void
@ -211,6 +216,15 @@ cogl_create_context (void)
_context->atlas = NULL;
_context->atlas_texture = COGL_INVALID_HANDLE;
/* As far as I can tell, GL_POINT_SPRITE doesn't have any effect
unless GL_COORD_REPLACE is enabled for an individual
layer. Therefore it seems like it should be ok to just leave it
enabled all the time instead of having to have a set property on
each material to track whether any layers have point sprite
coords enabled */
if (cogl_features_available (COGL_FEATURE_POINT_SPRITE))
GE (glEnable (GL_POINT_SPRITE));
return TRUE;
}

View File

@ -184,7 +184,9 @@ typedef enum
COGL_MATERIAL_LAYER_STATE_COMBINE_CONSTANT = 1L<<5,
COGL_MATERIAL_LAYER_STATE_USER_MATRIX = 1L<<6,
/* COGL_MATERIAL_LAYER_STATE_TEXTURE_INTERN = 1L<<7, */
COGL_MATERIAL_LAYER_STATE_POINT_SPRITE_COORDS = 1L<<7,
/* COGL_MATERIAL_LAYER_STATE_TEXTURE_INTERN = 1L<<8, */
COGL_MATERIAL_LAYER_STATE_ALL_SPARSE =
COGL_MATERIAL_LAYER_STATE_UNIT |
@ -193,12 +195,14 @@ typedef enum
COGL_MATERIAL_LAYER_STATE_WRAP_MODES |
COGL_MATERIAL_LAYER_STATE_COMBINE |
COGL_MATERIAL_LAYER_STATE_COMBINE_CONSTANT |
COGL_MATERIAL_LAYER_STATE_USER_MATRIX,
COGL_MATERIAL_LAYER_STATE_USER_MATRIX |
COGL_MATERIAL_LAYER_STATE_POINT_SPRITE_COORDS,
COGL_MATERIAL_LAYER_STATE_NEEDS_BIG_STATE =
COGL_MATERIAL_LAYER_STATE_COMBINE |
COGL_MATERIAL_LAYER_STATE_COMBINE_CONSTANT |
COGL_MATERIAL_LAYER_STATE_USER_MATRIX
COGL_MATERIAL_LAYER_STATE_USER_MATRIX |
COGL_MATERIAL_LAYER_STATE_POINT_SPRITE_COORDS,
} CoglMaterialLayerState;
@ -219,6 +223,8 @@ typedef struct
/* The texture matrix dscribes how to transform texture coordinates */
CoglMatrix matrix;
gboolean point_sprite_coords;
} CoglMaterialLayerBigState;
struct _CoglMaterialLayer

View File

@ -72,7 +72,13 @@
#define glUseProgram ctx->drv.pf_glUseProgram
#endif
/* This isn't defined in the GLES headers */
/* These aren't defined in the GLES headers */
#ifndef GL_POINT_SPRITE
#define GL_POINT_SPRITE 0x8861
#endif
#ifndef GL_COORD_REPLACE
#define GL_COORD_REPLACE 0x8862
#endif
#ifndef GL_CLAMP_TO_BORDER
#define GL_CLAMP_TO_BORDER 0x812d
#endif
@ -1549,6 +1555,9 @@ _cogl_material_layer_initialize_state (CoglMaterialLayer *dest,
if (differences & COGL_MATERIAL_LAYER_STATE_USER_MATRIX)
dest->big_state->matrix = src->big_state->matrix;
if (differences & COGL_MATERIAL_LAYER_STATE_POINT_SPRITE_COORDS)
dest->big_state->point_sprite_coords = src->big_state->point_sprite_coords;
}
/* NB: This function will allocate a new derived layer if you are
@ -2466,6 +2475,123 @@ _cogl_material_layer_get_wrap_modes (CoglMaterialLayer *layer,
*wrap_mode_r = authority->wrap_mode_r;
}
gboolean
cogl_material_set_layer_point_sprite_coords_enabled (CoglMaterial *material,
int layer_index,
gboolean enable,
GError **error)
{
CoglMaterialLayerState change =
COGL_MATERIAL_LAYER_STATE_POINT_SPRITE_COORDS;
CoglMaterialLayer *layer;
CoglMaterialLayer *new;
CoglMaterialLayer *authority;
g_return_val_if_fail (cogl_is_material (material), FALSE);
/* Don't allow point sprite coordinates to be enabled if the driver
doesn't support it */
if (enable && !cogl_features_available (COGL_FEATURE_POINT_SPRITE))
{
if (error)
{
g_set_error (error, COGL_ERROR, COGL_ERROR_MISSING_FEATURE,
"Point sprite texture coordinates are enabled "
"for a layer but the GL driver does not support it.");
}
else
{
static gboolean warning_seen = FALSE;
if (!warning_seen)
g_warning ("Point sprite texture coordinates are enabled "
"for a layer but the GL driver does not support it.");
warning_seen = TRUE;
}
return FALSE;
}
/* Note: this will ensure that the layer exists, creating one if it
* doesn't already.
*
* Note: If the layer already existed it's possibly owned by another
* material. If the layer is created then it will be owned by
* material. */
layer = _cogl_material_get_layer (material, layer_index);
/* Now find the ancestor of the layer that is the authority for the
* state we want to change */
authority = _cogl_material_layer_get_authority (layer, change);
if (authority->big_state->point_sprite_coords == enable)
return TRUE;
new = _cogl_material_layer_pre_change_notify (material, layer, change);
if (new != layer)
layer = new;
else
{
/* If the original layer we found is currently the authority on
* the state we are changing see if we can revert to one of our
* ancestors being the authority. */
if (layer == authority && authority->parent != NULL)
{
CoglMaterialLayer *old_authority =
_cogl_material_layer_get_authority (authority->parent, change);
if (old_authority->big_state->point_sprite_coords == enable)
{
layer->differences &= ~change;
g_assert (layer->owner == material);
if (layer->differences == 0)
_cogl_material_prune_empty_layer_difference (material,
layer);
return TRUE;
}
}
}
layer->big_state->point_sprite_coords = enable;
/* If we weren't previously the authority on this state then we need
* to extended our differences mask and so it's possible that some
* of our ancestry will now become redundant, so we aim to reparent
* ourselves if that's true... */
if (layer != authority)
{
layer->differences |= change;
_cogl_material_layer_prune_redundant_ancestry (layer);
}
return TRUE;
}
gboolean
cogl_material_get_layer_point_sprite_coords_enabled (CoglMaterial *material,
int layer_index)
{
CoglMaterialLayerState change =
COGL_MATERIAL_LAYER_STATE_POINT_SPRITE_COORDS;
CoglMaterialLayer *layer;
CoglMaterialLayer *authority;
g_return_val_if_fail (cogl_is_material (material), FALSE);
/* Note: this will ensure that the layer exists, creating one if it
* doesn't already.
*
* Note: If the layer already existed it's possibly owned by another
* material. If the layer is created then it will be owned by
* material. */
layer = _cogl_material_get_layer (material, layer_index);
/* FIXME: we shouldn't ever construct a layer in a getter function */
authority = _cogl_material_layer_get_authority (layer, change);
return authority->big_state->point_sprite_coords;
}
typedef struct
{
CoglMaterial *material;
@ -2793,6 +2919,16 @@ _cogl_material_layer_user_matrix_equal (CoglMaterialLayer *authority0,
return TRUE;
}
static gboolean
_cogl_material_layer_point_sprite_coords_equal (CoglMaterialLayer *authority0,
CoglMaterialLayer *authority1)
{
CoglMaterialLayerBigState *big_state0 = authority0->big_state;
CoglMaterialLayerBigState *big_state1 = authority1->big_state;
return big_state0->point_sprite_coords == big_state1->point_sprite_coords;
}
typedef gboolean
(*CoglMaterialLayerStateComparitor) (CoglMaterialLayer *authority0,
CoglMaterialLayer *authority1);
@ -2859,6 +2995,12 @@ _cogl_material_layer_equal (CoglMaterialLayer *layer0,
_cogl_material_layer_user_matrix_equal))
return FALSE;
if (layers_difference & COGL_MATERIAL_LAYER_STATE_POINT_SPRITE_COORDS &&
!layer_state_equal (COGL_MATERIAL_LAYER_STATE_POINT_SPRITE_COORDS,
layer0, layer1,
_cogl_material_layer_point_sprite_coords_equal))
return FALSE;
return TRUE;
}
@ -4357,6 +4499,8 @@ _cogl_material_init_default_layers (void)
big_state->texture_combine_alpha_op[0] = GL_SRC_ALPHA;
big_state->texture_combine_alpha_op[1] = GL_SRC_ALPHA;
big_state->point_sprite_coords = FALSE;
cogl_matrix_init_identity (&big_state->matrix);
ctx->default_layer_0 = _cogl_material_layer_object_new (layer);
@ -5575,9 +5719,23 @@ flush_layers_common_gl_state_cb (CoglMaterialLayer *layer, void *user_data)
_cogl_matrix_stack_flush_to_gl (unit->matrix_stack, COGL_MATRIX_TEXTURE);
}
cogl_object_ref (layer);
if (unit->layer != NULL)
cogl_object_unref (unit->layer);
if (layers_difference & COGL_MATERIAL_LAYER_STATE_POINT_SPRITE_COORDS)
{
CoglMaterialState change = COGL_MATERIAL_LAYER_STATE_POINT_SPRITE_COORDS;
CoglMaterialLayer *authority =
_cogl_material_layer_get_authority (layer, change);
CoglMaterialLayerBigState *big_state = authority->big_state;
_cogl_set_active_texture_unit (unit_index);
GE (glTexEnvi (GL_POINT_SPRITE, GL_COORD_REPLACE,
big_state->point_sprite_coords));
}
cogl_handle_ref (layer);
if (unit->layer != COGL_INVALID_HANDLE)
cogl_handle_unref (unit->layer);
unit->layer = layer;
unit->layer_changes_since_flush = 0;

View File

@ -921,6 +921,50 @@ cogl_material_set_layer_filters (CoglMaterial *material,
CoglMaterialFilter min_filter,
CoglMaterialFilter mag_filter);
/**
* cogl_material_set_layer_point_sprite_coords_enabled:
* @material: a #CoglHandle to a material.
* @layer_index: the layer number to change.
* @enable: whether to enable point sprite coord generation.
* @error: A return location for a GError, or NULL to ignore errors.
*
* When rendering points, if @enable is %TRUE then the texture
* coordinates for this layer will be replaced with coordinates that
* vary from 0.0 to 1.0 across the primitive. The top left of the
* point will have the coordinates 0.0,0.0 and the bottom right will
* have 1.0,1.0. If @enable is %FALSE then the coordinates will be
* fixed for the entire point.
*
* This function will only work if %COGL_FEATURE_POINT_SPRITE is
* available. If the feature is not available then the function will
* return %FALSE and set @error.
*
* Return value: %TRUE if the function succeeds, %FALSE otherwise.
* Since: 1.4
*/
gboolean
cogl_material_set_layer_point_sprite_coords_enabled (CoglMaterial *material,
int layer_index,
gboolean enable,
GError **error);
/**
* cogl_material_get_layer_point_sprite_coords_enabled:
* @material: a #CoglHandle to a material.
* @layer_index: the layer number to check.
*
* Gets whether point sprite coordinate generation is enabled for this
* texture layer.
*
* Return value: whether the texture coordinates will be replaced with
* point sprite coordinates.
*
* Since: 1.4
*/
gboolean
cogl_material_get_layer_point_sprite_coords_enabled (CoglMaterial *material,
int layer_index);
/**
* cogl_material_set_layer_wrap_mode_s:
* @material: A #CoglMaterial object

View File

@ -248,6 +248,8 @@ typedef enum { /*< prefix=COGL_PIXEL_FORMAT >*/
* @COGL_FEATURE_TEXTURE_NPOT_REPEAT: Repeat modes other than
* %COGL_MATERIAL_WRAP_MODE_CLAMP_TO_EDGE are supported by the
* hardware.
* @COGL_FEATURE_POINT_SPRITE: Whether
* cogl_material_set_layer_point_sprite_coords_enabled() is supported.
*
* Flags for the supported features.
*
@ -271,7 +273,8 @@ typedef enum
COGL_FEATURE_DEPTH_RANGE = (1 << 14),
COGL_FEATURE_TEXTURE_NPOT_BASIC = (1 << 15),
COGL_FEATURE_TEXTURE_NPOT_MIPMAP = (1 << 16),
COGL_FEATURE_TEXTURE_NPOT_REPEAT = (1 << 17)
COGL_FEATURE_TEXTURE_NPOT_REPEAT = (1 << 17),
COGL_FEATURE_POINT_SPRITE = (1 << 18)
} CoglFeatureFlags;
/**

View File

@ -380,3 +380,10 @@ COGL_FEATURE_FUNCTION (void, glBlendEquationSeparate,
(GLenum modeRGB,
GLenum modeAlpha))
COGL_FEATURE_END ()
COGL_FEATURE_BEGIN (point_sprites, 2, 0,
"ARB\0",
"point_sprite\0",
COGL_FEATURE_POINT_SPRITE,
0)
COGL_FEATURE_END ()

View File

@ -155,6 +155,9 @@ initialize_texture_units (CoglGles2Wrapper *w)
GL_SRC_COLOR) );
GE( _cogl_wrap_glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA,
GL_SRC_COLOR) );
GE( _cogl_wrap_glTexEnvi (GL_POINT_SPRITE, GL_COORD_REPLACE,
GL_FALSE) );
}
GE( _cogl_wrap_glMatrixMode ((GLenum) prev_mode));
@ -256,6 +259,10 @@ cogl_gles2_settings_equal (const CoglGles2WrapperSettings *a,
int arg, n_args;
GLenum func;
if (tex_env_a->point_sprite_coords !=
tex_env_b->point_sprite_coords)
return FALSE;
func = tex_env_a->texture_combine_rgb_func;
if (func != tex_env_b->texture_combine_rgb_func)
@ -329,7 +336,8 @@ cogl_gles2_get_vertex_shader (const CoglGles2WrapperSettings *settings)
g_string_append (shader_source, _cogl_fixed_vertex_shader_main_start);
for (i = 0; i < COGL_GLES2_MAX_TEXTURE_UNITS; i++)
if (COGL_GLES2_TEXTURE_UNIT_IS_ENABLED (settings->texture_units, i))
if (COGL_GLES2_TEXTURE_UNIT_IS_ENABLED (settings->texture_units, i) &&
!settings->tex_env[i].point_sprite_coords)
{
g_string_append_printf (shader_source,
"transformed_tex_coord = "
@ -386,6 +394,26 @@ cogl_gles2_get_vertex_shader (const CoglGles2WrapperSettings *settings)
return shader;
}
static void
cogl_gles2_add_texture_lookup (int unit,
const char *swizzle,
GString *shader_source)
{
_COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
g_string_append_printf (shader_source, "texture2D (texture_unit[%d], ", unit);
/* If point sprite coord generation is being used then divert to the
built-in varying var for that instead of the texture
coordinates */
if (w->settings.tex_env[unit].point_sprite_coords)
g_string_append (shader_source, "gl_PointCoord");
else
g_string_append_printf (shader_source, "tex_coord[%d]", unit);
g_string_append_printf (shader_source, ").%s", swizzle);
}
static void
cogl_gles2_add_arg (int unit,
GLenum src,
@ -413,9 +441,7 @@ cogl_gles2_add_arg (int unit,
switch (src)
{
case GL_TEXTURE:
g_string_append_printf (shader_source,
"texture2D (texture_unit[%d], tex_coord[%d]).%s",
unit, unit, swizzle);
cogl_gles2_add_texture_lookup (unit, swizzle, shader_source);
break;
case GL_CONSTANT:
@ -437,12 +463,8 @@ cogl_gles2_add_arg (int unit,
default:
if (src >= GL_TEXTURE0 &&
src < GL_TEXTURE0 + COGL_GLES2_MAX_TEXTURE_UNITS)
g_string_append_printf (shader_source,
"texture2D (texture_unit[%d], "
"tex_coord[%d]).%s",
src - GL_TEXTURE0,
src - GL_TEXTURE0,
swizzle);
cogl_gles2_add_texture_lookup (src - GL_TEXTURE0,
swizzle, shader_source);
break;
}
@ -1349,8 +1371,6 @@ _cogl_wrap_glDrawElements (GLenum mode, GLsizei count, GLenum type,
void
_cogl_wrap_glTexEnvi (GLenum target, GLenum pname, GLint param)
{
if (target == GL_TEXTURE_ENV)
{
CoglGles2WrapperTexEnv *tex_env;
@ -1358,6 +1378,8 @@ _cogl_wrap_glTexEnvi (GLenum target, GLenum pname, GLint param)
tex_env = w->settings.tex_env + w->active_texture_unit;
if (target == GL_TEXTURE_ENV)
{
switch (pname)
{
case GL_COMBINE_RGB:
@ -1388,6 +1410,17 @@ _cogl_wrap_glTexEnvi (GLenum target, GLenum pname, GLint param)
break;
}
w->settings_dirty = TRUE;
}
else if (target == GL_POINT_SPRITE)
{
switch (pname)
{
case GL_COORD_REPLACE:
tex_env->point_sprite_coords = param;
break;
}
w->settings_dirty = TRUE;
}
}

View File

@ -126,6 +126,8 @@ struct _CoglGles2WrapperTexEnv
GLenum texture_combine_alpha_op[3];
GLfloat texture_combine_constant[4];
GLboolean point_sprite_coords;
};
/* NB: We get a copy of this for each fragment/vertex
@ -319,6 +321,9 @@ struct _CoglGles2WrapperShader
#define GL_MAX_TEXTURE_UNITS 0x84e2
#define GL_POINT_SPRITE 0x8861
#define GL_COORD_REPLACE 0x8862
#endif /* GL_MODELVIEW */
void _cogl_gles2_wrapper_init (CoglGles2Wrapper *wrapper);

View File

@ -107,6 +107,9 @@ _cogl_features_init (void)
flags |= COGL_FEATURE_VBOS;
/* Both GLES 1.1 and GLES 2.0 support point sprites in core */
flags |= COGL_FEATURE_POINT_SPRITE;
/* Cache features */
ctx->feature_flags = flags;
ctx->features_cached = TRUE;

View File

@ -491,6 +491,8 @@ cogl_material_remove_layer
cogl_material_set_layer_combine
cogl_material_set_layer_combine_constant
cogl_material_set_layer_matrix
cogl_material_set_layer_point_sprite_coords_enabled
cogl_material_get_layer_point_sprite_coords_enabled
cogl_material_get_layers
cogl_material_get_n_layers
CoglMaterialFilter