Example of using the shader-chaining interface to create a custom strok shader that applies an animated wave effect entirely within the shader.
{
public:
virtual
void
{
float sum(0.0f);
for (int i = 0; i < 4; ++i)
{
}
}
virtual
unsigned int
{
return 3 + m_stroke_params.data_size();
}
float m_domain_coeff, m_phase;
};
call_ctor(bool uses_discard,
unsigned int num_subshaders)
{
vert_src,
frag_src,
deps,
num_subshaders);
}
call_ctor(bool,
unsigned int num_subshaders)
{
frag_src,
deps,
num_subshaders);
}
bool
bool apply_wavy_effect)
{
}
bool
bool)
{
return false;
}
template<typename T>
bool add_wavy_effect)
{
typename T::DependencyList deps;
deps.
add_shader(
"stroke_shader", stroking_shader);
const char *custom_vert_shader =
"void\n"
"fastuidraw_gl_vert_main(in uint sub_shader,\n"
" in uvec4 in_attrib0,\n"
" in uvec4 in_attrib1,\n"
" in uvec4 in_attrib2,\n"
" inout uint shader_data_block,\n"
" #ifdef FASTUIDRAW_RENDER_TO_COLOR_BUFFER\n"
" out int z_add,\n"
" out vec2 out_brush_p,\n"
" #endif\n"
" out vec3 out_clip_p)\n"
"{\n"
" shader_data_block += 3u;\n"
" stroke_shader(sub_shader, in_attrib0, in_attrib1, in_attrib2,\n"
" shader_data_block,\n"
" #ifdef FASTUIDRAW_RENDER_TO_COLOR_BUFFER\n"
" z_add, out_brush_p,\n"
" #endif\n"
" out_clip_p);\n"
"}\n";
const char *custom_wavy_frag_shader =
"#ifdef FASTUIDRAW_RENDER_TO_COLOR_BUFFER\n"
"#define return_type vec4\n"
"#else\n"
"#define return_type float\n"
"#endif\n"
"return_type\n"
"fastuidraw_gl_frag_main(in uint sub_shader,\n"
" inout uint shader_data_block)\n"
"{\n"
" vec4 cos_coeffs, sin_coeffs;\n"
" uvec4 tmp;\n"
" float coeff, inverse_sum, phase, width;\n"
" return_type return_value;\n"
" cos_coeffs = uintBitsToFloat(fastuidraw_fetch_data(shader_data_block));\n"
" sin_coeffs = uintBitsToFloat(fastuidraw_fetch_data(shader_data_block + 1u));\n"
" tmp = fastuidraw_fetch_data(shader_data_block + 2u);\n"
" coeff = uintBitsToFloat(tmp.x);\n"
" inverse_sum = uintBitsToFloat(tmp.y);\n"
" phase = uintBitsToFloat(tmp.z);\n"
" width = uintBitsToFloat(tmp.w);\n"
" shader_data_block += 3u;\n"
"\n"
" return_value = stroke_shader(sub_shader, shader_data_block);\n"
" float a, r;\n"
" vec4 cos_tuple, sin_tuple;\n"
" r = coeff * stroke_shader::fastuidraw_stroking_distance + phase;\n"
" cos_tuple = vec4(cos(r), cos(2.0 * r), cos(3.0 * r), cos(4.0 * r));\n"
" sin_tuple = vec4(sin(r), sin(2.0 * r), sin(3.0 * r), sin(4.0 * r));\n"
" a = inverse_sum * (dot(cos_coeffs, cos_tuple) + dot(sin_coeffs, sin_tuple));\n"
" a = abs(a);\n"
"#ifdef FASTUIDRAW_RENDER_TO_COLOR_BUFFER\n"
" if (a < stroke_shader::fastuidraw_stroking_relative_distance_from_center)\n"
" FASTUIDRAW_DISCARD;\n"
"#else\n"
" float q, dd;\n"
" q = max(a - stroke_shader::fastuidraw_stroking_relative_distance_from_center, 0.0);\n"
" dd = max(q, stroke_shader::fastuidraw_stroking_relative_distance_from_center_fwidth);\n"
" return_value *= q / dd;\n"
"#endif\n"
" return return_value;\n"
"}\n"
"#undef return_type\n";
const char *custom_pass_through_frag_shader =
"#ifdef FASTUIDRAW_RENDER_TO_COLOR_BUFFER\n"
"vec4\n"
"#else\n"
"float\n"
"#endif\n"
"fastuidraw_gl_frag_main(in uint sub_shader,\n"
" inout uint shader_data_block)\n"
"{\n"
" shader_data_block += 3u;"
" return stroke_shader(sub_shader, shader_data_block);\n"
"}\n";
const char *custom_frag_shader;
custom_frag_shader = (add_wavy_effect) ?
custom_wavy_frag_shader:
custom_pass_through_frag_shader;
return call_ctor(uses_discard(stroking_shader, add_wavy_effect),
ShaderSource().add_source(custom_vert_shader, ShaderSource::from_string),
ShaderSource().add_source(custom_frag_shader, ShaderSource::from_string),
deps,
stroking_shader->number_sub_shaders());
}
template<typename T>
{
public:
typedef std::map<shader_ref, shader_ref> shader_map;
shader_ref
fetch_generate_custom_shader(const shader_ref &src, bool add_wavy_effect)
{
typename shader_map::iterator iter;
shader_ref return_value;
iter = m_shaders.find(src);
if (iter != m_shaders.end())
{
return_value = iter->second;
}
else
{
return_value = create_custom_shader<T>(src, add_wavy_effect);
m_shaders[src] = return_value;
}
return return_value;
}
private:
shader_map m_shaders;
};
generate_item_shader(CustomShaderGenerator<fastuidraw::glsl::PainterItemShaderGLSL> &item_shaders,
CustomShaderGenerator<fastuidraw::glsl::PainterItemCoverageShaderGLSL> &cvg_shaders,
{
using namespace glsl;
{
}
else
{
}
if (src_cvg)
{
{
}
else
{
}
use_cvg = cvg_shaders.fetch_generate_custom_shader(src_cvg_glsl, true);
use = item_shaders.fetch_generate_custom_shader(src_glsl, false);
}
else
{
use = item_shaders.fetch_generate_custom_shader(src_glsl, true);
}
}
void
CustomShaderGenerator<fastuidraw::glsl::PainterItemShaderGLSL> &item_shaders,
CustomShaderGenerator<fastuidraw::glsl::PainterItemCoverageShaderGLSL> &cvg_shaders,
{
src_shader = src.
shader(tp, sh);
new_shader = generate_item_shader(item_shaders, cvg_shaders, src_shader);
dst.
shader(tp, sh, new_shader);
}
{
public:
explicit
m_base(base)
{}
virtual
float
float path_magnification,
float curve_flatness) const override
{
return m_base->compute_thresh(data.
sub_array(3),
path_magnification,
curve_flatness);
}
virtual
void
{
m_base->stroking_distances(data.
sub_array(3), out_values);
}
virtual
bool
{
return m_base->arc_stroking_possible(data.
sub_array(3));
}
virtual
bool
{
return m_base->data_compatible(data.
sub_array(3));
}
};
{
CustomShaderGenerator<PainterItemShaderGLSL> item_shaders;
CustomShaderGenerator<PainterItemCoverageShaderGLSL> cvg_shaders;
set_shader(return_value, item_shaders, cvg_shaders,
src, Painter::stroking_method_linear,
PainterStrokeShader::non_aa_shader);
set_shader(return_value, item_shaders, cvg_shaders,
src, Painter::stroking_method_arc,
PainterStrokeShader::non_aa_shader);
set_shader(return_value, item_shaders, cvg_shaders,
src, Painter::stroking_method_linear,
PainterStrokeShader::aa_shader);
set_shader(return_value, item_shaders, cvg_shaders,
src, Painter::stroking_method_arc,
PainterStrokeShader::aa_shader);
return_value
return return_value;
}
class ExampleCustomPathShading:public Initialization
{
public:
ExampleCustomPathShading(DemoRunner *runner, int argc, char **argv);
virtual
void
draw_frame(void) override;
virtual
void
handle_event(const SDL_Event &ev) override;
private:
};
ExampleCustomPathShading::
ExampleCustomPathShading(DemoRunner *runner, int argc, char **argv):
Initialization(runner, argc, argv)
{
m_path.approximate_bounding_box(&m_path_bounds);
m_stroke_shader = generate_stroke_shader(m_painter_engine_gl->default_shaders().stroke_shader());
m_painter_engine_gl->register_shader(m_stroke_shader);
}
void
ExampleCustomPathShading::
draw_frame(void)
{
float stroke_width, border;
m_surface_gl->viewport(vwp);
stroke_width = 8.0f;
border = 3.0f * stroke_width;
m_painter->shear(scale.
x(), scale.
y());
m_painter->translate(translate);
ExampleItemData data;
uint32_t ms;
float fc, fs, fc2, fs2;
ms = SDL_GetTicks() % 4000;
data.m_domain_coeff = 10.0f *
FASTUIDRAW_PI / (m_path_bounds.width() + m_path_bounds.height());
-4.0f * fs,
+2.0f * fs2,
-1.0f * fc2);
-2.0f * fc,
+4.0f * fs2,
-8.0f * fc2);
data.m_stroke_params.width(40.0f);
brush.
color(1.0f, 0.6f, 0.0f, 0.8f);
m_painter->stroke_path(m_stroke_shader,
m_path,
m_painter->end();
fastuidraw_glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
fastuidraw_glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
m_surface_gl->blit_surface(GL_NEAREST);
}
void
ExampleCustomPathShading::
handle_event(const SDL_Event &ev)
{
switch (ev.type)
{
case SDL_KEYDOWN:
switch (ev.key.keysym.sym)
{
}
break;
}
Initialization::handle_event(ev);
}
int
main(int argc, char **argv)
{
DemoRunner demo;
return demo.main<ExampleCustomPathShading>(argc, argv);
}