1#include <fastuidraw/painter/painter.hpp>
2#include <fastuidraw/text/glyph_cache.hpp>
3#include <fastuidraw/text/font_freetype.hpp>
4#include <fastuidraw/text/font_database.hpp>
5#include <fastuidraw/glsl/painter_brush_shader_glsl.hpp>
6
7#include "sdl_painter_demo.hpp"
8#include "PanZoomTracker.hpp"
9#include "text_helper.hpp"
10#include "read_path.hpp"
11#include "ImageLoader.hpp"
12#include "colorstop_command_line.hpp"
13#include "command_line_list.hpp"
14#include "cycle_value.hpp"
15
16using namespace fastuidraw;
17
18c_string
19on_off(bool v)
20{
21 return v ? "ON" : "OFF";
22}
23
24class ExampleCustomBrushData:public PainterBrushShaderData
25{
26public:
27 ExampleCustomBrushData(void):
28 m_width(100.0f),
29 m_height(100.0f)
30 {
31 }
32
33 ExampleCustomBrushData&
34 width(float v)
35 {
36 m_width = v;
37 return *this;
38 }
39
40 ExampleCustomBrushData&
41 height(float v)
42 {
43 m_height = v;
44 return *this;
45 }
46
47 void
48 pack_data(fastuidraw::c_array<fastuidraw::uvec4> dst) const override
49 {
50 dst[0].x() = fastuidraw::pack_float(1.0f / m_width);
51 dst[0].y() = fastuidraw::pack_float(1.0f / m_height);
52 }
53
54 unsigned int
55 data_size(void) const override
56 {
57 return FASTUIDRAW_NUMBER_BLOCK4_NEEDED(2);
58 }
59
60 float m_width, m_height;
61};
62
63class painter_brush_test:public sdl_painter_demo
64{
65public:
66 painter_brush_test(void);
67
68protected:
69
70 void
71 derived_init(int w, int h);
72
73 void
74 draw_frame(void);
75
76 void
77 handle_event(const SDL_Event &ev);
78
79private:
80 enum
81 {
82 custom_red_green_brush,
83 custom_green_blue_brush,
84
85 number_custom_brushes
86 };
87
88 command_line_argument_value<std::string> m_image_file;
89 command_line_argument_value<bool> m_use_atlas;
90
91 vecN<reference_counted_ptr<PainterBrushShader>, number_custom_brushes> m_brush_shader;
92 reference_counted_ptr<const Image> m_image;
93 unsigned int m_current_brush;
94};
95
96painter_brush_test::
97painter_brush_test(void):
98 m_image_file("", "image", "if a valid file name, apply an image to drawing the fill", *this),
99 m_use_atlas(true, "use_atlas",
100 "If false, each image is realized as a texture; if "
101 "GL_ARB_bindless_texture or GL_NV_bindless_texture "
102 "is supported, the Image objects are realized as bindless "
103 "texture, thus avoding draw breaks; if both of these "
104 "extensions is not present, then images are realized as "
105 "bound textures which means that a draw break will be present "
106 "whenever the image changes, harming performance.",
107 *this),
108 m_current_brush(number_custom_brushes)
109{
110 std::cout << "\tp: cycle through brushes\n";
111}
112
113void
114painter_brush_test::
115derived_init(int w, int h)
116{
117 FASTUIDRAWunused(w);
118 FASTUIDRAWunused(h);
119 if (!m_image_file.value().empty())
120 {
121 ImageLoader image_data(m_image_file.value());
122 if (image_data.non_empty())
123 {
124 if (m_use_atlas.value())
125 {
126 m_image = m_painter->image_atlas().create(image_data.width(),
127 image_data.height(),
128 image_data,
129 Image::on_atlas);
130 }
131 else
132 {
133 m_image = m_painter->image_atlas().create_non_atlas(image_data.width(),
134 image_data.height(),
135 image_data);
136 }
137 }
138 }
139
140 glsl::varying_list varyings;
141 c_string macros[number_custom_brushes] =
142 {
143 [0] = "RED_GREEN",
144 [1] = "GREEN_BLUE"
145 };
146 varyings
147 .add_float("brush_p_x")
148 .add_float("brush_p_y");
149
150 for (int i = 0; i < number_custom_brushes; ++i)
151 {
152 glsl::ShaderSource vert_src, frag_src;
153
154 vert_src
155 .add_macro(macros[i])
156 .add_source("custom_brush_example.vert.glsl.resource_string", glsl::ShaderSource::from_resource)
157 .remove_macro(macros[i]);
158
159 frag_src
160 .add_macro(macros[i])
161 .add_source("custom_brush_example.frag.glsl.resource_string", glsl::ShaderSource::from_resource)
162 .remove_macro(macros[i]);
163
164 m_brush_shader[i] = FASTUIDRAWnew glsl::PainterBrushShaderGLSL(1, vert_src, frag_src, varyings);
165 m_painter->painter_shader_registrar().register_shader(m_brush_shader[i]);
166 }
167}
168
169void
170painter_brush_test::
171draw_frame(void)
172{
173 m_painter->begin(m_surface, Painter::y_increases_downwards);
174
175 PainterBrush brush;
176 ExampleCustomBrushData custom_brush_data;
177 PainterData data;
178 vec2 dims(dimensions());
179
180 if (number_custom_brushes == m_current_brush)
181 {
182 if (m_image)
183 {
184 brush
185 .image(m_image)
186 .repeat_window(vec2(0.0f, 0.0f),
187 vec2(m_image->dimensions()));
188 }
189 else
190 {
191 brush.color(1.0f, 0.5f, 0.5f, 0.75f);
192 }
193 data.set(&brush);
194 }
195 else
196 {
197 custom_brush_data
198 .width(0.25f * dims.x())
199 .height(0.35f * dims.y());
200
201 PainterCustomBrush br(m_brush_shader[m_current_brush].get(),
202 &custom_brush_data);
203
204 data.set(br);
205 }
206
207 m_painter->fill_rect(data,
208 Rect()
209 .width(dims.x())
210 .height(dims.y()),
211 false);
212 m_painter->end();
213 fastuidraw_glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
214 fastuidraw_glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
215 m_surface->blit_surface(GL_NEAREST);
216}
217
218void
219painter_brush_test::
220handle_event(const SDL_Event &ev)
221{
222 switch(ev.type)
223 {
224 case SDL_QUIT:
225 end_demo(0);
226 break;
227
228 case SDL_WINDOWEVENT:
229 if (ev.window.event == SDL_WINDOWEVENT_RESIZED)
230 {
231 on_resize(ev.window.data1, ev.window.data2);
232 }
233 break;
234
235 case SDL_KEYUP:
236 switch(ev.key.keysym.sym)
237 {
238 case SDLK_ESCAPE:
239 end_demo(0);
240 break;
241 case SDLK_p:
242 cycle_value(m_current_brush,
243 ev.key.keysym.mod & (KMOD_SHIFT|KMOD_CTRL|KMOD_ALT),
244 number_custom_brushes + 1);
245 std::cout << "Set to brush #" << m_current_brush << "\n";
246 break;
247 }
248 break;
249 } //switch
250}
251
252int
253main(int argc, char **argv)
254{
255 painter_brush_test P;
256 return P.main(argc, argv);
257}
258