mirror of
https://github.com/aseprite/aseprite.git
synced 2025-04-23 17:42:42 +00:00
Merge branch 'main' into beta
This commit is contained in:
commit
56357e68ce
2
laf
2
laf
@ -1 +1 @@
|
|||||||
Subproject commit 1b5834cd52340f14408112b746c8c46a581c3488
|
Subproject commit 946fdf956b8a41a33337c9e1f0046bf4a4471b48
|
@ -157,6 +157,8 @@ set(DATA_OUTPUT_DIR ${CMAKE_BINARY_DIR}/bin/data)
|
|||||||
|
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
|
|
||||||
|
find_package(Git)
|
||||||
|
if(GIT_FOUND)
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
clone_strings
|
clone_strings
|
||||||
GIT_REPOSITORY https://github.com/aseprite/strings.git
|
GIT_REPOSITORY https://github.com/aseprite/strings.git
|
||||||
@ -168,6 +170,9 @@ FetchContent_Declare(
|
|||||||
TEST_COMMAND "")
|
TEST_COMMAND "")
|
||||||
FetchContent_MakeAvailable(clone_strings)
|
FetchContent_MakeAvailable(clone_strings)
|
||||||
add_custom_target(clone_strings DEPENDS clone_strings)
|
add_custom_target(clone_strings DEPENDS clone_strings)
|
||||||
|
else()
|
||||||
|
add_custom_target(clone_strings)
|
||||||
|
endif()
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
# Copy data/ directory target into bin/data/
|
# Copy data/ directory target into bin/data/
|
||||||
@ -182,6 +187,7 @@ foreach(fn ${src_data_files})
|
|||||||
list(APPEND out_data_files ${DATA_OUTPUT_DIR}/${fn})
|
list(APPEND out_data_files ${DATA_OUTPUT_DIR}/${fn})
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
if(GIT_FOUND)
|
||||||
# Copy original en.ini to strings.git/en.ini to keep it updated. We
|
# Copy original en.ini to strings.git/en.ini to keep it updated. We
|
||||||
# have to manually sync the "en.ini" file in the "strings" repo from
|
# have to manually sync the "en.ini" file in the "strings" repo from
|
||||||
# the "aseprite" repo.
|
# the "aseprite" repo.
|
||||||
@ -190,6 +196,7 @@ add_custom_command(
|
|||||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${SOURCE_DATA_DIR}/strings/en.ini ${DATA_OUTPUT_DIR}/strings.git/en.ini
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${SOURCE_DATA_DIR}/strings/en.ini ${DATA_OUTPUT_DIR}/strings.git/en.ini
|
||||||
MAIN_DEPENDENCY ${SOURCE_DATA_DIR}/strings/en.ini)
|
MAIN_DEPENDENCY ${SOURCE_DATA_DIR}/strings/en.ini)
|
||||||
list(APPEND out_data_files ${DATA_OUTPUT_DIR}/strings.git/en.ini)
|
list(APPEND out_data_files ${DATA_OUTPUT_DIR}/strings.git/en.ini)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT ${DATA_OUTPUT_DIR}/README.md
|
OUTPUT ${DATA_OUTPUT_DIR}/README.md
|
||||||
|
@ -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) 2019-2022 Igara Studio S.A.
|
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include "app/app.h"
|
#include "app/app.h"
|
||||||
#include "app/commands/cmd_export_sprite_sheet.h"
|
#include "app/commands/cmd_export_sprite_sheet.h"
|
||||||
|
#include "app/console.h"
|
||||||
#include "app/context.h"
|
#include "app/context.h"
|
||||||
#include "app/context_access.h"
|
#include "app/context_access.h"
|
||||||
#include "app/doc.h"
|
#include "app/doc.h"
|
||||||
@ -141,6 +142,17 @@ ConstraintType constraint_type_from_params(const ExportSpriteSheetParams& params
|
|||||||
|
|
||||||
#endif // ENABLE_UI
|
#endif // ENABLE_UI
|
||||||
|
|
||||||
|
void destroy_doc(Context* ctx, Doc* doc)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
DocDestroyer destroyer(ctx, doc, 500);
|
||||||
|
destroyer.destroyDocument();
|
||||||
|
}
|
||||||
|
catch (const LockedDocException& ex) {
|
||||||
|
Console::showException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Doc* generate_sprite_sheet_from_params(
|
Doc* generate_sprite_sheet_from_params(
|
||||||
DocExporter& exporter,
|
DocExporter& exporter,
|
||||||
Context* ctx,
|
Context* ctx,
|
||||||
@ -500,8 +512,7 @@ public:
|
|||||||
auto ctx = UIContext::instance();
|
auto ctx = UIContext::instance();
|
||||||
ctx->setActiveDocument(m_site.document());
|
ctx->setActiveDocument(m_site.document());
|
||||||
|
|
||||||
DocDestroyer destroyer(ctx, m_spriteSheet.release(), 100);
|
destroy_doc(ctx, m_spriteSheet.release());
|
||||||
destroyer.destroyDocument();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1014,8 +1025,7 @@ private:
|
|||||||
auto ctx = UIContext::instance();
|
auto ctx = UIContext::instance();
|
||||||
ctx->setActiveDocument(m_site.document());
|
ctx->setActiveDocument(m_site.document());
|
||||||
|
|
||||||
DocDestroyer destroyer(ctx, m_spriteSheet.release(), 100);
|
destroy_doc(ctx, m_spriteSheet.release());
|
||||||
destroyer.destroyDocument();
|
|
||||||
m_editor = nullptr;
|
m_editor = nullptr;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -1066,8 +1076,7 @@ private:
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (token.canceled()) {
|
if (token.canceled()) {
|
||||||
DocDestroyer destroyer(&tmpCtx, newDocument, 100);
|
destroy_doc(&tmpCtx, newDocument);
|
||||||
destroyer.destroyDocument();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1090,8 +1099,7 @@ private:
|
|||||||
// old one. IN this case the newDocument contains a back
|
// old one. IN this case the newDocument contains a back
|
||||||
// buffer (ImageBufferPtr) that will be discarded.
|
// buffer (ImageBufferPtr) that will be discarded.
|
||||||
m_executionID != executionID) {
|
m_executionID != executionID) {
|
||||||
DocDestroyer destroyer(context, newDocument, 100);
|
destroy_doc(context, newDocument);
|
||||||
destroyer.destroyDocument();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1137,8 +1145,7 @@ private:
|
|||||||
|
|
||||||
m_spriteSheet->notifyGeneralUpdate();
|
m_spriteSheet->notifyGeneralUpdate();
|
||||||
|
|
||||||
DocDestroyer destroyer(context, newDocument, 100);
|
destroy_doc(context, newDocument);
|
||||||
destroyer.destroyDocument();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
waitGenTaskAndDelete();
|
waitGenTaskAndDelete();
|
||||||
@ -1407,8 +1414,7 @@ void ExportSpriteSheetCommand::onExecute(Context* context)
|
|||||||
newDocument.release();
|
newDocument.release();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
DocDestroyer destroyer(context, newDocument.release(), 100);
|
destroy_doc(context, newDocument.release());
|
||||||
destroyer.destroyDocument();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2019-2022 Igara Studio S.A.
|
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -13,6 +13,7 @@
|
|||||||
#include "app/commands/command.h"
|
#include "app/commands/command.h"
|
||||||
#include "app/commands/commands.h"
|
#include "app/commands/commands.h"
|
||||||
#include "app/commands/new_params.h"
|
#include "app/commands/new_params.h"
|
||||||
|
#include "app/console.h"
|
||||||
#include "app/context.h"
|
#include "app/context.h"
|
||||||
#include "app/context_access.h"
|
#include "app/context_access.h"
|
||||||
#include "app/doc_access.h"
|
#include "app/doc_access.h"
|
||||||
@ -264,9 +265,14 @@ private:
|
|||||||
releaseEditor();
|
releaseEditor();
|
||||||
|
|
||||||
if (m_fileOpened) {
|
if (m_fileOpened) {
|
||||||
DocDestroyer destroyer(m_context, oldDocument, 100);
|
try {
|
||||||
|
DocDestroyer destroyer(m_context, oldDocument, 500);
|
||||||
destroyer.destroyDocument();
|
destroyer.destroyDocument();
|
||||||
}
|
}
|
||||||
|
catch (const LockedDocException& ex) {
|
||||||
|
Console::showException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
captureEditor();
|
captureEditor();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2018-2023 Igara Studio S.A.
|
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -14,11 +14,12 @@
|
|||||||
#include "app/color.h"
|
#include "app/color.h"
|
||||||
#include "app/color_utils.h"
|
#include "app/color_utils.h"
|
||||||
#include "app/commands/command.h"
|
#include "app/commands/command.h"
|
||||||
|
#include "app/console.h"
|
||||||
#include "app/context.h"
|
#include "app/context.h"
|
||||||
#include "app/context_access.h"
|
#include "app/context_access.h"
|
||||||
#include "app/doc.h"
|
#include "app/doc.h"
|
||||||
#include "app/ini_file.h"
|
|
||||||
#include "app/i18n/strings.h"
|
#include "app/i18n/strings.h"
|
||||||
|
#include "app/ini_file.h"
|
||||||
#include "app/modules/gui.h"
|
#include "app/modules/gui.h"
|
||||||
#include "app/tx.h"
|
#include "app/tx.h"
|
||||||
#include "app/ui/color_bar.h"
|
#include "app/ui/color_bar.h"
|
||||||
@ -260,7 +261,7 @@ void MaskByColorCommand::maskPreview(const ContextReader& reader)
|
|||||||
reader.sprite(), image,
|
reader.sprite(), image,
|
||||||
xpos, ypos,
|
xpos, ypos,
|
||||||
m_selMode->selectionMode()));
|
m_selMode->selectionMode()));
|
||||||
{
|
|
||||||
ContextWriter writer(reader);
|
ContextWriter writer(reader);
|
||||||
|
|
||||||
#ifdef SHOW_BOUNDARIES_GEN_PERFORMANCE
|
#ifdef SHOW_BOUNDARIES_GEN_PERFORMANCE
|
||||||
@ -277,7 +278,6 @@ void MaskByColorCommand::maskPreview(const ContextReader& reader)
|
|||||||
update_screen_for_document(writer.document());
|
update_screen_for_document(writer.document());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Command* CommandFactory::createMaskByColorCommand()
|
Command* CommandFactory::createMaskByColorCommand()
|
||||||
{
|
{
|
||||||
|
@ -784,11 +784,16 @@ public:
|
|||||||
m_context->activeDocument() &&
|
m_context->activeDocument() &&
|
||||||
m_context->activeDocument()->sprite() &&
|
m_context->activeDocument()->sprite() &&
|
||||||
m_context->activeDocument()->sprite()->gridBounds() != gridBounds()) {
|
m_context->activeDocument()->sprite()->gridBounds() != gridBounds()) {
|
||||||
ContextWriter writer(m_context);
|
try {
|
||||||
|
ContextWriter writer(m_context, 1000);
|
||||||
Tx tx(writer, Strings::commands_GridSettings(), ModifyDocument);
|
Tx tx(writer, Strings::commands_GridSettings(), ModifyDocument);
|
||||||
tx(new cmd::SetGridBounds(writer.sprite(), gridBounds()));
|
tx(new cmd::SetGridBounds(writer.sprite(), gridBounds()));
|
||||||
tx.commit();
|
tx.commit();
|
||||||
}
|
}
|
||||||
|
catch (const std::exception& ex) {
|
||||||
|
Console::showException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_curPref->show.grid(gridVisible()->isSelected());
|
m_curPref->show.grid(gridVisible()->isSelected());
|
||||||
m_curPref->grid.bounds(gridBounds());
|
m_curPref->grid.bounds(gridBounds());
|
||||||
|
@ -9,31 +9,32 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "app/cmd/add_tileset.h"
|
||||||
#include "app/cmd/assign_color_profile.h"
|
#include "app/cmd/assign_color_profile.h"
|
||||||
#include "app/cmd/convert_color_profile.h"
|
#include "app/cmd/convert_color_profile.h"
|
||||||
#include "app/cmd/add_tileset.h"
|
|
||||||
#include "app/cmd/remove_tileset.h"
|
#include "app/cmd/remove_tileset.h"
|
||||||
#include "app/cmd/set_pixel_ratio.h"
|
#include "app/cmd/set_pixel_ratio.h"
|
||||||
#include "app/cmd/set_user_data.h"
|
#include "app/cmd/set_user_data.h"
|
||||||
#include "app/color.h"
|
#include "app/color.h"
|
||||||
#include "app/commands/command.h"
|
#include "app/commands/command.h"
|
||||||
|
#include "app/console.h"
|
||||||
#include "app/context_access.h"
|
#include "app/context_access.h"
|
||||||
#include "app/doc_api.h"
|
#include "app/doc_api.h"
|
||||||
#include "app/i18n/strings.h"
|
#include "app/i18n/strings.h"
|
||||||
#include "app/modules/gui.h"
|
#include "app/modules/gui.h"
|
||||||
#include "app/pref/preferences.h"
|
#include "app/pref/preferences.h"
|
||||||
#include "app/util/tileset_utils.h"
|
|
||||||
#include "app/tx.h"
|
#include "app/tx.h"
|
||||||
#include "app/ui/color_button.h"
|
#include "app/ui/color_button.h"
|
||||||
#include "app/ui/user_data_view.h"
|
|
||||||
#include "app/ui/skin/skin_theme.h"
|
#include "app/ui/skin/skin_theme.h"
|
||||||
|
#include "app/ui/user_data_view.h"
|
||||||
#include "app/util/pixel_ratio.h"
|
#include "app/util/pixel_ratio.h"
|
||||||
|
#include "app/util/tileset_utils.h"
|
||||||
#include "base/mem_utils.h"
|
#include "base/mem_utils.h"
|
||||||
#include "doc/image.h"
|
#include "doc/image.h"
|
||||||
#include "doc/palette.h"
|
#include "doc/palette.h"
|
||||||
#include "doc/sprite.h"
|
#include "doc/sprite.h"
|
||||||
#include "doc/user_data.h"
|
|
||||||
#include "doc/tilesets.h"
|
#include "doc/tilesets.h"
|
||||||
|
#include "doc/user_data.h"
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
#include "os/color_space.h"
|
#include "os/color_space.h"
|
||||||
#include "os/system.h"
|
#include "os/system.h"
|
||||||
@ -352,12 +353,17 @@ void SpritePropertiesCommand::onExecute(Context* context)
|
|||||||
[&](){
|
[&](){
|
||||||
selectedColorProfile = window.colorProfile()->getSelectedItemIndex();
|
selectedColorProfile = window.colorProfile()->getSelectedItemIndex();
|
||||||
|
|
||||||
|
try {
|
||||||
ContextWriter writer(context);
|
ContextWriter writer(context);
|
||||||
Sprite* sprite(writer.sprite());
|
Sprite* sprite(writer.sprite());
|
||||||
Tx tx(writer, Strings::sprite_properties_assign_color_profile());
|
Tx tx(writer, Strings::sprite_properties_assign_color_profile());
|
||||||
tx(new cmd::AssignColorProfile(
|
tx(new cmd::AssignColorProfile(
|
||||||
sprite, colorSpaces[selectedColorProfile]->gfxColorSpace()));
|
sprite, colorSpaces[selectedColorProfile]->gfxColorSpace()));
|
||||||
tx.commit();
|
tx.commit();
|
||||||
|
}
|
||||||
|
catch (const base::Exception& e) {
|
||||||
|
Console::showException(e);
|
||||||
|
}
|
||||||
|
|
||||||
updateButtons();
|
updateButtons();
|
||||||
});
|
});
|
||||||
@ -365,12 +371,17 @@ void SpritePropertiesCommand::onExecute(Context* context)
|
|||||||
[&](){
|
[&](){
|
||||||
selectedColorProfile = window.colorProfile()->getSelectedItemIndex();
|
selectedColorProfile = window.colorProfile()->getSelectedItemIndex();
|
||||||
|
|
||||||
|
try {
|
||||||
ContextWriter writer(context);
|
ContextWriter writer(context);
|
||||||
Sprite* sprite(writer.sprite());
|
Sprite* sprite(writer.sprite());
|
||||||
Tx tx(writer, Strings::sprite_properties_convert_color_profile());
|
Tx tx(writer, Strings::sprite_properties_convert_color_profile());
|
||||||
tx(new cmd::ConvertColorProfile(
|
tx(new cmd::ConvertColorProfile(
|
||||||
sprite, colorSpaces[selectedColorProfile]->gfxColorSpace()));
|
sprite, colorSpaces[selectedColorProfile]->gfxColorSpace()));
|
||||||
tx.commit();
|
tx.commit();
|
||||||
|
}
|
||||||
|
catch (const base::Exception& e) {
|
||||||
|
Console::showException(e);
|
||||||
|
}
|
||||||
|
|
||||||
updateButtons();
|
updateButtons();
|
||||||
});
|
});
|
||||||
|
@ -88,19 +88,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;
|
||||||
@ -417,21 +407,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 = SkImages::RasterFromData(
|
|
||||||
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));
|
||||||
@ -444,15 +424,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 = SkImages::RasterFromData(
|
|
||||||
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));
|
||||||
|
|
||||||
@ -472,15 +443,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 = SkImages::RasterFromData(
|
|
||||||
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();
|
||||||
|
@ -655,35 +655,22 @@ bool ColorSelector::buildEffects()
|
|||||||
|
|
||||||
if (!m_mainEffect) {
|
if (!m_mainEffect) {
|
||||||
if (const char* code = getMainAreaShader())
|
if (const char* code = getMainAreaShader())
|
||||||
m_mainEffect = buildEffect(code);
|
m_mainEffect = make_shader(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_bottomEffect) {
|
if (!m_bottomEffect) {
|
||||||
if (const char* code = getBottomBarShader())
|
if (const char* code = getBottomBarShader())
|
||||||
m_bottomEffect = buildEffect(code);
|
m_bottomEffect = make_shader(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_alphaEffect) {
|
if (!m_alphaEffect) {
|
||||||
if (const char* code = getAlphaBarShader())
|
if (const char* code = getAlphaBarShader())
|
||||||
m_alphaEffect = buildEffect(code);
|
m_alphaEffect = make_shader(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (m_mainEffect && m_bottomEffect && m_alphaEffect);
|
return (m_mainEffect && m_bottomEffect && m_alphaEffect);
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ColorSelector::resetBottomEffect()
|
void ColorSelector::resetBottomEffect()
|
||||||
{
|
{
|
||||||
m_bottomEffect.reset();
|
m_bottomEffect.reset();
|
||||||
|
@ -121,7 +121,6 @@ namespace app {
|
|||||||
#if SK_ENABLE_SKSL
|
#if SK_ENABLE_SKSL
|
||||||
static const char* getAlphaBarShader();
|
static const char* getAlphaBarShader();
|
||||||
bool buildEffects();
|
bool buildEffects();
|
||||||
sk_sp<SkRuntimeEffect> buildEffect(const char* code);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Internal flag used to lock the modification of m_color.
|
// Internal flag used to lock the modification of m_color.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2019-2022 Igara Studio S.A.
|
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||||
// Copyright (C) 2017-2018 David Capello
|
// Copyright (C) 2017-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -14,6 +14,7 @@
|
|||||||
#include "app/cmd/set_mask_position.h"
|
#include "app/cmd/set_mask_position.h"
|
||||||
#include "app/commands/command.h"
|
#include "app/commands/command.h"
|
||||||
#include "app/commands/commands.h"
|
#include "app/commands/commands.h"
|
||||||
|
#include "app/console.h"
|
||||||
#include "app/context_access.h"
|
#include "app/context_access.h"
|
||||||
#include "app/tx.h"
|
#include "app/tx.h"
|
||||||
#include "app/ui/editor/editor.h"
|
#include "app/ui/editor/editor.h"
|
||||||
@ -80,12 +81,15 @@ EditorState::LeaveAction MovingSelectionState::onLeaveState(Editor* editor, Edit
|
|||||||
doc->generateMaskBoundaries();
|
doc->generateMaskBoundaries();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
{
|
try {
|
||||||
ContextWriter writer(UIContext::instance(), 1000);
|
ContextWriter writer(UIContext::instance(), 1000);
|
||||||
Tx tx(writer, "Move Selection Edges", DoesntModifyDocument);
|
Tx tx(writer, "Move Selection Edges", DoesntModifyDocument);
|
||||||
tx(new cmd::SetMaskPosition(doc, newOrigin));
|
tx(new cmd::SetMaskPosition(doc, newOrigin));
|
||||||
tx.commit();
|
tx.commit();
|
||||||
}
|
}
|
||||||
|
catch (const base::Exception& e) {
|
||||||
|
Console::showException(e);
|
||||||
|
}
|
||||||
doc->resetTransformation();
|
doc->resetTransformation();
|
||||||
}
|
}
|
||||||
doc->notifyGeneralUpdate();
|
doc->notifyGeneralUpdate();
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
|
// Copyright (C) 2024 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -29,6 +30,8 @@ namespace app {
|
|||||||
virtual bool onCanPaste(Context* ctx) = 0;
|
virtual bool onCanPaste(Context* ctx) = 0;
|
||||||
virtual bool onCanClear(Context* ctx) = 0;
|
virtual bool onCanClear(Context* ctx) = 0;
|
||||||
|
|
||||||
|
// These commands are executed from Context::executeCommand()
|
||||||
|
// which catch any exception that is thrown.
|
||||||
virtual bool onCut(Context* ctx) = 0;
|
virtual bool onCut(Context* ctx) = 0;
|
||||||
virtual bool onCopy(Context* ctx) = 0;
|
virtual bool onCopy(Context* ctx) = 0;
|
||||||
virtual bool onPaste(Context* ctx) = 0;
|
virtual bool onPaste(Context* ctx) = 0;
|
||||||
|
@ -1347,7 +1347,7 @@ bool Timeline::onProcessMessage(Message* msg)
|
|||||||
else if (mouseMsg->left()) {
|
else if (mouseMsg->left()) {
|
||||||
Command* command = Commands::instance()
|
Command* command = Commands::instance()
|
||||||
->byId(CommandId::FrameTagProperties());
|
->byId(CommandId::FrameTagProperties());
|
||||||
UIContext::instance()->executeCommand(command, params);
|
m_context->executeCommand(command, params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1389,13 +1389,18 @@ bool Timeline::onProcessMessage(Message* msg)
|
|||||||
if (tag) {
|
if (tag) {
|
||||||
if ((m_state == STATE_RESIZING_TAG_LEFT && tag->fromFrame() != m_resizeTagData.from) ||
|
if ((m_state == STATE_RESIZING_TAG_LEFT && tag->fromFrame() != m_resizeTagData.from) ||
|
||||||
(m_state == STATE_RESIZING_TAG_RIGHT && tag->toFrame() != m_resizeTagData.to)) {
|
(m_state == STATE_RESIZING_TAG_RIGHT && tag->toFrame() != m_resizeTagData.to)) {
|
||||||
ContextWriter writer(UIContext::instance());
|
try {
|
||||||
|
ContextWriter writer(m_context);
|
||||||
Tx tx(writer, Strings::commands_FrameTagProperties());
|
Tx tx(writer, Strings::commands_FrameTagProperties());
|
||||||
tx(new cmd::SetTagRange(
|
tx(new cmd::SetTagRange(
|
||||||
tag,
|
tag,
|
||||||
(m_state == STATE_RESIZING_TAG_LEFT ? m_resizeTagData.from: tag->fromFrame()),
|
(m_state == STATE_RESIZING_TAG_LEFT ? m_resizeTagData.from: tag->fromFrame()),
|
||||||
(m_state == STATE_RESIZING_TAG_RIGHT ? m_resizeTagData.to: tag->toFrame())));
|
(m_state == STATE_RESIZING_TAG_RIGHT ? m_resizeTagData.to: tag->toFrame())));
|
||||||
tx.commit();
|
tx.commit();
|
||||||
|
}
|
||||||
|
catch (const base::Exception& e) {
|
||||||
|
Console::showException(e);
|
||||||
|
}
|
||||||
|
|
||||||
regenerateRows();
|
regenerateRows();
|
||||||
}
|
}
|
||||||
@ -1431,7 +1436,7 @@ bool Timeline::onProcessMessage(Message* msg)
|
|||||||
Command* command = Commands::instance()
|
Command* command = Commands::instance()
|
||||||
->byId(CommandId::LayerProperties());
|
->byId(CommandId::LayerProperties());
|
||||||
|
|
||||||
UIContext::instance()->executeCommand(command);
|
m_context->executeCommand(command);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1441,7 +1446,7 @@ bool Timeline::onProcessMessage(Message* msg)
|
|||||||
Params params;
|
Params params;
|
||||||
params.set("frame", "current");
|
params.set("frame", "current");
|
||||||
|
|
||||||
UIContext::instance()->executeCommand(command, params);
|
m_context->executeCommand(command, params);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1449,7 +1454,7 @@ bool Timeline::onProcessMessage(Message* msg)
|
|||||||
Command* command = Commands::instance()
|
Command* command = Commands::instance()
|
||||||
->byId(CommandId::CelProperties());
|
->byId(CommandId::CelProperties());
|
||||||
|
|
||||||
UIContext::instance()->executeCommand(command);
|
m_context->executeCommand(command);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
101
src/app/util/shader_helpers.cpp
Normal file
101
src/app/util/shader_helpers.cpp
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
// 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"
|
||||||
|
#include "src/core/SkRuntimeEffectPriv.h"
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
sk_sp<SkRuntimeEffect> make_shader(const char* code)
|
||||||
|
{
|
||||||
|
SkRuntimeEffect::Options options;
|
||||||
|
|
||||||
|
// Allow usage of private functions like $hsl_to_rgb without a SkSL
|
||||||
|
// compilation error at runtime.
|
||||||
|
SkRuntimeEffectPriv::AllowPrivateAccess(&options);
|
||||||
|
|
||||||
|
auto result = SkRuntimeEffect::MakeForShader(SkString(code), options);
|
||||||
|
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 SkImages::RasterFromData(
|
||||||
|
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,15 +8,30 @@
|
|||||||
#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"
|
||||||
|
|
||||||
|
#if SK_ENABLE_SKSL
|
||||||
|
#include "include/effects/SkRuntimeEffect.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:
|
||||||
@ -71,8 +86,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
|
||||||
|
2
src/clip
2
src/clip
@ -1 +1 @@
|
|||||||
Subproject commit 94693e2414a2c69a8ca16f065240c80a94cc6221
|
Subproject commit 835cd0f7e7a964bb969482117856bc56a0ac12bf
|
Loading…
x
Reference in New Issue
Block a user