bl_bench_backend_agg.cpp (50584B)
1 // This file is part of Blend2D project <https://blend2d.com> 2 // 3 // See LICENSE.md for license and copyright information 4 // SPDX-License-Identifier: Zlib 5 6 #ifdef BL_BENCH_ENABLE_AGG 7 8 #include "bl_bench_app.h" 9 #include "bl_bench_backend.h" 10 11 #include <algorithm> 12 #include <cmath> 13 14 #include "agg_basics.h" 15 #include "agg_bezier_arc.h" 16 #include "agg_conv_curve.h" 17 #include "agg_conv_stroke.h" 18 #include "agg_conv_transform.h" 19 #include "agg_font_cache_manager.h" 20 #include "agg_gamma_functions.h" 21 #include "agg_image_accessors.h" 22 #include "agg_path_storage.h" 23 #include "agg_pixfmt_rgba.h" 24 #include "agg_rasterizer_scanline_aa.h" 25 #include "agg_rasterizer_scanline_aa_nogamma.h" 26 #include "agg_renderer_base.h" 27 #include "agg_renderer_scanline.h" 28 #include "agg_rendering_buffer.h" 29 #include "agg_rounded_rect.h" 30 #include "agg_scanline_u.h" 31 #include "agg_span_allocator.h" 32 #include "agg_span_converter.h" 33 #include "agg_span_gradient.h" 34 #include "agg_span_image_filter_rgba.h" 35 #include "agg_span_interpolator_linear.h" 36 #include "agg_trans_affine.h" 37 #include "agg_trans_viewport.h" 38 39 // AGG Benchmarking - Agg2D Abstraction 40 // ==================================== 41 42 // Agg2D - Version 1.0 (with modifications) 43 // Based on Anti-Grain Geometry 44 // Copyright (C) 2005 Maxim Shemanarev (http://www.antigrain.com) 45 // 46 // Permission to copy, use, modify, sell and distribute this software 47 // is granted provided this copyright notice appears in all copies. 48 // This software is provided "as is" without express or implied 49 // warranty, and with no claim as to its suitability for any purpose. 50 // 51 // Modifications: 52 // 25 Jan 2007 - Ported to AGG 2.4 Jerry Evans (jerry@novadsp.com) 53 // 21 June 2023 - Modified to only provide the required API for benchmarks 54 static const double g_approxScale = 2.0; 55 56 class Agg2D { 57 typedef agg::order_bgra ComponentOrder; 58 59 typedef agg::rgba8 ColorType; 60 typedef agg::blender_rgba_pre<ColorType, ComponentOrder> BlenderPre; 61 typedef agg::comp_op_adaptor_rgba_pre<ColorType, ComponentOrder> BlenderCompPre; 62 63 typedef agg::pixfmt_bgra32_pre PixFormatPre; 64 typedef agg::pixfmt_custom_blend_rgba<BlenderCompPre,agg::rendering_buffer> PixFormatCompPre; 65 66 typedef agg::renderer_base<PixFormatPre> RendererBasePre; 67 typedef agg::renderer_base<PixFormatCompPre> RendererBaseCompPre; 68 69 typedef agg::renderer_scanline_aa_solid<RendererBasePre> RendererSolid; 70 typedef agg::renderer_scanline_aa_solid<RendererBaseCompPre> RendererSolidComp; 71 72 typedef agg::span_allocator<ColorType> SpanAllocator; 73 typedef agg::pod_auto_array<ColorType, 256> GradientArray; 74 75 typedef agg::span_gradient<ColorType, agg::span_interpolator_linear<>, agg::gradient_x, GradientArray> LinearGradientSpan; 76 typedef agg::span_gradient<ColorType, agg::span_interpolator_linear<>, agg::gradient_circle, GradientArray> RadialGradientSpan; 77 typedef agg::span_gradient<ColorType, agg::span_interpolator_linear<>, agg::gradient_conic , GradientArray> ConicGradientSpan; 78 79 typedef agg::conv_curve<agg::path_storage> ConvCurve; 80 typedef agg::conv_stroke<ConvCurve> ConvStroke; 81 typedef agg::conv_transform<ConvCurve> PathTransform; 82 typedef agg::conv_transform<ConvStroke> StrokeTransform; 83 84 enum StyleFlag { 85 None, 86 Solid, 87 Linear, 88 Radial 89 }; 90 91 public: 92 friend class Agg2DRenderer; 93 94 typedef ColorType Color; 95 typedef agg::rect_i Rect; 96 typedef agg::rect_d RectD; 97 typedef agg::trans_affine Affine; 98 99 enum StyleSlot { 100 FillSlot, 101 StrokeSlot 102 }; 103 104 enum LineJoin { 105 JoinMiter = agg::miter_join, 106 JoinRound = agg::round_join, 107 JoinBevel = agg::bevel_join 108 }; 109 110 enum LineCap { 111 CapButt = agg::butt_cap, 112 CapSquare = agg::square_cap, 113 CapRound = agg::round_cap 114 }; 115 116 enum DrawPathFlag { 117 FillOnly, 118 StrokeOnly, 119 FillAndStroke, 120 FillWithLineColor 121 }; 122 123 enum ImageFilter { 124 NoFilter, 125 Bilinear 126 }; 127 128 enum ImageResample { 129 NoResample, 130 ResampleAlways, 131 ResampleOnZoomOut 132 }; 133 134 enum BlendMode { 135 BlendAlpha = agg::end_of_comp_op_e, 136 BlendClear = agg::comp_op_clear, 137 BlendSrc = agg::comp_op_src, 138 BlendDst = agg::comp_op_dst, 139 BlendSrcOver = agg::comp_op_src_over, 140 BlendDstOver = agg::comp_op_dst_over, 141 BlendSrcIn = agg::comp_op_src_in, 142 BlendDstIn = agg::comp_op_dst_in, 143 BlendSrcOut = agg::comp_op_src_out, 144 BlendDstOut = agg::comp_op_dst_out, 145 BlendSrcAtop = agg::comp_op_src_atop, 146 BlendDstAtop = agg::comp_op_dst_atop, 147 BlendXor = agg::comp_op_xor, 148 BlendAdd = agg::comp_op_plus, 149 BlendMultiply = agg::comp_op_multiply, 150 BlendScreen = agg::comp_op_screen, 151 BlendOverlay = agg::comp_op_overlay, 152 BlendDarken = agg::comp_op_darken, 153 BlendLighten = agg::comp_op_lighten, 154 BlendColorDodge = agg::comp_op_color_dodge, 155 BlendColorBurn = agg::comp_op_color_burn, 156 BlendHardLight = agg::comp_op_hard_light, 157 BlendSoftLight = agg::comp_op_soft_light, 158 BlendDifference = agg::comp_op_difference, 159 BlendExclusion = agg::comp_op_exclusion 160 }; 161 162 enum Direction { 163 CW, CCW 164 }; 165 166 struct Transformations { 167 double affineMatrix[6]; 168 }; 169 170 struct Image { 171 agg::rendering_buffer renBuf; 172 173 Image() {} 174 Image(unsigned char* buf, unsigned width, unsigned height, int stride) : 175 renBuf(buf, width, height, stride) {} 176 177 void attach(unsigned char* buf, unsigned width, unsigned height, int stride) { 178 renBuf.attach(buf, width, height, stride); 179 } 180 181 int width() const { return renBuf.width(); } 182 int height() const { return renBuf.height(); } 183 }; 184 185 private: 186 agg::rendering_buffer m_rbuf; 187 PixFormatPre m_pixFormatPre; 188 PixFormatCompPre m_pixFormatCompPre; 189 RendererBasePre m_renBasePre; 190 RendererBaseCompPre m_renBaseCompPre; 191 RendererSolid m_renSolid; 192 RendererSolidComp m_renSolidComp; 193 194 SpanAllocator m_allocator; 195 RectD m_clipBox; 196 197 BlendMode m_blendMode; 198 BlendMode m_imageBlendMode; 199 Color m_imageBlendColor; 200 201 agg::scanline_u8 m_scanline; 202 agg::rasterizer_scanline_aa_nogamma<> m_rasterizer; 203 double m_masterAlpha; 204 205 Color m_color[2]; 206 GradientArray m_gradient[2]; 207 208 LineCap m_lineCap; 209 LineJoin m_lineJoin; 210 211 StyleFlag m_styleFlag[2]; 212 agg::trans_affine m_gradientMatrix[2]; 213 double m_gradientD1[2]; 214 double m_gradientD2[2]; 215 216 ImageFilter m_imageFilter; 217 ImageResample m_imageResample; 218 agg::image_filter_lut m_imageFilterLut; 219 220 agg::span_interpolator_linear<> m_gradientInterpolator[2]; 221 222 agg::gradient_x m_linearGradientFunction; 223 agg::gradient_circle m_radialGradientFunction; 224 225 double m_lineWidth; 226 bool m_evenOddFlag; 227 228 agg::path_storage m_path; 229 agg::trans_affine m_transform; 230 231 ConvCurve m_convCurve; 232 ConvStroke m_convStroke; 233 234 PathTransform m_pathTransform; 235 StrokeTransform m_strokeTransform; 236 237 public: 238 Agg2D() : 239 m_rbuf(), 240 m_pixFormatPre(m_rbuf), 241 m_pixFormatCompPre(m_rbuf), 242 m_renBasePre(m_pixFormatPre), 243 m_renBaseCompPre(m_pixFormatCompPre), 244 m_renSolid(m_renBasePre), 245 m_renSolidComp(m_renBaseCompPre), 246 247 m_allocator(), 248 m_clipBox(0,0,0,0), 249 250 m_blendMode(BlendSrcOver), 251 m_imageBlendMode(BlendDst), 252 m_imageBlendColor(0,0,0), 253 254 m_scanline(), 255 m_rasterizer(), 256 257 m_masterAlpha(1.0), 258 259 m_color{}, 260 m_gradient{}, 261 262 m_lineCap(CapRound), 263 m_lineJoin(JoinRound), 264 265 m_styleFlag{Solid, Solid}, 266 m_gradientMatrix{}, 267 m_gradientD1{0.0, 0.0}, 268 m_gradientD2{100.0, 100.0}, 269 270 m_imageFilter(Bilinear), 271 m_imageResample(NoResample), 272 m_imageFilterLut(agg::image_filter_bilinear(), true), 273 274 m_gradientInterpolator{m_gradientMatrix[0], m_gradientMatrix[1]}, 275 m_linearGradientFunction(), 276 m_radialGradientFunction(), 277 278 m_lineWidth(1), 279 m_evenOddFlag(false), 280 281 m_path(), 282 m_transform(), 283 284 m_convCurve(m_path), 285 m_convStroke(m_convCurve), 286 287 m_pathTransform(m_convCurve, m_transform), 288 m_strokeTransform(m_convStroke, m_transform) 289 { 290 lineCap(m_lineCap); 291 lineJoin(m_lineJoin); 292 } 293 294 ~Agg2D() {} 295 296 // Setup 297 // ----- 298 299 void attach(unsigned char* buf, unsigned width, unsigned height, int stride) { 300 m_rbuf.attach(buf, width, height, stride); 301 m_renBasePre.reset_clipping(true); 302 m_renBaseCompPre.reset_clipping(true); 303 304 resetTransformations(); 305 lineWidth(1.0), 306 lineColor(0,0,0); 307 fillColor(255,255,255); 308 clipBox(0, 0, width, height); 309 lineCap(CapRound); 310 lineJoin(JoinRound); 311 imageFilter(Bilinear); 312 imageResample(NoResample); 313 m_masterAlpha = 1.0; 314 m_blendMode = BlendSrcOver; 315 } 316 317 void attach(Image& img) { 318 attach(img.renBuf.buf(), img.renBuf.width(), img.renBuf.height(), img.renBuf.stride()); 319 } 320 321 void clipBox(double x1, double y1, double x2, double y2) { 322 m_clipBox = RectD(x1, y1, x2, y2); 323 int rx1 = int(x1); 324 int ry1 = int(y1); 325 int rx2 = int(x2); 326 int ry2 = int(y2); 327 328 m_renBasePre.clip_box(rx1, ry1, rx2, ry2); 329 m_renBaseCompPre.clip_box(rx1, ry1, rx2, ry2); 330 331 m_rasterizer.clip_box(x1, y1, x2, y2); 332 } 333 334 RectD clipBox() const { return m_clipBox; } 335 336 void clearAll(Color c) { 337 c.premultiply(); 338 m_renBasePre.fill(c); 339 } 340 341 void clearAll(unsigned r, unsigned g, unsigned b, unsigned a) { 342 clearAll(Color(r, g, b, a)); 343 } 344 345 // Conversions 346 // ----------- 347 348 void worldToScreen(double& x, double& y) const { m_transform.transform(&x, &y); } 349 void screenToWorld(double& x, double& y) const { m_transform.inverse_transform(&x, &y); } 350 351 double worldToScreen(double scalar) const { 352 double x1 = 0, x2 = scalar; 353 double y1 = 0, y2 = scalar; 354 worldToScreen(x1, y1); 355 worldToScreen(x2, y2); 356 return std::sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)) * 0.7071068; 357 } 358 359 double screenToWorld(double scalar) const { 360 double x1 = 0, x2 = scalar; 361 double y1 = 0, y2 = scalar; 362 screenToWorld(x1, y1); 363 screenToWorld(x2, y2); 364 return std::sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)) * 0.7071068; 365 } 366 367 void alignPoint(double& x, double& y) const { 368 worldToScreen(x, y); 369 x = std::floor(x) + 0.5; 370 y = std::floor(y) + 0.5; 371 screenToWorld(x, y); 372 } 373 374 bool inBox(double worldX, double worldY) const { 375 worldToScreen(worldX, worldY); 376 return m_renBasePre.inbox(int(worldX), int(worldY)); 377 } 378 379 // General Attributes 380 // ------------------ 381 382 void blendMode(BlendMode m) { 383 m_blendMode = m; 384 m_pixFormatCompPre.comp_op(m); 385 } 386 BlendMode blendMode() const { return m_blendMode; } 387 388 void imageBlendMode(BlendMode m) { m_imageBlendMode = m; } 389 BlendMode imageBlendMode() const { return m_imageBlendMode; } 390 391 void imageBlendColor(Color c) { m_imageBlendColor = c; } 392 void imageBlendColor(unsigned r, unsigned g, unsigned b, unsigned a) { imageBlendColor(Color(r, g, b, a)); } 393 Color imageBlendColor() const { return m_imageBlendColor; } 394 395 void masterAlpha(double a) { m_masterAlpha = a; } 396 double masterAlpha() const { return m_masterAlpha; } 397 398 void fillColor(Color c) { 399 m_color[FillSlot] = c; 400 m_color[FillSlot].premultiply(); 401 m_styleFlag[FillSlot] = Solid; 402 } 403 404 void lineColor(Color c) { 405 m_color[StrokeSlot] = c; 406 m_color[StrokeSlot].premultiply(); 407 m_styleFlag[StrokeSlot] = Solid; 408 } 409 410 void fillColor(unsigned r, unsigned g, unsigned b, unsigned a = 0xFFu) { fillColor(Color(r, g, b, a)); } 411 void lineColor(unsigned r, unsigned g, unsigned b, unsigned a = 0xFFu) { lineColor(Color(r, g, b, a)); } 412 413 void noFill() { 414 m_color[FillSlot] = Color(0, 0, 0, 0); 415 m_styleFlag[FillSlot] = None; 416 } 417 418 void noLine() { 419 m_color[StrokeSlot] = Color(0, 0, 0, 0); 420 m_styleFlag[StrokeSlot] = None; 421 } 422 423 void setLinearGradient(StyleSlot slot, double x1, double y1, double x2, double y2, Color c1, Color c2, Color c3) { 424 int i; 425 426 for (i = 0; i < 128; i++) { 427 m_gradient[slot][i] = c1.gradient(c2, double(i) / 127.0); 428 m_gradient[slot][i].premultiply(); 429 } 430 431 for (; i < 256; i++) { 432 m_gradient[slot][i] = c2.gradient(c3, double(i - 128) / 127.0); 433 m_gradient[slot][i].premultiply(); 434 } 435 436 double angle = std::atan2(y2-y1, x2-x1); 437 m_gradientMatrix[slot].reset(); 438 m_gradientMatrix[slot] *= agg::trans_affine_rotation(angle); 439 m_gradientMatrix[slot] *= agg::trans_affine_translation(x1, y1); 440 m_gradientMatrix[slot] *= m_transform; 441 m_gradientMatrix[slot].invert(); 442 m_gradientD1[slot] = 0.0; 443 m_gradientD2[slot] = std::sqrt((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1)); 444 m_styleFlag[slot] = Linear; 445 m_color[slot] = Color(0,0,0); // Set some real color 446 } 447 448 void fillLinearGradient(double x1, double y1, double x2, double y2, Color c1, Color c2, Color c3) { 449 setLinearGradient(FillSlot, x1, y1, x2, y2, c1, c2, c3); 450 } 451 452 void lineLinearGradient(double x1, double y1, double x2, double y2, Color c1, Color c2, Color c3) { 453 setLinearGradient(StrokeSlot, x1, y1, x2, y2, c1, c2, c3); 454 } 455 456 void setRadialGradient(StyleSlot slot, double x, double y, double r, Color c1, Color c2, Color c3) { 457 int i; 458 459 for (i = 0; i < 128; i++) { 460 m_gradient[slot][i] = c1.gradient(c2, double(i) / 127.0); 461 m_gradient[slot][i].premultiply(); 462 } 463 464 for (; i < 256; i++) { 465 m_gradient[slot][i] = c2.gradient(c3, double(i - 128) / 127.0); 466 m_gradient[slot][i].premultiply(); 467 } 468 469 m_gradientD2[slot] = worldToScreen(r); 470 worldToScreen(x, y); 471 m_gradientMatrix[slot].reset(); 472 m_gradientMatrix[slot] *= agg::trans_affine_translation(x, y); 473 m_gradientMatrix[slot].invert(); 474 m_gradientD1[slot] = 0; 475 m_styleFlag[slot] = Radial; 476 m_color[slot] = Color(0,0,0); // Set some real color 477 } 478 479 void fillRadialGradient(double x, double y, double r, Color c1, Color c2, Color c3) { 480 setRadialGradient(FillSlot, x, y, r, c1, c2, c3); 481 } 482 483 void lineRadialGradient(double x, double y, double r, Color c1, Color c2, Color c3) { 484 setRadialGradient(StrokeSlot, x, y, r, c1, c2, c3); 485 } 486 487 void lineWidth(double w) { 488 m_lineWidth = w; 489 m_convStroke.width(w); 490 } 491 492 void fillEvenOdd(bool evenOddFlag) { 493 m_evenOddFlag = evenOddFlag; 494 m_rasterizer.filling_rule(evenOddFlag ? agg::fill_even_odd : agg::fill_non_zero); 495 } 496 497 void lineCap(LineCap cap) { 498 m_lineCap = cap; 499 m_convStroke.line_cap((agg::line_cap_e)cap); 500 } 501 502 void lineJoin(LineJoin join) { 503 m_lineJoin = join; 504 m_convStroke.line_join((agg::line_join_e)join); 505 } 506 507 double lineWidth(double w) const { return m_lineWidth; } 508 bool fillEvenOdd() const { return m_evenOddFlag; } 509 LineCap lineCap() const { return m_lineCap; } 510 LineJoin lineJoin() const { return m_lineJoin; } 511 512 // Transformations 513 // --------------- 514 515 Transformations transformations() const { 516 Transformations tr; 517 m_transform.store_to(tr.affineMatrix); 518 return tr; 519 } 520 521 void transformations(const Transformations& tr) { 522 m_transform.load_from(tr.affineMatrix); 523 m_convCurve.approximation_scale(worldToScreen(1.0) * g_approxScale); 524 m_convStroke.approximation_scale(worldToScreen(1.0) * g_approxScale); 525 } 526 527 void resetTransformations() { 528 m_transform.reset(); 529 } 530 531 void rotate(double angle) { m_transform *= agg::trans_affine_rotation(angle); } 532 void skew(double sx, double sy) { m_transform *= agg::trans_affine_skewing(sx, sy); } 533 void translate(double x, double y) { m_transform *= agg::trans_affine_translation(x, y); } 534 535 void affine(const Affine& tr) { 536 m_transform *= tr; 537 m_convCurve.approximation_scale(worldToScreen(1.0) * g_approxScale); 538 m_convStroke.approximation_scale(worldToScreen(1.0) * g_approxScale); 539 } 540 541 void affine(const Transformations& tr) { 542 affine(agg::trans_affine(tr.affineMatrix[0], tr.affineMatrix[1], tr.affineMatrix[2], 543 tr.affineMatrix[3], tr.affineMatrix[4], tr.affineMatrix[5])); 544 } 545 546 void scale(double sx, double sy) { 547 m_transform *= agg::trans_affine_scaling(sx, sy); 548 m_convCurve.approximation_scale(worldToScreen(1.0) * g_approxScale); 549 m_convStroke.approximation_scale(worldToScreen(1.0) * g_approxScale); 550 } 551 552 // Basic Shapes 553 // ------------ 554 555 void fillRectangleI(int x1, int y1, int x2, int y2, Color color); 556 557 void line(double x1, double y1, double x2, double y2); 558 void triangle(double x1, double y1, double x2, double y2, double x3, double y3); 559 void rectangle(double x1, double y1, double x2, double y2); 560 void roundedRect(double x1, double y1, double x2, double y2, double r); 561 void roundedRect(double x1, double y1, double x2, double y2, double rx, double ry); 562 void roundedRect(double x1, double y1, double x2, double y2, 563 double rxBottom, double ryBottom, 564 double rxTop, double ryTop); 565 void ellipse(double cx, double cy, double rx, double ry); 566 void arc(double cx, double cy, double rx, double ry, double start, double sweep); 567 void star(double cx, double cy, double r1, double r2, double startAngle, int numRays); 568 void curve(double x1, double y1, double x2, double y2, double x3, double y3); 569 void curve(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4); 570 void polygon(double* xy, int numPoints); 571 void polyline(double* xy, int numPoints); 572 573 574 // Path commands 575 // ------------- 576 577 void resetPath() { m_path.remove_all(); } 578 void moveTo(double x, double y) { m_path.move_to(x, y); } 579 void moveRel(double dx, double dy) { m_path.move_rel(dx, dy); } 580 void lineTo(double x, double y) { m_path.line_to(x, y); } 581 void lineRel(double dx, double dy) { m_path.line_rel(dx, dy); } 582 void horLineTo(double x) { m_path.hline_to(x); } 583 void horLineRel(double dx) { m_path.hline_rel(dx); } 584 void verLineTo(double y) { m_path.vline_to(y); } 585 void verLineRel(double dy) { m_path.vline_rel(dy); } 586 void arcTo(double rx, double ry, double angle, bool laFlag, bool sweepFlag, double x, double y) { m_path.arc_to(rx, ry, angle, laFlag, sweepFlag, x, y); } 587 void arcRel(double rx, double ry, double angle, bool laFlag, bool sweepFlag, double dx, double dy) { m_path.arc_rel(rx, ry, angle, laFlag, sweepFlag, dx, dy); } 588 void quadricCurveTo(double x0, double y0, double x1, double y1) { m_path.curve3(x0, y0, x1, y1); } 589 void quadricCurveRel(double x0, double y0, double x1, double y1) { m_path.curve3_rel(x0, y0, x1, y1); } 590 void quadricCurveTo(double x1, double y1) { m_path.curve3(x1, y1); } 591 void quadricCurveRel(double x1, double y1) { m_path.curve3_rel(x1, y1); } 592 void cubicCurveTo(double x0, double y0, double x1, double y1, double x2, double y2) { m_path.curve4(x0, y0, x1, y1, x2, y2); } 593 void cubicCurveRel(double x0, double y0, double x1, double y1, double x2, double y2) { m_path.curve4_rel(x0, y0, x1, y1, x2, y2); } 594 void cubicCurveTo(double x1, double y1, double x2, double y2) { m_path.curve4(x1, y1, x2, y2); } 595 void cubicCurveRel(double x1, double y1, double x2, double y2) { m_path.curve4_rel(x1, y1, x2, y2); } 596 597 void addEllipse(double cx, double cy, double rx, double ry, Direction dir) { 598 agg::bezier_arc arc(cx, cy, rx, ry, 0, (dir == CCW) ? 2*pi() : -2*pi()); 599 m_path.concat_path(arc,0); 600 m_path.close_polygon(); 601 } 602 603 void closePolygon() { m_path.close_polygon(); } 604 605 void drawPath(DrawPathFlag flag = FillAndStroke); 606 void drawPathNoTransform(DrawPathFlag flag = FillAndStroke); 607 608 609 // Image Transformations 610 // --------------------- 611 612 void imageFilter(ImageFilter f); 613 ImageFilter imageFilter() const { return m_imageFilter; } 614 615 void imageResample(ImageResample f) { m_imageResample = f; } 616 ImageResample imageResample() const { return m_imageResample; } 617 618 void transformImage(const Image& img, 619 int imgX1, int imgY1, int imgX2, int imgY2, 620 double dstX1, double dstY1, double dstX2, double dstY2); 621 622 void transformImage(const Image& img, 623 double dstX1, double dstY1, double dstX2, double dstY2); 624 625 void transformImage(const Image& img, 626 int imgX1, int imgY1, int imgX2, int imgY2, 627 const double* parallelogram); 628 629 void transformImage(const Image& img, const double* parallelogram); 630 631 void transformImagePath(const Image& img, 632 int imgX1, int imgY1, int imgX2, int imgY2, 633 double dstX1, double dstY1, double dstX2, double dstY2); 634 635 void transformImagePath(const Image& img, 636 double dstX1, double dstY1, double dstX2, double dstY2); 637 638 void transformImagePath(const Image& img, 639 int imgX1, int imgY1, int imgX2, int imgY2, 640 const double* parallelogram); 641 642 void transformImagePath(const Image& img, const double* parallelogram); 643 644 // Image Blending (no transformations available) 645 void blendImage(Image& img, 646 int imgX1, int imgY1, int imgX2, int imgY2, 647 double dstX, double dstY, unsigned alpha=255); 648 void blendImage(Image& img, double dstX, double dstY, unsigned alpha=255); 649 650 // Copy image directly, together with alpha-channel 651 void copyImage(Image& img, 652 int imgX1, int imgY1, int imgX2, int imgY2, 653 double dstX, double dstY); 654 void copyImage(Image& img, double dstX, double dstY); 655 656 // Auxiliary 657 // --------- 658 659 static inline double pi() { return agg::pi; } 660 static inline double deg2Rad(double v) { return v * agg::pi / 180.0; } 661 static inline double rad2Deg(double v) { return v * 180.0 / agg::pi; } 662 663 private: 664 void render(StyleSlot slot); 665 void addLine(double x1, double y1, double x2, double y2); 666 void renderImage(const Image& img, int x1, int y1, int x2, int y2, const double* parl); 667 }; 668 669 inline bool operator==(const Agg2D::Color& c1, const Agg2D::Color& c2) { return c1.r == c2.r && c1.g == c2.g && c1.b == c2.b && c1.a == c2.a; } 670 inline bool operator!=(const Agg2D::Color& c1, const Agg2D::Color& c2) { return !(c1 == c2); } 671 672 void Agg2D::addLine(double x1, double y1, double x2, double y2) { 673 m_path.move_to(x1, y1); 674 m_path.line_to(x2, y2); 675 } 676 677 void Agg2D::fillRectangleI(int x1, int y1, int x2, int y2, Color color) { 678 color.premultiply(); 679 680 if (m_blendMode == BlendSrc) { 681 m_renBasePre.copy_bar(x1, y1, x2, y2, color); 682 } 683 else if (m_blendMode == BlendSrcOver) { 684 m_renBasePre.blend_bar(x1, y1, x2, y2, color, 0xFF); 685 } 686 else { 687 m_renBaseCompPre.blend_bar(x1, y1, x2, y2, color, 0xFF); 688 } 689 } 690 691 void Agg2D::line(double x1, double y1, double x2, double y2) { 692 m_path.remove_all(); 693 addLine(x1, y1, x2, y2); 694 drawPath(StrokeOnly); 695 } 696 697 void Agg2D::triangle(double x1, double y1, double x2, double y2, double x3, double y3) { 698 m_path.remove_all(); 699 m_path.move_to(x1, y1); 700 m_path.line_to(x2, y2); 701 m_path.line_to(x3, y3); 702 m_path.close_polygon(); 703 drawPath(FillAndStroke); 704 } 705 706 void Agg2D::rectangle(double x1, double y1, double x2, double y2) { 707 m_path.remove_all(); 708 m_path.move_to(x1, y1); 709 m_path.line_to(x2, y1); 710 m_path.line_to(x2, y2); 711 m_path.line_to(x1, y2); 712 m_path.close_polygon(); 713 drawPath(FillAndStroke); 714 } 715 716 void Agg2D::roundedRect(double x1, double y1, double x2, double y2, double r) { 717 m_path.remove_all(); 718 agg::rounded_rect rc(x1, y1, x2, y2, r); 719 rc.normalize_radius(); 720 rc.approximation_scale(worldToScreen(1.0) * g_approxScale); 721 m_path.concat_path(rc,0); 722 drawPath(FillAndStroke); 723 } 724 725 void Agg2D::roundedRect(double x1, double y1, double x2, double y2, double rx, double ry) { 726 m_path.remove_all(); 727 agg::rounded_rect rc; 728 rc.rect(x1, y1, x2, y2); 729 rc.radius(rx, ry); 730 rc.normalize_radius(); 731 m_path.concat_path(rc,0); 732 drawPath(FillAndStroke); 733 } 734 735 void Agg2D::roundedRect(double x1, double y1, double x2, double y2, double rx_bottom, double ry_bottom, double rx_top, double ry_top) { 736 m_path.remove_all(); 737 agg::rounded_rect rc; 738 rc.rect(x1, y1, x2, y2); 739 rc.radius(rx_bottom, ry_bottom, rx_top, ry_top); 740 rc.normalize_radius(); 741 rc.approximation_scale(worldToScreen(1.0) * g_approxScale); 742 m_path.concat_path(rc,0); 743 drawPath(FillAndStroke); 744 } 745 746 void Agg2D::ellipse(double cx, double cy, double rx, double ry) { 747 m_path.remove_all(); 748 agg::bezier_arc arc(cx, cy, rx, ry, 0, 2*pi()); 749 m_path.concat_path(arc,0); 750 m_path.close_polygon(); 751 drawPath(FillAndStroke); 752 } 753 754 void Agg2D::arc(double cx, double cy, double rx, double ry, double start, double sweep) { 755 m_path.remove_all(); 756 agg::bezier_arc arc(cx, cy, rx, ry, start, sweep); 757 m_path.concat_path(arc,0); 758 drawPath(StrokeOnly); 759 } 760 761 void Agg2D::star(double cx, double cy, double r1, double r2, double startAngle, int numRays) { 762 m_path.remove_all(); 763 double da = agg::pi / double(numRays); 764 double a = startAngle; 765 for (int i = 0; i < numRays; i++) { 766 double x = cos(a) * r2 + cx; 767 double y = sin(a) * r2 + cy; 768 if (i) m_path.line_to(x, y); 769 else m_path.move_to(x, y); 770 a += da; 771 m_path.line_to(cos(a) * r1 + cx, sin(a) * r1 + cy); 772 a += da; 773 } 774 closePolygon(); 775 drawPath(FillAndStroke); 776 } 777 778 void Agg2D::curve(double x1, double y1, double x2, double y2, double x3, double y3) { 779 m_path.remove_all(); 780 m_path.move_to(x1, y1); 781 m_path.curve3(x2, y2, x3, y3); 782 drawPath(StrokeOnly); 783 } 784 785 void Agg2D::curve(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) { 786 m_path.remove_all(); 787 m_path.move_to(x1, y1); 788 m_path.curve4(x2, y2, x3, y3, x4, y4); 789 drawPath(StrokeOnly); 790 } 791 792 void Agg2D::polygon(double* xy, int numPoints) { 793 m_path.remove_all(); 794 m_path.concat_poly(xy,0,true); 795 closePolygon(); 796 drawPath(FillAndStroke); 797 } 798 799 void Agg2D::polyline(double* xy, int numPoints) { 800 m_path.remove_all(); 801 m_path.concat_poly(xy,0,true); 802 drawPath(StrokeOnly); 803 } 804 805 void Agg2D::imageFilter(ImageFilter f) { 806 m_imageFilter = f; 807 switch(f) { 808 case NoFilter: break; 809 case Bilinear: m_imageFilterLut.calculate(agg::image_filter_bilinear(), true); break; 810 } 811 } 812 813 void Agg2D::transformImage(const Image& img, int imgX1, int imgY1, int imgX2, int imgY2, double dstX1, double dstY1, double dstX2, double dstY2) { 814 resetPath(); 815 moveTo(dstX1, dstY1); 816 lineTo(dstX2, dstY1); 817 lineTo(dstX2, dstY2); 818 lineTo(dstX1, dstY2); 819 closePolygon(); 820 double parallelogram[6] = { dstX1, dstY1, dstX2, dstY1, dstX2, dstY2 }; 821 renderImage(img, imgX1, imgY1, imgX2, imgY2, parallelogram); 822 } 823 824 void Agg2D::transformImage(const Image& img, double dstX1, double dstY1, double dstX2, double dstY2) { 825 resetPath(); 826 moveTo(dstX1, dstY1); 827 lineTo(dstX2, dstY1); 828 lineTo(dstX2, dstY2); 829 lineTo(dstX1, dstY2); 830 closePolygon(); 831 double parallelogram[6] = { dstX1, dstY1, dstX2, dstY1, dstX2, dstY2 }; 832 renderImage(img, 0, 0, img.renBuf.width(), img.renBuf.height(), parallelogram); 833 } 834 835 void Agg2D::transformImage(const Image& img, int imgX1, int imgY1, int imgX2, int imgY2, const double* parallelogram) { 836 resetPath(); 837 moveTo(parallelogram[0], parallelogram[1]); 838 lineTo(parallelogram[2], parallelogram[3]); 839 lineTo(parallelogram[4], parallelogram[5]); 840 lineTo(parallelogram[0] + parallelogram[4] - parallelogram[2], parallelogram[1] + parallelogram[5] - parallelogram[3]); 841 closePolygon(); 842 renderImage(img, imgX1, imgY1, imgX2, imgY2, parallelogram); 843 } 844 845 846 void Agg2D::transformImage(const Image& img, const double* parallelogram) { 847 resetPath(); 848 moveTo(parallelogram[0], parallelogram[1]); 849 lineTo(parallelogram[2], parallelogram[3]); 850 lineTo(parallelogram[4], parallelogram[5]); 851 lineTo(parallelogram[0] + parallelogram[4] - parallelogram[2], parallelogram[1] + parallelogram[5] - parallelogram[3]); 852 closePolygon(); 853 renderImage(img, 0, 0, img.renBuf.width(), img.renBuf.height(), parallelogram); 854 } 855 856 void Agg2D::transformImagePath(const Image& img, int imgX1, int imgY1, int imgX2, int imgY2, double dstX1, double dstY1, double dstX2, double dstY2) { 857 double parallelogram[6] = { dstX1, dstY1, dstX2, dstY1, dstX2, dstY2 }; 858 renderImage(img, imgX1, imgY1, imgX2, imgY2, parallelogram); 859 } 860 861 void Agg2D::transformImagePath(const Image& img, double dstX1, double dstY1, double dstX2, double dstY2) { 862 double parallelogram[6] = { dstX1, dstY1, dstX2, dstY1, dstX2, dstY2 }; 863 renderImage(img, 0, 0, img.renBuf.width(), img.renBuf.height(), parallelogram); 864 } 865 866 void Agg2D::transformImagePath(const Image& img, int imgX1, int imgY1, int imgX2, int imgY2, const double* parallelogram) { 867 renderImage(img, imgX1, imgY1, imgX2, imgY2, parallelogram); 868 } 869 870 void Agg2D::transformImagePath(const Image& img, const double* parallelogram) { 871 renderImage(img, 0, 0, img.renBuf.width(), img.renBuf.height(), parallelogram); 872 } 873 874 void Agg2D::drawPath(DrawPathFlag flag) { 875 m_rasterizer.reset(); 876 switch(flag) { 877 case FillOnly: 878 if (m_styleFlag[FillSlot] != None) { 879 m_rasterizer.add_path(m_pathTransform); 880 render(FillSlot); 881 } 882 break; 883 884 case StrokeOnly: 885 if (m_styleFlag[StrokeSlot] != None && m_lineWidth > 0.0) { 886 m_rasterizer.add_path(m_strokeTransform); 887 render(StrokeSlot); 888 } 889 break; 890 891 case FillAndStroke: 892 if (m_styleFlag[FillSlot] != None) { 893 m_rasterizer.add_path(m_pathTransform); 894 render(FillSlot); 895 } 896 897 if (m_styleFlag[StrokeSlot] != None && m_lineWidth > 0.0) { 898 m_rasterizer.add_path(m_strokeTransform); 899 render(StrokeSlot); 900 } 901 break; 902 903 case FillWithLineColor: 904 if (m_styleFlag[StrokeSlot] != None) { 905 m_rasterizer.add_path(m_pathTransform); 906 render(StrokeSlot); 907 } 908 break; 909 } 910 } 911 912 class Agg2DRenderer { 913 public: 914 template<class BaseRenderer, class SolidRenderer> 915 void static render(Agg2D& gr, BaseRenderer& renBase, SolidRenderer& renSolid, Agg2D::StyleSlot slot) { 916 typedef agg::span_allocator<agg::rgba8> span_allocator_type; 917 typedef agg::renderer_scanline_aa<BaseRenderer, span_allocator_type, Agg2D::LinearGradientSpan> RendererLinearGradient; 918 typedef agg::renderer_scanline_aa<BaseRenderer, span_allocator_type, Agg2D::RadialGradientSpan> RendererRadialGradient; 919 920 switch (gr.m_styleFlag[slot]) { 921 case Agg2D::None: { 922 return; 923 } 924 925 case Agg2D::Solid: { 926 renSolid.color(gr.m_color[slot]); 927 agg::render_scanlines(gr.m_rasterizer, gr.m_scanline, renSolid); 928 return; 929 } 930 931 case Agg2D::Linear: { 932 Agg2D::LinearGradientSpan span(/*gr.m_allocator, */ 933 gr.m_gradientInterpolator[slot], 934 gr.m_linearGradientFunction, 935 gr.m_gradient[slot], 936 gr.m_gradientD1[slot], 937 gr.m_gradientD2[slot]); 938 RendererLinearGradient ren(renBase,gr.m_allocator,span); 939 agg::render_scanlines(gr.m_rasterizer, gr.m_scanline, ren); 940 return; 941 } 942 943 case Agg2D::Radial: { 944 Agg2D::RadialGradientSpan span(/*gr.m_allocator, */ 945 gr.m_gradientInterpolator[slot], 946 gr.m_radialGradientFunction, 947 gr.m_gradient[slot], 948 gr.m_gradientD1[slot], 949 gr.m_gradientD2[slot]); 950 RendererRadialGradient ren(renBase,gr.m_allocator,span); 951 agg::render_scanlines(gr.m_rasterizer, gr.m_scanline, ren); 952 return; 953 } 954 } 955 } 956 957 class SpanConvImageBlend { 958 private: 959 Agg2D::BlendMode m_mode; 960 Agg2D::Color m_color; 961 962 public: 963 SpanConvImageBlend(Agg2D::BlendMode m, Agg2D::Color c) : 964 m_mode(m), m_color(c) {} 965 966 void convert(Agg2D::Color* span, int x, int y, unsigned len) const { 967 unsigned l2; 968 Agg2D::Color* s2; 969 if (m_mode != Agg2D::BlendDst) { 970 l2 = len; 971 s2 = span; 972 typedef agg::comp_op_adaptor_clip_to_dst_rgba_pre<Agg2D::Color, agg::order_rgba> OpType; 973 do { 974 OpType::blend_pix(m_mode, (Agg2D::Color::value_type*)s2, m_color.r, m_color.g, m_color.b, Agg2D::Color::base_mask, agg::cover_full); 975 ++s2; 976 } 977 while(--l2); 978 } 979 if (m_color.a < Agg2D::Color::base_mask) { 980 l2 = len; 981 s2 = span; 982 unsigned a = m_color.a; 983 do { 984 s2->r = (s2->r * a) >> Agg2D::Color::base_shift; 985 s2->g = (s2->g * a) >> Agg2D::Color::base_shift; 986 s2->b = (s2->b * a) >> Agg2D::Color::base_shift; 987 s2->a = (s2->a * a) >> Agg2D::Color::base_shift; 988 ++s2; 989 } 990 while(--l2); 991 } 992 } 993 }; 994 995 template<class BaseRenderer, class SolidRenderer, class Rasterizer, class Scanline> 996 void static render(Agg2D& gr, BaseRenderer& renBase, SolidRenderer& renSolid, Rasterizer& ras, Scanline& sl) { 997 typedef agg::span_allocator<agg::rgba8> span_allocator_type; 998 typedef agg::renderer_scanline_aa<BaseRenderer,span_allocator_type,Agg2D::LinearGradientSpan> RendererLinearGradient; 999 typedef agg::renderer_scanline_aa<BaseRenderer,span_allocator_type,Agg2D::RadialGradientSpan> RendererRadialGradient; 1000 1001 int slot = 0; 1002 1003 switch (gr.m_styleFlag[slot]) { 1004 case Agg2D::None: { 1005 return; 1006 } 1007 1008 case Agg2D::Solid: { 1009 renSolid.color(gr.m_color[slot]); 1010 agg::render_scanlines(ras, sl, renSolid); 1011 return; 1012 } 1013 1014 case Agg2D::Linear: { 1015 Agg2D::LinearGradientSpan span(gr.m_gradientInterpolator[slot], 1016 gr.m_linearGradientFunction, 1017 gr.m_gradient[slot], 1018 gr.m_gradientD1[slot], 1019 gr.m_gradientD2[slot]); 1020 RendererLinearGradient ren(renBase,gr.m_allocator,span); 1021 agg::render_scanlines(ras, sl, ren); 1022 return; 1023 } 1024 1025 case Agg2D::Radial: { 1026 Agg2D::RadialGradientSpan span(gr.m_gradientInterpolator[slot], 1027 gr.m_radialGradientFunction, 1028 gr.m_gradient[slot], 1029 gr.m_gradientD1[slot], 1030 gr.m_gradientD2[slot]); 1031 RendererRadialGradient ren(renBase,gr.m_allocator,span); 1032 agg::render_scanlines(ras, sl, ren); 1033 return; 1034 } 1035 } 1036 } 1037 1038 template<class BaseRenderer, class Interpolator> 1039 static void renderImage(Agg2D& gr, const Agg2D::Image& img, BaseRenderer& renBase, Interpolator& interpolator) { 1040 Agg2D::Image& imgc = const_cast<Agg2D::Image&>(img); 1041 Agg2D::PixFormatPre img_pixf(imgc.renBuf); 1042 typedef agg::image_accessor_clone<Agg2D::PixFormatPre> img_source_type; 1043 img_source_type source(img_pixf); 1044 1045 SpanConvImageBlend blend(gr.m_imageBlendMode, gr.m_imageBlendColor); 1046 if (gr.m_imageFilter == Agg2D::NoFilter) { 1047 typedef agg::span_image_filter_rgba_nn<img_source_type,Interpolator> SpanGenType; 1048 typedef agg::span_converter<SpanGenType,SpanConvImageBlend> SpanConvType; 1049 typedef agg::renderer_scanline_aa<BaseRenderer,Agg2D::SpanAllocator,SpanGenType> RendererType; 1050 1051 SpanGenType sg(source,interpolator); 1052 SpanConvType sc(sg, blend); 1053 RendererType ri(renBase,gr.m_allocator,sg); 1054 agg::render_scanlines(gr.m_rasterizer, gr.m_scanline, ri); 1055 } 1056 else { 1057 bool resample = (gr.m_imageResample == Agg2D::ResampleAlways); 1058 if (gr.m_imageResample == Agg2D::ResampleOnZoomOut) { 1059 double sx, sy; 1060 interpolator.transformer().scaling_abs(&sx,&sy); 1061 if (sx > 1.125 || sy > 1.125) { 1062 resample = true; 1063 } 1064 } 1065 1066 if (resample) { 1067 typedef agg::span_image_resample_rgba_affine<img_source_type> SpanGenType; 1068 typedef agg::span_converter<SpanGenType,SpanConvImageBlend> SpanConvType; 1069 typedef agg::renderer_scanline_aa<BaseRenderer,Agg2D::SpanAllocator,SpanGenType> RendererType; 1070 1071 SpanGenType sg(source,interpolator,gr.m_imageFilterLut); 1072 SpanConvType sc(sg, blend); 1073 RendererType ri(renBase,gr.m_allocator,sg); 1074 agg::render_scanlines(gr.m_rasterizer, gr.m_scanline, ri); 1075 } 1076 else { 1077 typedef agg::span_image_filter_rgba_bilinear<img_source_type,Interpolator> SpanGenType; 1078 typedef agg::span_converter<SpanGenType,SpanConvImageBlend> SpanConvType; 1079 typedef agg::renderer_scanline_aa<BaseRenderer,Agg2D::SpanAllocator,SpanGenType> RendererType; 1080 1081 SpanGenType sg(source,interpolator); 1082 SpanConvType sc(sg, blend); 1083 RendererType ri(renBase,gr.m_allocator,sg); 1084 agg::render_scanlines(gr.m_rasterizer, gr.m_scanline, ri); 1085 } 1086 } 1087 } 1088 }; 1089 1090 void Agg2D::render(StyleSlot slot) { 1091 if (m_blendMode == BlendSrcOver) 1092 Agg2DRenderer::render(*this, m_renBasePre, m_renSolidComp, slot); 1093 else 1094 Agg2DRenderer::render(*this, m_renBaseCompPre, m_renSolidComp, slot); 1095 } 1096 1097 void Agg2D::renderImage(const Image& img, int x1, int y1, int x2, int y2, const double* parl) { 1098 agg::trans_affine mtx((double)x1, (double)y1, (double)x2, (double)y2, parl); 1099 mtx *= m_transform; 1100 mtx.invert(); 1101 1102 m_rasterizer.reset(); 1103 m_rasterizer.add_path(m_pathTransform); 1104 1105 typedef agg::span_interpolator_linear<agg::trans_affine> Interpolator; 1106 Interpolator interpolator(mtx); 1107 1108 Agg2DRenderer::renderImage(*this,img, m_renBaseCompPre, interpolator); 1109 } 1110 1111 void Agg2D::blendImage(Image& img, int imgX1, int imgY1, int imgX2, int imgY2, double dstX, double dstY, unsigned alpha) { 1112 worldToScreen(dstX, dstY); 1113 PixFormatPre pixF(img.renBuf); 1114 Rect r(imgX1, imgY1, imgX2, imgY2); 1115 m_renBaseCompPre.blend_from(pixF, &r, int(dstX)-imgX1, int(dstY)-imgY1, alpha); 1116 } 1117 1118 void Agg2D::blendImage(Image& img, double dstX, double dstY, unsigned alpha) { 1119 worldToScreen(dstX, dstY); 1120 PixFormatPre pixF(img.renBuf); 1121 m_renBasePre.blend_from(pixF, 0, int(dstX), int(dstY), alpha); 1122 m_renBaseCompPre.blend_from(pixF, 0, int(dstX), int(dstY), alpha); 1123 } 1124 1125 void Agg2D::copyImage(Image& img, int imgX1, int imgY1, int imgX2, int imgY2, double dstX, double dstY) { 1126 worldToScreen(dstX, dstY); 1127 Rect r(imgX1, imgY1, imgX2, imgY2); 1128 m_renBasePre.copy_from(img.renBuf, &r, int(dstX)-imgX1, int(dstY)-imgY1); 1129 } 1130 1131 void Agg2D::copyImage(Image& img, double dstX, double dstY) { 1132 worldToScreen(dstX, dstY); 1133 m_renBasePre.copy_from(img.renBuf, 0, int(dstX), int(dstY)); 1134 } 1135 1136 // AGG Benchmarking - Backend Implementation 1137 // ========================================= 1138 1139 namespace blbench { 1140 1141 static inline uint32_t to_agg2d_blend_mode(BLCompOp comp_op) { 1142 switch (comp_op) { 1143 case BL_COMP_OP_CLEAR : return uint32_t(Agg2D::BlendClear); break; 1144 case BL_COMP_OP_SRC_COPY : return uint32_t(Agg2D::BlendSrc); break; 1145 case BL_COMP_OP_DST_COPY : return uint32_t(Agg2D::BlendDst); break; 1146 case BL_COMP_OP_SRC_OVER : return uint32_t(Agg2D::BlendSrcOver); break; 1147 case BL_COMP_OP_DST_OVER : return uint32_t(Agg2D::BlendDstOver); break; 1148 case BL_COMP_OP_SRC_IN : return uint32_t(Agg2D::BlendSrcIn); break; 1149 case BL_COMP_OP_DST_IN : return uint32_t(Agg2D::BlendDstIn); break; 1150 case BL_COMP_OP_SRC_OUT : return uint32_t(Agg2D::BlendSrcOut); break; 1151 case BL_COMP_OP_DST_OUT : return uint32_t(Agg2D::BlendDstOut); break; 1152 case BL_COMP_OP_SRC_ATOP : return uint32_t(Agg2D::BlendSrcAtop); break; 1153 case BL_COMP_OP_DST_ATOP : return uint32_t(Agg2D::BlendDstAtop); break; 1154 case BL_COMP_OP_XOR : return uint32_t(Agg2D::BlendXor); break; 1155 case BL_COMP_OP_PLUS : return uint32_t(Agg2D::BlendAdd); break; 1156 case BL_COMP_OP_MULTIPLY : return uint32_t(Agg2D::BlendMultiply); break; 1157 case BL_COMP_OP_SCREEN : return uint32_t(Agg2D::BlendScreen); break; 1158 case BL_COMP_OP_OVERLAY : return uint32_t(Agg2D::BlendOverlay); break; 1159 case BL_COMP_OP_DARKEN : return uint32_t(Agg2D::BlendDarken); break; 1160 case BL_COMP_OP_LIGHTEN : return uint32_t(Agg2D::BlendLighten); break; 1161 case BL_COMP_OP_COLOR_DODGE: return uint32_t(Agg2D::BlendColorDodge); break; 1162 case BL_COMP_OP_COLOR_BURN : return uint32_t(Agg2D::BlendColorBurn); break; 1163 case BL_COMP_OP_HARD_LIGHT : return uint32_t(Agg2D::BlendHardLight); break; 1164 case BL_COMP_OP_SOFT_LIGHT : return uint32_t(Agg2D::BlendSoftLight); break; 1165 case BL_COMP_OP_DIFFERENCE : return uint32_t(Agg2D::BlendDifference); break; 1166 case BL_COMP_OP_EXCLUSION : return uint32_t(Agg2D::BlendExclusion); break; 1167 1168 default: 1169 return 0xFFFFFFFFu; 1170 } 1171 } 1172 1173 static inline Agg2D::Color to_agg2d_color(BLRgba32 rgba32) { 1174 return Agg2D::Color(rgba32.r(), rgba32.g(), rgba32.b(), rgba32.a()); 1175 } 1176 1177 struct AggModule : public Backend { 1178 Agg2D _ctx; 1179 1180 AggModule(); 1181 ~AggModule() override; 1182 1183 bool supports_comp_op(BLCompOp comp_op) const override; 1184 bool supports_style(StyleKind style) const override; 1185 1186 void before_run() override; 1187 void flush() override; 1188 void after_run() override; 1189 1190 void prepare_fill_stroke_option(RenderOp op); 1191 1192 template<typename RectT> 1193 void setup_style(RenderOp op, const RectT& rect); 1194 1195 void render_rect_a(RenderOp op) override; 1196 void render_rect_f(RenderOp op) override; 1197 void render_rect_rotated(RenderOp op) override; 1198 void render_round_f(RenderOp op) override; 1199 void render_round_rotated(RenderOp op) override; 1200 void render_polygon(RenderOp op, uint32_t complexity) override; 1201 void render_shape(RenderOp op, ShapeData shape) override; 1202 }; 1203 1204 AggModule::AggModule() { 1205 strcpy(_name, "AGG"); 1206 } 1207 AggModule::~AggModule() {} 1208 1209 bool AggModule::supports_comp_op(BLCompOp comp_op) const { 1210 return to_agg2d_blend_mode(comp_op) != 0xFFFFFFFFu; 1211 } 1212 1213 bool AggModule::supports_style(StyleKind style) const { 1214 return style == StyleKind::kSolid || 1215 style == StyleKind::kLinearPad || 1216 style == StyleKind::kLinearRepeat || 1217 style == StyleKind::kLinearReflect || 1218 style == StyleKind::kRadialPad || 1219 style == StyleKind::kRadialRepeat || 1220 style == StyleKind::kRadialReflect ; 1221 } 1222 1223 void AggModule::before_run() { 1224 int w = int(_params.screen_w); 1225 int h = int(_params.screen_h); 1226 1227 BLImageData surface_data; 1228 _surface.create(w, h, BL_FORMAT_PRGB32); 1229 _surface.make_mutable(&surface_data); 1230 1231 _ctx.attach( 1232 static_cast<unsigned char*>(surface_data.pixel_data), 1233 unsigned(surface_data.size.w), 1234 unsigned(surface_data.size.h), 1235 int(surface_data.stride)); 1236 1237 _ctx.fillEvenOdd(false); 1238 _ctx.noLine(); 1239 _ctx.blendMode(Agg2D::BlendSrc); 1240 _ctx.clearAll(Agg2D::Color(0, 0, 0, 0)); 1241 _ctx.blendMode(Agg2D::BlendMode(to_agg2d_blend_mode(_params.comp_op))); 1242 } 1243 1244 void AggModule::flush() { 1245 // Nothing... 1246 } 1247 1248 void AggModule::after_run() { 1249 _ctx.attach(nullptr, 0, 0, 0); 1250 } 1251 1252 void AggModule::prepare_fill_stroke_option(RenderOp op) { 1253 if (op == RenderOp::kStroke) 1254 _ctx.noFill(); 1255 else 1256 _ctx.noLine(); 1257 } 1258 1259 template<typename RectT> 1260 void AggModule::setup_style(RenderOp op, const RectT& rect) { 1261 switch (_params.style) { 1262 case StyleKind::kSolid: { 1263 BLRgba32 color = _rnd_color.next_rgba32(); 1264 if (op == RenderOp::kStroke) 1265 _ctx.lineColor(to_agg2d_color(color)); 1266 else 1267 _ctx.fillColor(to_agg2d_color(color)); 1268 break; 1269 } 1270 1271 case StyleKind::kLinearPad: 1272 case StyleKind::kLinearRepeat: 1273 case StyleKind::kLinearReflect: { 1274 double x1 = rect.x + rect.w * 0.2; 1275 double y1 = rect.y + rect.h * 0.2; 1276 double x2 = rect.x + rect.w * 0.8; 1277 double y2 = rect.y + rect.h * 0.8; 1278 1279 BLRgba32 c1 = _rnd_color.next_rgba32(); 1280 BLRgba32 c2 = _rnd_color.next_rgba32(); 1281 BLRgba32 c3 = _rnd_color.next_rgba32(); 1282 1283 if (op == RenderOp::kStroke) 1284 _ctx.lineLinearGradient(x1, y1, x2, y2, to_agg2d_color(c1), to_agg2d_color(c2), to_agg2d_color(c3)); 1285 else 1286 _ctx.fillLinearGradient(x1, y1, x2, y2, to_agg2d_color(c1), to_agg2d_color(c2), to_agg2d_color(c3)); 1287 break; 1288 } 1289 1290 case StyleKind::kRadialPad: 1291 case StyleKind::kRadialRepeat: 1292 case StyleKind::kRadialReflect: { 1293 double cx = rect.x + rect.w / 2.0; 1294 double cy = rect.y + rect.h / 2.0; 1295 double cr = (rect.w + rect.h) / 4.0; 1296 1297 BLRgba32 c1 = _rnd_color.next_rgba32(); 1298 BLRgba32 c2 = _rnd_color.next_rgba32(); 1299 BLRgba32 c3 = _rnd_color.next_rgba32(); 1300 1301 if (op == RenderOp::kStroke) 1302 _ctx.lineRadialGradient(cx, cy, cr, to_agg2d_color(c1), to_agg2d_color(c2), to_agg2d_color(c3)); 1303 else 1304 _ctx.fillRadialGradient(cx, cy, cr, to_agg2d_color(c1), to_agg2d_color(c2), to_agg2d_color(c3)); 1305 break; 1306 } 1307 1308 default: 1309 break; 1310 } 1311 } 1312 1313 void AggModule::render_rect_a(RenderOp op) { 1314 BLSizeI bounds(_params.screen_w, _params.screen_h); 1315 StyleKind style = _params.style; 1316 int wh = _params.shape_size; 1317 1318 prepare_fill_stroke_option(op); 1319 1320 if (_params.style == StyleKind::kSolid && op != RenderOp::kStroke) { 1321 for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) { 1322 BLRectI rect = _rnd_coord.next_rect_i(bounds, wh, wh); 1323 _ctx.fillRectangleI(rect.x, rect.y, rect.x + rect.w, rect.y + rect.h, to_agg2d_color(_rnd_color.next_rgba32())); 1324 } 1325 } 1326 else { 1327 for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) { 1328 BLRectI rect = _rnd_coord.next_rect_i(bounds, wh, wh); 1329 setup_style(op, rect); 1330 _ctx.rectangle(rect.x, rect.y, rect.x + rect.w, rect.y + rect.h); 1331 } 1332 } 1333 } 1334 1335 void AggModule::render_rect_f(RenderOp op) { 1336 BLSize bounds(_params.screen_w, _params.screen_h); 1337 StyleKind style = _params.style; 1338 double wh = _params.shape_size; 1339 1340 prepare_fill_stroke_option(op); 1341 1342 for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) { 1343 BLRect rect = _rnd_coord.next_rect(bounds, wh, wh); 1344 setup_style(op, rect); 1345 _ctx.rectangle(rect.x, rect.y, rect.x + rect.w, rect.y + rect.h); 1346 } 1347 } 1348 1349 void AggModule::render_rect_rotated(RenderOp op) { 1350 BLSize bounds(_params.screen_w, _params.screen_h); 1351 StyleKind style = _params.style; 1352 1353 double cx = double(_params.screen_w) * 0.5; 1354 double cy = double(_params.screen_h) * 0.5; 1355 double wh = _params.shape_size; 1356 double angle = 0.0; 1357 1358 prepare_fill_stroke_option(op); 1359 1360 for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++, angle += 0.01) { 1361 BLRect rect(_rnd_coord.next_rect(bounds, wh, wh)); 1362 1363 agg::trans_affine affine; 1364 affine.translate(-cx, -cy); 1365 affine.rotate(angle); 1366 affine.translate(cx, cy); 1367 1368 _ctx.affine(affine); 1369 setup_style(op, rect); 1370 _ctx.rectangle(rect.x, rect.y, rect.x + rect.w, rect.y + rect.h); 1371 _ctx.resetTransformations(); 1372 } 1373 } 1374 1375 void AggModule::render_round_f(RenderOp op) { 1376 BLSize bounds(_params.screen_w, _params.screen_h); 1377 StyleKind style = _params.style; 1378 double wh = _params.shape_size; 1379 1380 prepare_fill_stroke_option(op); 1381 1382 for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) { 1383 BLRect rect = _rnd_coord.next_rect(bounds, wh, wh); 1384 double radius = _rnd_extra.next_double(4.0, 40.0); 1385 1386 setup_style(op, rect); 1387 _ctx.roundedRect(rect.x, rect.y, rect.x + rect.w, rect.y + rect.h, radius); 1388 } 1389 } 1390 1391 void AggModule::render_round_rotated(RenderOp op) { 1392 BLSize bounds(_params.screen_w, _params.screen_h); 1393 StyleKind style = _params.style; 1394 1395 double cx = double(_params.screen_w) * 0.5; 1396 double cy = double(_params.screen_h) * 0.5; 1397 double wh = _params.shape_size; 1398 double angle = 0.0; 1399 1400 prepare_fill_stroke_option(op); 1401 1402 for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++, angle += 0.01) { 1403 BLRect rect(_rnd_coord.next_rect(bounds, wh, wh)); 1404 double radius = _rnd_extra.next_double(4.0, 40.0); 1405 1406 agg::trans_affine affine; 1407 affine.translate(-cx, -cy); 1408 affine.rotate(angle); 1409 affine.translate(cx, cy); 1410 _ctx.affine(affine); 1411 1412 setup_style(op, rect); 1413 _ctx.roundedRect(rect.x, rect.y, rect.x + rect.w, rect.y + rect.h, radius); 1414 _ctx.resetTransformations(); 1415 } 1416 } 1417 1418 void AggModule::render_polygon(RenderOp op, uint32_t complexity) { 1419 BLSizeI bounds(_params.screen_w - _params.shape_size, 1420 _params.screen_h - _params.shape_size); 1421 1422 StyleKind style = _params.style; 1423 double wh = _params.shape_size; 1424 1425 prepare_fill_stroke_option(op); 1426 _ctx.fillEvenOdd(op == RenderOp::kFillEvenOdd); 1427 1428 Agg2D::DrawPathFlag draw_path_flag = op == RenderOp::kStroke ? Agg2D::StrokeOnly : Agg2D::FillOnly; 1429 1430 for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) { 1431 BLPoint base(_rnd_coord.nextPoint(bounds)); 1432 1433 double x = _rnd_coord.next_double(base.x, base.x + wh); 1434 double y = _rnd_coord.next_double(base.y, base.y + wh); 1435 1436 _ctx.resetPath(); 1437 _ctx.moveTo(x, y); 1438 1439 for (uint32_t p = 1; p < complexity; p++) { 1440 x = _rnd_coord.next_double(base.x, base.x + wh); 1441 y = _rnd_coord.next_double(base.y, base.y + wh); 1442 _ctx.lineTo(x, y); 1443 } 1444 1445 setup_style(op, BLRect(base.x, base.y, wh, wh)); 1446 _ctx.drawPath(draw_path_flag); 1447 } 1448 } 1449 1450 void AggModule::render_shape(RenderOp op, ShapeData shape) { 1451 BLSizeI bounds(_params.screen_w - _params.shape_size, 1452 _params.screen_h - _params.shape_size); 1453 1454 StyleKind style = _params.style; 1455 double wh = double(_params.shape_size); 1456 1457 prepare_fill_stroke_option(op); 1458 _ctx.fillEvenOdd(op == RenderOp::kFillEvenOdd); 1459 1460 Agg2D::DrawPathFlag draw_path_flag = op == RenderOp::kStroke ? Agg2D::StrokeOnly : Agg2D::FillOnly; 1461 1462 for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) { 1463 BLPoint base(_rnd_coord.nextPoint(bounds)); 1464 ShapeIterator it(shape); 1465 1466 _ctx.resetPath(); 1467 while (it.has_command()) { 1468 if (it.is_move_to()) { 1469 _ctx.moveTo(base.x + it.x(0) * wh, base.y + it.y(0) * wh); 1470 } 1471 else if (it.is_line_to()) { 1472 _ctx.lineTo(base.x + it.x(0) * wh, base.y + it.y(0) * wh); 1473 } 1474 else if (it.is_quad_to()) { 1475 _ctx.quadricCurveTo( 1476 base.x + it.x(0) * wh, base.y + it.y(0) * wh, 1477 base.x + it.x(1) * wh, base.y + it.y(1) * wh 1478 ); 1479 } 1480 else if (it.is_cubic_to()) { 1481 _ctx.cubicCurveTo( 1482 base.x + it.x(0) * wh, base.y + it.y(0) * wh, 1483 base.x + it.x(1) * wh, base.y + it.y(1) * wh, 1484 base.x + it.x(2) * wh, base.y + it.y(2) * wh 1485 ); 1486 } 1487 else { 1488 _ctx.closePolygon(); 1489 } 1490 it.next(); 1491 } 1492 1493 setup_style(op, BLRect(base.x, base.y, wh, wh)); 1494 _ctx.drawPath(draw_path_flag); 1495 } 1496 } 1497 1498 Backend* create_agg_backend() { 1499 return new AggModule(); 1500 } 1501 1502 } // {blbench} 1503 1504 #endif // BL_BENCH_ENABLE_AGG