mirror of
https://github.com/thorvg/thorvg.git
synced 2025-07-23 22:58:44 +00:00
Merge 4768331b3b
into 16604a873a
This commit is contained in:
commit
fd0c84b18d
8 changed files with 143 additions and 22 deletions
|
@ -162,12 +162,12 @@ struct UserExample : tvgexam::Example
|
||||||
blender(canvas, "SoftLight", tvg::BlendMethod::SoftLight, 900.0f, 0.0f, data);
|
blender(canvas, "SoftLight", tvg::BlendMethod::SoftLight, 900.0f, 0.0f, data);
|
||||||
blender(canvas, "Difference", tvg::BlendMethod::Difference, 900.0f, 150.0f, data);
|
blender(canvas, "Difference", tvg::BlendMethod::Difference, 900.0f, 150.0f, data);
|
||||||
blender(canvas, "Exclusion", tvg::BlendMethod::Exclusion, 900.0f, 300.0f, data);
|
blender(canvas, "Exclusion", tvg::BlendMethod::Exclusion, 900.0f, 300.0f, data);
|
||||||
blender(canvas, "Hue (Not Supported)", tvg::BlendMethod::Hue, 900.0f, 450.0f, data);
|
blender(canvas, "Hue", tvg::BlendMethod::Hue, 900.0f, 450.0f, data);
|
||||||
blender(canvas, "Saturation (Not Supported)", tvg::BlendMethod::Saturation, 900.0f, 600.0f, data);
|
blender(canvas, "Saturation", tvg::BlendMethod::Saturation, 900.0f, 600.0f, data);
|
||||||
blender(canvas, "Color (Not Supported)", tvg::BlendMethod::Color, 900.0f, 750.0f, data);
|
blender(canvas, "Color", tvg::BlendMethod::Color, 900.0f, 750.0f, data);
|
||||||
blender(canvas, "Luminosity (Not Supported)", tvg::BlendMethod::Luminosity, 900.0f, 900.0f, data);
|
blender(canvas, "Luminosity", tvg::BlendMethod::Luminosity, 900.0f, 900.0f, data);
|
||||||
blender(canvas, "Add", tvg::BlendMethod::Add, 900.0f, 1050.0f, data);
|
blender(canvas, "Add", tvg::BlendMethod::Add, 900.0f, 1050.0f, data);
|
||||||
blender(canvas, "HardMix (Not Supported)", tvg::BlendMethod::HardMix, 900.0f, 1200.0f, data);
|
blender(canvas, "HardMix", tvg::BlendMethod::HardMix, 900.0f, 1200.0f, data);
|
||||||
|
|
||||||
free(data);
|
free(data);
|
||||||
|
|
||||||
|
|
10
inc/thorvg.h
10
inc/thorvg.h
|
@ -209,12 +209,12 @@ enum class BlendMethod : uint8_t
|
||||||
SoftLight, ///< The same as Overlay but with applying pure black or white does not result in pure black or white. (255 - 2 * S) * (D * D) + (2 * S * D)
|
SoftLight, ///< The same as Overlay but with applying pure black or white does not result in pure black or white. (255 - 2 * S) * (D * D) + (2 * S * D)
|
||||||
Difference, ///< Subtracts the bottom layer from the top layer or the other way around, to always get a non-negative value. (S - D) if (S > D), otherwise (D - S)
|
Difference, ///< Subtracts the bottom layer from the top layer or the other way around, to always get a non-negative value. (S - D) if (S > D), otherwise (D - S)
|
||||||
Exclusion, ///< The result is twice the product of the top and bottom layers, subtracted from their sum. S + D - (2 * S * D)
|
Exclusion, ///< The result is twice the product of the top and bottom layers, subtracted from their sum. S + D - (2 * S * D)
|
||||||
Hue, ///< Reserved. Not supported.
|
Hue, ///< Combine with HSL(Sh + Ds + Dl) then convert it to RGB.
|
||||||
Saturation, ///< Reserved. Not supported.
|
Saturation, ///< Combine with HSL(Dh + Ss + Dl) then convert it to RGB.
|
||||||
Color, ///< Reserved. Not supported.
|
Color, ///< Combine with HSL(Sh + Ss + Dl) then convert it to RGB.
|
||||||
Luminosity, ///< Reserved. Not supported.
|
Luminosity, ///< Combine with HSL(Dh + Ds + Sl) then convert it to RGB.
|
||||||
Add, ///< Simply adds pixel values of one layer with the other. (S + D)
|
Add, ///< Simply adds pixel values of one layer with the other. (S + D)
|
||||||
HardMix, ///< Reserved. Not supported.
|
HardMix, ///< Adds S and D; result is 255 if the sum is greater than or equal to 255, otherwise 0.
|
||||||
Composition = 255 ///< Used for intermediate composition. @since 1.0
|
Composition = 255 ///< Used for intermediate composition. @since 1.0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -27,11 +27,6 @@ namespace tvg
|
||||||
|
|
||||||
void hsl2rgb(float h, float s, float l, uint8_t& r, uint8_t& g, uint8_t& b)
|
void hsl2rgb(float h, float s, float l, uint8_t& r, uint8_t& g, uint8_t& b)
|
||||||
{
|
{
|
||||||
s = tvg::clamp(s, 0.0f, 1.0f);
|
|
||||||
l = tvg::clamp(l, 0.0f, 1.0f);
|
|
||||||
|
|
||||||
auto tr = 0.0f, tg = 0.0f, tb = 0.0f;
|
|
||||||
|
|
||||||
if (tvg::zero(s)) {
|
if (tvg::zero(s)) {
|
||||||
r = g = b = (uint8_t)nearbyint(l * 255.0f);
|
r = g = b = (uint8_t)nearbyint(l * 255.0f);
|
||||||
return;
|
return;
|
||||||
|
@ -53,6 +48,7 @@ void hsl2rgb(float h, float s, float l, uint8_t& r, uint8_t& g, uint8_t& b)
|
||||||
auto vsf = v * sv * f;
|
auto vsf = v * sv * f;
|
||||||
auto t = p + vsf;
|
auto t = p + vsf;
|
||||||
auto q = v - vsf;
|
auto q = v - vsf;
|
||||||
|
float tr, tg, tb;
|
||||||
|
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case 0: tr = v; tg = t; tb = p; break;
|
case 0: tr = v; tg = t; tb = p; break;
|
||||||
|
@ -61,7 +57,7 @@ void hsl2rgb(float h, float s, float l, uint8_t& r, uint8_t& g, uint8_t& b)
|
||||||
case 3: tr = p; tg = q; tb = v; break;
|
case 3: tr = p; tg = q; tb = v; break;
|
||||||
case 4: tr = t; tg = p; tb = v; break;
|
case 4: tr = t; tg = p; tb = v; break;
|
||||||
case 5: tr = v; tg = p; tb = q; break;
|
case 5: tr = v; tg = p; tb = q; break;
|
||||||
default: break;
|
default: tr = tg = tb = 0.0f; break;
|
||||||
}
|
}
|
||||||
r = (uint8_t)nearbyint(tr * 255.0f);
|
r = (uint8_t)nearbyint(tr * 255.0f);
|
||||||
g = (uint8_t)nearbyint(tg * 255.0f);
|
g = (uint8_t)nearbyint(tg * 255.0f);
|
||||||
|
|
|
@ -645,7 +645,7 @@ static bool _toColor(const char* str, uint8_t& r, uint8_t&g, uint8_t& b, char**
|
||||||
hsl.l /= 100.0f;
|
hsl.l /= 100.0f;
|
||||||
brightness = _skipSpace(brightness + 1, nullptr);
|
brightness = _skipSpace(brightness + 1, nullptr);
|
||||||
if (brightness && brightness[0] == ')' && brightness[1] == '\0') {
|
if (brightness && brightness[0] == ')' && brightness[1] == '\0') {
|
||||||
hsl2rgb(hsl.h, hsl.s, hsl.l, r, g, b);
|
hsl2rgb(hsl.h, tvg::clamp(hsl.s, 0.0f, 1.0f), tvg::clamp(hsl.l, 0.0f, 1.0f), r, g, b);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "tvgCommon.h"
|
#include "tvgCommon.h"
|
||||||
#include "tvgMath.h"
|
#include "tvgMath.h"
|
||||||
|
#include "tvgColor.h"
|
||||||
#include "tvgRender.h"
|
#include "tvgRender.h"
|
||||||
|
|
||||||
#define SW_CURVE_TYPE_POINT 0
|
#define SW_CURVE_TYPE_POINT 0
|
||||||
|
@ -564,6 +565,80 @@ static inline uint32_t opBlendSoftLight(uint32_t s, uint32_t d)
|
||||||
return BLEND_PRE(JOIN(255, f(C1(s), o.r), f(C2(s), o.g), f(C3(s), o.b)), s, o.a);
|
return BLEND_PRE(JOIN(255, f(C1(s), o.r), f(C2(s), o.g), f(C3(s), o.b)), s, o.a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void rasterRGB2HSL(uint8_t r, uint8_t g, uint8_t b, float* h, float* s, float* l);
|
||||||
|
|
||||||
|
static inline uint32_t opBlendHue(uint32_t s, uint32_t d)
|
||||||
|
{
|
||||||
|
RenderColor o;
|
||||||
|
if (!BLEND_UPRE(d, o)) return s;
|
||||||
|
|
||||||
|
float sh, ds, dl;
|
||||||
|
rasterRGB2HSL(C1(s), C2(s), C3(s), &sh, 0, 0);
|
||||||
|
rasterRGB2HSL(o.r, o.g, o.b, 0, &ds, &dl);
|
||||||
|
|
||||||
|
uint8_t r, g, b;
|
||||||
|
hsl2rgb(sh, ds, dl, r, g, b);
|
||||||
|
|
||||||
|
return BLEND_PRE(JOIN(255, r, g, b), s, o.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t opBlendSaturation(uint32_t s, uint32_t d)
|
||||||
|
{
|
||||||
|
RenderColor o;
|
||||||
|
if (!BLEND_UPRE(d, o)) return s;
|
||||||
|
|
||||||
|
float dh, ss, dl;
|
||||||
|
rasterRGB2HSL(C1(s), C2(s), C3(s), 0, &ss, 0);
|
||||||
|
rasterRGB2HSL(o.r, o.g, o.b, &dh, 0, &dl);
|
||||||
|
|
||||||
|
uint8_t r, g, b;
|
||||||
|
hsl2rgb(dh, ss, dl, r, g, b);
|
||||||
|
|
||||||
|
return BLEND_PRE(JOIN(255, r, g, b), s, o.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t opBlendColor(uint32_t s, uint32_t d)
|
||||||
|
{
|
||||||
|
RenderColor o;
|
||||||
|
if (!BLEND_UPRE(d, o)) return s;
|
||||||
|
|
||||||
|
float sh, ss, dl;
|
||||||
|
rasterRGB2HSL(C1(s), C2(s), C3(s), &sh, &ss, 0);
|
||||||
|
rasterRGB2HSL(o.r, o.g, o.b, 0, 0, &dl);
|
||||||
|
|
||||||
|
uint8_t r, g, b;
|
||||||
|
hsl2rgb(sh, ss, dl, r, g, b);
|
||||||
|
|
||||||
|
return BLEND_PRE(JOIN(255, r, g, b), s, o.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t opBlendLuminosity(uint32_t s, uint32_t d)
|
||||||
|
{
|
||||||
|
RenderColor o;
|
||||||
|
if (!BLEND_UPRE(d, o)) return s;
|
||||||
|
|
||||||
|
float dh, ds, sl;
|
||||||
|
rasterRGB2HSL(C1(s), C2(s), C3(s), 0, 0, &sl);
|
||||||
|
rasterRGB2HSL(o.r, o.g, o.b, &dh, &ds, 0);
|
||||||
|
|
||||||
|
uint8_t r, g, b;
|
||||||
|
hsl2rgb(dh, ds, sl, r, g, b);
|
||||||
|
|
||||||
|
return BLEND_PRE(JOIN(255, r, g, b), s, o.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t opBlendHardMix(uint32_t s, uint32_t d)
|
||||||
|
{
|
||||||
|
RenderColor o;
|
||||||
|
if (!BLEND_UPRE(d, o)) return s;
|
||||||
|
|
||||||
|
auto f = [](uint8_t s, uint8_t d) {
|
||||||
|
return (s + d >= 255) ? 255 : 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
return BLEND_PRE(JOIN(255, f(C1(s), o.r), f(C2(s), o.g), f(C3(s), o.b)), s, o.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int64_t mathMultiply(int64_t a, int64_t b);
|
int64_t mathMultiply(int64_t a, int64_t b);
|
||||||
int64_t mathDivide(int64_t a, int64_t b);
|
int64_t mathDivide(int64_t a, int64_t b);
|
||||||
|
@ -679,4 +754,6 @@ bool effectTint(SwCompositor* cmp, const RenderEffectTint* params, bool direct);
|
||||||
void effectTritoneUpdate(RenderEffectTritone* effect);
|
void effectTritoneUpdate(RenderEffectTritone* effect);
|
||||||
bool effectTritone(SwCompositor* cmp, const RenderEffectTritone* params, bool direct);
|
bool effectTritone(SwCompositor* cmp, const RenderEffectTritone* params, bool direct);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* _TVG_SW_COMMON_H_ */
|
#endif /* _TVG_SW_COMMON_H_ */
|
||||||
|
|
|
@ -1769,4 +1769,40 @@ void rasterXYFlip(uint32_t* src, uint32_t* dst, int32_t stride, int32_t w, int32
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//TODO: can be moved in tvgColor
|
||||||
|
void rasterRGB2HSL(uint8_t r, uint8_t g, uint8_t b, float* h, float* s, float* l)
|
||||||
|
{
|
||||||
|
auto rf = r / 255.0f;
|
||||||
|
auto gf = g / 255.0f;
|
||||||
|
auto bf = b / 255.0f;
|
||||||
|
auto maxVal = std::max(std::max(rf, gf), bf);
|
||||||
|
auto minVal = std::min(std::min(rf, gf), bf);
|
||||||
|
auto delta = maxVal - minVal;
|
||||||
|
|
||||||
|
//lightness
|
||||||
|
float t;
|
||||||
|
if (l || s) {
|
||||||
|
t = (maxVal + minVal) * 0.5f;
|
||||||
|
if (l) *l = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tvg::zero(delta)) {
|
||||||
|
if (h) *h = 0.0f;
|
||||||
|
if (s) *s = 0.0f;
|
||||||
|
} else {
|
||||||
|
//saturation
|
||||||
|
if (s) {
|
||||||
|
*s = (t < 0.5f) ? (delta / (maxVal + minVal)) : (delta / (2.0f - maxVal - minVal));
|
||||||
|
}
|
||||||
|
//hue
|
||||||
|
if (h) {
|
||||||
|
if (maxVal == rf) *h = (gf - bf) / delta + (gf < bf ? 6.0f : 0.0f);
|
||||||
|
else if (maxVal == gf) *h = (bf - rf) / delta + 2.0f;
|
||||||
|
else *h = (rf - gf) / delta + 4.0f;
|
||||||
|
*h *= 60.0f; //directly convert to degrees
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -564,9 +564,24 @@ bool SwRenderer::blend(BlendMethod method)
|
||||||
case BlendMethod::Exclusion:
|
case BlendMethod::Exclusion:
|
||||||
surface->blender = opBlendExclusion;
|
surface->blender = opBlendExclusion;
|
||||||
break;
|
break;
|
||||||
|
case BlendMethod::Hue:
|
||||||
|
surface->blender = opBlendHue;
|
||||||
|
break;
|
||||||
|
case BlendMethod::Saturation:
|
||||||
|
surface->blender = opBlendSaturation;
|
||||||
|
break;
|
||||||
|
case BlendMethod::Color:
|
||||||
|
surface->blender = opBlendColor;
|
||||||
|
break;
|
||||||
|
case BlendMethod::Luminosity:
|
||||||
|
surface->blender = opBlendLuminosity;
|
||||||
|
break;
|
||||||
case BlendMethod::Add:
|
case BlendMethod::Add:
|
||||||
surface->blender = opBlendAdd;
|
surface->blender = opBlendAdd;
|
||||||
break;
|
break;
|
||||||
|
case BlendMethod::HardMix:
|
||||||
|
surface->blender = opBlendHardMix;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
TVGLOG("SW_ENGINE", "Non supported blending option = %d", (int) method);
|
TVGLOG("SW_ENGINE", "Non supported blending option = %d", (int) method);
|
||||||
surface->blender = nullptr;
|
surface->blender = nullptr;
|
||||||
|
|
|
@ -429,10 +429,7 @@ uint8_t Paint::opacity() const noexcept
|
||||||
|
|
||||||
Result Paint::blend(BlendMethod method) noexcept
|
Result Paint::blend(BlendMethod method) noexcept
|
||||||
{
|
{
|
||||||
//TODO: Remove later
|
if (method <= BlendMethod::HardMix || method == BlendMethod::Composition) {
|
||||||
if (method == BlendMethod::Hue || method == BlendMethod::Saturation || method == BlendMethod::Color || method == BlendMethod::Luminosity || method == BlendMethod::HardMix) return Result::NonSupport;
|
|
||||||
|
|
||||||
if (method == BlendMethod::Composition || method <= BlendMethod::HardMix) {
|
|
||||||
pImpl->blend(method);
|
pImpl->blend(method);
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue