mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-14 13:21:34 +00:00
Use shaders for ColorTintShadeTone/ColorSpectrum selectors (#960)
This is the first step to optimize the painting code of ColorSelectors which were using a background thread to paint their surface. ColorWheel is still using the old method (without shaders). This impl is already a lot faster on CPU, and it's ready for GPU-acceleration in a future.
This commit is contained in:
parent
4b99d3022a
commit
aca96c6d36
2
laf
2
laf
@ -1 +1 @@
|
||||
Subproject commit 34c67cd6f2be9dbb14f559b7fb16160318b07086
|
||||
Subproject commit 8b0422877a39d655bf6a405eb2e2985763b150da
|
@ -40,22 +40,6 @@ using namespace gfx;
|
||||
|
||||
namespace {
|
||||
|
||||
gfx::Color gridColor1()
|
||||
{
|
||||
if (ui::is_ui_thread() && current_editor)
|
||||
return color_utils::color_for_ui(current_editor->docPref().bg.color1());
|
||||
else
|
||||
return gfx::rgba(128, 128, 128);
|
||||
}
|
||||
|
||||
gfx::Color gridColor2()
|
||||
{
|
||||
if (ui::is_ui_thread() && current_editor)
|
||||
return color_utils::color_for_ui(current_editor->docPref().bg.color2());
|
||||
else
|
||||
return gfx::rgba(192, 192, 192);
|
||||
}
|
||||
|
||||
void draw_checked_grid(ui::Graphics* g,
|
||||
const gfx::Rect& rc,
|
||||
const gfx::Size& tile,
|
||||
@ -90,11 +74,27 @@ void draw_checked_grid(ui::Graphics* g,
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
gfx::Color grid_color1()
|
||||
{
|
||||
if (ui::is_ui_thread() && current_editor)
|
||||
return color_utils::color_for_ui(current_editor->docPref().bg.color1());
|
||||
else
|
||||
return gfx::rgba(128, 128, 128);
|
||||
}
|
||||
|
||||
gfx::Color grid_color2()
|
||||
{
|
||||
if (ui::is_ui_thread() && current_editor)
|
||||
return color_utils::color_for_ui(current_editor->docPref().bg.color2());
|
||||
else
|
||||
return gfx::rgba(192, 192, 192);
|
||||
}
|
||||
|
||||
void draw_checked_grid(ui::Graphics* g,
|
||||
const gfx::Rect& rc,
|
||||
const gfx::Size& tile)
|
||||
{
|
||||
draw_checked_grid(g, rc, tile, gridColor1(), gridColor2());
|
||||
draw_checked_grid(g, rc, tile, grid_color1(), grid_color2());
|
||||
}
|
||||
|
||||
void draw_checked_grid(ui::Graphics* g,
|
||||
@ -102,7 +102,7 @@ void draw_checked_grid(ui::Graphics* g,
|
||||
const gfx::Size& tile,
|
||||
DocumentPreferences& docPref)
|
||||
{
|
||||
draw_checked_grid(g, rc, tile, gridColor1(), gridColor2());
|
||||
draw_checked_grid(g, rc, tile, grid_color1(), grid_color2());
|
||||
}
|
||||
|
||||
void draw_color(ui::Graphics* g,
|
||||
@ -208,8 +208,8 @@ void draw_alpha_slider(ui::Graphics* g,
|
||||
|
||||
for (int x=0; x<rc.w; ++x) {
|
||||
const int a = (255 * x / xmax);
|
||||
const doc::color_t c1 = doc::rgba_blender_normal(gridColor1(), c, a);
|
||||
const doc::color_t c2 = doc::rgba_blender_normal(gridColor2(), c, a);
|
||||
const doc::color_t c1 = doc::rgba_blender_normal(grid_color1(), c, a);
|
||||
const doc::color_t c2 = doc::rgba_blender_normal(grid_color2(), c, a);
|
||||
const int mid = rc.h/2;
|
||||
const int odd = (x / rc.h) & 1;
|
||||
g->drawVLine(
|
||||
@ -236,8 +236,8 @@ void draw_alpha_slider(os::Surface* s,
|
||||
os::Paint paint;
|
||||
for (int x=0; x<rc.w; ++x) {
|
||||
const int a = (255 * x / xmax);
|
||||
const doc::color_t c1 = doc::rgba_blender_normal(gridColor1(), c, a);
|
||||
const doc::color_t c2 = doc::rgba_blender_normal(gridColor2(), c, a);
|
||||
const doc::color_t c1 = doc::rgba_blender_normal(grid_color1(), c, a);
|
||||
const doc::color_t c2 = doc::rgba_blender_normal(grid_color2(), c, a);
|
||||
const int mid = rc.h/2;
|
||||
const int odd = (x / rc.h) & 1;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -27,6 +27,9 @@ namespace ui {
|
||||
|
||||
namespace app {
|
||||
|
||||
gfx::Color grid_color1();
|
||||
gfx::Color grid_color2();
|
||||
|
||||
void draw_checked_grid(ui::Graphics* g,
|
||||
const gfx::Rect& rc,
|
||||
const gfx::Size& tile);
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "app/modules/gfx.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "app/ui/status_bar.h"
|
||||
#include "app/util/shader_helpers.h"
|
||||
#include "base/clamp.h"
|
||||
#include "base/concurrent_queue.h"
|
||||
#include "base/scoped_value.h"
|
||||
@ -36,8 +37,16 @@
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <condition_variable>
|
||||
#include <cstdio>
|
||||
#include <thread>
|
||||
|
||||
#if SK_ENABLE_SKSL
|
||||
#include "os/skia/skia_surface.h"
|
||||
|
||||
#include "include/core/SkCanvas.h"
|
||||
#include "include/effects/SkRuntimeEffect.h"
|
||||
#endif
|
||||
|
||||
namespace app {
|
||||
|
||||
using namespace app::skin;
|
||||
@ -224,6 +233,11 @@ private:
|
||||
|
||||
static ColorSelector::Painter painter;
|
||||
|
||||
#if SK_ENABLE_SKSL
|
||||
// static
|
||||
sk_sp<SkRuntimeEffect> ColorSelector::m_alphaEffect;
|
||||
#endif
|
||||
|
||||
ColorSelector::ColorSelector()
|
||||
: Widget(kGenericWidget)
|
||||
, m_paintFlags(AllAreasFlag)
|
||||
@ -421,12 +435,88 @@ void ColorSelector::onPaint(ui::PaintEvent& ev)
|
||||
if (rc.isEmpty())
|
||||
return;
|
||||
|
||||
g->drawSurface(
|
||||
painter.getCanvas(rc.w, rc.h, theme->colors.workspace()),
|
||||
rc.x, rc.y);
|
||||
|
||||
gfx::Rect bottomBarBounds = this->bottomBarBounds();
|
||||
gfx::Rect alphaBarBounds = this->alphaBarBounds();
|
||||
|
||||
os::Surface* painterSurface = nullptr;
|
||||
|
||||
#if SK_ENABLE_SKSL // Paint with shaders
|
||||
buildEffects();
|
||||
if (m_mainEffect && m_bottomEffect && m_alphaEffect) {
|
||||
SkCanvas* canvas;
|
||||
bool isSRGB;
|
||||
// TODO compare both color spaces
|
||||
if (get_current_color_space()->isSRGB() &&
|
||||
g->getInternalSurface()->colorSpace()->isSRGB()) {
|
||||
// We can render directly in the ui::Graphics surface
|
||||
canvas = &static_cast<os::SkiaSurface*>(g->getInternalSurface())->canvas();
|
||||
isSRGB = true;
|
||||
}
|
||||
else {
|
||||
// We'll paint in the ColorSelector::Painter canvas, and so we
|
||||
// can convert color spaces.
|
||||
painterSurface = painter.getCanvas(rc.w, rc.h, theme->colors.workspace());
|
||||
canvas = &static_cast<os::SkiaSurface*>(painterSurface)->canvas();
|
||||
isSRGB = false;
|
||||
}
|
||||
|
||||
canvas->save();
|
||||
{
|
||||
SkPaint p;
|
||||
p.setStyle(SkPaint::kFill_Style);
|
||||
|
||||
// Main area
|
||||
gfx::Rect rc2(0, 0, rc.w, std::max(1, rc.h-bottomBarBounds.h-alphaBarBounds.h));
|
||||
|
||||
SkRuntimeShaderBuilder builder1(m_mainEffect);
|
||||
builder1.uniform("iRes") = SkV3{float(rc2.w), float(rc2.h), 0.0f};
|
||||
builder1.uniform("iColor") = appColor_to_SkV4(m_color);
|
||||
p.setShader(builder1.makeShader());
|
||||
|
||||
if (isSRGB)
|
||||
canvas->translate(rc.x+g->getInternalDeltaX(),
|
||||
rc.y+g->getInternalDeltaY());
|
||||
|
||||
canvas->drawRect(SkRect::MakeXYWH(0, 0, rc2.w, rc2.h), p);
|
||||
|
||||
// Bottom bar
|
||||
canvas->translate(0.0, rc2.h);
|
||||
rc2.h = bottomBarBounds.h;
|
||||
|
||||
SkRuntimeShaderBuilder builder2(m_bottomEffect);
|
||||
builder2.uniform("iRes") = SkV3{float(rc2.w), float(rc2.h), 0.0f};
|
||||
builder2.uniform("iColor") = appColor_to_SkV4(m_color);
|
||||
p.setShader(builder2.makeShader());
|
||||
|
||||
canvas->drawRect(SkRect::MakeXYWH(0, 0, rc2.w, rc2.h), p);
|
||||
|
||||
// Alpha bar
|
||||
canvas->translate(0.0, rc2.h);
|
||||
rc2.h = alphaBarBounds.h;
|
||||
|
||||
SkRuntimeShaderBuilder builder3(m_alphaEffect);
|
||||
builder3.uniform("iRes") = SkV3{float(rc2.w), float(rc2.h), 0.0f};
|
||||
builder3.uniform("iColor") = appColor_to_SkV4(m_color);
|
||||
builder3.uniform("iBg1") = gfxColor_to_SkV4(grid_color1());
|
||||
builder3.uniform("iBg2") = gfxColor_to_SkV4(grid_color2());
|
||||
p.setShader(builder3.makeShader());
|
||||
|
||||
canvas->drawRect(SkRect::MakeXYWH(0, 0, rc2.w, rc2.h), p);
|
||||
}
|
||||
canvas->restore();
|
||||
|
||||
// We already painted all areas
|
||||
m_paintFlags = 0;
|
||||
}
|
||||
else
|
||||
#endif // SK_ENABLE_SKSL
|
||||
{
|
||||
painterSurface = painter.getCanvas(rc.w, rc.h, theme->colors.workspace());
|
||||
}
|
||||
|
||||
if (painterSurface)
|
||||
g->drawSurface(painterSurface, rc.x, rc.y);
|
||||
|
||||
rc.h -= bottomBarBounds.h + alphaBarBounds.h;
|
||||
onPaintMainArea(g, rc);
|
||||
|
||||
@ -537,4 +627,56 @@ void ColorSelector::updateColorSpace()
|
||||
invalidate();
|
||||
}
|
||||
|
||||
#if SK_ENABLE_SKSL
|
||||
// static
|
||||
const char* ColorSelector::getAlphaBarShader()
|
||||
{
|
||||
return R"(
|
||||
uniform half3 iRes;
|
||||
uniform half4 iColor;
|
||||
uniform half4 iBg1;
|
||||
uniform half4 iBg2;
|
||||
|
||||
half4 main(vec2 fragcoord) {
|
||||
vec2 d = (fragcoord.xy / iRes.xy);
|
||||
half4 p = (mod((fragcoord.x / iRes.y) + floor(d.y+0.5), 2.0) > 1.0) ? iBg2: iBg1;
|
||||
half4 q = iColor.rgb1;
|
||||
float a = d.x;
|
||||
return (1.0-a)*p + a*q;
|
||||
}
|
||||
)";
|
||||
}
|
||||
|
||||
void ColorSelector::buildEffects()
|
||||
{
|
||||
if (!m_mainEffect) {
|
||||
if (const char* code = getMainAreaShader())
|
||||
m_mainEffect = buildEffect(code);
|
||||
}
|
||||
|
||||
if (!m_bottomEffect) {
|
||||
if (const char* code = getBottomBarShader())
|
||||
m_bottomEffect = buildEffect(code);
|
||||
}
|
||||
|
||||
if (!m_alphaEffect) {
|
||||
if (const char* code = getAlphaBarShader())
|
||||
m_alphaEffect = buildEffect(code);
|
||||
}
|
||||
}
|
||||
|
||||
sk_sp<SkRuntimeEffect> ColorSelector::buildEffect(const char* code)
|
||||
{
|
||||
auto result = SkRuntimeEffect::MakeForShader(SkString(code));
|
||||
if (!result.errorText.isEmpty()) {
|
||||
LOG(ERROR, "Shader error: %s\n", result.errorText.c_str());
|
||||
std::printf("Shader error: %s\n", result.errorText.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
else {
|
||||
return result.effect;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace app
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2016-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -21,6 +21,13 @@
|
||||
#include <atomic>
|
||||
#include <cmath>
|
||||
|
||||
// TODO We should wrap the SkRuntimeEffect in laf-os, SkRuntimeEffect
|
||||
// and SkRuntimeShaderBuilder might change in future Skia
|
||||
// versions.
|
||||
#if SK_ENABLE_SKSL
|
||||
#include "include/effects/SkRuntimeEffect.h"
|
||||
#endif
|
||||
|
||||
// TODO move this to laf::base
|
||||
inline bool cs_double_diff(double a, double b) {
|
||||
return std::fabs((a)-(b)) > 0.001;
|
||||
@ -61,6 +68,8 @@ namespace app {
|
||||
void onResize(ui::ResizeEvent& ev) override;
|
||||
void onPaint(ui::PaintEvent& ev) override;
|
||||
|
||||
virtual const char* getMainAreaShader() { return nullptr; }
|
||||
virtual const char* getBottomBarShader() { return nullptr; }
|
||||
virtual app::Color getMainAreaColor(const int u, const int umax,
|
||||
const int v, const int vmax) = 0;
|
||||
virtual app::Color getBottomBarColor(const int u, const int umax) = 0;
|
||||
@ -101,6 +110,12 @@ namespace app {
|
||||
|
||||
void updateColorSpace();
|
||||
|
||||
#if SK_ENABLE_SKSL
|
||||
static const char* getAlphaBarShader();
|
||||
void buildEffects();
|
||||
sk_sp<SkRuntimeEffect> buildEffect(const char* code);
|
||||
#endif
|
||||
|
||||
// Internal flag used to lock the modification of m_color.
|
||||
// E.g. When the user picks a color harmony, we don't want to
|
||||
// change the main color.
|
||||
@ -117,6 +132,13 @@ namespace app {
|
||||
ui::Timer m_timer;
|
||||
|
||||
obs::scoped_connection m_appConn;
|
||||
|
||||
#if SK_ENABLE_SKSL
|
||||
// Shaders
|
||||
sk_sp<SkRuntimeEffect> m_mainEffect;
|
||||
sk_sp<SkRuntimeEffect> m_bottomEffect;
|
||||
static sk_sp<SkRuntimeEffect> m_alphaEffect;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -14,6 +14,7 @@
|
||||
#include "app/color_utils.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "app/ui/status_bar.h"
|
||||
#include "app/util/shader_helpers.h"
|
||||
#include "base/clamp.h"
|
||||
#include "os/surface.h"
|
||||
#include "ui/graphics.h"
|
||||
@ -35,6 +36,52 @@ ColorSpectrum::ColorSpectrum()
|
||||
{
|
||||
}
|
||||
|
||||
const char* ColorSpectrum::getMainAreaShader()
|
||||
{
|
||||
#if SK_ENABLE_SKSL
|
||||
if (m_mainShader.empty()) {
|
||||
m_mainShader += "uniform half3 iRes;"
|
||||
"uniform half4 iColor;";
|
||||
m_mainShader += kRGB_to_HSL_sksl;
|
||||
m_mainShader += kHSL_to_RGB_sksl;
|
||||
m_mainShader += R"(
|
||||
half4 main(vec2 fragcoord) {
|
||||
vec2 d = fragcoord.xy / iRes.xy;
|
||||
half hue = d.x;
|
||||
half sat = rgb_to_hsl(iColor.rgb).y;
|
||||
half lit = 1.0 - d.y;
|
||||
return hsl_to_rgb(half3(hue, sat, lit)).rgb1;
|
||||
}
|
||||
)";
|
||||
}
|
||||
return m_mainShader.c_str();
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char* ColorSpectrum::getBottomBarShader()
|
||||
{
|
||||
#if SK_ENABLE_SKSL
|
||||
if (m_bottomShader.empty()) {
|
||||
m_bottomShader += "uniform half3 iRes;"
|
||||
"uniform half4 iColor;";
|
||||
m_bottomShader += kRGB_to_HSL_sksl;
|
||||
m_bottomShader += kHSL_to_RGB_sksl;
|
||||
m_bottomShader += R"(
|
||||
half4 main(vec2 fragcoord) {
|
||||
half s = (fragcoord.x / iRes.x);
|
||||
half3 hsl = rgb_to_hsl(iColor.rgb);
|
||||
return hsl_to_rgb(half3(hsl.x, s, hsl.z)).rgb1;
|
||||
}
|
||||
)";
|
||||
}
|
||||
return m_bottomShader.c_str();
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
app::Color ColorSpectrum::getMainAreaColor(const int u, const int umax,
|
||||
const int v, const int vmax)
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2022 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -17,6 +18,8 @@ namespace app {
|
||||
ColorSpectrum();
|
||||
|
||||
protected:
|
||||
const char* getMainAreaShader() override;
|
||||
const char* getBottomBarShader() override;
|
||||
app::Color getMainAreaColor(const int u, const int umax,
|
||||
const int v, const int vmax) override;
|
||||
app::Color getBottomBarColor(const int u, const int umax) override;
|
||||
@ -28,6 +31,10 @@ namespace app {
|
||||
const gfx::Rect& alpha,
|
||||
bool& stop) override;
|
||||
int onNeedsSurfaceRepaint(const app::Color& newColor) override;
|
||||
|
||||
private:
|
||||
std::string m_mainShader;
|
||||
std::string m_bottomShader;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2016-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -13,6 +13,7 @@
|
||||
|
||||
#include "app/color_utils.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "app/util/shader_helpers.h"
|
||||
#include "base/clamp.h"
|
||||
#include "ui/graphics.h"
|
||||
|
||||
@ -28,6 +29,52 @@ ColorTintShadeTone::ColorTintShadeTone()
|
||||
{
|
||||
}
|
||||
|
||||
const char* ColorTintShadeTone::getMainAreaShader()
|
||||
{
|
||||
#if SK_ENABLE_SKSL
|
||||
if (m_mainShader.empty()) {
|
||||
m_mainShader += "uniform half3 iRes;"
|
||||
"uniform half4 iColor;";
|
||||
m_mainShader += kRGB_to_HSV_sksl;
|
||||
m_mainShader += kHSV_to_RGB_sksl;
|
||||
m_mainShader += R"(
|
||||
half4 main(vec2 fragcoord) {
|
||||
vec2 d = fragcoord.xy / iRes.xy;
|
||||
half hue = rgb_to_hsv(iColor.rgb).x;
|
||||
half sat = d.x;
|
||||
half val = 1.0 - d.y;
|
||||
return hsv_to_rgb(vec3(hue, sat, val)).rgb1;
|
||||
}
|
||||
)";
|
||||
}
|
||||
return m_mainShader.c_str();
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char* ColorTintShadeTone::getBottomBarShader()
|
||||
{
|
||||
#if SK_ENABLE_SKSL
|
||||
if (m_bottomShader.empty()) {
|
||||
m_bottomShader += "uniform half3 iRes;"
|
||||
"uniform half4 iColor;";
|
||||
m_bottomShader += kRGB_to_HSV_sksl;
|
||||
m_bottomShader += kHSV_to_RGB_sksl;
|
||||
m_bottomShader += R"(
|
||||
half4 main(vec2 fragcoord) {
|
||||
half h = (fragcoord.x / iRes.x);
|
||||
half3 hsv = rgb_to_hsv(iColor.rgb);
|
||||
return hsv_to_rgb(half3(h, hsv.y, hsv.z)).rgb1;
|
||||
}
|
||||
)";
|
||||
}
|
||||
return m_bottomShader.c_str();
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
app::Color ColorTintShadeTone::getMainAreaColor(const int u, const int umax,
|
||||
const int v, const int vmax)
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2022 Igara Studio S.A.
|
||||
// Copyright (C) 2016-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -18,6 +19,8 @@ namespace app {
|
||||
ColorTintShadeTone();
|
||||
|
||||
protected:
|
||||
const char* getMainAreaShader() override;
|
||||
const char* getBottomBarShader() override;
|
||||
app::Color getMainAreaColor(const int u, const int umax,
|
||||
const int v, const int vmax) override;
|
||||
app::Color getBottomBarColor(const int u, const int umax) override;
|
||||
@ -29,6 +32,10 @@ namespace app {
|
||||
const gfx::Rect& alpha,
|
||||
bool& stop) override;
|
||||
int onNeedsSurfaceRepaint(const app::Color& newColor) override;
|
||||
|
||||
private:
|
||||
std::string m_mainShader;
|
||||
std::string m_bottomShader;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
67
src/app/util/shader_helpers.h
Normal file
67
src/app/util/shader_helpers.h
Normal file
@ -0,0 +1,67 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2022 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifndef APP_UTIL_SHADER_HELPERS_H_INCLUDED
|
||||
#define APP_UTIL_SHADER_HELPERS_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#if SK_ENABLE_SKSL
|
||||
|
||||
#include "app/color.h"
|
||||
#include "gfx/color.h"
|
||||
|
||||
#include "include/core/SkM44.h"
|
||||
|
||||
// To include kRGB_to_HSL_sksl and kHSL_to_RGB_sksl
|
||||
#include "src/core/SkRuntimeEffectPriv.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
// rgb_to_hsl() and hsv_to_hsl() functions by Sam Hocevar licensed
|
||||
// under WTFPL (https://en.wikipedia.org/wiki/WTFPL)
|
||||
// Source:
|
||||
// http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl
|
||||
// https://stackoverflow.com/a/17897228/408239
|
||||
|
||||
inline constexpr char kRGB_to_HSV_sksl[] = R"(
|
||||
half3 rgb_to_hsv(half3 c) {
|
||||
half4 K = half4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
|
||||
half4 p = mix(half4(c.bg, K.wz), half4(c.gb, K.xy), step(c.b, c.g));
|
||||
half4 q = mix(half4(p.xyw, c.r), half4(c.r, p.yzx), step(p.x, c.r));
|
||||
|
||||
float d = q.x - min(q.w, q.y);
|
||||
float e = 1.0e-10;
|
||||
return half3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
|
||||
}
|
||||
)";
|
||||
|
||||
inline constexpr char kHSV_to_RGB_sksl[] = R"(
|
||||
half3 hsv_to_rgb(half3 c) {
|
||||
half4 K = half4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
|
||||
half3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
|
||||
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
|
||||
}
|
||||
)";
|
||||
|
||||
inline SkV4 gfxColor_to_SkV4(gfx::Color color) {
|
||||
return SkV4{float(gfx::getr(color) / 255.0),
|
||||
float(gfx::getg(color) / 255.0),
|
||||
float(gfx::getb(color) / 255.0),
|
||||
float(gfx::geta(color) / 255.0)};
|
||||
}
|
||||
|
||||
inline SkV4 appColor_to_SkV4(const app::Color& color) {
|
||||
return SkV4{float(color.getRed() / 255.0),
|
||||
float(color.getGreen() / 255.0),
|
||||
float(color.getBlue() / 255.0),
|
||||
float(color.getAlpha() / 255.0)};
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user