1 #include <stdio.h>
2 #include "agg_basics.h"
3 #include "agg_rendering_buffer.h"
4 #include "agg_rasterizer_scanline_aa.h"
5 #include "agg_scanline_u.h"
6 #include "agg_scanline_p.h"
7 #include "agg_scanline_bin.h"
8 #include "agg_renderer_scanline.h"
9 #include "agg_renderer_primitives.h"
10 #include "agg_span_solid.h"
11 #include "agg_conv_curve.h"
12 #include "agg_conv_stroke.h"
13 #include "agg_gsv_text.h"
14 #include "agg_pixfmt_rgb.h"
15 #include "agg_scanline_boolean_algebra.h"
16 #include "agg_scanline_storage_aa.h"
17 #include "agg_scanline_storage_bin.h"
18 #include "platform/agg_platform_support.h"
19
20 #include "ctrl/agg_slider_ctrl.h"
21 #include "ctrl/agg_cbox_ctrl.h"
22 #include "ctrl/agg_rbox_ctrl.h"
23
24
25 enum flip_y_e { flip_y = true };
26
27
28
29
30 class spiral
31 {
32 public:
spiral(double x,double y,double r1,double r2,double step,double start_angle=0)33 spiral(double x, double y, double r1, double r2, double step, double start_angle=0) :
34 m_x(x),
35 m_y(y),
36 m_r1(r1),
37 m_r2(r2),
38 m_step(step),
39 m_start_angle(start_angle),
40 m_angle(start_angle),
41 m_da(agg::deg2rad(4.0)),
42 m_dr(m_step / 90.0)
43 {
44 }
45
rewind(unsigned)46 void rewind(unsigned)
47 {
48 m_angle = m_start_angle;
49 m_curr_r = m_r1;
50 m_start = true;
51 }
52
vertex(double * x,double * y)53 unsigned vertex(double* x, double* y)
54 {
55 if(m_curr_r > m_r2) return agg::path_cmd_stop;
56
57 *x = m_x + cos(m_angle) * m_curr_r;
58 *y = m_y + sin(m_angle) * m_curr_r;
59 m_curr_r += m_dr;
60 m_angle += m_da;
61 if(m_start)
62 {
63 m_start = false;
64 return agg::path_cmd_move_to;
65 }
66 return agg::path_cmd_line_to;
67 }
68
69 private:
70 double m_x;
71 double m_y;
72 double m_r1;
73 double m_r2;
74 double m_step;
75 double m_start_angle;
76
77 double m_angle;
78 double m_curr_r;
79 double m_da;
80 double m_dr;
81 bool m_start;
82 };
83
84
85
86 template<class Rasterizer, class Scanline>
count_spans(Rasterizer & ras,Scanline & sl)87 unsigned count_spans(Rasterizer& ras, Scanline& sl)
88 {
89 unsigned n = 0;
90 if(ras.rewind_scanlines())
91 {
92 sl.reset(ras.min_x(), ras.max_x());
93 while(ras.sweep_scanline(sl))
94 {
95 n += sl.num_spans();
96 }
97 }
98 return n;
99 }
100
101
102
103 void make_gb_poly(agg::path_storage& ps);
104 void make_arrows(agg::path_storage& ps);
105
106
107 class the_application : public agg::platform_support
108 {
109 typedef agg::pixfmt_bgr24 pixfmt_type;
110
111 agg::rbox_ctrl<agg::rgba8> m_polygons;
112 agg::rbox_ctrl<agg::rgba8> m_fill_rule;
113 agg::rbox_ctrl<agg::rgba8> m_scanline_type;
114 agg::rbox_ctrl<agg::rgba8> m_operation;
115 double m_x;
116 double m_y;
117
118 public:
the_application(agg::pix_format_e format,bool flip_y)119 the_application(agg::pix_format_e format, bool flip_y) :
120 agg::platform_support(format, flip_y),
121 m_polygons (5.0, 5.0, 5.0+205.0, 110.0, !flip_y),
122 m_fill_rule (200, 5.0, 200+105.0, 50.0, !flip_y),
123 m_scanline_type(300, 5.0, 300+115.0, 70.0, !flip_y),
124 m_operation (535.0, 5.0, 535.0+115.0, 145.0, !flip_y)
125 {
126 m_operation.add_item("None");
127 m_operation.add_item("OR");
128 m_operation.add_item("AND");
129 m_operation.add_item("XOR Linear");
130 m_operation.add_item("XOR Saddle");
131 m_operation.add_item("A-B");
132 m_operation.add_item("B-A");
133 m_operation.cur_item(2);
134 add_ctrl(m_operation);
135 m_operation.no_transform();
136
137 m_fill_rule.add_item("Even-Odd");
138 m_fill_rule.add_item("Non Zero");
139 m_fill_rule.cur_item(1);
140 add_ctrl(m_fill_rule);
141 m_fill_rule.no_transform();
142
143 m_scanline_type.add_item("scanline_p");
144 m_scanline_type.add_item("scanline_u");
145 m_scanline_type.add_item("scanline_bin");
146 m_scanline_type.cur_item(1);
147 add_ctrl(m_scanline_type);
148 m_scanline_type.no_transform();
149
150 m_polygons.add_item("Two Simple Paths");
151 m_polygons.add_item("Closed Stroke");
152 m_polygons.add_item("Great Britain and Arrows");
153 m_polygons.add_item("Great Britain and Spiral");
154 m_polygons.add_item("Spiral and Glyph");
155 m_polygons.cur_item(3);
156 add_ctrl(m_polygons);
157 m_polygons.no_transform();
158 }
159
160
161
162
163 template<class Rasterizer>
render_scanline_boolean(Rasterizer & ras1,Rasterizer & ras2)164 void render_scanline_boolean(Rasterizer& ras1, Rasterizer& ras2)
165 {
166 if(m_operation.cur_item() > 0)
167 {
168 agg::sbool_op_e op;
169 switch(m_operation.cur_item())
170 {
171 case 1: op = agg::sbool_or; break;
172 case 2: op = agg::sbool_and; break;
173 case 3: op = agg::sbool_xor; break;
174 case 4: op = agg::sbool_xor_saddle;break;
175 case 5: op = agg::sbool_a_minus_b; break;
176 case 6: op = agg::sbool_b_minus_a; break;
177 }
178
179 typedef agg::renderer_base<pixfmt_type> renderer_base;
180 pixfmt_type pixf(rbuf_window());
181 renderer_base rb(pixf);
182
183 double t1 = 0.0;
184 double t2 = 0.0;
185 unsigned num_spans = 0;
186
187 switch(m_scanline_type.cur_item())
188 {
189 case 0:
190 {
191 typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_solid;
192 typedef agg::scanline_p8 scanline_type;
193
194 renderer_solid ren(rb);
195
196 scanline_type sl;
197 scanline_type sl1;
198 scanline_type sl2;
199
200 // The intermediate storage is used only to test the perfoprmance,
201 // the short variant can be as follows:
202 // ------------------------
203 // ren.color(agg::rgba(0.5, 0.0, 0, 0.5));
204 // agg::sbool_combine_shapes_aa(op, ras1, ras2, sl1, sl2, sl, ren);
205
206 agg::scanline_storage_aa8 storage;
207 agg::scanline_storage_aa8 storage1;
208 agg::scanline_storage_aa8 storage2;
209
210 agg::render_scanlines(ras1, sl, storage1);
211 agg::render_scanlines(ras2, sl, storage2);
212
213 start_timer();
214 for(int i = 0; i < 10; i++)
215 {
216 agg::sbool_combine_shapes_aa(op, storage1, storage2, sl1, sl2, sl, storage);
217 }
218 t1 = elapsed_time() / 10.0;
219
220 start_timer();
221 ren.color(agg::rgba(0.5, 0.0, 0, 0.5));
222 agg::render_scanlines(storage, sl, ren);
223 t2 = elapsed_time();
224
225 num_spans = count_spans(storage, sl);
226 }
227 break;
228
229 case 1:
230 {
231 typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_solid;
232 typedef agg::scanline_u8 scanline_type;
233
234 renderer_solid ren(rb);
235
236 scanline_type sl;
237 scanline_type sl1;
238 scanline_type sl2;
239 agg::scanline_storage_aa8 storage;
240 agg::scanline_storage_aa8 storage1;
241 agg::scanline_storage_aa8 storage2;
242
243 agg::render_scanlines(ras1, sl, storage1);
244 agg::render_scanlines(ras2, sl, storage2);
245
246 start_timer();
247 for(int i = 0; i < 10; i++)
248 {
249 agg::sbool_combine_shapes_aa(op, storage1, storage2, sl1, sl2, sl, storage);
250 }
251 t1 = elapsed_time() / 10.0;
252
253 start_timer();
254 ren.color(agg::rgba(0.5, 0.0, 0, 0.5));
255 agg::render_scanlines(storage, sl, ren);
256 t2 = elapsed_time();
257
258 num_spans = count_spans(storage, sl);
259 }
260 break;
261
262
263 case 2:
264 {
265 typedef agg::renderer_scanline_bin_solid<renderer_base> renderer_solid;
266 typedef agg::scanline_bin scanline_type;
267
268 renderer_solid ren(rb);
269
270 scanline_type sl;
271 scanline_type sl1;
272 scanline_type sl2;
273
274 agg::scanline_storage_bin storage;
275 agg::scanline_storage_bin storage1;
276 agg::scanline_storage_bin storage2;
277
278 agg::render_scanlines(ras1, sl, storage1);
279 agg::render_scanlines(ras2, sl, storage2);
280
281 start_timer();
282 for(int i = 0; i < 10; i++)
283 {
284 agg::sbool_combine_shapes_bin(op, storage1, storage2, sl1, sl2, sl, storage);
285 }
286 t1 = elapsed_time() / 10.0;
287
288 start_timer();
289 ren.color(agg::rgba(0.5, 0.0, 0, 0.5));
290 agg::render_scanlines(storage, sl, ren);
291 t2 = elapsed_time();
292
293 num_spans = count_spans(storage, sl);
294 }
295 break;
296
297 }
298
299
300 char buf[100];
301 sprintf(buf, "Combine=%.3fms\n\nRender=%.3fms\n\nnum_spans=%d", t1, t2, num_spans);
302 agg::renderer_scanline_aa_solid<renderer_base> ren(rb);
303 agg::scanline_p8 sl;
304 agg::gsv_text txt;
305 agg::conv_stroke<agg::gsv_text> txt_stroke(txt);
306 txt_stroke.width(1.0);
307 txt_stroke.line_cap(agg::round_cap);
308 txt.size(8.0);
309 txt.start_point(420, 40);
310 txt.text(buf);
311 ras1.add_path(txt_stroke);
312 ren.color(agg::rgba(0.0, 0.0, 0.0));
313 agg::render_scanlines(ras1, sl, ren);
314
315
316 }
317 }
318
319
320
321
322 template<class Rasterizer>
render_sbool(Rasterizer & ras1,Rasterizer & ras2)323 unsigned render_sbool(Rasterizer& ras1, Rasterizer& ras2)
324 {
325 pixfmt_type pf(rbuf_window());
326 agg::renderer_base<pixfmt_type> rb(pf);
327 agg::renderer_scanline_aa_solid<agg::renderer_base<pixfmt_type> > ren(rb);
328 agg::scanline_p8 sl;
329
330 ras1.filling_rule(m_fill_rule.cur_item() ? agg::fill_non_zero : agg::fill_even_odd);
331 ras2.filling_rule(m_fill_rule.cur_item() ? agg::fill_non_zero : agg::fill_even_odd);
332
333 switch(m_polygons.cur_item())
334 {
335 case 0:
336 {
337 //------------------------------------
338 // Two simple paths
339 //
340 agg::path_storage ps1;
341 agg::path_storage ps2;
342
343 double x = m_x - initial_width()/2 + 100;
344 double y = m_y - initial_height()/2 + 100;
345 ps1.move_to(x+140, y+145);
346 ps1.line_to(x+225, y+44);
347 ps1.line_to(x+296, y+219);
348 ps1.close_polygon();
349
350 ps1.line_to(x+226, y+289);
351 ps1.line_to(x+82, y+292);
352
353 ps1.move_to(x+220, y+222);
354 ps1.line_to(x+363, y+249);
355 ps1.line_to(x+265, y+331);
356
357 ps1.move_to(x+242, y+243);
358 ps1.line_to(x+325, y+261);
359 ps1.line_to(x+268, y+309);
360
361 ps1.move_to(x+259, y+259);
362 ps1.line_to(x+273, y+288);
363 ps1.line_to(x+298, y+266);
364
365 ps2.move_to(100+32, 100+77);
366 ps2.line_to(100+473, 100+263);
367 ps2.line_to(100+351, 100+290);
368 ps2.line_to(100+354, 100+374);
369
370 ras1.reset();
371 ras1.add_path(ps1);
372 ren.color(agg::rgba(0, 0, 0, 0.1));
373 agg::render_scanlines(ras1, sl, ren);
374
375 ras2.reset();
376 ras2.add_path(ps2);
377 ren.color(agg::rgba(0, 0.6, 0, 0.1));
378 agg::render_scanlines(ras2, sl, ren);
379
380 render_scanline_boolean(ras1, ras2);
381 }
382 break;
383
384 case 1:
385 {
386 //------------------------------------
387 // Closed stroke
388 //
389 agg::path_storage ps1;
390 agg::path_storage ps2;
391 agg::conv_stroke<agg::path_storage> stroke(ps2);
392 stroke.width(15.0);
393
394 double x = m_x - initial_width()/2 + 100;
395 double y = m_y - initial_height()/2 + 100;
396 ps1.move_to(x+140, y+145);
397 ps1.line_to(x+225, y+44);
398 ps1.line_to(x+296, y+219);
399 ps1.close_polygon();
400
401 ps1.line_to(x+226, y+289);
402 ps1.line_to(x+82, y+292);
403
404 ps1.move_to(x+220-50, y+222);
405 ps1.line_to(x+363-50, y+249);
406 ps1.line_to(x+265-50, y+331);
407 ps1.close_polygon();
408
409 ps2.move_to(100+32, 100+77);
410 ps2.line_to(100+473, 100+263);
411 ps2.line_to(100+351, 100+290);
412 ps2.line_to(100+354, 100+374);
413 ps2.close_polygon();
414
415 ras1.reset();
416 ras1.add_path(ps1);
417 ren.color(agg::rgba(0, 0, 0, 0.1));
418 agg::render_scanlines(ras1, sl, ren);
419
420 ras2.reset();
421 ras2.add_path(stroke);
422 ren.color(agg::rgba(0, 0.6, 0, 0.1));
423 agg::render_scanlines(ras2, sl, ren);
424
425 render_scanline_boolean(ras1, ras2);
426 }
427 break;
428
429
430 case 2:
431 {
432 //------------------------------------
433 // Great Britain and Arrows
434 //
435 agg::path_storage gb_poly;
436 agg::path_storage arrows;
437 make_gb_poly(gb_poly);
438 make_arrows(arrows);
439
440 agg::trans_affine mtx1;
441 agg::trans_affine mtx2;
442 mtx1 *= agg::trans_affine_translation(-1150, -1150);
443 mtx1 *= agg::trans_affine_scaling(2.0);
444
445 mtx2 = mtx1;
446 mtx2 *= agg::trans_affine_translation(m_x - initial_width()/2,
447 m_y - initial_height()/2);
448
449 agg::conv_transform<agg::path_storage> trans_gb_poly(gb_poly, mtx1);
450 agg::conv_transform<agg::path_storage> trans_arrows(arrows, mtx2);
451
452 ras2.add_path(trans_gb_poly);
453 ren.color(agg::rgba(0.5, 0.5, 0, 0.1));
454 agg::render_scanlines(ras2, sl, ren);
455
456 agg::conv_stroke<agg::conv_transform<agg::path_storage> > stroke_gb_poly(trans_gb_poly);
457 stroke_gb_poly.width(0.1);
458 ras1.add_path(stroke_gb_poly);
459 ren.color(agg::rgba(0, 0, 0));
460 agg::render_scanlines(ras1, sl, ren);
461
462 ras2.add_path(trans_arrows);
463 ren.color(agg::rgba(0.0, 0.5, 0.5, 0.1));
464 agg::render_scanlines(ras2, sl, ren);
465
466 ras1.reset();
467 ras1.add_path(trans_gb_poly);
468
469 render_scanline_boolean(ras1, ras2);
470 }
471 break;
472
473
474 case 3:
475 {
476 //------------------------------------
477 // Great Britain and a Spiral
478 //
479 spiral sp(m_x, m_y, 10, 150, 30, 0.0);
480 agg::conv_stroke<spiral> stroke(sp);
481 stroke.width(15.0);
482
483 agg::path_storage gb_poly;
484 make_gb_poly(gb_poly);
485
486 agg::trans_affine mtx;
487 mtx *= agg::trans_affine_translation(-1150, -1150);
488 mtx *= agg::trans_affine_scaling(2.0);
489 mtx *= trans_affine_resizing();
490
491 agg::conv_transform<agg::path_storage> trans_gb_poly(gb_poly, mtx);
492
493
494 ras1.add_path(trans_gb_poly);
495 ren.color(agg::rgba(0.5, 0.5, 0, 0.1));
496 agg::render_scanlines(ras1, sl, ren);
497
498 agg::conv_stroke<agg::conv_transform<agg::path_storage> > stroke_gb_poly(trans_gb_poly);
499 stroke_gb_poly.width(0.1);
500 ras1.reset();
501 ras1.add_path(stroke_gb_poly);
502 ren.color(agg::rgba(0, 0, 0));
503 agg::render_scanlines(ras1, sl, ren);
504
505 ras2.reset();
506 ras2.add_path(stroke);
507 ren.color(agg::rgba(0.0, 0.5, 0.5, 0.1));
508 agg::render_scanlines(ras2, sl, ren);
509
510 ras1.reset();
511 ras1.add_path(trans_gb_poly);
512 render_scanline_boolean(ras1, ras2);
513 }
514 break;
515
516
517 case 4:
518 {
519 //------------------------------------
520 // Spiral and glyph
521 //
522 spiral sp(m_x, m_y, 10, 150, 30, 0.0);
523 agg::conv_stroke<spiral> stroke(sp);
524 stroke.width(15.0);
525
526 agg::path_storage glyph;
527 glyph.move_to(28.47, 6.45);
528 glyph.curve3(21.58, 1.12, 19.82, 0.29);
529 glyph.curve3(17.19, -0.93, 14.21, -0.93);
530 glyph.curve3(9.57, -0.93, 6.57, 2.25);
531 glyph.curve3(3.56, 5.42, 3.56, 10.60);
532 glyph.curve3(3.56, 13.87, 5.03, 16.26);
533 glyph.curve3(7.03, 19.58, 11.99, 22.51);
534 glyph.curve3(16.94, 25.44, 28.47, 29.64);
535 glyph.line_to(28.47, 31.40);
536 glyph.curve3(28.47, 38.09, 26.34, 40.58);
537 glyph.curve3(24.22, 43.07, 20.17, 43.07);
538 glyph.curve3(17.09, 43.07, 15.28, 41.41);
539 glyph.curve3(13.43, 39.75, 13.43, 37.60);
540 glyph.line_to(13.53, 34.77);
541 glyph.curve3(13.53, 32.52, 12.38, 31.30);
542 glyph.curve3(11.23, 30.08, 9.38, 30.08);
543 glyph.curve3(7.57, 30.08, 6.42, 31.35);
544 glyph.curve3(5.27, 32.62, 5.27, 34.81);
545 glyph.curve3(5.27, 39.01, 9.57, 42.53);
546 glyph.curve3(13.87, 46.04, 21.63, 46.04);
547 glyph.curve3(27.59, 46.04, 31.40, 44.04);
548 glyph.curve3(34.28, 42.53, 35.64, 39.31);
549 glyph.curve3(36.52, 37.21, 36.52, 30.71);
550 glyph.line_to(36.52, 15.53);
551 glyph.curve3(36.52, 9.13, 36.77, 7.69);
552 glyph.curve3(37.01, 6.25, 37.57, 5.76);
553 glyph.curve3(38.13, 5.27, 38.87, 5.27);
554 glyph.curve3(39.65, 5.27, 40.23, 5.62);
555 glyph.curve3(41.26, 6.25, 44.19, 9.18);
556 glyph.line_to(44.19, 6.45);
557 glyph.curve3(38.72, -0.88, 33.74, -0.88);
558 glyph.curve3(31.35, -0.88, 29.93, 0.78);
559 glyph.curve3(28.52, 2.44, 28.47, 6.45);
560 glyph.close_polygon();
561
562 glyph.move_to(28.47, 9.62);
563 glyph.line_to(28.47, 26.66);
564 glyph.curve3(21.09, 23.73, 18.95, 22.51);
565 glyph.curve3(15.09, 20.36, 13.43, 18.02);
566 glyph.curve3(11.77, 15.67, 11.77, 12.89);
567 glyph.curve3(11.77, 9.38, 13.87, 7.06);
568 glyph.curve3(15.97, 4.74, 18.70, 4.74);
569 glyph.curve3(22.41, 4.74, 28.47, 9.62);
570 glyph.close_polygon();
571
572 agg::trans_affine mtx;
573 mtx *= agg::trans_affine_scaling(4.0);
574 mtx *= agg::trans_affine_translation(220, 200);
575 agg::conv_transform<agg::path_storage> trans(glyph, mtx);
576 agg::conv_curve<agg::conv_transform<agg::path_storage> > curve(trans);
577
578 ras1.reset();
579 ras1.add_path(stroke);
580 ren.color(agg::rgba(0, 0, 0, 0.1));
581 agg::render_scanlines(ras1, sl, ren);
582
583 ras2.reset();
584 ras2.add_path(curve);
585 ren.color(agg::rgba(0, 0.6, 0, 0.1));
586 agg::render_scanlines(ras2, sl, ren);
587
588 render_scanline_boolean(ras1, ras2);
589 }
590 break;
591 }
592
593 return 0;
594 }
595
596
on_init()597 virtual void on_init()
598 {
599 m_x = width() / 2.0;
600 m_y = height() / 2.0;
601 }
602
on_draw()603 virtual void on_draw()
604 {
605 typedef agg::renderer_base<pixfmt_type> base_ren_type;
606 typedef agg::renderer_scanline_aa_solid<base_ren_type> renderer_solid;
607
608 agg::pixfmt_bgr24 pf(rbuf_window());
609 base_ren_type ren_base(pf);
610 renderer_solid ren_solid(ren_base);
611 ren_base.clear(agg::rgba(1,1,1));
612
613 agg::scanline_u8 sl;
614 agg::rasterizer_scanline_aa<> ras;
615 agg::rasterizer_scanline_aa<> ras2;
616
617 agg::render_ctrl(ras, sl, ren_base, m_polygons);
618 agg::render_ctrl(ras, sl, ren_base, m_fill_rule);
619 agg::render_ctrl(ras, sl, ren_base, m_scanline_type);
620 agg::render_ctrl(ras, sl, ren_base, m_operation);
621
622 render_sbool(ras, ras2);
623
624 }
625
626
627
628
on_mouse_button_down(int x,int y,unsigned flags)629 virtual void on_mouse_button_down(int x, int y, unsigned flags)
630 {
631 if(flags & agg::mouse_left)
632 {
633 m_x = x;
634 m_y = y;
635 force_redraw();
636 }
637
638 if(flags & agg::mouse_right)
639 {
640 char buf[100];
641 sprintf(buf, "%d %d", x, y);
642 message(buf);
643 }
644 }
645
646
on_mouse_move(int x,int y,unsigned flags)647 virtual void on_mouse_move(int x, int y, unsigned flags)
648 {
649 if(flags & agg::mouse_left)
650 {
651 m_x = x;
652 m_y = y;
653 force_redraw();
654 }
655 }
656
657
658
659 };
660
661
662
agg_main(int argc,char * argv[])663 int agg_main(int argc, char* argv[])
664 {
665 the_application app(agg::pix_format_bgr24, flip_y);
666 app.caption("AGG Example. Scanline Boolean");
667
668 if(app.init(655, 520, agg::window_resize))
669 {
670 return app.run();
671 }
672 return 1;
673 }
674
675
676