Changeset View
Changeset View
Standalone View
Standalone View
libs/pigment/compositeops/KoCompositeOpFunctions.h
Context not available. | |||||
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 | 179 | //Fixing Color Dodge to avoid ZX Colors on bright area. | |||
180 | if(dst == zeroValue<T>()) | 180 | | ||
181 | return zeroValue<T>(); | 181 | if(src == unitValue<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)); | ||
Context not available. | |||||
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 | | |||
Context not available. | |||||
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 | | |||
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 | | ||||
416 | template<class T> | 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; | ||
Context not available. | |||||
457 | inline T cfGlow(T src, T dst) { | 472 | inline T cfGlow(T src, T dst) { | ||
458 | using namespace Arithmetic; | 473 | 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 | 474 | // see http://www.pegtop.net/delphi/articles/blendmodes/quadratic.htm for formulas of Quadratic Blending Modes like Glow, Reflect, Freeze, and Heat | ||
475 | | ||||
476 | if (dst == unitValue<T>()) { | ||||
477 | return unitValue<T>(); | ||||
478 | } | ||||
479 | | ||||
480 | return clamp<T>(div(mul(src, src), inv(dst))); | ||||
481 | } | ||||
482 | | ||||
483 | template<class T> | ||||
484 | inline T cfReflect(T src, T dst) { | ||||
485 | using namespace Arithmetic; | ||||
460 | 486 | | |||
461 | if(dst == unitValue<T>()) { | 487 | | ||
488 | return clamp<T>(cfGlow(dst,src)); | ||||
489 | } | ||||
490 | | ||||
491 | template<class T> | ||||
492 | inline T cfHeat(T src, T dst) { | ||||
493 | using namespace Arithmetic; | ||||
494 | | ||||
495 | if(src == unitValue<T>()) { | ||||
462 | return unitValue<T>(); | 496 | return unitValue<T>(); | ||
463 | } | 497 | } | ||
464 | 498 | | |||
465 | if(src == zeroValue<T>()) { | 499 | if(dst == zeroValue<T>()) { | ||
466 | return zeroValue<T>(); | 500 | return zeroValue<T>(); | ||
467 | } | 501 | } | ||
502 | | ||||
503 | return inv(clamp<T>(div(mul(inv(src), inv(src)),dst))); | ||||
504 | } | ||||
505 | | ||||
506 | template<class T> | ||||
507 | inline T cfFreeze(T src, T dst) { | ||||
508 | using namespace Arithmetic; | ||||
468 | 509 | | |||
469 | return clamp<T>(div(mul(src, src), inv(dst))); | 510 | return (cfHeat(dst,src)); | ||
470 | } | 511 | } | ||
512 | | ||||
513 | template<class T> | ||||
514 | inline T cfHelow(T src, T dst) { | ||||
515 | using namespace Arithmetic; | ||||
516 | // see http://www.pegtop.net/delphi/articles/blendmodes/quadratic.htm for formulas of Quadratic Blending Modes like Glow, Reflect, Freeze, and Heat | ||||
517 | | ||||
518 | if (cfHardMixPhotoshop(src,dst) == unitValue<T>()) { | ||||
519 | return cfHeat(src,dst); | ||||
520 | } | ||||
471 | 521 | | |||
522 | if (src == zeroValue<T>()) { | ||||
523 | return zeroValue<T>(); | ||||
524 | } | ||||
525 | | ||||
526 | return (cfGlow(src,dst)); | ||||
527 | } | ||||
528 | | ||||
472 | template<class T> | 529 | template<class T> | ||
473 | inline T cfReflect(T src, T dst) { | 530 | inline T cfFrect(T src, T dst) { | ||
531 | using namespace Arithmetic; | ||||
532 | | ||||
533 | if (cfHardMixPhotoshop(src,dst) == unitValue<T>()) { | ||||
534 | return cfFreeze(src,dst); | ||||
535 | } | ||||
536 | | ||||
537 | if (dst == zeroValue<T>()) { | ||||
538 | return zeroValue<T>(); | ||||
539 | } | ||||
540 | | ||||
541 | return (cfReflect(src,dst)); | ||||
542 | } | ||||
543 | | ||||
544 | template<class T> | ||||
545 | inline T cfGleat(T src, T dst) { | ||||
474 | using namespace Arithmetic; | 546 | using namespace Arithmetic; | ||
547 | // see http://www.pegtop.net/delphi/articles/blendmodes/quadratic.htm for formulas of Quadratic Blending Modes like Glow, Reflect, Freeze, and Heat | ||||
475 | 548 | | |||
476 | return (cfGlow(dst,src)); | 549 | if(dst == unitValue<T>()) { | ||
550 | return unitValue<T>(); | ||||
551 | } | ||||
552 | | ||||
553 | if(cfHardMixPhotoshop(src,dst) == unitValue<T>()) { | ||||
554 | return cfGlow(src,dst); | ||||
555 | } | ||||
556 | | ||||
557 | return (cfHeat(src,dst)); | ||||
477 | } | 558 | } | ||
478 | 559 | | |||
479 | template<class T> | 560 | template<class T> | ||
480 | inline T cfHeat(T src, T dst) { | 561 | inline T cfReeze(T src, T dst) { | ||
481 | using namespace Arithmetic; | 562 | 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. | | |||
483 | 563 | | |||
484 | if(dst == zeroValue<T>()) { | 564 | return (cfGleat(dst,src)); | ||
565 | } | ||||
566 | template<class T> | ||||
567 | inline T cfFhyrd(T src, T dst) { | ||||
568 | using namespace Arithmetic; | ||||
569 | | ||||
570 | return (cfAllanon(cfFrect(src,dst),cfHelow(src,dst))); | ||||
571 | } | ||||
572 | | ||||
573 | template<class T> | ||||
574 | inline T cfInterpolation(T src, T dst) { | ||||
575 | using namespace Arithmetic; | ||||
576 | | ||||
577 | qreal fsrc = scale<qreal>(src); | ||||
578 | qreal fdst = scale<qreal>(dst); | ||||
579 | | ||||
580 | if(dst == zeroValue<T>() && src == zeroValue<T>()) { | ||||
581 | return zeroValue<T>(); | ||||
582 | } | ||||
583 | | ||||
584 | return scale<T>(.5f-.25f*cos(pi*(fsrc))-.25f*cos(pi*(fdst))); | ||||
585 | } | ||||
586 | | ||||
587 | template<class T> | ||||
588 | inline T cfInterpolationB(T src, T dst) { | ||||
589 | using namespace Arithmetic; | ||||
590 | | ||||
591 | return cfInterpolation(cfInterpolation(src,dst),cfInterpolation(src,dst)); | ||||
592 | } | ||||
593 | | ||||
594 | | ||||
595 | template<class T> | ||||
596 | inline T cfPenumbraB(T src, T dst) { | ||||
597 | using namespace Arithmetic; | ||||
598 | | ||||
599 | if (dst == unitValue<T>()) { | ||||
600 | return unitValue<T>(); | ||||
601 | } | ||||
602 | if (dst + src < unitValue<T>()) { | ||||
603 | return (cfColorDodge(dst,src)/2); | ||||
604 | } | ||||
605 | if (src == zeroValue<T>()) { | ||||
485 | return zeroValue<T>(); | 606 | return zeroValue<T>(); | ||
486 | } | 607 | } | ||
608 | | ||||
609 | return inv(clamp<T>(div(inv(dst),src)/2)); | ||||
610 | } | ||||
611 | | ||||
612 | template<class T> | ||||
613 | inline T cfPenumbraD(T src, T dst) { | ||||
614 | using namespace Arithmetic; | ||||
487 | 615 | | |||
488 | if(src == unitValue<T>()) { | 616 | if (dst == unitValue<T>()) { | ||
489 | return unitValue<T>(); | 617 | return unitValue<T>(); | ||
490 | } | 618 | } | ||
491 | 619 | | |||
492 | return inv(clamp<T>(div(mul(inv(src), inv(src)),dst))); | 620 | return cfArcTangent(src,inv(dst)); | ||
493 | } | 621 | } | ||
494 | 622 | | |||
495 | template<class T> | 623 | template<class T> | ||
496 | inline T cfFreeze(T src, T dst) { | 624 | inline T cfPenumbraC(T src, T dst) { | ||
625 | using namespace Arithmetic; | ||||
626 | | ||||
627 | return cfPenumbraD(dst,src); | ||||
628 | } | ||||
629 | | ||||
630 | template<class T> | ||||
631 | inline T cfPenumbraA(T src, T dst) { | ||||
632 | using namespace Arithmetic; | ||||
633 | | ||||
634 | return (cfPenumbraB(dst,src)); | ||||
635 | } | ||||
636 | | ||||
637 | template<class T> | ||||
638 | inline T cfSoftLightIFSIllusions(T src, T dst) { | ||||
639 | using namespace Arithmetic; | ||||
640 | | ||||
641 | qreal fsrc = scale<qreal>(src); | ||||
642 | qreal fdst = scale<qreal>(dst); | ||||
643 | | ||||
644 | return scale<T>(pow(fdst,pow(2.0,(mul(2.0,.5f-fsrc))))); | ||||
645 | } | ||||
646 | | ||||
647 | template<class T> | ||||
648 | inline T cfSoftLightPegtopDelphi(T src, T dst) { | ||||
649 | using namespace Arithmetic; | ||||
650 | | ||||
651 | return clamp<T>(cfAddition(mul(dst,cfScreen(src,dst)),mul(mul(src,dst),inv(dst)))); | ||||
652 | } | ||||
653 | | ||||
654 | template<class T> | ||||
655 | inline T cfNegation(T src, T dst) { | ||||
656 | using namespace Arithmetic; | ||||
657 | typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type; | ||||
658 | | ||||
659 | composite_type unit = unitValue<T>(); | ||||
660 | composite_type a = unit - src - dst; | ||||
661 | composite_type s = abs(a); | ||||
662 | composite_type d = unit - s; | ||||
663 | | ||||
664 | return T(d); | ||||
665 | } | ||||
666 | | ||||
667 | template<class T> | ||||
668 | inline T cfNor(T src, T dst) { | ||||
669 | using namespace Arithmetic; | ||||
670 | | ||||
671 | return and(src,dst); | ||||
672 | } | ||||
673 | | ||||
674 | template<class T> | ||||
675 | inline T cfNand(T src, T dst) { | ||||
676 | using namespace Arithmetic; | ||||
677 | | ||||
678 | return or(src,dst); | ||||
679 | } | ||||
680 | | ||||
681 | template<class T> | ||||
682 | inline T cfXor(T src, T dst) { | ||||
683 | using namespace Arithmetic; | ||||
684 | | ||||
685 | return xor(src,dst); | ||||
686 | } | ||||
687 | | ||||
688 | template<class T> | ||||
689 | inline T cfXnor(T src, T dst) { | ||||
690 | using namespace Arithmetic; | ||||
691 | | ||||
692 | return cfXor(src,inv(dst)); | ||||
693 | } | ||||
694 | | ||||
695 | template<class T> | ||||
696 | inline T cfAnd(T src, T dst) { | ||||
497 | using namespace Arithmetic; | 697 | using namespace Arithmetic; | ||
698 | | ||||
699 | return cfNor(inv(src),inv(dst)); | ||||
700 | } | ||||
701 | | ||||
702 | template<class T> | ||||
703 | inline T cfOr(T src, T dst) { | ||||
704 | using namespace Arithmetic; | ||||
705 | | ||||
706 | return cfNand(inv(src),inv(dst)); | ||||
707 | } | ||||
708 | | ||||
709 | template<class T> | ||||
710 | inline T cfConverse(T src, T dst) { | ||||
711 | using namespace Arithmetic; | ||||
712 | | ||||
713 | return cfOr(inv(src),dst); | ||||
714 | } | ||||
715 | | ||||
716 | template<class T> | ||||
717 | inline T cfNotConverse(T src, T dst) { | ||||
718 | using namespace Arithmetic; | ||||
719 | | ||||
720 | return cfAnd(src,inv(dst)); | ||||
721 | } | ||||
722 | | ||||
723 | template<class T> | ||||
724 | inline T cfImplies(T src, T dst) { | ||||
725 | using namespace Arithmetic; | ||||
726 | | ||||
727 | return cfOr(src,inv(dst)); | ||||
728 | } | ||||
729 | | ||||
730 | template<class T> | ||||
731 | inline T cfNotImplies(T src, T dst) { | ||||
732 | using namespace Arithmetic; | ||||
733 | | ||||
734 | return cfAnd(inv(src),dst); | ||||
735 | } | ||||
736 | | ||||
737 | template<class T> | ||||
738 | inline T cfPNormA(T src, T dst) { | ||||
739 | using namespace Arithmetic; | ||||
740 | //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... | ||||
498 | 741 | | |||
499 | return clamp<T>(cfHeat(dst,src)); | 742 | return clamp<T>(pow(pow(dst,2.3333333333333333)+pow(src,2.3333333333333333),0.428571428571434)); | ||
500 | } | 743 | } | ||
501 | 744 | | |||
745 | template<class T> | ||||
746 | inline T cfPNormB(T src, T dst) { | ||||
747 | using namespace Arithmetic; | ||||
748 | //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... | ||||
749 | | ||||
750 | return clamp<T>(pow(pow(dst,4)+pow(src,4),0.25)); | ||||
751 | } | ||||
502 | 752 | | |||
753 | template<class T> | ||||
754 | inline T cfSuperLight(T src, T dst) { | ||||
755 | using namespace Arithmetic; | ||||
756 | //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. | ||||
757 | | ||||
758 | qreal fsrc = scale<qreal>(src); | ||||
759 | qreal fdst = scale<qreal>(dst); | ||||
760 | | ||||
761 | if (fsrc < .5) { | ||||
762 | return scale<T>(inv(pow(pow(inv(fdst),2.875)+pow(inv(2.0*fsrc),2.875),1.0/2.875))); | ||||
763 | } | ||||
764 | | ||||
765 | return scale<T>(pow(pow(fdst,2.875)+pow(2.0*fsrc-1.0,2.875),1.0/2.875)); | ||||
766 | } | ||||
767 | | ||||
768 | template<class T> | ||||
769 | inline T cfTintIFSIllusions(T src, T dst) { | ||||
770 | using namespace Arithmetic; | ||||
771 | //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. | ||||
772 | | ||||
773 | qreal fsrc = scale<qreal>(src); | ||||
774 | qreal fdst = scale<qreal>(dst); | ||||
775 | | ||||
776 | return scale<T>(fsrc*inv(fdst)+sqrt(fdst)); | ||||
777 | } | ||||
778 | | ||||
779 | template<class T> | ||||
780 | inline T cfShadeIFSIllusions(T src, T dst) { | ||||
781 | using namespace Arithmetic; | ||||
782 | //Known as Shadow Blending mode found in IFS Illusions. Picked this name because it is the opposite of Tint (IFS Illusion Blending mode). | ||||
783 | | ||||
784 | qreal fsrc = scale<qreal>(src); | ||||
785 | qreal fdst = scale<qreal>(dst); | ||||
786 | | ||||
787 | return scale<T>(inv((inv(fdst)*fsrc)+sqrt(inv(fsrc)))); | ||||
788 | } | ||||
789 | | ||||
790 | template<class T> | ||||
791 | inline T cfFogLightenIFSIllusions(T src, T dst) { | ||||
792 | using namespace Arithmetic; | ||||
793 | //Known as Bright Blending mode found in IFS Illusions. Picked this name because the shading reminds me of fog when overlaying with a gradientt. | ||||
794 | | ||||
795 | qreal fsrc = scale<qreal>(src); | ||||
796 | qreal fdst = scale<qreal>(dst); | ||||
797 | | ||||
798 | if (fsrc < .5) { | ||||
799 | return scale<T>(inv(inv(fsrc)*fsrc)-inv(fdst)*inv(fsrc)); | ||||
800 | } | ||||
801 | | ||||
802 | return scale<T>(fsrc-inv(fdst)*inv(fsrc)+pow(inv(fsrc),2)); | ||||
803 | } | ||||
804 | | ||||
805 | template<class T> | ||||
806 | inline T cfFogDarkenIFSIllusions(T src, T dst) { | ||||
807 | using namespace Arithmetic; | ||||
808 | //Known as Dark Blending mode found in IFS Illusions. Picked this name because the shading reminds me of fog when overlaying with a gradient. | ||||
809 | | ||||
810 | qreal fsrc = scale<qreal>(src); | ||||
811 | qreal fdst = scale<qreal>(dst); | ||||
812 | | ||||
813 | if (fsrc < .5) { | ||||
814 | return scale<T>(inv(fsrc)*fsrc+fsrc*fdst); | ||||
815 | } | ||||
816 | | ||||
817 | return scale<T>(fsrc*fdst+fsrc-pow(fsrc,2)); | ||||
818 | } | ||||
819 | | ||||
820 | template<class T> | ||||
821 | inline T cfModulo(T src, T dst) { | ||||
822 | using namespace Arithmetic; | ||||
823 | | ||||
824 | return mod(dst,src); | ||||
825 | } | ||||
826 | | ||||
827 | template<class T> | ||||
828 | inline T cfModuloShift(T src, T dst) { | ||||
829 | using namespace Arithmetic; | ||||
830 | qreal fsrc = scale<qreal>(src); | ||||
831 | qreal fdst = scale<qreal>(dst); | ||||
832 | | ||||
833 | if (fsrc == 1.0 && fdst == 0.0) { | ||||
834 | return scale<T>(0.0); | ||||
835 | } | ||||
836 | | ||||
837 | | ||||
838 | return scale<T>(mod((fdst+fsrc),1.0000000000)); | ||||
839 | } | ||||
840 | | ||||
841 | template<class T> | ||||
842 | inline T cfModuloShiftContinuous(T src, T dst) { | ||||
843 | using namespace Arithmetic; | ||||
844 | //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. | ||||
845 | qreal fsrc = scale<qreal>(src); | ||||
846 | qreal fdst = scale<qreal>(dst); | ||||
847 | | ||||
848 | if (fsrc == 1.0 && fdst == 0.0) { | ||||
849 | return scale<T>(0.0); | ||||
850 | } | ||||
851 | | ||||
852 | return scale<T>((int(ceil(fdst+fsrc)) % 2 != 0) || (fdst == zeroValue<T>()) ? inv(cfModuloShift(fsrc,fdst)) : cfModuloShift(fsrc,fdst)); | ||||
853 | } | ||||
854 | | ||||
855 | template<class T> | ||||
856 | inline T cfDivisiveModulo(T src, T dst) { | ||||
857 | using namespace Arithmetic; | ||||
858 | //I have to use 1.00000 as unitValue failed to work for those area. | ||||
859 | | ||||
860 | qreal fsrc = scale<qreal>(src); | ||||
861 | qreal fdst = scale<qreal>(dst); | ||||
862 | | ||||
863 | if (fsrc == zeroValue<T>()) { | ||||
864 | return scale<T>(mod(((1.0000000000/epsilon<T>()) * fdst),1.0000000000)); | ||||
865 | } | ||||
866 | | ||||
867 | return scale<T>(mod(((1.0000000000/fsrc) * fdst),1.0000000000)); | ||||
868 | } | ||||
869 | | ||||
870 | template<class T> | ||||
871 | inline T cfDivisiveModuloContinuous(T src, T dst) { | ||||
872 | using namespace Arithmetic; | ||||
873 | | ||||
874 | qreal fsrc = scale<qreal>(src); | ||||
875 | qreal fdst = scale<qreal>(dst); | ||||
876 | | ||||
877 | if (fdst == zeroValue<T>()) { | ||||
878 | return zeroValue<T>(); | ||||
879 | } | ||||
880 | | ||||
881 | if (fsrc == zeroValue<T>()) { | ||||
882 | return cfDivisiveModulo(fsrc,fdst); | ||||
883 | } | ||||
884 | | ||||
885 | | ||||
886 | return scale<T>( int(ceil(fdst/fsrc)) % 2 != 0 ? cfDivisiveModulo(fsrc,fdst) : inv(cfDivisiveModulo(fsrc,fdst))); | ||||
887 | } | ||||
888 | | ||||
889 | template<class T> | ||||
890 | inline T cfModuloContinuous(T src, T dst) { | ||||
891 | using namespace Arithmetic; | ||||
892 | | ||||
893 | return cfMultiply(cfDivisiveModuloContinuous(src,dst),src); | ||||
894 | } | ||||
895 | | ||||
896 | template<class T> | ||||
897 | inline T cfColorBurnLogarithmic(T src, T dst) { | ||||
898 | using namespace Arithmetic; | ||||
899 | //Also known as Darken from EffectBank/Illusions.hu. IFS Illusions had used this blending mode. | ||||
900 | | ||||
901 | qreal fsrc = scale<qreal>(src); | ||||
902 | qreal fdst = scale<qreal>(dst); | ||||
903 | | ||||
904 | if (inv(fdst) == zeroValue<T>()) { | ||||
905 | return scale<T>(log2(1.0 + abs(fsrc)/abs(inv(.999999))/8)); | ||||
906 | } | ||||
907 | | ||||
908 | return scale<T>(log2(1.0 + abs(fsrc)/abs(inv(fdst))/8)); | ||||
909 | } | ||||
910 | | ||||
911 | template<class T> | ||||
912 | inline T cfColorDodgeLogarithmic(T src, T dst) { | ||||
913 | using namespace Arithmetic; | ||||
914 | //Also known as Lighten from EffectBank/Illusions.hu. IFS Illusions had used this blending mode. | ||||
915 | | ||||
916 | return inv(cfColorBurnLogarithmic(inv(src),inv(dst))); | ||||
917 | } | ||||
918 | | ||||
919 | template<class T> | ||||
920 | inline T cfEasyDodge(T src, T dst) { | ||||
921 | using namespace Arithmetic; | ||||
922 | // The 13 divided by 15 can be adjusted to taste. See imgblend.m | ||||
923 | | ||||
924 | qreal fsrc = scale<qreal>(src); | ||||
925 | qreal fdst = scale<qreal>(dst); | ||||
926 | | ||||
927 | | ||||
928 | return scale<T>(pow(fdst,mul(inv(fsrc != 1.0 ? fsrc : .999999999999),1.039999999))); | ||||
929 | } | ||||
930 | | ||||
931 | template<class T> | ||||
932 | inline T cfEasyBurn(T src, T dst) { | ||||
933 | using namespace Arithmetic; | ||||
934 | // The 13 divided by 15 can be adjusted to taste. See imgblend.m | ||||
935 | | ||||
936 | qreal fsrc = scale<qreal>(src); | ||||
937 | qreal fdst = scale<qreal>(dst); | ||||
938 | | ||||
939 | | ||||
940 | return scale<T>(inv(pow(inv(fsrc != 1.0 ? fsrc : .999999999999),mul(fdst,1.039999999)))); | ||||
941 | } | ||||
942 | | ||||
943 | template<class T> | ||||
944 | inline T cfFlatLight(T src, T dst) { | ||||
945 | using namespace Arithmetic; | ||||
946 | | ||||
947 | if (src == zeroValue<T>()) { | ||||
948 | return zeroValue<T>(); | ||||
949 | } | ||||
950 | | ||||
951 | return clamp<T>(cfHardMixPhotoshop(inv(src),dst)==unitValue<T>() ? cfPenumbraB(src,dst) : cfPenumbraA(src,dst)); | ||||
952 | } | ||||
503 | #endif // KOCOMPOSITEOP_FUNCTIONS_H_ | 953 | #endif // KOCOMPOSITEOP_FUNCTIONS_H_ | ||
Context not available. |