Changeset View
Changeset View
Standalone View
Standalone View
libs/pigment/compositeops/KoCompositeOpFunctions.h
Show First 20 Lines • Show All 170 Lines • ▼ Show 20 Line(s) | 170 | inline T cfLinearBurn(T src, T dst) { | |||
---|---|---|---|---|---|
171 | using namespace Arithmetic; | 171 | using namespace Arithmetic; | ||
172 | typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type; | 172 | typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type; | ||
173 | return clamp<T>(composite_type(src) + dst - unitValue<T>()); | 173 | return clamp<T>(composite_type(src) + dst - unitValue<T>()); | ||
174 | } | 174 | } | ||
175 | 175 | | |||
176 | template<class T> | 176 | template<class T> | ||
177 | inline T cfColorDodge(T src, T dst) { | 177 | inline T cfColorDodge(T src, T dst) { | ||
178 | using namespace Arithmetic; | 178 | using namespace Arithmetic; | ||
179 | //Fixing Color Dodge to avoid ZX Colors on bright area. | ||||
179 | 180 | | |||
180 | if(dst == zeroValue<T>()) | 181 | if(src == unitValue<T>()) | ||
181 | return zeroValue<T>(); | 182 | return unitValue<T>(); | ||
182 | 183 | | |||
183 | T invSrc = inv(src); | 184 | T invSrc = inv(src); | ||
184 | 185 | | |||
185 | if(invSrc < dst) | 186 | if(invSrc == zeroValue<T>()) | ||
186 | return unitValue<T>(); | 187 | return unitValue<T>(); | ||
187 | 188 | | |||
188 | return Arithmetic::clamp<T>(div(dst, invSrc)); | 189 | return Arithmetic::clamp<T>(div(dst, invSrc)); | ||
189 | } | 190 | } | ||
190 | 191 | | |||
191 | template<class T> | 192 | template<class T> | ||
192 | inline T cfAddition(T src, T dst) { | 193 | inline T cfAddition(T src, T dst) { | ||
193 | typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type; | 194 | typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type; | ||
▲ Show 20 Lines • Show All 149 Lines • ▼ Show 20 Line(s) | |||||
343 | inline T cfParallel(T src, T dst) { | 344 | inline T cfParallel(T src, T dst) { | ||
344 | using namespace Arithmetic; | 345 | using namespace Arithmetic; | ||
345 | typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type; | 346 | typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type; | ||
346 | 347 | | |||
347 | // min(max(2 / (1/dst + 1/src), 0), 1) | 348 | // min(max(2 / (1/dst + 1/src), 0), 1) | ||
348 | composite_type unit = unitValue<T>(); | 349 | composite_type unit = unitValue<T>(); | ||
349 | composite_type s = (src != zeroValue<T>()) ? div<T>(unit, src) : unit; | 350 | composite_type s = (src != zeroValue<T>()) ? div<T>(unit, src) : unit; | ||
350 | composite_type d = (dst != zeroValue<T>()) ? div<T>(unit, dst) : unit; | 351 | composite_type d = (dst != zeroValue<T>()) ? div<T>(unit, dst) : unit; | ||
352 | if (src == zeroValue<T>()) { | ||||
353 | return zeroValue<T>(); | ||||
354 | } | ||||
355 | | ||||
356 | if (dst == zeroValue<T>()) { | ||||
357 | return zeroValue<T>(); | ||||
358 | } | ||||
359 | | ||||
351 | return clamp<T>((unit+unit) * unit / (d+s)); | 360 | return clamp<T>((unit+unit) * unit / (d+s)); | ||
352 | } | 361 | } | ||
353 | 362 | | |||
354 | template<class T> | 363 | template<class T> | ||
355 | inline T cfEquivalence(T src, T dst) { | 364 | inline T cfEquivalence(T src, T dst) { | ||
356 | typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type; | 365 | typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type; | ||
357 | // 1 - abs(dst - src) | 366 | // 1 - abs(dst - src) | ||
358 | composite_type x = composite_type(dst) - src; | 367 | composite_type x = composite_type(dst) - src; | ||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Line(s) | |||||
409 | 418 | | |||
410 | template<class T> | 419 | template<class T> | ||
411 | inline T cfGammaLight(T src, T dst) { | 420 | inline T cfGammaLight(T src, T dst) { | ||
412 | using namespace Arithmetic; | 421 | using namespace Arithmetic; | ||
413 | return scale<T>(pow(scale<qreal>(dst), scale<qreal>(src))); | 422 | return scale<T>(pow(scale<qreal>(dst), scale<qreal>(src))); | ||
414 | } | 423 | } | ||
415 | 424 | | |||
416 | template<class T> | 425 | template<class T> | ||
426 | inline T cfGammaIllumination(T src, T dst) { | ||||
427 | using namespace Arithmetic; | ||||
428 | return inv(cfGammaDark(inv(src),inv(dst))); | ||||
429 | } | ||||
430 | | ||||
431 | template<class T> | ||||
417 | inline T cfGeometricMean(T src, T dst) { | 432 | inline T cfGeometricMean(T src, T dst) { | ||
418 | using namespace Arithmetic; | 433 | using namespace Arithmetic; | ||
419 | return scale<T>(sqrt(scale<qreal>(dst) * scale<qreal>(src))); | 434 | return scale<T>(sqrt(scale<qreal>(dst) * scale<qreal>(src))); | ||
420 | } | 435 | } | ||
421 | 436 | | |||
422 | template<class T> | 437 | template<class T> | ||
423 | inline T cfOver(T src, T dst) { Q_UNUSED(dst); return src; } | 438 | inline T cfOver(T src, T dst) { Q_UNUSED(dst); return src; } | ||
424 | 439 | | |||
425 | template<class T> | 440 | template<class T> | ||
426 | inline T cfOverlay(T src, T dst) { return cfHardLight(dst, src); } | 441 | inline T cfOverlay(T src, T dst) { return cfHardLight(dst, src); } | ||
427 | 442 | | |||
428 | template<class T> | 443 | template<class T> | ||
429 | inline T cfMultiply(T src, T dst) { return Arithmetic::mul(src, dst); } | 444 | inline T cfMultiply(T src, T dst) { return Arithmetic::mul(src, dst); } | ||
430 | 445 | | |||
431 | template<class T> | 446 | template<class T> | ||
432 | inline T cfHardOverlay(T src, T dst) { | 447 | inline T cfHardOverlay(T src, T dst) { | ||
433 | using namespace Arithmetic; | 448 | using namespace Arithmetic; | ||
434 | 449 | | |||
435 | qreal fsrc = scale<qreal>(src); | 450 | qreal fsrc = scale<qreal>(src); | ||
436 | qreal fdst = scale<qreal>(dst); | 451 | qreal fdst = scale<qreal>(dst); | ||
437 | 452 | | |||
453 | if (fsrc == 1.0) { | ||||
454 | return scale<T>(1.0);} | ||||
455 | | ||||
438 | if(fsrc > 0.5f) { | 456 | if(fsrc > 0.5f) { | ||
439 | return scale<T>(cfDivide(inv(2.0 * fsrc - 1.0f), fdst)); | 457 | return scale<T>(cfDivide(inv(2.0 * fsrc - 1.0f), fdst)); | ||
440 | } | 458 | } | ||
441 | return scale<T>(mul(2.0 * fsrc, fdst)); | 459 | return scale<T>(mul(2.0 * fsrc, fdst)); | ||
442 | } | 460 | } | ||
443 | 461 | | |||
444 | template<class T> | 462 | template<class T> | ||
445 | inline T cfDifference(T src, T dst) { return qMax(src,dst) - qMin(src,dst); } | 463 | inline T cfDifference(T src, T dst) { return qMax(src,dst) - qMin(src,dst); } | ||
446 | 464 | | |||
447 | template<class T> | 465 | template<class T> | ||
448 | inline T cfScreen(T src, T dst) { return Arithmetic::unionShapeOpacity(src, dst); } | 466 | inline T cfScreen(T src, T dst) { return Arithmetic::unionShapeOpacity(src, dst); } | ||
449 | 467 | | |||
450 | template<class T> | 468 | template<class T> | ||
451 | inline T cfDarkenOnly(T src, T dst) { return qMin(src, dst); } | 469 | inline T cfDarkenOnly(T src, T dst) { return qMin(src, dst); } | ||
452 | 470 | | |||
453 | template<class T> | 471 | template<class T> | ||
454 | inline T cfLightenOnly(T src, T dst) { return qMax(src, dst); } | 472 | inline T cfLightenOnly(T src, T dst) { return qMax(src, dst); } | ||
455 | 473 | | |||
456 | template<class T> | 474 | template<class T> | ||
457 | inline T cfGlow(T src, T dst) { | 475 | inline T cfGlow(T src, T dst) { | ||
458 | using namespace Arithmetic; | 476 | using namespace Arithmetic; | ||
459 | // see http://www.pegtop.net/delphi/articles/blendmodes/quadratic.htm for formulas of Quadratic Blending Modes like Glow, Reflect, Freeze, and Heat | 477 | // see http://www.pegtop.net/delphi/articles/blendmodes/quadratic.htm for formulas of Quadratic Blending Modes like Glow, Reflect, Freeze, and Heat | ||
460 | 478 | | |||
461 | if(dst == unitValue<T>()) { | 479 | if (dst == unitValue<T>()) { | ||
462 | return unitValue<T>(); | 480 | return unitValue<T>(); | ||
463 | } | 481 | } | ||
464 | 482 | | |||
465 | if(src == zeroValue<T>()) { | | |||
466 | return zeroValue<T>(); | | |||
467 | } | | |||
468 | | ||||
469 | return clamp<T>(div(mul(src, src), inv(dst))); | 483 | return clamp<T>(div(mul(src, src), inv(dst))); | ||
470 | } | 484 | } | ||
471 | 485 | | |||
472 | template<class T> | 486 | template<class T> | ||
473 | inline T cfReflect(T src, T dst) { | 487 | inline T cfReflect(T src, T dst) { | ||
474 | using namespace Arithmetic; | 488 | using namespace Arithmetic; | ||
475 | 489 | | |||
476 | return (cfGlow(dst,src)); | 490 | | ||
491 | return clamp<T>(cfGlow(dst,src)); | ||||
477 | } | 492 | } | ||
478 | 493 | | |||
479 | template<class T> | 494 | template<class T> | ||
480 | inline T cfHeat(T src, T dst) { | 495 | inline T cfHeat(T src, T dst) { | ||
481 | using namespace Arithmetic; | 496 | using namespace Arithmetic; | ||
482 | // Heat, and Freeze only works properly on 8-bit images. It does not work properly on any other color depth. For now, if Heat and Freeze are proven useful for 8-bit painting, then there should be some way of solving this issue. | 497 | | ||
498 | if(src == unitValue<T>()) { | ||||
499 | return unitValue<T>(); | ||||
500 | } | ||||
483 | 501 | | |||
484 | if(dst == zeroValue<T>()) { | 502 | if(dst == zeroValue<T>()) { | ||
485 | return zeroValue<T>(); | 503 | return zeroValue<T>(); | ||
486 | } | 504 | } | ||
487 | 505 | | |||
488 | if(src == unitValue<T>()) { | 506 | return inv(clamp<T>(div(mul(inv(src), inv(src)),dst))); | ||
507 | } | ||||
508 | | ||||
509 | template<class T> | ||||
510 | inline T cfFreeze(T src, T dst) { | ||||
511 | using namespace Arithmetic; | ||||
512 | | ||||
513 | return (cfHeat(dst,src)); | ||||
514 | } | ||||
515 | | ||||
516 | template<class T> | ||||
517 | inline T cfHelow(T src, T dst) { | ||||
518 | using namespace Arithmetic; | ||||
519 | // see http://www.pegtop.net/delphi/articles/blendmodes/quadratic.htm for formulas of Quadratic Blending Modes like Glow, Reflect, Freeze, and Heat | ||||
520 | | ||||
521 | if (cfHardMixPhotoshop(src,dst) == unitValue<T>()) { | ||||
522 | return cfHeat(src,dst); | ||||
523 | } | ||||
524 | | ||||
525 | if (src == zeroValue<T>()) { | ||||
526 | return zeroValue<T>(); | ||||
527 | } | ||||
528 | | ||||
529 | return (cfGlow(src,dst)); | ||||
530 | } | ||||
531 | | ||||
532 | template<class T> | ||||
533 | inline T cfFrect(T src, T dst) { | ||||
534 | using namespace Arithmetic; | ||||
535 | | ||||
536 | if (cfHardMixPhotoshop(src,dst) == unitValue<T>()) { | ||||
537 | return cfFreeze(src,dst); | ||||
538 | } | ||||
539 | | ||||
540 | if (dst == zeroValue<T>()) { | ||||
541 | return zeroValue<T>(); | ||||
542 | } | ||||
543 | | ||||
544 | return (cfReflect(src,dst)); | ||||
545 | } | ||||
546 | | ||||
547 | template<class T> | ||||
548 | inline T cfGleat(T src, T dst) { | ||||
549 | using namespace Arithmetic; | ||||
550 | // see http://www.pegtop.net/delphi/articles/blendmodes/quadratic.htm for formulas of Quadratic Blending Modes like Glow, Reflect, Freeze, and Heat | ||||
551 | | ||||
552 | if(dst == unitValue<T>()) { | ||||
489 | return unitValue<T>(); | 553 | return unitValue<T>(); | ||
490 | } | 554 | } | ||
491 | 555 | | |||
492 | return inv(clamp<T>(div(mul(inv(src), inv(src)),dst))); | 556 | if(cfHardMixPhotoshop(src,dst) == unitValue<T>()) { | ||
557 | return cfGlow(src,dst); | ||||
558 | } | ||||
559 | | ||||
560 | return (cfHeat(src,dst)); | ||||
493 | } | 561 | } | ||
494 | 562 | | |||
495 | template<class T> | 563 | template<class T> | ||
496 | inline T cfFreeze(T src, T dst) { | 564 | inline T cfReeze(T src, T dst) { | ||
565 | using namespace Arithmetic; | ||||
566 | | ||||
567 | return (cfGleat(dst,src)); | ||||
568 | } | ||||
569 | template<class T> | ||||
570 | inline T cfFhyrd(T src, T dst) { | ||||
571 | using namespace Arithmetic; | ||||
572 | | ||||
573 | return (cfAllanon(cfFrect(src,dst),cfHelow(src,dst))); | ||||
574 | } | ||||
575 | | ||||
576 | template<class T> | ||||
577 | inline T cfInterpolation(T src, T dst) { | ||||
578 | using namespace Arithmetic; | ||||
579 | | ||||
580 | qreal fsrc = scale<qreal>(src); | ||||
581 | qreal fdst = scale<qreal>(dst); | ||||
582 | | ||||
583 | if(dst == zeroValue<T>() && src == zeroValue<T>()) { | ||||
584 | return zeroValue<T>(); | ||||
585 | } | ||||
586 | | ||||
587 | return scale<T>(.5f-.25f*cos(pi*(fsrc))-.25f*cos(pi*(fdst))); | ||||
588 | } | ||||
589 | | ||||
590 | template<class T> | ||||
591 | inline T cfInterpolationB(T src, T dst) { | ||||
592 | using namespace Arithmetic; | ||||
593 | | ||||
594 | return cfInterpolation(cfInterpolation(src,dst),cfInterpolation(src,dst)); | ||||
595 | } | ||||
596 | | ||||
597 | | ||||
598 | template<class T> | ||||
599 | inline T cfPenumbraB(T src, T dst) { | ||||
600 | using namespace Arithmetic; | ||||
601 | | ||||
602 | if (dst == unitValue<T>()) { | ||||
603 | return unitValue<T>(); | ||||
604 | } | ||||
605 | if (dst + src < unitValue<T>()) { | ||||
606 | return (cfColorDodge(dst,src)/2); | ||||
607 | } | ||||
608 | if (src == zeroValue<T>()) { | ||||
609 | return zeroValue<T>(); | ||||
610 | } | ||||
611 | | ||||
612 | return inv(clamp<T>(div(inv(dst),src)/2)); | ||||
613 | } | ||||
614 | | ||||
615 | template<class T> | ||||
616 | inline T cfPenumbraD(T src, T dst) { | ||||
617 | using namespace Arithmetic; | ||||
618 | | ||||
619 | if (dst == unitValue<T>()) { | ||||
620 | return unitValue<T>(); | ||||
621 | } | ||||
622 | | ||||
623 | return cfArcTangent(src,inv(dst)); | ||||
624 | } | ||||
625 | | ||||
626 | template<class T> | ||||
627 | inline T cfPenumbraC(T src, T dst) { | ||||
628 | using namespace Arithmetic; | ||||
629 | | ||||
630 | return cfPenumbraD(dst,src); | ||||
631 | } | ||||
632 | | ||||
633 | template<class T> | ||||
634 | inline T cfPenumbraA(T src, T dst) { | ||||
635 | using namespace Arithmetic; | ||||
636 | | ||||
637 | return (cfPenumbraB(dst,src)); | ||||
638 | } | ||||
639 | | ||||
640 | template<class T> | ||||
641 | inline T cfSoftLightIFSIllusions(T src, T dst) { | ||||
642 | using namespace Arithmetic; | ||||
643 | | ||||
644 | qreal fsrc = scale<qreal>(src); | ||||
645 | qreal fdst = scale<qreal>(dst); | ||||
646 | | ||||
647 | return scale<T>(pow(fdst,pow(2.0,(mul(2.0,.5f-fsrc))))); | ||||
648 | } | ||||
649 | | ||||
650 | template<class T> | ||||
651 | inline T cfSoftLightPegtopDelphi(T src, T dst) { | ||||
652 | using namespace Arithmetic; | ||||
653 | | ||||
654 | return clamp<T>(cfAddition(mul(dst,cfScreen(src,dst)),mul(mul(src,dst),inv(dst)))); | ||||
655 | } | ||||
656 | | ||||
657 | template<class T> | ||||
658 | inline T cfNegation(T src, T dst) { | ||||
659 | using namespace Arithmetic; | ||||
660 | typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type; | ||||
661 | | ||||
662 | composite_type unit = unitValue<T>(); | ||||
663 | composite_type a = unit - src - dst; | ||||
664 | composite_type s = abs(a); | ||||
665 | composite_type d = unit - s; | ||||
666 | | ||||
667 | return T(d); | ||||
668 | } | ||||
669 | | ||||
670 | template<class T> | ||||
671 | inline T cfNor(T src, T dst) { | ||||
672 | using namespace Arithmetic; | ||||
673 | | ||||
674 | return and(src,dst); | ||||
675 | } | ||||
676 | | ||||
677 | template<class T> | ||||
678 | inline T cfNand(T src, T dst) { | ||||
679 | using namespace Arithmetic; | ||||
680 | | ||||
681 | return or(src,dst); | ||||
682 | } | ||||
683 | | ||||
684 | template<class T> | ||||
685 | inline T cfXor(T src, T dst) { | ||||
686 | using namespace Arithmetic; | ||||
687 | | ||||
688 | return xor(src,dst); | ||||
689 | } | ||||
690 | | ||||
691 | template<class T> | ||||
692 | inline T cfXnor(T src, T dst) { | ||||
693 | using namespace Arithmetic; | ||||
694 | | ||||
695 | return cfXor(src,inv(dst)); | ||||
696 | } | ||||
697 | | ||||
698 | template<class T> | ||||
699 | inline T cfAnd(T src, T dst) { | ||||
700 | using namespace Arithmetic; | ||||
701 | | ||||
702 | return cfNor(inv(src),inv(dst)); | ||||
703 | } | ||||
704 | | ||||
705 | template<class T> | ||||
706 | inline T cfOr(T src, T dst) { | ||||
707 | using namespace Arithmetic; | ||||
708 | | ||||
709 | return cfNand(inv(src),inv(dst)); | ||||
710 | } | ||||
711 | | ||||
712 | template<class T> | ||||
713 | inline T cfConverse(T src, T dst) { | ||||
714 | using namespace Arithmetic; | ||||
715 | | ||||
716 | return cfOr(inv(src),dst); | ||||
717 | } | ||||
718 | | ||||
719 | template<class T> | ||||
720 | inline T cfNotConverse(T src, T dst) { | ||||
721 | using namespace Arithmetic; | ||||
722 | | ||||
723 | return cfAnd(src,inv(dst)); | ||||
724 | } | ||||
725 | | ||||
726 | template<class T> | ||||
727 | inline T cfImplies(T src, T dst) { | ||||
728 | using namespace Arithmetic; | ||||
729 | | ||||
730 | return cfOr(src,inv(dst)); | ||||
731 | } | ||||
732 | | ||||
733 | template<class T> | ||||
734 | inline T cfNotImplies(T src, T dst) { | ||||
735 | using namespace Arithmetic; | ||||
736 | | ||||
737 | return cfAnd(inv(src),dst); | ||||
738 | } | ||||
739 | | ||||
740 | template<class T> | ||||
741 | inline T cfPNormA(T src, T dst) { | ||||
742 | using namespace Arithmetic; | ||||
743 | //This is also known as P-Norm mode with factor of 2.3333 See IMBLEND image blending mode samples, and please see imblend.m file found on Additional Blending Mode thread at Phabricator. 1/2.3333 is .42875... | ||||
744 | | ||||
745 | return clamp<T>(pow(pow(dst,2.3333333333333333)+pow(src,2.3333333333333333),0.428571428571434)); | ||||
746 | } | ||||
747 | | ||||
748 | template<class T> | ||||
749 | inline T cfPNormB(T src, T dst) { | ||||
750 | using namespace Arithmetic; | ||||
751 | //This is also known as P-Norm mode with factor of 2.3333 See IMBLEND image blending mode samples, and please see imblend.m file found on Additional Blending Mode thread at Phabricator. 1/2.3333 is .42875... | ||||
752 | | ||||
753 | return clamp<T>(pow(pow(dst,4)+pow(src,4),0.25)); | ||||
754 | } | ||||
755 | | ||||
756 | template<class T> | ||||
757 | inline T cfSuperLight(T src, T dst) { | ||||
758 | using namespace Arithmetic; | ||||
759 | //4.0 can be adjusted to taste. 4.0 is picked for being the best in terms of contrast and details. See imblend.m file. | ||||
760 | | ||||
761 | qreal fsrc = scale<qreal>(src); | ||||
762 | qreal fdst = scale<qreal>(dst); | ||||
763 | | ||||
764 | if (fsrc < .5) { | ||||
765 | return scale<T>(inv(pow(pow(inv(fdst),2.875)+pow(inv(2.0*fsrc),2.875),1.0/2.875))); | ||||
766 | } | ||||
767 | | ||||
768 | return scale<T>(pow(pow(fdst,2.875)+pow(2.0*fsrc-1.0,2.875),1.0/2.875)); | ||||
769 | } | ||||
770 | | ||||
771 | template<class T> | ||||
772 | inline T cfTintIFSIllusions(T src, T dst) { | ||||
773 | using namespace Arithmetic; | ||||
774 | //Known as Light Blending mode found in IFS Illusions. Picked this name because it results into a very strong tint, and has better naming convention. | ||||
775 | | ||||
776 | qreal fsrc = scale<qreal>(src); | ||||
777 | qreal fdst = scale<qreal>(dst); | ||||
778 | | ||||
779 | return scale<T>(fsrc*inv(fdst)+sqrt(fdst)); | ||||
780 | } | ||||
781 | | ||||
782 | template<class T> | ||||
783 | inline T cfShadeIFSIllusions(T src, T dst) { | ||||
497 | using namespace Arithmetic; | 784 | using namespace Arithmetic; | ||
785 | //Known as Shadow Blending mode found in IFS Illusions. Picked this name because it is the opposite of Tint (IFS Illusion Blending mode). | ||||
786 | | ||||
787 | qreal fsrc = scale<qreal>(src); | ||||
788 | qreal fdst = scale<qreal>(dst); | ||||
789 | | ||||
790 | return scale<T>(inv((inv(fdst)*fsrc)+sqrt(inv(fsrc)))); | ||||
791 | } | ||||
792 | | ||||
793 | template<class T> | ||||
794 | inline T cfFogLightenIFSIllusions(T src, T dst) { | ||||
795 | using namespace Arithmetic; | ||||
796 | //Known as Bright Blending mode found in IFS Illusions. Picked this name because the shading reminds me of fog when overlaying with a gradientt. | ||||
797 | | ||||
798 | qreal fsrc = scale<qreal>(src); | ||||
799 | qreal fdst = scale<qreal>(dst); | ||||
498 | 800 | | |||
499 | return clamp<T>(cfHeat(dst,src)); | 801 | if (fsrc < .5) { | ||
802 | return scale<T>(inv(inv(fsrc)*fsrc)-inv(fdst)*inv(fsrc)); | ||||
500 | } | 803 | } | ||
501 | 804 | | |||
805 | return scale<T>(fsrc-inv(fdst)*inv(fsrc)+pow(inv(fsrc),2)); | ||||
806 | } | ||||
807 | | ||||
808 | template<class T> | ||||
809 | inline T cfFogDarkenIFSIllusions(T src, T dst) { | ||||
810 | using namespace Arithmetic; | ||||
811 | //Known as Dark Blending mode found in IFS Illusions. Picked this name because the shading reminds me of fog when overlaying with a gradient. | ||||
812 | | ||||
813 | qreal fsrc = scale<qreal>(src); | ||||
814 | qreal fdst = scale<qreal>(dst); | ||||
815 | | ||||
816 | if (fsrc < .5) { | ||||
817 | return scale<T>(inv(fsrc)*fsrc+fsrc*fdst); | ||||
818 | } | ||||
819 | | ||||
820 | return scale<T>(fsrc*fdst+fsrc-pow(fsrc,2)); | ||||
821 | } | ||||
822 | | ||||
823 | template<class T> | ||||
824 | inline T cfModulo(T src, T dst) { | ||||
825 | using namespace Arithmetic; | ||||
826 | | ||||
827 | return mod(dst,src); | ||||
828 | } | ||||
829 | | ||||
830 | template<class T> | ||||
831 | inline T cfModuloShift(T src, T dst) { | ||||
832 | using namespace Arithmetic; | ||||
833 | qreal fsrc = scale<qreal>(src); | ||||
834 | qreal fdst = scale<qreal>(dst); | ||||
502 | 835 | | |||
836 | if (fsrc == 1.0 && fdst == 0.0) { | ||||
837 | return scale<T>(0.0); | ||||
838 | } | ||||
839 | | ||||
840 | | ||||
841 | return scale<T>(mod((fdst+fsrc),1.0000000000)); | ||||
842 | } | ||||
843 | | ||||
844 | template<class T> | ||||
845 | inline T cfModuloShiftContinuous(T src, T dst) { | ||||
846 | using namespace Arithmetic; | ||||
847 | //This blending mode do not behave like difference/equilavent with destination layer inverted if you use group layer on addition while the content of group layer contains several addition-mode layers, it works as expected on float images. So, no need to change this. | ||||
848 | qreal fsrc = scale<qreal>(src); | ||||
849 | qreal fdst = scale<qreal>(dst); | ||||
850 | | ||||
851 | if (fsrc == 1.0 && fdst == 0.0) { | ||||
852 | return scale<T>(0.0); | ||||
853 | } | ||||
854 | | ||||
855 | return scale<T>((int(ceil(fdst+fsrc)) % 2 != 0) || (fdst == zeroValue<T>()) ? inv(cfModuloShift(fsrc,fdst)) : cfModuloShift(fsrc,fdst)); | ||||
856 | } | ||||
857 | | ||||
858 | template<class T> | ||||
859 | inline T cfDivisiveModulo(T src, T dst) { | ||||
860 | using namespace Arithmetic; | ||||
861 | //I have to use 1.00000 as unitValue failed to work for those area. | ||||
862 | | ||||
863 | qreal fsrc = scale<qreal>(src); | ||||
864 | qreal fdst = scale<qreal>(dst); | ||||
865 | | ||||
866 | if (fsrc == zeroValue<T>()) { | ||||
867 | return scale<T>(mod(((1.0000000000/epsilon<T>()) * fdst),1.0000000000)); | ||||
868 | } | ||||
869 | | ||||
870 | return scale<T>(mod(((1.0000000000/fsrc) * fdst),1.0000000000)); | ||||
871 | } | ||||
872 | | ||||
873 | template<class T> | ||||
874 | inline T cfDivisiveModuloContinuous(T src, T dst) { | ||||
875 | using namespace Arithmetic; | ||||
876 | | ||||
877 | qreal fsrc = scale<qreal>(src); | ||||
878 | qreal fdst = scale<qreal>(dst); | ||||
879 | | ||||
880 | if (fdst == zeroValue<T>()) { | ||||
881 | return zeroValue<T>(); | ||||
882 | } | ||||
883 | | ||||
884 | if (fsrc == zeroValue<T>()) { | ||||
885 | return cfDivisiveModulo(fsrc,fdst); | ||||
886 | } | ||||
887 | | ||||
888 | | ||||
889 | return scale<T>( int(ceil(fdst/fsrc)) % 2 != 0 ? cfDivisiveModulo(fsrc,fdst) : inv(cfDivisiveModulo(fsrc,fdst))); | ||||
890 | } | ||||
891 | | ||||
892 | template<class T> | ||||
893 | inline T cfModuloContinuous(T src, T dst) { | ||||
894 | using namespace Arithmetic; | ||||
895 | | ||||
896 | return cfMultiply(cfDivisiveModuloContinuous(src,dst),src); | ||||
897 | } | ||||
898 | | ||||
899 | template<class T> | ||||
900 | inline T cfColorBurnLogarithmic(T src, T dst) { | ||||
901 | using namespace Arithmetic; | ||||
902 | //Also known as Darken from EffectBank/Illusions.hu. IFS Illusions had used this blending mode. | ||||
903 | | ||||
904 | qreal fsrc = scale<qreal>(src); | ||||
905 | qreal fdst = scale<qreal>(dst); | ||||
906 | | ||||
907 | if (inv(fdst) == zeroValue<T>()) { | ||||
908 | return scale<T>(log2(1.0 + abs(fsrc)/abs(inv(.999999))/8)); | ||||
909 | } | ||||
910 | | ||||
911 | return scale<T>(log2(1.0 + abs(fsrc)/abs(inv(fdst))/8)); | ||||
912 | } | ||||
913 | | ||||
914 | template<class T> | ||||
915 | inline T cfColorDodgeLogarithmic(T src, T dst) { | ||||
916 | using namespace Arithmetic; | ||||
917 | //Also known as Lighten from EffectBank/Illusions.hu. IFS Illusions had used this blending mode. | ||||
918 | | ||||
919 | return inv(cfColorBurnLogarithmic(inv(src),inv(dst))); | ||||
920 | } | ||||
921 | | ||||
922 | template<class T> | ||||
923 | inline T cfEasyDodge(T src, T dst) { | ||||
924 | using namespace Arithmetic; | ||||
925 | // The 13 divided by 15 can be adjusted to taste. See imgblend.m | ||||
926 | | ||||
927 | qreal fsrc = scale<qreal>(src); | ||||
928 | qreal fdst = scale<qreal>(dst); | ||||
929 | | ||||
930 | if (fsrc == 1.0) { | ||||
931 | return scale<T>(1.0);} | ||||
932 | | ||||
933 | | ||||
934 | return scale<T>(pow(fdst,mul(inv(fsrc != 1.0 ? fsrc : .999999999999),1.039999999))); | ||||
935 | } | ||||
936 | | ||||
937 | template<class T> | ||||
938 | inline T cfEasyBurn(T src, T dst) { | ||||
939 | using namespace Arithmetic; | ||||
940 | // The 13 divided by 15 can be adjusted to taste. See imgblend.m | ||||
941 | | ||||
942 | qreal fsrc = scale<qreal>(src); | ||||
943 | qreal fdst = scale<qreal>(dst); | ||||
944 | | ||||
945 | | ||||
946 | return scale<T>(inv(pow(inv(fsrc != 1.0 ? fsrc : .999999999999),mul(fdst,1.039999999)))); | ||||
947 | } | ||||
948 | | ||||
949 | template<class T> | ||||
950 | inline T cfFlatLight(T src, T dst) { | ||||
951 | using namespace Arithmetic; | ||||
952 | | ||||
953 | if (src == zeroValue<T>()) { | ||||
954 | return zeroValue<T>(); | ||||
955 | } | ||||
956 | | ||||
957 | return clamp<T>(cfHardMixPhotoshop(inv(src),dst)==unitValue<T>() ? cfPenumbraB(src,dst) : cfPenumbraA(src,dst)); | ||||
958 | } | ||||
503 | #endif // KOCOMPOSITEOP_FUNCTIONS_H_ | 959 | #endif // KOCOMPOSITEOP_FUNCTIONS_H_ |