mirror of
https://github.com/thorvg/thorvg.git
synced 2025-07-23 14:48:24 +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, "Difference", tvg::BlendMethod::Difference, 900.0f, 150.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, "Saturation (Not Supported)", tvg::BlendMethod::Saturation, 900.0f, 600.0f, data);
|
||||
blender(canvas, "Color (Not Supported)", tvg::BlendMethod::Color, 900.0f, 750.0f, data);
|
||||
blender(canvas, "Luminosity (Not Supported)", tvg::BlendMethod::Luminosity, 900.0f, 900.0f, data);
|
||||
blender(canvas, "Hue", tvg::BlendMethod::Hue, 900.0f, 450.0f, data);
|
||||
blender(canvas, "Saturation", tvg::BlendMethod::Saturation, 900.0f, 600.0f, data);
|
||||
blender(canvas, "Color", tvg::BlendMethod::Color, 900.0f, 750.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, "HardMix (Not Supported)", tvg::BlendMethod::HardMix, 900.0f, 1200.0f, data);
|
||||
blender(canvas, "HardMix", tvg::BlendMethod::HardMix, 900.0f, 1200.0f, 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)
|
||||
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)
|
||||
Hue, ///< Reserved. Not supported.
|
||||
Saturation, ///< Reserved. Not supported.
|
||||
Color, ///< Reserved. Not supported.
|
||||
Luminosity, ///< Reserved. Not supported.
|
||||
Hue, ///< Combine with HSL(Sh + Ds + Dl) then convert it to RGB.
|
||||
Saturation, ///< Combine with HSL(Dh + Ss + Dl) then convert it to RGB.
|
||||
Color, ///< Combine with HSL(Sh + Ss + Dl) then convert it to RGB.
|
||||
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)
|
||||
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
|
||||
};
|
||||
|
||||
|
|
|
@ -27,11 +27,6 @@ namespace tvg
|
|||
|
||||
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)) {
|
||||
r = g = b = (uint8_t)nearbyint(l * 255.0f);
|
||||
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 t = p + vsf;
|
||||
auto q = v - vsf;
|
||||
float tr, tg, tb;
|
||||
|
||||
switch (i) {
|
||||
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 4: tr = t; tg = p; tb = v; 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);
|
||||
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;
|
||||
brightness = _skipSpace(brightness + 1, nullptr);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <algorithm>
|
||||
#include "tvgCommon.h"
|
||||
#include "tvgMath.h"
|
||||
#include "tvgColor.h"
|
||||
#include "tvgRender.h"
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
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 mathDivide(int64_t a, int64_t b);
|
||||
|
@ -679,4 +754,6 @@ bool effectTint(SwCompositor* cmp, const RenderEffectTint* params, bool direct);
|
|||
void effectTritoneUpdate(RenderEffectTritone* effect);
|
||||
bool effectTritone(SwCompositor* cmp, const RenderEffectTritone* params, bool direct);
|
||||
|
||||
|
||||
|
||||
#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:
|
||||
surface->blender = opBlendExclusion;
|
||||
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:
|
||||
surface->blender = opBlendAdd;
|
||||
break;
|
||||
case BlendMethod::HardMix:
|
||||
surface->blender = opBlendHardMix;
|
||||
break;
|
||||
default:
|
||||
TVGLOG("SW_ENGINE", "Non supported blending option = %d", (int) method);
|
||||
surface->blender = nullptr;
|
||||
|
|
|
@ -429,10 +429,7 @@ uint8_t Paint::opacity() const noexcept
|
|||
|
||||
Result Paint::blend(BlendMethod method) noexcept
|
||||
{
|
||||
//TODO: Remove later
|
||||
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) {
|
||||
if (method <= BlendMethod::HardMix || method == BlendMethod::Composition) {
|
||||
pImpl->blend(method);
|
||||
return Result::Success;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue