diff --git a/cogl/cogl-material-arbfp.c b/cogl/cogl-material-arbfp.c index 724a5f7cb..6bf2e89f9 100644 --- a/cogl/cogl-material-arbfp.c +++ b/cogl/cogl-material-arbfp.c @@ -226,17 +226,17 @@ find_arbfp_authority (CoglMaterial *material, CoglHandle user_program) g_alloca (sizeof (CoglMaterialLayer *) * n_layers); state.i = 0; state.layers = authority0_layers; - _cogl_material_foreach_layer (authority0, - add_layer_to_array_cb, - &state); + _cogl_material_foreach_layer_internal (authority0, + add_layer_to_array_cb, + &state); authority1_layers = g_alloca (sizeof (CoglMaterialLayer *) * n_layers); state.i = 0; state.layers = authority1_layers; - _cogl_material_foreach_layer (authority1, - add_layer_to_array_cb, - &state); + _cogl_material_foreach_layer_internal (authority1, + add_layer_to_array_cb, + &state); if (layers_arbfp_would_differ (authority0_layers, authority1_layers, n_layers)) diff --git a/cogl/cogl-material-opengl.c b/cogl/cogl-material-opengl.c index 9283bb683..b3d117a50 100644 --- a/cogl/cogl-material-opengl.c +++ b/cogl/cogl-material-opengl.c @@ -833,9 +833,9 @@ _cogl_material_flush_common_gl_state (CoglMaterial *material, state.i = 0; state.layer_differences = layer_differences; - _cogl_material_foreach_layer (material, - flush_layers_common_gl_state_cb, - &state); + _cogl_material_foreach_layer_internal (material, + flush_layers_common_gl_state_cb, + &state); /* Disable additional texture units that may have previously been in use.. */ for (; state.i < ctx->texture_units->len; state.i++) @@ -1115,9 +1115,9 @@ _cogl_material_flush_gl_state (CoglMaterial *material, memset (layer_differences, 0, sizeof (layer_differences)); state.i = 0; state.layer_differences = layer_differences; - _cogl_material_foreach_layer (material, - compare_layer_differences_cb, - &state); + _cogl_material_foreach_layer_internal (material, + compare_layer_differences_cb, + &state); } /* First flush everything that's the same regardless of which @@ -1178,9 +1178,9 @@ _cogl_material_flush_gl_state (CoglMaterial *material, state.layer_differences = layer_differences; state.error_adding_layer = FALSE; state.added_layer = FALSE; - _cogl_material_foreach_layer (material, - backend_add_layer_cb, - &state); + _cogl_material_foreach_layer_internal (material, + backend_add_layer_cb, + &state); if (G_UNLIKELY (state.error_adding_layer)) continue; diff --git a/cogl/cogl-material-private.h b/cogl/cogl-material-private.h index e5e62988e..1a3915217 100644 --- a/cogl/cogl-material-private.h +++ b/cogl/cogl-material-private.h @@ -903,13 +903,13 @@ _cogl_material_layer_get_authority (CoglMaterialLayer *layer, CoglHandle _cogl_material_layer_get_texture (CoglMaterialLayer *layer); -typedef gboolean (*CoglMaterialLayerCallback) (CoglMaterialLayer *layer, - void *user_data); +typedef gboolean (*CoglMaterialInternalLayerCallback) (CoglMaterialLayer *layer, + void *user_data); void -_cogl_material_foreach_layer (CoglMaterial *material, - CoglMaterialLayerCallback callback, - void *user_data); +_cogl_material_foreach_layer_internal (CoglMaterial *material, + CoglMaterialInternalLayerCallback callback, + void *user_data); int _cogl_material_layer_get_unit_index (CoglMaterialLayer *layer); diff --git a/cogl/cogl-material.c b/cogl/cogl-material.c index 477238f07..216914e28 100644 --- a/cogl/cogl-material.c +++ b/cogl/cogl-material.c @@ -676,14 +676,12 @@ _cogl_material_update_layers_cache (CoglMaterial *material) g_warn_if_reached (); } -/* TODO: add public cogl_material_foreach_layer but instead of passing - * a CoglMaterialLayer pointer to the callback we should pass a - * layer_index instead. */ - +/* XXX: Be carefull when using this API that the callback given doesn't result + * in the layer cache being invalidated during the iteration! */ void -_cogl_material_foreach_layer (CoglMaterial *material, - CoglMaterialLayerCallback callback, - void *user_data) +_cogl_material_foreach_layer_internal (CoglMaterial *material, + CoglMaterialInternalLayerCallback callback, + void *user_data) { CoglMaterial *authority = _cogl_material_get_authority (material, COGL_MATERIAL_STATE_LAYERS); @@ -698,7 +696,53 @@ _cogl_material_foreach_layer (CoglMaterial *material, _cogl_material_update_layers_cache (authority); for (i = 0, cont = TRUE; i < n_layers && cont == TRUE; i++) - cont = callback (authority->layers_cache[i], user_data); + { + g_return_if_fail (authority->layers_cache_dirty == FALSE); + cont = callback (authority->layers_cache[i], user_data); + } +} + +typedef struct +{ + int i; + int *indices; +} AppendLayerIndexState; + +static gboolean +append_layer_index_cb (CoglMaterialLayer *layer, + void *user_data) +{ + AppendLayerIndexState *state = user_data; + state->indices[state->i++] = layer->index; + return TRUE; +} + +void +cogl_material_foreach_layer (CoglMaterial *material, + CoglMaterialLayerCallback callback, + void *user_data) +{ + CoglMaterial *authority = + _cogl_material_get_authority (material, COGL_MATERIAL_STATE_LAYERS); + AppendLayerIndexState state; + gboolean cont; + int i; + + /* XXX: We don't know what the user is going to want to do to the layers + * but any modification of layers can result in the layer graph changing + * which could confuse _cogl_material_foreach_layer_internal(). We first + * get a list of layer indices which will remain valid so long as the + * user doesn't remove layers. */ + + state.i = 0; + state.indices = g_alloca (authority->n_layers * sizeof (int)); + + _cogl_material_foreach_layer_internal (material, + append_layer_index_cb, + &state); + + for (i = 0, cont = TRUE; i < authority->n_layers && cont; i++) + cont = callback (material, state.indices[i], user_data); } static gboolean @@ -872,9 +916,9 @@ _cogl_material_needs_blending_enabled (CoglMaterial *material, * To start with that's defined by the material color which * must be fully opaque if we got this far. */ gboolean has_alpha = FALSE; - _cogl_material_foreach_layer (material, - layer_has_alpha_cb, - &has_alpha); + _cogl_material_foreach_layer_internal (material, + layer_has_alpha_cb, + &has_alpha); if (has_alpha) return TRUE; } @@ -1393,9 +1437,9 @@ _cogl_material_prune_to_n_layers (CoglMaterial *material, int n) state.keep_n = n; state.current_pos = 0; state.needs_pruning = FALSE; - _cogl_material_foreach_layer (material, - update_prune_layers_info_cb, - &state); + _cogl_material_foreach_layer_internal (material, + update_prune_layers_info_cb, + &state); material->n_layers = n; @@ -1814,7 +1858,7 @@ _cogl_material_get_layer_info (CoglMaterial *material, int n_layers = material->n_layers; int i; - /* FIXME: _cogl_material_foreach_layer now calls + /* FIXME: _cogl_material_foreach_layer_internal now calls * _cogl_material_update_layers_cache anyway so this codepath is * pointless! */ if (layer_info->ignore_shift_layers_if_found && @@ -1827,9 +1871,9 @@ _cogl_material_get_layer_info (CoglMaterial *material, * necessarily have to iterate all the layers of the material we * use a foreach_layer callback instead of updating the cache * and iterating that as below. */ - _cogl_material_foreach_layer (material, - update_layer_info_cb, - layer_info); + _cogl_material_foreach_layer_internal (material, + update_layer_info_cb, + layer_info); return; } @@ -2743,9 +2787,9 @@ _cogl_material_apply_overrides (CoglMaterial *material, state.material = material; state.fallback_layers = options->fallback_layers; - _cogl_material_foreach_layer (material, - fallback_layer_cb, - &state); + _cogl_material_foreach_layer_internal (material, + fallback_layer_cb, + &state); } if (options->flags & COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE) @@ -2756,13 +2800,13 @@ _cogl_material_apply_overrides (CoglMaterial *material, /* NB: we are overriding the first layer, but we don't know * the user's given layer_index, which is why we use - * _cogl_material_foreach_layer() here even though we know + * _cogl_material_foreach_layer_internal() here even though we know * there's only one layer. */ state.material = material; state.gl_texture = options->layer0_override_texture; - _cogl_material_foreach_layer (material, - override_layer_texture_cb, - &state); + _cogl_material_foreach_layer_internal (material, + override_layer_texture_cb, + &state); } if (options->flags & COGL_MATERIAL_FLUSH_WRAP_MODE_OVERRIDES) @@ -2772,9 +2816,9 @@ _cogl_material_apply_overrides (CoglMaterial *material, state.material = material; state.wrap_mode_overrides = &options->wrap_mode_overrides; state.i = 0; - _cogl_material_foreach_layer (material, - apply_wrap_mode_overrides_cb, - &state); + _cogl_material_foreach_layer_internal (material, + apply_wrap_mode_overrides_cb, + &state); } } @@ -5074,9 +5118,9 @@ cogl_material_get_layers (CoglMaterial *material) material->deprecated_get_layers_list = NULL; - _cogl_material_foreach_layer (material, - prepend_layer_to_list_cb, - &material->deprecated_get_layers_list); + _cogl_material_foreach_layer_internal (material, + prepend_layer_to_list_cb, + &material->deprecated_get_layers_list); material->deprecated_get_layers_list = g_list_reverse (material->deprecated_get_layers_list); @@ -5550,7 +5594,7 @@ dump_material_cb (CoglMaterialNode *node, void *user_data) } if (layers) - _cogl_material_foreach_layer (material, dump_layer_ref_cb, state); + _cogl_material_foreach_layer_internal (material, dump_layer_ref_cb, state); state_out.parent_id = material_id; diff --git a/cogl/cogl-material.h b/cogl/cogl-material.h index 11ce4e54c..75c487eb1 100644 --- a/cogl/cogl-material.h +++ b/cogl/cogl-material.h @@ -1348,6 +1348,39 @@ cogl_material_get_depth_range (CoglMaterial *material, float *near_val, float *far_val); +/** + * CoglMaterialLayerCallback: + * @material: The #CoglMaterial whos layers are being iterated + * @layer_index: The current layer index + * @user_data: The private data passed to cogl_material_foreach_layer() + * + * The callback prototype used with cogl_material_foreach_layer() for + * iterating all the layers of a @material. + * + * Since: 1.4 + * Stability: Unstable + */ +typedef gboolean (*CoglMaterialLayerCallback) (CoglMaterial *material, + int layer_index, + void *user_data); + +/** + * cogl_material_foreach_layer: + * @material: A #CoglMaterial object + * @callback: A #CoglMaterialLayerCallback to be called for each layer + * index + * @user_data: Private data that will be passed to the callback + * + * Iterates all the layer indices of the given @material. + * + * Since: 1.4 + * Stability: Unstable + */ +void +cogl_material_foreach_layer (CoglMaterial *material, + CoglMaterialLayerCallback callback, + void *user_data); + #endif /* COGL_ENABLE_EXPERIMENTAL_API */ G_END_DECLS