diff --git a/cogl/Makefile.am b/cogl/Makefile.am index b5d91ae0f..be9fd1673 100644 --- a/cogl/Makefile.am +++ b/cogl/Makefile.am @@ -67,7 +67,6 @@ cogl_public_h = \ $(srcdir)/cogl-fixed.h \ $(srcdir)/cogl-depth-state.h \ $(srcdir)/cogl-material-compat.h \ - $(srcdir)/cogl-pipeline.h \ $(srcdir)/cogl-vector.h \ $(srcdir)/cogl-euler.h \ $(srcdir)/cogl-quaternion.h \ @@ -99,6 +98,8 @@ cogl_experimental_h = \ $(srcdir)/cogl-onscreen-template.h \ $(srcdir)/cogl-display.h \ $(srcdir)/cogl-context.h \ + $(srcdir)/cogl-pipeline.h \ + $(srcdir)/cogl-pipeline-state.h \ $(srcdir)/cogl2-path.h \ $(srcdir)/cogl2-clip-state.h \ $(srcdir)/cogl2-experimental.h \ @@ -244,6 +245,8 @@ cogl_sources_c = \ $(srcdir)/cogl-depth-state-private.h \ $(srcdir)/cogl-pipeline.c \ $(srcdir)/cogl-pipeline-private.h \ + $(srcdir)/cogl-pipeline-state.c \ + $(srcdir)/cogl-pipeline-state-private.h \ $(srcdir)/cogl-pipeline-opengl.c \ $(srcdir)/cogl-pipeline-opengl-private.h \ $(srcdir)/cogl-pipeline-fragend-glsl.c \ diff --git a/cogl/cogl-pipeline-private.h b/cogl/cogl-pipeline-private.h index 6e8fc359d..628ba355a 100644 --- a/cogl/cogl-pipeline-private.h +++ b/cogl/cogl-pipeline-private.h @@ -610,6 +610,21 @@ typedef struct CoglPipelineLayer *layer; } CoglPipelineLayerCacheEntry; +/* Sometimes when evaluating pipelines, either during comparisons or + * if calculating a hash value we need to tweak the evaluation + * semantics */ +typedef enum _CoglPipelineEvalFlags +{ + COGL_PIPELINE_EVAL_FLAG_NONE = 0 +} CoglPipelineEvalFlags; + +typedef struct _CoglPipelineHashState +{ + unsigned long layer_differences; + CoglPipelineEvalFlags flags; + unsigned int hash; +} CoglPipelineHashState; + /* * CoglPipelineDestroyCallback * @pipeline: The #CoglPipeline that has been destroyed @@ -842,6 +857,27 @@ _cogl_pipeline_get_authority (CoglPipeline *pipeline, return authority; } +typedef gboolean (*CoglPipelineStateComparitor) (CoglPipeline *authority0, + CoglPipeline *authority1); + +void +_cogl_pipeline_update_authority (CoglPipeline *pipeline, + CoglPipeline *authority, + CoglPipelineState state, + CoglPipelineStateComparitor comparitor); + +void +_cogl_pipeline_pre_change_notify (CoglPipeline *pipeline, + CoglPipelineState change, + const CoglColor *new_color, + gboolean from_layer_change); + +void +_cogl_pipeline_prune_redundant_ancestry (CoglPipeline *pipeline); + +void _cogl_pipeline_update_blend_enable (CoglPipeline *pipeline, + CoglPipelineState changes); + /* * SECTION:cogl-pipeline-internals * @short_description: Functions for creating custom primitives that make use @@ -1069,14 +1105,6 @@ unsigned long _cogl_pipeline_compare_differences (CoglPipeline *pipeline0, CoglPipeline *pipeline1); -/* Sometimes when evaluating pipelines, either during comparisons or - * if calculating a hash value we need to tweak the evaluation - * semantics */ -typedef enum _CoglPipelineEvalFlags -{ - COGL_PIPELINE_EVAL_FLAG_NONE = 0 -} CoglPipelineEvalFlags; - gboolean _cogl_pipeline_equal (CoglPipeline *pipeline0, CoglPipeline *pipeline1, diff --git a/cogl/cogl-pipeline-state-private.h b/cogl/cogl-pipeline-state-private.h new file mode 100644 index 000000000..b6c41588b --- /dev/null +++ b/cogl/cogl-pipeline-state-private.h @@ -0,0 +1,126 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * + * + * Authors: + * Robert Bragg <robert@linux.intel.com> + */ + +#ifndef __COGL_PIPELINE_STATE_PRIVATE_H +#define __COGL_PIPELINE_STATE_PRIVATE_H + +CoglPipeline * +_cogl_pipeline_get_user_program (CoglPipeline *pipeline); + +void +_cogl_pipeline_set_fog_state (CoglPipeline *pipeline, + const CoglPipelineFogState *fog_state); + +gboolean +_cogl_pipeline_color_equal (CoglPipeline *authority0, + CoglPipeline *authority1); + +gboolean +_cogl_pipeline_lighting_state_equal (CoglPipeline *authority0, + CoglPipeline *authority1); + +gboolean +_cogl_pipeline_alpha_func_state_equal (CoglPipeline *authority0, + CoglPipeline *authority1); + +gboolean +_cogl_pipeline_alpha_func_reference_state_equal (CoglPipeline *authority0, + CoglPipeline *authority1); + +gboolean +_cogl_pipeline_blend_state_equal (CoglPipeline *authority0, + CoglPipeline *authority1); + +gboolean +_cogl_pipeline_depth_state_equal (CoglPipeline *authority0, + CoglPipeline *authority1); + +gboolean +_cogl_pipeline_fog_state_equal (CoglPipeline *authority0, + CoglPipeline *authority1); + +gboolean +_cogl_pipeline_point_size_equal (CoglPipeline *authority0, + CoglPipeline *authority1); + +gboolean +_cogl_pipeline_logic_ops_state_equal (CoglPipeline *authority0, + CoglPipeline *authority1); + +gboolean +_cogl_pipeline_user_shader_equal (CoglPipeline *authority0, + CoglPipeline *authority1); + +void +_cogl_pipeline_hash_color_state (CoglPipeline *authority, + CoglPipelineHashState *state); + +void +_cogl_pipeline_hash_blend_enable_state (CoglPipeline *authority, + CoglPipelineHashState *state); + +void +_cogl_pipeline_hash_layers_state (CoglPipeline *authority, + CoglPipelineHashState *state); + +void +_cogl_pipeline_hash_lighting_state (CoglPipeline *authority, + CoglPipelineHashState *state); + +void +_cogl_pipeline_hash_alpha_func_state (CoglPipeline *authority, + CoglPipelineHashState *state); + +void +_cogl_pipeline_hash_alpha_func_reference_state (CoglPipeline *authority, + CoglPipelineHashState *state); + +void +_cogl_pipeline_hash_blend_state (CoglPipeline *authority, + CoglPipelineHashState *state); + +void +_cogl_pipeline_hash_user_shader_state (CoglPipeline *authority, + CoglPipelineHashState *state); + +void +_cogl_pipeline_hash_depth_state (CoglPipeline *authority, + CoglPipelineHashState *state); + +void +_cogl_pipeline_hash_fog_state (CoglPipeline *authority, + CoglPipelineHashState *state); + +void +_cogl_pipeline_hash_point_size_state (CoglPipeline *authority, + CoglPipelineHashState *state); + +void +_cogl_pipeline_hash_logic_ops_state (CoglPipeline *authority, + CoglPipelineHashState *state); + +#endif /* __COGL_PIPELINE_STATE_PRIVATE_H */ diff --git a/cogl/cogl-pipeline-state.c b/cogl/cogl-pipeline-state.c new file mode 100644 index 000000000..9a1888c14 --- /dev/null +++ b/cogl/cogl-pipeline-state.c @@ -0,0 +1,1367 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * + * + * Authors: + * Robert Bragg <robert@linux.intel.com> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "cogl-context-private.h" +#include "cogl-color-private.h" +#include "cogl-blend-string.h" +#include "cogl-util.h" +#include "cogl-depth-state-private.h" +#include "cogl-pipeline-private.h" + +#include "string.h" + +#ifndef GL_FUNC_ADD +#define GL_FUNC_ADD 0x8006 +#endif + +CoglPipeline * +_cogl_pipeline_get_user_program (CoglPipeline *pipeline) +{ + CoglPipeline *authority; + + g_return_val_if_fail (cogl_is_pipeline (pipeline), NULL); + + authority = + _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_USER_SHADER); + + return authority->big_state->user_program; +} + +gboolean +_cogl_pipeline_color_equal (CoglPipeline *authority0, + CoglPipeline *authority1) +{ + return cogl_color_equal (&authority0->color, &authority1->color); +} + +gboolean +_cogl_pipeline_lighting_state_equal (CoglPipeline *authority0, + CoglPipeline *authority1) +{ + CoglPipelineLightingState *state0 = &authority0->big_state->lighting_state; + CoglPipelineLightingState *state1 = &authority1->big_state->lighting_state; + + if (memcmp (state0->ambient, state1->ambient, sizeof (float) * 4) != 0) + return FALSE; + if (memcmp (state0->diffuse, state1->diffuse, sizeof (float) * 4) != 0) + return FALSE; + if (memcmp (state0->specular, state1->specular, sizeof (float) * 4) != 0) + return FALSE; + if (memcmp (state0->emission, state1->emission, sizeof (float) * 4) != 0) + return FALSE; + if (state0->shininess != state1->shininess) + return FALSE; + + return TRUE; +} + +gboolean +_cogl_pipeline_alpha_func_state_equal (CoglPipeline *authority0, + CoglPipeline *authority1) +{ + CoglPipelineAlphaFuncState *alpha_state0 = + &authority0->big_state->alpha_state; + CoglPipelineAlphaFuncState *alpha_state1 = + &authority1->big_state->alpha_state; + + return alpha_state0->alpha_func == alpha_state1->alpha_func; +} + +gboolean +_cogl_pipeline_alpha_func_reference_state_equal (CoglPipeline *authority0, + CoglPipeline *authority1) +{ + CoglPipelineAlphaFuncState *alpha_state0 = + &authority0->big_state->alpha_state; + CoglPipelineAlphaFuncState *alpha_state1 = + &authority1->big_state->alpha_state; + + return (alpha_state0->alpha_func_reference == + alpha_state1->alpha_func_reference); +} + +gboolean +_cogl_pipeline_blend_state_equal (CoglPipeline *authority0, + CoglPipeline *authority1) +{ + CoglPipelineBlendState *blend_state0 = &authority0->big_state->blend_state; + CoglPipelineBlendState *blend_state1 = &authority1->big_state->blend_state; + + _COGL_GET_CONTEXT (ctx, FALSE); + +#if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL) + if (ctx->driver != COGL_DRIVER_GLES1) + { + if (blend_state0->blend_equation_rgb != blend_state1->blend_equation_rgb) + return FALSE; + if (blend_state0->blend_equation_alpha != + blend_state1->blend_equation_alpha) + return FALSE; + if (blend_state0->blend_src_factor_alpha != + blend_state1->blend_src_factor_alpha) + return FALSE; + if (blend_state0->blend_dst_factor_alpha != + blend_state1->blend_dst_factor_alpha) + return FALSE; + } +#endif + if (blend_state0->blend_src_factor_rgb != + blend_state1->blend_src_factor_rgb) + return FALSE; + if (blend_state0->blend_dst_factor_rgb != + blend_state1->blend_dst_factor_rgb) + return FALSE; +#if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL) + if (ctx->driver != COGL_DRIVER_GLES1 && + (blend_state0->blend_src_factor_rgb == GL_ONE_MINUS_CONSTANT_COLOR || + blend_state0->blend_src_factor_rgb == GL_CONSTANT_COLOR || + blend_state0->blend_dst_factor_rgb == GL_ONE_MINUS_CONSTANT_COLOR || + blend_state0->blend_dst_factor_rgb == GL_CONSTANT_COLOR)) + { + if (!cogl_color_equal (&blend_state0->blend_constant, + &blend_state1->blend_constant)) + return FALSE; + } +#endif + + return TRUE; +} + +gboolean +_cogl_pipeline_depth_state_equal (CoglPipeline *authority0, + CoglPipeline *authority1) +{ + if (authority0->big_state->depth_state.test_enabled == FALSE && + authority1->big_state->depth_state.test_enabled == FALSE) + return TRUE; + else + { + CoglDepthState *s0 = &authority0->big_state->depth_state; + CoglDepthState *s1 = &authority1->big_state->depth_state; + return s0->test_enabled == s1->test_enabled && + s0->test_function == s1->test_function && + s0->write_enabled == s1->write_enabled && + s0->range_near == s1->range_near && + s0->range_far == s1->range_far; + } +} + +gboolean +_cogl_pipeline_fog_state_equal (CoglPipeline *authority0, + CoglPipeline *authority1) +{ + CoglPipelineFogState *fog_state0 = &authority0->big_state->fog_state; + CoglPipelineFogState *fog_state1 = &authority1->big_state->fog_state; + + if (fog_state0->enabled == fog_state1->enabled && + cogl_color_equal (&fog_state0->color, &fog_state1->color) && + fog_state0->mode == fog_state1->mode && + fog_state0->density == fog_state1->density && + fog_state0->z_near == fog_state1->z_near && + fog_state0->z_far == fog_state1->z_far) + return TRUE; + else + return FALSE; +} + +gboolean +_cogl_pipeline_point_size_equal (CoglPipeline *authority0, + CoglPipeline *authority1) +{ + return authority0->big_state->point_size == authority1->big_state->point_size; +} + +gboolean +_cogl_pipeline_logic_ops_state_equal (CoglPipeline *authority0, + CoglPipeline *authority1) +{ + CoglPipelineLogicOpsState *logic_ops_state0 = &authority0->big_state->logic_ops_state; + CoglPipelineLogicOpsState *logic_ops_state1 = &authority1->big_state->logic_ops_state; + + return logic_ops_state0->color_mask == logic_ops_state1->color_mask; +} + +gboolean +_cogl_pipeline_user_shader_equal (CoglPipeline *authority0, + CoglPipeline *authority1) +{ + return (authority0->big_state->user_program == + authority1->big_state->user_program); +} + +void +cogl_pipeline_get_color (CoglPipeline *pipeline, + CoglColor *color) +{ + CoglPipeline *authority; + + g_return_if_fail (cogl_is_pipeline (pipeline)); + + authority = + _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_COLOR); + + *color = authority->color; +} + +/* This is used heavily by the cogl journal when logging quads */ +void +_cogl_pipeline_get_colorubv (CoglPipeline *pipeline, + guint8 *color) +{ + CoglPipeline *authority = + _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_COLOR); + + _cogl_color_get_rgba_4ubv (&authority->color, color); +} + +void +cogl_pipeline_set_color (CoglPipeline *pipeline, + const CoglColor *color) +{ + CoglPipelineState state = COGL_PIPELINE_STATE_COLOR; + CoglPipeline *authority; + + g_return_if_fail (cogl_is_pipeline (pipeline)); + + authority = _cogl_pipeline_get_authority (pipeline, state); + + if (cogl_color_equal (color, &authority->color)) + return; + + /* - Flush journal primitives referencing the current state. + * - Make sure the pipeline has no dependants so it may be modified. + * - If the pipeline isn't currently an authority for the state being + * changed, then initialize that state from the current authority. + */ + _cogl_pipeline_pre_change_notify (pipeline, state, color, FALSE); + + pipeline->color = *color; + + _cogl_pipeline_update_authority (pipeline, authority, state, + _cogl_pipeline_color_equal); + + _cogl_pipeline_update_blend_enable (pipeline, state); +} + +void +cogl_pipeline_set_color4ub (CoglPipeline *pipeline, + guint8 red, + guint8 green, + guint8 blue, + guint8 alpha) +{ + CoglColor color; + cogl_color_init_from_4ub (&color, red, green, blue, alpha); + cogl_pipeline_set_color (pipeline, &color); +} + +void +cogl_pipeline_set_color4f (CoglPipeline *pipeline, + float red, + float green, + float blue, + float alpha) +{ + CoglColor color; + cogl_color_init_from_4f (&color, red, green, blue, alpha); + cogl_pipeline_set_color (pipeline, &color); +} + +CoglPipelineBlendEnable +_cogl_pipeline_get_blend_enabled (CoglPipeline *pipeline) +{ + CoglPipeline *authority; + + g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE); + + authority = + _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_BLEND_ENABLE); + return authority->blend_enable; +} + +gboolean +_cogl_pipeline_blend_enable_equal (CoglPipeline *authority0, + CoglPipeline *authority1) +{ + return authority0->blend_enable == authority1->blend_enable ? TRUE : FALSE; +} + +void +_cogl_pipeline_set_blend_enabled (CoglPipeline *pipeline, + CoglPipelineBlendEnable enable) +{ + CoglPipelineState state = COGL_PIPELINE_STATE_BLEND_ENABLE; + CoglPipeline *authority; + + g_return_if_fail (cogl_is_pipeline (pipeline)); + g_return_if_fail (enable > 1 && + "don't pass TRUE or FALSE to _set_blend_enabled!"); + + authority = _cogl_pipeline_get_authority (pipeline, state); + + if (authority->blend_enable == enable) + return; + + /* - Flush journal primitives referencing the current state. + * - Make sure the pipeline has no dependants so it may be modified. + * - If the pipeline isn't currently an authority for the state being + * changed, then initialize that state from the current authority. + */ + _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); + + pipeline->blend_enable = enable; + + _cogl_pipeline_update_authority (pipeline, authority, state, + _cogl_pipeline_blend_enable_equal); + + _cogl_pipeline_update_blend_enable (pipeline, state); +} + +void +cogl_pipeline_get_ambient (CoglPipeline *pipeline, + CoglColor *ambient) +{ + CoglPipeline *authority; + + g_return_if_fail (cogl_is_pipeline (pipeline)); + + authority = + _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING); + + cogl_color_init_from_4fv (ambient, + authority->big_state->lighting_state.ambient); +} + +void +cogl_pipeline_set_ambient (CoglPipeline *pipeline, + const CoglColor *ambient) +{ + CoglPipelineState state = COGL_PIPELINE_STATE_LIGHTING; + CoglPipeline *authority; + CoglPipelineLightingState *lighting_state; + + g_return_if_fail (cogl_is_pipeline (pipeline)); + + authority = _cogl_pipeline_get_authority (pipeline, state); + + lighting_state = &authority->big_state->lighting_state; + if (cogl_color_equal (ambient, &lighting_state->ambient)) + return; + + /* - Flush journal primitives referencing the current state. + * - Make sure the pipeline has no dependants so it may be modified. + * - If the pipeline isn't currently an authority for the state being + * changed, then initialize that state from the current authority. + */ + _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); + + lighting_state = &pipeline->big_state->lighting_state; + lighting_state->ambient[0] = cogl_color_get_red_float (ambient); + lighting_state->ambient[1] = cogl_color_get_green_float (ambient); + lighting_state->ambient[2] = cogl_color_get_blue_float (ambient); + lighting_state->ambient[3] = cogl_color_get_alpha_float (ambient); + + _cogl_pipeline_update_authority (pipeline, authority, state, + _cogl_pipeline_lighting_state_equal); + + _cogl_pipeline_update_blend_enable (pipeline, state); +} + +void +cogl_pipeline_get_diffuse (CoglPipeline *pipeline, + CoglColor *diffuse) +{ + CoglPipeline *authority; + + g_return_if_fail (cogl_is_pipeline (pipeline)); + + authority = + _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING); + + cogl_color_init_from_4fv (diffuse, + authority->big_state->lighting_state.diffuse); +} + +void +cogl_pipeline_set_diffuse (CoglPipeline *pipeline, + const CoglColor *diffuse) +{ + CoglPipelineState state = COGL_PIPELINE_STATE_LIGHTING; + CoglPipeline *authority; + CoglPipelineLightingState *lighting_state; + + g_return_if_fail (cogl_is_pipeline (pipeline)); + + authority = _cogl_pipeline_get_authority (pipeline, state); + + lighting_state = &authority->big_state->lighting_state; + if (cogl_color_equal (diffuse, &lighting_state->diffuse)) + return; + + /* - Flush journal primitives referencing the current state. + * - Make sure the pipeline has no dependants so it may be modified. + * - If the pipeline isn't currently an authority for the state being + * changed, then initialize that state from the current authority. + */ + _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); + + lighting_state = &pipeline->big_state->lighting_state; + lighting_state->diffuse[0] = cogl_color_get_red_float (diffuse); + lighting_state->diffuse[1] = cogl_color_get_green_float (diffuse); + lighting_state->diffuse[2] = cogl_color_get_blue_float (diffuse); + lighting_state->diffuse[3] = cogl_color_get_alpha_float (diffuse); + + + _cogl_pipeline_update_authority (pipeline, authority, state, + _cogl_pipeline_lighting_state_equal); + + _cogl_pipeline_update_blend_enable (pipeline, state); +} + +void +cogl_pipeline_set_ambient_and_diffuse (CoglPipeline *pipeline, + const CoglColor *color) +{ + cogl_pipeline_set_ambient (pipeline, color); + cogl_pipeline_set_diffuse (pipeline, color); +} + +void +cogl_pipeline_get_specular (CoglPipeline *pipeline, + CoglColor *specular) +{ + CoglPipeline *authority; + + g_return_if_fail (cogl_is_pipeline (pipeline)); + + authority = + _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING); + + cogl_color_init_from_4fv (specular, + authority->big_state->lighting_state.specular); +} + +void +cogl_pipeline_set_specular (CoglPipeline *pipeline, const CoglColor *specular) +{ + CoglPipeline *authority; + CoglPipelineState state = COGL_PIPELINE_STATE_LIGHTING; + CoglPipelineLightingState *lighting_state; + + g_return_if_fail (cogl_is_pipeline (pipeline)); + + authority = _cogl_pipeline_get_authority (pipeline, state); + + lighting_state = &authority->big_state->lighting_state; + if (cogl_color_equal (specular, &lighting_state->specular)) + return; + + /* - Flush journal primitives referencing the current state. + * - Make sure the pipeline has no dependants so it may be modified. + * - If the pipeline isn't currently an authority for the state being + * changed, then initialize that state from the current authority. + */ + _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); + + lighting_state = &pipeline->big_state->lighting_state; + lighting_state->specular[0] = cogl_color_get_red_float (specular); + lighting_state->specular[1] = cogl_color_get_green_float (specular); + lighting_state->specular[2] = cogl_color_get_blue_float (specular); + lighting_state->specular[3] = cogl_color_get_alpha_float (specular); + + _cogl_pipeline_update_authority (pipeline, authority, state, + _cogl_pipeline_lighting_state_equal); + + _cogl_pipeline_update_blend_enable (pipeline, state); +} + +float +cogl_pipeline_get_shininess (CoglPipeline *pipeline) +{ + CoglPipeline *authority; + + g_return_val_if_fail (cogl_is_pipeline (pipeline), 0); + + authority = + _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING); + + return authority->big_state->lighting_state.shininess; +} + +void +cogl_pipeline_set_shininess (CoglPipeline *pipeline, + float shininess) +{ + CoglPipeline *authority; + CoglPipelineState state = COGL_PIPELINE_STATE_LIGHTING; + CoglPipelineLightingState *lighting_state; + + g_return_if_fail (cogl_is_pipeline (pipeline)); + + if (shininess < 0.0) + { + g_warning ("Out of range shininess %f supplied for pipeline\n", + shininess); + return; + } + + authority = _cogl_pipeline_get_authority (pipeline, state); + + lighting_state = &authority->big_state->lighting_state; + + if (lighting_state->shininess == shininess) + return; + + /* - Flush journal primitives referencing the current state. + * - Make sure the pipeline has no dependants so it may be modified. + * - If the pipeline isn't currently an authority for the state being + * changed, then initialize that state from the current authority. + */ + _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); + + lighting_state = &pipeline->big_state->lighting_state; + lighting_state->shininess = shininess; + + _cogl_pipeline_update_authority (pipeline, authority, state, + _cogl_pipeline_lighting_state_equal); +} + +void +cogl_pipeline_get_emission (CoglPipeline *pipeline, + CoglColor *emission) +{ + CoglPipeline *authority; + + g_return_if_fail (cogl_is_pipeline (pipeline)); + + authority = + _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING); + + cogl_color_init_from_4fv (emission, + authority->big_state->lighting_state.emission); +} + +void +cogl_pipeline_set_emission (CoglPipeline *pipeline, const CoglColor *emission) +{ + CoglPipeline *authority; + CoglPipelineState state = COGL_PIPELINE_STATE_LIGHTING; + CoglPipelineLightingState *lighting_state; + + g_return_if_fail (cogl_is_pipeline (pipeline)); + + authority = _cogl_pipeline_get_authority (pipeline, state); + + lighting_state = &authority->big_state->lighting_state; + if (cogl_color_equal (emission, &lighting_state->emission)) + return; + + /* - Flush journal primitives referencing the current state. + * - Make sure the pipeline has no dependants so it may be modified. + * - If the pipeline isn't currently an authority for the state being + * changed, then initialize that state from the current authority. + */ + _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); + + lighting_state = &pipeline->big_state->lighting_state; + lighting_state->emission[0] = cogl_color_get_red_float (emission); + lighting_state->emission[1] = cogl_color_get_green_float (emission); + lighting_state->emission[2] = cogl_color_get_blue_float (emission); + lighting_state->emission[3] = cogl_color_get_alpha_float (emission); + + _cogl_pipeline_update_authority (pipeline, authority, state, + _cogl_pipeline_lighting_state_equal); + + _cogl_pipeline_update_blend_enable (pipeline, state); +} + +static void +_cogl_pipeline_set_alpha_test_function (CoglPipeline *pipeline, + CoglPipelineAlphaFunc alpha_func) +{ + CoglPipelineState state = COGL_PIPELINE_STATE_ALPHA_FUNC; + CoglPipeline *authority; + CoglPipelineAlphaFuncState *alpha_state; + + g_return_if_fail (cogl_is_pipeline (pipeline)); + + authority = _cogl_pipeline_get_authority (pipeline, state); + + alpha_state = &authority->big_state->alpha_state; + if (alpha_state->alpha_func == alpha_func) + return; + + /* - Flush journal primitives referencing the current state. + * - Make sure the pipeline has no dependants so it may be modified. + * - If the pipeline isn't currently an authority for the state being + * changed, then initialize that state from the current authority. + */ + _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); + + alpha_state = &pipeline->big_state->alpha_state; + alpha_state->alpha_func = alpha_func; + + _cogl_pipeline_update_authority (pipeline, authority, state, + _cogl_pipeline_alpha_func_state_equal); +} + +static void +_cogl_pipeline_set_alpha_test_function_reference (CoglPipeline *pipeline, + float alpha_reference) +{ + CoglPipelineState state = COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE; + CoglPipeline *authority; + CoglPipelineAlphaFuncState *alpha_state; + + g_return_if_fail (cogl_is_pipeline (pipeline)); + + authority = _cogl_pipeline_get_authority (pipeline, state); + + alpha_state = &authority->big_state->alpha_state; + if (alpha_state->alpha_func_reference == alpha_reference) + return; + + /* - Flush journal primitives referencing the current state. + * - Make sure the pipeline has no dependants so it may be modified. + * - If the pipeline isn't currently an authority for the state being + * changed, then initialize that state from the current authority. + */ + _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); + + alpha_state = &pipeline->big_state->alpha_state; + alpha_state->alpha_func_reference = alpha_reference; + + _cogl_pipeline_update_authority + (pipeline, authority, state, + _cogl_pipeline_alpha_func_reference_state_equal); +} + +void +cogl_pipeline_set_alpha_test_function (CoglPipeline *pipeline, + CoglPipelineAlphaFunc alpha_func, + float alpha_reference) +{ + _cogl_pipeline_set_alpha_test_function (pipeline, alpha_func); + _cogl_pipeline_set_alpha_test_function_reference (pipeline, alpha_reference); +} + +CoglPipelineAlphaFunc +cogl_pipeline_get_alpha_test_function (CoglPipeline *pipeline) +{ + CoglPipeline *authority; + + g_return_val_if_fail (cogl_is_pipeline (pipeline), 0); + + authority = + _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_ALPHA_FUNC); + + return authority->big_state->alpha_state.alpha_func; +} + +float +cogl_pipeline_get_alpha_test_reference (CoglPipeline *pipeline) +{ + CoglPipeline *authority; + + g_return_val_if_fail (cogl_is_pipeline (pipeline), 0.0f); + + authority = + _cogl_pipeline_get_authority (pipeline, + COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE); + + return authority->big_state->alpha_state.alpha_func_reference; +} + +GLenum +arg_to_gl_blend_factor (CoglBlendStringArgument *arg) +{ + if (arg->source.is_zero) + return GL_ZERO; + if (arg->factor.is_one) + return GL_ONE; + else if (arg->factor.is_src_alpha_saturate) + return GL_SRC_ALPHA_SATURATE; + else if (arg->factor.source.info->type == + COGL_BLEND_STRING_COLOR_SOURCE_SRC_COLOR) + { + if (arg->factor.source.mask != COGL_BLEND_STRING_CHANNEL_MASK_ALPHA) + { + if (arg->factor.source.one_minus) + return GL_ONE_MINUS_SRC_COLOR; + else + return GL_SRC_COLOR; + } + else + { + if (arg->factor.source.one_minus) + return GL_ONE_MINUS_SRC_ALPHA; + else + return GL_SRC_ALPHA; + } + } + else if (arg->factor.source.info->type == + COGL_BLEND_STRING_COLOR_SOURCE_DST_COLOR) + { + if (arg->factor.source.mask != COGL_BLEND_STRING_CHANNEL_MASK_ALPHA) + { + if (arg->factor.source.one_minus) + return GL_ONE_MINUS_DST_COLOR; + else + return GL_DST_COLOR; + } + else + { + if (arg->factor.source.one_minus) + return GL_ONE_MINUS_DST_ALPHA; + else + return GL_DST_ALPHA; + } + } +#if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL) + else if (arg->factor.source.info->type == + COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT) + { + if (arg->factor.source.mask != COGL_BLEND_STRING_CHANNEL_MASK_ALPHA) + { + if (arg->factor.source.one_minus) + return GL_ONE_MINUS_CONSTANT_COLOR; + else + return GL_CONSTANT_COLOR; + } + else + { + if (arg->factor.source.one_minus) + return GL_ONE_MINUS_CONSTANT_ALPHA; + else + return GL_CONSTANT_ALPHA; + } + } +#endif + + g_warning ("Unable to determine valid blend factor from blend string\n"); + return GL_ONE; +} + +void +setup_blend_state (CoglBlendStringStatement *statement, + GLenum *blend_equation, + GLint *blend_src_factor, + GLint *blend_dst_factor) +{ + switch (statement->function->type) + { + case COGL_BLEND_STRING_FUNCTION_ADD: + *blend_equation = GL_FUNC_ADD; + break; + /* TODO - add more */ + default: + g_warning ("Unsupported blend function given"); + *blend_equation = GL_FUNC_ADD; + } + + *blend_src_factor = arg_to_gl_blend_factor (&statement->args[0]); + *blend_dst_factor = arg_to_gl_blend_factor (&statement->args[1]); +} + +gboolean +cogl_pipeline_set_blend (CoglPipeline *pipeline, + const char *blend_description, + GError **error) +{ + CoglPipelineState state = COGL_PIPELINE_STATE_BLEND; + CoglPipeline *authority; + CoglBlendStringStatement statements[2]; + CoglBlendStringStatement *rgb; + CoglBlendStringStatement *a; + GError *internal_error = NULL; + int count; + CoglPipelineBlendState *blend_state; + + _COGL_GET_CONTEXT (ctx, FALSE); + + g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE); + + count = + _cogl_blend_string_compile (blend_description, + COGL_BLEND_STRING_CONTEXT_BLENDING, + statements, + &internal_error); + if (!count) + { + if (error) + g_propagate_error (error, internal_error); + else + { + g_warning ("Cannot compile blend description: %s\n", + internal_error->message); + g_error_free (internal_error); + } + return FALSE; + } + + if (count == 1) + rgb = a = statements; + else + { + rgb = &statements[0]; + a = &statements[1]; + } + + authority = + _cogl_pipeline_get_authority (pipeline, state); + + /* - Flush journal primitives referencing the current state. + * - Make sure the pipeline has no dependants so it may be modified. + * - If the pipeline isn't currently an authority for the state being + * changed, then initialize that state from the current authority. + */ + _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); + + blend_state = &pipeline->big_state->blend_state; +#if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES2) + if (ctx->driver != COGL_DRIVER_GLES1) + { + setup_blend_state (rgb, + &blend_state->blend_equation_rgb, + &blend_state->blend_src_factor_rgb, + &blend_state->blend_dst_factor_rgb); + setup_blend_state (a, + &blend_state->blend_equation_alpha, + &blend_state->blend_src_factor_alpha, + &blend_state->blend_dst_factor_alpha); + } + else +#endif + { + setup_blend_state (rgb, + NULL, + &blend_state->blend_src_factor_rgb, + &blend_state->blend_dst_factor_rgb); + } + + /* If we are the current authority see if we can revert to one of our + * ancestors being the authority */ + if (pipeline == authority && + _cogl_pipeline_get_parent (authority) != NULL) + { + CoglPipeline *parent = _cogl_pipeline_get_parent (authority); + CoglPipeline *old_authority = + _cogl_pipeline_get_authority (parent, state); + + if (_cogl_pipeline_blend_state_equal (authority, old_authority)) + pipeline->differences &= ~state; + } + + /* 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 (pipeline != authority) + { + pipeline->differences |= state; + _cogl_pipeline_prune_redundant_ancestry (pipeline); + } + + _cogl_pipeline_update_blend_enable (pipeline, state); + + return TRUE; +} + +void +cogl_pipeline_set_blend_constant (CoglPipeline *pipeline, + const CoglColor *constant_color) +{ + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + g_return_if_fail (cogl_is_pipeline (pipeline)); + + if (ctx->driver == COGL_DRIVER_GLES1) + return; + +#if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL) + { + CoglPipelineState state = COGL_PIPELINE_STATE_BLEND; + CoglPipeline *authority; + CoglPipelineBlendState *blend_state; + + authority = _cogl_pipeline_get_authority (pipeline, state); + + blend_state = &authority->big_state->blend_state; + if (cogl_color_equal (constant_color, &blend_state->blend_constant)) + return; + + /* - Flush journal primitives referencing the current state. + * - Make sure the pipeline has no dependants so it may be modified. + * - If the pipeline isn't currently an authority for the state being + * changed, then initialize that state from the current authority. + */ + _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); + + blend_state = &pipeline->big_state->blend_state; + blend_state->blend_constant = *constant_color; + + _cogl_pipeline_update_authority (pipeline, authority, state, + _cogl_pipeline_blend_state_equal); + + _cogl_pipeline_update_blend_enable (pipeline, state); + } +#endif +} + +CoglHandle +cogl_pipeline_get_user_program (CoglPipeline *pipeline) +{ + CoglPipeline *authority; + + g_return_val_if_fail (cogl_is_pipeline (pipeline), COGL_INVALID_HANDLE); + + authority = + _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_USER_SHADER); + + return authority->big_state->user_program; +} + +/* XXX: for now we don't mind if the program has vertex shaders + * attached but if we ever make a similar API public we should only + * allow attaching of programs containing fragment shaders. Eventually + * we will have a CoglPipeline abstraction to also cover vertex + * processing. + */ +void +cogl_pipeline_set_user_program (CoglPipeline *pipeline, + CoglHandle program) +{ + CoglPipelineState state = COGL_PIPELINE_STATE_USER_SHADER; + CoglPipeline *authority; + + g_return_if_fail (cogl_is_pipeline (pipeline)); + + authority = _cogl_pipeline_get_authority (pipeline, state); + + if (authority->big_state->user_program == program) + return; + + /* - Flush journal primitives referencing the current state. + * - Make sure the pipeline has no dependants so it may be modified. + * - If the pipeline isn't currently an authority for the state being + * changed, then initialize that state from the current authority. + */ + _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); + + if (program != COGL_INVALID_HANDLE) + { + _cogl_pipeline_set_fragend (pipeline, COGL_PIPELINE_FRAGEND_DEFAULT); + _cogl_pipeline_set_vertend (pipeline, COGL_PIPELINE_VERTEND_DEFAULT); + } + + /* If we are the current authority see if we can revert to one of our + * ancestors being the authority */ + if (pipeline == authority && + _cogl_pipeline_get_parent (authority) != NULL) + { + CoglPipeline *parent = _cogl_pipeline_get_parent (authority); + CoglPipeline *old_authority = + _cogl_pipeline_get_authority (parent, state); + + if (old_authority->big_state->user_program == program) + pipeline->differences &= ~state; + } + else if (pipeline != authority) + { + /* 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... */ + pipeline->differences |= state; + _cogl_pipeline_prune_redundant_ancestry (pipeline); + } + + if (program != COGL_INVALID_HANDLE) + cogl_handle_ref (program); + if (authority == pipeline && + pipeline->big_state->user_program != COGL_INVALID_HANDLE) + cogl_handle_unref (pipeline->big_state->user_program); + pipeline->big_state->user_program = program; + + _cogl_pipeline_update_blend_enable (pipeline, state); +} + +gboolean +cogl_pipeline_set_depth_state (CoglPipeline *pipeline, + const CoglDepthState *depth_state, + GError **error) +{ + CoglPipelineState state = COGL_PIPELINE_STATE_DEPTH; + CoglPipeline *authority; + CoglDepthState *orig_state; + + _COGL_GET_CONTEXT (ctx, FALSE); + + g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE); + g_return_val_if_fail (depth_state->magic == COGL_DEPTH_STATE_MAGIC, FALSE); + + authority = _cogl_pipeline_get_authority (pipeline, state); + + orig_state = &authority->big_state->depth_state; + if (orig_state->test_enabled == depth_state->test_enabled && + orig_state->write_enabled == depth_state->write_enabled && + orig_state->test_function == depth_state->test_function && + orig_state->range_near == depth_state->range_near && + orig_state->range_far == depth_state->range_far) + return TRUE; + + if (ctx->driver == COGL_DRIVER_GLES1 && + (depth_state->range_near != 0 || + depth_state->range_far != 1)) + { + g_set_error (error, + COGL_ERROR, + COGL_ERROR_UNSUPPORTED, + "glDepthRange not available on GLES 1"); + return FALSE; + } + + /* - Flush journal primitives referencing the current state. + * - Make sure the pipeline has no dependants so it may be modified. + * - If the pipeline isn't currently an authority for the state being + * changed, then initialize that state from the current authority. + */ + _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); + + pipeline->big_state->depth_state = *depth_state; + + _cogl_pipeline_update_authority (pipeline, authority, state, + _cogl_pipeline_depth_state_equal); + + return TRUE; +} + +void +cogl_pipeline_get_depth_state (CoglPipeline *pipeline, + CoglDepthState *state) +{ + CoglPipeline *authority; + + g_return_if_fail (cogl_is_pipeline (pipeline)); + + authority = + _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_DEPTH); + *state = authority->big_state->depth_state; +} + +CoglColorMask +cogl_pipeline_get_color_mask (CoglPipeline *pipeline) +{ + CoglPipeline *authority; + + g_return_val_if_fail (cogl_is_pipeline (pipeline), 0); + + authority = + _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LOGIC_OPS); + + return authority->big_state->logic_ops_state.color_mask; +} + +void +cogl_pipeline_set_color_mask (CoglPipeline *pipeline, + CoglColorMask color_mask) +{ + CoglPipelineState state = COGL_PIPELINE_STATE_LOGIC_OPS; + CoglPipeline *authority; + CoglPipelineLogicOpsState *logic_ops_state; + + g_return_if_fail (cogl_is_pipeline (pipeline)); + + authority = _cogl_pipeline_get_authority (pipeline, state); + + logic_ops_state = &authority->big_state->logic_ops_state; + if (logic_ops_state->color_mask == color_mask) + return; + + /* - Flush journal primitives referencing the current state. + * - Make sure the pipeline has no dependants so it may be modified. + * - If the pipeline isn't currently an authority for the state being + * changed, then initialize that state from the current authority. + */ + _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); + + logic_ops_state = &pipeline->big_state->logic_ops_state; + logic_ops_state->color_mask = color_mask; + + _cogl_pipeline_update_authority (pipeline, authority, state, + _cogl_pipeline_logic_ops_state_equal); +} + +void +_cogl_pipeline_set_fog_state (CoglPipeline *pipeline, + const CoglPipelineFogState *fog_state) +{ + CoglPipelineState state = COGL_PIPELINE_STATE_FOG; + CoglPipeline *authority; + CoglPipelineFogState *current_fog_state; + + g_return_if_fail (cogl_is_pipeline (pipeline)); + + authority = _cogl_pipeline_get_authority (pipeline, state); + + current_fog_state = &authority->big_state->fog_state; + + if (current_fog_state->enabled == fog_state->enabled && + cogl_color_equal (¤t_fog_state->color, &fog_state->color) && + current_fog_state->mode == fog_state->mode && + current_fog_state->density == fog_state->density && + current_fog_state->z_near == fog_state->z_near && + current_fog_state->z_far == fog_state->z_far) + return; + + /* - Flush journal primitives referencing the current state. + * - Make sure the pipeline has no dependants so it may be modified. + * - If the pipeline isn't currently an authority for the state being + * changed, then initialize that state from the current authority. + */ + _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); + + pipeline->big_state->fog_state = *fog_state; + + _cogl_pipeline_update_authority (pipeline, authority, state, + _cogl_pipeline_fog_state_equal); +} + +float +cogl_pipeline_get_point_size (CoglPipeline *pipeline) +{ + CoglPipeline *authority; + + g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE); + + authority = + _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_POINT_SIZE); + + return authority->big_state->point_size; +} + +void +cogl_pipeline_set_point_size (CoglPipeline *pipeline, + float point_size) +{ + CoglPipelineState state = COGL_PIPELINE_STATE_POINT_SIZE; + CoglPipeline *authority; + + g_return_if_fail (cogl_is_pipeline (pipeline)); + + authority = _cogl_pipeline_get_authority (pipeline, state); + + if (authority->big_state->point_size == point_size) + return; + + /* - Flush journal primitives referencing the current state. + * - Make sure the pipeline has no dependants so it may be modified. + * - If the pipeline isn't currently an authority for the state being + * changed, then initialize that state from the current authority. + */ + _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); + + pipeline->big_state->point_size = point_size; + + _cogl_pipeline_update_authority (pipeline, authority, state, + _cogl_pipeline_point_size_equal); +} + +void +_cogl_pipeline_hash_color_state (CoglPipeline *authority, + CoglPipelineHashState *state) +{ + state->hash = _cogl_util_one_at_a_time_hash (state->hash, &authority->color, + _COGL_COLOR_DATA_SIZE); +} + +void +_cogl_pipeline_hash_blend_enable_state (CoglPipeline *authority, + CoglPipelineHashState *state) +{ + guint8 blend_enable = authority->blend_enable; + state->hash = _cogl_util_one_at_a_time_hash (state->hash, &blend_enable, 1); +} + +void +_cogl_pipeline_hash_lighting_state (CoglPipeline *authority, + CoglPipelineHashState *state) +{ + CoglPipelineLightingState *lighting_state = + &authority->big_state->lighting_state; + state->hash = + _cogl_util_one_at_a_time_hash (state->hash, lighting_state, + sizeof (CoglPipelineLightingState)); +} + +void +_cogl_pipeline_hash_alpha_func_state (CoglPipeline *authority, + CoglPipelineHashState *state) +{ + CoglPipelineAlphaFuncState *alpha_state = &authority->big_state->alpha_state; + state->hash = + _cogl_util_one_at_a_time_hash (state->hash, &alpha_state->alpha_func, + sizeof (alpha_state->alpha_func)); +} + +void +_cogl_pipeline_hash_alpha_func_reference_state (CoglPipeline *authority, + CoglPipelineHashState *state) +{ + CoglPipelineAlphaFuncState *alpha_state = &authority->big_state->alpha_state; + float ref = alpha_state->alpha_func_reference; + state->hash = + _cogl_util_one_at_a_time_hash (state->hash, &ref, sizeof (float)); +} + +void +_cogl_pipeline_hash_blend_state (CoglPipeline *authority, + CoglPipelineHashState *state) +{ + CoglPipelineBlendState *blend_state = &authority->big_state->blend_state; + unsigned int hash; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + if (!authority->real_blend_enable) + return; + + hash = state->hash; + +#if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL) + if (ctx->driver != COGL_DRIVER_GLES1) + { + hash = + _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_equation_rgb, + sizeof (blend_state->blend_equation_rgb)); + hash = + _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_equation_alpha, + sizeof (blend_state->blend_equation_alpha)); + hash = + _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_src_factor_alpha, + sizeof (blend_state->blend_src_factor_alpha)); + hash = + _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_dst_factor_alpha, + sizeof (blend_state->blend_dst_factor_alpha)); + + if (blend_state->blend_src_factor_rgb == GL_ONE_MINUS_CONSTANT_COLOR || + blend_state->blend_src_factor_rgb == GL_CONSTANT_COLOR || + blend_state->blend_dst_factor_rgb == GL_ONE_MINUS_CONSTANT_COLOR || + blend_state->blend_dst_factor_rgb == GL_CONSTANT_COLOR) + { + hash = + _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_constant, + sizeof (blend_state->blend_constant)); + } + } +#endif + + hash = + _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_src_factor_rgb, + sizeof (blend_state->blend_src_factor_rgb)); + hash = + _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_dst_factor_rgb, + sizeof (blend_state->blend_dst_factor_rgb)); + + state->hash = hash; +} + +void +_cogl_pipeline_hash_user_shader_state (CoglPipeline *authority, + CoglPipelineHashState *state) +{ + CoglHandle user_program = authority->big_state->user_program; + state->hash = _cogl_util_one_at_a_time_hash (state->hash, &user_program, + sizeof (user_program)); +} + +void +_cogl_pipeline_hash_depth_state (CoglPipeline *authority, + CoglPipelineHashState *state) +{ + CoglDepthState *depth_state = &authority->big_state->depth_state; + unsigned int hash = state->hash; + + if (depth_state->test_enabled) + { + guint8 enabled = depth_state->test_enabled; + CoglDepthTestFunction function = depth_state->test_function; + hash = _cogl_util_one_at_a_time_hash (hash, &enabled, sizeof (enabled)); + hash = _cogl_util_one_at_a_time_hash (hash, &function, sizeof (function)); + } + + if (depth_state->write_enabled) + { + guint8 enabled = depth_state->write_enabled; + float near_val = depth_state->range_near; + float far_val = depth_state->range_far; + hash = _cogl_util_one_at_a_time_hash (hash, &enabled, sizeof (enabled)); + hash = _cogl_util_one_at_a_time_hash (hash, &near_val, sizeof (near_val)); + hash = _cogl_util_one_at_a_time_hash (hash, &far_val, sizeof (far_val)); + } + + state->hash = hash; +} + +void +_cogl_pipeline_hash_fog_state (CoglPipeline *authority, + CoglPipelineHashState *state) +{ + CoglPipelineFogState *fog_state = &authority->big_state->fog_state; + unsigned long hash = state->hash; + + if (!fog_state->enabled) + hash = _cogl_util_one_at_a_time_hash (hash, &fog_state->enabled, + sizeof (fog_state->enabled)); + else + hash = _cogl_util_one_at_a_time_hash (hash, &fog_state, + sizeof (CoglPipelineFogState)); + + state->hash = hash; +} + +void +_cogl_pipeline_hash_point_size_state (CoglPipeline *authority, + CoglPipelineHashState *state) +{ + float point_size = authority->big_state->point_size; + state->hash = _cogl_util_one_at_a_time_hash (state->hash, &point_size, + sizeof (point_size)); +} + +void +_cogl_pipeline_hash_logic_ops_state (CoglPipeline *authority, + CoglPipelineHashState *state) +{ + CoglPipelineLogicOpsState *logic_ops_state = &authority->big_state->logic_ops_state; + state->hash = _cogl_util_one_at_a_time_hash (state->hash, &logic_ops_state->color_mask, + sizeof (CoglColorMask)); +} diff --git a/cogl/cogl-pipeline-state.h b/cogl/cogl-pipeline-state.h new file mode 100644 index 000000000..7015b00c0 --- /dev/null +++ b/cogl/cogl-pipeline-state.h @@ -0,0 +1,693 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2007,2008,2009,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 <http://www.gnu.org/licenses/>. + * + * + */ + +#if !defined(__COGL_H_INSIDE__) && !defined(CLUTTER_COMPILATION) +#error "Only <cogl/cogl.h> can be included directly." +#endif + +#ifndef __COGL_PIPELINE_STATE_H__ +#define __COGL_PIPELINE_STATE_H__ + +#include <cogl/cogl-pipeline.h> +#include <cogl/cogl-color.h> +#include <glib.h> + +G_BEGIN_DECLS + +#ifdef COGL_ENABLE_EXPERIMENTAL_API + +#define cogl_pipeline_set_color cogl_pipeline_set_color_EXP +/** + * cogl_pipeline_set_color: + * @pipeline: A #CoglPipeline object + * @color: The components of the color + * + * Sets the basic color of the pipeline, used when no lighting is enabled. + * + * Note that if you don't add any layers to the pipeline then the color + * will be blended unmodified with the destination; the default blend + * expects premultiplied colors: for example, use (0.5, 0.0, 0.0, 0.5) for + * semi-transparent red. See cogl_color_premultiply(). + * + * The default value is (1.0, 1.0, 1.0, 1.0) + * + * Since: 2.0 + * Stability: Unstable + */ +void +cogl_pipeline_set_color (CoglPipeline *pipeline, + const CoglColor *color); + +#define cogl_pipeline_set_color4ub cogl_pipeline_set_color4ub_EXP +/** + * cogl_pipeline_set_color4ub: + * @pipeline: A #CoglPipeline object + * @red: The red component + * @green: The green component + * @blue: The blue component + * @alpha: The alpha component + * + * Sets the basic color of the pipeline, used when no lighting is enabled. + * + * The default value is (0xff, 0xff, 0xff, 0xff) + * + * Since: 2.0 + * Stability: Unstable + */ +void +cogl_pipeline_set_color4ub (CoglPipeline *pipeline, + guint8 red, + guint8 green, + guint8 blue, + guint8 alpha); + +#define cogl_pipeline_set_color4f cogl_pipeline_set_color4f_EXP +/** + * cogl_pipeline_set_color4f: + * @pipeline: A #CoglPipeline object + * @red: The red component + * @green: The green component + * @blue: The blue component + * @alpha: The alpha component + * + * Sets the basic color of the pipeline, used when no lighting is enabled. + * + * The default value is (1.0, 1.0, 1.0, 1.0) + * + * Since: 2.0 + * Stability: Unstable + */ +void +cogl_pipeline_set_color4f (CoglPipeline *pipeline, + float red, + float green, + float blue, + float alpha); + +#define cogl_pipeline_get_color cogl_pipeline_get_color_EXP +/** + * cogl_pipeline_get_color: + * @pipeline: A #CoglPipeline object + * @color: (out): The location to store the color + * + * Retrieves the current pipeline color. + * + * Since: 2.0 + * Stability: Unstable + */ +void +cogl_pipeline_get_color (CoglPipeline *pipeline, + CoglColor *color); + +#define cogl_pipeline_set_ambient cogl_pipeline_set_ambient_EXP +/** + * cogl_pipeline_set_ambient: + * @pipeline: A #CoglPipeline object + * @ambient: The components of the desired ambient color + * + * Sets the pipeline's ambient color, in the standard OpenGL lighting + * model. The ambient color affects the overall color of the object. + * + * Since the diffuse color will be intense when the light hits the surface + * directly, the ambient will be most apparent where the light hits at a + * slant. + * + * The default value is (0.2, 0.2, 0.2, 1.0) + * + * Since: 2.0 + * Stability: Unstable + */ +void +cogl_pipeline_set_ambient (CoglPipeline *pipeline, + const CoglColor *ambient); + +#define cogl_pipeline_get_ambient cogl_pipeline_get_ambient_EXP +/** + * cogl_pipeline_get_ambient: + * @pipeline: A #CoglPipeline object + * @ambient: The location to store the ambient color + * + * Retrieves the current ambient color for @pipeline + * + * Since: 2.0 + * Stability: Unstable + */ +void +cogl_pipeline_get_ambient (CoglPipeline *pipeline, + CoglColor *ambient); + +#define cogl_pipeline_set_diffuse cogl_pipeline_set_diffuse_EXP +/** + * cogl_pipeline_set_diffuse: + * @pipeline: A #CoglPipeline object + * @diffuse: The components of the desired diffuse color + * + * Sets the pipeline's diffuse color, in the standard OpenGL lighting + * model. The diffuse color is most intense where the light hits the + * surface directly - perpendicular to the surface. + * + * The default value is (0.8, 0.8, 0.8, 1.0) + * + * Since: 2.0 + * Stability: Unstable + */ +void +cogl_pipeline_set_diffuse (CoglPipeline *pipeline, + const CoglColor *diffuse); + +#define cogl_pipeline_get_diffuse cogl_pipeline_get_diffuse_EXP +/** + * cogl_pipeline_get_diffuse: + * @pipeline: A #CoglPipeline object + * @diffuse: The location to store the diffuse color + * + * Retrieves the current diffuse color for @pipeline + * + * Since: 2.0 + * Stability: Unstable + */ +void +cogl_pipeline_get_diffuse (CoglPipeline *pipeline, + CoglColor *diffuse); + +#define cogl_pipeline_set_ambient_and_diffuse \ + cogl_pipeline_set_ambient_and_diffuse_EXP +/** + * cogl_pipeline_set_ambient_and_diffuse: + * @pipeline: A #CoglPipeline object + * @color: The components of the desired ambient and diffuse colors + * + * Conveniently sets the diffuse and ambient color of @pipeline at the same + * time. See cogl_pipeline_set_ambient() and cogl_pipeline_set_diffuse(). + * + * The default ambient color is (0.2, 0.2, 0.2, 1.0) + * + * The default diffuse color is (0.8, 0.8, 0.8, 1.0) + * + * Since: 2.0 + * Stability: Unstable + */ +void +cogl_pipeline_set_ambient_and_diffuse (CoglPipeline *pipeline, + const CoglColor *color); + +#define cogl_pipeline_set_specular cogl_pipeline_set_specular_EXP +/** + * cogl_pipeline_set_specular: + * @pipeline: A #CoglPipeline object + * @specular: The components of the desired specular color + * + * Sets the pipeline's specular color, in the standard OpenGL lighting + * model. The intensity of the specular color depends on the viewport + * position, and is brightest along the lines of reflection. + * + * The default value is (0.0, 0.0, 0.0, 1.0) + * + * Since: 2.0 + * Stability: Unstable + */ +void +cogl_pipeline_set_specular (CoglPipeline *pipeline, + const CoglColor *specular); + +#define cogl_pipeline_get_specular cogl_pipeline_get_specular_EXP +/** + * cogl_pipeline_get_specular: + * @pipeline: A #CoglPipeline object + * @specular: The location to store the specular color + * + * Retrieves the pipelines current specular color. + * + * Since: 2.0 + * Stability: Unstable + */ +void +cogl_pipeline_get_specular (CoglPipeline *pipeline, + CoglColor *specular); + +#define cogl_pipeline_set_shininess cogl_pipeline_set_shininess_EXP +/** + * cogl_pipeline_set_shininess: + * @pipeline: A #CoglPipeline object + * @shininess: The desired shininess; must be >= 0.0 + * + * Sets the shininess of the pipeline, in the standard OpenGL lighting + * model, which determines the size of the specular highlights. A + * higher @shininess will produce smaller highlights which makes the + * object appear more shiny. + * + * The default value is 0.0 + * + * Since: 2.0 + * Stability: Unstable + */ +void +cogl_pipeline_set_shininess (CoglPipeline *pipeline, + float shininess); + +#define cogl_pipeline_get_shininess cogl_pipeline_get_shininess_EXP +/** + * cogl_pipeline_get_shininess: + * @pipeline: A #CoglPipeline object + * + * Retrieves the pipelines current emission color. + * + * Return value: The pipelines current shininess value + * + * Since: 2.0 + * Stability: Unstable + */ +float +cogl_pipeline_get_shininess (CoglPipeline *pipeline); + +#define cogl_pipeline_set_emission cogl_pipeline_set_emission_EXP +/** + * cogl_pipeline_set_emission: + * @pipeline: A #CoglPipeline object + * @emission: The components of the desired emissive color + * + * Sets the pipeline's emissive color, in the standard OpenGL lighting + * model. It will look like the surface is a light source emitting this + * color. + * + * The default value is (0.0, 0.0, 0.0, 1.0) + * + * Since: 2.0 + * Stability: Unstable + */ +void +cogl_pipeline_set_emission (CoglPipeline *pipeline, + const CoglColor *emission); + +#define cogl_pipeline_get_emission cogl_pipeline_get_emission_EXP +/** + * cogl_pipeline_get_emission: + * @pipeline: A #CoglPipeline object + * @emission: The location to store the emission color + * + * Retrieves the pipelines current emission color. + * + * Since: 2.0 + * Stability: Unstable + */ +void +cogl_pipeline_get_emission (CoglPipeline *pipeline, + CoglColor *emission); + +/** + * CoglPipelineAlphaFunc: + * @COGL_PIPELINE_ALPHA_FUNC_NEVER: Never let the fragment through. + * @COGL_PIPELINE_ALPHA_FUNC_LESS: Let the fragment through if the incoming + * alpha value is less than the reference alpha value + * @COGL_PIPELINE_ALPHA_FUNC_EQUAL: Let the fragment through if the incoming + * alpha value equals the reference alpha value + * @COGL_PIPELINE_ALPHA_FUNC_LEQUAL: Let the fragment through if the incoming + * alpha value is less than or equal to the reference alpha value + * @COGL_PIPELINE_ALPHA_FUNC_GREATER: Let the fragment through if the incoming + * alpha value is greater than the reference alpha value + * @COGL_PIPELINE_ALPHA_FUNC_NOTEQUAL: Let the fragment through if the incoming + * alpha value does not equal the reference alpha value + * @COGL_PIPELINE_ALPHA_FUNC_GEQUAL: Let the fragment through if the incoming + * alpha value is greater than or equal to the reference alpha value. + * @COGL_PIPELINE_ALPHA_FUNC_ALWAYS: Always let the fragment through. + * + * Alpha testing happens before blending primitives with the framebuffer and + * gives an opportunity to discard fragments based on a comparison with the + * incoming alpha value and a reference alpha value. The #CoglPipelineAlphaFunc + * determines how the comparison is done. + */ +typedef enum { + COGL_PIPELINE_ALPHA_FUNC_NEVER = 0x0200, + COGL_PIPELINE_ALPHA_FUNC_LESS = 0x0201, + COGL_PIPELINE_ALPHA_FUNC_EQUAL = 0x0202, + COGL_PIPELINE_ALPHA_FUNC_LEQUAL = 0x0203, + COGL_PIPELINE_ALPHA_FUNC_GREATER = 0x0204, + COGL_PIPELINE_ALPHA_FUNC_NOTEQUAL = 0x0205, + COGL_PIPELINE_ALPHA_FUNC_GEQUAL = 0x0206, + COGL_PIPELINE_ALPHA_FUNC_ALWAYS = 0x0207 +} CoglPipelineAlphaFunc; +/* NB: these values come from the equivalents in gl.h */ + +#define cogl_pipeline_set_alpha_test_function \ + cogl_pipeline_set_alpha_test_function_EXP +/** + * cogl_pipeline_set_alpha_test_function: + * @pipeline: A #CoglPipeline object + * @alpha_func: A @CoglPipelineAlphaFunc constant + * @alpha_reference: A reference point that the chosen alpha function uses + * to compare incoming fragments to. + * + * Before a primitive is blended with the framebuffer, it goes through an + * alpha test stage which lets you discard fragments based on the current + * alpha value. This function lets you change the function used to evaluate + * the alpha channel, and thus determine which fragments are discarded + * and which continue on to the blending stage. + * + * The default is %COGL_PIPELINE_ALPHA_FUNC_ALWAYS + * + * Since: 2.0 + * Stability: Unstable + */ +void +cogl_pipeline_set_alpha_test_function (CoglPipeline *pipeline, + CoglPipelineAlphaFunc alpha_func, + float alpha_reference); + +#define cogl_pipeline_get_alpha_test_function \ + cogl_pipeline_get_alpha_test_function_EXP +/** + * cogl_pipeline_get_alpha_test_function: + * @pipeline: A #CoglPipeline object + * + * Return value: The alpha test function of @pipeline. + * + * Since: 2.0 + * Stability: Unstable + */ +CoglPipelineAlphaFunc +cogl_pipeline_get_alpha_test_function (CoglPipeline *pipeline); + +#define cogl_pipeline_get_alpha_test_reference \ + cogl_pipeline_get_alpha_test_reference_EXP +/** + * cogl_pipeline_get_alpha_test_reference: + * @pipeline: A #CoglPipeline object + * + * Return value: The alpha test reference value of @pipeline. + * + * Since: 2.0 + * Stability: Unstable + */ +float +cogl_pipeline_get_alpha_test_reference (CoglPipeline *pipeline); + +#define cogl_pipeline_set_blend cogl_pipeline_set_blend_EXP +/** + * cogl_pipeline_set_blend: + * @pipeline: A #CoglPipeline object + * @blend_string: A <link linkend="cogl-Blend-Strings">Cogl blend string</link> + * describing the desired blend function. + * @error: return location for a #GError that may report lack of driver + * support if you give separate blend string statements for the alpha + * channel and RGB channels since some drivers, or backends such as + * GLES 1.1, don't support this feature. May be %NULL, in which case a + * warning will be printed out using GLib's logging facilities if an + * error is encountered. + * + * If not already familiar; please refer <link linkend="cogl-Blend-Strings">here</link> + * for an overview of what blend strings are, and their syntax. + * + * Blending occurs after the alpha test function, and combines fragments with + * the framebuffer. + + * Currently the only blend function Cogl exposes is ADD(). So any valid + * blend statements will be of the form: + * + * |[ + * <channel-mask>=ADD(SRC_COLOR*(<factor>), DST_COLOR*(<factor>)) + * ]| + * + * This is the list of source-names usable as blend factors: + * <itemizedlist> + * <listitem><para>SRC_COLOR: The color of the in comming fragment</para></listitem> + * <listitem><para>DST_COLOR: The color of the framebuffer</para></listitem> + * <listitem><para>CONSTANT: The constant set via cogl_pipeline_set_blend_constant()</para></listitem> + * </itemizedlist> + * + * The source names can be used according to the + * <link linkend="cogl-Blend-String-syntax">color-source and factor syntax</link>, + * so for example "(1-SRC_COLOR[A])" would be a valid factor, as would + * "(CONSTANT[RGB])" + * + * These can also be used as factors: + * <itemizedlist> + * <listitem>0: (0, 0, 0, 0)</listitem> + * <listitem>1: (1, 1, 1, 1)</listitem> + * <listitem>SRC_ALPHA_SATURATE_FACTOR: (f,f,f,1) where f = MIN(SRC_COLOR[A],1-DST_COLOR[A])</listitem> + * </itemizedlist> + * + * <note>Remember; all color components are normalized to the range [0, 1] + * before computing the result of blending.</note> + * + * <example id="cogl-Blend-Strings-blend-unpremul"> + * <title>Blend Strings/1</title> + * <para>Blend a non-premultiplied source over a destination with + * premultiplied alpha:</para> + * <programlisting> + * "RGB = ADD(SRC_COLOR*(SRC_COLOR[A]), DST_COLOR*(1-SRC_COLOR[A]))" + * "A = ADD(SRC_COLOR, DST_COLOR*(1-SRC_COLOR[A]))" + * </programlisting> + * </example> + * + * <example id="cogl-Blend-Strings-blend-premul"> + * <title>Blend Strings/2</title> + * <para>Blend a premultiplied source over a destination with + * premultiplied alpha</para> + * <programlisting> + * "RGBA = ADD(SRC_COLOR, DST_COLOR*(1-SRC_COLOR[A]))" + * </programlisting> + * </example> + * + * The default blend string is: + * |[ + * RGBA = ADD (SRC_COLOR, DST_COLOR*(1-SRC_COLOR[A])) + * ]| + * + * That gives normal alpha-blending when the calculated color for the pipeline + * is in premultiplied form. + * + * Return value: %TRUE if the blend string was successfully parsed, and the + * described blending is supported by the underlying driver/hardware. If + * there was an error, %FALSE is returned and @error is set accordingly (if + * present). + * + * Since: 2.0 + * Stability: Unstable + */ +gboolean +cogl_pipeline_set_blend (CoglPipeline *pipeline, + const char *blend_string, + GError **error); + +#define cogl_pipeline_set_blend_constant cogl_pipeline_set_blend_constant_EXP +/** + * cogl_pipeline_set_blend_constant: + * @pipeline: A #CoglPipeline object + * @constant_color: The constant color you want + * + * When blending is setup to reference a CONSTANT blend factor then + * blending will depend on the constant set with this function. + * + * Since: 2.0 + * Stability: Unstable + */ +void +cogl_pipeline_set_blend_constant (CoglPipeline *pipeline, + const CoglColor *constant_color); + +#define cogl_pipeline_set_point_size cogl_pipeline_set_point_size_EXP +/** + * cogl_pipeline_set_point_size: + * @pipeline: a #CoglPipeline pointer + * @point_size: the new point size. + * + * Changes the size of points drawn when %COGL_VERTICES_MODE_POINTS is + * used with the vertex buffer API. Note that typically the GPU will + * only support a limited minimum and maximum range of point sizes. If + * the chosen point size is outside that range then the nearest value + * within that range will be used instead. The size of a point is in + * screen space so it will be the same regardless of any + * transformations. The default point size is 1.0. + * + * Since: 2.0 + * Stability: Unstable + */ +void +cogl_pipeline_set_point_size (CoglPipeline *pipeline, + float point_size); + +#define cogl_pipeline_get_point_size cogl_pipeline_get_point_size_EXP +/** + * cogl_pipeline_get_point_size: + * @pipeline: a #CoglPipeline pointer + * + * Get the size of points drawn when %COGL_VERTICES_MODE_POINTS is + * used with the vertex buffer API. + * + * Return value: the point size of the @pipeline. + * + * Since: 2.0 + * Stability: Unstable + */ +float +cogl_pipeline_get_point_size (CoglPipeline *pipeline); + +#define cogl_pipeline_get_color_mask cogl_pipeline_get_color_mask_EXP +/** + * cogl_pipeline_get_color_mask: + * @pipeline: a #CoglPipeline object. + * + * Gets the current #CoglColorMask of which channels would be written to the + * current framebuffer. Each bit set in the mask means that the + * corresponding color would be written. + * + * Returns: A #CoglColorMask + * Since: 1.8 + * Stability: unstable + */ +CoglColorMask +cogl_pipeline_get_color_mask (CoglPipeline *pipeline); + +#define cogl_pipeline_set_color_mask cogl_pipeline_set_color_mask_EXP +/** + * cogl_pipeline_set_color_mask: + * @pipeline: a #CoglPipeline object. + * @color_mask: A #CoglColorMask of which color channels to write to + * the current framebuffer. + * + * Defines a bit mask of which color channels should be written to the + * current framebuffer. If a bit is set in @color_mask that means that + * color will be written. + * + * Since: 1.8 + * Stability: unstable + */ +void +cogl_pipeline_set_color_mask (CoglPipeline *pipeline, + CoglColorMask color_mask); + +#define cogl_pipeline_get_user_program cogl_pipeline_get_user_program_EXP +/** + * cogl_pipeline_get_user_program: + * @pipeline: a #CoglPipeline object. + * + * Queries what user program has been associated with the given + * @pipeline using cogl_pipeline_set_user_program(). + * + * Return value: The current user program or %COGL_INVALID_HANDLE. + * + * Since: 2.0 + * Stability: Unstable + */ +CoglHandle +cogl_pipeline_get_user_program (CoglPipeline *pipeline); + +#define cogl_pipeline_set_user_program cogl_pipeline_set_user_program_EXP +/** + * cogl_pipeline_set_user_program: + * @pipeline: a #CoglPipeline object. + * @program: A #CoglHandle to a linked CoglProgram + * + * Associates a linked CoglProgram with the given pipeline so that the + * program can take full control of vertex and/or fragment processing. + * + * This is an example of how it can be used to associate an ARBfp + * program with a #CoglPipeline: + * |[ + * CoglHandle shader; + * CoglHandle program; + * CoglPipeline *pipeline; + * + * shader = cogl_create_shader (COGL_SHADER_TYPE_FRAGMENT); + * cogl_shader_source (shader, + * "!!ARBfp1.0\n" + * "MOV result.color,fragment.color;\n" + * "END\n"); + * cogl_shader_compile (shader); + * + * program = cogl_create_program (); + * cogl_program_attach_shader (program, shader); + * cogl_program_link (program); + * + * pipeline = cogl_pipeline_new (); + * cogl_pipeline_set_user_program (pipeline, program); + * + * cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff); + * cogl_rectangle (0, 0, 100, 100); + * ]| + * + * It is possibly worth keeping in mind that this API is not part of + * the long term design for how we want to expose shaders to Cogl + * developers (We are planning on deprecating the cogl_program and + * cogl_shader APIs in favour of a "snippet" framework) but in the + * meantime we hope this will handle most practical GLSL and ARBfp + * requirements. + * + * Also remember you need to check for either the + * %COGL_FEATURE_SHADERS_GLSL or %COGL_FEATURE_SHADERS_ARBFP before + * using the cogl_program or cogl_shader API. + * + * Since: 2.0 + * Stability: Unstable + */ +void +cogl_pipeline_set_user_program (CoglPipeline *pipeline, + CoglHandle program); + +#define cogl_pipeline_set_depth_state cogl_pipeline_set_depth_state_EXP +/** + * cogl_pipeline_set_depth_state: + * @pipeline: A #CoglPipeline object + * @state: A #CoglDepthState struct + * @error: A #GError to report failures to setup the given @state. + * + * This commits all the depth state configured in @state struct to the + * given @pipeline. The configuration values are copied into the + * pipeline so there is no requirement to keep the #CoglDepthState + * struct around if you don't need it any more. + * + * Note: Since some platforms do not support the depth range feature + * it is possible for this function to fail and report an @error. + * + * Returns: TRUE if the GPU supports all the given @state else %FALSE + * and returns an @error. + * + * Since: 2.0 + * Stability: Unstable + */ +gboolean +cogl_pipeline_set_depth_state (CoglPipeline *pipeline, + const CoglDepthState *state, + GError **error); + +#define cogl_pipeline_get_depth_state cogl_pipeline_get_depth_state_EXP +/** + * cogl_pipeline_get_depth_state + * @pipeline: A #CoglPipeline object + * @state: A destination #CoglDepthState struct + * + * Retrieves the current depth state configuration for the given + * @pipeline as previously set using cogl_pipeline_set_depth_state(). + * + * Since: 2.0 + * Stability: Unstable + */ +void +cogl_pipeline_get_depth_state (CoglPipeline *pipeline, + CoglDepthState *state_out); + +#endif /* COGL_ENABLE_EXPERIMENTAL_API */ + +G_END_DECLS + +#endif /* __COGL_PIPELINE_STATE_H__ */ diff --git a/cogl/cogl-pipeline.c b/cogl/cogl-pipeline.c index 8b87a2ea8..384b646d7 100644 --- a/cogl/cogl-pipeline.c +++ b/cogl/cogl-pipeline.c @@ -37,6 +37,7 @@ #include "cogl-pipeline-private.h" #include "cogl-pipeline-opengl-private.h" +#include "cogl-pipeline-state-private.h" #include "cogl-texture-private.h" #include "cogl-blend-string.h" #include "cogl-journal-private.h" @@ -49,13 +50,6 @@ #include <glib/gprintf.h> #include <string.h> -#ifndef GL_FUNC_ADD -#define GL_FUNC_ADD 0x8006 -#endif - -typedef gboolean (*CoglPipelineStateComparitor) (CoglPipeline *authority0, - CoglPipeline *authority1); - static CoglPipelineLayer *_cogl_pipeline_layer_copy (CoglPipelineLayer *layer); static void _cogl_pipeline_free (CoglPipeline *tex); @@ -63,8 +57,6 @@ static void _cogl_pipeline_layer_free (CoglPipelineLayer *layer); static void _cogl_pipeline_add_layer_difference (CoglPipeline *pipeline, CoglPipelineLayer *layer, gboolean inc_n_layers); -static void handle_automatic_blend_enable (CoglPipeline *pipeline, - CoglPipelineState changes); static void recursively_free_layer_caches (CoglPipeline *pipeline); static gboolean _cogl_pipeline_is_weak (CoglPipeline *pipeline); @@ -792,19 +784,6 @@ layer_has_alpha_cb (CoglPipelineLayer *layer, void *data) return TRUE; } -static CoglPipeline * -_cogl_pipeline_get_user_program (CoglPipeline *pipeline) -{ - CoglPipeline *authority; - - g_return_val_if_fail (cogl_is_pipeline (pipeline), NULL); - - authority = - _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_USER_SHADER); - - return authority->big_state->user_program; -} - static gboolean _cogl_pipeline_needs_blending_enabled (CoglPipeline *pipeline, unsigned long changes, @@ -1084,7 +1063,7 @@ _cogl_pipeline_copy_differences (CoglPipeline *dest, */ check_for_blending_change: if (differences & COGL_PIPELINE_STATE_AFFECTS_BLENDING) - handle_automatic_blend_enable (dest, differences); + _cogl_pipeline_update_blend_enable (dest, differences); dest->differences |= differences; } @@ -1203,7 +1182,7 @@ reparent_children_cb (CoglPipelineNode *node, return TRUE; } -static void +void _cogl_pipeline_pre_change_notify (CoglPipeline *pipeline, CoglPipelineState change, const CoglColor *new_color, @@ -1514,9 +1493,9 @@ _cogl_pipeline_try_reverting_layers_authority (CoglPipeline *authority, } -static void -handle_automatic_blend_enable (CoglPipeline *pipeline, - CoglPipelineState change) +void +_cogl_pipeline_update_blend_enable (CoglPipeline *pipeline, + CoglPipelineState change) { gboolean blend_enable = _cogl_pipeline_needs_blending_enabled (pipeline, change, NULL); @@ -2288,7 +2267,7 @@ _cogl_pipeline_set_layer_texture_target (CoglPipeline *pipeline, changed: - handle_automatic_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS); + _cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS); } static void @@ -2367,7 +2346,7 @@ _cogl_pipeline_set_layer_texture_data (CoglPipeline *pipeline, changed: - handle_automatic_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS); + _cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS); } /* A convenience for querying the target of a given texture that @@ -3353,168 +3332,6 @@ _cogl_pipeline_layer_equal (CoglPipelineLayer *layer0, return TRUE; } -static gboolean -_cogl_pipeline_color_equal (CoglPipeline *authority0, - CoglPipeline *authority1) -{ - return cogl_color_equal (&authority0->color, &authority1->color); -} - -static gboolean -_cogl_pipeline_lighting_state_equal (CoglPipeline *authority0, - CoglPipeline *authority1) -{ - CoglPipelineLightingState *state0 = &authority0->big_state->lighting_state; - CoglPipelineLightingState *state1 = &authority1->big_state->lighting_state; - - if (memcmp (state0->ambient, state1->ambient, sizeof (float) * 4) != 0) - return FALSE; - if (memcmp (state0->diffuse, state1->diffuse, sizeof (float) * 4) != 0) - return FALSE; - if (memcmp (state0->specular, state1->specular, sizeof (float) * 4) != 0) - return FALSE; - if (memcmp (state0->emission, state1->emission, sizeof (float) * 4) != 0) - return FALSE; - if (state0->shininess != state1->shininess) - return FALSE; - - return TRUE; -} - -static gboolean -_cogl_pipeline_alpha_func_state_equal (CoglPipeline *authority0, - CoglPipeline *authority1) -{ - CoglPipelineAlphaFuncState *alpha_state0 = - &authority0->big_state->alpha_state; - CoglPipelineAlphaFuncState *alpha_state1 = - &authority1->big_state->alpha_state; - - return alpha_state0->alpha_func == alpha_state1->alpha_func; -} - -static gboolean -_cogl_pipeline_alpha_func_reference_state_equal (CoglPipeline *authority0, - CoglPipeline *authority1) -{ - CoglPipelineAlphaFuncState *alpha_state0 = - &authority0->big_state->alpha_state; - CoglPipelineAlphaFuncState *alpha_state1 = - &authority1->big_state->alpha_state; - - return (alpha_state0->alpha_func_reference == - alpha_state1->alpha_func_reference); -} - -static gboolean -_cogl_pipeline_blend_state_equal (CoglPipeline *authority0, - CoglPipeline *authority1) -{ - CoglPipelineBlendState *blend_state0 = &authority0->big_state->blend_state; - CoglPipelineBlendState *blend_state1 = &authority1->big_state->blend_state; - - _COGL_GET_CONTEXT (ctx, FALSE); - -#if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL) - if (ctx->driver != COGL_DRIVER_GLES1) - { - if (blend_state0->blend_equation_rgb != blend_state1->blend_equation_rgb) - return FALSE; - if (blend_state0->blend_equation_alpha != - blend_state1->blend_equation_alpha) - return FALSE; - if (blend_state0->blend_src_factor_alpha != - blend_state1->blend_src_factor_alpha) - return FALSE; - if (blend_state0->blend_dst_factor_alpha != - blend_state1->blend_dst_factor_alpha) - return FALSE; - } -#endif - if (blend_state0->blend_src_factor_rgb != - blend_state1->blend_src_factor_rgb) - return FALSE; - if (blend_state0->blend_dst_factor_rgb != - blend_state1->blend_dst_factor_rgb) - return FALSE; -#if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL) - if (ctx->driver != COGL_DRIVER_GLES1 && - (blend_state0->blend_src_factor_rgb == GL_ONE_MINUS_CONSTANT_COLOR || - blend_state0->blend_src_factor_rgb == GL_CONSTANT_COLOR || - blend_state0->blend_dst_factor_rgb == GL_ONE_MINUS_CONSTANT_COLOR || - blend_state0->blend_dst_factor_rgb == GL_CONSTANT_COLOR)) - { - if (!cogl_color_equal (&blend_state0->blend_constant, - &blend_state1->blend_constant)) - return FALSE; - } -#endif - - return TRUE; -} - -static gboolean -_cogl_pipeline_depth_state_equal (CoglPipeline *authority0, - CoglPipeline *authority1) -{ - if (authority0->big_state->depth_state.test_enabled == FALSE && - authority1->big_state->depth_state.test_enabled == FALSE) - return TRUE; - else - { - CoglDepthState *s0 = &authority0->big_state->depth_state; - CoglDepthState *s1 = &authority1->big_state->depth_state; - return s0->test_enabled == s1->test_enabled && - s0->test_function == s1->test_function && - s0->write_enabled == s1->write_enabled && - s0->range_near == s1->range_near && - s0->range_far == s1->range_far; - } -} - -static gboolean -_cogl_pipeline_fog_state_equal (CoglPipeline *authority0, - CoglPipeline *authority1) -{ - CoglPipelineFogState *fog_state0 = &authority0->big_state->fog_state; - CoglPipelineFogState *fog_state1 = &authority1->big_state->fog_state; - - if (fog_state0->enabled == fog_state1->enabled && - cogl_color_equal (&fog_state0->color, &fog_state1->color) && - fog_state0->mode == fog_state1->mode && - fog_state0->density == fog_state1->density && - fog_state0->z_near == fog_state1->z_near && - fog_state0->z_far == fog_state1->z_far) - return TRUE; - else - return FALSE; -} - -static gboolean -_cogl_pipeline_point_size_equal (CoglPipeline *authority0, - CoglPipeline *authority1) -{ - return authority0->big_state->point_size == authority1->big_state->point_size; -} - -static gboolean -_cogl_pipeline_logic_ops_state_equal (CoglPipeline *authority0, - CoglPipeline *authority1) -{ - CoglPipelineLogicOpsState *logic_ops_state0 = &authority0->big_state->logic_ops_state; - CoglPipelineLogicOpsState *logic_ops_state1 = &authority1->big_state->logic_ops_state; - - return logic_ops_state0->color_mask == logic_ops_state1->color_mask; -} - -static gboolean -_cogl_pipeline_user_shader_equal (CoglPipeline *authority0, - CoglPipeline *authority1) -{ - return (authority0->big_state->user_program == - authority1->big_state->user_program); -} - static gboolean _cogl_pipeline_layers_equal (CoglPipeline *authority0, CoglPipeline *authority1, @@ -3850,31 +3667,6 @@ done: } void -cogl_pipeline_get_color (CoglPipeline *pipeline, - CoglColor *color) -{ - CoglPipeline *authority; - - g_return_if_fail (cogl_is_pipeline (pipeline)); - - authority = - _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_COLOR); - - *color = authority->color; -} - -/* This is used heavily by the cogl journal when logging quads */ -void -_cogl_pipeline_get_colorubv (CoglPipeline *pipeline, - guint8 *color) -{ - CoglPipeline *authority = - _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_COLOR); - - _cogl_color_get_rgba_4ubv (&authority->color, color); -} - -static void _cogl_pipeline_prune_redundant_ancestry (CoglPipeline *pipeline) { CoglPipeline *new_parent = _cogl_pipeline_get_parent (pipeline); @@ -3914,7 +3706,7 @@ _cogl_pipeline_prune_redundant_ancestry (CoglPipeline *pipeline) } } -static void +void _cogl_pipeline_update_authority (CoglPipeline *pipeline, CoglPipeline *authority, CoglPipelineState state, @@ -3943,919 +3735,6 @@ _cogl_pipeline_update_authority (CoglPipeline *pipeline, } } -void -cogl_pipeline_set_color (CoglPipeline *pipeline, - const CoglColor *color) -{ - CoglPipelineState state = COGL_PIPELINE_STATE_COLOR; - CoglPipeline *authority; - - g_return_if_fail (cogl_is_pipeline (pipeline)); - - authority = _cogl_pipeline_get_authority (pipeline, state); - - if (cogl_color_equal (color, &authority->color)) - return; - - /* - Flush journal primitives referencing the current state. - * - Make sure the pipeline has no dependants so it may be modified. - * - If the pipeline isn't currently an authority for the state being - * changed, then initialize that state from the current authority. - */ - _cogl_pipeline_pre_change_notify (pipeline, state, color, FALSE); - - pipeline->color = *color; - - _cogl_pipeline_update_authority (pipeline, authority, state, - _cogl_pipeline_color_equal); - - handle_automatic_blend_enable (pipeline, state); -} - -void -cogl_pipeline_set_color4ub (CoglPipeline *pipeline, - guint8 red, - guint8 green, - guint8 blue, - guint8 alpha) -{ - CoglColor color; - cogl_color_init_from_4ub (&color, red, green, blue, alpha); - cogl_pipeline_set_color (pipeline, &color); -} - -void -cogl_pipeline_set_color4f (CoglPipeline *pipeline, - float red, - float green, - float blue, - float alpha) -{ - CoglColor color; - cogl_color_init_from_4f (&color, red, green, blue, alpha); - cogl_pipeline_set_color (pipeline, &color); -} - -CoglPipelineBlendEnable -_cogl_pipeline_get_blend_enabled (CoglPipeline *pipeline) -{ - CoglPipeline *authority; - - g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE); - - authority = - _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_BLEND_ENABLE); - return authority->blend_enable; -} - -static gboolean -_cogl_pipeline_blend_enable_equal (CoglPipeline *authority0, - CoglPipeline *authority1) -{ - return authority0->blend_enable == authority1->blend_enable ? TRUE : FALSE; -} - -void -_cogl_pipeline_set_blend_enabled (CoglPipeline *pipeline, - CoglPipelineBlendEnable enable) -{ - CoglPipelineState state = COGL_PIPELINE_STATE_BLEND_ENABLE; - CoglPipeline *authority; - - g_return_if_fail (cogl_is_pipeline (pipeline)); - g_return_if_fail (enable > 1 && - "don't pass TRUE or FALSE to _set_blend_enabled!"); - - authority = _cogl_pipeline_get_authority (pipeline, state); - - if (authority->blend_enable == enable) - return; - - /* - Flush journal primitives referencing the current state. - * - Make sure the pipeline has no dependants so it may be modified. - * - If the pipeline isn't currently an authority for the state being - * changed, then initialize that state from the current authority. - */ - _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); - - pipeline->blend_enable = enable; - - _cogl_pipeline_update_authority (pipeline, authority, state, - _cogl_pipeline_blend_enable_equal); - - handle_automatic_blend_enable (pipeline, state); -} - -void -cogl_pipeline_get_ambient (CoglPipeline *pipeline, - CoglColor *ambient) -{ - CoglPipeline *authority; - - g_return_if_fail (cogl_is_pipeline (pipeline)); - - authority = - _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING); - - cogl_color_init_from_4fv (ambient, - authority->big_state->lighting_state.ambient); -} - -void -cogl_pipeline_set_ambient (CoglPipeline *pipeline, - const CoglColor *ambient) -{ - CoglPipelineState state = COGL_PIPELINE_STATE_LIGHTING; - CoglPipeline *authority; - CoglPipelineLightingState *lighting_state; - - g_return_if_fail (cogl_is_pipeline (pipeline)); - - authority = _cogl_pipeline_get_authority (pipeline, state); - - lighting_state = &authority->big_state->lighting_state; - if (cogl_color_equal (ambient, &lighting_state->ambient)) - return; - - /* - Flush journal primitives referencing the current state. - * - Make sure the pipeline has no dependants so it may be modified. - * - If the pipeline isn't currently an authority for the state being - * changed, then initialize that state from the current authority. - */ - _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); - - lighting_state = &pipeline->big_state->lighting_state; - lighting_state->ambient[0] = cogl_color_get_red_float (ambient); - lighting_state->ambient[1] = cogl_color_get_green_float (ambient); - lighting_state->ambient[2] = cogl_color_get_blue_float (ambient); - lighting_state->ambient[3] = cogl_color_get_alpha_float (ambient); - - _cogl_pipeline_update_authority (pipeline, authority, state, - _cogl_pipeline_lighting_state_equal); - - handle_automatic_blend_enable (pipeline, state); -} - -void -cogl_pipeline_get_diffuse (CoglPipeline *pipeline, - CoglColor *diffuse) -{ - CoglPipeline *authority; - - g_return_if_fail (cogl_is_pipeline (pipeline)); - - authority = - _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING); - - cogl_color_init_from_4fv (diffuse, - authority->big_state->lighting_state.diffuse); -} - -void -cogl_pipeline_set_diffuse (CoglPipeline *pipeline, - const CoglColor *diffuse) -{ - CoglPipelineState state = COGL_PIPELINE_STATE_LIGHTING; - CoglPipeline *authority; - CoglPipelineLightingState *lighting_state; - - g_return_if_fail (cogl_is_pipeline (pipeline)); - - authority = _cogl_pipeline_get_authority (pipeline, state); - - lighting_state = &authority->big_state->lighting_state; - if (cogl_color_equal (diffuse, &lighting_state->diffuse)) - return; - - /* - Flush journal primitives referencing the current state. - * - Make sure the pipeline has no dependants so it may be modified. - * - If the pipeline isn't currently an authority for the state being - * changed, then initialize that state from the current authority. - */ - _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); - - lighting_state = &pipeline->big_state->lighting_state; - lighting_state->diffuse[0] = cogl_color_get_red_float (diffuse); - lighting_state->diffuse[1] = cogl_color_get_green_float (diffuse); - lighting_state->diffuse[2] = cogl_color_get_blue_float (diffuse); - lighting_state->diffuse[3] = cogl_color_get_alpha_float (diffuse); - - - _cogl_pipeline_update_authority (pipeline, authority, state, - _cogl_pipeline_lighting_state_equal); - - handle_automatic_blend_enable (pipeline, state); -} - -void -cogl_pipeline_set_ambient_and_diffuse (CoglPipeline *pipeline, - const CoglColor *color) -{ - cogl_pipeline_set_ambient (pipeline, color); - cogl_pipeline_set_diffuse (pipeline, color); -} - -void -cogl_pipeline_get_specular (CoglPipeline *pipeline, - CoglColor *specular) -{ - CoglPipeline *authority; - - g_return_if_fail (cogl_is_pipeline (pipeline)); - - authority = - _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING); - - cogl_color_init_from_4fv (specular, - authority->big_state->lighting_state.specular); -} - -void -cogl_pipeline_set_specular (CoglPipeline *pipeline, const CoglColor *specular) -{ - CoglPipeline *authority; - CoglPipelineState state = COGL_PIPELINE_STATE_LIGHTING; - CoglPipelineLightingState *lighting_state; - - g_return_if_fail (cogl_is_pipeline (pipeline)); - - authority = _cogl_pipeline_get_authority (pipeline, state); - - lighting_state = &authority->big_state->lighting_state; - if (cogl_color_equal (specular, &lighting_state->specular)) - return; - - /* - Flush journal primitives referencing the current state. - * - Make sure the pipeline has no dependants so it may be modified. - * - If the pipeline isn't currently an authority for the state being - * changed, then initialize that state from the current authority. - */ - _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); - - lighting_state = &pipeline->big_state->lighting_state; - lighting_state->specular[0] = cogl_color_get_red_float (specular); - lighting_state->specular[1] = cogl_color_get_green_float (specular); - lighting_state->specular[2] = cogl_color_get_blue_float (specular); - lighting_state->specular[3] = cogl_color_get_alpha_float (specular); - - _cogl_pipeline_update_authority (pipeline, authority, state, - _cogl_pipeline_lighting_state_equal); - - handle_automatic_blend_enable (pipeline, state); -} - -float -cogl_pipeline_get_shininess (CoglPipeline *pipeline) -{ - CoglPipeline *authority; - - g_return_val_if_fail (cogl_is_pipeline (pipeline), 0); - - authority = - _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING); - - return authority->big_state->lighting_state.shininess; -} - -void -cogl_pipeline_set_shininess (CoglPipeline *pipeline, - float shininess) -{ - CoglPipeline *authority; - CoglPipelineState state = COGL_PIPELINE_STATE_LIGHTING; - CoglPipelineLightingState *lighting_state; - - g_return_if_fail (cogl_is_pipeline (pipeline)); - - if (shininess < 0.0) - { - g_warning ("Out of range shininess %f supplied for pipeline\n", - shininess); - return; - } - - authority = _cogl_pipeline_get_authority (pipeline, state); - - lighting_state = &authority->big_state->lighting_state; - - if (lighting_state->shininess == shininess) - return; - - /* - Flush journal primitives referencing the current state. - * - Make sure the pipeline has no dependants so it may be modified. - * - If the pipeline isn't currently an authority for the state being - * changed, then initialize that state from the current authority. - */ - _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); - - lighting_state = &pipeline->big_state->lighting_state; - lighting_state->shininess = shininess; - - _cogl_pipeline_update_authority (pipeline, authority, state, - _cogl_pipeline_lighting_state_equal); -} - -void -cogl_pipeline_get_emission (CoglPipeline *pipeline, - CoglColor *emission) -{ - CoglPipeline *authority; - - g_return_if_fail (cogl_is_pipeline (pipeline)); - - authority = - _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING); - - cogl_color_init_from_4fv (emission, - authority->big_state->lighting_state.emission); -} - -void -cogl_pipeline_set_emission (CoglPipeline *pipeline, const CoglColor *emission) -{ - CoglPipeline *authority; - CoglPipelineState state = COGL_PIPELINE_STATE_LIGHTING; - CoglPipelineLightingState *lighting_state; - - g_return_if_fail (cogl_is_pipeline (pipeline)); - - authority = _cogl_pipeline_get_authority (pipeline, state); - - lighting_state = &authority->big_state->lighting_state; - if (cogl_color_equal (emission, &lighting_state->emission)) - return; - - /* - Flush journal primitives referencing the current state. - * - Make sure the pipeline has no dependants so it may be modified. - * - If the pipeline isn't currently an authority for the state being - * changed, then initialize that state from the current authority. - */ - _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); - - lighting_state = &pipeline->big_state->lighting_state; - lighting_state->emission[0] = cogl_color_get_red_float (emission); - lighting_state->emission[1] = cogl_color_get_green_float (emission); - lighting_state->emission[2] = cogl_color_get_blue_float (emission); - lighting_state->emission[3] = cogl_color_get_alpha_float (emission); - - _cogl_pipeline_update_authority (pipeline, authority, state, - _cogl_pipeline_lighting_state_equal); - - handle_automatic_blend_enable (pipeline, state); -} - -static void -_cogl_pipeline_set_alpha_test_function (CoglPipeline *pipeline, - CoglPipelineAlphaFunc alpha_func) -{ - CoglPipelineState state = COGL_PIPELINE_STATE_ALPHA_FUNC; - CoglPipeline *authority; - CoglPipelineAlphaFuncState *alpha_state; - - g_return_if_fail (cogl_is_pipeline (pipeline)); - - authority = _cogl_pipeline_get_authority (pipeline, state); - - alpha_state = &authority->big_state->alpha_state; - if (alpha_state->alpha_func == alpha_func) - return; - - /* - Flush journal primitives referencing the current state. - * - Make sure the pipeline has no dependants so it may be modified. - * - If the pipeline isn't currently an authority for the state being - * changed, then initialize that state from the current authority. - */ - _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); - - alpha_state = &pipeline->big_state->alpha_state; - alpha_state->alpha_func = alpha_func; - - _cogl_pipeline_update_authority (pipeline, authority, state, - _cogl_pipeline_alpha_func_state_equal); -} - -static void -_cogl_pipeline_set_alpha_test_function_reference (CoglPipeline *pipeline, - float alpha_reference) -{ - CoglPipelineState state = COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE; - CoglPipeline *authority; - CoglPipelineAlphaFuncState *alpha_state; - - g_return_if_fail (cogl_is_pipeline (pipeline)); - - authority = _cogl_pipeline_get_authority (pipeline, state); - - alpha_state = &authority->big_state->alpha_state; - if (alpha_state->alpha_func_reference == alpha_reference) - return; - - /* - Flush journal primitives referencing the current state. - * - Make sure the pipeline has no dependants so it may be modified. - * - If the pipeline isn't currently an authority for the state being - * changed, then initialize that state from the current authority. - */ - _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); - - alpha_state = &pipeline->big_state->alpha_state; - alpha_state->alpha_func_reference = alpha_reference; - - _cogl_pipeline_update_authority - (pipeline, authority, state, - _cogl_pipeline_alpha_func_reference_state_equal); -} - -void -cogl_pipeline_set_alpha_test_function (CoglPipeline *pipeline, - CoglPipelineAlphaFunc alpha_func, - float alpha_reference) -{ - _cogl_pipeline_set_alpha_test_function (pipeline, alpha_func); - _cogl_pipeline_set_alpha_test_function_reference (pipeline, alpha_reference); -} - -CoglPipelineAlphaFunc -cogl_pipeline_get_alpha_test_function (CoglPipeline *pipeline) -{ - CoglPipeline *authority; - - g_return_val_if_fail (cogl_is_pipeline (pipeline), 0); - - authority = - _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_ALPHA_FUNC); - - return authority->big_state->alpha_state.alpha_func; -} - -float -cogl_pipeline_get_alpha_test_reference (CoglPipeline *pipeline) -{ - CoglPipeline *authority; - - g_return_val_if_fail (cogl_is_pipeline (pipeline), 0.0f); - - authority = - _cogl_pipeline_get_authority (pipeline, - COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE); - - return authority->big_state->alpha_state.alpha_func_reference; -} - -GLenum -arg_to_gl_blend_factor (CoglBlendStringArgument *arg) -{ - if (arg->source.is_zero) - return GL_ZERO; - if (arg->factor.is_one) - return GL_ONE; - else if (arg->factor.is_src_alpha_saturate) - return GL_SRC_ALPHA_SATURATE; - else if (arg->factor.source.info->type == - COGL_BLEND_STRING_COLOR_SOURCE_SRC_COLOR) - { - if (arg->factor.source.mask != COGL_BLEND_STRING_CHANNEL_MASK_ALPHA) - { - if (arg->factor.source.one_minus) - return GL_ONE_MINUS_SRC_COLOR; - else - return GL_SRC_COLOR; - } - else - { - if (arg->factor.source.one_minus) - return GL_ONE_MINUS_SRC_ALPHA; - else - return GL_SRC_ALPHA; - } - } - else if (arg->factor.source.info->type == - COGL_BLEND_STRING_COLOR_SOURCE_DST_COLOR) - { - if (arg->factor.source.mask != COGL_BLEND_STRING_CHANNEL_MASK_ALPHA) - { - if (arg->factor.source.one_minus) - return GL_ONE_MINUS_DST_COLOR; - else - return GL_DST_COLOR; - } - else - { - if (arg->factor.source.one_minus) - return GL_ONE_MINUS_DST_ALPHA; - else - return GL_DST_ALPHA; - } - } -#if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL) - else if (arg->factor.source.info->type == - COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT) - { - if (arg->factor.source.mask != COGL_BLEND_STRING_CHANNEL_MASK_ALPHA) - { - if (arg->factor.source.one_minus) - return GL_ONE_MINUS_CONSTANT_COLOR; - else - return GL_CONSTANT_COLOR; - } - else - { - if (arg->factor.source.one_minus) - return GL_ONE_MINUS_CONSTANT_ALPHA; - else - return GL_CONSTANT_ALPHA; - } - } -#endif - - g_warning ("Unable to determine valid blend factor from blend string\n"); - return GL_ONE; -} - -void -setup_blend_state (CoglBlendStringStatement *statement, - GLenum *blend_equation, - GLint *blend_src_factor, - GLint *blend_dst_factor) -{ - switch (statement->function->type) - { - case COGL_BLEND_STRING_FUNCTION_ADD: - *blend_equation = GL_FUNC_ADD; - break; - /* TODO - add more */ - default: - g_warning ("Unsupported blend function given"); - *blend_equation = GL_FUNC_ADD; - } - - *blend_src_factor = arg_to_gl_blend_factor (&statement->args[0]); - *blend_dst_factor = arg_to_gl_blend_factor (&statement->args[1]); -} - -gboolean -cogl_pipeline_set_blend (CoglPipeline *pipeline, - const char *blend_description, - GError **error) -{ - CoglPipelineState state = COGL_PIPELINE_STATE_BLEND; - CoglPipeline *authority; - CoglBlendStringStatement statements[2]; - CoglBlendStringStatement *rgb; - CoglBlendStringStatement *a; - GError *internal_error = NULL; - int count; - CoglPipelineBlendState *blend_state; - - _COGL_GET_CONTEXT (ctx, FALSE); - - g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE); - - count = - _cogl_blend_string_compile (blend_description, - COGL_BLEND_STRING_CONTEXT_BLENDING, - statements, - &internal_error); - if (!count) - { - if (error) - g_propagate_error (error, internal_error); - else - { - g_warning ("Cannot compile blend description: %s\n", - internal_error->message); - g_error_free (internal_error); - } - return FALSE; - } - - if (count == 1) - rgb = a = statements; - else - { - rgb = &statements[0]; - a = &statements[1]; - } - - authority = - _cogl_pipeline_get_authority (pipeline, state); - - /* - Flush journal primitives referencing the current state. - * - Make sure the pipeline has no dependants so it may be modified. - * - If the pipeline isn't currently an authority for the state being - * changed, then initialize that state from the current authority. - */ - _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); - - blend_state = &pipeline->big_state->blend_state; -#if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES2) - if (ctx->driver != COGL_DRIVER_GLES1) - { - setup_blend_state (rgb, - &blend_state->blend_equation_rgb, - &blend_state->blend_src_factor_rgb, - &blend_state->blend_dst_factor_rgb); - setup_blend_state (a, - &blend_state->blend_equation_alpha, - &blend_state->blend_src_factor_alpha, - &blend_state->blend_dst_factor_alpha); - } - else -#endif - { - setup_blend_state (rgb, - NULL, - &blend_state->blend_src_factor_rgb, - &blend_state->blend_dst_factor_rgb); - } - - /* If we are the current authority see if we can revert to one of our - * ancestors being the authority */ - if (pipeline == authority && - _cogl_pipeline_get_parent (authority) != NULL) - { - CoglPipeline *parent = _cogl_pipeline_get_parent (authority); - CoglPipeline *old_authority = - _cogl_pipeline_get_authority (parent, state); - - if (_cogl_pipeline_blend_state_equal (authority, old_authority)) - pipeline->differences &= ~state; - } - - /* 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 (pipeline != authority) - { - pipeline->differences |= state; - _cogl_pipeline_prune_redundant_ancestry (pipeline); - } - - handle_automatic_blend_enable (pipeline, state); - - return TRUE; -} - -void -cogl_pipeline_set_blend_constant (CoglPipeline *pipeline, - const CoglColor *constant_color) -{ - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - g_return_if_fail (cogl_is_pipeline (pipeline)); - - if (ctx->driver == COGL_DRIVER_GLES1) - return; - -#if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL) - { - CoglPipelineState state = COGL_PIPELINE_STATE_BLEND; - CoglPipeline *authority; - CoglPipelineBlendState *blend_state; - - authority = _cogl_pipeline_get_authority (pipeline, state); - - blend_state = &authority->big_state->blend_state; - if (cogl_color_equal (constant_color, &blend_state->blend_constant)) - return; - - /* - Flush journal primitives referencing the current state. - * - Make sure the pipeline has no dependants so it may be modified. - * - If the pipeline isn't currently an authority for the state being - * changed, then initialize that state from the current authority. - */ - _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); - - blend_state = &pipeline->big_state->blend_state; - blend_state->blend_constant = *constant_color; - - _cogl_pipeline_update_authority (pipeline, authority, state, - _cogl_pipeline_blend_state_equal); - - handle_automatic_blend_enable (pipeline, state); - } -#endif -} - -CoglHandle -cogl_pipeline_get_user_program (CoglPipeline *pipeline) -{ - CoglPipeline *authority; - - g_return_val_if_fail (cogl_is_pipeline (pipeline), COGL_INVALID_HANDLE); - - authority = - _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_USER_SHADER); - - return authority->big_state->user_program; -} - -/* XXX: for now we don't mind if the program has vertex shaders - * attached but if we ever make a similar API public we should only - * allow attaching of programs containing fragment shaders. Eventually - * we will have a CoglPipeline abstraction to also cover vertex - * processing. - */ -void -cogl_pipeline_set_user_program (CoglPipeline *pipeline, - CoglHandle program) -{ - CoglPipelineState state = COGL_PIPELINE_STATE_USER_SHADER; - CoglPipeline *authority; - - g_return_if_fail (cogl_is_pipeline (pipeline)); - - authority = _cogl_pipeline_get_authority (pipeline, state); - - if (authority->big_state->user_program == program) - return; - - /* - Flush journal primitives referencing the current state. - * - Make sure the pipeline has no dependants so it may be modified. - * - If the pipeline isn't currently an authority for the state being - * changed, then initialize that state from the current authority. - */ - _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); - - if (program != COGL_INVALID_HANDLE) - { - _cogl_pipeline_set_fragend (pipeline, COGL_PIPELINE_FRAGEND_DEFAULT); - _cogl_pipeline_set_vertend (pipeline, COGL_PIPELINE_VERTEND_DEFAULT); - } - - /* If we are the current authority see if we can revert to one of our - * ancestors being the authority */ - if (pipeline == authority && - _cogl_pipeline_get_parent (authority) != NULL) - { - CoglPipeline *parent = _cogl_pipeline_get_parent (authority); - CoglPipeline *old_authority = - _cogl_pipeline_get_authority (parent, state); - - if (old_authority->big_state->user_program == program) - pipeline->differences &= ~state; - } - else if (pipeline != authority) - { - /* 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... */ - pipeline->differences |= state; - _cogl_pipeline_prune_redundant_ancestry (pipeline); - } - - if (program != COGL_INVALID_HANDLE) - cogl_handle_ref (program); - if (authority == pipeline && - pipeline->big_state->user_program != COGL_INVALID_HANDLE) - cogl_handle_unref (pipeline->big_state->user_program); - pipeline->big_state->user_program = program; - - handle_automatic_blend_enable (pipeline, state); -} - -gboolean -cogl_pipeline_set_depth_state (CoglPipeline *pipeline, - const CoglDepthState *depth_state, - GError **error) -{ - CoglPipelineState state = COGL_PIPELINE_STATE_DEPTH; - CoglPipeline *authority; - CoglDepthState *orig_state; - - _COGL_GET_CONTEXT (ctx, FALSE); - - g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE); - g_return_val_if_fail (depth_state->magic == COGL_DEPTH_STATE_MAGIC, FALSE); - - authority = _cogl_pipeline_get_authority (pipeline, state); - - orig_state = &authority->big_state->depth_state; - if (orig_state->test_enabled == depth_state->test_enabled && - orig_state->write_enabled == depth_state->write_enabled && - orig_state->test_function == depth_state->test_function && - orig_state->range_near == depth_state->range_near && - orig_state->range_far == depth_state->range_far) - return TRUE; - - if (ctx->driver == COGL_DRIVER_GLES1 && - (depth_state->range_near != 0 || - depth_state->range_far != 1)) - { - g_set_error (error, - COGL_ERROR, - COGL_ERROR_UNSUPPORTED, - "glDepthRange not available on GLES 1"); - return FALSE; - } - - /* - Flush journal primitives referencing the current state. - * - Make sure the pipeline has no dependants so it may be modified. - * - If the pipeline isn't currently an authority for the state being - * changed, then initialize that state from the current authority. - */ - _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); - - pipeline->big_state->depth_state = *depth_state; - - _cogl_pipeline_update_authority (pipeline, authority, state, - _cogl_pipeline_depth_state_equal); - - return TRUE; -} - -void -cogl_pipeline_get_depth_state (CoglPipeline *pipeline, - CoglDepthState *state) -{ - CoglPipeline *authority; - - g_return_if_fail (cogl_is_pipeline (pipeline)); - - authority = - _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_DEPTH); - *state = authority->big_state->depth_state; -} - -CoglColorMask -cogl_pipeline_get_color_mask (CoglPipeline *pipeline) -{ - CoglPipeline *authority; - - g_return_val_if_fail (cogl_is_pipeline (pipeline), 0); - - authority = - _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LOGIC_OPS); - - return authority->big_state->logic_ops_state.color_mask; -} - -void -cogl_pipeline_set_color_mask (CoglPipeline *pipeline, - CoglColorMask color_mask) -{ - CoglPipelineState state = COGL_PIPELINE_STATE_LOGIC_OPS; - CoglPipeline *authority; - CoglPipelineLogicOpsState *logic_ops_state; - - g_return_if_fail (cogl_is_pipeline (pipeline)); - - authority = _cogl_pipeline_get_authority (pipeline, state); - - logic_ops_state = &authority->big_state->logic_ops_state; - if (logic_ops_state->color_mask == color_mask) - return; - - /* - Flush journal primitives referencing the current state. - * - Make sure the pipeline has no dependants so it may be modified. - * - If the pipeline isn't currently an authority for the state being - * changed, then initialize that state from the current authority. - */ - _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); - - logic_ops_state = &pipeline->big_state->logic_ops_state; - logic_ops_state->color_mask = color_mask; - - _cogl_pipeline_update_authority (pipeline, authority, state, - _cogl_pipeline_logic_ops_state_equal); -} - -static void -_cogl_pipeline_set_fog_state (CoglPipeline *pipeline, - const CoglPipelineFogState *fog_state) -{ - CoglPipelineState state = COGL_PIPELINE_STATE_FOG; - CoglPipeline *authority; - CoglPipelineFogState *current_fog_state; - - g_return_if_fail (cogl_is_pipeline (pipeline)); - - authority = _cogl_pipeline_get_authority (pipeline, state); - - current_fog_state = &authority->big_state->fog_state; - - if (current_fog_state->enabled == fog_state->enabled && - cogl_color_equal (¤t_fog_state->color, &fog_state->color) && - current_fog_state->mode == fog_state->mode && - current_fog_state->density == fog_state->density && - current_fog_state->z_near == fog_state->z_near && - current_fog_state->z_far == fog_state->z_far) - return; - - /* - Flush journal primitives referencing the current state. - * - Make sure the pipeline has no dependants so it may be modified. - * - If the pipeline isn't currently an authority for the state being - * changed, then initialize that state from the current authority. - */ - _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); - - pipeline->big_state->fog_state = *fog_state; - - _cogl_pipeline_update_authority (pipeline, authority, state, - _cogl_pipeline_fog_state_equal); -} - unsigned long _cogl_pipeline_get_age (CoglPipeline *pipeline) { @@ -4887,8 +3766,8 @@ _cogl_pipeline_layer_free (CoglPipelineLayer *layer) _cogl_pipeline_layer_unparent (COGL_PIPELINE_NODE (layer)); if (layer->differences & COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA && - layer->texture != COGL_INVALID_HANDLE) - cogl_handle_unref (layer->texture); + layer->texture != NULL) + cogl_object_unref (layer->texture); if (layer->differences & COGL_PIPELINE_LAYER_STATE_NEEDS_BIG_STATE) g_slice_free (CoglPipelineLayerBigState, layer->big_state); @@ -4942,7 +3821,7 @@ _cogl_pipeline_init_default_layers (void) layer->unit_index = 0; - layer->texture = COGL_INVALID_HANDLE; + layer->texture = NULL; layer->target = 0; layer->mag_filter = COGL_PIPELINE_FILTER_LINEAR; @@ -5209,7 +4088,7 @@ cogl_pipeline_set_layer_combine (CoglPipeline *pipeline, changed: - handle_automatic_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS); + _cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS); return TRUE; } @@ -5294,7 +4173,7 @@ cogl_pipeline_set_layer_combine_constant (CoglPipeline *pipeline, changed: - handle_automatic_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS); + _cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS); } void @@ -5460,7 +4339,7 @@ cogl_pipeline_remove_layer (CoglPipeline *pipeline, int layer_index) _cogl_pipeline_remove_layer_difference (pipeline, layer_info.layer, TRUE); _cogl_pipeline_try_reverting_layers_authority (pipeline, NULL); - handle_automatic_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS); + _cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS); } static gboolean @@ -5734,48 +4613,6 @@ cogl_pipeline_set_layer_filters (CoglPipeline *pipeline, } } -float -cogl_pipeline_get_point_size (CoglHandle handle) -{ - CoglPipeline *pipeline = COGL_PIPELINE (handle); - CoglPipeline *authority; - - g_return_val_if_fail (cogl_is_pipeline (handle), FALSE); - - authority = - _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_POINT_SIZE); - - return authority->big_state->point_size; -} - -void -cogl_pipeline_set_point_size (CoglHandle handle, - float point_size) -{ - CoglPipeline *pipeline = COGL_PIPELINE (handle); - CoglPipelineState state = COGL_PIPELINE_STATE_POINT_SIZE; - CoglPipeline *authority; - - g_return_if_fail (cogl_is_pipeline (handle)); - - authority = _cogl_pipeline_get_authority (pipeline, state); - - if (authority->big_state->point_size == point_size) - return; - - /* - Flush journal primitives referencing the current state. - * - Make sure the pipeline has no dependants so it may be modified. - * - If the pipeline isn't currently an authority for the state being - * changed, then initialize that state from the current authority. - */ - _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); - - pipeline->big_state->point_size = point_size; - - _cogl_pipeline_update_authority (pipeline, authority, state, - _cogl_pipeline_point_size_equal); -} - /* 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 */ @@ -5831,17 +4668,10 @@ _cogl_pipeline_set_static_breadcrumb (CoglPipeline *pipeline, pipeline->static_breadcrumb = breadcrumb; } -typedef struct _HashState -{ - unsigned long layer_differences; - CoglPipelineEvalFlags flags; - unsigned int hash; -} HashState; - static void _cogl_pipeline_layer_hash_unit_state (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, - HashState *state) + CoglPipelineHashState *state) { int unit = authority->unit_index; state->hash = @@ -5851,7 +4681,7 @@ _cogl_pipeline_layer_hash_unit_state (CoglPipelineLayer *authority, static void _cogl_pipeline_layer_hash_texture_target_state (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, - HashState *state) + CoglPipelineHashState *state) { GLenum gl_target = authority->target; @@ -5862,7 +4692,7 @@ _cogl_pipeline_layer_hash_texture_target_state (CoglPipelineLayer *authority, static void _cogl_pipeline_layer_hash_texture_data_state (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, - HashState *state) + CoglPipelineHashState *state) { GLuint gl_handle; @@ -5875,7 +4705,7 @@ _cogl_pipeline_layer_hash_texture_data_state (CoglPipelineLayer *authority, static void _cogl_pipeline_layer_hash_filters_state (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, - HashState *state) + CoglPipelineHashState *state) { unsigned int hash = state->hash; hash = _cogl_util_one_at_a_time_hash (hash, &authority->mag_filter, @@ -5888,7 +4718,7 @@ _cogl_pipeline_layer_hash_filters_state (CoglPipelineLayer *authority, static void _cogl_pipeline_layer_hash_wrap_modes_state (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, - HashState *state) + CoglPipelineHashState *state) { unsigned int hash = state->hash; hash = _cogl_util_one_at_a_time_hash (hash, &authority->wrap_mode_s, @@ -5903,7 +4733,7 @@ _cogl_pipeline_layer_hash_wrap_modes_state (CoglPipelineLayer *authority, static void _cogl_pipeline_layer_hash_combine_state (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, - HashState *state) + CoglPipelineHashState *state) { unsigned int hash = state->hash; CoglPipelineLayerBigState *b = authority->big_state; @@ -5942,7 +4772,7 @@ _cogl_pipeline_layer_hash_combine_state (CoglPipelineLayer *authority, static void _cogl_pipeline_layer_hash_combine_constant_state (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, - HashState *state) + CoglPipelineHashState *state) { CoglPipelineLayerBigState *b = authority->big_state; gboolean need_hash = FALSE; @@ -5992,7 +4822,7 @@ done: static void _cogl_pipeline_layer_hash_user_matrix_state (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, - HashState *state) + CoglPipelineHashState *state) { CoglPipelineLayerBigState *big_state = authority->big_state; state->hash = _cogl_util_one_at_a_time_hash (state->hash, &big_state->matrix, @@ -6002,7 +4832,7 @@ _cogl_pipeline_layer_hash_user_matrix_state (CoglPipelineLayer *authority, static void _cogl_pipeline_layer_hash_point_sprite_state (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, - HashState *state) + CoglPipelineHashState *state) { CoglPipelineLayerBigState *big_state = authority->big_state; state->hash = @@ -6012,7 +4842,7 @@ _cogl_pipeline_layer_hash_point_sprite_state (CoglPipelineLayer *authority, typedef void (*LayerStateHashFunction) (CoglPipelineLayer *authority, CoglPipelineLayer **authorities, - HashState *state); + CoglPipelineHashState *state); static LayerStateHashFunction layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT]; @@ -6052,7 +4882,7 @@ static gboolean _cogl_pipeline_hash_layer_cb (CoglPipelineLayer *layer, void *user_data) { - HashState *state = user_data; + CoglPipelineHashState *state = user_data; unsigned long differences = state->layer_differences; CoglPipelineLayer *authorities[COGL_PIPELINE_LAYER_STATE_COUNT]; unsigned long mask; @@ -6095,25 +4925,9 @@ _cogl_pipeline_hash_layer_cb (CoglPipelineLayer *layer, return TRUE; } -static void -_cogl_pipeline_hash_color_state (CoglPipeline *authority, - HashState *state) -{ - state->hash = _cogl_util_one_at_a_time_hash (state->hash, &authority->color, - _COGL_COLOR_DATA_SIZE); -} - -static void -_cogl_pipeline_hash_blend_enable_state (CoglPipeline *authority, - HashState *state) -{ - guint8 blend_enable = authority->blend_enable; - state->hash = _cogl_util_one_at_a_time_hash (state->hash, &blend_enable, 1); -} - -static void +void _cogl_pipeline_hash_layers_state (CoglPipeline *authority, - HashState *state) + CoglPipelineHashState *state) { state->hash = _cogl_util_one_at_a_time_hash (state->hash, &authority->n_layers, @@ -6123,162 +4937,7 @@ _cogl_pipeline_hash_layers_state (CoglPipeline *authority, state); } -static void -_cogl_pipeline_hash_lighting_state (CoglPipeline *authority, - HashState *state) -{ - CoglPipelineLightingState *lighting_state = - &authority->big_state->lighting_state; - state->hash = - _cogl_util_one_at_a_time_hash (state->hash, lighting_state, - sizeof (CoglPipelineLightingState)); -} - -static void -_cogl_pipeline_hash_alpha_func_state (CoglPipeline *authority, - HashState *state) -{ - CoglPipelineAlphaFuncState *alpha_state = &authority->big_state->alpha_state; - state->hash = - _cogl_util_one_at_a_time_hash (state->hash, &alpha_state->alpha_func, - sizeof (alpha_state->alpha_func)); -} - -static void -_cogl_pipeline_hash_alpha_func_reference_state (CoglPipeline *authority, - HashState *state) -{ - CoglPipelineAlphaFuncState *alpha_state = &authority->big_state->alpha_state; - float ref = alpha_state->alpha_func_reference; - state->hash = - _cogl_util_one_at_a_time_hash (state->hash, &ref, sizeof (float)); -} - -static void -_cogl_pipeline_hash_blend_state (CoglPipeline *authority, - HashState *state) -{ - CoglPipelineBlendState *blend_state = &authority->big_state->blend_state; - unsigned int hash; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - if (!authority->real_blend_enable) - return; - - hash = state->hash; - -#if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL) - if (ctx->driver != COGL_DRIVER_GLES1) - { - hash = - _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_equation_rgb, - sizeof (blend_state->blend_equation_rgb)); - hash = - _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_equation_alpha, - sizeof (blend_state->blend_equation_alpha)); - hash = - _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_src_factor_alpha, - sizeof (blend_state->blend_src_factor_alpha)); - hash = - _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_dst_factor_alpha, - sizeof (blend_state->blend_dst_factor_alpha)); - - if (blend_state->blend_src_factor_rgb == GL_ONE_MINUS_CONSTANT_COLOR || - blend_state->blend_src_factor_rgb == GL_CONSTANT_COLOR || - blend_state->blend_dst_factor_rgb == GL_ONE_MINUS_CONSTANT_COLOR || - blend_state->blend_dst_factor_rgb == GL_CONSTANT_COLOR) - { - hash = - _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_constant, - sizeof (blend_state->blend_constant)); - } - } -#endif - - hash = - _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_src_factor_rgb, - sizeof (blend_state->blend_src_factor_rgb)); - hash = - _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_dst_factor_rgb, - sizeof (blend_state->blend_dst_factor_rgb)); - - state->hash = hash; -} - -static void -_cogl_pipeline_hash_user_shader_state (CoglPipeline *authority, - HashState *state) -{ - CoglHandle user_program = authority->big_state->user_program; - state->hash = _cogl_util_one_at_a_time_hash (state->hash, &user_program, - sizeof (user_program)); -} - -static void -_cogl_pipeline_hash_depth_state (CoglPipeline *authority, - HashState *state) -{ - CoglDepthState *depth_state = &authority->big_state->depth_state; - unsigned int hash = state->hash; - - if (depth_state->test_enabled) - { - guint8 enabled = depth_state->test_enabled; - CoglDepthTestFunction function = depth_state->test_function; - hash = _cogl_util_one_at_a_time_hash (hash, &enabled, sizeof (enabled)); - hash = _cogl_util_one_at_a_time_hash (hash, &function, sizeof (function)); - } - - if (depth_state->write_enabled) - { - guint8 enabled = depth_state->write_enabled; - float near_val = depth_state->range_near; - float far_val = depth_state->range_far; - hash = _cogl_util_one_at_a_time_hash (hash, &enabled, sizeof (enabled)); - hash = _cogl_util_one_at_a_time_hash (hash, &near_val, sizeof (near_val)); - hash = _cogl_util_one_at_a_time_hash (hash, &far_val, sizeof (far_val)); - } - - state->hash = hash; -} - -static void -_cogl_pipeline_hash_fog_state (CoglPipeline *authority, - HashState *state) -{ - CoglPipelineFogState *fog_state = &authority->big_state->fog_state; - unsigned long hash = state->hash; - - if (!fog_state->enabled) - hash = _cogl_util_one_at_a_time_hash (hash, &fog_state->enabled, - sizeof (fog_state->enabled)); - else - hash = _cogl_util_one_at_a_time_hash (hash, &fog_state, - sizeof (CoglPipelineFogState)); - - state->hash = hash; -} - -static void -_cogl_pipeline_hash_point_size_state (CoglPipeline *authority, - HashState *state) -{ - float point_size = authority->big_state->point_size; - state->hash = _cogl_util_one_at_a_time_hash (state->hash, &point_size, - sizeof (point_size)); -} - -static void -_cogl_pipeline_hash_logic_ops_state (CoglPipeline *authority, - HashState *state) -{ - CoglPipelineLogicOpsState *logic_ops_state = &authority->big_state->logic_ops_state; - state->hash = _cogl_util_one_at_a_time_hash (state->hash, &logic_ops_state->color_mask, - sizeof (CoglColorMask)); -} - -typedef void (*StateHashFunction) (CoglPipeline *authority, HashState *state); +typedef void (*StateHashFunction) (CoglPipeline *authority, CoglPipelineHashState *state); static StateHashFunction state_hash_functions[COGL_PIPELINE_STATE_SPARSE_COUNT]; @@ -6327,7 +4986,7 @@ _cogl_pipeline_hash (CoglPipeline *pipeline, CoglPipeline *authorities[COGL_PIPELINE_STATE_SPARSE_COUNT]; unsigned long mask; int i; - HashState state; + CoglPipelineHashState state; unsigned int final_hash = 0; state.hash = 0; diff --git a/cogl/cogl-pipeline.h b/cogl/cogl-pipeline.h index 15b100cd3..0bcbb35f1 100644 --- a/cogl/cogl-pipeline.h +++ b/cogl/cogl-pipeline.h @@ -172,562 +172,6 @@ cogl_pipeline_copy (CoglPipeline *source); gboolean cogl_is_pipeline (CoglHandle handle); -/** - * cogl_pipeline_set_color: - * @pipeline: A #CoglPipeline object - * @color: The components of the color - * - * Sets the basic color of the pipeline, used when no lighting is enabled. - * - * Note that if you don't add any layers to the pipeline then the color - * will be blended unmodified with the destination; the default blend - * expects premultiplied colors: for example, use (0.5, 0.0, 0.0, 0.5) for - * semi-transparent red. See cogl_color_premultiply(). - * - * The default value is (1.0, 1.0, 1.0, 1.0) - * - * Since: 2.0 - */ -void -cogl_pipeline_set_color (CoglPipeline *pipeline, - const CoglColor *color); - -/** - * cogl_pipeline_set_color4ub: - * @pipeline: A #CoglPipeline object - * @red: The red component - * @green: The green component - * @blue: The blue component - * @alpha: The alpha component - * - * Sets the basic color of the pipeline, used when no lighting is enabled. - * - * The default value is (0xff, 0xff, 0xff, 0xff) - * - * Since: 2.0 - */ -void -cogl_pipeline_set_color4ub (CoglPipeline *pipeline, - guint8 red, - guint8 green, - guint8 blue, - guint8 alpha); - -/** - * cogl_pipeline_set_color4f: - * @pipeline: A #CoglPipeline object - * @red: The red component - * @green: The green component - * @blue: The blue component - * @alpha: The alpha component - * - * Sets the basic color of the pipeline, used when no lighting is enabled. - * - * The default value is (1.0, 1.0, 1.0, 1.0) - * - * Since: 2.0 - */ -void -cogl_pipeline_set_color4f (CoglPipeline *pipeline, - float red, - float green, - float blue, - float alpha); - -/** - * cogl_pipeline_get_color: - * @pipeline: A #CoglPipeline object - * @color: (out): The location to store the color - * - * Retrieves the current pipeline color. - * - * Since: 2.0 - */ -void -cogl_pipeline_get_color (CoglPipeline *pipeline, - CoglColor *color); - -/** - * cogl_pipeline_set_ambient: - * @pipeline: A #CoglPipeline object - * @ambient: The components of the desired ambient color - * - * Sets the pipeline's ambient color, in the standard OpenGL lighting - * model. The ambient color affects the overall color of the object. - * - * Since the diffuse color will be intense when the light hits the surface - * directly, the ambient will be most apparent where the light hits at a - * slant. - * - * The default value is (0.2, 0.2, 0.2, 1.0) - * - * Since: 2.0 - */ -void -cogl_pipeline_set_ambient (CoglPipeline *pipeline, - const CoglColor *ambient); - -/** - * cogl_pipeline_get_ambient: - * @pipeline: A #CoglPipeline object - * @ambient: The location to store the ambient color - * - * Retrieves the current ambient color for @pipeline - * - * Since: 2.0 - */ -void -cogl_pipeline_get_ambient (CoglPipeline *pipeline, - CoglColor *ambient); - -/** - * cogl_pipeline_set_diffuse: - * @pipeline: A #CoglPipeline object - * @diffuse: The components of the desired diffuse color - * - * Sets the pipeline's diffuse color, in the standard OpenGL lighting - * model. The diffuse color is most intense where the light hits the - * surface directly - perpendicular to the surface. - * - * The default value is (0.8, 0.8, 0.8, 1.0) - * - * Since: 2.0 - */ -void -cogl_pipeline_set_diffuse (CoglPipeline *pipeline, - const CoglColor *diffuse); - -/** - * cogl_pipeline_get_diffuse: - * @pipeline: A #CoglPipeline object - * @diffuse: The location to store the diffuse color - * - * Retrieves the current diffuse color for @pipeline - * - * Since: 2.0 - */ -void -cogl_pipeline_get_diffuse (CoglPipeline *pipeline, - CoglColor *diffuse); - -/** - * cogl_pipeline_set_ambient_and_diffuse: - * @pipeline: A #CoglPipeline object - * @color: The components of the desired ambient and diffuse colors - * - * Conveniently sets the diffuse and ambient color of @pipeline at the same - * time. See cogl_pipeline_set_ambient() and cogl_pipeline_set_diffuse(). - * - * The default ambient color is (0.2, 0.2, 0.2, 1.0) - * - * The default diffuse color is (0.8, 0.8, 0.8, 1.0) - * - * Since: 2.0 - */ -void -cogl_pipeline_set_ambient_and_diffuse (CoglPipeline *pipeline, - const CoglColor *color); - -/** - * cogl_pipeline_set_specular: - * @pipeline: A #CoglPipeline object - * @specular: The components of the desired specular color - * - * Sets the pipeline's specular color, in the standard OpenGL lighting - * model. The intensity of the specular color depends on the viewport - * position, and is brightest along the lines of reflection. - * - * The default value is (0.0, 0.0, 0.0, 1.0) - * - * Since: 2.0 - */ -void -cogl_pipeline_set_specular (CoglPipeline *pipeline, - const CoglColor *specular); - -/** - * cogl_pipeline_get_specular: - * @pipeline: A #CoglPipeline object - * @specular: The location to store the specular color - * - * Retrieves the pipelines current specular color. - * - * Since: 2.0 - */ -void -cogl_pipeline_get_specular (CoglPipeline *pipeline, - CoglColor *specular); - -/** - * cogl_pipeline_set_shininess: - * @pipeline: A #CoglPipeline object - * @shininess: The desired shininess; must be >= 0.0 - * - * Sets the shininess of the pipeline, in the standard OpenGL lighting - * model, which determines the size of the specular highlights. A - * higher @shininess will produce smaller highlights which makes the - * object appear more shiny. - * - * The default value is 0.0 - * - * Since: 2.0 - */ -void -cogl_pipeline_set_shininess (CoglPipeline *pipeline, - float shininess); - -/** - * cogl_pipeline_get_shininess: - * @pipeline: A #CoglPipeline object - * - * Retrieves the pipelines current emission color. - * - * Return value: The pipelines current shininess value - * - * Since: 2.0 - */ -float -cogl_pipeline_get_shininess (CoglPipeline *pipeline); - -/** - * cogl_pipeline_set_emission: - * @pipeline: A #CoglPipeline object - * @emission: The components of the desired emissive color - * - * Sets the pipeline's emissive color, in the standard OpenGL lighting - * model. It will look like the surface is a light source emitting this - * color. - * - * The default value is (0.0, 0.0, 0.0, 1.0) - * - * Since: 2.0 - */ -void -cogl_pipeline_set_emission (CoglPipeline *pipeline, - const CoglColor *emission); - -/** - * cogl_pipeline_get_emission: - * @pipeline: A #CoglPipeline object - * @emission: The location to store the emission color - * - * Retrieves the pipelines current emission color. - * - * Since: 2.0 - */ -void -cogl_pipeline_get_emission (CoglPipeline *pipeline, - CoglColor *emission); - -/** - * CoglPipelineAlphaFunc: - * @COGL_PIPELINE_ALPHA_FUNC_NEVER: Never let the fragment through. - * @COGL_PIPELINE_ALPHA_FUNC_LESS: Let the fragment through if the incoming - * alpha value is less than the reference alpha value - * @COGL_PIPELINE_ALPHA_FUNC_EQUAL: Let the fragment through if the incoming - * alpha value equals the reference alpha value - * @COGL_PIPELINE_ALPHA_FUNC_LEQUAL: Let the fragment through if the incoming - * alpha value is less than or equal to the reference alpha value - * @COGL_PIPELINE_ALPHA_FUNC_GREATER: Let the fragment through if the incoming - * alpha value is greater than the reference alpha value - * @COGL_PIPELINE_ALPHA_FUNC_NOTEQUAL: Let the fragment through if the incoming - * alpha value does not equal the reference alpha value - * @COGL_PIPELINE_ALPHA_FUNC_GEQUAL: Let the fragment through if the incoming - * alpha value is greater than or equal to the reference alpha value. - * @COGL_PIPELINE_ALPHA_FUNC_ALWAYS: Always let the fragment through. - * - * Alpha testing happens before blending primitives with the framebuffer and - * gives an opportunity to discard fragments based on a comparison with the - * incoming alpha value and a reference alpha value. The #CoglPipelineAlphaFunc - * determines how the comparison is done. - */ -typedef enum { - COGL_PIPELINE_ALPHA_FUNC_NEVER = 0x0200, - COGL_PIPELINE_ALPHA_FUNC_LESS = 0x0201, - COGL_PIPELINE_ALPHA_FUNC_EQUAL = 0x0202, - COGL_PIPELINE_ALPHA_FUNC_LEQUAL = 0x0203, - COGL_PIPELINE_ALPHA_FUNC_GREATER = 0x0204, - COGL_PIPELINE_ALPHA_FUNC_NOTEQUAL = 0x0205, - COGL_PIPELINE_ALPHA_FUNC_GEQUAL = 0x0206, - COGL_PIPELINE_ALPHA_FUNC_ALWAYS = 0x0207 -} CoglPipelineAlphaFunc; -/* NB: these values come from the equivalents in gl.h */ - -/** - * cogl_pipeline_set_alpha_test_function: - * @pipeline: A #CoglPipeline object - * @alpha_func: A @CoglPipelineAlphaFunc constant - * @alpha_reference: A reference point that the chosen alpha function uses - * to compare incoming fragments to. - * - * Before a primitive is blended with the framebuffer, it goes through an - * alpha test stage which lets you discard fragments based on the current - * alpha value. This function lets you change the function used to evaluate - * the alpha channel, and thus determine which fragments are discarded - * and which continue on to the blending stage. - * - * The default is %COGL_PIPELINE_ALPHA_FUNC_ALWAYS - * - * Since: 2.0 - */ -void -cogl_pipeline_set_alpha_test_function (CoglPipeline *pipeline, - CoglPipelineAlphaFunc alpha_func, - float alpha_reference); - -/** - * cogl_pipeline_get_alpha_test_function: - * @pipeline: A #CoglPipeline object - * - * Return value: The alpha test function of @pipeline. - * - * Since: 2.0 - */ -CoglPipelineAlphaFunc -cogl_pipeline_get_alpha_test_function (CoglPipeline *pipeline); - -/** - * cogl_pipeline_get_alpha_test_reference: - * @pipeline: A #CoglPipeline object - * - * Return value: The alpha test reference value of @pipeline. - * - * Since: 2.0 - */ -float -cogl_pipeline_get_alpha_test_reference (CoglPipeline *pipeline); - -/** - * cogl_pipeline_set_blend: - * @pipeline: A #CoglPipeline object - * @blend_string: A <link linkend="cogl-Blend-Strings">Cogl blend string</link> - * describing the desired blend function. - * @error: return location for a #GError that may report lack of driver - * support if you give separate blend string statements for the alpha - * channel and RGB channels since some drivers, or backends such as - * GLES 1.1, don't support this feature. May be %NULL, in which case a - * warning will be printed out using GLib's logging facilities if an - * error is encountered. - * - * If not already familiar; please refer <link linkend="cogl-Blend-Strings">here</link> - * for an overview of what blend strings are, and their syntax. - * - * Blending occurs after the alpha test function, and combines fragments with - * the framebuffer. - - * Currently the only blend function Cogl exposes is ADD(). So any valid - * blend statements will be of the form: - * - * |[ - * <channel-mask>=ADD(SRC_COLOR*(<factor>), DST_COLOR*(<factor>)) - * ]| - * - * This is the list of source-names usable as blend factors: - * <itemizedlist> - * <listitem><para>SRC_COLOR: The color of the in comming fragment</para></listitem> - * <listitem><para>DST_COLOR: The color of the framebuffer</para></listitem> - * <listitem><para>CONSTANT: The constant set via cogl_pipeline_set_blend_constant()</para></listitem> - * </itemizedlist> - * - * The source names can be used according to the - * <link linkend="cogl-Blend-String-syntax">color-source and factor syntax</link>, - * so for example "(1-SRC_COLOR[A])" would be a valid factor, as would - * "(CONSTANT[RGB])" - * - * These can also be used as factors: - * <itemizedlist> - * <listitem>0: (0, 0, 0, 0)</listitem> - * <listitem>1: (1, 1, 1, 1)</listitem> - * <listitem>SRC_ALPHA_SATURATE_FACTOR: (f,f,f,1) where f = MIN(SRC_COLOR[A],1-DST_COLOR[A])</listitem> - * </itemizedlist> - * - * <note>Remember; all color components are normalized to the range [0, 1] - * before computing the result of blending.</note> - * - * <example id="cogl-Blend-Strings-blend-unpremul"> - * <title>Blend Strings/1</title> - * <para>Blend a non-premultiplied source over a destination with - * premultiplied alpha:</para> - * <programlisting> - * "RGB = ADD(SRC_COLOR*(SRC_COLOR[A]), DST_COLOR*(1-SRC_COLOR[A]))" - * "A = ADD(SRC_COLOR, DST_COLOR*(1-SRC_COLOR[A]))" - * </programlisting> - * </example> - * - * <example id="cogl-Blend-Strings-blend-premul"> - * <title>Blend Strings/2</title> - * <para>Blend a premultiplied source over a destination with - * premultiplied alpha</para> - * <programlisting> - * "RGBA = ADD(SRC_COLOR, DST_COLOR*(1-SRC_COLOR[A]))" - * </programlisting> - * </example> - * - * The default blend string is: - * |[ - * RGBA = ADD (SRC_COLOR, DST_COLOR*(1-SRC_COLOR[A])) - * ]| - * - * That gives normal alpha-blending when the calculated color for the pipeline - * is in premultiplied form. - * - * Return value: %TRUE if the blend string was successfully parsed, and the - * described blending is supported by the underlying driver/hardware. If - * there was an error, %FALSE is returned and @error is set accordingly (if - * present). - * - * Since: 2.0 - */ -gboolean -cogl_pipeline_set_blend (CoglPipeline *pipeline, - const char *blend_string, - GError **error); - -/** - * cogl_pipeline_set_blend_constant: - * @pipeline: A #CoglPipeline object - * @constant_color: The constant color you want - * - * When blending is setup to reference a CONSTANT blend factor then - * blending will depend on the constant set with this function. - * - * Since: 2.0 - */ -void -cogl_pipeline_set_blend_constant (CoglPipeline *pipeline, - const CoglColor *constant_color); - -/** - * cogl_pipeline_set_point_size: - * @pipeline: a #CoglHandle to a pipeline. - * @point_size: the new point size. - * - * Changes the size of points drawn when %COGL_VERTICES_MODE_POINTS is - * used with the vertex buffer API. Note that typically the GPU will - * only support a limited minimum and maximum range of point sizes. If - * the chosen point size is outside that range then the nearest value - * within that range will be used instead. The size of a point is in - * screen space so it will be the same regardless of any - * transformations. The default point size is 1.0. - * - * Since: 2.0 - */ -void -cogl_pipeline_set_point_size (CoglHandle pipeline, - float point_size); - -/** - * cogl_pipeline_get_point_size: - * @pipeline: a #CoglHandle to a pipeline. - * - * Get the size of points drawn when %COGL_VERTICES_MODE_POINTS is - * used with the vertex buffer API. - * - * Return value: the point size of the pipeline. - * - * Since: 2.0 - */ -float -cogl_pipeline_get_point_size (CoglHandle pipeline); - -#define cogl_pipeline_get_color_mask cogl_pipeline_get_color_mask_EXP -/** - * cogl_pipeline_get_color_mask: - * @pipeline: a #CoglPipeline object. - * - * Gets the current #CoglColorMask of which channels would be written to the - * current framebuffer. Each bit set in the mask means that the - * corresponding color would be written. - * - * Returns: A #CoglColorMask - * Since: 1.8 - * Stability: unstable - */ -CoglColorMask -cogl_pipeline_get_color_mask (CoglPipeline *pipeline); - -#define cogl_pipeline_set_color_mask cogl_pipeline_set_color_mask_EXP -/** - * cogl_pipeline_set_color_mask: - * @pipeline: a #CoglPipeline object. - * @color_mask: A #CoglColorMask of which color channels to write to - * the current framebuffer. - * - * Defines a bit mask of which color channels should be written to the - * current framebuffer. If a bit is set in @color_mask that means that - * color will be written. - * - * Since: 1.8 - * Stability: unstable - */ -void -cogl_pipeline_set_color_mask (CoglPipeline *pipeline, - CoglColorMask color_mask); - -/** - * cogl_pipeline_get_user_program: - * @pipeline: a #CoglPipeline object. - * - * Queries what user program has been associated with the given - * @pipeline using cogl_pipeline_set_user_program(). - * - * Return value: The current user program or %COGL_INVALID_HANDLE. - * - * Since: 2.0 - */ -CoglHandle -cogl_pipeline_get_user_program (CoglPipeline *pipeline); - -/** - * cogl_pipeline_set_user_program: - * @pipeline: a #CoglPipeline object. - * @program: A #CoglHandle to a linked CoglProgram - * - * Associates a linked CoglProgram with the given pipeline so that the - * program can take full control of vertex and/or fragment processing. - * - * This is an example of how it can be used to associate an ARBfp - * program with a #CoglPipeline: - * |[ - * CoglHandle shader; - * CoglHandle program; - * CoglPipeline *pipeline; - * - * shader = cogl_create_shader (COGL_SHADER_TYPE_FRAGMENT); - * cogl_shader_source (shader, - * "!!ARBfp1.0\n" - * "MOV result.color,fragment.color;\n" - * "END\n"); - * cogl_shader_compile (shader); - * - * program = cogl_create_program (); - * cogl_program_attach_shader (program, shader); - * cogl_program_link (program); - * - * pipeline = cogl_pipeline_new (); - * cogl_pipeline_set_user_program (pipeline, program); - * - * cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff); - * cogl_rectangle (0, 0, 100, 100); - * ]| - * - * It is possibly worth keeping in mind that this API is not part of - * the long term design for how we want to expose shaders to Cogl - * developers (We are planning on deprecating the cogl_program and - * cogl_shader APIs in favour of a "snippet" framework) but in the - * meantime we hope this will handle most practical GLSL and ARBfp - * requirements. - * - * Also remember you need to check for either the - * %COGL_FEATURE_SHADERS_GLSL or %COGL_FEATURE_SHADERS_ARBFP before - * using the cogl_program or cogl_shader API. - * - * Since: 2.0 - */ -void -cogl_pipeline_set_user_program (CoglPipeline *pipeline, - CoglHandle program); - /** * cogl_pipeline_set_layer: * @pipeline: A #CoglPipeline object @@ -1084,46 +528,6 @@ cogl_pipeline_set_layer_wrap_mode (CoglPipeline *pipeline, #ifdef COGL_ENABLE_EXPERIMENTAL_API -/** - * cogl_pipeline_set_depth_state: - * @pipeline: A #CoglPipeline object - * @state: A #CoglDepthState struct - * @error: A #GError to report failures to setup the given @state. - * - * This commits all the depth state configured in @state struct to the - * given @pipeline. The configuration values are copied into the - * pipeline so there is no requirement to keep the #CoglDepthState - * struct around if you don't need it any more. - * - * Note: Since some platforms do not support the depth range feature - * it is possible for this function to fail and report an @error. - * - * Returns: TRUE if the GPU supports all the given @state else %FALSE - * and returns an @error. - * - * Since: 2.0 - * Stability: Unstable - */ -gboolean -cogl_pipeline_set_depth_state (CoglPipeline *pipeline, - const CoglDepthState *state, - GError **error); - -/** - * cogl_pipeline_get_depth_state - * @pipeline: A #CoglPipeline object - * @state: A destination #CoglDepthState struct - * - * Retrieves the current depth state configuration for the given - * @pipeline as previously set using cogl_pipeline_set_depth_state(). - * - * Since: 2.0 - * Stability: Unstable - */ -void -cogl_pipeline_get_depth_state (CoglPipeline *pipeline, - CoglDepthState *state_out); - /** * CoglPipelineLayerCallback: * @pipeline: The #CoglPipeline whos layers are being iterated diff --git a/cogl/cogl.h b/cogl/cogl.h index ff7f8f46b..6d433c293 100644 --- a/cogl/cogl.h +++ b/cogl/cogl.h @@ -88,6 +88,7 @@ typedef struct _CoglFramebuffer CoglFramebuffer; #include <cogl/cogl-primitive.h> #include <cogl/cogl-depth-state.h> #include <cogl/cogl-pipeline.h> +#include <cogl/cogl-pipeline-state.h> #include <cogl/cogl-framebuffer.h> #ifdef COGL_HAS_XLIB #include <cogl/cogl-xlib.h> diff --git a/doc/reference/cogl-2.0-experimental/Makefile.am b/doc/reference/cogl-2.0-experimental/Makefile.am index 051714935..b2b9b2f4e 100644 --- a/doc/reference/cogl-2.0-experimental/Makefile.am +++ b/doc/reference/cogl-2.0-experimental/Makefile.am @@ -74,6 +74,7 @@ IGNORE_HFILES=\ cogl-pipeline-fragend-glsl-private.h \ cogl-pipeline-opengl-private.h \ cogl-pipeline-private.h \ + cogl-pipeline-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 ef416e496..e4cd24b99 100644 --- a/doc/reference/cogl/Makefile.am +++ b/doc/reference/cogl/Makefile.am @@ -72,6 +72,7 @@ IGNORE_HFILES=\ cogl-pipeline-fragend-glsl-private.h \ cogl-pipeline-opengl-private.h \ cogl-pipeline-private.h \ + cogl-pipeline-state-private.h \ cogl-pipeline-progend-glsl-private.h \ cogl-pipeline-vertend-fixed-private.h \ cogl-pipeline-vertend-glsl-private.h \