diff --git a/libs/pigment/KoColorSpaceMaths.h b/libs/pigment/KoColorSpaceMaths.h --- a/libs/pigment/KoColorSpaceMaths.h +++ b/libs/pigment/KoColorSpaceMaths.h @@ -249,6 +249,22 @@ return (dst_compositetype(a) * KoColorSpaceMathsTraits<_Tdst>::unitValue) / b; } + inline static dst_compositetype modulus(_T a, _Tdst b) { + return (dst_compositetype(a) - floor(dst_compositetype(a)/((b != (KoColorSpaceMathsTraits<_T>::zeroValue - traits::epsilon) ? b : KoColorSpaceMathsTraits<_T>::zeroValue) + traits::epsilon))*(b + traits::epsilon)); + } + + inline static dst_compositetype xor(_T a, _Tdst b) { + return (int (a * std::numeric_limits::max() - traits::epsilon) ^ int (b * std::numeric_limits::max() - traits::epsilon)); + } + + inline static dst_compositetype and(_T a, _Tdst b) { + return (int (a * std::numeric_limits::max() - traits::epsilon) & int (b * std::numeric_limits::max() - traits::epsilon)); + } + + inline static dst_compositetype or(_T a, _Tdst b) { + return (int (a * std::numeric_limits::max() - traits::epsilon) | int (b * std::numeric_limits::max() - traits::epsilon)); + } + /** * Inversion : unitValue - a * @param a @@ -575,7 +591,19 @@ template inline typename KoColorSpaceMathsTraits::compositetype div(T a, T b) { return KoColorSpaceMaths::divide(a, b); } - + + template + inline typename KoColorSpaceMathsTraits::compositetype + xor(T a, T b) { return KoColorSpaceMaths::xor(a, b); } + + template + inline typename KoColorSpaceMathsTraits::compositetype + and(T a, T b) { return KoColorSpaceMaths::and(a, b); } + + template + inline typename KoColorSpaceMathsTraits::compositetype + or(T a, T b) { return KoColorSpaceMaths::or(a, b); } + template inline T clamp(typename KoColorSpaceMathsTraits::compositetype a) { return KoColorSpaceMaths::clamp(a); @@ -612,6 +640,13 @@ inline T blend(T src, T srcAlpha, T dst, T dstAlpha, T cfValue) { return mul(inv(srcAlpha), dstAlpha, dst) + mul(inv(dstAlpha), srcAlpha, src) + mul(dstAlpha, srcAlpha, cfValue); } + + template + inline T epsilon() { return KoColorSpaceMathsTraits::epsilon; } + + template + inline typename KoColorSpaceMathsTraits::compositetype + mod(T a, T b) { return KoColorSpaceMaths::modulus(a, b); } } struct HSYType diff --git a/libs/pigment/KoCompositeOp.h b/libs/pigment/KoCompositeOp.h --- a/libs/pigment/KoCompositeOp.h +++ b/libs/pigment/KoCompositeOp.h @@ -42,15 +42,17 @@ static QString categoryColor(); static QString categoryArithmetic(); + static QString categoryBinary(); + static QString categoryModulo(); static QString categoryNegative(); static QString categoryLight(); static QString categoryDark(); static QString categoryHSY(); static QString categoryHSI(); static QString categoryHSL(); static QString categoryHSV(); static QString categoryMix(); - static QString categoryMisc(); + static QString categoryMisc(); static QString categoryQuadratic(); struct KRITAPIGMENT_EXPORT ParameterInfo diff --git a/libs/pigment/KoCompositeOp.cpp b/libs/pigment/KoCompositeOp.cpp --- a/libs/pigment/KoCompositeOp.cpp +++ b/libs/pigment/KoCompositeOp.cpp @@ -32,6 +32,8 @@ } QString KoCompositeOp::categoryArithmetic() { return i18n("Arithmetic"); } +QString KoCompositeOp::categoryBinary() { return i18n("Binary"); } +QString KoCompositeOp::categoryModulo() { return i18n("Modulo"); } QString KoCompositeOp::categoryNegative() { return i18n("Negative"); } QString KoCompositeOp::categoryLight() { return i18n("Lighten"); } QString KoCompositeOp::categoryDark() { return i18n("Darken"); } @@ -41,7 +43,7 @@ QString KoCompositeOp::categoryHSV() { return i18n("HSV"); } QString KoCompositeOp::categoryMix() { return i18n("Mix"); } QString KoCompositeOp::categoryMisc() { return i18n("Misc"); } -QString KoCompositeOp::categoryQuadratic() { return i18n("Quadratic"); } +QString KoCompositeOp::categoryQuadratic() { return i18n("Quadratic"); } KoCompositeOp::ParameterInfo::ParameterInfo() : opacity(1.0f), diff --git a/libs/pigment/KoCompositeOpRegistry.h b/libs/pigment/KoCompositeOpRegistry.h --- a/libs/pigment/KoCompositeOpRegistry.h +++ b/libs/pigment/KoCompositeOpRegistry.h @@ -42,6 +42,16 @@ const QString COMPOSITE_DESTINATION_ATOP = "destination-atop"; const QString COMPOSITE_XOR = "xor"; +const QString COMPOSITE_OR = "or"; +const QString COMPOSITE_AND = "and"; +const QString COMPOSITE_NAND = "nand"; +const QString COMPOSITE_NOR = "nor"; +const QString COMPOSITE_XNOR = "xnor"; +const QString COMPOSITE_IMPLICATION = "implication"; +const QString COMPOSITE_NOT_IMPLICATION = "not_implication"; +const QString COMPOSITE_CONVERSE = "converse"; +const QString COMPOSITE_NOT_CONVERSE = "not_converse"; + const QString COMPOSITE_PLUS = "plus"; const QString COMPOSITE_MINUS = "minus"; const QString COMPOSITE_ADD = "add"; @@ -53,6 +63,14 @@ 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_MOD = "modulo"; +const QString COMPOSITE_MOD_CON = "modulo_continuous"; +const QString COMPOSITE_DIVISIVE_MOD = "divisive_modulo"; +const QString COMPOSITE_DIVISIVE_MOD_CON = "divisive_modulo_continuous"; +const QString COMPOSITE_MODULO_SHIFT = "modulo_shift"; +const QString COMPOSITE_MODULO_SHIFT_CON = "modulo_shift_continuous"; const QString COMPOSITE_EQUIVALENCE = "equivalence"; const QString COMPOSITE_ALLANON = "allanon"; @@ -66,23 +84,44 @@ const QString COMPOSITE_BEHIND = "behind"; const QString COMPOSITE_GREATER = "greater"; const QString COMPOSITE_HARD_OVERLAY = "hard overlay"; +const QString COMPOSITE_INTERPOLATION = "interpolation"; +const QString COMPOSITE_INTERPOLATIONB = "interpolation 2x"; +const QString COMPOSITE_PENUMBRAA = "penumbra a"; +const QString COMPOSITE_PENUMBRAB = "penumbra b"; +const QString COMPOSITE_PENUMBRAC = "penumbra c"; +const QString COMPOSITE_PENUMBRAD = "penumbra d"; const QString COMPOSITE_DARKEN = "darken"; const QString COMPOSITE_BURN = "burn";//this is also known as 'color burn'. +const QString COMPOSITE_BURN_LOGARITHMIC = "burn_logarithmic"; const QString COMPOSITE_LINEAR_BURN = "linear_burn"; const QString COMPOSITE_GAMMA_DARK = "gamma_dark"; +const QString COMPOSITE_SHADE_IFS_ILLUSIONS = "shade_ifs_illusions"; +const QString COMPOSITE_FOG_DARKEN_IFS_ILLUSIONS = "fog_darken_ifs_illusions"; +const QString COMPOSITE_EASY_BURN = "easy burn"; const QString COMPOSITE_LIGHTEN = "lighten"; const QString COMPOSITE_DODGE = "dodge"; +const QString COMPOSITE_DODGE_LOGARITHMIC = "dodge_logarithmic"; const QString COMPOSITE_LINEAR_DODGE = "linear_dodge"; const QString COMPOSITE_SCREEN = "screen"; const QString COMPOSITE_HARD_LIGHT = "hard_light"; +const QString COMPOSITE_SOFT_LIGHT_IFS_ILLUSIONS = "soft_light_ifs_illusions"; +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"; +const QString COMPOSITE_GAMMA_ILLUMINATION = "gamma_illumination"; const QString COMPOSITE_VIVID_LIGHT = "vivid_light"; +const QString COMPOSITE_FLAT_LIGHT = "flat_light"; const QString COMPOSITE_LINEAR_LIGHT = "linear light"; const QString COMPOSITE_PIN_LIGHT = "pin_light"; +const QString COMPOSITE_PNORM_A = "pnorm_a"; +const QString COMPOSITE_PNORM_B = "pnorm_b"; +const QString COMPOSITE_SUPER_LIGHT = "super_light"; +const QString COMPOSITE_TINT_IFS_ILLUSIONS = "tint_ifs_illusions"; +const QString COMPOSITE_FOG_LIGHTEN_IFS_ILLUSIONS = "fog_lighten_ifs_illusions"; +const QString COMPOSITE_EASY_DODGE = "easy dodge"; const QString COMPOSITE_HUE = "hue"; const QString COMPOSITE_COLOR = "color"; @@ -142,6 +181,11 @@ const QString COMPOSITE_GLOW = "glow"; const QString COMPOSITE_FREEZE = "freeze"; const QString COMPOSITE_HEAT = "heat"; +const QString COMPOSITE_GLEAT = "glow_heat"; +const QString COMPOSITE_HELOW = "heat_glow"; +const QString COMPOSITE_REEZE = "reflect_freeze"; +const QString COMPOSITE_FRECT = "freeze_reflect"; +const QString COMPOSITE_FHYRD = "heat_glow_freeze_reflect_hybrid"; diff --git a/libs/pigment/KoCompositeOpRegistry.cpp b/libs/pigment/KoCompositeOpRegistry.cpp --- a/libs/pigment/KoCompositeOpRegistry.cpp +++ b/libs/pigment/KoCompositeOpRegistry.cpp @@ -35,8 +35,10 @@ { m_categories << KoID("arithmetic", i18n("Arithmetic")) + << KoID("binary" , i18n("Binary")) << KoID("dark" , i18n("Darken")) << KoID("light" , i18n("Lighten")) + << KoID("modulo" , i18n("Modulo")) << KoID("negative" , i18n("Negative")) << KoID("mix" , i18n("Mix")) << KoID("misc" , i18n("Misc")) @@ -51,98 +53,143 @@ m_map.insert(m_categories[0], KoID(COMPOSITE_MULT , i18n("Multiply"))); m_map.insert(m_categories[0], KoID(COMPOSITE_DIVIDE , i18n("Divide"))); m_map.insert(m_categories[0], KoID(COMPOSITE_INVERSE_SUBTRACT, i18n("Inverse Subtract"))); + + m_map.insert(m_categories[1], KoID(COMPOSITE_XOR , i18n("XOR"))); + m_map.insert(m_categories[1], KoID(COMPOSITE_OR , i18n("OR"))); + m_map.insert(m_categories[1], KoID(COMPOSITE_AND , i18n("AND"))); + m_map.insert(m_categories[1], KoID(COMPOSITE_NAND , i18n("NAND"))); + m_map.insert(m_categories[1], KoID(COMPOSITE_NOR , i18n("NOR"))); + m_map.insert(m_categories[1], KoID(COMPOSITE_XNOR , i18n("XNOR"))); + m_map.insert(m_categories[1], KoID(COMPOSITE_IMPLICATION , i18n("IMPLICATION"))); + m_map.insert(m_categories[1], KoID(COMPOSITE_NOT_IMPLICATION , i18n("NOT IMPLICATION"))); + m_map.insert(m_categories[1], KoID(COMPOSITE_CONVERSE , i18n("CONVERSE"))); + m_map.insert(m_categories[1], KoID(COMPOSITE_NOT_CONVERSE , i18n("NOT CONVERSE"))); + + m_map.insert(m_categories[2], KoID(COMPOSITE_BURN , i18n("Burn"))); + m_map.insert(m_categories[2], KoID(COMPOSITE_BURN_LOGARITHMIC , i18n("Burn - Logarithmic"))); + m_map.insert(m_categories[2], KoID(COMPOSITE_LINEAR_BURN, i18n("Linear Burn"))); + m_map.insert(m_categories[2], KoID(COMPOSITE_DARKEN , i18n("Darken"))); + m_map.insert(m_categories[2], KoID(COMPOSITE_GAMMA_DARK , i18n("Gamma Dark"))); + m_map.insert(m_categories[2], KoID(COMPOSITE_DARKER_COLOR , i18n("Darker Color"))); + m_map.insert(m_categories[2], KoID(COMPOSITE_SHADE_IFS_ILLUSIONS, i18n("Shade (IFS Illusions)"))); + m_map.insert(m_categories[2], KoID(COMPOSITE_FOG_DARKEN_IFS_ILLUSIONS, i18n("Fog Darken (IFS Illusions)"))); + m_map.insert(m_categories[2], KoID(COMPOSITE_EASY_BURN , i18n("Easy Burn"))); + + m_map.insert(m_categories[3], KoID(COMPOSITE_DODGE , i18n("Color Dodge"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_DODGE_LOGARITHMIC , i18n("Color Dodge - Logarithmic"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_LINEAR_DODGE, i18n("Linear Dodge"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_LIGHTEN , i18n("Lighten"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_LINEAR_LIGHT, i18n("Linear Light"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_SCREEN , i18n("Screen"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_PIN_LIGHT , i18n("Pin Light"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_VIVID_LIGHT , i18n("Vivid Light"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_FLAT_LIGHT , i18n("Flat Light"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_HARD_LIGHT , i18n("Hard Light"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_SOFT_LIGHT_IFS_ILLUSIONS, i18n("Soft Light (IFS Illusions)"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_SOFT_LIGHT_PEGTOP_DELPHI, i18n("Soft Light (Pegtop-Delphi)"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_SOFT_LIGHT_PHOTOSHOP, i18n("Soft Light (Photoshop)"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_SOFT_LIGHT_SVG, i18n("Soft Light (SVG)"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_GAMMA_LIGHT , i18n("Gamma Light"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_GAMMA_ILLUMINATION , i18n("Gamma Illumination"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_LIGHTER_COLOR , i18n("Lighter Color"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_PNORM_A , i18n("P-Norm A"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_PNORM_B , i18n("P-Norm B"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_SUPER_LIGHT , i18n("Super Light"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_TINT_IFS_ILLUSIONS, i18n("Tint (IFS Illusions)"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_FOG_LIGHTEN_IFS_ILLUSIONS, i18n("Fog Lighten (IFS Illusions)"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_EASY_DODGE , i18n("Easy Dodge"))); + + m_map.insert(m_categories[4], KoID(COMPOSITE_MOD , i18n("Modulo"))); + m_map.insert(m_categories[4], KoID(COMPOSITE_MOD_CON , i18n("Modulo - Continuous"))); + m_map.insert(m_categories[4], KoID(COMPOSITE_DIVISIVE_MOD , i18n("Divisive Modulo"))); + m_map.insert(m_categories[4], KoID(COMPOSITE_DIVISIVE_MOD_CON , i18n("Divisive Modulo - Continuous"))); + m_map.insert(m_categories[4], KoID(COMPOSITE_MODULO_SHIFT , i18n("Modulo Shift"))); + m_map.insert(m_categories[4], KoID(COMPOSITE_MODULO_SHIFT_CON , i18n("Modulo Shift - Continuous"))); + + m_map.insert(m_categories[5], KoID(COMPOSITE_DIFF , i18n("Difference"))); + m_map.insert(m_categories[5], KoID(COMPOSITE_EQUIVALENCE , i18n("Equivalence"))); + m_map.insert(m_categories[5], KoID(COMPOSITE_ADDITIVE_SUBTRACTIVE , i18n("Additive Subtractive"))); + m_map.insert(m_categories[5], KoID(COMPOSITE_EXCLUSION , i18n("Exclusion"))); + m_map.insert(m_categories[5], KoID(COMPOSITE_ARC_TANGENT , i18n("Arcus Tangent"))); + m_map.insert(m_categories[5], KoID(COMPOSITE_NEGATION , i18n("Negation"))); + + m_map.insert(m_categories[6], KoID(COMPOSITE_OVER , i18n("Normal"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_BEHIND , i18n("Behind"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_GREATER , i18n("Greater"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_OVERLAY , i18n("Overlay"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_ERASE , i18n("Erase"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_ALPHA_DARKEN , i18n("Alpha Darken"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_HARD_MIX , i18n("Hard Mix"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_HARD_MIX_PHOTOSHOP, i18n("Hard Mix (Photoshop)"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_GRAIN_MERGE , i18n("Grain Merge"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_GRAIN_EXTRACT , i18n("Grain Extract"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_PARALLEL , i18n("Parallel"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_ALLANON , i18n("Allanon"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_GEOMETRIC_MEAN , i18n("Geometric Mean"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_DESTINATION_ATOP, i18n("Destination Atop"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_DESTINATION_IN , i18n("Destination In"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_HARD_OVERLAY , i18n("Hard Overlay"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_INTERPOLATION , i18n("Interpolation"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_INTERPOLATIONB , i18n("Interpolation - 2X"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_PENUMBRAA , i18n("Penumbra A"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_PENUMBRAB , i18n("Penumbra B"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_PENUMBRAC , i18n("Penumbra C"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_PENUMBRAD , i18n("Penumbra D"))); + + m_map.insert(m_categories[7], KoID(COMPOSITE_BUMPMAP , i18n("Bumpmap"))); + m_map.insert(m_categories[7], KoID(COMPOSITE_COMBINE_NORMAL, i18n("Combine Normal Map"))); + m_map.insert(m_categories[7], KoID(COMPOSITE_DISSOLVE , i18n("Dissolve"))); + m_map.insert(m_categories[7], KoID(COMPOSITE_COPY_RED , i18n("Copy Red"))); + m_map.insert(m_categories[7], KoID(COMPOSITE_COPY_GREEN, i18n("Copy Green"))); + m_map.insert(m_categories[7], KoID(COMPOSITE_COPY_BLUE , i18n("Copy Blue"))); + m_map.insert(m_categories[7], KoID(COMPOSITE_COPY , i18n("Copy"))); + m_map.insert(m_categories[7], KoID(COMPOSITE_TANGENT_NORMALMAP, i18n("Tangent Normalmap"))); + + m_map.insert(m_categories[8], KoID(COMPOSITE_COLOR , i18n("Color"))); + m_map.insert(m_categories[8], KoID(COMPOSITE_HUE , i18n("Hue"))); + m_map.insert(m_categories[8], KoID(COMPOSITE_SATURATION , i18n("Saturation"))); + m_map.insert(m_categories[8], KoID(COMPOSITE_LUMINIZE , i18n("Luminosity"))); + m_map.insert(m_categories[8], KoID(COMPOSITE_DEC_SATURATION, i18n("Decrease Saturation"))); + m_map.insert(m_categories[8], KoID(COMPOSITE_INC_SATURATION, i18n("Increase Saturation"))); + m_map.insert(m_categories[8], KoID(COMPOSITE_DEC_LUMINOSITY, i18n("Decrease Luminosity"))); + m_map.insert(m_categories[8], KoID(COMPOSITE_INC_LUMINOSITY, i18n("Increase Luminosity"))); + + m_map.insert(m_categories[9], KoID(COMPOSITE_COLOR_HSI , i18n("Color HSI"))); + m_map.insert(m_categories[9], KoID(COMPOSITE_HUE_HSI , i18n("Hue HSI"))); + m_map.insert(m_categories[9], KoID(COMPOSITE_SATURATION_HSI , i18n("Saturation HSI"))); + m_map.insert(m_categories[9], KoID(COMPOSITE_INTENSITY , i18n("Intensity"))); + m_map.insert(m_categories[9], KoID(COMPOSITE_DEC_SATURATION_HSI, i18n("Decrease Saturation HSI"))); + m_map.insert(m_categories[9], KoID(COMPOSITE_INC_SATURATION_HSI, i18n("Increase Saturation HSI"))); + m_map.insert(m_categories[9], KoID(COMPOSITE_DEC_INTENSITY , i18n("Decrease Intensity"))); + m_map.insert(m_categories[9], KoID(COMPOSITE_INC_INTENSITY , i18n("Increase Intensity"))); + + m_map.insert(m_categories[10], KoID(COMPOSITE_COLOR_HSL , i18n("Color HSL"))); + m_map.insert(m_categories[10], KoID(COMPOSITE_HUE_HSL , i18n("Hue HSL"))); + m_map.insert(m_categories[10], KoID(COMPOSITE_SATURATION_HSL , i18n("Saturation HSL"))); + m_map.insert(m_categories[10], KoID(COMPOSITE_LIGHTNESS , i18n("Lightness"))); + m_map.insert(m_categories[10], KoID(COMPOSITE_DEC_SATURATION_HSL, i18n("Decrease Saturation HSL"))); + m_map.insert(m_categories[10], KoID(COMPOSITE_INC_SATURATION_HSL, i18n("Increase Saturation HSL"))); + m_map.insert(m_categories[10], KoID(COMPOSITE_DEC_LIGHTNESS , i18n("Decrease Lightness"))); + m_map.insert(m_categories[10], KoID(COMPOSITE_INC_LIGHTNESS , i18n("Increase Lightness"))); - m_map.insert(m_categories[1], KoID(COMPOSITE_BURN , i18n("Burn"))); - m_map.insert(m_categories[1], KoID(COMPOSITE_LINEAR_BURN, i18n("Linear Burn"))); - m_map.insert(m_categories[1], KoID(COMPOSITE_DARKEN , i18n("Darken"))); - m_map.insert(m_categories[1], KoID(COMPOSITE_GAMMA_DARK , i18n("Gamma Dark"))); - m_map.insert(m_categories[1], KoID(COMPOSITE_DARKER_COLOR , i18n("Darker Color"))); - - m_map.insert(m_categories[2], KoID(COMPOSITE_DODGE , i18n("Color Dodge"))); - m_map.insert(m_categories[2], KoID(COMPOSITE_LINEAR_DODGE, i18n("Linear Dodge"))); - m_map.insert(m_categories[2], KoID(COMPOSITE_LIGHTEN , i18n("Lighten"))); - m_map.insert(m_categories[2], KoID(COMPOSITE_LINEAR_LIGHT, i18n("Linear Light"))); - m_map.insert(m_categories[2], KoID(COMPOSITE_SCREEN , i18n("Screen"))); - 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_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"))); - m_map.insert(m_categories[2], KoID(COMPOSITE_LIGHTER_COLOR , i18n("Lighter Color"))); - - m_map.insert(m_categories[3], KoID(COMPOSITE_DIFF , i18n("Difference"))); - m_map.insert(m_categories[3], KoID(COMPOSITE_EQUIVALENCE , i18n("Equivalence"))); - 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[4], KoID(COMPOSITE_OVER , i18n("Normal"))); - m_map.insert(m_categories[4], KoID(COMPOSITE_BEHIND , i18n("Behind"))); - m_map.insert(m_categories[4], KoID(COMPOSITE_GREATER , i18n("Greater"))); - m_map.insert(m_categories[4], KoID(COMPOSITE_OVERLAY , i18n("Overlay"))); - m_map.insert(m_categories[4], KoID(COMPOSITE_ERASE , i18n("Erase"))); - m_map.insert(m_categories[4], KoID(COMPOSITE_ALPHA_DARKEN , i18n("Alpha Darken"))); - m_map.insert(m_categories[4], KoID(COMPOSITE_HARD_MIX , i18n("Hard Mix"))); - m_map.insert(m_categories[4], KoID(COMPOSITE_HARD_MIX_PHOTOSHOP, i18n("Hard Mix (Photoshop)"))); - m_map.insert(m_categories[4], KoID(COMPOSITE_GRAIN_MERGE , i18n("Grain Merge"))); - m_map.insert(m_categories[4], KoID(COMPOSITE_GRAIN_EXTRACT , i18n("Grain Extract"))); - m_map.insert(m_categories[4], KoID(COMPOSITE_PARALLEL , i18n("Parallel"))); - m_map.insert(m_categories[4], KoID(COMPOSITE_ALLANON , i18n("Allanon"))); - m_map.insert(m_categories[4], KoID(COMPOSITE_GEOMETRIC_MEAN , i18n("Geometric Mean"))); - 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[5], KoID(COMPOSITE_BUMPMAP , i18n("Bumpmap"))); - m_map.insert(m_categories[5], KoID(COMPOSITE_COMBINE_NORMAL, i18n("Combine Normal Map"))); - m_map.insert(m_categories[5], KoID(COMPOSITE_DISSOLVE , i18n("Dissolve"))); - m_map.insert(m_categories[5], KoID(COMPOSITE_COPY_RED , i18n("Copy Red"))); - m_map.insert(m_categories[5], KoID(COMPOSITE_COPY_GREEN, i18n("Copy Green"))); - m_map.insert(m_categories[5], KoID(COMPOSITE_COPY_BLUE , i18n("Copy Blue"))); - m_map.insert(m_categories[5], KoID(COMPOSITE_COPY , i18n("Copy"))); - m_map.insert(m_categories[5], KoID(COMPOSITE_TANGENT_NORMALMAP, i18n("Tangent Normalmap"))); - - m_map.insert(m_categories[6], KoID(COMPOSITE_COLOR , i18n("Color"))); - m_map.insert(m_categories[6], KoID(COMPOSITE_HUE , i18n("Hue"))); - m_map.insert(m_categories[6], KoID(COMPOSITE_SATURATION , i18n("Saturation"))); - m_map.insert(m_categories[6], KoID(COMPOSITE_LUMINIZE , i18n("Luminosity"))); - m_map.insert(m_categories[6], KoID(COMPOSITE_DEC_SATURATION, i18n("Decrease Saturation"))); - m_map.insert(m_categories[6], KoID(COMPOSITE_INC_SATURATION, i18n("Increase Saturation"))); - m_map.insert(m_categories[6], KoID(COMPOSITE_DEC_LUMINOSITY, i18n("Decrease Luminosity"))); - m_map.insert(m_categories[6], KoID(COMPOSITE_INC_LUMINOSITY, i18n("Increase Luminosity"))); - - m_map.insert(m_categories[7], KoID(COMPOSITE_COLOR_HSI , i18n("Color HSI"))); - m_map.insert(m_categories[7], KoID(COMPOSITE_HUE_HSI , i18n("Hue HSI"))); - m_map.insert(m_categories[7], KoID(COMPOSITE_SATURATION_HSI , i18n("Saturation HSI"))); - m_map.insert(m_categories[7], KoID(COMPOSITE_INTENSITY , i18n("Intensity"))); - m_map.insert(m_categories[7], KoID(COMPOSITE_DEC_SATURATION_HSI, i18n("Decrease Saturation HSI"))); - m_map.insert(m_categories[7], KoID(COMPOSITE_INC_SATURATION_HSI, i18n("Increase Saturation HSI"))); - m_map.insert(m_categories[7], KoID(COMPOSITE_DEC_INTENSITY , i18n("Decrease Intensity"))); - m_map.insert(m_categories[7], KoID(COMPOSITE_INC_INTENSITY , i18n("Increase Intensity"))); - - m_map.insert(m_categories[8], KoID(COMPOSITE_COLOR_HSL , i18n("Color HSL"))); - m_map.insert(m_categories[8], KoID(COMPOSITE_HUE_HSL , i18n("Hue HSL"))); - m_map.insert(m_categories[8], KoID(COMPOSITE_SATURATION_HSL , i18n("Saturation HSL"))); - m_map.insert(m_categories[8], KoID(COMPOSITE_LIGHTNESS , i18n("Lightness"))); - m_map.insert(m_categories[8], KoID(COMPOSITE_DEC_SATURATION_HSL, i18n("Decrease Saturation HSL"))); - m_map.insert(m_categories[8], KoID(COMPOSITE_INC_SATURATION_HSL, i18n("Increase Saturation HSL"))); - m_map.insert(m_categories[8], KoID(COMPOSITE_DEC_LIGHTNESS , i18n("Decrease Lightness"))); - m_map.insert(m_categories[8], KoID(COMPOSITE_INC_LIGHTNESS , i18n("Increase Lightness"))); - - m_map.insert(m_categories[9], KoID(COMPOSITE_COLOR_HSV , i18n("Color HSV"))); - m_map.insert(m_categories[9], KoID(COMPOSITE_HUE_HSV , i18n("Hue HSV"))); - m_map.insert(m_categories[9], KoID(COMPOSITE_SATURATION_HSV , i18n("Saturation HSV"))); - m_map.insert(m_categories[9], KoID(COMPOSITE_VALUE , i18nc("HSV Value", "Value"))); - m_map.insert(m_categories[9], KoID(COMPOSITE_DEC_SATURATION_HSV, i18n("Decrease Saturation HSV"))); - m_map.insert(m_categories[9], KoID(COMPOSITE_INC_SATURATION_HSV, i18n("Increase Saturation HSV"))); - m_map.insert(m_categories[9], KoID(COMPOSITE_DEC_VALUE , i18n("Decrease Value"))); - m_map.insert(m_categories[9], KoID(COMPOSITE_INC_VALUE , i18n("Increase Value"))); + m_map.insert(m_categories[11], KoID(COMPOSITE_COLOR_HSV , i18n("Color HSV"))); + m_map.insert(m_categories[11], KoID(COMPOSITE_HUE_HSV , i18n("Hue HSV"))); + m_map.insert(m_categories[11], KoID(COMPOSITE_SATURATION_HSV , i18n("Saturation HSV"))); + m_map.insert(m_categories[11], KoID(COMPOSITE_VALUE , i18nc("HSV Value", "Value"))); + m_map.insert(m_categories[11], KoID(COMPOSITE_DEC_SATURATION_HSV, i18n("Decrease Saturation HSV"))); + m_map.insert(m_categories[11], KoID(COMPOSITE_INC_SATURATION_HSV, i18n("Increase Saturation HSV"))); + m_map.insert(m_categories[11], KoID(COMPOSITE_DEC_VALUE , i18n("Decrease Value"))); + m_map.insert(m_categories[11], KoID(COMPOSITE_INC_VALUE , i18n("Increase Value"))); - m_map.insert(m_categories[10], KoID(COMPOSITE_REFLECT , i18n("Reflect"))); - 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[12], KoID(COMPOSITE_REFLECT , i18n("Reflect"))); + m_map.insert(m_categories[12], KoID(COMPOSITE_GLOW , i18n("Glow"))); + m_map.insert(m_categories[12], KoID(COMPOSITE_FREEZE , i18n("Freeze"))); + m_map.insert(m_categories[12], KoID(COMPOSITE_HEAT , i18n("Heat"))); + m_map.insert(m_categories[12], KoID(COMPOSITE_GLEAT , i18n("Glow-Heat"))); + m_map.insert(m_categories[12], KoID(COMPOSITE_HELOW , i18n("Heat-Glow"))); + m_map.insert(m_categories[12], KoID(COMPOSITE_REEZE , i18n("Reflect-Freeze"))); + m_map.insert(m_categories[12], KoID(COMPOSITE_FRECT , i18n("Freeze-Reflect"))); + m_map.insert(m_categories[12], KoID(COMPOSITE_FHYRD , i18n("Heat-Glow & Freeze-Reflect Hybrid"))); } 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 @@ -176,13 +176,14 @@ template inline T cfColorDodge(T src, T dst) { using namespace Arithmetic; - - if(dst == zeroValue()) - return zeroValue(); + //Fixing Color Dodge to avoid ZX Colors on bright area. + + if(src == unitValue()) + return unitValue(); T invSrc = inv(src); - if(invSrc < dst) + if(invSrc == zeroValue()) return unitValue(); return Arithmetic::clamp(div(dst, invSrc)); @@ -347,7 +348,15 @@ // min(max(2 / (1/dst + 1/src), 0), 1) composite_type unit = unitValue(); composite_type s = (src != zeroValue()) ? div(unit, src) : unit; - composite_type d = (dst != zeroValue()) ? div(unit, dst) : unit; + composite_type d = (dst != zeroValue()) ? div(unit, dst) : unit; + if (src == zeroValue()) { + return zeroValue(); + } + + if (dst == zeroValue()) { + return zeroValue(); + } + return clamp((unit+unit) * unit / (d+s)); } @@ -413,6 +422,12 @@ return scale(pow(scale(dst), scale(src))); } +template +inline T cfGammaIllumination(T src, T dst) { + using namespace Arithmetic; + return inv(cfGammaDark(inv(src),inv(dst))); +} + template inline T cfGeometricMean(T src, T dst) { using namespace Arithmetic; @@ -434,6 +449,9 @@ qreal fsrc = scale(src); qreal fdst = scale(dst); + + if (fsrc == 1.0) { + return scale(1.0);} if(fsrc > 0.5f) { return scale(cfDivide(inv(2.0 * fsrc - 1.0f), fdst)); @@ -457,47 +475,485 @@ inline T cfGlow(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 (dst == unitValue()) { + return unitValue(); + } + + return clamp(div(mul(src, src), inv(dst))); +} + +template +inline T cfReflect(T src, T dst) { + using namespace Arithmetic; - if(dst == unitValue()) { + + return clamp(cfGlow(dst,src)); +} + +template +inline T cfHeat(T src, T dst) { + using namespace Arithmetic; + + if(src == unitValue()) { return unitValue(); } - if(src == zeroValue()) { + if(dst == zeroValue()) { return zeroValue(); } + + return inv(clamp(div(mul(inv(src), inv(src)),dst))); +} + +template +inline T cfFreeze(T src, T dst) { + using namespace Arithmetic; - return clamp(div(mul(src, src), inv(dst))); + return (cfHeat(dst,src)); } + +template +inline T cfHelow(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); + } + + if (src == zeroValue()) { + return zeroValue(); + } + + return (cfGlow(src,dst)); +} + template -inline T cfReflect(T src, T dst) { +inline T cfFrect(T src, T dst) { + using namespace Arithmetic; + + if (cfHardMixPhotoshop(src,dst) == unitValue()) { + return cfFreeze(src,dst); + } + + if (dst == zeroValue()) { + return zeroValue(); + } + + return (cfReflect(src,dst)); +} + +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(dst == unitValue()) { + return unitValue(); + } - return (cfGlow(dst,src)); + if(cfHardMixPhotoshop(src,dst) == unitValue()) { + return cfGlow(src,dst); + } + + return (cfHeat(src,dst)); } template -inline T cfHeat(T src, T dst) { +inline T cfReeze(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 (cfGleat(dst,src)); +} +template +inline T cfFhyrd(T src, T dst) { + using namespace Arithmetic; + + return (cfAllanon(cfFrect(src,dst),cfHelow(src,dst))); +} + +template +inline T cfInterpolation(T src, T dst) { + using namespace Arithmetic; + + qreal fsrc = scale(src); + qreal fdst = scale(dst); + + if(dst == zeroValue() && src == zeroValue()) { return zeroValue(); + } + + return scale(.5f-.25f*cos(pi*(fsrc))-.25f*cos(pi*(fdst))); +} + +template +inline T cfInterpolationB(T src, T dst) { + using namespace Arithmetic; + + return cfInterpolation(cfInterpolation(src,dst),cfInterpolation(src,dst)); +} + + +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(inv(dst),src)/2)); +} + +template +inline T cfPenumbraD(T src, T dst) { + using namespace Arithmetic; - if(src == unitValue()) { + if (dst == unitValue()) { return unitValue(); } - return inv(clamp(div(mul(inv(src), inv(src)),dst))); + return cfArcTangent(src,inv(dst)); } template -inline T cfFreeze(T src, T dst) { +inline T cfPenumbraC(T src, T dst) { + using namespace Arithmetic; + + return cfPenumbraD(dst,src); +} + +template +inline T cfPenumbraA(T src, T dst) { + using namespace Arithmetic; + + return (cfPenumbraB(dst,src)); +} + +template +inline T cfSoftLightIFSIllusions(T src, T dst) { + using namespace Arithmetic; + + qreal fsrc = scale(src); + qreal fdst = scale(dst); + + return scale(pow(fdst,pow(2.0,(mul(2.0,.5f-fsrc))))); +} + +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 cfNor(T src, T dst) { + using namespace Arithmetic; + + return and(src,dst); +} + +template +inline T cfNand(T src, T dst) { + using namespace Arithmetic; + + return or(src,dst); +} + +template +inline T cfXor(T src, T dst) { + using namespace Arithmetic; + + return xor(src,dst); +} + +template +inline T cfXnor(T src, T dst) { + using namespace Arithmetic; + + return cfXor(src,inv(dst)); +} + +template +inline T cfAnd(T src, T dst) { using namespace Arithmetic; + + return cfNor(inv(src),inv(dst)); +} + +template +inline T cfOr(T src, T dst) { + using namespace Arithmetic; + + return cfNand(inv(src),inv(dst)); +} + +template +inline T cfConverse(T src, T dst) { + using namespace Arithmetic; + + return cfOr(inv(src),dst); +} + +template +inline T cfNotConverse(T src, T dst) { + using namespace Arithmetic; + + return cfAnd(src,inv(dst)); +} + +template +inline T cfImplies(T src, T dst) { + using namespace Arithmetic; + + return cfOr(src,inv(dst)); +} + +template +inline T cfNotImplies(T src, T dst) { + using namespace Arithmetic; + + return cfAnd(inv(src),dst); +} + +template +inline T cfPNormA(T src, T dst) { + using namespace Arithmetic; + //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... + + return clamp(pow(pow(dst,2.3333333333333333)+pow(src,2.3333333333333333),0.428571428571434)); +} + +template +inline T cfPNormB(T src, T dst) { + using namespace Arithmetic; + //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... + + return clamp(pow(pow(dst,4)+pow(src,4),0.25)); +} + +template +inline T cfSuperLight(T src, T dst) { + using namespace Arithmetic; + //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. + + qreal fsrc = scale(src); + qreal fdst = scale(dst); + + if (fsrc < .5) { + return scale(inv(pow(pow(inv(fdst),2.875)+pow(inv(2.0*fsrc),2.875),1.0/2.875))); + } + + return scale(pow(pow(fdst,2.875)+pow(2.0*fsrc-1.0,2.875),1.0/2.875)); +} + +template +inline T cfTintIFSIllusions(T src, T dst) { + using namespace Arithmetic; + //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. + + qreal fsrc = scale(src); + qreal fdst = scale(dst); + + return scale(fsrc*inv(fdst)+sqrt(fdst)); +} + +template +inline T cfShadeIFSIllusions(T src, T dst) { + using namespace Arithmetic; + //Known as Shadow Blending mode found in IFS Illusions. Picked this name because it is the opposite of Tint (IFS Illusion Blending mode). + + qreal fsrc = scale(src); + qreal fdst = scale(dst); + + return scale(inv((inv(fdst)*fsrc)+sqrt(inv(fsrc)))); +} + +template +inline T cfFogLightenIFSIllusions(T src, T dst) { + using namespace Arithmetic; + //Known as Bright Blending mode found in IFS Illusions. Picked this name because the shading reminds me of fog when overlaying with a gradientt. + + qreal fsrc = scale(src); + qreal fdst = scale(dst); + + if (fsrc < .5) { + return scale(inv(inv(fsrc)*fsrc)-inv(fdst)*inv(fsrc)); + } + + return scale(fsrc-inv(fdst)*inv(fsrc)+pow(inv(fsrc),2)); +} + +template +inline T cfFogDarkenIFSIllusions(T src, T dst) { + using namespace Arithmetic; + //Known as Dark Blending mode found in IFS Illusions. Picked this name because the shading reminds me of fog when overlaying with a gradient. + + qreal fsrc = scale(src); + qreal fdst = scale(dst); + + if (fsrc < .5) { + return scale(inv(fsrc)*fsrc+fsrc*fdst); + } + + return scale(fsrc*fdst+fsrc-pow(fsrc,2)); +} + +template +inline T cfModulo(T src, T dst) { + using namespace Arithmetic; + + return mod(dst,src); +} + +template +inline T cfModuloShift(T src, T dst) { + using namespace Arithmetic; + qreal fsrc = scale(src); + qreal fdst = scale(dst); + + if (fsrc == 1.0 && fdst == 0.0) { + return scale(0.0); + } + - return clamp(cfHeat(dst,src)); + return scale(mod((fdst+fsrc),1.0000000000)); } +template +inline T cfModuloShiftContinuous(T src, T dst) { + using namespace Arithmetic; + //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. + qreal fsrc = scale(src); + qreal fdst = scale(dst); + + if (fsrc == 1.0 && fdst == 0.0) { + return scale(0.0); + } + + return scale((int(ceil(fdst+fsrc)) % 2 != 0) || (fdst == zeroValue()) ? inv(cfModuloShift(fsrc,fdst)) : cfModuloShift(fsrc,fdst)); +} +template +inline T cfDivisiveModulo(T src, T dst) { + using namespace Arithmetic; + //I have to use 1.00000 as unitValue failed to work for those area. + + qreal fsrc = scale(src); + qreal fdst = scale(dst); + + if (fsrc == zeroValue()) { + return scale(mod(((1.0000000000/epsilon()) * fdst),1.0000000000)); + } + + return scale(mod(((1.0000000000/fsrc) * fdst),1.0000000000)); +} + +template +inline T cfDivisiveModuloContinuous(T src, T dst) { + using namespace Arithmetic; + + qreal fsrc = scale(src); + qreal fdst = scale(dst); + + if (fdst == zeroValue()) { + return zeroValue(); + } + + if (fsrc == zeroValue()) { + return cfDivisiveModulo(fsrc,fdst); + } + + + return scale( int(ceil(fdst/fsrc)) % 2 != 0 ? cfDivisiveModulo(fsrc,fdst) : inv(cfDivisiveModulo(fsrc,fdst))); +} + +template +inline T cfModuloContinuous(T src, T dst) { + using namespace Arithmetic; + + return cfMultiply(cfDivisiveModuloContinuous(src,dst),src); +} + +template +inline T cfColorBurnLogarithmic(T src, T dst) { + using namespace Arithmetic; + //Also known as Darken from EffectBank/Illusions.hu. IFS Illusions had used this blending mode. + + qreal fsrc = scale(src); + qreal fdst = scale(dst); + + if (inv(fdst) == zeroValue()) { + return scale(log2(1.0 + abs(fsrc)/abs(inv(.999999))/8)); + } + + return scale(log2(1.0 + abs(fsrc)/abs(inv(fdst))/8)); +} + +template +inline T cfColorDodgeLogarithmic(T src, T dst) { + using namespace Arithmetic; + //Also known as Lighten from EffectBank/Illusions.hu. IFS Illusions had used this blending mode. + + return inv(cfColorBurnLogarithmic(inv(src),inv(dst))); +} + +template +inline T cfEasyDodge(T src, T dst) { + using namespace Arithmetic; + // The 13 divided by 15 can be adjusted to taste. See imgblend.m + + qreal fsrc = scale(src); + qreal fdst = scale(dst); + + if (fsrc == 1.0) { + return scale(1.0);} + + + return scale(pow(fdst,mul(inv(fsrc != 1.0 ? fsrc : .999999999999),1.039999999))); +} + +template +inline T cfEasyBurn(T src, T dst) { + using namespace Arithmetic; + // The 13 divided by 15 can be adjusted to taste. See imgblend.m + + qreal fsrc = scale(src); + qreal fdst = scale(dst); + + + return scale(inv(pow(inv(fsrc != 1.0 ? fsrc : .999999999999),mul(fdst,1.039999999)))); +} + +template +inline T cfFlatLight(T src, T dst) { + using namespace Arithmetic; + + if (src == zeroValue()) { + return zeroValue(); + } + + return clamp(cfHardMixPhotoshop(inv(src),dst)==unitValue() ? cfPenumbraB(src,dst) : cfPenumbraA(src,dst)); +} #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 @@ -134,40 +134,85 @@ 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<&cfInterpolation >(cs, COMPOSITE_INTERPOLATION , i18n("Interpolation") , KoCompositeOp::categoryMix()); + add<&cfInterpolationB >(cs, COMPOSITE_INTERPOLATIONB , i18n("Interpolation - 2X") , KoCompositeOp::categoryMix()); + add<&cfPenumbraA >(cs, COMPOSITE_PENUMBRAA , i18n("Penumbra A") , KoCompositeOp::categoryMix()); + add<&cfPenumbraB >(cs, COMPOSITE_PENUMBRAB , i18n("Penumbra B") , KoCompositeOp::categoryMix()); + add<&cfPenumbraC >(cs, COMPOSITE_PENUMBRAC , i18n("Penumbra C") , KoCompositeOp::categoryMix()); + add<&cfPenumbraD >(cs, COMPOSITE_PENUMBRAD , i18n("Penumbra D") , 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<&cfSoftLightIFSIllusions>(cs, COMPOSITE_SOFT_LIGHT_IFS_ILLUSIONS, i18n("Soft Light (IFS Illusions)") , 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()); + add<&cfGammaIllumination >(cs, COMPOSITE_GAMMA_ILLUMINATION , i18n("Gamma Illumination") , KoCompositeOp::categoryLight()); add<&cfVividLight >(cs, COMPOSITE_VIVID_LIGHT , i18n("Vivid Light") , KoCompositeOp::categoryLight()); + add<&cfFlatLight >(cs, COMPOSITE_FLAT_LIGHT , i18n("Flat Light") , KoCompositeOp::categoryLight()); add<&cfPinLight >(cs, COMPOSITE_PIN_LIGHT , i18n("Pin Light") , KoCompositeOp::categoryLight()); add<&cfLinearLight >(cs, COMPOSITE_LINEAR_LIGHT, i18n("Linear Light"), KoCompositeOp::categoryLight()); + add<&cfPNormA >(cs, COMPOSITE_PNORM_A , i18n("P-Norm A") , KoCompositeOp::categoryLight()); + add<&cfPNormB >(cs, COMPOSITE_PNORM_B , i18n("P-Norm B") , KoCompositeOp::categoryLight()); + add<&cfSuperLight >(cs, COMPOSITE_SUPER_LIGHT , i18n("Super Light") , KoCompositeOp::categoryLight()); + add<&cfTintIFSIllusions >(cs, COMPOSITE_TINT_IFS_ILLUSIONS , i18n("Tint (IFS Illusions)") , KoCompositeOp::categoryLight()); + add<&cfFogLightenIFSIllusions >(cs, COMPOSITE_FOG_LIGHTEN_IFS_ILLUSIONS , i18n("Fog Lighten (IFS Illusions)") , KoCompositeOp::categoryLight()); + add<&cfColorDodgeLogarithmic >(cs, COMPOSITE_DODGE_LOGARITHMIC , i18n("Color Dodge - Logarithmic") , KoCompositeOp::categoryLight()); + add<&cfEasyDodge >(cs, COMPOSITE_EASY_DODGE , i18n("Easy Dodge") , KoCompositeOp::categoryLight()); add<&cfColorBurn >(cs, COMPOSITE_BURN , i18n("Color Burn") , KoCompositeOp::categoryDark()); add<&cfLinearBurn >(cs, COMPOSITE_LINEAR_BURN , i18n("Linear Burn"), KoCompositeOp::categoryDark()); add<&cfDarkenOnly >(cs, COMPOSITE_DARKEN , i18n("Darken") , KoCompositeOp::categoryDark()); add<&cfGammaDark >(cs, COMPOSITE_GAMMA_DARK , i18n("Gamma Dark") , KoCompositeOp::categoryDark()); + add<&cfShadeIFSIllusions >(cs, COMPOSITE_SHADE_IFS_ILLUSIONS , i18n("Shade (IFS_Illusions)") , KoCompositeOp::categoryDark()); + add<&cfFogDarkenIFSIllusions >(cs, COMPOSITE_FOG_DARKEN_IFS_ILLUSIONS , i18n("Fog Darken (IFS Illusions)") , KoCompositeOp::categoryDark()); + add<&cfColorBurnLogarithmic >(cs, COMPOSITE_BURN_LOGARITHMIC , i18n("Color Burn - Logarithmic") , KoCompositeOp::categoryDark()); + add<&cfEasyBurn >(cs, COMPOSITE_EASY_BURN , i18n("Easy Burn") , KoCompositeOp::categoryDark()); add<&cfAddition >(cs, COMPOSITE_ADD , i18n("Addition") , KoCompositeOp::categoryArithmetic()); add<&cfSubtract >(cs, COMPOSITE_SUBTRACT , i18n("Subtract") , KoCompositeOp::categoryArithmetic()); add<&cfInverseSubtract >(cs, COMPOSITE_INVERSE_SUBTRACT, i18n("Inversed-Subtract"), KoCompositeOp::categoryArithmetic()); add<&cfMultiply >(cs, COMPOSITE_MULT , i18n("Multiply") , KoCompositeOp::categoryArithmetic()); add<&cfDivide >(cs, COMPOSITE_DIVIDE , i18n("Divide") , KoCompositeOp::categoryArithmetic()); + add<&cfModulo >(cs, COMPOSITE_MOD , i18n("Modulo") , KoCompositeOp::categoryModulo()); + add<&cfModuloContinuous >(cs, COMPOSITE_MOD_CON , i18n("Modulo - Continuous") , KoCompositeOp::categoryModulo()); + add<&cfDivisiveModulo >(cs, COMPOSITE_DIVISIVE_MOD , i18n("Divisive Modulo") , KoCompositeOp::categoryModulo()); + add<&cfDivisiveModuloContinuous >(cs, COMPOSITE_DIVISIVE_MOD_CON , i18n("Divisive Modulo - Continuous") , KoCompositeOp::categoryModulo()); + add<&cfModuloShift >(cs, COMPOSITE_MODULO_SHIFT , i18n("Modulo Shift") , KoCompositeOp::categoryModulo()); + add<&cfModuloShiftContinuous >(cs, COMPOSITE_MODULO_SHIFT_CON , i18n("Modulo Shift - Continuous") , KoCompositeOp::categoryModulo()); + add<&cfArcTangent >(cs, COMPOSITE_ARC_TANGENT , i18n("Arcus Tangent") , KoCompositeOp::categoryNegative()); add<&cfDifference >(cs, COMPOSITE_DIFF , i18n("Difference") , KoCompositeOp::categoryNegative()); 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<&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<&cfXor >(cs, COMPOSITE_XOR , i18n("XOR") , KoCompositeOp::categoryBinary()); + add<&cfOr >(cs, COMPOSITE_OR , i18n("OR") , KoCompositeOp::categoryBinary()); + add<&cfAnd >(cs, COMPOSITE_AND , i18n("AND") , KoCompositeOp::categoryBinary()); + add<&cfNand >(cs, COMPOSITE_NAND , i18n("NAND") , KoCompositeOp::categoryBinary()); + add<&cfNor >(cs, COMPOSITE_NOR , i18n("NOR") , KoCompositeOp::categoryBinary()); + add<&cfXnor >(cs, COMPOSITE_XNOR , i18n("XNOR") , KoCompositeOp::categoryBinary()); + add<&cfImplies >(cs, COMPOSITE_IMPLICATION , i18n("IMPLICATION") , KoCompositeOp::categoryBinary()); + add<&cfNotImplies >(cs, COMPOSITE_NOT_IMPLICATION , i18n("NOT IMPLICATION") , KoCompositeOp::categoryBinary()); + add<&cfConverse >(cs, COMPOSITE_CONVERSE , i18n("CONVERSE") , KoCompositeOp::categoryBinary()); + add<&cfNotConverse >(cs, COMPOSITE_NOT_CONVERSE , i18n("NOT CONVERSE") , KoCompositeOp::categoryBinary()); + + 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("Glow-Heat") , KoCompositeOp::categoryQuadratic()); + add<&cfHelow >(cs, COMPOSITE_HELOW , i18n("Heat-Glow") , KoCompositeOp::categoryQuadratic()); + add<&cfReeze >(cs, COMPOSITE_REEZE , i18n("Reflect-Freeze") , KoCompositeOp::categoryQuadratic()); + add<&cfFrect >(cs, COMPOSITE_FRECT , i18n("Freeze-Reflect") , KoCompositeOp::categoryQuadratic()); + add<&cfFhyrd >(cs, COMPOSITE_FHYRD , i18n("Heat-Glow & Freeze-Reflect Hybrid") , KoCompositeOp::categoryQuadratic()); cs->addCompositeOp(new KoCompositeOpDissolve(cs, KoCompositeOp::categoryMisc())); }