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 | |
16 | using namespace fastuidraw; |
17 | |
18 | c_string |
19 | on_off(bool v) |
20 | { |
21 | return v ? "ON" : "OFF" ; |
22 | } |
23 | |
24 | class ExampleCustomBrushData:public PainterBrushShaderData |
25 | { |
26 | public: |
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 | |
63 | class painter_brush_test:public sdl_painter_demo |
64 | { |
65 | public: |
66 | painter_brush_test(void); |
67 | |
68 | protected: |
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 | |
79 | private: |
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 | |
96 | painter_brush_test:: |
97 | painter_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 | |
113 | void |
114 | painter_brush_test:: |
115 | derived_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 | |
169 | void |
170 | painter_brush_test:: |
171 | draw_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 | |
218 | void |
219 | painter_brush_test:: |
220 | handle_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 | |
252 | int |
253 | main(int argc, char **argv) |
254 | { |
255 | painter_brush_test P; |
256 | return P.main(argc, argv); |
257 | } |
258 | |