1#include <fstream>
2#include <dirent.h>
3
4#include <fastuidraw/painter/painter.hpp>
5#include <fastuidraw/text/glyph_cache.hpp>
6#include <fastuidraw/text/font_freetype.hpp>
7#include <fastuidraw/text/font_database.hpp>
8#include <fastuidraw/gl_backend/gl_context_properties.hpp>
9
10#include "sdl_painter_demo.hpp"
11#include "PainterWidget.hpp"
12#include "simple_time.hpp"
13#include "PanZoomTracker.hpp"
14#include "text_helper.hpp"
15#include "read_path.hpp"
16#include "ImageLoader.hpp"
17#include "colorstop_command_line.hpp"
18#include "command_line_list.hpp"
19#include "cycle_value.hpp"
20#include "text_helper.hpp"
21
22#include "cell.hpp"
23#include "table.hpp"
24#include "random.hpp"
25
26using namespace fastuidraw;
27
28bool
29compare_named_images(const named_image &lhs,
30 const named_image &rhs)
31{
32 return lhs.second < rhs.second;
33}
34
35class painter_cells:public sdl_painter_demo
36{
37public:
38 painter_cells(void);
39
40 ~painter_cells();
41
42protected:
43 void
44 derived_init(int w, int h);
45
46 void
47 draw_frame(void);
48
49 void
50 handle_event(const SDL_Event &ev);
51
52private:
53 typedef std::pair<enum Painter::blend_mode_t, std::string> named_blend_mode;
54
55 static
56 void
57 generate_random_colors(int count, std::vector<vec4> &out_values, bool force_opaque);
58
59 static
60 void
61 dump_file(const std::string &filename, std::vector<std::string> &dest);
62
63 void
64 add_images(const std::string &filename, std::vector<named_image> &dest);
65
66 void
67 add_single_image(const std::string &filename, std::vector<named_image> &dest);
68
69 void
70 update_cts_params(void);
71
72 command_line_argument_value<float> m_table_width, m_table_height;
73 command_line_argument_value<int> m_num_cells_x, m_num_cells_y;
74 command_line_argument_value<int> m_cell_group_size;
75 command_line_argument_value<std::string> m_font;
76 command_line_argument_value<float> m_pixel_size;
77 enumerated_command_line_argument_value<enum glyph_type> m_renderer;
78 command_line_argument_value<float> m_fps_pixel_size;
79 command_line_list<std::string> m_strings;
80 command_line_list<std::string> m_files;
81 command_line_list<std::string> m_images;
82 enumerated_command_line_argument_value<enum PainterImageBrushShader::filter_t> m_image_filter;
83 command_line_argument_value<bool> m_image_use_mipmaps;
84 command_line_argument_value<bool> m_use_atlas;
85 command_line_argument_value<bool> m_draw_image_name;
86 command_line_argument_value<int> m_num_background_colors;
87 command_line_argument_value<bool> m_background_colors_opaque;
88 command_line_argument_value<int> m_num_text_colors;
89 command_line_argument_value<bool> m_text_colors_opaque;
90 command_line_argument_value<int> m_num_rect_colors;
91 command_line_argument_value<bool> m_rect_colors_opaque;
92 command_line_argument_value<float> m_min_x_velocity, m_max_x_velocity;
93 command_line_argument_value<float> m_min_y_velocity, m_max_y_velocity;
94 command_line_argument_value<int> m_min_degree_per_second;
95 command_line_argument_value<int> m_max_degree_per_second;
96 command_line_argument_value<int> m_table_rotate_degrees_per_s;
97 command_line_argument_value<float> m_change_stroke_width_rate;
98
99 command_line_argument_value<int> m_num_frames;
100 command_line_argument_value<int> m_skip_frames;
101 command_line_argument_value<bool> m_init_show_all_table;
102 command_line_argument_value<bool> m_init_table_rotating;
103 command_line_argument_value<bool> m_init_table_clipped;
104 command_line_argument_value<bool> m_init_cell_rotating;
105 command_line_argument_value<bool> m_init_draw_text;
106 command_line_argument_value<bool> m_init_draw_images;
107 command_line_argument_value<float> m_init_stroke_width;
108 command_line_argument_value<bool> m_init_anti_alias_stroking;
109
110 CellSharedState m_cell_shared_state;
111 TableParams m_table_params;
112 PanZoomTrackerSDLEvent m_zoomer;
113 Table *m_table;
114 simple_time m_time, m_draw_timer;
115 PainterData::brush_value m_text_brush;
116
117 unsigned int m_current_blend;
118 std::vector<named_blend_mode> m_blend_labels;
119
120 int m_frame;
121 uint64_t m_benchmark_time_us;
122 simple_time m_benchmark_timer;
123 std::vector<uint64_t> m_frame_times;
124
125 int m_show_surface, m_last_shown_surface;
126};
127
128painter_cells::
129painter_cells(void):
130 m_table_width(800, "table_width", "Table Width", *this),
131 m_table_height(600, "table_height", "Table Height", *this),
132 m_num_cells_x(10, "num_cells_x", "Number of cells across", *this),
133 m_num_cells_y(10, "num_cells_y", "Number of cells down", *this),
134 m_cell_group_size(1, "cell_group_size", "width and height in number of cells for cell group size", *this),
135 m_font(default_font(), "font", "File from which to take font", *this),
136 m_pixel_size(24.0f, "font_pixel_size", "Render size for text rendering", *this),
137 m_renderer(adaptive_rendering,
138 enumerated_string_type<enum glyph_type>()
139 .add_entry("distance_field", distance_field_glyph, "Distance field rendering")
140 .add_entry("restricted_rays", restricted_rays_glyph, "Restricted Rays rendering")
141 .add_entry("adaptive", adaptive_rendering, "Adaptive rendering"),
142 "glyph_render",
143 "Specifies how to render glyphs",
144 *this),
145 m_fps_pixel_size(24.0f, "fps_font_pixel_size", "Render size for text rendering of fps", *this),
146 m_strings("add_string", "add a string to use by the cells", *this),
147 m_files("add_string_file", "add a string to use by a cell, taken from file", *this),
148 m_images("add_image", "Add an image to use by the cells", *this),
149 m_image_filter(PainterImageBrushShader::filter_nearest,
150 enumerated_string_type<enum PainterImageBrushShader::filter_t>()
151 .add_entry("nearest", PainterImageBrushShader::filter_nearest, "nearest filtering")
152 .add_entry("linear", PainterImageBrushShader::filter_linear, "(bi)linear filtering")
153 .add_entry("cubic", PainterImageBrushShader::filter_cubic, "(bi)cubic filtering"),
154 "image_filter",
155 "Specifies how to filter the images applied to the rects",
156 *this),
157 m_image_use_mipmaps(false, "image_mipmap", "If true, apply mipmapp filtering to images", *this),
158 m_use_atlas(true, "use_atlas",
159 "If false, each image is realized as a texture; if "
160 "GL_ARB_bindless_texture or GL_NV_bindless_texture "
161 "is supported, the Image objects are realized as bindless "
162 "texture, thus avoding draw breaks; if both of these "
163 "extensions is not present, then images are realized as "
164 "bound textures which means that a draw break will be present "
165 "whenever the image changes, harming performance.",
166 *this),
167 m_draw_image_name(false, "draw_image_name", "If true draw the image name in each cell as part of the text", *this),
168 m_num_background_colors(1, "num_background_colors", "Number of distinct background colors in cells", *this),
169 m_background_colors_opaque(false, "background_colors_opaque",
170 "If true, all background colors for rects are forced to be opaque",
171 *this),
172 m_num_text_colors(1, "num_text_colors", "Number of distinct text colors in cells", *this),
173 m_text_colors_opaque(true, "text_colors_opaque",
174 "If true, all text colors are forced to be opaque",
175 *this),
176 m_num_rect_colors(0, "num_rect_colors", "Number of distinct colors which modulates the image, 0 means no modulation", *this),
177 m_rect_colors_opaque(true, "rect_colors_opaque",
178 "If true, all rect colors are forced to be opaque",
179 *this),
180 m_min_x_velocity(-10.0f, "min_x_velocity", "Minimum x-velocity for cell content in pixels/s", *this),
181 m_max_x_velocity(+10.0f, "max_x_velocity", "Maximum x-velocity for cell content in pixels/s", *this),
182 m_min_y_velocity(-10.0f, "min_y_velocity", "Minimum y-velocity for cell content in pixels/s", *this),
183 m_max_y_velocity(+10.0f, "max_y_velocity", "Maximum y-velocity for cell content in pixels/s", *this),
184 m_min_degree_per_second(60, "min_degree_velocity", "max rotation speed in degrees/second", *this),
185 m_max_degree_per_second(60, "max_degree_velocity", "max rotation speed in degrees/second", *this),
186 m_table_rotate_degrees_per_s(20, "table_degree_velocity", "rotation speed of table in degrees/second", *this),
187 m_change_stroke_width_rate(10.0f, "change_stroke_width_rate",
188 "rate of change in pixels/sec for changing stroke width "
189 "when changing stroke when key is down",
190 *this),
191 m_num_frames(-1, "num_frames",
192 "If positive, then run demo in benchmark mode terminating after the given number of frames",
193 *this),
194 m_skip_frames(1, "num_skip_frames",
195 "If num_frames > 0, then gives the number of frames to ignore in benchmarking",
196 *this),
197 m_init_show_all_table(true, "init_show_all_table",
198 "If true, initialize scroll and zoom to show entire table",
199 *this),
200 m_init_table_rotating(false, "init_table_rotating",
201 "If true, initialize table to be rotating",
202 *this),
203 m_init_table_clipped(false, "init_table_clipped",
204 "If true, initialize to enable clipping on the table",
205 *this),
206 m_init_cell_rotating(false, "init_cell_rotating",
207 "If true, intialize to have cells rotating",
208 *this),
209 m_init_draw_text(true, "init_draw_text",
210 "If true, intialize to draw text in cells",
211 *this),
212 m_init_draw_images(true, "init_draw_image",
213 "If true, intialize to draw image in cells",
214 *this),
215 m_init_stroke_width(10.0f, "init_stroke_width",
216 "Initial value for stroking width",
217 *this),
218 m_init_anti_alias_stroking(true, "init_antialias_stroking",
219 "Initial value for anti-aliasing for stroking",
220 *this),
221 m_table(nullptr),
222 m_current_blend(0),
223 m_show_surface(0),
224 m_last_shown_surface(0)
225{
226 std::cout << "Controls:\n"
227 << "\t[: decrease stroke width(hold left-shift for slower rate and right shift for faster)\n"
228 << "\t]: increase stroke width(hold left-shift for slower rate and right shift for faster)\n"
229 << "\ta: toggle anti-aliasing of stroking\n"
230 << "\tp: pause cell rotate\n"
231 << "\t0: set zoom factor to 1.0\n"
232 << "\tc: toggle clipping of table\n"
233 << "\tv: toggle table rotating\n"
234 << "\tr: toggle rotating individual cells\n"
235 << "\tt: toggle draw cell text\n"
236 << "\ti: toggle draw cell image\n"
237 << "\tb: cycle blend mode applied to image rect\n"
238 << "\tctrl-b: cycle blend mode applied to image rect\n"
239 << "\ty: toggle drawing widgets as transparent or opaque\n"
240 << "\tLeft Mouse Drag: pan\n"
241 << "\tHold Left Mouse, then drag up/down: zoom out/in\n";
242}
243
244painter_cells::
245~painter_cells()
246{
247 if (m_table != nullptr)
248 {
249 FASTUIDRAWdelete(m_table);
250 }
251}
252
253void
254painter_cells::
255generate_random_colors(int count, std::vector<vec4> &out_values, bool force_opaque)
256{
257 out_values.resize(count);
258 for(int i = 0; i < count; ++i)
259 {
260 out_values[i] = random_value(vec4(0.0f, 0.0f, 0.0f, 0.2f),
261 vec4(1.0f, 1.0f, 1.0f, 0.8f));
262 if (force_opaque)
263 {
264 out_values[i].w() = 1.0f;
265 }
266 }
267}
268
269void
270painter_cells::
271dump_file(const std::string &filename, std::vector<std::string> &dest)
272{
273 std::ifstream istr(filename.c_str());
274 if (istr)
275 {
276 std::ostringstream str;
277 str << istr.rdbuf();
278 dest.push_back(str.str());
279 }
280}
281
282void
283painter_cells::
284add_images(const std::string &filename, std::vector<named_image> &dest)
285{
286 DIR *dir;
287 struct dirent *entry;
288
289 dir = opendir(filename.c_str());
290 if (!dir)
291 {
292 add_single_image(filename, dest);
293 return;
294 }
295
296 for(entry = readdir(dir); entry != nullptr; entry = readdir(dir))
297 {
298 std::string file;
299 file = entry->d_name;
300 if (file != ".." && file != ".")
301 {
302 add_images(filename + "/" + file, dest);
303 }
304 }
305 closedir(dir);
306}
307
308void
309painter_cells::
310add_single_image(const std::string &filename, std::vector<named_image> &dest)
311{
312 ImageLoader image_data(filename);
313 if (image_data.non_empty())
314 {
315 reference_counted_ptr<const Image> im;
316
317 std::cout << "\tImage \"" << filename << "\" of size "
318 << image_data.dimensions() << " loaded";
319
320 if (m_use_atlas.value())
321 {
322 im = m_painter->image_atlas().create(image_data.width(),
323 image_data.height(),
324 image_data,
325 Image::on_atlas);
326 }
327 else
328 {
329 im = m_painter->image_atlas().create_non_atlas(image_data.width(),
330 image_data.height(),
331 image_data);
332 }
333
334 switch (im->type())
335 {
336 case Image::on_atlas:
337 std::cout << " on atlas with number_mipmap_levels = "
338 << im->number_mipmap_levels();
339 break;
340 case Image::bindless_texture2d:
341 std::cout << " bindlessly";
342 break;
343 case Image::context_texture2d:
344 std::cout << " as bound texture (WARNING: large performance impact expected)";
345 break;
346 }
347
348 std::cout << " @" << im.get() << ".\n";
349 dest.push_back(named_image(im, filename));
350 }
351}
352
353void
354painter_cells::
355derived_init(int w, int h)
356{
357 m_table_params.m_wh = vec2(m_table_width.value(), m_table_height.value());
358 m_table_params.m_cell_count = ivec2(m_num_cells_x.value(), m_num_cells_y.value());
359 m_table_params.m_line_color = vec4(1.0f, 1.0f, 1.0f, 1.0f);
360 m_table_params.m_cell_state = &m_cell_shared_state;
361 m_table_params.m_zoomer = &m_zoomer;
362 m_table_params.m_draw_image_name = m_draw_image_name.value();
363 m_table_params.m_table_rotate_degrees_per_s = m_table_rotate_degrees_per_s.value();
364 m_table_params.m_timer_based_animation = (m_num_frames.value() <= 0);
365
366 reference_counted_ptr<FreeTypeFace::GeneratorBase> gen;
367 gen = FASTUIDRAWnew FreeTypeFace::GeneratorMemory(m_font.value().c_str(), 0);
368 m_table_params.m_font_database = m_font_database;
369 m_table_params.m_glyph_cache = &m_painter->glyph_cache();
370 if (gen->check_creation() == routine_success)
371 {
372 m_table_params.m_font = FASTUIDRAWnew FontFreeType(gen, m_ft_lib);
373 }
374 else
375 {
376 std::cout << "\n-----------------------------------------------------"
377 << "\nWarning: unable to create font from file \""
378 << m_font.value() << "\"\n"
379 << "-----------------------------------------------------\n";
380 }
381
382 m_table_params.m_pixel_size = m_pixel_size.value();
383 m_table_params.m_texts.reserve(m_strings.size() + m_files.size());
384 for(const auto &S : m_strings)
385 {
386 m_table_params.m_texts.push_back(S);
387 }
388
389 for(const auto &S : m_files)
390 {
391 dump_file(S, m_table_params.m_texts);
392 }
393
394 for(const auto &S : m_images)
395 {
396 add_images(S, m_table_params.m_images);
397 }
398 std::cout << "Loaded " << m_table_params.m_images.size() << " images total\n";
399 std::sort(m_table_params.m_images.begin(),
400 m_table_params.m_images.end(),
401 compare_named_images);
402 m_table_params.m_image_filter = m_image_filter.value();
403 m_table_params.m_image_mipmapping = m_image_use_mipmaps.value() ?
404 PainterImageBrushShader::apply_mipmapping:
405 PainterImageBrushShader::dont_apply_mipmapping;
406
407 generate_random_colors(m_num_background_colors.value(), m_table_params.m_background_colors,
408 m_background_colors_opaque.value());
409 generate_random_colors(m_num_text_colors.value(), m_table_params.m_text_colors,
410 m_text_colors_opaque.value());
411 generate_random_colors(m_num_rect_colors.value(), m_table_params.m_rect_colors,
412 m_rect_colors_opaque.value());
413
414 if (m_table_params.m_images.empty() && m_table_params.m_rect_colors.empty())
415 {
416 vec4 C(0.2f, 0.7f, 0.7f, 0.6f);
417 m_table_params.m_rect_colors.push_back(C);
418 }
419
420 m_table_params.m_min_speed = vec2(m_min_x_velocity.value(), m_min_y_velocity.value());
421 m_table_params.m_max_speed = vec2(m_max_x_velocity.value(), m_max_y_velocity.value());
422 m_table_params.m_min_degrees_per_s = m_min_degree_per_second.value();
423 m_table_params.m_max_degrees_per_s = m_max_degree_per_second.value();
424
425 if (m_cell_group_size.value() > 0)
426 {
427 m_table_params.m_max_cell_group_size = m_cell_group_size.value();
428 }
429 else
430 {
431 m_table_params.m_max_cell_group_size = 2 * std::max(m_num_cells_x.value(), m_num_cells_y.value());
432 }
433
434 m_table = FASTUIDRAWnew Table(m_table_params);
435 m_table->m_clipped = m_init_table_clipped.value();
436 m_table->m_rotating = m_init_table_rotating.value();
437 m_cell_shared_state.m_draw_text = m_init_draw_text.value();
438 m_cell_shared_state.m_draw_image = m_init_draw_images.value();
439 m_cell_shared_state.m_rotating = m_init_cell_rotating.value();
440 m_cell_shared_state.m_stroke_width = m_init_stroke_width.value();
441 m_cell_shared_state.m_anti_alias_stroking = m_init_anti_alias_stroking.value();
442 m_cell_shared_state.m_glyph_render = m_renderer.value();
443
444 /* init m_zoomer so that table contents fit into screen.
445 */
446 vec2 twh;
447 ScaleTranslate<float> tr1, tr2;
448
449 twh = m_table_params.m_wh / vec2(w, h);
450 tr1.translation(-0.5f * m_table_params.m_wh);
451 tr2.translation(0.5f * vec2(w, h));
452
453 if (m_init_show_all_table.value())
454 {
455 ScaleTranslate<float> sc;
456 sc.scale(1.0f / std::max(twh.x(), twh.y()));
457 m_zoomer.transformation(tr2 * sc * tr1);
458 }
459 else
460 {
461 m_zoomer.transformation(tr2 * tr1);
462 }
463
464
465 if (m_table_params.m_font)
466 {
467 std::cout << "Font: " << m_table_params.m_font->properties() << "\n";
468 }
469 else
470 {
471 std::cout << "Font: nullptr\n";
472 }
473
474 std::cout << "Window resolution = " << dimensions() << "\n";
475
476 m_frame = -m_skip_frames.value();
477 if (m_num_frames.value() > 0)
478 {
479 m_frame_times.reserve(m_num_frames.value());
480 }
481
482#define ADD_COMPOSITE_MODE(X) \
483 m_blend_labels.push_back(named_blend_mode(Painter::X, #X))
484
485 ADD_COMPOSITE_MODE(blend_porter_duff_src_over);
486 ADD_COMPOSITE_MODE(blend_porter_duff_clear);
487 ADD_COMPOSITE_MODE(blend_porter_duff_src);
488 ADD_COMPOSITE_MODE(blend_porter_duff_dst);
489 ADD_COMPOSITE_MODE(blend_porter_duff_dst_over);
490 ADD_COMPOSITE_MODE(blend_porter_duff_src_in);
491 ADD_COMPOSITE_MODE(blend_porter_duff_dst_in);
492 ADD_COMPOSITE_MODE(blend_porter_duff_src_out);
493 ADD_COMPOSITE_MODE(blend_porter_duff_dst_out);
494 ADD_COMPOSITE_MODE(blend_porter_duff_src_atop);
495 ADD_COMPOSITE_MODE(blend_porter_duff_dst_atop);
496 ADD_COMPOSITE_MODE(blend_porter_duff_xor);
497
498#define ADD_BLEND_MODE(X) do { \
499 if (m_painter->default_shaders().blend_shaders().shader(Painter::X)) \
500 { \
501 m_blend_labels.push_back(named_blend_mode(Painter::X, #X)); \
502 } \
503 } while(0)
504
505 ADD_BLEND_MODE(blend_w3c_multiply);
506 ADD_BLEND_MODE(blend_w3c_screen);
507 ADD_BLEND_MODE(blend_w3c_overlay);
508 ADD_BLEND_MODE(blend_w3c_darken);
509 ADD_BLEND_MODE(blend_w3c_lighten);
510 ADD_BLEND_MODE(blend_w3c_color_dodge);
511 ADD_BLEND_MODE(blend_w3c_color_burn);
512 ADD_BLEND_MODE(blend_w3c_hardlight);
513 ADD_BLEND_MODE(blend_w3c_softlight);
514 ADD_BLEND_MODE(blend_w3c_difference);
515 ADD_BLEND_MODE(blend_w3c_exclusion);
516 ADD_BLEND_MODE(blend_w3c_hue);
517 ADD_BLEND_MODE(blend_w3c_saturation);
518 ADD_BLEND_MODE(blend_w3c_color);
519 ADD_BLEND_MODE(blend_w3c_luminosity);
520}
521
522void
523painter_cells::
524update_cts_params(void)
525{
526 const Uint8 *keyboard_state = SDL_GetKeyboardState(nullptr);
527 FASTUIDRAWassert(keyboard_state != nullptr);
528
529 float speed = static_cast<float>(m_draw_timer.restart()) * 0.001f;
530
531 if (keyboard_state[SDL_SCANCODE_LSHIFT])
532 {
533 speed *= 0.1f;
534 }
535 if (keyboard_state[SDL_SCANCODE_RSHIFT])
536 {
537 speed *= 10.0f;
538 }
539
540 if (keyboard_state[SDL_SCANCODE_RIGHTBRACKET])
541 {
542 m_cell_shared_state.m_stroke_width += m_change_stroke_width_rate.value() * speed / m_zoomer.transformation().scale();
543 }
544
545 if (keyboard_state[SDL_SCANCODE_LEFTBRACKET])
546 {
547 m_cell_shared_state.m_stroke_width -= m_change_stroke_width_rate.value() * speed / m_zoomer.transformation().scale();
548 m_cell_shared_state.m_stroke_width = std::max(m_cell_shared_state.m_stroke_width, 0.0f);
549 }
550}
551
552void
553painter_cells::
554draw_frame(void)
555{
556 uint64_t ms, us;
557 ivec2 wh(dimensions());
558
559 us = m_time.restart_us();
560 ms = us / 1000;
561
562 if (m_frame == 0)
563 {
564 m_benchmark_timer.restart();
565 }
566 else if (m_frame > 0)
567 {
568 m_frame_times.push_back(us);
569 }
570
571 if (m_num_frames.value() > 0 && m_frame == m_num_frames.value())
572 {
573 m_benchmark_time_us = m_benchmark_timer.elapsed_us();
574 std::cout << "Frame times(in us):\n";
575 for(unsigned int i = 0, endi = m_frame_times.size(); i < endi; ++i)
576 {
577 std::cout << m_frame_times[i] << " us\n";
578 }
579 std::cout << "Did " << m_num_frames.value() << " frames in "
580 << m_benchmark_time_us << "us, average time = "
581 << static_cast<float>(m_benchmark_time_us) / static_cast<float>(m_frame)
582 << "us\n " << 1000.0f * 1000.0f * static_cast<float>(m_frame) / static_cast<float>(m_benchmark_time_us)
583 << " FPS\n";
584 end_demo(0);
585 return;
586 }
587
588 update_cts_params();
589 m_cell_shared_state.m_cells_drawn = 0;
590
591 m_surface->clear_color(vec4(0.5f, 0.5f, 0.5f, 1.0f));
592 m_painter->begin(m_surface, Painter::y_increases_downwards);
593
594 m_painter->save();
595 m_painter->translate(m_zoomer.transformation().translation());
596 m_painter->scale(m_zoomer.transformation().scale());
597 /* update m_bb_min and m_bb_max as the window corners in
598 coordinates; Table will do the right thing with these numbers
599 to change them
600 */
601 m_table->m_bb_min = vec2(0.0f, 0.0f);
602 m_table->m_bb_max = vec2(wh);
603
604 m_table->paint(m_painter);
605 m_painter->restore();
606
607
608 if (m_table_params.m_timer_based_animation)
609 {
610 std::ostringstream ostr;
611
612 ostr << "\nFPS = ";
613 if (us > 0)
614 {
615 ostr << static_cast<int>(1000.0f * 1000.0f / static_cast<float>(us));
616 }
617 else
618 {
619 ostr << "NAN";
620 }
621
622 ostr << "\nms = " << ms
623 << "\nDrew " << m_cell_shared_state.m_cells_drawn << " cells";
624
625 fastuidraw::c_array<const unsigned int> stats(painter_stats());
626 for (unsigned int i = 0; i < stats.size(); ++i)
627 {
628 enum Painter::query_stats_t st;
629
630 st = static_cast<enum Painter::query_stats_t>(i);
631 ostr << "\n" << Painter::label(st) << ": " << stats[i];
632 }
633 ostr << "\ndraw_generics: " << m_painter->draw_data_added_count() << "\n";
634
635 if (!m_text_brush.packed())
636 {
637 PainterBrush brush;
638 brush.color(0.0f, 1.0f, 1.0f, 1.0f);
639 m_text_brush = m_painter->packed_value_pool().create_packed_brush(brush);
640 }
641 draw_text(ostr.str(), m_fps_pixel_size.value(),
642 m_table_params.m_font.get(), PainterData(m_text_brush));
643 }
644
645 c_array<const PainterSurface* const> surfaces;
646
647 surfaces = m_painter->end();
648 fastuidraw_glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
649 fastuidraw_glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
650
651 m_show_surface = t_min(m_show_surface, (int)surfaces.size());
652 if (m_show_surface <= 0 || m_show_surface > surfaces.size())
653 {
654 m_surface->blit_surface(GL_NEAREST);
655 }
656 else
657 {
658 const gl::PainterSurfaceGL *S;
659 PainterSurface::Viewport src, dest;
660
661 src = m_surface->viewport();
662 S = dynamic_cast<const gl::PainterSurfaceGL*>(surfaces[m_show_surface - 1]);
663
664 dest.m_origin = src.m_origin;
665 dest.m_dimensions = ivec2(src.m_dimensions.x(), src.m_dimensions.y() / 2);
666 m_surface->blit_surface(src, dest, GL_LINEAR);
667
668 dest.m_origin.y() += dest.m_dimensions.y();
669 S->blit_surface(src, dest, GL_LINEAR);
670 }
671
672 if (m_last_shown_surface != m_show_surface)
673 {
674 if (m_show_surface > 0)
675 {
676 std::cout << "Show offscreen surface: " << m_show_surface - 1 << "\n";
677 }
678 else
679 {
680 std::cout << "Don't show offscreen surface\n";
681 }
682 m_last_shown_surface = m_show_surface;
683 }
684 ++m_frame;
685}
686
687void
688painter_cells::
689handle_event(const SDL_Event &ev)
690{
691 m_zoomer.handle_event(ev);
692
693 switch(ev.type)
694 {
695 case SDL_QUIT:
696 end_demo(0);
697 break;
698
699 case SDL_WINDOWEVENT:
700 if (ev.window.event == SDL_WINDOWEVENT_RESIZED)
701 {
702 on_resize(ev.window.data1, ev.window.data2);
703 }
704 break;
705
706 case SDL_KEYUP:
707 switch(ev.key.keysym.sym)
708 {
709 case SDLK_ESCAPE:
710 end_demo(0);
711 break;
712 case SDLK_a:
713 if (m_cell_shared_state.m_stroke_width > 0.0f)
714 {
715 m_cell_shared_state.m_anti_alias_stroking = !m_cell_shared_state.m_anti_alias_stroking;
716 std::cout << "Stroking anti-aliasing = "
717 << m_cell_shared_state.m_anti_alias_stroking
718 << "\n";
719 }
720 break;
721 case SDLK_v:
722 m_table->m_rotating = !m_table->m_rotating;
723 std::cout << "Table Rotating = " << m_table->m_rotating << "\n";
724 break;
725 case SDLK_c:
726 m_table->m_clipped = !m_table->m_clipped;
727 std::cout << "Table clipped = " << m_table->m_clipped << "\n";
728 break;
729 case SDLK_p:
730 m_cell_shared_state.m_pause = !m_cell_shared_state.m_pause;
731 std::cout << "Paused = " << m_cell_shared_state.m_pause << "\n";
732 break;
733 case SDLK_r:
734 m_cell_shared_state.m_rotating = !m_cell_shared_state.m_rotating;
735 std::cout << "Cell Rotating = " << m_cell_shared_state.m_rotating << "\n";
736 break;
737 case SDLK_t:
738 m_cell_shared_state.m_draw_text = !m_cell_shared_state.m_draw_text;
739 std::cout << "Draw Text = " << m_cell_shared_state.m_draw_text << "\n";
740 break;
741 case SDLK_i:
742 m_cell_shared_state.m_draw_image = !m_cell_shared_state.m_draw_image;
743 std::cout << "Draw Image = " << m_cell_shared_state.m_draw_image << "\n";
744 break;
745 case SDLK_b:
746 cycle_value(m_current_blend, ev.key.keysym.mod & (KMOD_SHIFT | KMOD_ALT | KMOD_CTRL), m_blend_labels.size());
747 std::cout << "Rect Blend mode set to: " << m_blend_labels[m_current_blend].second << "\n";
748 m_cell_shared_state.m_rect_blend_mode = m_blend_labels[m_current_blend].first;
749 break;
750 case SDLK_y:
751 m_cell_shared_state.m_draw_transparent = !m_cell_shared_state.m_draw_transparent;
752 if (m_cell_shared_state.m_draw_transparent)
753 {
754 std::cout << "Draw cells transparently\n";
755 }
756 else
757 {
758 std::cout << "Draw cells opaquely\n";
759 }
760 break;
761
762 case SDLK_o:
763 if (ev.key.keysym.mod & (KMOD_SHIFT | KMOD_ALT))
764 {
765 if (m_show_surface > 0)
766 {
767 --m_show_surface;
768 }
769 }
770 else
771 {
772 ++m_show_surface;
773 }
774 break;
775
776 case SDLK_0:
777 m_zoomer.transformation(ScaleTranslate<float>());
778 break;
779 }
780 break;
781 }
782}
783
784int
785main(int argc, char **argv)
786{
787 painter_cells P;
788 return P.main(argc, argv);
789}
790