diff --git a/cogl/cogl-pipeline-fragend-glsl.c b/cogl/cogl-pipeline-fragend-glsl.c index aa8a8d916..8bbd9fa4a 100644 --- a/cogl/cogl-pipeline-fragend-glsl.c +++ b/cogl/cogl-pipeline-fragend-glsl.c @@ -957,8 +957,11 @@ _cogl_pipeline_fragend_glsl_end (CoglPipeline *pipeline, if ((source = cogl_snippet_get_pre (snippet->snippet))) g_string_append (shader_state->source, source); - /* Chain on to the next function */ - if (snippet_num > 0) + /* Chain on to the next function, or bypass it if there is + a replace string */ + if ((source = cogl_snippet_get_replace (snippet->snippet))) + g_string_append (shader_state->source, source); + else if (snippet_num > 0) g_string_append_printf (shader_state->source, " cogl_snippet%i ();\n", snippet_num - 1); diff --git a/cogl/cogl-pipeline-state.h b/cogl/cogl-pipeline-state.h index d2c0ada89..027287628 100644 --- a/cogl/cogl-pipeline-state.h +++ b/cogl/cogl-pipeline-state.h @@ -954,6 +954,11 @@ cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, * The ‘pre’ string in @snippet will be inserted at the top of the * main() function before any vertex processing is done. * + * The ‘replace’ string in @snippet will be used instead of the + * generated vertex processing if it is present. This can be used if + * the application wants to provide a complete vertex shader and + * doesn't need the generated output from Cogl. + * * The ‘post’ string in @snippet will be inserted after all of the * standard vertex processing is done. This can be used to modify the * outputs. @@ -982,6 +987,11 @@ cogl_pipeline_add_vertex_hook (CoglPipeline *pipeline, * The ‘pre’ string in @snippet will be inserted at the top of the * main() function before any fragment processing is done. * + * The ‘replace’ string in @snippet will be used instead of the + * generated fragment processing if it is present. This can be used if + * the application wants to provide a complete fragment shader and + * doesn't need the generated output from Cogl. + * * The ‘post’ string in @snippet will be inserted after all of the * standard fragment processing is done. At this point the generated * value for the rest of the pipeline state will already be in diff --git a/cogl/cogl-pipeline-vertend-glsl.c b/cogl/cogl-pipeline-vertend-glsl.c index 680375856..16637ec58 100644 --- a/cogl/cogl-pipeline-vertend-glsl.c +++ b/cogl/cogl-pipeline-vertend-glsl.c @@ -397,8 +397,11 @@ _cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline, if ((source = cogl_snippet_get_pre (snippet->snippet))) g_string_append (shader_state->source, source); - /* Chain on to the next function */ - if (snippet_num > 0) + /* Chain on to the next function, or bypass it if there is + a replace string */ + if ((source = cogl_snippet_get_replace (snippet->snippet))) + g_string_append (shader_state->source, source); + else if (snippet_num > 0) g_string_append_printf (shader_state->source, " cogl_snippet%i ();\n", snippet_num - 1); diff --git a/cogl/cogl-snippet-private.h b/cogl/cogl-snippet-private.h index b7ee4a838..bcc6abe0a 100644 --- a/cogl/cogl-snippet-private.h +++ b/cogl/cogl-snippet-private.h @@ -44,6 +44,7 @@ struct _CoglSnippet char *declarations; char *pre; + char *replace; char *post; }; diff --git a/cogl/cogl-snippet.c b/cogl/cogl-snippet.c index 08b19a88d..d3a066f15 100644 --- a/cogl/cogl-snippet.c +++ b/cogl/cogl-snippet.c @@ -108,6 +108,27 @@ cogl_snippet_get_pre (CoglSnippet *snippet) return snippet->pre; } +void +cogl_snippet_set_replace (CoglSnippet *snippet, + const char *replace) +{ + _COGL_RETURN_IF_FAIL (cogl_is_snippet (snippet)); + + if (!_cogl_snippet_modify (snippet)) + return; + + g_free (snippet->replace); + snippet->replace = replace ? g_strdup (replace) : NULL; +} + +const char * +cogl_snippet_get_replace (CoglSnippet *snippet) +{ + _COGL_RETURN_VAL_IF_FAIL (cogl_is_snippet (snippet), NULL); + + return snippet->replace; +} + void cogl_snippet_set_post (CoglSnippet *snippet, const char *post) @@ -140,6 +161,7 @@ _cogl_snippet_free (CoglSnippet *snippet) { g_free (snippet->declarations); g_free (snippet->pre); + g_free (snippet->replace); g_free (snippet->post); g_slice_free (CoglSnippet, snippet); } diff --git a/cogl/cogl-snippet.h b/cogl/cogl-snippet.h index 7afa18a20..260aed916 100644 --- a/cogl/cogl-snippet.h +++ b/cogl/cogl-snippet.h @@ -154,6 +154,42 @@ cogl_snippet_set_pre (CoglSnippet *snippet, const char * cogl_snippet_get_pre (CoglSnippet *snippet); +#define cogl_snippet_set_replace cogl_snippet_set_replace_EXP +/** + * cogl_snippet_set_replace: + * @snippet: A #CoglSnippet + * @replace: The new source string for the replace section of this snippet. + * + * Sets a source string that will be used instead of any generated + * source code or any previous snippets for this hook point. Please + * see the documentation of each hook point in #CoglPipeline for a + * description of how this string should be used. + * + * This function should only be called before the snippet is attached + * to its first pipeline. After that the snippet should be considered + * immutable. + * + * Since: 1.10 + * Stability: Unstable + */ +void +cogl_snippet_set_replace (CoglSnippet *snippet, + const char *replace); + +#define cogl_snippet_get_replace cogl_snippet_get_replace_EXP +/** + * cogl_snippet_get_replace: + * @snippet: A #CoglSnippet + * + * Return value: the source string that was set with + * cogl_snippet_set_replace() or %NULL if none was set. + * + * Since: 1.10 + * Stability: Unstable + */ +const char * +cogl_snippet_get_replace (CoglSnippet *snippet); + #define cogl_snippet_set_post cogl_snippet_set_post_EXP /** * cogl_snippet_set_post: diff --git a/tests/conform/test-snippets.c b/tests/conform/test-snippets.c index 6a5bf60b4..f3e9ae118 100644 --- a/tests/conform/test-snippets.c +++ b/tests/conform/test-snippets.c @@ -150,25 +150,55 @@ paint (TestState *state) cogl_object_unref (snippet); + /* Check the replace string */ + snippet = cogl_snippet_new (NULL, NULL); + cogl_snippet_set_pre (snippet, + "cogl_color_out = vec4 (0.0, 0.5, 0.0, 1.0);"); + /* Remove the generated output. If the replace string isn't working + then the code from the pre string would get overwritten with + white */ + cogl_snippet_set_replace (snippet, "/* do nothing */"); + cogl_snippet_set_post (snippet, + "cogl_color_out += vec4 (0.5, 0.0, 0.0, 1.0);"); + + pipeline = cogl_pipeline_new (); + cogl_pipeline_add_fragment_hook (pipeline, snippet); + cogl_push_source (pipeline); + cogl_rectangle (70, 0, 80, 10); + cogl_pop_source (); + cogl_object_unref (pipeline); + + cogl_object_unref (snippet); + /* Sanity check modifying the snippet */ snippet = cogl_snippet_new ("foo", "bar"); g_assert_cmpstr (cogl_snippet_get_declarations (snippet), ==, "foo"); g_assert_cmpstr (cogl_snippet_get_post (snippet), ==, "bar"); + g_assert_cmpstr (cogl_snippet_get_replace (snippet), ==, NULL); g_assert_cmpstr (cogl_snippet_get_pre (snippet), ==, NULL); cogl_snippet_set_declarations (snippet, "fu"); g_assert_cmpstr (cogl_snippet_get_declarations (snippet), ==, "fu"); g_assert_cmpstr (cogl_snippet_get_post (snippet), ==, "bar"); + g_assert_cmpstr (cogl_snippet_get_replace (snippet), ==, NULL); g_assert_cmpstr (cogl_snippet_get_pre (snippet), ==, NULL); cogl_snippet_set_post (snippet, "ba"); g_assert_cmpstr (cogl_snippet_get_declarations (snippet), ==, "fu"); g_assert_cmpstr (cogl_snippet_get_post (snippet), ==, "ba"); + g_assert_cmpstr (cogl_snippet_get_replace (snippet), ==, NULL); g_assert_cmpstr (cogl_snippet_get_pre (snippet), ==, NULL); cogl_snippet_set_pre (snippet, "fuba"); g_assert_cmpstr (cogl_snippet_get_declarations (snippet), ==, "fu"); g_assert_cmpstr (cogl_snippet_get_post (snippet), ==, "ba"); + g_assert_cmpstr (cogl_snippet_get_replace (snippet), ==, NULL); + g_assert_cmpstr (cogl_snippet_get_pre (snippet), ==, "fuba"); + + cogl_snippet_set_replace (snippet, "baba"); + g_assert_cmpstr (cogl_snippet_get_declarations (snippet), ==, "fu"); + g_assert_cmpstr (cogl_snippet_get_post (snippet), ==, "ba"); + g_assert_cmpstr (cogl_snippet_get_replace (snippet), ==, "baba"); g_assert_cmpstr (cogl_snippet_get_pre (snippet), ==, "fuba"); } @@ -182,6 +212,7 @@ validate_result (void) test_utils_check_pixel (45, 5, 0xff0000ff); test_utils_check_pixel (55, 5, 0x00ff00ff); test_utils_check_pixel (65, 5, 0x00ff00ff); + test_utils_check_pixel (75, 5, 0x808000ff); } void