diff --git a/libs/pigment/KoCompositeOpRegistry.h b/libs/pigment/KoCompositeOpRegistry.h --- a/libs/pigment/KoCompositeOpRegistry.h +++ b/libs/pigment/KoCompositeOpRegistry.h @@ -53,6 +53,9 @@ const QString COMPOSITE_ARC_TANGENT = "arc_tangent"; const QString COMPOSITE_GEOMETRIC_MEAN = "geometric_mean"; const QString COMPOSITE_ADDITIVE_SUBTRACTIVE = "additive_subtractive"; +const QString COMPOSITE_NEGATION = "negation"; +const QString COMPOSITE_PHOENIX = "phoenix"; +const QString COMPOSITE_SIGNED_DIFFERENCE = "signed_difference"; const QString COMPOSITE_EQUIVALENCE = "equivalence"; const QString COMPOSITE_ALLANON = "allanon"; @@ -66,6 +69,9 @@ const QString COMPOSITE_BEHIND = "behind"; const QString COMPOSITE_GREATER = "greater"; const QString COMPOSITE_HARD_OVERLAY = "hard overlay"; +const QString COMPOSITE_INTERPOLATE = "interpolate"; +const QString COMPOSITE_PENUMBRAA = "penumbra a"; +const QString COMPOSITE_PENUMBRAB = "penumbra b"; const QString COMPOSITE_DARKEN = "darken"; const QString COMPOSITE_BURN = "burn";//this is also known as 'color burn'. @@ -77,6 +83,7 @@ const QString COMPOSITE_LINEAR_DODGE = "linear_dodge"; const QString COMPOSITE_SCREEN = "screen"; const QString COMPOSITE_HARD_LIGHT = "hard_light"; +const QString COMPOSITE_SOFT_LIGHT_PEGTOP_DELPHI = "soft_light_pegtop_delphi"; const QString COMPOSITE_SOFT_LIGHT_PHOTOSHOP = "soft_light"; const QString COMPOSITE_SOFT_LIGHT_SVG = "soft_light_svg"; const QString COMPOSITE_GAMMA_LIGHT = "gamma_light"; @@ -142,6 +149,10 @@ const QString COMPOSITE_GLOW = "glow"; const QString COMPOSITE_FREEZE = "freeze"; const QString COMPOSITE_HEAT = "heat"; +const QString COMPOSITE_GLEAT = "gleat"; +const QString COMPOSITE_HELOW = "helow"; +const QString COMPOSITE_REEZE = "reeze"; +const QString COMPOSITE_FRECT = "frect"; diff --git a/libs/pigment/KoCompositeOpRegistry.cpp b/libs/pigment/KoCompositeOpRegistry.cpp --- a/libs/pigment/KoCompositeOpRegistry.cpp +++ b/libs/pigment/KoCompositeOpRegistry.cpp @@ -66,6 +66,7 @@ m_map.insert(m_categories[2], KoID(COMPOSITE_PIN_LIGHT , i18n("Pin Light"))); m_map.insert(m_categories[2], KoID(COMPOSITE_VIVID_LIGHT , i18n("Vivid Light"))); m_map.insert(m_categories[2], KoID(COMPOSITE_HARD_LIGHT , i18n("Hard Light"))); + m_map.insert(m_categories[2], KoID(COMPOSITE_SOFT_LIGHT_PEGTOP_DELPHI, i18n("Soft Light (Pegtop-Delphi)"))); m_map.insert(m_categories[2], KoID(COMPOSITE_SOFT_LIGHT_PHOTOSHOP, i18n("Soft Light (Photoshop)"))); m_map.insert(m_categories[2], KoID(COMPOSITE_SOFT_LIGHT_SVG, i18n("Soft Light (SVG)"))); m_map.insert(m_categories[2], KoID(COMPOSITE_GAMMA_LIGHT , i18n("Gamma Light"))); @@ -76,6 +77,9 @@ m_map.insert(m_categories[3], KoID(COMPOSITE_ADDITIVE_SUBTRACTIVE, i18n("Additive Subtractive"))); m_map.insert(m_categories[3], KoID(COMPOSITE_EXCLUSION , i18n("Exclusion"))); m_map.insert(m_categories[3], KoID(COMPOSITE_ARC_TANGENT , i18n("Arcus Tangent"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_NEGATION , i18n("Negation"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_PHOENIX , i18n("Phoenix"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_SIGNED_DIFFERENCE , i18n("Signed Difference"))); m_map.insert(m_categories[4], KoID(COMPOSITE_OVER , i18n("Normal"))); m_map.insert(m_categories[4], KoID(COMPOSITE_BEHIND , i18n("Behind"))); @@ -93,6 +97,9 @@ m_map.insert(m_categories[4], KoID(COMPOSITE_DESTINATION_ATOP, i18n("Destination Atop"))); m_map.insert(m_categories[4], KoID(COMPOSITE_DESTINATION_IN , i18n("Destination In"))); m_map.insert(m_categories[4], KoID(COMPOSITE_HARD_OVERLAY , i18n("Hard Overlay"))); + m_map.insert(m_categories[4], KoID(COMPOSITE_INTERPOLATE , i18n("Interpolate"))); + m_map.insert(m_categories[4], KoID(COMPOSITE_PENUMBRAA , i18n("Penumbra A"))); + m_map.insert(m_categories[4], KoID(COMPOSITE_PENUMBRAB , i18n("Penumbra B"))); m_map.insert(m_categories[5], KoID(COMPOSITE_BUMPMAP , i18n("Bumpmap"))); m_map.insert(m_categories[5], KoID(COMPOSITE_COMBINE_NORMAL, i18n("Combine Normal Map"))); @@ -143,6 +150,10 @@ m_map.insert(m_categories[10], KoID(COMPOSITE_GLOW , i18n("Glow"))); m_map.insert(m_categories[10], KoID(COMPOSITE_FREEZE , i18n("Freeze"))); m_map.insert(m_categories[10], KoID(COMPOSITE_HEAT , i18n("Heat"))); + m_map.insert(m_categories[10], KoID(COMPOSITE_GLEAT , i18n("Gleat"))); + m_map.insert(m_categories[10], KoID(COMPOSITE_HELOW , i18n("Helow"))); + m_map.insert(m_categories[10], KoID(COMPOSITE_REEZE , i18n("Reeze"))); + m_map.insert(m_categories[10], KoID(COMPOSITE_FRECT , i18n("Frect"))); } const KoCompositeOpRegistry& KoCompositeOpRegistry::instance() diff --git a/libs/pigment/compositeops/KoCompositeOpFunctions.h b/libs/pigment/compositeops/KoCompositeOpFunctions.h --- a/libs/pigment/compositeops/KoCompositeOpFunctions.h +++ b/libs/pigment/compositeops/KoCompositeOpFunctions.h @@ -479,25 +479,130 @@ template inline T cfHeat(T src, T dst) { using namespace Arithmetic; - // 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. - if(dst == zeroValue()) { + return inv(cfGlow(inv(src),inv(dst))); +} + +template +inline T cfFreeze(T src, T dst) { + using namespace Arithmetic; + + return (cfHeat(dst,src)); +} + +template +inline T cfFrect(T src, T dst) { + using namespace Arithmetic; + // see http://www.pegtop.net/delphi/articles/blendmodes/quadratic.htm for formulas of Quadratic Blending Modes like Glow, Reflect, Freeze, and Heat + + if(cfHardMixPhotoshop(src,dst) == unitValue()) { + return cfHeat(src,dst); + } + + return (cfGlow(src,dst)); +} + +template +inline T cfHelow(T src, T dst) { + using namespace Arithmetic; + + if(src == zeroValue()) { return zeroValue(); } - if(src == unitValue()) { + return (cfFrect(dst,src)); +} + +template +inline T cfGleat(T src, T dst) { + using namespace Arithmetic; + // see http://www.pegtop.net/delphi/articles/blendmodes/quadratic.htm for formulas of Quadratic Blending Modes like Glow, Reflect, Freeze, and Heat + + if(cfHardMixPhotoshop(src,dst) == unitValue()) { + return cfGlow(src,dst); + } + + return (cfHeat(src,dst)); +} + +template +inline T cfReeze(T src, T dst) { + using namespace Arithmetic; + + return (cfGleat(dst,src)); +} + +template +inline T cfInterpolate(T src, T dst) { + using namespace Arithmetic; + typedef typename KoColorSpaceMathsTraits::compositetype composite_type; + // Interpolate does not work on integer images due to cos (pi*src), and cos (pi*dst). Another issue to be solved. + + composite_type half = cfAllanon(unitValue(),zeroValue()); + composite_type four = cfAllanon(cfAllanon(unitValue(),zeroValue()),zeroValue()); + composite_type seta = cos(pi*src); + composite_type setb = cos(pi*dst); + + return clamp(half - seta * four - setb * four); +} + + +template +inline T cfPenumbraB(T src, T dst) { + using namespace Arithmetic; + + if(dst == unitValue()) { return unitValue(); + } + if(dst+src < unitValue()) { + return (cfColorDodge(dst,src)/2); + } + if(src == zeroValue()) { + return zeroValue(); } - return inv(clamp(div(mul(inv(src), inv(src)),dst))); + return inv(clamp(div(inv(dst),src)/2)); } template -inline T cfFreeze(T src, T dst) { +inline T cfPenumbraA(T src, T dst) { using namespace Arithmetic; - return clamp(cfHeat(dst,src)); + return (cfPenumbraB(dst,src)); } +template +inline T cfSoftLightPegtopDelphi(T src, T dst) { + using namespace Arithmetic; + + return clamp(cfAddition(mul(dst,cfScreen(src,dst)),mul(mul(src,dst),inv(dst)))); +} + +template +inline T cfNegation(T src, T dst) { + using namespace Arithmetic; + typedef typename KoColorSpaceMathsTraits::compositetype composite_type; + + composite_type unit = unitValue(); + composite_type a = unit - src - dst; + composite_type s = abs(a); + composite_type d = unit - s; + + return T(d); +} + +template +inline T cfPhoenix(T src, T dst) { + using namespace Arithmetic; + + return clamp(inv(cfDifference(src,dst))); +} + +template +inline T cfSignedDifference(T src, T dst) { + using namespace Arithmetic; + + return clamp((src-dst)/2 + halfValue()); +} #endif // KOCOMPOSITEOP_FUNCTIONS_H_ diff --git a/libs/pigment/compositeops/KoCompositeOps.h b/libs/pigment/compositeops/KoCompositeOps.h --- a/libs/pigment/compositeops/KoCompositeOps.h +++ b/libs/pigment/compositeops/KoCompositeOps.h @@ -124,12 +124,16 @@ add<&cfParallel >(cs, COMPOSITE_PARALLEL , i18n("Parallel") , KoCompositeOp::categoryMix()); add<&cfAllanon >(cs, COMPOSITE_ALLANON , i18n("Allanon") , KoCompositeOp::categoryMix()); add<&cfHardOverlay >(cs, COMPOSITE_HARD_OVERLAY , i18n("Hard Overlay") , KoCompositeOp::categoryMix()); + add<&cfInterpolate >(cs, COMPOSITE_INTERPOLATE , i18n("Interpolate") , KoCompositeOp::categoryMix()); + add<&cfPenumbraA >(cs, COMPOSITE_PENUMBRAA , i18n("Penumbra A") , KoCompositeOp::categoryMix()); + add<&cfPenumbraB >(cs, COMPOSITE_PENUMBRAB , i18n("Penumbra B") , KoCompositeOp::categoryMix()); add<&cfScreen >(cs, COMPOSITE_SCREEN , i18n("Screen") , KoCompositeOp::categoryLight()); add<&cfColorDodge >(cs, COMPOSITE_DODGE , i18n("Color Dodge") , KoCompositeOp::categoryLight()); add<&cfAddition >(cs, COMPOSITE_LINEAR_DODGE, i18n("Linear Dodge"), KoCompositeOp::categoryLight()); add<&cfLightenOnly >(cs, COMPOSITE_LIGHTEN , i18n("Lighten") , KoCompositeOp::categoryLight()); add<&cfHardLight >(cs, COMPOSITE_HARD_LIGHT , i18n("Hard Light") , KoCompositeOp::categoryLight()); + add<&cfSoftLightPegtopDelphi>(cs, COMPOSITE_SOFT_LIGHT_PEGTOP_DELPHI, i18n("Soft Light (Pegtop-Delphi)") , KoCompositeOp::categoryLight()); add<&cfSoftLightSvg >(cs, COMPOSITE_SOFT_LIGHT_SVG, i18n("Soft Light (SVG)") , KoCompositeOp::categoryLight()); add<&cfSoftLight >(cs, COMPOSITE_SOFT_LIGHT_PHOTOSHOP, i18n("Soft Light (Photoshop)") , KoCompositeOp::categoryLight()); add<&cfGammaLight >(cs, COMPOSITE_GAMMA_LIGHT , i18n("Gamma Light") , KoCompositeOp::categoryLight()); @@ -153,11 +157,18 @@ add<&cfExclusion >(cs, COMPOSITE_EXCLUSION , i18n("Exclusion") , KoCompositeOp::categoryNegative()); add<&cfEquivalence >(cs, COMPOSITE_EQUIVALENCE , i18n("Equivalence") , KoCompositeOp::categoryNegative()); add<&cfAdditiveSubtractive >(cs, COMPOSITE_ADDITIVE_SUBTRACTIVE , i18n("Additive-Subtractive") , KoCompositeOp::categoryNegative()); + add<&cfNegation >(cs, COMPOSITE_NEGATION , i18n("Negation") , KoCompositeOp::categoryNegative()); + add<&cfPhoenix >(cs, COMPOSITE_PHOENIX , i18n("Phoenix") , KoCompositeOp::categoryNegative()); + add<&cfSignedDifference >(cs, COMPOSITE_SIGNED_DIFFERENCE , i18n("Signed Difference") , KoCompositeOp::categoryNegative()); add<&cfReflect >(cs, COMPOSITE_REFLECT , i18n("Reflect") , KoCompositeOp::categoryQuadratic()); add<&cfGlow >(cs, COMPOSITE_GLOW , i18n("Glow") , KoCompositeOp::categoryQuadratic()); add<&cfFreeze >(cs, COMPOSITE_FREEZE , i18n("Freeze") , KoCompositeOp::categoryQuadratic()); add<&cfHeat >(cs, COMPOSITE_HEAT , i18n("Heat") , KoCompositeOp::categoryQuadratic()); + add<&cfGleat >(cs, COMPOSITE_GLEAT , i18n("Gleat") , KoCompositeOp::categoryQuadratic()); + add<&cfHelow >(cs, COMPOSITE_HELOW , i18n("Helow") , KoCompositeOp::categoryQuadratic()); + add<&cfReeze >(cs, COMPOSITE_REEZE , i18n("Reeze") , KoCompositeOp::categoryQuadratic()); + add<&cfFrect >(cs, COMPOSITE_FRECT , i18n("Frect") , KoCompositeOp::categoryQuadratic()); cs->addCompositeOp(new KoCompositeOpDissolve(cs, KoCompositeOp::categoryMisc())); }