mirror of
https://github.com/aseprite/aseprite.git
synced 2024-12-29 18:20:44 +00:00
Add helper functions make_shader(), make_skimage/skcanvas_for_docimage()
These functions can be used to create a new Skia shader from SkSL code, and a new SkImage/SkCanvas to modify a doc::Image*
This commit is contained in:
parent
50d4f9d802
commit
b8514ad1c6
@ -699,6 +699,7 @@ add_library(app-lib
|
|||||||
util/range_utils.cpp
|
util/range_utils.cpp
|
||||||
util/readable_time.cpp
|
util/readable_time.cpp
|
||||||
util/resize_image.cpp
|
util/resize_image.cpp
|
||||||
|
util/shader_helpers.cpp
|
||||||
util/tile_flags_utils.cpp
|
util/tile_flags_utils.cpp
|
||||||
util/tileset_utils.cpp
|
util/tileset_utils.cpp
|
||||||
util/wrap_point.cpp
|
util/wrap_point.cpp
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2022-2023 Igara Studio S.A.
|
// Copyright (C) 2022-2024 Igara Studio S.A.
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
// the End-User License Agreement for Aseprite.
|
// the End-User License Agreement for Aseprite.
|
||||||
@ -87,19 +87,9 @@ ShaderRenderer::ShaderRenderer()
|
|||||||
m_properties.renderBgOnScreen = true;
|
m_properties.renderBgOnScreen = true;
|
||||||
m_properties.requiresRgbaBackbuffer = true;
|
m_properties.requiresRgbaBackbuffer = true;
|
||||||
|
|
||||||
auto makeShader = [](const char* code) {
|
m_bgEffect = make_shader(kBgShaderCode);
|
||||||
auto result = SkRuntimeEffect::MakeForShader(SkString(code));
|
m_indexedEffect = make_shader(kIndexedShaderCode);
|
||||||
if (!result.errorText.isEmpty()) {
|
m_grayscaleEffect = make_shader(kGrayscaleShaderCode);
|
||||||
LOG(ERROR, "Shader error: %s\n", result.errorText.c_str());
|
|
||||||
std::printf("Shader error: %s\n", result.errorText.c_str());
|
|
||||||
throw std::runtime_error("Cannot compile shaders for ShaderRenderer");
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
m_bgEffect = makeShader(kBgShaderCode).effect;
|
|
||||||
m_indexedEffect = makeShader(kIndexedShaderCode).effect;
|
|
||||||
m_grayscaleEffect = makeShader(kGrayscaleShaderCode).effect;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderRenderer::~ShaderRenderer() = default;
|
ShaderRenderer::~ShaderRenderer() = default;
|
||||||
@ -416,21 +406,11 @@ void ShaderRenderer::drawImage(SkCanvas* canvas,
|
|||||||
const int opacity,
|
const int opacity,
|
||||||
const doc::BlendMode blendMode)
|
const doc::BlendMode blendMode)
|
||||||
{
|
{
|
||||||
auto skData = SkData::MakeWithoutCopy(
|
auto skImg = make_skimage_for_docimage(srcImage);
|
||||||
(const void*)srcImage->getPixelAddress(0, 0),
|
|
||||||
srcImage->rowBytes() * srcImage->height());
|
|
||||||
|
|
||||||
switch (srcImage->colorMode()) {
|
switch (srcImage->colorMode()) {
|
||||||
|
|
||||||
case doc::ColorMode::RGB: {
|
case doc::ColorMode::RGB: {
|
||||||
auto skImg = SkImage::MakeRasterData(
|
|
||||||
SkImageInfo::Make(srcImage->width(),
|
|
||||||
srcImage->height(),
|
|
||||||
kRGBA_8888_SkColorType,
|
|
||||||
kUnpremul_SkAlphaType),
|
|
||||||
skData,
|
|
||||||
srcImage->rowBytes());
|
|
||||||
|
|
||||||
SkPaint p;
|
SkPaint p;
|
||||||
p.setAlpha(opacity);
|
p.setAlpha(opacity);
|
||||||
p.setBlendMode(to_skia(blendMode));
|
p.setBlendMode(to_skia(blendMode));
|
||||||
@ -443,15 +423,6 @@ void ShaderRenderer::drawImage(SkCanvas* canvas,
|
|||||||
}
|
}
|
||||||
|
|
||||||
case doc::ColorMode::GRAYSCALE: {
|
case doc::ColorMode::GRAYSCALE: {
|
||||||
// We use kR8G8_unorm_SkColorType to access gray and alpha
|
|
||||||
auto skImg = SkImage::MakeRasterData(
|
|
||||||
SkImageInfo::Make(srcImage->width(),
|
|
||||||
srcImage->height(),
|
|
||||||
kR8G8_unorm_SkColorType,
|
|
||||||
kOpaque_SkAlphaType),
|
|
||||||
skData,
|
|
||||||
srcImage->rowBytes());
|
|
||||||
|
|
||||||
SkRuntimeShaderBuilder builder(m_grayscaleEffect);
|
SkRuntimeShaderBuilder builder(m_grayscaleEffect);
|
||||||
builder.child("iImg") = skImg->makeRawShader(SkSamplingOptions(SkFilterMode::kNearest));
|
builder.child("iImg") = skImg->makeRawShader(SkSamplingOptions(SkFilterMode::kNearest));
|
||||||
|
|
||||||
@ -471,15 +442,6 @@ void ShaderRenderer::drawImage(SkCanvas* canvas,
|
|||||||
}
|
}
|
||||||
|
|
||||||
case doc::ColorMode::INDEXED: {
|
case doc::ColorMode::INDEXED: {
|
||||||
// We use kAlpha_8_SkColorType to access to the index value through the alpha channel
|
|
||||||
auto skImg = SkImage::MakeRasterData(
|
|
||||||
SkImageInfo::Make(srcImage->width(),
|
|
||||||
srcImage->height(),
|
|
||||||
kAlpha_8_SkColorType,
|
|
||||||
kUnpremul_SkAlphaType),
|
|
||||||
skData,
|
|
||||||
srcImage->rowBytes());
|
|
||||||
|
|
||||||
// Use the palette data as an "width x height" image where
|
// Use the palette data as an "width x height" image where
|
||||||
// width=number of palette colors, and height=1
|
// width=number of palette colors, and height=1
|
||||||
const size_t palSize = sizeof(color_t) * m_palette.size();
|
const size_t palSize = sizeof(color_t) * m_palette.size();
|
||||||
|
94
src/app/util/shader_helpers.cpp
Normal file
94
src/app/util/shader_helpers.cpp
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
// Aseprite
|
||||||
|
// Copyright (C) 2024 Igara Studio S.A.
|
||||||
|
//
|
||||||
|
// This program is distributed under the terms of
|
||||||
|
// the End-User License Agreement for Aseprite.
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SK_ENABLE_SKSL
|
||||||
|
|
||||||
|
#include "app/util/shader_helpers.h"
|
||||||
|
|
||||||
|
#include "base/exception.h"
|
||||||
|
#include "doc/image.h"
|
||||||
|
#include "fmt/format.h"
|
||||||
|
|
||||||
|
#include "include/effects/SkRuntimeEffect.h"
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
sk_sp<SkRuntimeEffect> make_shader(const char* code)
|
||||||
|
{
|
||||||
|
auto result = SkRuntimeEffect::MakeForShader(SkString(code));
|
||||||
|
if (!result.errorText.isEmpty()) {
|
||||||
|
std::string error = fmt::format("Error compiling shader.\nError: {}\n",
|
||||||
|
result.errorText.c_str());
|
||||||
|
LOG(ERROR, error.c_str());
|
||||||
|
std::printf("%s", error.c_str());
|
||||||
|
throw base::Exception(error);
|
||||||
|
}
|
||||||
|
return result.effect;
|
||||||
|
}
|
||||||
|
|
||||||
|
SkImageInfo get_skimageinfo_for_docimage(const doc::Image* img)
|
||||||
|
{
|
||||||
|
switch (img->colorMode()) {
|
||||||
|
|
||||||
|
case doc::ColorMode::RGB:
|
||||||
|
return SkImageInfo::Make(img->width(),
|
||||||
|
img->height(),
|
||||||
|
kRGBA_8888_SkColorType,
|
||||||
|
kUnpremul_SkAlphaType);
|
||||||
|
|
||||||
|
case doc::ColorMode::GRAYSCALE:
|
||||||
|
// We use kR8G8_unorm_SkColorType to access gray and alpha
|
||||||
|
return SkImageInfo::Make(img->width(),
|
||||||
|
img->height(),
|
||||||
|
kR8G8_unorm_SkColorType,
|
||||||
|
kOpaque_SkAlphaType);
|
||||||
|
|
||||||
|
case doc::ColorMode::INDEXED: {
|
||||||
|
// We use kAlpha_8_SkColorType to access to the index value through the alpha channel
|
||||||
|
return SkImageInfo::Make(img->width(),
|
||||||
|
img->height(),
|
||||||
|
kAlpha_8_SkColorType,
|
||||||
|
kUnpremul_SkAlphaType);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SkImageInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
sk_sp<SkImage> make_skimage_for_docimage(const doc::Image* img)
|
||||||
|
{
|
||||||
|
switch (img->colorMode()) {
|
||||||
|
case doc::ColorMode::RGB:
|
||||||
|
case doc::ColorMode::GRAYSCALE:
|
||||||
|
case doc::ColorMode::INDEXED: {
|
||||||
|
auto skData = SkData::MakeWithoutCopy(
|
||||||
|
(const void*)img->getPixelAddress(0, 0),
|
||||||
|
img->rowBytes() * img->height());
|
||||||
|
|
||||||
|
return SkImage::MakeRasterData(
|
||||||
|
get_skimageinfo_for_docimage(img),
|
||||||
|
skData,
|
||||||
|
img->rowBytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<SkCanvas> make_skcanvas_for_docimage(const doc::Image* img)
|
||||||
|
{
|
||||||
|
return SkCanvas::MakeRasterDirect(
|
||||||
|
get_skimageinfo_for_docimage(img),
|
||||||
|
(void*)img->getPixelAddress(0, 0),
|
||||||
|
img->rowBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace app
|
||||||
|
|
||||||
|
#endif // SK_ENABLE_SKSL
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2022 Igara Studio S.A.
|
// Copyright (C) 2022-2024 Igara Studio S.A.
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
// the End-User License Agreement for Aseprite.
|
// the End-User License Agreement for Aseprite.
|
||||||
@ -8,18 +8,32 @@
|
|||||||
#define APP_UTIL_SHADER_HELPERS_H_INCLUDED
|
#define APP_UTIL_SHADER_HELPERS_H_INCLUDED
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#if SK_ENABLE_SKSL
|
#if LAF_SKIA
|
||||||
|
|
||||||
#include "app/color.h"
|
#include "app/color.h"
|
||||||
#include "gfx/color.h"
|
#include "gfx/color.h"
|
||||||
|
|
||||||
|
#include "include/core/SkCanvas.h"
|
||||||
|
#include "include/core/SkImage.h"
|
||||||
#include "include/core/SkM44.h"
|
#include "include/core/SkM44.h"
|
||||||
|
#include "include/core/SkRefCnt.h"
|
||||||
|
|
||||||
// To include kRGB_to_HSL_sksl and kHSL_to_RGB_sksl
|
#if SK_ENABLE_SKSL
|
||||||
#include "src/core/SkRuntimeEffectPriv.h"
|
#include "include/effects/SkRuntimeEffect.h"
|
||||||
|
// To include kRGB_to_HSL_sksl and kHSL_to_RGB_sksl
|
||||||
|
#include "src/core/SkRuntimeEffectPriv.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace doc {
|
||||||
|
class Image;
|
||||||
|
}
|
||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
|
|
||||||
|
#if SK_ENABLE_SKSL
|
||||||
|
|
||||||
// rgb_to_hsl() and hsv_to_hsl() functions by Sam Hocevar licensed
|
// rgb_to_hsl() and hsv_to_hsl() functions by Sam Hocevar licensed
|
||||||
// under WTFPL (https://en.wikipedia.org/wiki/WTFPL)
|
// under WTFPL (https://en.wikipedia.org/wiki/WTFPL)
|
||||||
// Source:
|
// Source:
|
||||||
@ -74,8 +88,16 @@ inline SkV4 appColorHsl_to_SkV4(const app::Color& color) {
|
|||||||
float(color.getAlpha() / 255.0)};
|
float(color.getAlpha() / 255.0)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sk_sp<SkRuntimeEffect> make_shader(const char* code);
|
||||||
|
|
||||||
|
#endif // SK_ENABLE_SKSL
|
||||||
|
|
||||||
|
SkImageInfo get_skimageinfo_for_docimage(const doc::Image* img);
|
||||||
|
sk_sp<SkImage> make_skimage_for_docimage(const doc::Image* img);
|
||||||
|
std::unique_ptr<SkCanvas> make_skcanvas_for_docimage(const doc::Image* img);
|
||||||
|
|
||||||
} // namespace app
|
} // namespace app
|
||||||
|
|
||||||
#endif
|
#endif // LAF_SKIA
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user