From db6c452aaa7920c418ba90418fd047d3c53804d0 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Thu, 8 Sep 2011 00:42:22 +0100 Subject: [PATCH] pipeline: split out all layer state apis As part of an on-going effort to get cogl-pipeline.c into a more maintainable state this splits out all the apis relating just to layer state. This just leaves code relating to the core CoglPipeline and CoglPipelineLayer design left in cogl-pipeline.c. This splits out around 2k more lines from cogl-pipeline.c although we are still left with nearly 4k lines so we still have some way to go! Reviewed-by: Neil Roberts --- cogl/Makefile.am | 3 + cogl/cogl-pipeline-layer-state-private.h | 115 ++ cogl/cogl-pipeline-layer-state.c | 1664 +++++++++++++++++ cogl/cogl-pipeline-layer-state.h | 503 +++++ cogl/cogl-pipeline-private.h | 31 + cogl/cogl-pipeline.c | 1644 +--------------- cogl/cogl-pipeline.h | 433 ----- cogl/cogl.h | 1 + .../cogl-2.0-experimental/Makefile.am | 1 + doc/reference/cogl/Makefile.am | 1 + 10 files changed, 2324 insertions(+), 2072 deletions(-) create mode 100644 cogl/cogl-pipeline-layer-state-private.h create mode 100644 cogl/cogl-pipeline-layer-state.c create mode 100644 cogl/cogl-pipeline-layer-state.h diff --git a/cogl/Makefile.am b/cogl/Makefile.am index be9fd1673..c0c048b60 100644 --- a/cogl/Makefile.am +++ b/cogl/Makefile.am @@ -100,6 +100,7 @@ cogl_experimental_h = \ $(srcdir)/cogl-context.h \ $(srcdir)/cogl-pipeline.h \ $(srcdir)/cogl-pipeline-state.h \ + $(srcdir)/cogl-pipeline-layer-state.h \ $(srcdir)/cogl2-path.h \ $(srcdir)/cogl2-clip-state.h \ $(srcdir)/cogl2-experimental.h \ @@ -246,6 +247,8 @@ cogl_sources_c = \ $(srcdir)/cogl-pipeline.c \ $(srcdir)/cogl-pipeline-private.h \ $(srcdir)/cogl-pipeline-state.c \ + $(srcdir)/cogl-pipeline-layer-state-private.h \ + $(srcdir)/cogl-pipeline-layer-state.c \ $(srcdir)/cogl-pipeline-state-private.h \ $(srcdir)/cogl-pipeline-opengl.c \ $(srcdir)/cogl-pipeline-opengl-private.h \ diff --git a/cogl/cogl-pipeline-layer-state-private.h b/cogl/cogl-pipeline-layer-state-private.h new file mode 100644 index 000000000..5c0aa64d9 --- /dev/null +++ b/cogl/cogl-pipeline-layer-state-private.h @@ -0,0 +1,115 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2011 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + * + * + * Authors: + * Robert Bragg + */ + +#ifndef __COGL_PIPELINE_LAYER_STATE_PRIVATE_H +#define __COGL_PIPELINE_LAYER_STATE_PRIVATE_H + +CoglPipelineLayer * +_cogl_pipeline_set_layer_unit (CoglPipeline *required_owner, + CoglPipelineLayer *layer, + int unit_index); + +gboolean +_cogl_pipeline_layer_texture_target_equal (CoglPipelineLayer *authority0, + CoglPipelineLayer *authority1, + CoglPipelineEvalFlags flags); + +gboolean +_cogl_pipeline_layer_texture_data_equal (CoglPipelineLayer *authority0, + CoglPipelineLayer *authority1, + CoglPipelineEvalFlags flags); + +gboolean +_cogl_pipeline_layer_combine_state_equal (CoglPipelineLayer *authority0, + CoglPipelineLayer *authority1); + +gboolean +_cogl_pipeline_layer_combine_constant_equal (CoglPipelineLayer *authority0, + CoglPipelineLayer *authority1); + +gboolean +_cogl_pipeline_layer_filters_equal (CoglPipelineLayer *authority0, + CoglPipelineLayer *authority1); + +gboolean +_cogl_pipeline_layer_wrap_modes_equal (CoglPipelineLayer *authority0, + CoglPipelineLayer *authority1); + +gboolean +_cogl_pipeline_layer_user_matrix_equal (CoglPipelineLayer *authority0, + CoglPipelineLayer *authority1); + +gboolean +_cogl_pipeline_layer_point_sprite_coords_equal (CoglPipelineLayer *authority0, + CoglPipelineLayer *authority1); + +void +_cogl_pipeline_layer_hash_unit_state (CoglPipelineLayer *authority, + CoglPipelineLayer **authorities, + CoglPipelineHashState *state); + +void +_cogl_pipeline_layer_hash_texture_target_state (CoglPipelineLayer *authority, + CoglPipelineLayer **authorities, + CoglPipelineHashState *state); + +void +_cogl_pipeline_layer_hash_texture_data_state (CoglPipelineLayer *authority, + CoglPipelineLayer **authorities, + CoglPipelineHashState *state); + +void +_cogl_pipeline_layer_hash_filters_state (CoglPipelineLayer *authority, + CoglPipelineLayer **authorities, + CoglPipelineHashState *state); + +void +_cogl_pipeline_layer_hash_wrap_modes_state (CoglPipelineLayer *authority, + CoglPipelineLayer **authorities, + CoglPipelineHashState *state); + +void +_cogl_pipeline_layer_hash_combine_state (CoglPipelineLayer *authority, + CoglPipelineLayer **authorities, + CoglPipelineHashState *state); + +void +_cogl_pipeline_layer_hash_combine_constant_state (CoglPipelineLayer *authority, + CoglPipelineLayer **authorities, + CoglPipelineHashState *state); + +void +_cogl_pipeline_layer_hash_user_matrix_state (CoglPipelineLayer *authority, + CoglPipelineLayer **authorities, + CoglPipelineHashState *state); + +void +_cogl_pipeline_layer_hash_point_sprite_state (CoglPipelineLayer *authority, + CoglPipelineLayer **authorities, + CoglPipelineHashState *state); + +#endif /* __COGL_PIPELINE_LAYER_STATE_PRIVATE_H */ diff --git a/cogl/cogl-pipeline-layer-state.c b/cogl/cogl-pipeline-layer-state.c new file mode 100644 index 000000000..ae8978276 --- /dev/null +++ b/cogl/cogl-pipeline-layer-state.c @@ -0,0 +1,1664 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2008,2009,2010 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + * + * + * Authors: + * Robert Bragg + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "cogl-pipeline-private.h" +#include "cogl-blend-string.h" +#include "cogl-util.h" +#include "cogl-matrix.h" + +#include "string.h" +#if 0 +#include "cogl-context-private.h" +#include "cogl-color-private.h" + +#endif + +/* + * XXX: consider special casing layer->unit_index so it's not a sparse + * property so instead we can assume it's valid for all layer + * instances. + * - We would need to initialize ->unit_index in + * _cogl_pipeline_layer_copy (). + * + * XXX: If you use this API you should consider that the given layer + * might not be writeable and so a new derived layer will be allocated + * and modified instead. The layer modified will be returned so you + * can identify when this happens. + */ +CoglPipelineLayer * +_cogl_pipeline_set_layer_unit (CoglPipeline *required_owner, + CoglPipelineLayer *layer, + int unit_index) +{ + CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_UNIT; + CoglPipelineLayer *authority = + _cogl_pipeline_layer_get_authority (layer, change); + CoglPipelineLayer *new; + + if (authority->unit_index == unit_index) + return layer; + + new = + _cogl_pipeline_layer_pre_change_notify (required_owner, + layer, + change); + if (new != layer) + layer = new; + else + { + /* If the 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 && + _cogl_pipeline_layer_get_parent (authority) != NULL) + { + CoglPipelineLayer *parent = + _cogl_pipeline_layer_get_parent (authority); + CoglPipelineLayer *old_authority = + _cogl_pipeline_layer_get_authority (parent, change); + + if (old_authority->unit_index == unit_index) + { + layer->differences &= ~change; + return layer; + } + } + } + + layer->unit_index = unit_index; + + /* 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_pipeline_layer_prune_redundant_ancestry (layer); + } + + return layer; +} + +CoglHandle +_cogl_pipeline_layer_get_texture_real (CoglPipelineLayer *layer) +{ + CoglPipelineLayer *authority = + _cogl_pipeline_layer_get_authority (layer, + COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA); + + return authority->texture; +} + +CoglHandle +_cogl_pipeline_get_layer_texture (CoglPipeline *pipeline, + int layer_index) +{ + CoglPipelineLayer *layer = + _cogl_pipeline_get_layer (pipeline, layer_index); + return _cogl_pipeline_layer_get_texture (layer); +} + +static void +_cogl_pipeline_set_layer_texture_target (CoglPipeline *pipeline, + int layer_index, + GLenum target) +{ + CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET; + CoglPipelineLayer *layer; + CoglPipelineLayer *authority; + CoglPipelineLayer *new; + + /* 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 + * pipeline. If the layer is created then it will be owned by + * pipeline. */ + layer = _cogl_pipeline_get_layer (pipeline, layer_index); + + /* Now find the ancestor of the layer that is the authority for the + * state we want to change */ + authority = _cogl_pipeline_layer_get_authority (layer, change); + + if (target == authority->target) + return; + + new = _cogl_pipeline_layer_pre_change_notify (pipeline, 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 && + _cogl_pipeline_layer_get_parent (authority) != NULL) + { + CoglPipelineLayer *parent = + _cogl_pipeline_layer_get_parent (authority); + CoglPipelineLayer *old_authority = + _cogl_pipeline_layer_get_authority (parent, change); + + if (old_authority->target == target) + { + layer->differences &= ~change; + + g_assert (layer->owner == pipeline); + if (layer->differences == 0) + _cogl_pipeline_prune_empty_layer_difference (pipeline, + layer); + goto changed; + } + } + } + + layer->target = target; + + /* 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_pipeline_layer_prune_redundant_ancestry (layer); + } + +changed: + + _cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS); +} + +static void +_cogl_pipeline_set_layer_texture_data (CoglPipeline *pipeline, + int layer_index, + CoglHandle texture) +{ + CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA; + CoglPipelineLayer *layer; + CoglPipelineLayer *authority; + CoglPipelineLayer *new; + + /* 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 + * pipeline. If the layer is created then it will be owned by + * pipeline. */ + layer = _cogl_pipeline_get_layer (pipeline, layer_index); + + /* Now find the ancestor of the layer that is the authority for the + * state we want to change */ + authority = _cogl_pipeline_layer_get_authority (layer, change); + + if (authority->texture == texture) + return; + + new = _cogl_pipeline_layer_pre_change_notify (pipeline, 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 && + _cogl_pipeline_layer_get_parent (authority) != NULL) + { + CoglPipelineLayer *parent = + _cogl_pipeline_layer_get_parent (authority); + CoglPipelineLayer *old_authority = + _cogl_pipeline_layer_get_authority (parent, change); + + if (old_authority->texture == texture) + { + layer->differences &= ~change; + + if (layer->texture != NULL) + cogl_object_unref (layer->texture); + + g_assert (layer->owner == pipeline); + if (layer->differences == 0) + _cogl_pipeline_prune_empty_layer_difference (pipeline, + layer); + goto changed; + } + } + } + + if (texture != NULL) + cogl_object_ref (texture); + if (layer == authority && + layer->texture != NULL) + cogl_object_unref (layer->texture); + layer->texture = texture; + + /* 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_pipeline_layer_prune_redundant_ancestry (layer); + } + +changed: + + _cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS); +} + +/* A convenience for querying the target of a given texture that + * notably returns 0 for NULL textures - so we can say that a layer + * with no associated CoglTexture will have a texture target of 0. + */ +static GLenum +get_texture_target (CoglHandle texture) +{ + GLuint ignore_handle; + GLenum gl_target; + + g_return_val_if_fail (texture, 0); + + cogl_texture_get_gl_texture (texture, &ignore_handle, &gl_target); + + return gl_target; +} + +void +cogl_pipeline_set_layer_texture (CoglPipeline *pipeline, + int layer_index, + CoglHandle texture) +{ + /* For the convenience of fragend code we separate texture state + * into the "target" and the "data", and setting a layer texture + * updates both of these properties. + * + * One example for why this is helpful is that the fragends may + * cache programs they generate and want to re-use those programs + * with all pipelines having equivalent fragment processing state. + * For the sake of determining if pipelines have equivalent fragment + * processing state we don't need to compare that the same + * underlying texture objects are referenced by the pipelines but we + * do need to see if they use the same texture targets. Making this + * distinction is much simpler if they are in different state + * groups. + * + * Note: if a NULL texture is set then we leave the target unchanged + * so we can avoid needlessly invalidating any associated fragment + * program. + */ + if (texture) + _cogl_pipeline_set_layer_texture_target (pipeline, layer_index, + get_texture_target (texture)); + _cogl_pipeline_set_layer_texture_data (pipeline, layer_index, texture); +} + +void +_cogl_pipeline_set_layer_wrap_modes (CoglPipeline *pipeline, + CoglPipelineLayer *layer, + CoglPipelineLayer *authority, + CoglPipelineWrapModeInternal wrap_mode_s, + CoglPipelineWrapModeInternal wrap_mode_t, + CoglPipelineWrapModeInternal wrap_mode_p) +{ + CoglPipelineLayer *new; + CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES; + + if (authority->wrap_mode_s == wrap_mode_s && + authority->wrap_mode_t == wrap_mode_t && + authority->wrap_mode_p == wrap_mode_p) + return; + + new = _cogl_pipeline_layer_pre_change_notify (pipeline, 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 && + _cogl_pipeline_layer_get_parent (authority) != NULL) + { + CoglPipelineLayer *parent = + _cogl_pipeline_layer_get_parent (authority); + CoglPipelineLayer *old_authority = + _cogl_pipeline_layer_get_authority (parent, change); + + if (old_authority->wrap_mode_s == wrap_mode_s && + old_authority->wrap_mode_t == wrap_mode_t && + old_authority->wrap_mode_p == wrap_mode_p) + { + layer->differences &= ~change; + + g_assert (layer->owner == pipeline); + if (layer->differences == 0) + _cogl_pipeline_prune_empty_layer_difference (pipeline, + layer); + return; + } + } + } + + layer->wrap_mode_s = wrap_mode_s; + layer->wrap_mode_t = wrap_mode_t; + layer->wrap_mode_p = wrap_mode_p; + + /* 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_pipeline_layer_prune_redundant_ancestry (layer); + } +} + +static CoglPipelineWrapModeInternal +public_to_internal_wrap_mode (CoglPipelineWrapMode mode) +{ + return (CoglPipelineWrapModeInternal)mode; +} + +static CoglPipelineWrapMode +internal_to_public_wrap_mode (CoglPipelineWrapModeInternal internal_mode) +{ + g_return_val_if_fail (internal_mode != + COGL_PIPELINE_WRAP_MODE_INTERNAL_CLAMP_TO_BORDER, + COGL_PIPELINE_WRAP_MODE_AUTOMATIC); + return (CoglPipelineWrapMode)internal_mode; +} + +void +cogl_pipeline_set_layer_wrap_mode_s (CoglPipeline *pipeline, + int layer_index, + CoglPipelineWrapMode mode) +{ + CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES; + CoglPipelineLayer *layer; + CoglPipelineLayer *authority; + CoglPipelineWrapModeInternal internal_mode = + public_to_internal_wrap_mode (mode); + + g_return_if_fail (cogl_is_pipeline (pipeline)); + + /* 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 + * pipeline. If the layer is created then it will be owned by + * pipeline. */ + layer = _cogl_pipeline_get_layer (pipeline, layer_index); + + /* Now find the ancestor of the layer that is the authority for the + * state we want to change */ + authority = _cogl_pipeline_layer_get_authority (layer, change); + + _cogl_pipeline_set_layer_wrap_modes (pipeline, layer, authority, + internal_mode, + authority->wrap_mode_t, + authority->wrap_mode_p); +} + +void +cogl_pipeline_set_layer_wrap_mode_t (CoglPipeline *pipeline, + int layer_index, + CoglPipelineWrapMode mode) +{ + CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES; + CoglPipelineLayer *layer; + CoglPipelineLayer *authority; + CoglPipelineWrapModeInternal internal_mode = + public_to_internal_wrap_mode (mode); + + g_return_if_fail (cogl_is_pipeline (pipeline)); + + /* 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 + * pipeline. If the layer is created then it will be owned by + * pipeline. */ + layer = _cogl_pipeline_get_layer (pipeline, layer_index); + + /* Now find the ancestor of the layer that is the authority for the + * state we want to change */ + authority = _cogl_pipeline_layer_get_authority (layer, change); + + _cogl_pipeline_set_layer_wrap_modes (pipeline, layer, authority, + authority->wrap_mode_s, + internal_mode, + authority->wrap_mode_p); +} + +/* The rationale for naming the third texture coordinate 'p' instead + of OpenGL's usual 'r' is that 'r' conflicts with the usual naming + of the 'red' component when treating a vector as a color. Under + GLSL this is awkward because the texture swizzling for a vector + uses a single letter for each component and the names for colors, + textures and positions are synonymous. GLSL works around this by + naming the components of the texture s, t, p and q. Cogl already + effectively already exposes this naming because it exposes GLSL so + it makes sense to use that naming consistently. Another alternative + could be u, v and w. This is what Blender and Direct3D use. However + the w component conflicts with the w component of a position + vertex. */ +void +cogl_pipeline_set_layer_wrap_mode_p (CoglPipeline *pipeline, + int layer_index, + CoglPipelineWrapMode mode) +{ + CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES; + CoglPipelineLayer *layer; + CoglPipelineLayer *authority; + CoglPipelineWrapModeInternal internal_mode = + public_to_internal_wrap_mode (mode); + + g_return_if_fail (cogl_is_pipeline (pipeline)); + + /* 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 + * pipeline. If the layer is created then it will be owned by + * pipeline. */ + layer = _cogl_pipeline_get_layer (pipeline, layer_index); + + /* Now find the ancestor of the layer that is the authority for the + * state we want to change */ + authority = _cogl_pipeline_layer_get_authority (layer, change); + + _cogl_pipeline_set_layer_wrap_modes (pipeline, layer, authority, + authority->wrap_mode_s, + authority->wrap_mode_t, + internal_mode); +} + +void +cogl_pipeline_set_layer_wrap_mode (CoglPipeline *pipeline, + int layer_index, + CoglPipelineWrapMode mode) +{ + CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES; + CoglPipelineLayer *layer; + CoglPipelineLayer *authority; + CoglPipelineWrapModeInternal internal_mode = + public_to_internal_wrap_mode (mode); + + g_return_if_fail (cogl_is_pipeline (pipeline)); + + /* 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 + * pipeline. If the layer is created then it will be owned by + * pipeline. */ + layer = _cogl_pipeline_get_layer (pipeline, layer_index); + + /* Now find the ancestor of the layer that is the authority for the + * state we want to change */ + authority = _cogl_pipeline_layer_get_authority (layer, change); + + _cogl_pipeline_set_layer_wrap_modes (pipeline, layer, authority, + internal_mode, + internal_mode, + internal_mode); + /* XXX: I wonder if we should really be duplicating the mode into + * the 'r' wrap mode too? */ +} + +/* FIXME: deprecate this API */ +CoglPipelineWrapMode +_cogl_pipeline_layer_get_wrap_mode_s (CoglPipelineLayer *layer) +{ + CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES; + CoglPipelineLayer *authority; + + g_return_val_if_fail (_cogl_is_pipeline_layer (layer), FALSE); + + /* Now find the ancestor of the layer that is the authority for the + * state we want to change */ + authority = _cogl_pipeline_layer_get_authority (layer, change); + + return internal_to_public_wrap_mode (authority->wrap_mode_s); +} + +CoglPipelineWrapMode +cogl_pipeline_get_layer_wrap_mode_s (CoglPipeline *pipeline, int layer_index) +{ + CoglPipelineLayer *layer; + + g_return_val_if_fail (cogl_is_pipeline (pipeline), 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 + * pipeline. If the layer is created then it will be owned by + * pipeline. */ + layer = _cogl_pipeline_get_layer (pipeline, layer_index); + /* FIXME: we shouldn't ever construct a layer in a getter function */ + + return _cogl_pipeline_layer_get_wrap_mode_s (layer); +} + +/* FIXME: deprecate this API */ +CoglPipelineWrapMode +_cogl_pipeline_layer_get_wrap_mode_t (CoglPipelineLayer *layer) +{ + CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES; + CoglPipelineLayer *authority; + + g_return_val_if_fail (_cogl_is_pipeline_layer (layer), FALSE); + + /* Now find the ancestor of the layer that is the authority for the + * state we want to change */ + authority = _cogl_pipeline_layer_get_authority (layer, change); + + return internal_to_public_wrap_mode (authority->wrap_mode_t); +} + +CoglPipelineWrapMode +cogl_pipeline_get_layer_wrap_mode_t (CoglPipeline *pipeline, int layer_index) +{ + CoglPipelineLayer *layer; + + g_return_val_if_fail (cogl_is_pipeline (pipeline), 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 + * pipeline. If the layer is created then it will be owned by + * pipeline. */ + layer = _cogl_pipeline_get_layer (pipeline, layer_index); + /* FIXME: we shouldn't ever construct a layer in a getter function */ + + return _cogl_pipeline_layer_get_wrap_mode_t (layer); +} + +CoglPipelineWrapMode +_cogl_pipeline_layer_get_wrap_mode_p (CoglPipelineLayer *layer) +{ + CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES; + CoglPipelineLayer *authority = + _cogl_pipeline_layer_get_authority (layer, change); + + return internal_to_public_wrap_mode (authority->wrap_mode_p); +} + +CoglPipelineWrapMode +cogl_pipeline_get_layer_wrap_mode_p (CoglPipeline *pipeline, int layer_index) +{ + CoglPipelineLayer *layer; + + g_return_val_if_fail (cogl_is_pipeline (pipeline), 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 + * pipeline. If the layer is created then it will be owned by + * pipeline. */ + layer = _cogl_pipeline_get_layer (pipeline, layer_index); + + return _cogl_pipeline_layer_get_wrap_mode_p (layer); +} + +void +_cogl_pipeline_layer_get_wrap_modes (CoglPipelineLayer *layer, + CoglPipelineWrapModeInternal *wrap_mode_s, + CoglPipelineWrapModeInternal *wrap_mode_t, + CoglPipelineWrapModeInternal *wrap_mode_p) +{ + CoglPipelineLayer *authority = + _cogl_pipeline_layer_get_authority (layer, + COGL_PIPELINE_LAYER_STATE_WRAP_MODES); + + *wrap_mode_s = authority->wrap_mode_s; + *wrap_mode_t = authority->wrap_mode_t; + *wrap_mode_p = authority->wrap_mode_p; +} + +gboolean +cogl_pipeline_set_layer_point_sprite_coords_enabled (CoglPipeline *pipeline, + int layer_index, + gboolean enable, + GError **error) +{ + CoglPipelineLayerState change = + COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS; + CoglPipelineLayer *layer; + CoglPipelineLayer *new; + CoglPipelineLayer *authority; + + g_return_val_if_fail (cogl_is_pipeline (pipeline), 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_UNSUPPORTED, + "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 + * pipeline. If the layer is created then it will be owned by + * pipeline. */ + layer = _cogl_pipeline_get_layer (pipeline, layer_index); + + /* Now find the ancestor of the layer that is the authority for the + * state we want to change */ + authority = _cogl_pipeline_layer_get_authority (layer, change); + + if (authority->big_state->point_sprite_coords == enable) + return TRUE; + + new = _cogl_pipeline_layer_pre_change_notify (pipeline, 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 && + _cogl_pipeline_layer_get_parent (authority) != NULL) + { + CoglPipelineLayer *parent = + _cogl_pipeline_layer_get_parent (authority); + CoglPipelineLayer *old_authority = + _cogl_pipeline_layer_get_authority (parent, change); + + if (old_authority->big_state->point_sprite_coords == enable) + { + layer->differences &= ~change; + + g_assert (layer->owner == pipeline); + if (layer->differences == 0) + _cogl_pipeline_prune_empty_layer_difference (pipeline, + 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_pipeline_layer_prune_redundant_ancestry (layer); + } + + return TRUE; +} + +gboolean +cogl_pipeline_get_layer_point_sprite_coords_enabled (CoglPipeline *pipeline, + int layer_index) +{ + CoglPipelineLayerState change = + COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS; + CoglPipelineLayer *layer; + CoglPipelineLayer *authority; + + g_return_val_if_fail (cogl_is_pipeline (pipeline), 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 + * pipeline. If the layer is created then it will be owned by + * pipeline. */ + layer = _cogl_pipeline_get_layer (pipeline, layer_index); + /* FIXME: we shouldn't ever construct a layer in a getter function */ + + authority = _cogl_pipeline_layer_get_authority (layer, change); + + return authority->big_state->point_sprite_coords; +} + +gboolean +_cogl_pipeline_layer_texture_target_equal (CoglPipelineLayer *authority0, + CoglPipelineLayer *authority1, + CoglPipelineEvalFlags flags) +{ + return authority0->target == authority1->target; +} + +gboolean +_cogl_pipeline_layer_texture_data_equal (CoglPipelineLayer *authority0, + CoglPipelineLayer *authority1, + CoglPipelineEvalFlags flags) +{ + GLuint gl_handle0, gl_handle1; + + cogl_texture_get_gl_texture (authority0->texture, &gl_handle0, NULL); + cogl_texture_get_gl_texture (authority1->texture, &gl_handle1, NULL); + + return gl_handle0 == gl_handle1; +} + +gboolean +_cogl_pipeline_layer_combine_state_equal (CoglPipelineLayer *authority0, + CoglPipelineLayer *authority1) +{ + CoglPipelineLayerBigState *big_state0 = authority0->big_state; + CoglPipelineLayerBigState *big_state1 = authority1->big_state; + int n_args; + int i; + + if (big_state0->texture_combine_rgb_func != + big_state1->texture_combine_rgb_func) + return FALSE; + + if (big_state0->texture_combine_alpha_func != + big_state1->texture_combine_alpha_func) + return FALSE; + + n_args = + _cogl_get_n_args_for_combine_func (big_state0->texture_combine_rgb_func); + for (i = 0; i < n_args; i++) + { + if ((big_state0->texture_combine_rgb_src[i] != + big_state1->texture_combine_rgb_src[i]) || + (big_state0->texture_combine_rgb_op[i] != + big_state1->texture_combine_rgb_op[i])) + return FALSE; + } + + n_args = + _cogl_get_n_args_for_combine_func (big_state0->texture_combine_alpha_func); + for (i = 0; i < n_args; i++) + { + if ((big_state0->texture_combine_alpha_src[i] != + big_state1->texture_combine_alpha_src[i]) || + (big_state0->texture_combine_alpha_op[i] != + big_state1->texture_combine_alpha_op[i])) + return FALSE; + } + + return TRUE; +} + +gboolean +_cogl_pipeline_layer_combine_constant_equal (CoglPipelineLayer *authority0, + CoglPipelineLayer *authority1) +{ + return memcmp (authority0->big_state->texture_combine_constant, + authority1->big_state->texture_combine_constant, + sizeof (float) * 4) == 0 ? TRUE : FALSE; +} + +gboolean +_cogl_pipeline_layer_filters_equal (CoglPipelineLayer *authority0, + CoglPipelineLayer *authority1) +{ + if (authority0->mag_filter != authority1->mag_filter) + return FALSE; + if (authority0->min_filter != authority1->min_filter) + return FALSE; + + return TRUE; +} + +static gboolean +compare_wrap_mode_equal (CoglPipelineWrapMode wrap_mode0, + CoglPipelineWrapMode wrap_mode1) +{ + /* We consider AUTOMATIC to be equivalent to CLAMP_TO_EDGE because + the primitives code is expected to override this to something + else if it wants it to be behave any other way */ + if (wrap_mode0 == COGL_PIPELINE_WRAP_MODE_AUTOMATIC) + wrap_mode0 = COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE; + if (wrap_mode1 == COGL_PIPELINE_WRAP_MODE_AUTOMATIC) + wrap_mode1 = COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE; + + return wrap_mode0 == wrap_mode1; +} + +gboolean +_cogl_pipeline_layer_wrap_modes_equal (CoglPipelineLayer *authority0, + CoglPipelineLayer *authority1) +{ + if (!compare_wrap_mode_equal (authority0->wrap_mode_s, + authority1->wrap_mode_s) || + !compare_wrap_mode_equal (authority0->wrap_mode_t, + authority1->wrap_mode_t) || + !compare_wrap_mode_equal (authority0->wrap_mode_p, + authority1->wrap_mode_p)) + return FALSE; + + return TRUE; +} + +gboolean +_cogl_pipeline_layer_user_matrix_equal (CoglPipelineLayer *authority0, + CoglPipelineLayer *authority1) +{ + CoglPipelineLayerBigState *big_state0 = authority0->big_state; + CoglPipelineLayerBigState *big_state1 = authority1->big_state; + + if (!cogl_matrix_equal (&big_state0->matrix, &big_state1->matrix)) + return FALSE; + + return TRUE; +} + +gboolean +_cogl_pipeline_layer_point_sprite_coords_equal (CoglPipelineLayer *authority0, + CoglPipelineLayer *authority1) +{ + CoglPipelineLayerBigState *big_state0 = authority0->big_state; + CoglPipelineLayerBigState *big_state1 = authority1->big_state; + + return big_state0->point_sprite_coords == big_state1->point_sprite_coords; +} + +static void +setup_texture_combine_state (CoglBlendStringStatement *statement, + CoglPipelineCombineFunc *texture_combine_func, + CoglPipelineCombineSource *texture_combine_src, + CoglPipelineCombineOp *texture_combine_op) +{ + int i; + + switch (statement->function->type) + { + case COGL_BLEND_STRING_FUNCTION_REPLACE: + *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_REPLACE; + break; + case COGL_BLEND_STRING_FUNCTION_MODULATE: + *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_MODULATE; + break; + case COGL_BLEND_STRING_FUNCTION_ADD: + *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_ADD; + break; + case COGL_BLEND_STRING_FUNCTION_ADD_SIGNED: + *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_ADD_SIGNED; + break; + case COGL_BLEND_STRING_FUNCTION_INTERPOLATE: + *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_INTERPOLATE; + break; + case COGL_BLEND_STRING_FUNCTION_SUBTRACT: + *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_SUBTRACT; + break; + case COGL_BLEND_STRING_FUNCTION_DOT3_RGB: + *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_DOT3_RGB; + break; + case COGL_BLEND_STRING_FUNCTION_DOT3_RGBA: + *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_DOT3_RGBA; + break; + } + + for (i = 0; i < statement->function->argc; i++) + { + CoglBlendStringArgument *arg = &statement->args[i]; + + switch (arg->source.info->type) + { + case COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT: + texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_CONSTANT; + break; + case COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE: + texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_TEXTURE; + break; + case COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE_N: + texture_combine_src[i] = + COGL_PIPELINE_COMBINE_SOURCE_TEXTURE0 + arg->source.texture; + break; + case COGL_BLEND_STRING_COLOR_SOURCE_PRIMARY: + texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_PRIMARY_COLOR; + break; + case COGL_BLEND_STRING_COLOR_SOURCE_PREVIOUS: + texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS; + break; + default: + g_warning ("Unexpected texture combine source"); + texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_TEXTURE; + } + + if (arg->source.mask == COGL_BLEND_STRING_CHANNEL_MASK_RGB) + { + if (statement->args[i].source.one_minus) + texture_combine_op[i] = + COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_COLOR; + else + texture_combine_op[i] = COGL_PIPELINE_COMBINE_OP_SRC_COLOR; + } + else + { + if (statement->args[i].source.one_minus) + texture_combine_op[i] = + COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_ALPHA; + else + texture_combine_op[i] = COGL_PIPELINE_COMBINE_OP_SRC_ALPHA; + } + } +} + +gboolean +cogl_pipeline_set_layer_combine (CoglPipeline *pipeline, + int layer_index, + const char *combine_description, + GError **error) +{ + CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_COMBINE; + CoglPipelineLayer *authority; + CoglPipelineLayer *layer; + CoglBlendStringStatement statements[2]; + CoglBlendStringStatement split[2]; + CoglBlendStringStatement *rgb; + CoglBlendStringStatement *a; + GError *internal_error = NULL; + int count; + + g_return_val_if_fail (cogl_is_pipeline (pipeline), 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 + * pipeline. If the layer is created then it will be owned by + * pipeline. */ + layer = _cogl_pipeline_get_layer (pipeline, layer_index); + + /* Now find the ancestor of the layer that is the authority for the + * state we want to change */ + authority = _cogl_pipeline_layer_get_authority (layer, state); + + count = + _cogl_blend_string_compile (combine_description, + COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE, + statements, + &internal_error); + if (!count) + { + if (error) + g_propagate_error (error, internal_error); + else + { + g_warning ("Cannot compile combine description: %s\n", + internal_error->message); + g_error_free (internal_error); + } + return FALSE; + } + + if (statements[0].mask == COGL_BLEND_STRING_CHANNEL_MASK_RGBA) + { + _cogl_blend_string_split_rgba_statement (statements, + &split[0], &split[1]); + rgb = &split[0]; + a = &split[1]; + } + else + { + rgb = &statements[0]; + a = &statements[1]; + } + + /* FIXME: compare the new state with the current state! */ + + /* possibly flush primitives referencing the current state... */ + layer = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state); + + setup_texture_combine_state (rgb, + &layer->big_state->texture_combine_rgb_func, + layer->big_state->texture_combine_rgb_src, + layer->big_state->texture_combine_rgb_op); + + setup_texture_combine_state (a, + &layer->big_state->texture_combine_alpha_func, + layer->big_state->texture_combine_alpha_src, + layer->big_state->texture_combine_alpha_op); + + /* 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 && + _cogl_pipeline_layer_get_parent (authority) != NULL) + { + CoglPipelineLayer *parent = _cogl_pipeline_layer_get_parent (authority); + CoglPipelineLayer *old_authority = + _cogl_pipeline_layer_get_authority (parent, state); + + if (_cogl_pipeline_layer_combine_state_equal (authority, + old_authority)) + { + layer->differences &= ~state; + + g_assert (layer->owner == pipeline); + if (layer->differences == 0) + _cogl_pipeline_prune_empty_layer_difference (pipeline, + layer); + goto changed; + } + } + + /* 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 |= state; + _cogl_pipeline_layer_prune_redundant_ancestry (layer); + } + +changed: + + _cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS); + return TRUE; +} + +void +cogl_pipeline_set_layer_combine_constant (CoglPipeline *pipeline, + int layer_index, + const CoglColor *constant_color) +{ + CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT; + CoglPipelineLayer *layer; + CoglPipelineLayer *authority; + CoglPipelineLayer *new; + float color_as_floats[4]; + + g_return_if_fail (cogl_is_pipeline (pipeline)); + + /* 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 + * pipeline. If the layer is created then it will be owned by + * pipeline. */ + layer = _cogl_pipeline_get_layer (pipeline, layer_index); + + /* Now find the ancestor of the layer that is the authority for the + * state we want to change */ + authority = _cogl_pipeline_layer_get_authority (layer, state); + + color_as_floats[0] = cogl_color_get_red_float (constant_color); + color_as_floats[1] = cogl_color_get_green_float (constant_color); + color_as_floats[2] = cogl_color_get_blue_float (constant_color); + color_as_floats[3] = cogl_color_get_alpha_float (constant_color); + + if (memcmp (authority->big_state->texture_combine_constant, + color_as_floats, sizeof (float) * 4) == 0) + return; + + new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state); + 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 && + _cogl_pipeline_layer_get_parent (authority) != NULL) + { + CoglPipelineLayer *parent = + _cogl_pipeline_layer_get_parent (authority); + CoglPipelineLayer *old_authority = + _cogl_pipeline_layer_get_authority (parent, state); + CoglPipelineLayerBigState *old_big_state = old_authority->big_state; + + if (memcmp (old_big_state->texture_combine_constant, + color_as_floats, sizeof (float) * 4) == 0) + { + layer->differences &= ~state; + + g_assert (layer->owner == pipeline); + if (layer->differences == 0) + _cogl_pipeline_prune_empty_layer_difference (pipeline, + layer); + goto changed; + } + } + } + + memcpy (layer->big_state->texture_combine_constant, + color_as_floats, + sizeof (color_as_floats)); + + /* 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 |= state; + _cogl_pipeline_layer_prune_redundant_ancestry (layer); + } + +changed: + + _cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS); +} + +void +_cogl_pipeline_get_layer_combine_constant (CoglPipeline *pipeline, + int layer_index, + float *constant) +{ + CoglPipelineLayerState change = + COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT; + CoglPipelineLayer *layer; + CoglPipelineLayer *authority; + + g_return_if_fail (cogl_is_pipeline (pipeline)); + + /* 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 + * pipeline. If the layer is created then it will be owned by + * pipeline. */ + layer = _cogl_pipeline_get_layer (pipeline, layer_index); + /* FIXME: we shouldn't ever construct a layer in a getter function */ + + authority = _cogl_pipeline_layer_get_authority (layer, change); + memcpy (constant, authority->big_state->texture_combine_constant, + sizeof (float) * 4); +} + +/* We should probably make a public API version of this that has a + matrix out-param. For an internal API it's good to be able to avoid + copying the matrix */ +const CoglMatrix * +_cogl_pipeline_get_layer_matrix (CoglPipeline *pipeline, int layer_index) +{ + CoglPipelineLayerState change = + COGL_PIPELINE_LAYER_STATE_USER_MATRIX; + CoglPipelineLayer *layer; + CoglPipelineLayer *authority; + + g_return_val_if_fail (cogl_is_pipeline (pipeline), NULL); + + layer = _cogl_pipeline_get_layer (pipeline, layer_index); + + authority = _cogl_pipeline_layer_get_authority (layer, change); + return &authority->big_state->matrix; +} + +void +cogl_pipeline_set_layer_matrix (CoglPipeline *pipeline, + int layer_index, + const CoglMatrix *matrix) +{ + CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_USER_MATRIX; + CoglPipelineLayer *layer; + CoglPipelineLayer *authority; + CoglPipelineLayer *new; + + g_return_if_fail (cogl_is_pipeline (pipeline)); + + /* 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 + * pipeline. If the layer is created then it will be owned by + * pipeline. */ + layer = _cogl_pipeline_get_layer (pipeline, layer_index); + + /* Now find the ancestor of the layer that is the authority for the + * state we want to change */ + authority = _cogl_pipeline_layer_get_authority (layer, state); + + if (cogl_matrix_equal (matrix, &authority->big_state->matrix)) + return; + + new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state); + 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 && + _cogl_pipeline_layer_get_parent (authority) != NULL) + { + CoglPipelineLayer *parent = + _cogl_pipeline_layer_get_parent (authority); + CoglPipelineLayer *old_authority = + _cogl_pipeline_layer_get_authority (parent, state); + + if (cogl_matrix_equal (matrix, &old_authority->big_state->matrix)) + { + layer->differences &= ~state; + + g_assert (layer->owner == pipeline); + if (layer->differences == 0) + _cogl_pipeline_prune_empty_layer_difference (pipeline, + layer); + return; + } + } + } + + layer->big_state->matrix = *matrix; + + /* 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 |= state; + _cogl_pipeline_layer_prune_redundant_ancestry (layer); + } +} + +/* FIXME: deprecate and replace with + * cogl_pipeline_get_layer_texture() instead. */ +CoglHandle +_cogl_pipeline_layer_get_texture (CoglPipelineLayer *layer) +{ + g_return_val_if_fail (_cogl_is_pipeline_layer (layer), NULL); + + return _cogl_pipeline_layer_get_texture_real (layer); +} + +gboolean +_cogl_pipeline_layer_has_user_matrix (CoglPipeline *pipeline, + int layer_index) +{ + CoglPipelineLayer *layer; + CoglPipelineLayer *authority; + + layer = _cogl_pipeline_get_layer (pipeline, layer_index); + + authority = + _cogl_pipeline_layer_get_authority (layer, + COGL_PIPELINE_LAYER_STATE_USER_MATRIX); + + /* If the authority is the default pipeline then no, otherwise yes */ + return _cogl_pipeline_layer_get_parent (authority) ? TRUE : FALSE; +} + +void +_cogl_pipeline_layer_get_filters (CoglPipelineLayer *layer, + CoglPipelineFilter *min_filter, + CoglPipelineFilter *mag_filter) +{ + CoglPipelineLayer *authority = + _cogl_pipeline_layer_get_authority (layer, + COGL_PIPELINE_LAYER_STATE_FILTERS); + + *min_filter = authority->min_filter; + *mag_filter = authority->mag_filter; +} + +void +_cogl_pipeline_get_layer_filters (CoglPipeline *pipeline, + int layer_index, + CoglPipelineFilter *min_filter, + CoglPipelineFilter *mag_filter) +{ + CoglPipelineLayer *layer; + CoglPipelineLayer *authority; + + g_return_if_fail (cogl_is_pipeline (pipeline)); + + layer = _cogl_pipeline_get_layer (pipeline, layer_index); + + authority = + _cogl_pipeline_layer_get_authority (layer, + COGL_PIPELINE_LAYER_STATE_FILTERS); + + *min_filter = authority->min_filter; + *mag_filter = authority->mag_filter; +} + +CoglPipelineFilter +_cogl_pipeline_get_layer_min_filter (CoglPipeline *pipeline, + int layer_index) +{ + CoglPipelineFilter min_filter; + CoglPipelineFilter mag_filter; + + _cogl_pipeline_get_layer_filters (pipeline, layer_index, + &min_filter, &mag_filter); + return min_filter; +} + +CoglPipelineFilter +_cogl_pipeline_get_layer_mag_filter (CoglPipeline *pipeline, + int layer_index) +{ + CoglPipelineFilter min_filter; + CoglPipelineFilter mag_filter; + + _cogl_pipeline_get_layer_filters (pipeline, layer_index, + &min_filter, &mag_filter); + return mag_filter; +} + +CoglPipelineFilter +_cogl_pipeline_layer_get_min_filter (CoglPipelineLayer *layer) +{ + CoglPipelineLayer *authority; + + g_return_val_if_fail (_cogl_is_pipeline_layer (layer), 0); + + authority = + _cogl_pipeline_layer_get_authority (layer, + COGL_PIPELINE_LAYER_STATE_FILTERS); + + return authority->min_filter; +} + +CoglPipelineFilter +_cogl_pipeline_layer_get_mag_filter (CoglPipelineLayer *layer) +{ + CoglPipelineLayer *authority; + + g_return_val_if_fail (_cogl_is_pipeline_layer (layer), 0); + + authority = + _cogl_pipeline_layer_get_authority (layer, + COGL_PIPELINE_LAYER_STATE_FILTERS); + + return authority->mag_filter; +} + +void +cogl_pipeline_set_layer_filters (CoglPipeline *pipeline, + int layer_index, + CoglPipelineFilter min_filter, + CoglPipelineFilter mag_filter) +{ + CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_FILTERS; + CoglPipelineLayer *layer; + CoglPipelineLayer *authority; + CoglPipelineLayer *new; + + g_return_if_fail (cogl_is_pipeline (pipeline)); + + /* 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 + * pipeline. If the layer is created then it will be owned by + * pipeline. */ + layer = _cogl_pipeline_get_layer (pipeline, layer_index); + + /* Now find the ancestor of the layer that is the authority for the + * state we want to change */ + authority = _cogl_pipeline_layer_get_authority (layer, state); + + if (authority->min_filter == min_filter && + authority->mag_filter == mag_filter) + return; + + new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state); + 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 && + _cogl_pipeline_layer_get_parent (authority) != NULL) + { + CoglPipelineLayer *parent = + _cogl_pipeline_layer_get_parent (authority); + CoglPipelineLayer *old_authority = + _cogl_pipeline_layer_get_authority (parent, state); + + if (old_authority->min_filter == min_filter && + old_authority->mag_filter == mag_filter) + { + layer->differences &= ~state; + + g_assert (layer->owner == pipeline); + if (layer->differences == 0) + _cogl_pipeline_prune_empty_layer_difference (pipeline, + layer); + return; + } + } + } + + layer->min_filter = min_filter; + layer->mag_filter = mag_filter; + + /* 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 |= state; + _cogl_pipeline_layer_prune_redundant_ancestry (layer); + } +} + +void +_cogl_pipeline_layer_hash_unit_state (CoglPipelineLayer *authority, + CoglPipelineLayer **authorities, + CoglPipelineHashState *state) +{ + int unit = authority->unit_index; + state->hash = + _cogl_util_one_at_a_time_hash (state->hash, &unit, sizeof (unit)); +} + +void +_cogl_pipeline_layer_hash_texture_target_state (CoglPipelineLayer *authority, + CoglPipelineLayer **authorities, + CoglPipelineHashState *state) +{ + GLenum gl_target = authority->target; + + state->hash = + _cogl_util_one_at_a_time_hash (state->hash, &gl_target, sizeof (gl_target)); +} + +void +_cogl_pipeline_layer_hash_texture_data_state (CoglPipelineLayer *authority, + CoglPipelineLayer **authorities, + CoglPipelineHashState *state) +{ + GLuint gl_handle; + + cogl_texture_get_gl_texture (authority->texture, &gl_handle, NULL); + + state->hash = + _cogl_util_one_at_a_time_hash (state->hash, &gl_handle, sizeof (gl_handle)); +} + +void +_cogl_pipeline_layer_hash_filters_state (CoglPipelineLayer *authority, + CoglPipelineLayer **authorities, + CoglPipelineHashState *state) +{ + unsigned int hash = state->hash; + hash = _cogl_util_one_at_a_time_hash (hash, &authority->mag_filter, + sizeof (authority->mag_filter)); + hash = _cogl_util_one_at_a_time_hash (hash, &authority->min_filter, + sizeof (authority->min_filter)); + state->hash = hash; +} + +void +_cogl_pipeline_layer_hash_wrap_modes_state (CoglPipelineLayer *authority, + CoglPipelineLayer **authorities, + CoglPipelineHashState *state) +{ + unsigned int hash = state->hash; + hash = _cogl_util_one_at_a_time_hash (hash, &authority->wrap_mode_s, + sizeof (authority->wrap_mode_s)); + hash = _cogl_util_one_at_a_time_hash (hash, &authority->wrap_mode_t, + sizeof (authority->wrap_mode_t)); + hash = _cogl_util_one_at_a_time_hash (hash, &authority->wrap_mode_p, + sizeof (authority->wrap_mode_p)); + state->hash = hash; +} + +void +_cogl_pipeline_layer_hash_combine_state (CoglPipelineLayer *authority, + CoglPipelineLayer **authorities, + CoglPipelineHashState *state) +{ + unsigned int hash = state->hash; + CoglPipelineLayerBigState *b = authority->big_state; + int n_args; + int i; + + hash = _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_rgb_func, + sizeof (b->texture_combine_rgb_func)); + n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_rgb_func); + for (i = 0; i < n_args; i++) + { + hash = + _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_rgb_src[i], + sizeof (b->texture_combine_rgb_src[i])); + hash = + _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_rgb_op[i], + sizeof (b->texture_combine_rgb_op[i])); + } + + hash = _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_alpha_func, + sizeof (b->texture_combine_alpha_func)); + n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_alpha_func); + for (i = 0; i < n_args; i++) + { + hash = + _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_alpha_src[i], + sizeof (b->texture_combine_alpha_src[i])); + hash = + _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_alpha_op[i], + sizeof (b->texture_combine_alpha_op[i])); + } + + state->hash = hash; +} + +void +_cogl_pipeline_layer_hash_combine_constant_state (CoglPipelineLayer *authority, + CoglPipelineLayer **authorities, + CoglPipelineHashState *state) +{ + CoglPipelineLayerBigState *b = authority->big_state; + gboolean need_hash = FALSE; + int n_args; + int i; + + /* XXX: If the user also asked to hash the ALPHA_FUNC_STATE then it + * would be nice if we could combine the n_args loops in this + * function and _cogl_pipeline_layer_hash_combine_state. + */ + + n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_rgb_func); + for (i = 0; i < n_args; i++) + { + if (b->texture_combine_rgb_src[i] == + COGL_PIPELINE_COMBINE_SOURCE_CONSTANT) + { + /* XXX: should we be careful to only hash the alpha + * component in the COGL_PIPELINE_COMBINE_OP_SRC_ALPHA case? */ + need_hash = TRUE; + goto done; + } + } + + n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_alpha_func); + for (i = 0; i < n_args; i++) + { + if (b->texture_combine_alpha_src[i] == + COGL_PIPELINE_COMBINE_SOURCE_CONSTANT) + { + /* XXX: should we be careful to only hash the alpha + * component in the COGL_PIPELINE_COMBINE_OP_SRC_ALPHA case? */ + need_hash = TRUE; + goto done; + } + } + +done: + if (need_hash) + { + float *constant = b->texture_combine_constant; + state->hash = _cogl_util_one_at_a_time_hash (state->hash, constant, + sizeof (float) * 4); + } +} + +void +_cogl_pipeline_layer_hash_user_matrix_state (CoglPipelineLayer *authority, + CoglPipelineLayer **authorities, + CoglPipelineHashState *state) +{ + CoglPipelineLayerBigState *big_state = authority->big_state; + state->hash = _cogl_util_one_at_a_time_hash (state->hash, &big_state->matrix, + sizeof (float) * 16); +} + +void +_cogl_pipeline_layer_hash_point_sprite_state (CoglPipelineLayer *authority, + CoglPipelineLayer **authorities, + CoglPipelineHashState *state) +{ + CoglPipelineLayerBigState *big_state = authority->big_state; + state->hash = + _cogl_util_one_at_a_time_hash (state->hash, &big_state->point_sprite_coords, + sizeof (big_state->point_sprite_coords)); +} + + diff --git a/cogl/cogl-pipeline-layer-state.h b/cogl/cogl-pipeline-layer-state.h new file mode 100644 index 000000000..415e544f1 --- /dev/null +++ b/cogl/cogl-pipeline-layer-state.h @@ -0,0 +1,503 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2007,2008,2009 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * + */ + +#if !defined(__COGL_H_INSIDE__) && !defined(CLUTTER_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __COGL_PIPELINE_LAYER_STATE_H__ +#define __COGL_PIPELINE_LAYER_STATE_H__ + +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +#ifdef COGL_ENABLE_EXPERIMENTAL_API + +/** + * CoglPipelineFilter: + * @COGL_PIPELINE_FILTER_NEAREST: Measuring in manhatten distance from the, + * current pixel center, use the nearest texture texel + * @COGL_PIPELINE_FILTER_LINEAR: Use the weighted average of the 4 texels + * nearest the current pixel center + * @COGL_PIPELINE_FILTER_NEAREST_MIPMAP_NEAREST: Select the mimap level whose + * texel size most closely matches the current pixel, and use the + * %COGL_PIPELINE_FILTER_NEAREST criterion + * @COGL_PIPELINE_FILTER_LINEAR_MIPMAP_NEAREST: Select the mimap level whose + * texel size most closely matches the current pixel, and use the + * %COGL_PIPELINE_FILTER_LINEAR criterion + * @COGL_PIPELINE_FILTER_NEAREST_MIPMAP_LINEAR: Select the two mimap levels + * whose texel size most closely matches the current pixel, use + * the %COGL_PIPELINE_FILTER_NEAREST criterion on each one and take + * their weighted average + * @COGL_PIPELINE_FILTER_LINEAR_MIPMAP_LINEAR: Select the two mimap levels + * whose texel size most closely matches the current pixel, use + * the %COGL_PIPELINE_FILTER_LINEAR criterion on each one and take + * their weighted average + * + * Texture filtering is used whenever the current pixel maps either to more + * than one texture element (texel) or less than one. These filter enums + * correspond to different strategies used to come up with a pixel color, by + * possibly referring to multiple neighbouring texels and taking a weighted + * average or simply using the nearest texel. + */ +typedef enum { + COGL_PIPELINE_FILTER_NEAREST = 0x2600, + COGL_PIPELINE_FILTER_LINEAR = 0x2601, + COGL_PIPELINE_FILTER_NEAREST_MIPMAP_NEAREST = 0x2700, + COGL_PIPELINE_FILTER_LINEAR_MIPMAP_NEAREST = 0x2701, + COGL_PIPELINE_FILTER_NEAREST_MIPMAP_LINEAR = 0x2702, + COGL_PIPELINE_FILTER_LINEAR_MIPMAP_LINEAR = 0x2703 +} CoglPipelineFilter; +/* NB: these values come from the equivalents in gl.h */ + +/** + * CoglPipelineWrapMode: + * @COGL_PIPELINE_WRAP_MODE_REPEAT: The texture will be repeated. This + * is useful for example to draw a tiled background. + * @COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE: The coordinates outside the + * range 0→1 will sample copies of the edge pixels of the + * texture. This is useful to avoid artifacts if only one copy of + * the texture is being rendered. + * @COGL_PIPELINE_WRAP_MODE_AUTOMATIC: Cogl will try to automatically + * decide which of the above two to use. For cogl_rectangle(), it + * will use repeat mode if any of the texture coordinates are + * outside the range 0→1, otherwise it will use clamp to edge. For + * cogl_polygon() it will always use repeat mode. For + * cogl_vertex_buffer_draw() it will use repeat mode except for + * layers that have point sprite coordinate generation enabled. This + * is the default value. + * + * The wrap mode specifies what happens when texture coordinates + * outside the range 0→1 are used. Note that if the filter mode is + * anything but %COGL_PIPELINE_FILTER_NEAREST then texels outside the + * range 0→1 might be used even when the coordinate is exactly 0 or 1 + * because OpenGL will try to sample neighbouring pixels. For example + * if you are trying to render the full texture then you may get + * artifacts around the edges when the pixels from the other side are + * merged in if the wrap mode is set to repeat. + * + * Since: 2.0 + */ +/* GL_ALWAYS is just used here as a value that is known not to clash + * with any valid GL wrap modes + * + * XXX: keep the values in sync with the CoglPipelineWrapModeInternal + * enum so no conversion is actually needed. + */ +typedef enum { + COGL_PIPELINE_WRAP_MODE_REPEAT = 0x2901, + COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE = 0x812F, + COGL_PIPELINE_WRAP_MODE_AUTOMATIC = 0x0207 +} CoglPipelineWrapMode; +/* NB: these values come from the equivalents in gl.h */ + +#define cogl_pipeline_set_layer_texture cogl_pipeline_set_layer_texture_EXP +/** + * cogl_pipeline_set_layer: + * @pipeline: A #CoglPipeline object + * @layer_index: the index of the layer + * @texture: a #CoglHandle for the layer object + * + * In addition to the standard OpenGL lighting model a Cogl pipeline 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. + * + * In the future, we may define other types of pipeline layers, such + * as purely GLSL based layers. + * + * Since: 2.0 + */ +void +cogl_pipeline_set_layer_texture (CoglPipeline *pipeline, + int layer_index, + CoglHandle texture); + +#define cogl_pipeline_remove_layer cogl_pipeline_remove_layer_EXP +/** + * cogl_pipeline_remove_layer: + * @pipeline: A #CoglPipeline object + * @layer_index: Specifies the layer you want to remove + * + * This function removes a layer from your pipeline + */ +void +cogl_pipeline_remove_layer (CoglPipeline *pipeline, + int layer_index); + +#define cogl_pipeline_set_layer_combine cogl_pipeline_set_layer_combine_EXP +/** + * cogl_pipeline_set_layer_combine: + * @pipeline: A #CoglPipeline object + * @layer_index: Specifies the layer you want define a combine function for + * @blend_string: A Cogl blend string + * describing the desired texture combine function. + * @error: A #GError that may report parse errors or lack of GPU/driver + * support. May be %NULL, in which case a warning will be printed out if an + * error is encountered. + * + * If not already familiar; you can refer + * here for an overview of what blend + * strings are and there syntax. + * + * These are all the functions available for texture combining: + * + * REPLACE(arg0) = arg0 + * MODULATE(arg0, arg1) = arg0 x arg1 + * ADD(arg0, arg1) = arg0 + arg1 + * ADD_SIGNED(arg0, arg1) = arg0 + arg1 - 0.5 + * INTERPOLATE(arg0, arg1, arg2) = arg0 x arg2 + arg1 x (1 - arg2) + * SUBTRACT(arg0, arg1) = arg0 - arg1 + * + * + * DOT3_RGB(arg0, arg1) = 4 x ((arg0[R] - 0.5)) * (arg1[R] - 0.5) + + * (arg0[G] - 0.5)) * (arg1[G] - 0.5) + + * (arg0[B] - 0.5)) * (arg1[B] - 0.5)) + * + * + * + * + * DOT3_RGBA(arg0, arg1) = 4 x ((arg0[R] - 0.5)) * (arg1[R] - 0.5) + + * (arg0[G] - 0.5)) * (arg1[G] - 0.5) + + * (arg0[B] - 0.5)) * (arg1[B] - 0.5)) + * + * + * + * + * Refer to the + * color-source syntax for + * describing the arguments. The valid source names for texture combining + * are: + * + * + * TEXTURE + * Use the color from the current texture layer + * + * + * TEXTURE_0, TEXTURE_1, etc + * Use the color from the specified texture layer + * + * + * CONSTANT + * Use the color from the constant given with + * cogl_pipeline_set_layer_constant() + * + * + * PRIMARY + * Use the color of the pipeline as set with + * cogl_pipeline_set_color() + * + * + * PREVIOUS + * Either use the texture color from the previous layer, or + * if this is layer 0, use the color of the pipeline as set with + * cogl_pipeline_set_color() + * + * + * + * + * Layer Combine Examples + * This is effectively what the default blending is: + * + * RGBA = MODULATE (PREVIOUS, TEXTURE) + * + * This could be used to cross-fade between two images, using + * the alpha component of a constant as the interpolator. The constant + * color is given by calling cogl_pipeline_set_layer_constant. + * + * RGBA = INTERPOLATE (PREVIOUS, TEXTURE, CONSTANT[A]) + * + * + * + * You can't give a multiplication factor for arguments as you can + * with blending. + * + * Return value: %TRUE if the blend string was successfully parsed, and the + * described texture combining is supported by the underlying driver and + * or hardware. On failure, %FALSE is returned and @error is set + * + * Since: 2.0 + */ +gboolean +cogl_pipeline_set_layer_combine (CoglPipeline *pipeline, + int layer_index, + const char *blend_string, + GError **error); + +#define cogl_pipeline_set_layer_combine_constant \ + cogl_pipeline_set_layer_combine_constant_EXP +/** + * cogl_pipeline_set_layer_combine_constant: + * @pipeline: A #CoglPipeline object + * @layer_index: Specifies the layer you want to specify a constant used + * for texture combining + * @constant: The constant color you want + * + * When you are using the 'CONSTANT' color source in a layer combine + * description then you can use this function to define its value. + * + * Since: 2.0 + */ +void +cogl_pipeline_set_layer_combine_constant (CoglPipeline *pipeline, + int layer_index, + const CoglColor *constant); + +#define cogl_pipeline_set_layer_matrix cogl_pipeline_set_layer_matrix_EXP +/** + * cogl_pipeline_set_layer_matrix: + * @pipeline: A #CoglPipeline object + * @layer_index: the index for the layer inside @pipeline + * @matrix: the transformation matrix for the layer + * + * This function lets you set a matrix that can be used to e.g. translate + * and rotate a single layer of a pipeline used to fill your geometry. + */ +void +cogl_pipeline_set_layer_matrix (CoglPipeline *pipeline, + int layer_index, + const CoglMatrix *matrix); + +#define cogl_pipeline_get_n_layers cogl_pipeline_get_n_layers_EXP +/** + * cogl_pipeline_get_n_layers: + * @pipeline: A #CoglPipeline object + * + * Retrieves the number of layers defined for the given @pipeline + * + * Return value: the number of layers + * + * Since: 2.0 + */ +int +cogl_pipeline_get_n_layers (CoglPipeline *pipeline); + +#define cogl_pipeline_set_layer_filters cogl_pipeline_set_layer_filters_EXP +/** + * cogl_pipeline_set_layer_filters: + * @pipeline: A #CoglPipeline object + * @layer_index: the layer number to change. + * @min_filter: the filter used when scaling a texture down. + * @mag_filter: the filter used when magnifying a texture. + * + * Changes the decimation and interpolation filters used when a texture is + * drawn at other scales than 100%. + */ +void +cogl_pipeline_set_layer_filters (CoglPipeline *pipeline, + int layer_index, + CoglPipelineFilter min_filter, + CoglPipelineFilter mag_filter); + +#define cogl_pipeline_set_layer_point_sprite_coords_enabled \ + cogl_pipeline_set_layer_point_sprite_coords_enabled_EXP +/** + * cogl_pipeline_set_layer_point_sprite_coords_enabled: + * @pipeline: a #CoglHandle to a pipeline. + * @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: 2.0 + */ +gboolean +cogl_pipeline_set_layer_point_sprite_coords_enabled (CoglPipeline *pipeline, + int layer_index, + gboolean enable, + GError **error); + +#define cogl_pipeline_get_layer_point_sprite_coords_enabled \ + cogl_pipeline_get_layer_point_sprite_coords_enabled_EXP +/** + * cogl_pipeline_get_layer_point_sprite_coords_enabled: + * @pipeline: a #CoglHandle to a pipeline. + * @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: 2.0 + */ +gboolean +cogl_pipeline_get_layer_point_sprite_coords_enabled (CoglPipeline *pipeline, + int layer_index); + +#define cogl_pipeline_get_layer_wrap_mode_s \ + cogl_pipeline_get_layer_wrap_mode_s_EXP +/** + * cogl_pipeline_get_layer_wrap_mode_s: + * @pipeline: A #CoglPipeline object + * @layer_index: the layer number to change. + * + * Returns the wrap mode for the 's' coordinate of texture lookups on this + * layer. + * + * Return value: the wrap mode for the 's' coordinate of texture lookups on + * this layer. + * + * Since: 1.6 + */ +CoglPipelineWrapMode +cogl_pipeline_get_layer_wrap_mode_s (CoglPipeline *pipeline, + int layer_index); + +#define cogl_pipeline_set_layer_wrap_mode_s \ + cogl_pipeline_set_layer_wrap_mode_s_EXP +/** + * cogl_pipeline_set_layer_wrap_mode_s: + * @pipeline: A #CoglPipeline object + * @layer_index: the layer number to change. + * @mode: the new wrap mode + * + * Sets the wrap mode for the 's' coordinate of texture lookups on this layer. + * + * Since: 2.0 + */ +void +cogl_pipeline_set_layer_wrap_mode_s (CoglPipeline *pipeline, + int layer_index, + CoglPipelineWrapMode mode); + +#define cogl_pipeline_get_layer_wrap_mode_t \ + cogl_pipeline_get_layer_wrap_mode_t_EXP +/** + * cogl_pipeline_get_layer_wrap_mode_t: + * @pipeline: A #CoglPipeline object + * @layer_index: the layer number to change. + * + * Returns the wrap mode for the 't' coordinate of texture lookups on this + * layer. + * + * Return value: the wrap mode for the 't' coordinate of texture lookups on + * this layer. + * + * Since: 1.6 + */ +CoglPipelineWrapMode +cogl_pipeline_get_layer_wrap_mode_t (CoglPipeline *pipeline, + int layer_index); + + +#define cogl_pipeline_set_layer_wrap_mode_t \ + cogl_pipeline_set_layer_wrap_mode_t_EXP +/** + * cogl_pipeline_set_layer_wrap_mode_t: + * @pipeline: A #CoglPipeline object + * @layer_index: the layer number to change. + * @mode: the new wrap mode + * + * Sets the wrap mode for the 't' coordinate of texture lookups on this layer. + * + * Since: 2.0 + */ +void +cogl_pipeline_set_layer_wrap_mode_t (CoglPipeline *pipeline, + int layer_index, + CoglPipelineWrapMode mode); + +#define cogl_pipeline_get_layer_wrap_mode_p \ + cogl_pipeline_get_layer_wrap_mode_p_EXP +/** + * cogl_pipeline_get_layer_wrap_mode_p: + * @pipeline: A #CoglPipeline object + * @layer_index: the layer number to change. + * + * Returns the wrap mode for the 'p' coordinate of texture lookups on this + * layer. + * + * Return value: the wrap mode for the 'p' coordinate of texture lookups on + * this layer. + * + * Since: 1.6 + */ +CoglPipelineWrapMode +cogl_pipeline_get_layer_wrap_mode_p (CoglPipeline *pipeline, + int layer_index); + +#define cogl_pipeline_set_layer_wrap_mode_p \ + cogl_pipeline_set_layer_wrap_mode_p_EXP +/** + * cogl_pipeline_set_layer_wrap_mode_p: + * @pipeline: A #CoglPipeline object + * @layer_index: the layer number to change. + * @mode: the new wrap mode + * + * Sets the wrap mode for the 'p' coordinate of texture lookups on + * this layer. 'p' is the third coordinate. + * + * Since: 2.0 + */ +void +cogl_pipeline_set_layer_wrap_mode_p (CoglPipeline *pipeline, + int layer_index, + CoglPipelineWrapMode mode); + +#define cogl_pipeline_set_layer_wrap_mode \ + cogl_pipeline_set_layer_wrap_mode_EXP +/** + * cogl_pipeline_set_layer_wrap_mode: + * @pipeline: A #CoglPipeline object + * @layer_index: the layer number to change. + * @mode: the new wrap mode + * + * Sets the wrap mode for all three coordinates of texture lookups on + * this layer. This is equivalent to calling + * cogl_pipeline_set_layer_wrap_mode_s(), + * cogl_pipeline_set_layer_wrap_mode_t() and + * cogl_pipeline_set_layer_wrap_mode_p() separately. + * + * Since: 2.0 + */ +void +cogl_pipeline_set_layer_wrap_mode (CoglPipeline *pipeline, + int layer_index, + CoglPipelineWrapMode mode); + +#endif /* COGL_ENABLE_EXPERIMENTAL_API */ + +G_END_DECLS + +#endif /* __COGL_PIPELINE_LAYER_STATE_H__ */ diff --git a/cogl/cogl-pipeline-private.h b/cogl/cogl-pipeline-private.h index 628ba355a..7e019c28e 100644 --- a/cogl/cogl-pipeline-private.h +++ b/cogl/cogl-pipeline-private.h @@ -860,6 +860,11 @@ _cogl_pipeline_get_authority (CoglPipeline *pipeline, typedef gboolean (*CoglPipelineStateComparitor) (CoglPipeline *authority0, CoglPipeline *authority1); +typedef gboolean +(*CoglPipelineLayerStateComparitor) (CoglPipelineLayer *authority0, + CoglPipelineLayer *authority1); + + void _cogl_pipeline_update_authority (CoglPipeline *pipeline, CoglPipeline *authority, @@ -878,6 +883,32 @@ _cogl_pipeline_prune_redundant_ancestry (CoglPipeline *pipeline); void _cogl_pipeline_update_blend_enable (CoglPipeline *pipeline, CoglPipelineState changes); +CoglPipelineLayer * +_cogl_pipeline_get_layer (CoglPipeline *pipeline, + int layer_index); + +gboolean +_cogl_is_pipeline_layer (void *object); + +static inline CoglPipelineLayer * +_cogl_pipeline_layer_get_parent (CoglPipelineLayer *layer) +{ + CoglPipelineNode *parent_node = COGL_PIPELINE_NODE (layer)->parent; + return COGL_PIPELINE_LAYER (parent_node); +} + +CoglPipelineLayer * +_cogl_pipeline_layer_pre_change_notify (CoglPipeline *required_owner, + CoglPipelineLayer *layer, + CoglPipelineLayerState change); + +void +_cogl_pipeline_layer_prune_redundant_ancestry (CoglPipelineLayer *layer); + +void +_cogl_pipeline_prune_empty_layer_difference (CoglPipeline *layers_authority, + CoglPipelineLayer *layer); + /* * SECTION:cogl-pipeline-internals * @short_description: Functions for creating custom primitives that make use diff --git a/cogl/cogl-pipeline.c b/cogl/cogl-pipeline.c index 384b646d7..70bda8ffb 100644 --- a/cogl/cogl-pipeline.c +++ b/cogl/cogl-pipeline.c @@ -38,6 +38,7 @@ #include "cogl-pipeline-private.h" #include "cogl-pipeline-opengl-private.h" #include "cogl-pipeline-state-private.h" +#include "cogl-pipeline-layer-state-private.h" #include "cogl-texture-private.h" #include "cogl-blend-string.h" #include "cogl-journal-private.h" @@ -556,16 +557,6 @@ _cogl_pipeline_get_real_blend_enabled (CoglPipeline *pipeline) return pipeline->real_blend_enable; } -/* XXX: Think twice before making this non static since it is used - * heavily and we expect the compiler to inline it... - */ -static CoglPipelineLayer * -_cogl_pipeline_layer_get_parent (CoglPipelineLayer *layer) -{ - CoglPipelineNode *parent_node = COGL_PIPELINE_NODE (layer)->parent; - return COGL_PIPELINE_LAYER (parent_node); -} - CoglPipelineLayer * _cogl_pipeline_layer_get_authority (CoglPipelineLayer *layer, unsigned long difference) @@ -1730,7 +1721,7 @@ _cogl_pipeline_layer_init_multi_property_sparse_state ( * required_owner can only by NULL for new, currently unowned layers * with no dependants. */ -static CoglPipelineLayer * +CoglPipelineLayer * _cogl_pipeline_layer_pre_change_notify (CoglPipeline *required_owner, CoglPipelineLayer *layer, CoglPipelineLayerState change) @@ -1847,7 +1838,7 @@ _cogl_pipeline_layer_set_parent (CoglPipelineLayer *layer, /* XXX: This is duplicated logic; the same as for * _cogl_pipeline_prune_redundant_ancestry it would be nice to find a * way to consolidate these functions! */ -static void +void _cogl_pipeline_layer_prune_redundant_ancestry (CoglPipelineLayer *layer) { CoglPipelineLayer *new_parent = _cogl_pipeline_layer_get_parent (layer); @@ -1862,73 +1853,6 @@ _cogl_pipeline_layer_prune_redundant_ancestry (CoglPipelineLayer *layer) _cogl_pipeline_layer_set_parent (layer, new_parent); } -/* - * XXX: consider special casing layer->unit_index so it's not a sparse - * property so instead we can assume it's valid for all layer - * instances. - * - We would need to initialize ->unit_index in - * _cogl_pipeline_layer_copy (). - * - * XXX: If you use this API you should consider that the given layer - * might not be writeable and so a new derived layer will be allocated - * and modified instead. The layer modified will be returned so you - * can identify when this happens. - */ -static CoglPipelineLayer * -_cogl_pipeline_set_layer_unit (CoglPipeline *required_owner, - CoglPipelineLayer *layer, - int unit_index) -{ - CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_UNIT; - CoglPipelineLayer *authority = - _cogl_pipeline_layer_get_authority (layer, change); - CoglPipelineLayer *new; - - if (authority->unit_index == unit_index) - return layer; - - new = - _cogl_pipeline_layer_pre_change_notify (required_owner, - layer, - change); - if (new != layer) - layer = new; - else - { - /* If the 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 && - _cogl_pipeline_layer_get_parent (authority) != NULL) - { - CoglPipelineLayer *parent = - _cogl_pipeline_layer_get_parent (authority); - CoglPipelineLayer *old_authority = - _cogl_pipeline_layer_get_authority (parent, change); - - if (old_authority->unit_index == unit_index) - { - layer->differences &= ~change; - return layer; - } - } - } - - layer->unit_index = unit_index; - - /* 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_pipeline_layer_prune_redundant_ancestry (layer); - } - - return layer; -} - typedef struct { /* The layer we are trying to find */ @@ -2029,7 +1953,7 @@ _cogl_pipeline_get_layer_info (CoglPipeline *pipeline, } } -static CoglPipelineLayer * +CoglPipelineLayer * _cogl_pipeline_get_layer (CoglPipeline *pipeline, int layer_index) { @@ -2102,26 +2026,7 @@ _cogl_pipeline_get_layer (CoglPipeline *pipeline, return layer; } -CoglHandle -_cogl_pipeline_layer_get_texture_real (CoglPipelineLayer *layer) -{ - CoglPipelineLayer *authority = - _cogl_pipeline_layer_get_authority (layer, - COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA); - - return authority->texture; -} - -CoglHandle -_cogl_pipeline_get_layer_texture (CoglPipeline *pipeline, - int layer_index) -{ - CoglPipelineLayer *layer = - _cogl_pipeline_get_layer (pipeline, layer_index); - return _cogl_pipeline_layer_get_texture (layer); -} - -static void +void _cogl_pipeline_prune_empty_layer_difference (CoglPipeline *layers_authority, CoglPipelineLayer *layer) { @@ -2199,202 +2104,6 @@ _cogl_pipeline_prune_empty_layer_difference (CoglPipeline *layers_authority, } } -static void -_cogl_pipeline_set_layer_texture_target (CoglPipeline *pipeline, - int layer_index, - GLenum target) -{ - CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET; - CoglPipelineLayer *layer; - CoglPipelineLayer *authority; - CoglPipelineLayer *new; - - /* 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 - * pipeline. If the layer is created then it will be owned by - * pipeline. */ - layer = _cogl_pipeline_get_layer (pipeline, layer_index); - - /* Now find the ancestor of the layer that is the authority for the - * state we want to change */ - authority = _cogl_pipeline_layer_get_authority (layer, change); - - if (target == authority->target) - return; - - new = _cogl_pipeline_layer_pre_change_notify (pipeline, 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 && - _cogl_pipeline_layer_get_parent (authority) != NULL) - { - CoglPipelineLayer *parent = - _cogl_pipeline_layer_get_parent (authority); - CoglPipelineLayer *old_authority = - _cogl_pipeline_layer_get_authority (parent, change); - - if (old_authority->target == target) - { - layer->differences &= ~change; - - g_assert (layer->owner == pipeline); - if (layer->differences == 0) - _cogl_pipeline_prune_empty_layer_difference (pipeline, - layer); - goto changed; - } - } - } - - layer->target = target; - - /* 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_pipeline_layer_prune_redundant_ancestry (layer); - } - -changed: - - _cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS); -} - -static void -_cogl_pipeline_set_layer_texture_data (CoglPipeline *pipeline, - int layer_index, - CoglHandle texture) -{ - CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA; - CoglPipelineLayer *layer; - CoglPipelineLayer *authority; - CoglPipelineLayer *new; - - /* 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 - * pipeline. If the layer is created then it will be owned by - * pipeline. */ - layer = _cogl_pipeline_get_layer (pipeline, layer_index); - - /* Now find the ancestor of the layer that is the authority for the - * state we want to change */ - authority = _cogl_pipeline_layer_get_authority (layer, change); - - if (authority->texture == texture) - return; - - new = _cogl_pipeline_layer_pre_change_notify (pipeline, 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 && - _cogl_pipeline_layer_get_parent (authority) != NULL) - { - CoglPipelineLayer *parent = - _cogl_pipeline_layer_get_parent (authority); - CoglPipelineLayer *old_authority = - _cogl_pipeline_layer_get_authority (parent, change); - - if (old_authority->texture == texture) - { - layer->differences &= ~change; - - if (layer->texture != COGL_INVALID_HANDLE) - cogl_handle_unref (layer->texture); - - g_assert (layer->owner == pipeline); - if (layer->differences == 0) - _cogl_pipeline_prune_empty_layer_difference (pipeline, - layer); - goto changed; - } - } - } - - if (texture != COGL_INVALID_HANDLE) - cogl_handle_ref (texture); - if (layer == authority && - layer->texture != COGL_INVALID_HANDLE) - cogl_handle_unref (layer->texture); - layer->texture = texture; - - /* 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_pipeline_layer_prune_redundant_ancestry (layer); - } - -changed: - - _cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS); -} - -/* A convenience for querying the target of a given texture that - * notably returns 0 for NULL textures - so we can say that a layer - * with no associated CoglTexture will have a texture target of 0. - */ -static GLenum -get_texture_target (CoglHandle texture) -{ - GLuint ignore_handle; - GLenum gl_target; - - g_return_val_if_fail (texture, 0); - - cogl_texture_get_gl_texture (texture, &ignore_handle, &gl_target); - - return gl_target; -} - -void -cogl_pipeline_set_layer_texture (CoglPipeline *pipeline, - int layer_index, - CoglHandle texture) -{ - /* For the convenience of fragend code we separate texture state - * into the "target" and the "data", and setting a layer texture - * updates both of these properties. - * - * One example for why this is helpful is that the fragends may - * cache programs they generate and want to re-use those programs - * with all pipelines having equivalent fragment processing state. - * For the sake of determining if pipelines have equivalent fragment - * processing state we don't need to compare that the same - * underlying texture objects are referenced by the pipelines but we - * do need to see if they use the same texture targets. Making this - * distinction is much simpler if they are in different state - * groups. - * - * Note: if a NULL texture is set then we leave the target unchanged - * so we can avoid needlessly invalidating any associated fragment - * program. - */ - if (texture) - _cogl_pipeline_set_layer_texture_target (pipeline, layer_index, - get_texture_target (texture)); - _cogl_pipeline_set_layer_texture_data (pipeline, layer_index, texture); -} - typedef struct { int i; @@ -2449,454 +2158,6 @@ fallback_layer_cb (CoglPipelineLayer *layer, void *user_data) return TRUE; } -void -_cogl_pipeline_set_layer_wrap_modes (CoglPipeline *pipeline, - CoglPipelineLayer *layer, - CoglPipelineLayer *authority, - CoglPipelineWrapModeInternal wrap_mode_s, - CoglPipelineWrapModeInternal wrap_mode_t, - CoglPipelineWrapModeInternal wrap_mode_p) -{ - CoglPipelineLayer *new; - CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES; - - if (authority->wrap_mode_s == wrap_mode_s && - authority->wrap_mode_t == wrap_mode_t && - authority->wrap_mode_p == wrap_mode_p) - return; - - new = _cogl_pipeline_layer_pre_change_notify (pipeline, 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 && - _cogl_pipeline_layer_get_parent (authority) != NULL) - { - CoglPipelineLayer *parent = - _cogl_pipeline_layer_get_parent (authority); - CoglPipelineLayer *old_authority = - _cogl_pipeline_layer_get_authority (parent, change); - - if (old_authority->wrap_mode_s == wrap_mode_s && - old_authority->wrap_mode_t == wrap_mode_t && - old_authority->wrap_mode_p == wrap_mode_p) - { - layer->differences &= ~change; - - g_assert (layer->owner == pipeline); - if (layer->differences == 0) - _cogl_pipeline_prune_empty_layer_difference (pipeline, - layer); - return; - } - } - } - - layer->wrap_mode_s = wrap_mode_s; - layer->wrap_mode_t = wrap_mode_t; - layer->wrap_mode_p = wrap_mode_p; - - /* 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_pipeline_layer_prune_redundant_ancestry (layer); - } -} - -static CoglPipelineWrapModeInternal -public_to_internal_wrap_mode (CoglPipelineWrapMode mode) -{ - return (CoglPipelineWrapModeInternal)mode; -} - -static CoglPipelineWrapMode -internal_to_public_wrap_mode (CoglPipelineWrapModeInternal internal_mode) -{ - g_return_val_if_fail (internal_mode != - COGL_PIPELINE_WRAP_MODE_INTERNAL_CLAMP_TO_BORDER, - COGL_PIPELINE_WRAP_MODE_AUTOMATIC); - return (CoglPipelineWrapMode)internal_mode; -} - -void -cogl_pipeline_set_layer_wrap_mode_s (CoglPipeline *pipeline, - int layer_index, - CoglPipelineWrapMode mode) -{ - CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES; - CoglPipelineLayer *layer; - CoglPipelineLayer *authority; - CoglPipelineWrapModeInternal internal_mode = - public_to_internal_wrap_mode (mode); - - g_return_if_fail (cogl_is_pipeline (pipeline)); - - /* 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 - * pipeline. If the layer is created then it will be owned by - * pipeline. */ - layer = _cogl_pipeline_get_layer (pipeline, layer_index); - - /* Now find the ancestor of the layer that is the authority for the - * state we want to change */ - authority = _cogl_pipeline_layer_get_authority (layer, change); - - _cogl_pipeline_set_layer_wrap_modes (pipeline, layer, authority, - internal_mode, - authority->wrap_mode_t, - authority->wrap_mode_p); -} - -void -cogl_pipeline_set_layer_wrap_mode_t (CoglPipeline *pipeline, - int layer_index, - CoglPipelineWrapMode mode) -{ - CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES; - CoglPipelineLayer *layer; - CoglPipelineLayer *authority; - CoglPipelineWrapModeInternal internal_mode = - public_to_internal_wrap_mode (mode); - - g_return_if_fail (cogl_is_pipeline (pipeline)); - - /* 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 - * pipeline. If the layer is created then it will be owned by - * pipeline. */ - layer = _cogl_pipeline_get_layer (pipeline, layer_index); - - /* Now find the ancestor of the layer that is the authority for the - * state we want to change */ - authority = _cogl_pipeline_layer_get_authority (layer, change); - - _cogl_pipeline_set_layer_wrap_modes (pipeline, layer, authority, - authority->wrap_mode_s, - internal_mode, - authority->wrap_mode_p); -} - -/* The rationale for naming the third texture coordinate 'p' instead - of OpenGL's usual 'r' is that 'r' conflicts with the usual naming - of the 'red' component when treating a vector as a color. Under - GLSL this is awkward because the texture swizzling for a vector - uses a single letter for each component and the names for colors, - textures and positions are synonymous. GLSL works around this by - naming the components of the texture s, t, p and q. Cogl already - effectively already exposes this naming because it exposes GLSL so - it makes sense to use that naming consistently. Another alternative - could be u, v and w. This is what Blender and Direct3D use. However - the w component conflicts with the w component of a position - vertex. */ -void -cogl_pipeline_set_layer_wrap_mode_p (CoglPipeline *pipeline, - int layer_index, - CoglPipelineWrapMode mode) -{ - CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES; - CoglPipelineLayer *layer; - CoglPipelineLayer *authority; - CoglPipelineWrapModeInternal internal_mode = - public_to_internal_wrap_mode (mode); - - g_return_if_fail (cogl_is_pipeline (pipeline)); - - /* 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 - * pipeline. If the layer is created then it will be owned by - * pipeline. */ - layer = _cogl_pipeline_get_layer (pipeline, layer_index); - - /* Now find the ancestor of the layer that is the authority for the - * state we want to change */ - authority = _cogl_pipeline_layer_get_authority (layer, change); - - _cogl_pipeline_set_layer_wrap_modes (pipeline, layer, authority, - authority->wrap_mode_s, - authority->wrap_mode_t, - internal_mode); -} - -void -cogl_pipeline_set_layer_wrap_mode (CoglPipeline *pipeline, - int layer_index, - CoglPipelineWrapMode mode) -{ - CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES; - CoglPipelineLayer *layer; - CoglPipelineLayer *authority; - CoglPipelineWrapModeInternal internal_mode = - public_to_internal_wrap_mode (mode); - - g_return_if_fail (cogl_is_pipeline (pipeline)); - - /* 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 - * pipeline. If the layer is created then it will be owned by - * pipeline. */ - layer = _cogl_pipeline_get_layer (pipeline, layer_index); - - /* Now find the ancestor of the layer that is the authority for the - * state we want to change */ - authority = _cogl_pipeline_layer_get_authority (layer, change); - - _cogl_pipeline_set_layer_wrap_modes (pipeline, layer, authority, - internal_mode, - internal_mode, - internal_mode); - /* XXX: I wonder if we should really be duplicating the mode into - * the 'r' wrap mode too? */ -} - -/* FIXME: deprecate this API */ -CoglPipelineWrapMode -_cogl_pipeline_layer_get_wrap_mode_s (CoglPipelineLayer *layer) -{ - CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES; - CoglPipelineLayer *authority; - - g_return_val_if_fail (_cogl_is_pipeline_layer (layer), FALSE); - - /* Now find the ancestor of the layer that is the authority for the - * state we want to change */ - authority = _cogl_pipeline_layer_get_authority (layer, change); - - return internal_to_public_wrap_mode (authority->wrap_mode_s); -} - -CoglPipelineWrapMode -cogl_pipeline_get_layer_wrap_mode_s (CoglPipeline *pipeline, int layer_index) -{ - CoglPipelineLayer *layer; - - g_return_val_if_fail (cogl_is_pipeline (pipeline), 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 - * pipeline. If the layer is created then it will be owned by - * pipeline. */ - layer = _cogl_pipeline_get_layer (pipeline, layer_index); - /* FIXME: we shouldn't ever construct a layer in a getter function */ - - return _cogl_pipeline_layer_get_wrap_mode_s (layer); -} - -/* FIXME: deprecate this API */ -CoglPipelineWrapMode -_cogl_pipeline_layer_get_wrap_mode_t (CoglPipelineLayer *layer) -{ - CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES; - CoglPipelineLayer *authority; - - g_return_val_if_fail (_cogl_is_pipeline_layer (layer), FALSE); - - /* Now find the ancestor of the layer that is the authority for the - * state we want to change */ - authority = _cogl_pipeline_layer_get_authority (layer, change); - - return internal_to_public_wrap_mode (authority->wrap_mode_t); -} - -CoglPipelineWrapMode -cogl_pipeline_get_layer_wrap_mode_t (CoglPipeline *pipeline, int layer_index) -{ - CoglPipelineLayer *layer; - - g_return_val_if_fail (cogl_is_pipeline (pipeline), 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 - * pipeline. If the layer is created then it will be owned by - * pipeline. */ - layer = _cogl_pipeline_get_layer (pipeline, layer_index); - /* FIXME: we shouldn't ever construct a layer in a getter function */ - - return _cogl_pipeline_layer_get_wrap_mode_t (layer); -} - -CoglPipelineWrapMode -_cogl_pipeline_layer_get_wrap_mode_p (CoglPipelineLayer *layer) -{ - CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_WRAP_MODES; - CoglPipelineLayer *authority = - _cogl_pipeline_layer_get_authority (layer, change); - - return internal_to_public_wrap_mode (authority->wrap_mode_p); -} - -CoglPipelineWrapMode -cogl_pipeline_get_layer_wrap_mode_p (CoglPipeline *pipeline, int layer_index) -{ - CoglPipelineLayer *layer; - - g_return_val_if_fail (cogl_is_pipeline (pipeline), 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 - * pipeline. If the layer is created then it will be owned by - * pipeline. */ - layer = _cogl_pipeline_get_layer (pipeline, layer_index); - - return _cogl_pipeline_layer_get_wrap_mode_p (layer); -} - -void -_cogl_pipeline_layer_get_wrap_modes (CoglPipelineLayer *layer, - CoglPipelineWrapModeInternal *wrap_mode_s, - CoglPipelineWrapModeInternal *wrap_mode_t, - CoglPipelineWrapModeInternal *wrap_mode_p) -{ - CoglPipelineLayer *authority = - _cogl_pipeline_layer_get_authority (layer, - COGL_PIPELINE_LAYER_STATE_WRAP_MODES); - - *wrap_mode_s = authority->wrap_mode_s; - *wrap_mode_t = authority->wrap_mode_t; - *wrap_mode_p = authority->wrap_mode_p; -} - -gboolean -cogl_pipeline_set_layer_point_sprite_coords_enabled (CoglPipeline *pipeline, - int layer_index, - gboolean enable, - GError **error) -{ - CoglPipelineLayerState change = - COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS; - CoglPipelineLayer *layer; - CoglPipelineLayer *new; - CoglPipelineLayer *authority; - - g_return_val_if_fail (cogl_is_pipeline (pipeline), 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_UNSUPPORTED, - "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 - * pipeline. If the layer is created then it will be owned by - * pipeline. */ - layer = _cogl_pipeline_get_layer (pipeline, layer_index); - - /* Now find the ancestor of the layer that is the authority for the - * state we want to change */ - authority = _cogl_pipeline_layer_get_authority (layer, change); - - if (authority->big_state->point_sprite_coords == enable) - return TRUE; - - new = _cogl_pipeline_layer_pre_change_notify (pipeline, 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 && - _cogl_pipeline_layer_get_parent (authority) != NULL) - { - CoglPipelineLayer *parent = - _cogl_pipeline_layer_get_parent (authority); - CoglPipelineLayer *old_authority = - _cogl_pipeline_layer_get_authority (parent, change); - - if (old_authority->big_state->point_sprite_coords == enable) - { - layer->differences &= ~change; - - g_assert (layer->owner == pipeline); - if (layer->differences == 0) - _cogl_pipeline_prune_empty_layer_difference (pipeline, - 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_pipeline_layer_prune_redundant_ancestry (layer); - } - - return TRUE; -} - -gboolean -cogl_pipeline_get_layer_point_sprite_coords_enabled (CoglPipeline *pipeline, - int layer_index) -{ - CoglPipelineLayerState change = - COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS; - CoglPipelineLayer *layer; - CoglPipelineLayer *authority; - - g_return_val_if_fail (cogl_is_pipeline (pipeline), 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 - * pipeline. If the layer is created then it will be owned by - * pipeline. */ - layer = _cogl_pipeline_get_layer (pipeline, layer_index); - /* FIXME: we shouldn't ever construct a layer in a getter function */ - - authority = _cogl_pipeline_layer_get_authority (layer, change); - - return authority->big_state->point_sprite_coords; -} - typedef struct { CoglPipeline *pipeline; @@ -2970,27 +2231,6 @@ _cogl_pipeline_apply_overrides (CoglPipeline *pipeline, } } -static gboolean -_cogl_pipeline_layer_texture_target_equal (CoglPipelineLayer *authority0, - CoglPipelineLayer *authority1, - CoglPipelineEvalFlags flags) -{ - return authority0->target == authority1->target; -} - -static gboolean -_cogl_pipeline_layer_texture_data_equal (CoglPipelineLayer *authority0, - CoglPipelineLayer *authority1, - CoglPipelineEvalFlags flags) -{ - GLuint gl_handle0, gl_handle1; - - cogl_texture_get_gl_texture (authority0->texture, &gl_handle0, NULL); - cogl_texture_get_gl_texture (authority1->texture, &gl_handle1, NULL); - - return gl_handle0 == gl_handle1; -} - /* Determine the mask of differences between two layers. * * XXX: If layers and pipelines could both be cast to a common Tree @@ -3083,126 +2323,6 @@ _cogl_pipeline_layer_compare_differences (CoglPipelineLayer *layer0, return layers_difference; } -static gboolean -_cogl_pipeline_layer_combine_state_equal (CoglPipelineLayer *authority0, - CoglPipelineLayer *authority1) -{ - CoglPipelineLayerBigState *big_state0 = authority0->big_state; - CoglPipelineLayerBigState *big_state1 = authority1->big_state; - int n_args; - int i; - - if (big_state0->texture_combine_rgb_func != - big_state1->texture_combine_rgb_func) - return FALSE; - - if (big_state0->texture_combine_alpha_func != - big_state1->texture_combine_alpha_func) - return FALSE; - - n_args = - _cogl_get_n_args_for_combine_func (big_state0->texture_combine_rgb_func); - for (i = 0; i < n_args; i++) - { - if ((big_state0->texture_combine_rgb_src[i] != - big_state1->texture_combine_rgb_src[i]) || - (big_state0->texture_combine_rgb_op[i] != - big_state1->texture_combine_rgb_op[i])) - return FALSE; - } - - n_args = - _cogl_get_n_args_for_combine_func (big_state0->texture_combine_alpha_func); - for (i = 0; i < n_args; i++) - { - if ((big_state0->texture_combine_alpha_src[i] != - big_state1->texture_combine_alpha_src[i]) || - (big_state0->texture_combine_alpha_op[i] != - big_state1->texture_combine_alpha_op[i])) - return FALSE; - } - - return TRUE; -} - -static gboolean -_cogl_pipeline_layer_combine_constant_equal (CoglPipelineLayer *authority0, - CoglPipelineLayer *authority1) -{ - return memcmp (authority0->big_state->texture_combine_constant, - authority1->big_state->texture_combine_constant, - sizeof (float) * 4) == 0 ? TRUE : FALSE; -} - -static gboolean -_cogl_pipeline_layer_filters_equal (CoglPipelineLayer *authority0, - CoglPipelineLayer *authority1) -{ - if (authority0->mag_filter != authority1->mag_filter) - return FALSE; - if (authority0->min_filter != authority1->min_filter) - return FALSE; - - return TRUE; -} - -static gboolean -compare_wrap_mode_equal (CoglPipelineWrapMode wrap_mode0, - CoglPipelineWrapMode wrap_mode1) -{ - /* We consider AUTOMATIC to be equivalent to CLAMP_TO_EDGE because - the primitives code is expected to override this to something - else if it wants it to be behave any other way */ - if (wrap_mode0 == COGL_PIPELINE_WRAP_MODE_AUTOMATIC) - wrap_mode0 = COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE; - if (wrap_mode1 == COGL_PIPELINE_WRAP_MODE_AUTOMATIC) - wrap_mode1 = COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE; - - return wrap_mode0 == wrap_mode1; -} - -static gboolean -_cogl_pipeline_layer_wrap_modes_equal (CoglPipelineLayer *authority0, - CoglPipelineLayer *authority1) -{ - if (!compare_wrap_mode_equal (authority0->wrap_mode_s, - authority1->wrap_mode_s) || - !compare_wrap_mode_equal (authority0->wrap_mode_t, - authority1->wrap_mode_t) || - !compare_wrap_mode_equal (authority0->wrap_mode_p, - authority1->wrap_mode_p)) - return FALSE; - - return TRUE; -} - -static gboolean -_cogl_pipeline_layer_user_matrix_equal (CoglPipelineLayer *authority0, - CoglPipelineLayer *authority1) -{ - CoglPipelineLayerBigState *big_state0 = authority0->big_state; - CoglPipelineLayerBigState *big_state1 = authority1->big_state; - - if (!cogl_matrix_equal (&big_state0->matrix, &big_state1->matrix)) - return FALSE; - - return TRUE; -} - -static gboolean -_cogl_pipeline_layer_point_sprite_coords_equal (CoglPipelineLayer *authority0, - CoglPipelineLayer *authority1) -{ - CoglPipelineLayerBigState *big_state0 = authority0->big_state; - CoglPipelineLayerBigState *big_state1 = authority1->big_state; - - return big_state0->point_sprite_coords == big_state1->point_sprite_coords; -} - -typedef gboolean -(*CoglPipelineLayerStateComparitor) (CoglPipelineLayer *authority0, - CoglPipelineLayer *authority1); - static gboolean layer_state_equal (CoglPipelineLayerStateIndex state_index, CoglPipelineLayer **authorities0, @@ -3895,401 +3015,6 @@ _cogl_pipeline_init_default_layers (void) _cogl_pipeline_layer_copy (ctx->default_layer_n); } -static void -setup_texture_combine_state (CoglBlendStringStatement *statement, - CoglPipelineCombineFunc *texture_combine_func, - CoglPipelineCombineSource *texture_combine_src, - CoglPipelineCombineOp *texture_combine_op) -{ - int i; - - switch (statement->function->type) - { - case COGL_BLEND_STRING_FUNCTION_REPLACE: - *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_REPLACE; - break; - case COGL_BLEND_STRING_FUNCTION_MODULATE: - *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_MODULATE; - break; - case COGL_BLEND_STRING_FUNCTION_ADD: - *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_ADD; - break; - case COGL_BLEND_STRING_FUNCTION_ADD_SIGNED: - *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_ADD_SIGNED; - break; - case COGL_BLEND_STRING_FUNCTION_INTERPOLATE: - *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_INTERPOLATE; - break; - case COGL_BLEND_STRING_FUNCTION_SUBTRACT: - *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_SUBTRACT; - break; - case COGL_BLEND_STRING_FUNCTION_DOT3_RGB: - *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_DOT3_RGB; - break; - case COGL_BLEND_STRING_FUNCTION_DOT3_RGBA: - *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_DOT3_RGBA; - break; - } - - for (i = 0; i < statement->function->argc; i++) - { - CoglBlendStringArgument *arg = &statement->args[i]; - - switch (arg->source.info->type) - { - case COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT: - texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_CONSTANT; - break; - case COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE: - texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_TEXTURE; - break; - case COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE_N: - texture_combine_src[i] = - COGL_PIPELINE_COMBINE_SOURCE_TEXTURE0 + arg->source.texture; - break; - case COGL_BLEND_STRING_COLOR_SOURCE_PRIMARY: - texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_PRIMARY_COLOR; - break; - case COGL_BLEND_STRING_COLOR_SOURCE_PREVIOUS: - texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS; - break; - default: - g_warning ("Unexpected texture combine source"); - texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_TEXTURE; - } - - if (arg->source.mask == COGL_BLEND_STRING_CHANNEL_MASK_RGB) - { - if (statement->args[i].source.one_minus) - texture_combine_op[i] = - COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_COLOR; - else - texture_combine_op[i] = COGL_PIPELINE_COMBINE_OP_SRC_COLOR; - } - else - { - if (statement->args[i].source.one_minus) - texture_combine_op[i] = - COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_ALPHA; - else - texture_combine_op[i] = COGL_PIPELINE_COMBINE_OP_SRC_ALPHA; - } - } -} - -gboolean -cogl_pipeline_set_layer_combine (CoglPipeline *pipeline, - int layer_index, - const char *combine_description, - GError **error) -{ - CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_COMBINE; - CoglPipelineLayer *authority; - CoglPipelineLayer *layer; - CoglBlendStringStatement statements[2]; - CoglBlendStringStatement split[2]; - CoglBlendStringStatement *rgb; - CoglBlendStringStatement *a; - GError *internal_error = NULL; - int count; - - g_return_val_if_fail (cogl_is_pipeline (pipeline), 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 - * pipeline. If the layer is created then it will be owned by - * pipeline. */ - layer = _cogl_pipeline_get_layer (pipeline, layer_index); - - /* Now find the ancestor of the layer that is the authority for the - * state we want to change */ - authority = _cogl_pipeline_layer_get_authority (layer, state); - - count = - _cogl_blend_string_compile (combine_description, - COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE, - statements, - &internal_error); - if (!count) - { - if (error) - g_propagate_error (error, internal_error); - else - { - g_warning ("Cannot compile combine description: %s\n", - internal_error->message); - g_error_free (internal_error); - } - return FALSE; - } - - if (statements[0].mask == COGL_BLEND_STRING_CHANNEL_MASK_RGBA) - { - _cogl_blend_string_split_rgba_statement (statements, - &split[0], &split[1]); - rgb = &split[0]; - a = &split[1]; - } - else - { - rgb = &statements[0]; - a = &statements[1]; - } - - /* FIXME: compare the new state with the current state! */ - - /* possibly flush primitives referencing the current state... */ - layer = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state); - - setup_texture_combine_state (rgb, - &layer->big_state->texture_combine_rgb_func, - layer->big_state->texture_combine_rgb_src, - layer->big_state->texture_combine_rgb_op); - - setup_texture_combine_state (a, - &layer->big_state->texture_combine_alpha_func, - layer->big_state->texture_combine_alpha_src, - layer->big_state->texture_combine_alpha_op); - - /* 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 && - _cogl_pipeline_layer_get_parent (authority) != NULL) - { - CoglPipelineLayer *parent = _cogl_pipeline_layer_get_parent (authority); - CoglPipelineLayer *old_authority = - _cogl_pipeline_layer_get_authority (parent, state); - - if (_cogl_pipeline_layer_combine_state_equal (authority, - old_authority)) - { - layer->differences &= ~state; - - g_assert (layer->owner == pipeline); - if (layer->differences == 0) - _cogl_pipeline_prune_empty_layer_difference (pipeline, - layer); - goto changed; - } - } - - /* 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 |= state; - _cogl_pipeline_layer_prune_redundant_ancestry (layer); - } - -changed: - - _cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS); - return TRUE; -} - -void -cogl_pipeline_set_layer_combine_constant (CoglPipeline *pipeline, - int layer_index, - const CoglColor *constant_color) -{ - CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT; - CoglPipelineLayer *layer; - CoglPipelineLayer *authority; - CoglPipelineLayer *new; - float color_as_floats[4]; - - g_return_if_fail (cogl_is_pipeline (pipeline)); - - /* 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 - * pipeline. If the layer is created then it will be owned by - * pipeline. */ - layer = _cogl_pipeline_get_layer (pipeline, layer_index); - - /* Now find the ancestor of the layer that is the authority for the - * state we want to change */ - authority = _cogl_pipeline_layer_get_authority (layer, state); - - color_as_floats[0] = cogl_color_get_red_float (constant_color); - color_as_floats[1] = cogl_color_get_green_float (constant_color); - color_as_floats[2] = cogl_color_get_blue_float (constant_color); - color_as_floats[3] = cogl_color_get_alpha_float (constant_color); - - if (memcmp (authority->big_state->texture_combine_constant, - color_as_floats, sizeof (float) * 4) == 0) - return; - - new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state); - 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 && - _cogl_pipeline_layer_get_parent (authority) != NULL) - { - CoglPipelineLayer *parent = - _cogl_pipeline_layer_get_parent (authority); - CoglPipelineLayer *old_authority = - _cogl_pipeline_layer_get_authority (parent, state); - CoglPipelineLayerBigState *old_big_state = old_authority->big_state; - - if (memcmp (old_big_state->texture_combine_constant, - color_as_floats, sizeof (float) * 4) == 0) - { - layer->differences &= ~state; - - g_assert (layer->owner == pipeline); - if (layer->differences == 0) - _cogl_pipeline_prune_empty_layer_difference (pipeline, - layer); - goto changed; - } - } - } - - memcpy (layer->big_state->texture_combine_constant, - color_as_floats, - sizeof (color_as_floats)); - - /* 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 |= state; - _cogl_pipeline_layer_prune_redundant_ancestry (layer); - } - -changed: - - _cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS); -} - -void -_cogl_pipeline_get_layer_combine_constant (CoglPipeline *pipeline, - int layer_index, - float *constant) -{ - CoglPipelineLayerState change = - COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT; - CoglPipelineLayer *layer; - CoglPipelineLayer *authority; - - g_return_if_fail (cogl_is_pipeline (pipeline)); - - /* 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 - * pipeline. If the layer is created then it will be owned by - * pipeline. */ - layer = _cogl_pipeline_get_layer (pipeline, layer_index); - /* FIXME: we shouldn't ever construct a layer in a getter function */ - - authority = _cogl_pipeline_layer_get_authority (layer, change); - memcpy (constant, authority->big_state->texture_combine_constant, - sizeof (float) * 4); -} - -/* We should probably make a public API version of this that has a - matrix out-param. For an internal API it's good to be able to avoid - copying the matrix */ -const CoglMatrix * -_cogl_pipeline_get_layer_matrix (CoglPipeline *pipeline, int layer_index) -{ - CoglPipelineLayerState change = - COGL_PIPELINE_LAYER_STATE_USER_MATRIX; - CoglPipelineLayer *layer; - CoglPipelineLayer *authority; - - g_return_val_if_fail (cogl_is_pipeline (pipeline), NULL); - - layer = _cogl_pipeline_get_layer (pipeline, layer_index); - - authority = _cogl_pipeline_layer_get_authority (layer, change); - return &authority->big_state->matrix; -} - -void -cogl_pipeline_set_layer_matrix (CoglPipeline *pipeline, - int layer_index, - const CoglMatrix *matrix) -{ - CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_USER_MATRIX; - CoglPipelineLayer *layer; - CoglPipelineLayer *authority; - CoglPipelineLayer *new; - - g_return_if_fail (cogl_is_pipeline (pipeline)); - - /* 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 - * pipeline. If the layer is created then it will be owned by - * pipeline. */ - layer = _cogl_pipeline_get_layer (pipeline, layer_index); - - /* Now find the ancestor of the layer that is the authority for the - * state we want to change */ - authority = _cogl_pipeline_layer_get_authority (layer, state); - - if (cogl_matrix_equal (matrix, &authority->big_state->matrix)) - return; - - new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state); - 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 && - _cogl_pipeline_layer_get_parent (authority) != NULL) - { - CoglPipelineLayer *parent = - _cogl_pipeline_layer_get_parent (authority); - CoglPipelineLayer *old_authority = - _cogl_pipeline_layer_get_authority (parent, state); - - if (cogl_matrix_equal (matrix, &old_authority->big_state->matrix)) - { - layer->differences &= ~state; - - g_assert (layer->owner == pipeline); - if (layer->differences == 0) - _cogl_pipeline_prune_empty_layer_difference (pipeline, - layer); - return; - } - } - } - - layer->big_state->matrix = *matrix; - - /* 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 |= state; - _cogl_pipeline_layer_prune_redundant_ancestry (layer); - } -} - void cogl_pipeline_remove_layer (CoglPipeline *pipeline, int layer_index) { @@ -4391,92 +3116,6 @@ cogl_pipeline_get_n_layers (CoglPipeline *pipeline) return authority->n_layers; } -/* FIXME: deprecate and replace with - * cogl_pipeline_get_layer_texture() instead. */ -CoglHandle -_cogl_pipeline_layer_get_texture (CoglPipelineLayer *layer) -{ - g_return_val_if_fail (_cogl_is_pipeline_layer (layer), - COGL_INVALID_HANDLE); - - return _cogl_pipeline_layer_get_texture_real (layer); -} - -gboolean -_cogl_pipeline_layer_has_user_matrix (CoglPipeline *pipeline, - int layer_index) -{ - CoglPipelineLayer *layer; - CoglPipelineLayer *authority; - - layer = _cogl_pipeline_get_layer (pipeline, layer_index); - - authority = - _cogl_pipeline_layer_get_authority (layer, - COGL_PIPELINE_LAYER_STATE_USER_MATRIX); - - /* If the authority is the default pipeline then no, otherwise yes */ - return _cogl_pipeline_layer_get_parent (authority) ? TRUE : FALSE; -} - -void -_cogl_pipeline_layer_get_filters (CoglPipelineLayer *layer, - CoglPipelineFilter *min_filter, - CoglPipelineFilter *mag_filter) -{ - CoglPipelineLayer *authority = - _cogl_pipeline_layer_get_authority (layer, - COGL_PIPELINE_LAYER_STATE_FILTERS); - - *min_filter = authority->min_filter; - *mag_filter = authority->mag_filter; -} - -void -_cogl_pipeline_get_layer_filters (CoglPipeline *pipeline, - int layer_index, - CoglPipelineFilter *min_filter, - CoglPipelineFilter *mag_filter) -{ - CoglPipelineLayer *layer; - CoglPipelineLayer *authority; - - g_return_if_fail (cogl_is_pipeline (pipeline)); - - layer = _cogl_pipeline_get_layer (pipeline, layer_index); - - authority = - _cogl_pipeline_layer_get_authority (layer, - COGL_PIPELINE_LAYER_STATE_FILTERS); - - *min_filter = authority->min_filter; - *mag_filter = authority->mag_filter; -} - -CoglPipelineFilter -_cogl_pipeline_get_layer_min_filter (CoglPipeline *pipeline, - int layer_index) -{ - CoglPipelineFilter min_filter; - CoglPipelineFilter mag_filter; - - _cogl_pipeline_get_layer_filters (pipeline, layer_index, - &min_filter, &mag_filter); - return min_filter; -} - -CoglPipelineFilter -_cogl_pipeline_get_layer_mag_filter (CoglPipeline *pipeline, - int layer_index) -{ - CoglPipelineFilter min_filter; - CoglPipelineFilter mag_filter; - - _cogl_pipeline_get_layer_filters (pipeline, layer_index, - &min_filter, &mag_filter); - return mag_filter; -} - void _cogl_pipeline_layer_pre_paint (CoglPipelineLayer *layer) { @@ -4512,107 +3151,6 @@ _cogl_pipeline_pre_paint_for_layer (CoglPipeline *pipeline, _cogl_pipeline_layer_pre_paint (layer); } -CoglPipelineFilter -_cogl_pipeline_layer_get_min_filter (CoglPipelineLayer *layer) -{ - CoglPipelineLayer *authority; - - g_return_val_if_fail (_cogl_is_pipeline_layer (layer), 0); - - authority = - _cogl_pipeline_layer_get_authority (layer, - COGL_PIPELINE_LAYER_STATE_FILTERS); - - return authority->min_filter; -} - -CoglPipelineFilter -_cogl_pipeline_layer_get_mag_filter (CoglPipelineLayer *layer) -{ - CoglPipelineLayer *authority; - - g_return_val_if_fail (_cogl_is_pipeline_layer (layer), 0); - - authority = - _cogl_pipeline_layer_get_authority (layer, - COGL_PIPELINE_LAYER_STATE_FILTERS); - - return authority->mag_filter; -} - -void -cogl_pipeline_set_layer_filters (CoglPipeline *pipeline, - int layer_index, - CoglPipelineFilter min_filter, - CoglPipelineFilter mag_filter) -{ - CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_FILTERS; - CoglPipelineLayer *layer; - CoglPipelineLayer *authority; - CoglPipelineLayer *new; - - g_return_if_fail (cogl_is_pipeline (pipeline)); - - /* 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 - * pipeline. If the layer is created then it will be owned by - * pipeline. */ - layer = _cogl_pipeline_get_layer (pipeline, layer_index); - - /* Now find the ancestor of the layer that is the authority for the - * state we want to change */ - authority = _cogl_pipeline_layer_get_authority (layer, state); - - if (authority->min_filter == min_filter && - authority->mag_filter == mag_filter) - return; - - new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state); - 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 && - _cogl_pipeline_layer_get_parent (authority) != NULL) - { - CoglPipelineLayer *parent = - _cogl_pipeline_layer_get_parent (authority); - CoglPipelineLayer *old_authority = - _cogl_pipeline_layer_get_authority (parent, state); - - if (old_authority->min_filter == min_filter && - old_authority->mag_filter == mag_filter) - { - layer->differences &= ~state; - - g_assert (layer->owner == pipeline); - if (layer->differences == 0) - _cogl_pipeline_prune_empty_layer_difference (pipeline, - layer); - return; - } - } - } - - layer->min_filter = min_filter; - layer->mag_filter = mag_filter; - - /* 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 |= state; - _cogl_pipeline_layer_prune_redundant_ancestry (layer); - } -} - /* While a pipeline is referenced by the Cogl journal we can not allow * modifications, so this gives us a mechanism to track journal * references separately */ @@ -4668,178 +3206,6 @@ _cogl_pipeline_set_static_breadcrumb (CoglPipeline *pipeline, pipeline->static_breadcrumb = breadcrumb; } -static void -_cogl_pipeline_layer_hash_unit_state (CoglPipelineLayer *authority, - CoglPipelineLayer **authorities, - CoglPipelineHashState *state) -{ - int unit = authority->unit_index; - state->hash = - _cogl_util_one_at_a_time_hash (state->hash, &unit, sizeof (unit)); -} - -static void -_cogl_pipeline_layer_hash_texture_target_state (CoglPipelineLayer *authority, - CoglPipelineLayer **authorities, - CoglPipelineHashState *state) -{ - GLenum gl_target = authority->target; - - state->hash = - _cogl_util_one_at_a_time_hash (state->hash, &gl_target, sizeof (gl_target)); -} - -static void -_cogl_pipeline_layer_hash_texture_data_state (CoglPipelineLayer *authority, - CoglPipelineLayer **authorities, - CoglPipelineHashState *state) -{ - GLuint gl_handle; - - cogl_texture_get_gl_texture (authority->texture, &gl_handle, NULL); - - state->hash = - _cogl_util_one_at_a_time_hash (state->hash, &gl_handle, sizeof (gl_handle)); -} - -static void -_cogl_pipeline_layer_hash_filters_state (CoglPipelineLayer *authority, - CoglPipelineLayer **authorities, - CoglPipelineHashState *state) -{ - unsigned int hash = state->hash; - hash = _cogl_util_one_at_a_time_hash (hash, &authority->mag_filter, - sizeof (authority->mag_filter)); - hash = _cogl_util_one_at_a_time_hash (hash, &authority->min_filter, - sizeof (authority->min_filter)); - state->hash = hash; -} - -static void -_cogl_pipeline_layer_hash_wrap_modes_state (CoglPipelineLayer *authority, - CoglPipelineLayer **authorities, - CoglPipelineHashState *state) -{ - unsigned int hash = state->hash; - hash = _cogl_util_one_at_a_time_hash (hash, &authority->wrap_mode_s, - sizeof (authority->wrap_mode_s)); - hash = _cogl_util_one_at_a_time_hash (hash, &authority->wrap_mode_t, - sizeof (authority->wrap_mode_t)); - hash = _cogl_util_one_at_a_time_hash (hash, &authority->wrap_mode_p, - sizeof (authority->wrap_mode_p)); - state->hash = hash; -} - -static void -_cogl_pipeline_layer_hash_combine_state (CoglPipelineLayer *authority, - CoglPipelineLayer **authorities, - CoglPipelineHashState *state) -{ - unsigned int hash = state->hash; - CoglPipelineLayerBigState *b = authority->big_state; - int n_args; - int i; - - hash = _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_rgb_func, - sizeof (b->texture_combine_rgb_func)); - n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_rgb_func); - for (i = 0; i < n_args; i++) - { - hash = - _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_rgb_src[i], - sizeof (b->texture_combine_rgb_src[i])); - hash = - _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_rgb_op[i], - sizeof (b->texture_combine_rgb_op[i])); - } - - hash = _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_alpha_func, - sizeof (b->texture_combine_alpha_func)); - n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_alpha_func); - for (i = 0; i < n_args; i++) - { - hash = - _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_alpha_src[i], - sizeof (b->texture_combine_alpha_src[i])); - hash = - _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_alpha_op[i], - sizeof (b->texture_combine_alpha_op[i])); - } - - state->hash = hash; -} - -static void -_cogl_pipeline_layer_hash_combine_constant_state (CoglPipelineLayer *authority, - CoglPipelineLayer **authorities, - CoglPipelineHashState *state) -{ - CoglPipelineLayerBigState *b = authority->big_state; - gboolean need_hash = FALSE; - int n_args; - int i; - - /* XXX: If the user also asked to hash the ALPHA_FUNC_STATE then it - * would be nice if we could combine the n_args loops in this - * function and _cogl_pipeline_layer_hash_combine_state. - */ - - n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_rgb_func); - for (i = 0; i < n_args; i++) - { - if (b->texture_combine_rgb_src[i] == - COGL_PIPELINE_COMBINE_SOURCE_CONSTANT) - { - /* XXX: should we be careful to only hash the alpha - * component in the COGL_PIPELINE_COMBINE_OP_SRC_ALPHA case? */ - need_hash = TRUE; - goto done; - } - } - - n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_alpha_func); - for (i = 0; i < n_args; i++) - { - if (b->texture_combine_alpha_src[i] == - COGL_PIPELINE_COMBINE_SOURCE_CONSTANT) - { - /* XXX: should we be careful to only hash the alpha - * component in the COGL_PIPELINE_COMBINE_OP_SRC_ALPHA case? */ - need_hash = TRUE; - goto done; - } - } - -done: - if (need_hash) - { - float *constant = b->texture_combine_constant; - state->hash = _cogl_util_one_at_a_time_hash (state->hash, constant, - sizeof (float) * 4); - } -} - -static void -_cogl_pipeline_layer_hash_user_matrix_state (CoglPipelineLayer *authority, - CoglPipelineLayer **authorities, - CoglPipelineHashState *state) -{ - CoglPipelineLayerBigState *big_state = authority->big_state; - state->hash = _cogl_util_one_at_a_time_hash (state->hash, &big_state->matrix, - sizeof (float) * 16); -} - -static void -_cogl_pipeline_layer_hash_point_sprite_state (CoglPipelineLayer *authority, - CoglPipelineLayer **authorities, - CoglPipelineHashState *state) -{ - CoglPipelineLayerBigState *big_state = authority->big_state; - state->hash = - _cogl_util_one_at_a_time_hash (state->hash, &big_state->point_sprite_coords, - sizeof (big_state->point_sprite_coords)); -} - typedef void (*LayerStateHashFunction) (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, CoglPipelineHashState *state); diff --git a/cogl/cogl-pipeline.h b/cogl/cogl-pipeline.h index 0bcbb35f1..0ea79e959 100644 --- a/cogl/cogl-pipeline.h +++ b/cogl/cogl-pipeline.h @@ -31,7 +31,6 @@ G_BEGIN_DECLS #include -#include /** * SECTION:cogl-pipeline @@ -51,84 +50,6 @@ typedef struct _CoglPipeline CoglPipeline; #define COGL_PIPELINE(OBJECT) ((CoglPipeline *)OBJECT) -/** - * CoglPipelineFilter: - * @COGL_PIPELINE_FILTER_NEAREST: Measuring in manhatten distance from the, - * current pixel center, use the nearest texture texel - * @COGL_PIPELINE_FILTER_LINEAR: Use the weighted average of the 4 texels - * nearest the current pixel center - * @COGL_PIPELINE_FILTER_NEAREST_MIPMAP_NEAREST: Select the mimap level whose - * texel size most closely matches the current pixel, and use the - * %COGL_PIPELINE_FILTER_NEAREST criterion - * @COGL_PIPELINE_FILTER_LINEAR_MIPMAP_NEAREST: Select the mimap level whose - * texel size most closely matches the current pixel, and use the - * %COGL_PIPELINE_FILTER_LINEAR criterion - * @COGL_PIPELINE_FILTER_NEAREST_MIPMAP_LINEAR: Select the two mimap levels - * whose texel size most closely matches the current pixel, use - * the %COGL_PIPELINE_FILTER_NEAREST criterion on each one and take - * their weighted average - * @COGL_PIPELINE_FILTER_LINEAR_MIPMAP_LINEAR: Select the two mimap levels - * whose texel size most closely matches the current pixel, use - * the %COGL_PIPELINE_FILTER_LINEAR criterion on each one and take - * their weighted average - * - * Texture filtering is used whenever the current pixel maps either to more - * than one texture element (texel) or less than one. These filter enums - * correspond to different strategies used to come up with a pixel color, by - * possibly referring to multiple neighbouring texels and taking a weighted - * average or simply using the nearest texel. - */ -typedef enum { - COGL_PIPELINE_FILTER_NEAREST = 0x2600, - COGL_PIPELINE_FILTER_LINEAR = 0x2601, - COGL_PIPELINE_FILTER_NEAREST_MIPMAP_NEAREST = 0x2700, - COGL_PIPELINE_FILTER_LINEAR_MIPMAP_NEAREST = 0x2701, - COGL_PIPELINE_FILTER_NEAREST_MIPMAP_LINEAR = 0x2702, - COGL_PIPELINE_FILTER_LINEAR_MIPMAP_LINEAR = 0x2703 -} CoglPipelineFilter; -/* NB: these values come from the equivalents in gl.h */ - -/** - * CoglPipelineWrapMode: - * @COGL_PIPELINE_WRAP_MODE_REPEAT: The texture will be repeated. This - * is useful for example to draw a tiled background. - * @COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE: The coordinates outside the - * range 0→1 will sample copies of the edge pixels of the - * texture. This is useful to avoid artifacts if only one copy of - * the texture is being rendered. - * @COGL_PIPELINE_WRAP_MODE_AUTOMATIC: Cogl will try to automatically - * decide which of the above two to use. For cogl_rectangle(), it - * will use repeat mode if any of the texture coordinates are - * outside the range 0→1, otherwise it will use clamp to edge. For - * cogl_polygon() it will always use repeat mode. For - * cogl_vertex_buffer_draw() it will use repeat mode except for - * layers that have point sprite coordinate generation enabled. This - * is the default value. - * - * The wrap mode specifies what happens when texture coordinates - * outside the range 0→1 are used. Note that if the filter mode is - * anything but %COGL_PIPELINE_FILTER_NEAREST then texels outside the - * range 0→1 might be used even when the coordinate is exactly 0 or 1 - * because OpenGL will try to sample neighbouring pixels. For example - * if you are trying to render the full texture then you may get - * artifacts around the edges when the pixels from the other side are - * merged in if the wrap mode is set to repeat. - * - * Since: 2.0 - */ -/* GL_ALWAYS is just used here as a value that is known not to clash - * with any valid GL wrap modes - * - * XXX: keep the values in sync with the CoglPipelineWrapModeInternal - * enum so no conversion is actually needed. - */ -typedef enum { - COGL_PIPELINE_WRAP_MODE_REPEAT = 0x2901, - COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE = 0x812F, - COGL_PIPELINE_WRAP_MODE_AUTOMATIC = 0x0207 -} CoglPipelineWrapMode; -/* NB: these values come from the equivalents in gl.h */ - /** * cogl_pipeline_new: * @@ -172,360 +93,6 @@ cogl_pipeline_copy (CoglPipeline *source); gboolean cogl_is_pipeline (CoglHandle handle); -/** - * cogl_pipeline_set_layer: - * @pipeline: A #CoglPipeline object - * @layer_index: the index of the layer - * @texture: a #CoglHandle for the layer object - * - * In addition to the standard OpenGL lighting model a Cogl pipeline 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. - * - * In the future, we may define other types of pipeline layers, such - * as purely GLSL based layers. - * - * Since: 2.0 - */ -void -cogl_pipeline_set_layer_texture (CoglPipeline *pipeline, - int layer_index, - CoglHandle texture); - -/** - * cogl_pipeline_remove_layer: - * @pipeline: A #CoglPipeline object - * @layer_index: Specifies the layer you want to remove - * - * This function removes a layer from your pipeline - */ -void -cogl_pipeline_remove_layer (CoglPipeline *pipeline, - int layer_index); - -/** - * cogl_pipeline_set_layer_combine: - * @pipeline: A #CoglPipeline object - * @layer_index: Specifies the layer you want define a combine function for - * @blend_string: A Cogl blend string - * describing the desired texture combine function. - * @error: A #GError that may report parse errors or lack of GPU/driver - * support. May be %NULL, in which case a warning will be printed out if an - * error is encountered. - * - * If not already familiar; you can refer - * here for an overview of what blend - * strings are and there syntax. - * - * These are all the functions available for texture combining: - * - * REPLACE(arg0) = arg0 - * MODULATE(arg0, arg1) = arg0 x arg1 - * ADD(arg0, arg1) = arg0 + arg1 - * ADD_SIGNED(arg0, arg1) = arg0 + arg1 - 0.5 - * INTERPOLATE(arg0, arg1, arg2) = arg0 x arg2 + arg1 x (1 - arg2) - * SUBTRACT(arg0, arg1) = arg0 - arg1 - * - * - * DOT3_RGB(arg0, arg1) = 4 x ((arg0[R] - 0.5)) * (arg1[R] - 0.5) + - * (arg0[G] - 0.5)) * (arg1[G] - 0.5) + - * (arg0[B] - 0.5)) * (arg1[B] - 0.5)) - * - * - * - * - * DOT3_RGBA(arg0, arg1) = 4 x ((arg0[R] - 0.5)) * (arg1[R] - 0.5) + - * (arg0[G] - 0.5)) * (arg1[G] - 0.5) + - * (arg0[B] - 0.5)) * (arg1[B] - 0.5)) - * - * - * - * - * Refer to the - * color-source syntax for - * describing the arguments. The valid source names for texture combining - * are: - * - * - * TEXTURE - * Use the color from the current texture layer - * - * - * TEXTURE_0, TEXTURE_1, etc - * Use the color from the specified texture layer - * - * - * CONSTANT - * Use the color from the constant given with - * cogl_pipeline_set_layer_constant() - * - * - * PRIMARY - * Use the color of the pipeline as set with - * cogl_pipeline_set_color() - * - * - * PREVIOUS - * Either use the texture color from the previous layer, or - * if this is layer 0, use the color of the pipeline as set with - * cogl_pipeline_set_color() - * - * - * - * - * Layer Combine Examples - * This is effectively what the default blending is: - * - * RGBA = MODULATE (PREVIOUS, TEXTURE) - * - * This could be used to cross-fade between two images, using - * the alpha component of a constant as the interpolator. The constant - * color is given by calling cogl_pipeline_set_layer_constant. - * - * RGBA = INTERPOLATE (PREVIOUS, TEXTURE, CONSTANT[A]) - * - * - * - * You can't give a multiplication factor for arguments as you can - * with blending. - * - * Return value: %TRUE if the blend string was successfully parsed, and the - * described texture combining is supported by the underlying driver and - * or hardware. On failure, %FALSE is returned and @error is set - * - * Since: 2.0 - */ -gboolean -cogl_pipeline_set_layer_combine (CoglPipeline *pipeline, - int layer_index, - const char *blend_string, - GError **error); - -/** - * cogl_pipeline_set_layer_combine_constant: - * @pipeline: A #CoglPipeline object - * @layer_index: Specifies the layer you want to specify a constant used - * for texture combining - * @constant: The constant color you want - * - * When you are using the 'CONSTANT' color source in a layer combine - * description then you can use this function to define its value. - * - * Since: 2.0 - */ -void -cogl_pipeline_set_layer_combine_constant (CoglPipeline *pipeline, - int layer_index, - const CoglColor *constant); - -/** - * cogl_pipeline_set_layer_matrix: - * @pipeline: A #CoglPipeline object - * @layer_index: the index for the layer inside @pipeline - * @matrix: the transformation matrix for the layer - * - * This function lets you set a matrix that can be used to e.g. translate - * and rotate a single layer of a pipeline used to fill your geometry. - */ -void -cogl_pipeline_set_layer_matrix (CoglPipeline *pipeline, - int layer_index, - const CoglMatrix *matrix); - -/** - * cogl_pipeline_get_n_layers: - * @pipeline: A #CoglPipeline object - * - * Retrieves the number of layers defined for the given @pipeline - * - * Return value: the number of layers - * - * Since: 2.0 - */ -int -cogl_pipeline_get_n_layers (CoglPipeline *pipeline); - -/** - * cogl_pipeline_set_layer_filters: - * @pipeline: A #CoglPipeline object - * @layer_index: the layer number to change. - * @min_filter: the filter used when scaling a texture down. - * @mag_filter: the filter used when magnifying a texture. - * - * Changes the decimation and interpolation filters used when a texture is - * drawn at other scales than 100%. - */ -void -cogl_pipeline_set_layer_filters (CoglPipeline *pipeline, - int layer_index, - CoglPipelineFilter min_filter, - CoglPipelineFilter mag_filter); - -/** - * cogl_pipeline_set_layer_point_sprite_coords_enabled: - * @pipeline: a #CoglHandle to a pipeline. - * @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: 2.0 - */ -gboolean -cogl_pipeline_set_layer_point_sprite_coords_enabled (CoglPipeline *pipeline, - int layer_index, - gboolean enable, - GError **error); - -/** - * cogl_pipeline_get_layer_point_sprite_coords_enabled: - * @pipeline: a #CoglHandle to a pipeline. - * @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: 2.0 - */ -gboolean -cogl_pipeline_get_layer_point_sprite_coords_enabled (CoglPipeline *pipeline, - int layer_index); - -/** - * cogl_pipeline_get_layer_wrap_mode_s: - * @pipeline: A #CoglPipeline object - * @layer_index: the layer number to change. - * - * Returns the wrap mode for the 's' coordinate of texture lookups on this - * layer. - * - * Return value: the wrap mode for the 's' coordinate of texture lookups on - * this layer. - * - * Since: 1.6 - */ -CoglPipelineWrapMode -cogl_pipeline_get_layer_wrap_mode_s (CoglPipeline *pipeline, - int layer_index); - -/** - * cogl_pipeline_set_layer_wrap_mode_s: - * @pipeline: A #CoglPipeline object - * @layer_index: the layer number to change. - * @mode: the new wrap mode - * - * Sets the wrap mode for the 's' coordinate of texture lookups on this layer. - * - * Since: 2.0 - */ -void -cogl_pipeline_set_layer_wrap_mode_s (CoglPipeline *pipeline, - int layer_index, - CoglPipelineWrapMode mode); - -/** - * cogl_pipeline_get_layer_wrap_mode_t: - * @pipeline: A #CoglPipeline object - * @layer_index: the layer number to change. - * - * Returns the wrap mode for the 't' coordinate of texture lookups on this - * layer. - * - * Return value: the wrap mode for the 't' coordinate of texture lookups on - * this layer. - * - * Since: 1.6 - */ -CoglPipelineWrapMode -cogl_pipeline_get_layer_wrap_mode_t (CoglPipeline *pipeline, - int layer_index); - - -/** - * cogl_pipeline_set_layer_wrap_mode_t: - * @pipeline: A #CoglPipeline object - * @layer_index: the layer number to change. - * @mode: the new wrap mode - * - * Sets the wrap mode for the 't' coordinate of texture lookups on this layer. - * - * Since: 2.0 - */ -void -cogl_pipeline_set_layer_wrap_mode_t (CoglPipeline *pipeline, - int layer_index, - CoglPipelineWrapMode mode); - -/** - * cogl_pipeline_get_layer_wrap_mode_p: - * @pipeline: A #CoglPipeline object - * @layer_index: the layer number to change. - * - * Returns the wrap mode for the 'p' coordinate of texture lookups on this - * layer. - * - * Return value: the wrap mode for the 'p' coordinate of texture lookups on - * this layer. - * - * Since: 1.6 - */ -CoglPipelineWrapMode -cogl_pipeline_get_layer_wrap_mode_p (CoglPipeline *pipeline, - int layer_index); - -/** - * cogl_pipeline_set_layer_wrap_mode_p: - * @pipeline: A #CoglPipeline object - * @layer_index: the layer number to change. - * @mode: the new wrap mode - * - * Sets the wrap mode for the 'p' coordinate of texture lookups on - * this layer. 'p' is the third coordinate. - * - * Since: 2.0 - */ -void -cogl_pipeline_set_layer_wrap_mode_p (CoglPipeline *pipeline, - int layer_index, - CoglPipelineWrapMode mode); - -/** - * cogl_pipeline_set_layer_wrap_mode: - * @pipeline: A #CoglPipeline object - * @layer_index: the layer number to change. - * @mode: the new wrap mode - * - * Sets the wrap mode for all three coordinates of texture lookups on - * this layer. This is equivalent to calling - * cogl_pipeline_set_layer_wrap_mode_s(), - * cogl_pipeline_set_layer_wrap_mode_t() and - * cogl_pipeline_set_layer_wrap_mode_p() separately. - * - * Since: 2.0 - */ -void -cogl_pipeline_set_layer_wrap_mode (CoglPipeline *pipeline, - int layer_index, - CoglPipelineWrapMode mode); - #ifdef COGL_ENABLE_EXPERIMENTAL_API /** diff --git a/cogl/cogl.h b/cogl/cogl.h index 6d433c293..db4366b6c 100644 --- a/cogl/cogl.h +++ b/cogl/cogl.h @@ -89,6 +89,7 @@ typedef struct _CoglFramebuffer CoglFramebuffer; #include #include #include +#include #include #ifdef COGL_HAS_XLIB #include diff --git a/doc/reference/cogl-2.0-experimental/Makefile.am b/doc/reference/cogl-2.0-experimental/Makefile.am index b2b9b2f4e..e34e89b97 100644 --- a/doc/reference/cogl-2.0-experimental/Makefile.am +++ b/doc/reference/cogl-2.0-experimental/Makefile.am @@ -75,6 +75,7 @@ IGNORE_HFILES=\ cogl-pipeline-opengl-private.h \ cogl-pipeline-private.h \ cogl-pipeline-state-private.h \ + cogl-pipeline-layer-state-private.h \ cogl-pipeline-progend-glsl-private.h \ cogl-pipeline-vertend-fixed-private.h \ cogl-pipeline-vertend-glsl-private.h \ diff --git a/doc/reference/cogl/Makefile.am b/doc/reference/cogl/Makefile.am index e4cd24b99..fb5dd3f3c 100644 --- a/doc/reference/cogl/Makefile.am +++ b/doc/reference/cogl/Makefile.am @@ -73,6 +73,7 @@ IGNORE_HFILES=\ cogl-pipeline-opengl-private.h \ cogl-pipeline-private.h \ cogl-pipeline-state-private.h \ + cogl-pipeline-layer-state-private.h \ cogl-pipeline-progend-glsl-private.h \ cogl-pipeline-vertend-fixed-private.h \ cogl-pipeline-vertend-glsl-private.h \