Example on how to create a custom-brush that builds from teh standard brush.
The Example Custom Brush builds from Example Initialization to demonstrate how to create a custom-brush that builds from the standard brush. The example custom is implemented by modifying in the fragment shader the brush position fed to the standard brush.
A custom brush is defined essentially by two elements: a shader and data to feed the shader. The shader is represented by fastuidraw::PainterBrushShader and the data to feed it is represented by fastuidraw::PainterBrushShaderData. The data represents the small amount of data that the shader unpacks from the data store.
Using the symbols documented in GLSL Built in Shaders, the implementation of the data used by the custom brush and the shader for it is given by
#include <iostream>
#include <fstream>
#include <sstream>
{
public:
ExampleCustomBrushData(void):
m_phase(0.0f),
m_amplitude(0.0f),
m_period(1.0f)
{}
unsigned int
{
return 1 + m_brush_values.data_size();
}
void
{
}
unsigned int
{
return m_brush_values.number_resources();
}
void
{
m_brush_values.save_resources(dst);
}
{
return m_brush_values.bind_images();
}
float m_phase, m_period, m_amplitude;
};
{
const char *custom_brush_vert_shader =
"void\n"
"fastuidraw_gl_vert_brush_main(in uint sub_shader,\n"
" inout uint shader_data_block,\n"
" in vec2 brush_p)\n"
"{\n"
" shader_data_block += 1u;\n"
" standard_brush(0u, shader_data_block, brush_p);\n"
"}\n";
const char *custom_brush_frag_shader =
"vec4\n"
"fastuidraw_gl_frag_brush_main(in uint sub_shader,\n"
" inout uint shader_data_block)\n"
"{\n"
" const float PI = 3.14159265358979323846;\n"
" uvec3 packed_value;\n"
" float phase, period, amplitude;\n"
""
" packed_value = fastuidraw_fetch_data(shader_data_block).xyz;\n"
" phase = uintBitsToFloat(packed_value.x);\n"
" period = uintBitsToFloat(packed_value.y);\n"
" amplitude = uintBitsToFloat(packed_value.z);\n"
""
" standard_brush::fastuidraw_brush_p_x += amplitude * cos((2.0 * PI / period) * (phase + standard_brush::fastuidraw_brush_p_y));\n"
""
" shader_data_block += 1u;\n"
" return standard_brush(sub_shader, shader_data_block);\n"
"}\n";
vert.
add_source(
"custom_brush_vert_shader", ShaderSource::from_resource);
frag.
add_source(
"custom_brush_frag_shader", ShaderSource::from_resource);
unsigned int number_context_textures(0);
vert, frag,
varyings, deps);
#ifdef FASTUIDRAW_DEBUG
{
pr = painter_engine_gl->
program(PainterEngineGL::program_all, PainterBlendShader::single_src);
{
std::cout << "Uber GLSL-program failed to be linked, dumping logs and sources of it\n";
std::ofstream program_log("program_log.txt");
program_log <<
"Log:\n" << pr->
log()
<< "\n";
GLenum tps[2] = {GL_VERTEX_SHADER, GL_FRAGMENT_SHADER};
for (GLenum tp : tps)
{
for (
unsigned int i = 0, endi = pr->
num_shaders(tp); i < endi; ++i)
{
{
std::ostringstream name_common, name_log, name_src;
name_common << "compliled_failed.shader_" << i
<< "." << Shader::gl_shader_type_label(tp)
<< ".";
name_log << name_common.str() << "log";
name_src << name_common.str() << "glsl";
std::ofstream shader_log(name_log.str().c_str());
std::ofstream shader_src(name_src.str().c_str());
}
}
}
return_value = nullptr;
}
}
#endif
return return_value;
}
The implementation of using the custom brush is given by
class ExampleCustomBrush:public Initialization
{
public:
ExampleCustomBrush(DemoRunner *runner, int argc, char **argv);
~ExampleCustomBrush()
{}
virtual
void
draw_frame(void) override;
private:
};
ExampleCustomBrush::
ExampleCustomBrush(DemoRunner *runner, int argc, char **argv):
Initialization(runner, argc, argv)
{
m_color_stops = m_painter_engine_gl->colorstop_atlas().create(seq, 8);
m_custom_brush_shader = create_wavy_custom_brush(m_painter_engine_gl.get());
if (!m_custom_brush_shader)
{
end_demo(-1);
}
if (argc >= 2)
{
ImageSourceSDL image_loader(argv[1]);
m_image = m_painter_engine_gl->image_atlas().create(image_loader.width(),
image_loader.height(),
image_loader);
}
}
void
ExampleCustomBrush::
draw_frame(void)
{
m_surface_gl->viewport(vwp);
uint32_t t;
t = SDL_GetTicks() % 4000u;
ExampleCustomBrushData brush;
brush.m_brush_values
.color(1.0f, 1.0f, 1.0f, 1.0f)
.linear_gradient(m_color_stops,
window_dims * 0.45f,
window_dims * 0.55f,
if (m_image)
{
brush.m_brush_values.image(m_image);
}
float tf;
brush.m_phase = window_dims.y() * static_cast<float>(t) / 4000.0f;
brush.m_period = window_dims.y();
&brush);
m_painter->fill_rect(custom_brush,
.min_point(0.0f, 0.0f)
.max_point(window_dims));
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);
}
int
main(int argc, char **argv)
{
DemoRunner demo_runner;
return demo_runner.main<ExampleCustomBrush>(argc, argv);
}