1 /* === S Y N F I G ========================================================= */ 2 /*! \file synfig/rendering/software/function/blurtemplates.h 3 ** \brief Blur Templates Header 4 ** 5 ** $Id$ 6 ** 7 ** \legal 8 ** ......... ... 2015 Ivan Mahonin 9 ** 10 ** This package is free software; you can redistribute it and/or 11 ** modify it under the terms of the GNU General Public License as 12 ** published by the Free Software Foundation; either version 2 of 13 ** the License, or (at your option) any later version. 14 ** 15 ** This package is distributed in the hope that it will be useful, 16 ** but WITHOUT ANY WARRANTY; without even the implied warranty of 17 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 ** General Public License for more details. 19 ** \endlegal 20 */ 21 /* ========================================================================= */ 22 23 /* === S T A R T =========================================================== */ 24 25 #ifndef __SYNFIG_RENDERING_SOFTWARE_BLURTEMPLATES_H 26 #define __SYNFIG_RENDERING_SOFTWARE_BLURTEMPLATES_H 27 28 /* === H E A D E R S ======================================================= */ 29 30 #include <cassert> 31 32 #include <algorithm> 33 #include <deque> 34 35 #include "array.h" 36 37 #include <synfig/angle.h> 38 #include <synfig/surface.h> 39 40 /* === M A C R O S ========================================================= */ 41 42 /* === T Y P E D E F S ===================================================== */ 43 44 /* === C L A S S E S & S T R U C T S ======================================= */ 45 46 namespace synfig 47 { 48 namespace rendering 49 { 50 namespace software 51 { 52 53 class BlurTemplates 54 { 55 public: 56 template<typename T> amplifier_box()57 static T amplifier_box() { return T(0.25)*sqrt(T(PI)); } 58 template<typename T> amplifier_cross()59 static T amplifier_cross() { return T(1.0); } 60 template<typename T> amplifier_disk()61 static T amplifier_disk() { return T(0.5); } 62 template<typename T> amplifier_gauss()63 static T amplifier_gauss() { return T(3.0)/T(8.0); } 64 template<typename T> amplifier_fastgauss()65 static T amplifier_fastgauss() { return amplifier_gauss<T>(); } 66 67 68 template<typename T> operatorAbs69 struct Abs { T operator() (const T &x) { return abs(x); } }; 70 71 template<typename T> gauss(const T & x,const T & r)72 static T gauss(const T &x, const T &r) 73 { 74 static const T precision(1e-10); 75 static const T k( T(1.0)/sqrt(T(2.0)*PI) ); 76 if (fabs(r) < precision) 77 return fabs(x) < precision ? T(1.0) : T(0.0); 78 return k*exp(T(-0.5)*x*x/(r*r))/r; 79 } 80 81 template<typename T> ungauss(const T & x)82 static T ungauss(const T &x) 83 { 84 static const T k( T(1.0)/sqrt(T(2.0)*PI) ); 85 return sqrt(-T(2.0)*log(x/k)); 86 } 87 88 template<typename T> fill_pattern_box(const Array<T,1> & x,const T & size)89 static void fill_pattern_box(const Array<T, 1> &x, const T &size) 90 { 91 typedef Array<T, 1> A; 92 93 const T precision(1e-10); 94 T s(fabs(size)); 95 int sizei = 1 + (int)floor(s + precision); 96 97 /// assume that pattern already contains zeros 98 for(typename A::Iterator i(x, 0, std::min(sizei, x.count)); i; ++i) 99 *i = T(1.0); 100 101 // antialiasing 102 if (sizei < x.count) 103 x[sizei] = T(sizei-1) - s; 104 } 105 106 template<typename T> fill_pattern_gauss(const Array<T,1> & x,T size)107 static void fill_pattern_gauss(const Array<T, 1> &x, T size) 108 { 109 if (x.count <= 0) return; 110 T s = T(0.5)+fabs(size); 111 x[0] = gauss(T(0.0), s); 112 for(int i = 0; i < x.count; ++i) 113 x[i] = gauss(T(i), s); 114 } 115 116 template<typename T> fill_pattern_2d_disk(const Array<T,2> & x,const T & size_x,const T & size_y)117 static void fill_pattern_2d_disk(const Array<T, 2> &x, const T &size_x, const T &size_y) 118 { 119 const T precision(1e-10); 120 121 T sx(T(0.5) + fabs(size_x)); 122 T sy(T(0.5) + fabs(size_y)); 123 124 int sizec = std::min(x.get_count(1)-1, (int)ceil(sx - precision)); 125 int sizer = std::min(x.get_count(0)-1, (int)ceil(sy - precision)); 126 127 // draw sector 128 T k0x(sx - T(0.5)), k0y(sy - T(0.5)); 129 T k1x(sx + T(0.5)), k1y(sy + T(0.5)); 130 T kk0x( k0x > precision ? T(1.0)/k0x : T(0.0) ); 131 T kk0y( k0y > precision ? T(1.0)/k0y : T(0.0) ); 132 T kk1x( k1x > precision ? T(1.0)/k1x : T(0.0) ); 133 T kk1y( k1y > precision ? T(1.0)/k1y : T(0.0) ); 134 T pp0x(0.0), pp0y(0.0); 135 T pp1x(0.0), pp1y(0.0); 136 for(int r = 0; r <= sizer; ++r) 137 { 138 for(int c = 0; c <= sizec; ++c) 139 { 140 T &v = x[r][c]; 141 T r1_squared = pp1x*pp1x + pp1y*pp1y; 142 /// assume that pattern already contains zeros 143 if (r1_squared < T(1.0)) 144 { 145 T r0_squared = pp0x*pp0x + pp0y*pp0y; 146 if (r0_squared <= T(1.0)) 147 { 148 v = T(1.0); 149 } 150 else 151 { 152 T rr0 = sqrt(r0_squared); 153 T rr1 = sqrt(r1_squared); 154 T drr = rr0 - rr1; 155 v = drr > precision ? rr0*(1.0 - rr1)/drr : T(0.0); 156 } 157 } 158 pp0x += kk0x; 159 pp1x += kk1x; 160 } 161 pp0x = T(0.0); pp0y += kk0y; 162 pp1x = T(0.0); pp1y += kk1y; 163 } 164 165 /// assume that pattern already contains zeros 166 /// and don't touch other cells 167 } 168 169 template<typename T> mirror_pattern(const Array<T,1> & x)170 static void mirror_pattern(const Array<T, 1> &x) 171 { 172 typedef Array<T, 1> A; 173 int count = (x.count-1)/2; 174 typename A::ReverseIterator j(x); 175 for(typename A::Iterator i(x, 1, 1 + count); i; ++i, ++j) 176 *j = *i; 177 } 178 179 template<typename T> mirror_pattern_2d(const Array<T,2> & x)180 static void mirror_pattern_2d(const Array<T, 2> &x) 181 { 182 typedef Array<T, 2> A; 183 int count = (x.count-1)/2; 184 for(typename A::Iterator i(x, 1, 1 + count); i; ++i) 185 mirror_pattern(*i); 186 for(typename A::Iterator i(x.reorder(1, 0)); i; ++i) 187 mirror_pattern(*i); 188 } 189 190 template<typename T> normalize_full_pattern(const Array<T,1> & x)191 static void normalize_full_pattern(const Array<T, 1> &x) 192 { 193 const T precision(1e-10); 194 typedef Array<T, 1> A; 195 T sum = T(0.0); 196 for(typename A::Iterator i(x); i; ++i) 197 sum += *i; 198 if (sum > precision) 199 { 200 T k = T(1.0)/sum; 201 for(typename A::Iterator i(x); i; ++i) 202 *i *= k; 203 } 204 } 205 206 template<typename T> normalize_half_pattern(const Array<T,1> & x)207 static void normalize_half_pattern(const Array<T, 1> &x) 208 { 209 if (x.count <= 0) return; 210 const T precision(1e-10); 211 typedef Array<T, 1> A; 212 T sum = x[0]; 213 for(typename A::Iterator i(x, 1); i; ++i) 214 sum += T(2.0)*(*i); 215 if (sum > precision) 216 { 217 T k = T(1.0)/sum; 218 for(typename A::Iterator i(x); i; ++i) 219 *i *= k; 220 } 221 } 222 223 template<typename T> normalize_full_pattern_2d(const Array<T,2> & x)224 static void normalize_full_pattern_2d(const Array<T, 2> &x) 225 { 226 if (x.get_count(0) <= 0 || x.get_count(1) <= 0) return; 227 const T precision(1e-10); 228 typedef Array<T, 2> A; 229 typedef Array<T, 1> B; 230 T sum = T(0.0); 231 for(typename A::Iterator i(x); i; ++i) 232 for(typename B::Iterator j(*i); j; ++j) 233 sum += *j; 234 if (sum > precision) 235 { 236 T k = T(1.0)/sum; 237 for(typename A::Iterator i(x); i; ++i) 238 for(typename B::Iterator j(*i); j; ++j) 239 *j *= k; 240 } 241 } 242 243 template<typename T> normalize_half_pattern_2d(const Array<T,2> & x)244 static void normalize_half_pattern_2d(const Array<T, 2> &x) 245 { 246 if (x.get_count(0) <= 0 || x.get_count(1) <= 0) return; 247 const T precision(1e-10); 248 typedef Array<T, 2> A; 249 typedef Array<T, 1> B; 250 T sum = x[0][0]; 251 for(typename A::Iterator i(x, 1); i; ++i) 252 sum += T(2.0)*(*i)[0]; 253 for(typename B::Iterator j(x[0], 1); j; ++j) 254 sum += T(2.0)*(*j); 255 for(typename A::Iterator i(x, 1); i; ++i) 256 for(typename B::Iterator j(*i, 1); j; ++j) 257 sum += T(4.0)*(*j); 258 if (sum > precision) 259 { 260 T k = T(1.0)/sum; 261 for(typename A::Iterator i(x); i; ++i) 262 for(typename B::Iterator j(*i); j; ++j) 263 *j *= k; 264 } 265 } 266 267 template<typename T> blur_pattern(const Array<T,1> & dst,const Array<T,1> & src,const Array<T,1> & pattern)268 static void blur_pattern(const Array<T, 1> &dst, const Array<T, 1> &src, const Array<T, 1> &pattern) 269 { 270 typedef Array<T, 1> A; 271 if (pattern.count <= 0) 272 { 273 dst.assign(src); 274 return; 275 } 276 277 int pattern_size = pattern.count - 1; 278 int end = std::min(src.count, dst.count) - pattern_size; 279 280 int si = pattern_size; 281 for(typename A::Iterator di(dst, pattern_size, end); di; ++di, ++si) 282 { 283 (*di) += src[si] * pattern[0]; 284 for(int i = 1; i <= pattern_size; ++i) 285 (*di) += (src[si - i] + src[si + i])*pattern[i]; 286 } 287 } 288 289 template<typename T> blur_2d_pattern(const Array<T,2> & dst,const Array<T,2> & src,const Array<T,2> & pattern)290 static void blur_2d_pattern(const Array<T, 2> &dst, const Array<T, 2> &src, const Array<T, 2> &pattern) 291 { 292 typedef Array<T, 2> A; 293 typedef Array<T, 1> B; 294 if (pattern.get_count(0) <= 0 || pattern.get_count(1) <= 0) 295 { 296 dst.assign(src); 297 return; 298 } 299 300 int pattern_size0 = pattern.get_count(0) - 1; 301 int pattern_size1 = pattern.get_count(1) - 1; 302 int end0 = std::min(src.get_count(0), dst.get_count(0)) - pattern_size0; 303 int end1 = std::min(src.get_count(1), dst.get_count(1)) - pattern_size1; 304 305 int si0 = pattern_size0; 306 int si1 = pattern_size1; 307 for(typename A::Iterator di0(dst, pattern_size0, end0); di0; ++di0, ++si0, si1 = pattern_size1) 308 for(typename B::Iterator di1(*di0, pattern_size1, end1); di1; ++di1, ++si1) 309 { 310 (*di1) += src[si0][si1]*pattern[0][0]; 311 312 for(int i0 = 1; i0 <= pattern_size0; ++i0) 313 (*di1) += (src[si0 - i0][si1] + src[si0 + i0][si1])*pattern[i0][0]; 314 for(int i1 = 1; i1 <= pattern_size1; ++i1) 315 (*di1) += (src[si0][si1 - i1] + src[si0][si1 + i1])*pattern[0][i1]; 316 317 for(int i0 = 1; i0 <= pattern_size0; ++i0) 318 for(int i1 = 1; i1 <= pattern_size1; ++i1) 319 (*di1) += pattern[i0][i1]*( src[si0 - i0][si1 - i1] 320 + src[si0 - i0][si1 + i1] 321 + src[si0 + i0][si1 - i1] 322 + src[si0 + i0][si1 + i1] ); 323 } 324 } 325 326 template<typename T> blur_box_discrete(const Array<T,1> & x,std::deque<T> & q,const int size)327 static void blur_box_discrete(const Array<T, 1> &x, std::deque<T> &q, const int size) 328 { 329 typedef Array<T, 1> A; 330 if (size == 0) return; 331 332 int s = abs(size); 333 int full_size = 1 + 2*s; 334 if (x.count < full_size) return; 335 T w(T(1.0)/T(full_size)); 336 T sum(0.0); 337 q.clear(); 338 for(typename A::Iterator i(x, 0, full_size); i; ++i) 339 { q.push_back(*i); sum += *i; } 340 for(typename A::Iterator i(x, full_size), j(x, s); i; ++i, ++j) 341 { 342 *j = w*sum; 343 sum += *i - q.front(); 344 q.pop_front(); 345 q.push_back(*i); 346 } 347 } 348 349 template<typename T> blur_box_discrete(const Array<T,1> & dst,const Array<const T,1> & src,const int size,const int offset)350 static void blur_box_discrete(const Array<T, 1> &dst, const Array<const T, 1> &src, const int size, const int offset) 351 { 352 typedef Array<T, 1> A; 353 typedef Array<const T, 1> B; 354 355 int s = abs(size); 356 int o0 = std::max(offset - s, 0); 357 int o1 = std::max(s - offset, 0); 358 if (o0 >= src.count) return; 359 if (o1 >= dst.count) return; 360 361 if (s == 0) 362 { 363 // copy 364 typename B::Iterator j(dst, o1); 365 for(typename A::Iterator i(src, o0); i && j; ++i, ++j) 366 *j = *i; 367 } 368 else 369 { 370 int full_size = 1 + 2*s; 371 if (full_size + o0 > src.count) return; 372 T w(T(1.0)/T(full_size)); 373 T sum(0.0); 374 for(typename A::Iterator i(src, o0, full_size+o0); i; ++i) 375 sum += *i; 376 typename B::Iterator j(dst, o1); 377 for(typename A::Iterator i0(src, o0), i1(src, full_size+o0); i1 && j; ++i0, ++j, ++i1) 378 { 379 *j = w*sum; 380 sum += *i1 - *i0; 381 } 382 } 383 } 384 385 template<typename T> blur_box_aa(const Array<T,1> & x,std::deque<T> & q,const T & size)386 static void blur_box_aa(const Array<T, 1> &x, std::deque<T> &q, const T &size) 387 { 388 typedef Array<T, 1> A; 389 390 const T precision(1e-10); 391 T s(fabs(size)); 392 if (s < precision) return; 393 394 int sizei = 1 + (int)floor(s + precision); 395 if (x.count <= 2*sizei) return; 396 397 T w(T(1.0)/(T(1.0) + T(2.0)*s)); 398 T aa(T(sizei) - s); 399 T sum(0.0); 400 T aa_out = x[0]; 401 q.clear(); 402 for(typename A::Iterator i(x, 1, 2*sizei); i; ++i) 403 { q.push_back(*i); sum += *i; } 404 q.push_back(x[2*sizei]); 405 sum += aa*(aa_out + q.back()); 406 for(typename A::Iterator i(x, 2*sizei+1), j(x, sizei); i; ++i, ++j) 407 { 408 *j = w*sum; 409 T d = q.back() - q.front(); 410 sum += aa*(*i - aa_out - d) + d; 411 aa_out = q.front(); 412 q.pop_front(); 413 q.push_back(*i); 414 } 415 } 416 417 template<typename T> blur_box_aa(const Array<T,1> & dst,const Array<const T,1> & src,const T & size,const int offset)418 static void blur_box_aa(const Array<T, 1> &dst, const Array<const T, 1> &src, const T &size, const int offset) 419 { 420 typedef Array<T, 1> A; 421 typedef Array<const T, 1> B; 422 const T precision(1e-10); 423 424 T s(fabs(size)); 425 int sizei = 1 + (int)floor(s + precision); 426 int o0 = std::max(offset - sizei - 1, 0); 427 int o1 = std::max(sizei + 1 - offset, 0); 428 if (o0 >= src.count) return; 429 if (o1 >= dst.count) return; 430 431 if (s < precision) 432 { 433 // copy 434 typename B::Iterator j(dst, o1); 435 for(typename A::Iterator i(src, o0); i && j; ++i, ++j) 436 *j = *i; 437 } 438 else 439 { 440 if (2*sizei + o0 >= src.count) return; 441 T w(T(1.0)/(T(1.0) + T(2.0)*s)); 442 T aa(T(sizei) - s); 443 T sum(0.0); 444 T aa_out = src[o0]; 445 for(typename A::Iterator i(src, o0, 2*sizei+o0); i; ++i) 446 sum += *i; 447 T aa_in = src[2*sizei+o0]; 448 sum += aa*(aa_out + aa_in); 449 typename B::Iterator j(dst, o1); 450 for(typename A::Iterator i0(src, o0+1), i1(src, 2*sizei+o0+1); i1 && j; ++i0, ++j, ++i1) 451 { 452 *j = w*sum; 453 T d = aa_in - *i0; 454 sum += aa(*i1 - aa_out - d) + d; 455 aa_out = *i0; 456 aa_in = *i1; 457 } 458 } 459 } 460 461 template<typename T> blur_box(const Array<T,1> & x,std::deque<T> & q,const T & size)462 static void blur_box(const Array<T, 1> &x, std::deque<T> &q, const T &size) 463 { 464 const T precision(1e-5); 465 if (fabs(size - round(size)) < precision) 466 blur_box_discrete(x, q, (int)round(size)); 467 else 468 blur_box_aa(x, q, size); 469 } 470 471 template<typename T> blur_box(const Array<T,1> & dst,const Array<const T,1> & src,const T & size,const int offset)472 static void blur_box(const Array<T, 1> &dst, const Array<const T, 1> &src, const T &size, const int offset) 473 { 474 const T precision(1e-5); 475 if (fabs(size - round(size)) < precision) 476 blur_box_discrete(dst, src, (int)round(size), offset); 477 else 478 blur_box_aa(dst, src, size, offset); 479 } 480 481 template<typename T> blur_iir(const Array<T,1> & x,const T & k0,const T & k1,const T & k2,const T & k3)482 static void blur_iir(const Array<T, 1> &x, const T &k0, const T &k1, const T &k2, const T &k3) 483 { 484 typedef Array<T, 1> A; 485 T d3(0.0), d2(0.0), d1(0.0), d0; 486 for(typename A::Iterator i(x); i; ++i) 487 *i = d0 = k0*(*i) + k1*d1 + k2*d2 + k3*d3, d3 = d2, d2 = d1, d1 = d0; 488 d3 = d2 = d1 = T(0.0); 489 for(typename A::ReverseIterator i(x); i; ++i) 490 *i = d0 = k0*(*i) + k1*d1 + k2*d2 + k3*d3, d3 = d2, d2 = d1, d1 = d0; 491 } 492 493 template<typename T> blur_iir(const Array<T,1> & dst,const Array<T,1> & src,const T & k0,const T & k1,const T & k2,const T & k3)494 static void blur_iir(const Array<T, 1> &dst, const Array<T, 1> &src, const T &k0, const T &k1, const T &k2, const T &k3) 495 { 496 typedef Array<T, 1> A; 497 int count = std::min(dst.count, src.count); 498 T d3(0.0), d2(0.0), d1(0.0), d0; 499 dst[0] = dst[1] = dst[2] = dst[dst.count - 1] = dst[dst.count - 2] = dst[dst.count - 3] = 0.0; 500 for(typename A::Iterator j(dst, count), i(src, count); j; ++j, ++i) 501 *j = d0 = k0*(*i) + k1*d1 + k2*d2 + k3*d3, d3 = d2, d2 = d1, d1 = d0; 502 d3 = d2 = d1 = T(0.0); 503 for(typename A::ReverseIterator j(dst, dst.count - count), i(src, src.count - count); j; ++j, ++i) 504 *j = d0 = k0*(*i) + k1*d1 + k2*d2 + k3*d3, d3 = d2, d2 = d1, d1 = d0; 505 } 506 surface_as_array(Array<const Color,2> & a,const synfig::Surface & src,const RectInt & r)507 static void surface_as_array(Array<const Color, 2> &a, const synfig::Surface &src, const RectInt &r) 508 { 509 assert(src.is_valid() && r.is_valid()); 510 assert(r.minx >= 0 && r.miny >= 0); 511 assert(r.maxx <= src.get_w() && r.miny <= src.get_h()); 512 a.pointer = &src[r.miny][r.minx]; 513 a.set_dim(r.maxy - r.miny, src.get_pitch()/sizeof(Color)) 514 .set_dim(r.maxx - r.minx, 1); 515 } 516 surface_as_array(Array<Color,2> & a,synfig::Surface & src,const RectInt & r)517 static void surface_as_array(Array<Color, 2> &a, synfig::Surface &src, const RectInt &r) 518 { 519 assert(src.is_valid() && r.is_valid()); 520 assert(r.minx >= 0 && r.miny >= 0); 521 assert(r.maxx <= src.get_w() && r.miny <= src.get_h()); 522 a.pointer = &src[r.miny][r.minx]; 523 a.set_dim(r.maxy - r.miny, src.get_pitch()/sizeof(Color)) 524 .set_dim(r.maxx - r.minx, 1); 525 } 526 surface_as_array(synfig::Surface & src)527 static Array<Color, 2> surface_as_array(synfig::Surface &src) 528 { Array<Color, 2> a; surface_as_array(a, src, RectInt(0, 0, src.get_w(), src.get_h())); return a; } surface_as_array(synfig::Surface & src,const RectInt & r)529 static Array<Color, 2> surface_as_array(synfig::Surface &src, const RectInt &r) 530 { Array<Color, 2> a; surface_as_array(a, src, r); return a; } 531 surface_as_array(const synfig::Surface & src)532 static Array<const Color, 2> surface_as_array(const synfig::Surface &src) 533 { Array<const Color, 2> a; surface_as_array(a, src, RectInt(0, 0, src.get_w(), src.get_h())); return a; } surface_as_array(const synfig::Surface & src,const RectInt & r)534 static Array<const Color, 2> surface_as_array(const synfig::Surface &src, const RectInt &r) 535 { Array<const Color, 2> a; surface_as_array(a, src, r); return a; } 536 537 template<typename T> surface_read(const Array<T,3> & dst,const Array<const Color,2> & src)538 static void surface_read( 539 const Array<T, 3> &dst, 540 const Array<const Color, 2> &src ) 541 { 542 assert(dst.count == src.count); 543 assert(dst.sub().count == src.sub().count); 544 assert(dst.sub().sub().count == 4); 545 Array<const Color, 2>::Iterator rr(src); 546 for(typename Array<T, 3>::Iterator r(dst); r; ++r, ++rr) 547 { 548 Array<const Color, 1>::Iterator cc(*rr); 549 for(typename Array<T, 2>::Iterator c(*r); c; ++c, ++cc) 550 { 551 T a = cc->get_a(); 552 (*c)[0] = cc->get_r()*a; 553 (*c)[1] = cc->get_g()*a; 554 (*c)[2] = cc->get_b()*a; 555 (*c)[3] = a; 556 } 557 } 558 } 559 560 template<typename T> surface_read(const Array<T,3> & dst,const synfig::Surface & src,const VectorInt & dst_offset,const RectInt & src_rect)561 static void surface_read( 562 const Array<T, 3> &dst, 563 const synfig::Surface &src, 564 const VectorInt &dst_offset, 565 const RectInt &src_rect ) 566 { 567 RectInt dst_rect = src_rect - src_rect.get_min() + dst_offset; 568 Array<T, 3> dst_range = dst.get_range(1, dst_rect.minx, dst_rect.maxx) 569 .get_range(0, dst_rect.miny, dst_rect.maxy); 570 Array<const Color, 2> src_range = surface_as_array(src, src_rect); 571 surface_read(dst_range, src_range); 572 } 573 574 template<typename T> surface_write(const Array<Color,2> & dst,const Array<T,3> & src)575 static void surface_write( 576 const Array<Color, 2> &dst, 577 const Array<T, 3> &src ) 578 { 579 assert(dst.count == src.count); 580 assert(dst.sub().count == src.sub().count); 581 assert(src.sub().sub().count == 4); 582 const ColorReal precision = 1e-10; 583 Array<Color, 2>::Iterator rr(dst); 584 for(typename Array<T, 3>::Iterator r(src); r; ++r, ++rr) 585 { 586 Array<Color, 1>::Iterator cc(*rr); 587 for(typename Array<T, 2>::Iterator c(*r); c; ++c, ++cc) 588 { 589 Real a = (*c)[3]; 590 Real one_div_a = fabs(a) < precision ? 0.0 : 1.0/a; 591 Color color((*c)[0]*one_div_a, (*c)[1]*one_div_a, (*c)[2]*one_div_a, a); 592 *cc = color; 593 } 594 } 595 } 596 597 template<typename T> surface_write(const Array<Color,2> & dst,const Array<T,3> & src,Color::BlendMethod blend_method,ColorReal amount)598 static void surface_write( 599 const Array<Color, 2> &dst, 600 const Array<T, 3> &src, 601 Color::BlendMethod blend_method, 602 ColorReal amount ) 603 { 604 assert(dst.count == src.count); 605 assert(dst.sub().count == src.sub().count); 606 assert(src.sub().sub().count == 4); 607 const ColorReal precision = 1e-10; 608 Array<Color, 2>::Iterator rr(dst); 609 for(typename Array<T, 3>::Iterator r(src); r; ++r, ++rr) 610 { 611 Array<Color, 1>::Iterator cc(*rr); 612 for(typename Array<T, 2>::Iterator c(*r); c; ++c, ++cc) 613 { 614 ColorReal a = (*c)[3]; 615 Real one_div_a = fabs(a) < precision ? 0.0 : 1.0/a; 616 Color color((*c)[0]*one_div_a, (*c)[1]*one_div_a, (*c)[2]*one_div_a, a); 617 *cc = Color::blend(color, *cc, amount, blend_method); 618 } 619 } 620 } 621 622 template<typename T> surface_write(synfig::Surface & dst,const Array<T,3> & src,const RectInt & dst_rect,const VectorInt & src_offset,bool blend,Color::BlendMethod blend_method,ColorReal amount)623 static void surface_write( 624 synfig::Surface &dst, 625 const Array<T, 3> &src, 626 const RectInt &dst_rect, 627 const VectorInt &src_offset, 628 bool blend, 629 Color::BlendMethod blend_method, 630 ColorReal amount ) 631 { 632 RectInt src_rect = dst_rect - dst_rect.get_min() + src_offset; 633 Array<Color, 2> dst_range = surface_as_array(dst, dst_rect); 634 Array<T, 3> src_range = src.get_range(1, src_rect.minx, src_rect.maxx) 635 .get_range(0, src_rect.miny, src_rect.maxy); 636 if (blend) surface_write(dst_range, src_range, blend_method, amount); 637 else surface_write(dst_range, src_range); 638 } 639 }; 640 641 } /* end namespace software */ 642 } /* end namespace rendering */ 643 } /* end namespace synfig */ 644 645 /* -- E N D ----------------------------------------------------------------- */ 646 647 #endif 648