mirror of
https://github.com/aseprite/aseprite.git
synced 2025-04-17 08:43:11 +00:00
Fix non-normal blend modes when the backdrop is transparent (fix #1096)
This commit is contained in:
parent
cc62e9ed59
commit
f53544842c
@ -166,6 +166,7 @@
|
||||
</section>
|
||||
<section id="experimental" text="Experimental">
|
||||
<option id="new_render_engine" type="bool" default="true" />
|
||||
<option id="new_blend" type="bool" default="true" />
|
||||
<option id="use_native_clipboard" type="bool" default="true" />
|
||||
<option id="use_native_file_dialog" type="bool" default="false" />
|
||||
<option id="one_finger_as_mouse_movement" type="bool" default="true" />
|
||||
|
@ -1082,6 +1082,7 @@ disable_extension = &Disable
|
||||
uninstall_extension = &Uninstall
|
||||
open_extension_folder = Open &Folder
|
||||
user_interface = User Interface
|
||||
new_blend = New layer blending method
|
||||
new_render_engine = New render engine for sprite editor
|
||||
native_clipboard = Use native clipboard
|
||||
native_file_dialog = Use native file dialog
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2018 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2018-2019 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2001-2018 David Capello -->
|
||||
<gui>
|
||||
<window id="options" text="@.title">
|
||||
@ -362,8 +362,8 @@
|
||||
<check id="gif_options_alert" text="@.gif_options_alert"
|
||||
pref="gif.show_alert" />
|
||||
<check id="jpeg_options_alert" text="@.jpeg_options_alert"
|
||||
pref="jpeg.show_alert" />
|
||||
<check id="svg_options_alert" text="@.svg_options_alert"
|
||||
pref="jpeg.show_alert" />
|
||||
<check id="svg_options_alert" text="@.svg_options_alert"
|
||||
pref="svg.show_alert" />
|
||||
<check id="advanced_mode_alert" text="@.advanced_mode_alert"
|
||||
pref="advanced_mode.show_alert" />
|
||||
@ -414,6 +414,11 @@
|
||||
pref="experimental.new_render_engine" />
|
||||
<link text="(#1671)" url="https://github.com/aseprite/aseprite/issues/1671" />
|
||||
</hbox>
|
||||
<hbox>
|
||||
<check text="@.new_blend"
|
||||
pref="experimental.new_blend" />
|
||||
<link text="(#1096)" url="https://github.com/aseprite/aseprite/issues/1096" />
|
||||
</hbox>
|
||||
<check id="native_clipboard" text="@.native_clipboard" />
|
||||
<check id="native_file_dialog" text="@.native_file_dialog" />
|
||||
<check id="one_finger_as_mouse_movement"
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -31,9 +32,11 @@ namespace app {
|
||||
namespace cmd {
|
||||
|
||||
FlattenLayers::FlattenLayers(doc::Sprite* sprite,
|
||||
const doc::SelectedLayers& layers0)
|
||||
const doc::SelectedLayers& layers0,
|
||||
const bool newBlend)
|
||||
: WithSprite(sprite)
|
||||
{
|
||||
m_newBlendMethod = newBlend;
|
||||
doc::SelectedLayers layers(layers0);
|
||||
layers.removeChildrenIfParentIsSelected();
|
||||
|
||||
@ -87,6 +90,7 @@ void FlattenLayers::onExecute()
|
||||
}
|
||||
|
||||
render::Render render;
|
||||
render.setNewBlend(m_newBlendMethod);
|
||||
render.setBgType(render::BgType::NONE);
|
||||
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -20,13 +21,15 @@ namespace cmd {
|
||||
, public WithSprite {
|
||||
public:
|
||||
FlattenLayers(doc::Sprite* sprite,
|
||||
const doc::SelectedLayers& layers);
|
||||
const doc::SelectedLayers& layers,
|
||||
const bool newBlendMethod);
|
||||
|
||||
protected:
|
||||
void onExecute() override;
|
||||
|
||||
private:
|
||||
ObjectIds m_layerIds;
|
||||
bool m_newBlendMethod;
|
||||
};
|
||||
|
||||
} // namespace cmd
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -88,7 +89,8 @@ void ColorPicker::pickColor(const Site& site,
|
||||
m_color = app::Color::fromImage(
|
||||
sprite->pixelFormat(),
|
||||
render::get_sprite_pixel(sprite, pos.x, pos.y,
|
||||
site.frame(), proj));
|
||||
site.frame(), proj,
|
||||
Preferences::instance().experimental.newBlend()));
|
||||
|
||||
doc::CelList cels;
|
||||
sprite->pickCels(pos.x, pos.y, site.frame(), 128,
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -78,7 +79,8 @@ public:
|
||||
const doc::PixelFormat pixelFormat,
|
||||
const render::DitheringAlgorithm ditheringAlgorithm,
|
||||
const render::DitheringMatrix& ditheringMatrix,
|
||||
const gfx::Point& pos)
|
||||
const gfx::Point& pos,
|
||||
const bool newBlend)
|
||||
: m_image(dstImage)
|
||||
, m_pos(pos)
|
||||
, m_running(true)
|
||||
@ -89,11 +91,13 @@ public:
|
||||
sprite, frame,
|
||||
pixelFormat,
|
||||
ditheringAlgorithm,
|
||||
ditheringMatrix]() { // Copy the matrix
|
||||
ditheringMatrix,
|
||||
newBlend]() { // Copy the matrix
|
||||
run(sprite, frame,
|
||||
pixelFormat,
|
||||
ditheringAlgorithm,
|
||||
ditheringMatrix);
|
||||
ditheringMatrix,
|
||||
newBlend);
|
||||
})
|
||||
{
|
||||
}
|
||||
@ -116,13 +120,15 @@ private:
|
||||
const doc::frame_t frame,
|
||||
const doc::PixelFormat pixelFormat,
|
||||
const render::DitheringAlgorithm ditheringAlgorithm,
|
||||
const render::DitheringMatrix& ditheringMatrix) {
|
||||
const render::DitheringMatrix& ditheringMatrix,
|
||||
const bool newBlend) {
|
||||
doc::ImageRef tmp(
|
||||
Image::create(sprite->pixelFormat(),
|
||||
m_image->width(),
|
||||
m_image->height()));
|
||||
|
||||
render::Render render;
|
||||
render.setNewBlend(newBlend);
|
||||
render.renderSprite(
|
||||
tmp.get(), sprite, frame,
|
||||
gfx::Clip(0, 0,
|
||||
@ -291,7 +297,8 @@ private:
|
||||
dstPixelFormat,
|
||||
ditheringAlgorithm(),
|
||||
ditheringMatrix(),
|
||||
visibleBounds.origin()));
|
||||
visibleBounds.origin(),
|
||||
Preferences::instance().experimental.newBlend()));
|
||||
|
||||
m_timer.start();
|
||||
}
|
||||
@ -467,15 +474,16 @@ void ChangePixelFormatCommand::onExecute(Context* context)
|
||||
{
|
||||
const ContextReader reader(context);
|
||||
SpriteJob job(reader, "Color Mode Change");
|
||||
const bool newBlend = Preferences::instance().experimental.newBlend();
|
||||
job.startJobWithCallback(
|
||||
[this, &job, flatten] {
|
||||
[this, &job, flatten, newBlend] {
|
||||
Sprite* sprite(job.sprite());
|
||||
|
||||
if (flatten) {
|
||||
SelectedLayers selLayers;
|
||||
for (auto layer : sprite->root()->layers())
|
||||
selLayers.insert(layer);
|
||||
job.tx()(new cmd::FlattenLayers(sprite, selLayers));
|
||||
job.tx()(new cmd::FlattenLayers(sprite, selLayers, newBlend));
|
||||
}
|
||||
|
||||
job.tx()(
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -111,12 +112,14 @@ void ColorQuantizationCommand::onExecute(Context* context)
|
||||
|
||||
ContextReader reader(context);
|
||||
SpriteJob job(reader, "Color Quantization");
|
||||
const bool newBlend = Preferences::instance().experimental.newBlend();
|
||||
job.startJobWithCallback(
|
||||
[sprite, withAlpha, &tmpPalette, &job]{
|
||||
[sprite, withAlpha, &tmpPalette, &job, newBlend]{
|
||||
render::create_palette_from_sprite(
|
||||
sprite, 0, sprite->lastFrame(),
|
||||
withAlpha, &tmpPalette,
|
||||
&job); // SpriteJob is a render::TaskDelegate
|
||||
&job,
|
||||
newBlend); // SpriteJob is a render::TaskDelegate
|
||||
});
|
||||
job.waitJob();
|
||||
if (job.isCanceled())
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -82,8 +83,10 @@ void FlattenLayersCommand::onExecute(Context* context)
|
||||
range.selectLayer(layer);
|
||||
}
|
||||
}
|
||||
|
||||
tx(new cmd::FlattenLayers(sprite, range.selectedLayers()));
|
||||
const bool newBlend = Preferences::instance().experimental.newBlend();
|
||||
tx(new cmd::FlattenLayers(sprite,
|
||||
range.selectedLayers(),
|
||||
newBlend));
|
||||
tx.commit();
|
||||
}
|
||||
|
||||
|
@ -367,6 +367,7 @@ void ImportSpriteSheetCommand::onExecute(Context* context)
|
||||
Sprite* sprite = document->sprite();
|
||||
frame_t currentFrame = context->activeSite().frame();
|
||||
render::Render render;
|
||||
render.setNewBlend(Preferences::instance().experimental.newBlend());
|
||||
|
||||
// Each sprite in the sheet
|
||||
std::vector<gfx::Rect> tileRects;
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -137,7 +138,8 @@ void NewBrushCommand::onQuickboxCancel(Editor* editor)
|
||||
|
||||
void NewBrushCommand::createBrush(const Site& site, const Mask* mask)
|
||||
{
|
||||
doc::ImageRef image(new_image_from_mask(site, mask));
|
||||
doc::ImageRef image(new_image_from_mask(site, mask,
|
||||
Preferences::instance().experimental.newBlend()));
|
||||
if (!image)
|
||||
return;
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -254,6 +255,7 @@ void NewLayerCommand::onExecute(Context* context)
|
||||
if (pasteDoc && layer->isImage()) {
|
||||
Sprite* pasteSpr = pasteDoc->sprite();
|
||||
render::Render render;
|
||||
render.setNewBlend(true);
|
||||
render.setBgType(render::BgType::NONE);
|
||||
|
||||
// Add more frames at the end
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2019 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -55,7 +55,7 @@ void NewSpriteFromSelectionCommand::onExecute(Context* context)
|
||||
const Sprite* sprite = site.sprite();
|
||||
const Mask* mask = doc->mask();
|
||||
ImageRef image(
|
||||
new_image_from_mask(site, mask));
|
||||
new_image_from_mask(site, mask, true));
|
||||
if (!image)
|
||||
return;
|
||||
|
||||
|
@ -451,7 +451,8 @@ Doc* Doc::duplicate(DuplicateType type) const
|
||||
(spriteCopy,
|
||||
sourceSprite->root(),
|
||||
gfx::Rect(0, 0, sourceSprite->width(), sourceSprite->height()),
|
||||
frame_t(0), sourceSprite->lastFrame());
|
||||
frame_t(0), sourceSprite->lastFrame(),
|
||||
Preferences::instance().experimental.newBlend());
|
||||
|
||||
// Add and select the new flat layer
|
||||
spriteCopy->root()->addLayer(flatLayer);
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2019 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -1018,6 +1018,8 @@ void DocExporter::renderSample(const Sample& sample, doc::Image* dst, int x, int
|
||||
*sample.selectedLayers());
|
||||
|
||||
render::Render render;
|
||||
render.setNewBlend(Preferences::instance().experimental.newBlend());
|
||||
|
||||
if (extrude) {
|
||||
const gfx::Rect& trim = sample.trimmedBounds();
|
||||
|
||||
|
@ -730,6 +730,8 @@ void FileOp::operate(IFileOpProgress* progress)
|
||||
|
||||
// For each frame in the sprite.
|
||||
render::Render render;
|
||||
render.setNewBlend(Preferences::instance().experimental.newBlend());
|
||||
|
||||
frame_t outputFrame = 0;
|
||||
for (frame_t frame : m_roi.selectedFrames()) {
|
||||
// Draw the "frame" in "m_seq.image"
|
||||
@ -891,7 +893,7 @@ void FileOp::postLoad()
|
||||
base::SharedPtr<Palette> palette(
|
||||
render::create_palette_from_sprite(
|
||||
sprite, frame_t(0), sprite->lastFrame(), true,
|
||||
nullptr, nullptr));
|
||||
nullptr, nullptr, Preferences::instance().experimental.newBlend()));
|
||||
|
||||
sprite->resetPalettes();
|
||||
sprite->setPalette(palette.get(), false);
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2019 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -14,6 +14,7 @@
|
||||
#include "app/file/file_format.h"
|
||||
#include "app/file/format_options.h"
|
||||
#include "app/modules/palettes.h"
|
||||
#include "app/pref/preferences.h"
|
||||
#include "base/file_handle.h"
|
||||
#include "doc/doc.h"
|
||||
#include "flic/flic.h"
|
||||
@ -217,6 +218,7 @@ bool FliFormat::onSave(FileOp* fop)
|
||||
// Create the bitmaps
|
||||
ImageRef bmp(Image::create(IMAGE_INDEXED, sprite->width(), sprite->height()));
|
||||
render::Render render;
|
||||
render.setNewBlend(Preferences::instance().experimental.newBlend());
|
||||
|
||||
// Write frame by frame
|
||||
flic::Frame fliFrame;
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2019 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -1333,6 +1333,8 @@ private:
|
||||
|
||||
void renderFrame(frame_t frame, Image* dst) {
|
||||
render::Render render;
|
||||
render.setNewBlend(Preferences::instance().experimental.newBlend());
|
||||
|
||||
render.setBgType(render::BgType::NONE);
|
||||
clear_image(dst, m_clearColor);
|
||||
render.renderSprite(dst, m_sprite, frame);
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2019 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -15,6 +15,7 @@
|
||||
#include "app/file/file.h"
|
||||
#include "app/file/file_format.h"
|
||||
#include "app/file/format_options.h"
|
||||
#include "app/pref/preferences.h"
|
||||
#include "base/cfile.h"
|
||||
#include "base/file_handle.h"
|
||||
#include "doc/doc.h"
|
||||
@ -284,6 +285,8 @@ bool IcoFormat::onSave(FileOp* fop)
|
||||
sprite->height()));
|
||||
|
||||
render::Render render;
|
||||
render.setNewBlend(Preferences::instance().experimental.newBlend());
|
||||
|
||||
for (n=frame_t(0); n<num; ++n) {
|
||||
render.renderSprite(image.get(), sprite, n);
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -26,10 +27,12 @@ static bool has_cels(const Layer* layer, frame_t frame);
|
||||
|
||||
LayerImage* create_flatten_layer_copy(Sprite* dstSprite, const Layer* srcLayer,
|
||||
const gfx::Rect& bounds,
|
||||
frame_t frmin, frame_t frmax)
|
||||
frame_t frmin, frame_t frmax,
|
||||
const bool newBlend)
|
||||
{
|
||||
std::unique_ptr<LayerImage> flatLayer(new LayerImage(dstSprite));
|
||||
render::Render render;
|
||||
render.setNewBlend(newBlend);
|
||||
|
||||
for (frame_t frame=frmin; frame<=frmax; ++frame) {
|
||||
// Does this frame have cels to render?
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -28,7 +29,8 @@ namespace app {
|
||||
// sprite.
|
||||
LayerImage* create_flatten_layer_copy(Sprite* dstSprite, const Layer* srcLayer,
|
||||
const gfx::Rect& bounds,
|
||||
frame_t frmin, frame_t frmax);
|
||||
frame_t frmin, frame_t frmax,
|
||||
const bool newBlend);
|
||||
|
||||
} // namespace app
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2019 Igara Studio S.A.
|
||||
// Copyright (C) 2015-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -177,6 +177,7 @@ int Image_drawSprite(lua_State* L)
|
||||
// the source image without undo information.
|
||||
if (obj->cel(L) == nullptr) {
|
||||
render::Render render;
|
||||
render.setNewBlend(true);
|
||||
render.renderSprite(
|
||||
dst, sprite, frame,
|
||||
gfx::Clip(pos.x, pos.y,
|
||||
@ -189,6 +190,7 @@ int Image_drawSprite(lua_State* L)
|
||||
|
||||
ImageRef tmp(Image::createCopy(dst));
|
||||
render::Render render;
|
||||
render.setNewBlend(true);
|
||||
render.renderSprite(
|
||||
tmp.get(), sprite, frame,
|
||||
gfx::Clip(pos.x, pos.y,
|
||||
|
@ -589,6 +589,7 @@ void Editor::drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& sprite
|
||||
rendered.reset(Image::create(IMAGE_RGB, rc2.w, rc2.h,
|
||||
m_renderEngine->getRenderImageBuffer()));
|
||||
|
||||
m_renderEngine->setNewBlendMethod(Preferences::instance().experimental.newBlend());
|
||||
m_renderEngine->setRefLayersVisiblity(true);
|
||||
m_renderEngine->setSelectedLayer(m_layer);
|
||||
if (m_flags & Editor::kUseNonactiveLayersOpacityWhenEnabled)
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -21,6 +22,7 @@ static doc::ImageBufferPtr g_renderBuffer;
|
||||
EditorRender::EditorRender()
|
||||
: m_render(new render::Render)
|
||||
{
|
||||
m_render->setNewBlend(Preferences::instance().experimental.newBlend());
|
||||
}
|
||||
|
||||
EditorRender::~EditorRender()
|
||||
@ -38,6 +40,11 @@ void EditorRender::setNonactiveLayersOpacity(const int opacity)
|
||||
m_render->setNonactiveLayersOpacity(opacity);
|
||||
}
|
||||
|
||||
void EditorRender::setNewBlendMethod(const bool newBlend)
|
||||
{
|
||||
m_render->setNewBlend(newBlend);
|
||||
}
|
||||
|
||||
void EditorRender::setProjection(const render::Projection& projection)
|
||||
{
|
||||
m_render->setProjection(projection);
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -41,6 +42,7 @@ namespace app {
|
||||
|
||||
void setRefLayersVisiblity(const bool visible);
|
||||
void setNonactiveLayersOpacity(const int opacity);
|
||||
void setNewBlendMethod(const bool newBlend);
|
||||
|
||||
void setProjection(const render::Projection& projection);
|
||||
|
||||
|
@ -685,11 +685,13 @@ void PixelsMovement::drawImage(doc::Image* dst, const gfx::Point& pt, bool rende
|
||||
dst->setMaskColor(m_sprite->transparentColor());
|
||||
dst->clear(dst->maskColor());
|
||||
|
||||
if (renderOriginalLayer)
|
||||
render::Render().renderLayer(
|
||||
if (renderOriginalLayer) {
|
||||
render::Render render;
|
||||
render.renderLayer(
|
||||
dst, m_layer, m_site.frame(),
|
||||
gfx::Clip(bounds.x-pt.x, bounds.y-pt.y, bounds),
|
||||
BlendMode::SRC);
|
||||
}
|
||||
|
||||
color_t maskColor = m_maskColor;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2019 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -720,7 +720,8 @@ void StandbyState::transformSelection(Editor* editor, MouseMessage* msg, HandleT
|
||||
editor->brushPreview().hide();
|
||||
|
||||
EditorCustomizationDelegate* customization = editor->getCustomizationDelegate();
|
||||
std::unique_ptr<Image> tmpImage(new_image_from_mask(editor->getSite()));
|
||||
std::unique_ptr<Image> tmpImage(new_image_from_mask(editor->getSite(),
|
||||
Preferences::instance().experimental.newBlend()));
|
||||
|
||||
PixelsMovementPtr pixelsMovement(
|
||||
new PixelsMovement(UIContext::instance(),
|
||||
|
@ -372,7 +372,9 @@ public:
|
||||
|
||||
m_floodfillSrcImage->clear(m_sprite->transparentColor());
|
||||
|
||||
render::Render().renderSprite(
|
||||
render::Render render;
|
||||
render.setNewBlend(Preferences::instance().experimental.newBlend());
|
||||
render.renderSprite(
|
||||
m_floodfillSrcImage,
|
||||
m_sprite,
|
||||
m_frame,
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -192,7 +193,9 @@ static bool copy_from_document(const Site& site, bool merged = false)
|
||||
ASSERT(document);
|
||||
|
||||
const Mask* mask = document->mask();
|
||||
Image* image = new_image_from_mask(site, mask, merged);
|
||||
Image* image = new_image_from_mask(site, mask,
|
||||
Preferences::instance().experimental.newBlend(),
|
||||
merged);
|
||||
if (!image)
|
||||
return false;
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -21,14 +22,15 @@ namespace app {
|
||||
|
||||
using namespace doc;
|
||||
|
||||
Image* new_image_from_mask(const Site& site)
|
||||
Image* new_image_from_mask(const Site& site, const bool newBlend)
|
||||
{
|
||||
const Mask* srcMask = site.document()->mask();
|
||||
return new_image_from_mask(site, srcMask);
|
||||
return new_image_from_mask(site, srcMask, newBlend);
|
||||
}
|
||||
|
||||
doc::Image* new_image_from_mask(const Site& site,
|
||||
const doc::Mask* srcMask,
|
||||
const bool newBlend,
|
||||
bool merged)
|
||||
{
|
||||
const Sprite* srcSprite = site.sprite();
|
||||
@ -53,6 +55,7 @@ doc::Image* new_image_from_mask(const Site& site,
|
||||
int x = 0, y = 0;
|
||||
if (merged) {
|
||||
render::Render render;
|
||||
render.setNewBlend(newBlend);
|
||||
render.renderSprite(dst.get(), srcSprite, site.frame(),
|
||||
gfx::Clip(0, 0, srcBounds));
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -16,9 +17,11 @@ namespace doc {
|
||||
namespace app {
|
||||
class Site;
|
||||
|
||||
doc::Image* new_image_from_mask(const Site& site);
|
||||
doc::Image* new_image_from_mask(const Site& site,
|
||||
const bool newBlend);
|
||||
doc::Image* new_image_from_mask(const Site& site,
|
||||
const doc::Mask* mask,
|
||||
const bool newBlend,
|
||||
bool merged = false);
|
||||
|
||||
} // namespace app
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2019 Igara Studio S.A.
|
||||
// Copyright (c) 2001-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -37,6 +38,39 @@ namespace {
|
||||
#define blend_difference(b, s) (ABS((b) - (s)))
|
||||
#define blend_exclusion(b, s, t) ((t) = MUL_UN8((b), (s), (t)), ((b) + (s) - 2*(t)))
|
||||
|
||||
// New Blender Method macros
|
||||
#define RGBA_BLENDER_N(name) \
|
||||
color_t rgba_blender_##name##_n(color_t backdrop, color_t src, int opacity) { \
|
||||
if (backdrop & rgba_a_mask) { \
|
||||
color_t normal = rgba_blender_normal(backdrop, src, opacity); \
|
||||
color_t blend = rgba_blender_##name(backdrop, src, opacity); \
|
||||
int Ba = rgba_geta(backdrop); \
|
||||
color_t normalToBlendMerge = rgba_blender_merge(normal, blend, Ba); \
|
||||
int t; \
|
||||
int srcTotalAlpha = MUL_UN8(rgba_geta(src), opacity, t); \
|
||||
int compositeAlpha = MUL_UN8(Ba, srcTotalAlpha, t); \
|
||||
return rgba_blender_merge(normalToBlendMerge, blend, compositeAlpha); \
|
||||
} \
|
||||
else \
|
||||
return rgba_blender_normal(backdrop, src, opacity); \
|
||||
}
|
||||
|
||||
#define GRAYA_BLENDER_N(name) \
|
||||
color_t graya_blender_##name##_n(color_t backdrop, color_t src, int opacity) { \
|
||||
if (backdrop & graya_a_mask) { \
|
||||
color_t normal = graya_blender_normal(backdrop, src, opacity); \
|
||||
color_t blend = graya_blender_##name(backdrop, src, opacity); \
|
||||
int Ba = graya_geta(backdrop); \
|
||||
color_t normalToBlendMerge = graya_blender_merge(normal, blend, Ba); \
|
||||
int t; \
|
||||
int srcTotalAlpha = MUL_UN8(graya_geta(src), opacity, t); \
|
||||
int compositeAlpha = MUL_UN8(Ba, srcTotalAlpha, t); \
|
||||
return graya_blender_merge(normalToBlendMerge, blend, compositeAlpha); \
|
||||
} \
|
||||
else \
|
||||
return graya_blender_normal(backdrop, src, opacity); \
|
||||
}
|
||||
|
||||
inline uint32_t blend_divide(uint32_t b, uint32_t s)
|
||||
{
|
||||
if (b == 0)
|
||||
@ -169,13 +203,13 @@ color_t rgba_blender_normal(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int t;
|
||||
|
||||
if ((backdrop & rgba_a_mask) == 0) {
|
||||
if (!(backdrop & rgba_a_mask)) {
|
||||
int a = rgba_geta(src);
|
||||
a = MUL_UN8(a, opacity, t);
|
||||
a <<= rgba_a_shift;
|
||||
return (src & rgba_rgb_mask) | a;
|
||||
}
|
||||
else if ((src & rgba_a_mask) == 0) {
|
||||
else if (!(src & rgba_a_mask)) {
|
||||
return backdrop;
|
||||
}
|
||||
|
||||
@ -209,6 +243,14 @@ color_t rgba_blender_normal(color_t backdrop, color_t src, int opacity)
|
||||
return rgba(Rr, Rg, Rb, Ra);
|
||||
}
|
||||
|
||||
color_t rgba_blender_normal_dst_over(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int t;
|
||||
int Sa = MUL_UN8(rgba_geta(src), opacity, t);
|
||||
src = (src & rgba_rgb_mask) | (Sa << rgba_a_shift);
|
||||
return rgba_blender_normal(src, backdrop);
|
||||
}
|
||||
|
||||
color_t rgba_blender_multiply(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int t;
|
||||
@ -469,6 +511,26 @@ color_t rgba_blender_divide(color_t backdrop, color_t src, int opacity)
|
||||
return rgba_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
// New Blender Methods:
|
||||
RGBA_BLENDER_N(multiply)
|
||||
RGBA_BLENDER_N(screen)
|
||||
RGBA_BLENDER_N(overlay)
|
||||
RGBA_BLENDER_N(darken)
|
||||
RGBA_BLENDER_N(lighten)
|
||||
RGBA_BLENDER_N(color_dodge)
|
||||
RGBA_BLENDER_N(color_burn)
|
||||
RGBA_BLENDER_N(hard_light)
|
||||
RGBA_BLENDER_N(soft_light)
|
||||
RGBA_BLENDER_N(difference)
|
||||
RGBA_BLENDER_N(exclusion)
|
||||
RGBA_BLENDER_N(hsl_color)
|
||||
RGBA_BLENDER_N(hsl_hue)
|
||||
RGBA_BLENDER_N(hsl_saturation)
|
||||
RGBA_BLENDER_N(hsl_luminosity)
|
||||
RGBA_BLENDER_N(addition)
|
||||
RGBA_BLENDER_N(subtract)
|
||||
RGBA_BLENDER_N(divide)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// GRAY blenders
|
||||
|
||||
@ -520,13 +582,13 @@ color_t graya_blender_normal(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int t;
|
||||
|
||||
if ((backdrop & graya_a_mask) == 0) {
|
||||
if (!(backdrop & graya_a_mask)) {
|
||||
int a = graya_geta(src);
|
||||
a = MUL_UN8(a, opacity, t);
|
||||
a <<= graya_a_shift;
|
||||
return (src & 0xff) | a;
|
||||
}
|
||||
else if ((src & graya_a_mask) == 0)
|
||||
else if (!(src & graya_a_mask))
|
||||
return backdrop;
|
||||
|
||||
int Bg, Ba;
|
||||
@ -649,6 +711,21 @@ color_t graya_blender_divide(color_t backdrop, color_t src, int opacity)
|
||||
return graya_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
GRAYA_BLENDER_N(multiply)
|
||||
GRAYA_BLENDER_N(screen)
|
||||
GRAYA_BLENDER_N(overlay)
|
||||
GRAYA_BLENDER_N(darken)
|
||||
GRAYA_BLENDER_N(lighten)
|
||||
GRAYA_BLENDER_N(color_dodge)
|
||||
GRAYA_BLENDER_N(color_burn)
|
||||
GRAYA_BLENDER_N(hard_light)
|
||||
GRAYA_BLENDER_N(soft_light)
|
||||
GRAYA_BLENDER_N(difference)
|
||||
GRAYA_BLENDER_N(exclusion)
|
||||
GRAYA_BLENDER_N(addition)
|
||||
GRAYA_BLENDER_N(subtract)
|
||||
GRAYA_BLENDER_N(divide)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// indexed
|
||||
|
||||
@ -660,7 +737,7 @@ color_t indexed_blender_src(color_t dst, color_t src, int opacity)
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// getters
|
||||
|
||||
BlendFunc get_rgba_blender(BlendMode blendmode)
|
||||
BlendFunc get_rgba_blender(BlendMode blendmode, const bool newBlend)
|
||||
{
|
||||
switch (blendmode) {
|
||||
case BlendMode::SRC: return rgba_blender_src;
|
||||
@ -668,32 +745,33 @@ BlendFunc get_rgba_blender(BlendMode blendmode)
|
||||
case BlendMode::NEG_BW: return rgba_blender_neg_bw;
|
||||
case BlendMode::RED_TINT: return rgba_blender_red_tint;
|
||||
case BlendMode::BLUE_TINT: return rgba_blender_blue_tint;
|
||||
case BlendMode::DST_OVER: return rgba_blender_normal_dst_over;
|
||||
|
||||
case BlendMode::NORMAL: return rgba_blender_normal;
|
||||
case BlendMode::MULTIPLY: return rgba_blender_multiply;
|
||||
case BlendMode::SCREEN: return rgba_blender_screen;
|
||||
case BlendMode::OVERLAY: return rgba_blender_overlay;
|
||||
case BlendMode::DARKEN: return rgba_blender_darken;
|
||||
case BlendMode::LIGHTEN: return rgba_blender_lighten;
|
||||
case BlendMode::COLOR_DODGE: return rgba_blender_color_dodge;
|
||||
case BlendMode::COLOR_BURN: return rgba_blender_color_burn;
|
||||
case BlendMode::HARD_LIGHT: return rgba_blender_hard_light;
|
||||
case BlendMode::SOFT_LIGHT: return rgba_blender_soft_light;
|
||||
case BlendMode::DIFFERENCE: return rgba_blender_difference;
|
||||
case BlendMode::EXCLUSION: return rgba_blender_exclusion;
|
||||
case BlendMode::HSL_HUE: return rgba_blender_hsl_hue;
|
||||
case BlendMode::HSL_SATURATION: return rgba_blender_hsl_saturation;
|
||||
case BlendMode::HSL_COLOR: return rgba_blender_hsl_color;
|
||||
case BlendMode::HSL_LUMINOSITY: return rgba_blender_hsl_luminosity;
|
||||
case BlendMode::ADDITION: return rgba_blender_addition;
|
||||
case BlendMode::SUBTRACT: return rgba_blender_subtract;
|
||||
case BlendMode::DIVIDE: return rgba_blender_divide;
|
||||
case BlendMode::MULTIPLY: return newBlend? rgba_blender_multiply_n: rgba_blender_multiply;
|
||||
case BlendMode::SCREEN: return newBlend? rgba_blender_screen_n: rgba_blender_screen;
|
||||
case BlendMode::OVERLAY: return newBlend? rgba_blender_overlay_n: rgba_blender_overlay;
|
||||
case BlendMode::DARKEN: return newBlend? rgba_blender_darken_n: rgba_blender_darken;
|
||||
case BlendMode::LIGHTEN: return newBlend? rgba_blender_lighten_n: rgba_blender_lighten;
|
||||
case BlendMode::COLOR_DODGE: return newBlend? rgba_blender_color_dodge_n: rgba_blender_color_dodge;
|
||||
case BlendMode::COLOR_BURN: return newBlend? rgba_blender_color_burn_n: rgba_blender_color_burn;
|
||||
case BlendMode::HARD_LIGHT: return newBlend? rgba_blender_hard_light_n: rgba_blender_hard_light;
|
||||
case BlendMode::SOFT_LIGHT: return newBlend? rgba_blender_soft_light_n: rgba_blender_soft_light;
|
||||
case BlendMode::DIFFERENCE: return newBlend? rgba_blender_difference_n: rgba_blender_difference;
|
||||
case BlendMode::EXCLUSION: return newBlend? rgba_blender_exclusion_n: rgba_blender_exclusion;
|
||||
case BlendMode::HSL_HUE: return newBlend? rgba_blender_hsl_hue_n: rgba_blender_hsl_hue;
|
||||
case BlendMode::HSL_SATURATION: return newBlend? rgba_blender_hsl_saturation_n: rgba_blender_hsl_saturation;
|
||||
case BlendMode::HSL_COLOR: return newBlend? rgba_blender_hsl_color_n: rgba_blender_hsl_color;
|
||||
case BlendMode::HSL_LUMINOSITY: return newBlend? rgba_blender_hsl_luminosity_n: rgba_blender_hsl_luminosity;
|
||||
case BlendMode::ADDITION: return newBlend? rgba_blender_addition_n: rgba_blender_addition;
|
||||
case BlendMode::SUBTRACT: return newBlend? rgba_blender_subtract_n: rgba_blender_subtract;
|
||||
case BlendMode::DIVIDE: return newBlend? rgba_blender_divide_n: rgba_blender_divide;
|
||||
}
|
||||
ASSERT(false);
|
||||
return rgba_blender_src;
|
||||
}
|
||||
|
||||
BlendFunc get_graya_blender(BlendMode blendmode)
|
||||
BlendFunc get_graya_blender(BlendMode blendmode, const bool newBlend)
|
||||
{
|
||||
switch (blendmode) {
|
||||
case BlendMode::SRC: return graya_blender_src;
|
||||
@ -703,30 +781,30 @@ BlendFunc get_graya_blender(BlendMode blendmode)
|
||||
case BlendMode::BLUE_TINT: return graya_blender_normal;
|
||||
|
||||
case BlendMode::NORMAL: return graya_blender_normal;
|
||||
case BlendMode::MULTIPLY: return graya_blender_multiply;
|
||||
case BlendMode::SCREEN: return graya_blender_screen;
|
||||
case BlendMode::OVERLAY: return graya_blender_overlay;
|
||||
case BlendMode::DARKEN: return graya_blender_darken;
|
||||
case BlendMode::LIGHTEN: return graya_blender_lighten;
|
||||
case BlendMode::COLOR_DODGE: return graya_blender_color_dodge;
|
||||
case BlendMode::COLOR_BURN: return graya_blender_color_burn;
|
||||
case BlendMode::HARD_LIGHT: return graya_blender_hard_light;
|
||||
case BlendMode::SOFT_LIGHT: return graya_blender_soft_light;
|
||||
case BlendMode::DIFFERENCE: return graya_blender_difference;
|
||||
case BlendMode::EXCLUSION: return graya_blender_exclusion;
|
||||
case BlendMode::MULTIPLY: return newBlend? graya_blender_multiply_n: graya_blender_multiply;
|
||||
case BlendMode::SCREEN: return newBlend? graya_blender_screen_n: graya_blender_screen;
|
||||
case BlendMode::OVERLAY: return newBlend? graya_blender_overlay_n: graya_blender_overlay;
|
||||
case BlendMode::DARKEN: return newBlend? graya_blender_darken_n: graya_blender_darken;
|
||||
case BlendMode::LIGHTEN: return newBlend? graya_blender_lighten_n: graya_blender_lighten;
|
||||
case BlendMode::COLOR_DODGE: return newBlend? graya_blender_color_dodge_n: graya_blender_color_dodge;
|
||||
case BlendMode::COLOR_BURN: return newBlend? graya_blender_color_burn_n: graya_blender_color_burn;
|
||||
case BlendMode::HARD_LIGHT: return newBlend? graya_blender_hard_light_n: graya_blender_hard_light;
|
||||
case BlendMode::SOFT_LIGHT: return newBlend? graya_blender_soft_light_n: graya_blender_soft_light;
|
||||
case BlendMode::DIFFERENCE: return newBlend? graya_blender_difference_n: graya_blender_difference;
|
||||
case BlendMode::EXCLUSION: return newBlend? graya_blender_exclusion_n: graya_blender_exclusion;
|
||||
case BlendMode::HSL_HUE: return graya_blender_normal;
|
||||
case BlendMode::HSL_SATURATION: return graya_blender_normal;
|
||||
case BlendMode::HSL_COLOR: return graya_blender_normal;
|
||||
case BlendMode::HSL_LUMINOSITY: return graya_blender_normal;
|
||||
case BlendMode::ADDITION: return graya_blender_addition;
|
||||
case BlendMode::SUBTRACT: return graya_blender_subtract;
|
||||
case BlendMode::DIVIDE: return graya_blender_divide;
|
||||
case BlendMode::ADDITION: return newBlend? graya_blender_exclusion_n: graya_blender_addition;
|
||||
case BlendMode::SUBTRACT: return newBlend? graya_blender_subtract_n: graya_blender_subtract;
|
||||
case BlendMode::DIVIDE: return newBlend? graya_blender_divide_n: graya_blender_divide;
|
||||
}
|
||||
ASSERT(false);
|
||||
return graya_blender_src;
|
||||
}
|
||||
|
||||
BlendFunc get_indexed_blender(BlendMode blendmode)
|
||||
BlendFunc get_indexed_blender(BlendMode blendmode, const bool newBlend)
|
||||
{
|
||||
return indexed_blender_src;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (c) 2001-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -21,6 +22,7 @@ namespace doc {
|
||||
color_t rgba_blender_red_tint(color_t backdrop, color_t src, int opacity);
|
||||
color_t rgba_blender_blue_tint(color_t backdrop, color_t src, int opacity);
|
||||
color_t rgba_blender_normal(color_t backdrop, color_t src, int opacity = 255);
|
||||
color_t rgba_blender_normal_dst_over(color_t backdrop, color_t src, int opacity);
|
||||
color_t rgba_blender_multiply(color_t backdrop, color_t src, int opacity);
|
||||
color_t rgba_blender_screen(color_t backdrop, color_t src, int opacity);
|
||||
color_t rgba_blender_overlay(color_t backdrop, color_t src, int opacity);
|
||||
@ -55,12 +57,15 @@ namespace doc {
|
||||
color_t graya_blender_soft_light(color_t backdrop, color_t src, int opacity);
|
||||
color_t graya_blender_difference(color_t backdrop, color_t src, int opacity);
|
||||
color_t graya_blender_exclusion(color_t backdrop, color_t src, int opacity);
|
||||
color_t graya_blender_addition(color_t backdrop, color_t src, int opacity);
|
||||
color_t graya_blender_subtract(color_t backdrop, color_t src, int opacity);
|
||||
color_t graya_blender_divide(color_t backdrop, color_t src, int opacity);
|
||||
|
||||
color_t indexed_blender_src(color_t dst, color_t src, int opacity);
|
||||
|
||||
BlendFunc get_rgba_blender(BlendMode blendmode);
|
||||
BlendFunc get_graya_blender(BlendMode blendmode);
|
||||
BlendFunc get_indexed_blender(BlendMode blendmode);
|
||||
BlendFunc get_rgba_blender(BlendMode blendmode, const bool newBlend);
|
||||
BlendFunc get_graya_blender(BlendMode blendmode, const bool newBlend);
|
||||
BlendFunc get_indexed_blender(BlendMode blendmode, const bool newBlend);
|
||||
|
||||
} // namespace doc
|
||||
|
||||
|
@ -20,6 +20,7 @@ namespace doc {
|
||||
NEG_BW = -4, // Negative Black & White
|
||||
RED_TINT = -5,
|
||||
BLUE_TINT = -6,
|
||||
DST_OVER = -7,
|
||||
|
||||
// Aseprite (.ase files) blend modes
|
||||
NORMAL = 0,
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2018 Igara Studio S.A.
|
||||
// Copyright (c) 2018-2019 Igara Studio S.A.
|
||||
// Copyright (c) 2001-2015 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -39,8 +39,8 @@ namespace doc {
|
||||
return bytes_per_pixel * pixels_per_row;
|
||||
}
|
||||
|
||||
static inline BlendFunc get_blender(BlendMode blend_mode) {
|
||||
return get_rgba_blender(blend_mode);
|
||||
static inline BlendFunc get_blender(BlendMode blend_mode, bool newBlend) {
|
||||
return get_rgba_blender(blend_mode, newBlend);
|
||||
}
|
||||
|
||||
static inline bool same_color(const pixel_t a, const pixel_t b) {
|
||||
@ -80,8 +80,8 @@ namespace doc {
|
||||
return bytes_per_pixel * pixels_per_row;
|
||||
}
|
||||
|
||||
static inline BlendFunc get_blender(BlendMode blend_mode) {
|
||||
return get_graya_blender(blend_mode);
|
||||
static inline BlendFunc get_blender(BlendMode blend_mode, bool newBlend) {
|
||||
return get_graya_blender(blend_mode, newBlend);
|
||||
}
|
||||
|
||||
static inline bool same_color(const pixel_t a, const pixel_t b) {
|
||||
@ -121,8 +121,8 @@ namespace doc {
|
||||
return bytes_per_pixel * pixels_per_row;
|
||||
}
|
||||
|
||||
static inline BlendFunc get_blender(BlendMode blend_mode) {
|
||||
return get_indexed_blender(blend_mode);
|
||||
static inline BlendFunc get_blender(BlendMode blend_mode, bool newBlend) {
|
||||
return get_indexed_blender(blend_mode, newBlend);
|
||||
}
|
||||
|
||||
static inline bool same_color(const pixel_t a, const pixel_t b) {
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite Render Library
|
||||
// Copyright (c) 2019 Igara Studio S.A.
|
||||
// Copyright (c) 2001-2018 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -20,7 +21,8 @@ color_t get_sprite_pixel(const Sprite* sprite,
|
||||
const double x,
|
||||
const double y,
|
||||
const frame_t frame,
|
||||
const Projection& proj)
|
||||
const Projection& proj,
|
||||
const bool newBlend)
|
||||
{
|
||||
color_t color = 0;
|
||||
|
||||
@ -29,6 +31,7 @@ color_t get_sprite_pixel(const Sprite* sprite,
|
||||
std::unique_ptr<Image> image(Image::create(sprite->pixelFormat(), 1, 1));
|
||||
|
||||
render::Render render;
|
||||
render.setNewBlend(newBlend);
|
||||
render.setRefLayersVisiblity(true);
|
||||
render.setProjection(proj);
|
||||
render.renderSprite(
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite Render Library
|
||||
// Copyright (c) 2019 Igara Studio S.A.
|
||||
// Copyright (c) 2001-2016 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -26,7 +27,8 @@ namespace render {
|
||||
const double x,
|
||||
const double y,
|
||||
const frame_t frame,
|
||||
const Projection& proj);
|
||||
const Projection& proj,
|
||||
const bool newBlend);
|
||||
|
||||
} // namespace render
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite Render Library
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (c) 2001-2018 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -40,7 +41,8 @@ Palette* create_palette_from_sprite(
|
||||
const frame_t toFrame,
|
||||
const bool withAlpha,
|
||||
Palette* palette,
|
||||
TaskDelegate* delegate)
|
||||
TaskDelegate* delegate,
|
||||
const bool newBlend)
|
||||
{
|
||||
PaletteOptimizer optimizer;
|
||||
|
||||
@ -53,6 +55,7 @@ Palette* create_palette_from_sprite(
|
||||
|
||||
// Feed the optimizer with all rendered frames
|
||||
render::Render render;
|
||||
render.setNewBlend(newBlend);
|
||||
for (frame_t frame=fromFrame; frame<=toFrame; ++frame) {
|
||||
render.renderSprite(flat_image.get(), sprite, frame);
|
||||
optimizer.feedWithImage(flat_image.get(), withAlpha);
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite Rener Library
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (c) 2001-2015, 2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -43,7 +44,8 @@ namespace render {
|
||||
const doc::frame_t toFrame,
|
||||
const bool withAlpha,
|
||||
doc::Palette* newPalette, // Can be NULL to create a new palette
|
||||
TaskDelegate* delegate);
|
||||
TaskDelegate* delegate,
|
||||
const bool newBlend);
|
||||
|
||||
// Changes the image pixel format. The dithering method is used only
|
||||
// when you want to convert from RGB to Indexed.
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite Render Library
|
||||
// Copyright (c) 2019 Igara Studio S.A.
|
||||
// Copyright (c) 2001-2018 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -33,9 +34,9 @@ class BlenderHelper {
|
||||
BlendFunc m_blendFunc;
|
||||
color_t m_mask_color;
|
||||
public:
|
||||
BlenderHelper(const Image* src, const Palette* pal, BlendMode blendMode)
|
||||
BlenderHelper(const Image* src, const Palette* pal, BlendMode blendMode, const bool newBlend)
|
||||
{
|
||||
m_blendFunc = SrcTraits::get_blender(blendMode);
|
||||
m_blendFunc = SrcTraits::get_blender(blendMode, newBlend);
|
||||
m_mask_color = src->maskColor();
|
||||
}
|
||||
inline typename DstTraits::pixel_t
|
||||
@ -55,9 +56,9 @@ class BlenderHelper<RgbTraits, GrayscaleTraits> {
|
||||
BlendFunc m_blendFunc;
|
||||
color_t m_mask_color;
|
||||
public:
|
||||
BlenderHelper(const Image* src, const Palette* pal, BlendMode blendMode)
|
||||
BlenderHelper(const Image* src, const Palette* pal, BlendMode blendMode, const bool newBlend)
|
||||
{
|
||||
m_blendFunc = RgbTraits::get_blender(blendMode);
|
||||
m_blendFunc = RgbTraits::get_blender(blendMode, newBlend);
|
||||
m_mask_color = src->maskColor();
|
||||
}
|
||||
inline RgbTraits::pixel_t
|
||||
@ -81,10 +82,10 @@ class BlenderHelper<RgbTraits, IndexedTraits> {
|
||||
BlendFunc m_blendFunc;
|
||||
color_t m_mask_color;
|
||||
public:
|
||||
BlenderHelper(const Image* src, const Palette* pal, BlendMode blendMode)
|
||||
BlenderHelper(const Image* src, const Palette* pal, BlendMode blendMode, const bool newBlend)
|
||||
{
|
||||
m_blendMode = blendMode;
|
||||
m_blendFunc = RgbTraits::get_blender(blendMode);
|
||||
m_blendFunc = RgbTraits::get_blender(blendMode, newBlend);
|
||||
m_mask_color = src->maskColor();
|
||||
m_pal = pal;
|
||||
}
|
||||
@ -111,7 +112,7 @@ class BlenderHelper<IndexedTraits, IndexedTraits> {
|
||||
BlendMode m_blendMode;
|
||||
color_t m_mask_color;
|
||||
public:
|
||||
BlenderHelper(const Image* src, const Palette* pal, BlendMode blendMode)
|
||||
BlenderHelper(const Image* src, const Palette* pal, BlendMode blendMode, const bool newBlend)
|
||||
{
|
||||
m_blendMode = blendMode;
|
||||
m_mask_color = src->maskColor();
|
||||
@ -140,14 +141,15 @@ void composite_image_without_scale(
|
||||
const int opacity,
|
||||
const BlendMode blendMode,
|
||||
const double sx,
|
||||
const double sy)
|
||||
const double sy,
|
||||
const bool newBlend)
|
||||
{
|
||||
ASSERT(dst);
|
||||
ASSERT(src);
|
||||
ASSERT(DstTraits::pixel_format == dst->pixelFormat());
|
||||
ASSERT(SrcTraits::pixel_format == src->pixelFormat());
|
||||
|
||||
BlenderHelper<DstTraits, SrcTraits> blender(src, pal, blendMode);
|
||||
BlenderHelper<DstTraits, SrcTraits> blender(src, pal, blendMode, newBlend);
|
||||
|
||||
gfx::Clip area(areaF);
|
||||
if (!area.clip(dst->width(), dst->height(),
|
||||
@ -195,7 +197,8 @@ void composite_image_scale_up(
|
||||
const int opacity,
|
||||
const BlendMode blendMode,
|
||||
const double sx,
|
||||
const double sy)
|
||||
const double sy,
|
||||
const bool newBlend)
|
||||
{
|
||||
ASSERT(dst);
|
||||
ASSERT(src);
|
||||
@ -208,7 +211,7 @@ void composite_image_scale_up(
|
||||
int(sy*double(src->height()))))
|
||||
return;
|
||||
|
||||
BlenderHelper<DstTraits, SrcTraits> blender(src, pal, blendMode);
|
||||
BlenderHelper<DstTraits, SrcTraits> blender(src, pal, blendMode, newBlend);
|
||||
int px_x, px_y;
|
||||
int px_w = int(sx);
|
||||
int px_h = int(sy);
|
||||
@ -334,7 +337,8 @@ void composite_image_scale_down(
|
||||
const int opacity,
|
||||
const BlendMode blendMode,
|
||||
const double sx,
|
||||
const double sy)
|
||||
const double sy,
|
||||
const bool newBlend)
|
||||
{
|
||||
ASSERT(dst);
|
||||
ASSERT(src);
|
||||
@ -347,7 +351,7 @@ void composite_image_scale_down(
|
||||
int(sy*double(src->height()))))
|
||||
return;
|
||||
|
||||
BlenderHelper<DstTraits, SrcTraits> blender(src, pal, blendMode);
|
||||
BlenderHelper<DstTraits, SrcTraits> blender(src, pal, blendMode, newBlend);
|
||||
int step_w = int(1.0 / sx);
|
||||
int step_h = int(1.0 / sy);
|
||||
if (step_w < 1 || step_h < 1)
|
||||
@ -401,7 +405,8 @@ void composite_image_general(
|
||||
const int opacity,
|
||||
const BlendMode blendMode,
|
||||
const double sx,
|
||||
const double sy)
|
||||
const double sy,
|
||||
const bool newBlend)
|
||||
{
|
||||
ASSERT(dst);
|
||||
ASSERT(src);
|
||||
@ -413,7 +418,7 @@ void composite_image_general(
|
||||
sx*src->width(), sy*src->height()))
|
||||
return;
|
||||
|
||||
BlenderHelper<DstTraits, SrcTraits> blender(src, pal, blendMode);
|
||||
BlenderHelper<DstTraits, SrcTraits> blender(src, pal, blendMode, newBlend);
|
||||
|
||||
gfx::Rect dstBounds(
|
||||
area.dstBounds().x, area.dstBounds().y,
|
||||
@ -514,6 +519,7 @@ Render::Render()
|
||||
, m_extraType(ExtraType::NONE)
|
||||
, m_extraCel(NULL)
|
||||
, m_extraImage(NULL)
|
||||
, m_newBlendMethod(true)
|
||||
, m_bgType(BgType::TRANSPARENT)
|
||||
, m_bgCheckedSize(16, 16)
|
||||
, m_globalOpacity(255)
|
||||
@ -539,6 +545,11 @@ void Render::setNonactiveLayersOpacity(const int opacity)
|
||||
m_nonactiveLayersOpacity = opacity;
|
||||
}
|
||||
|
||||
void Render::setNewBlend(const bool newBlend)
|
||||
{
|
||||
m_newBlendMethod = newBlend;
|
||||
}
|
||||
|
||||
void Render::setProjection(const Projection& projection)
|
||||
{
|
||||
m_proj = projection;
|
||||
@ -694,53 +705,26 @@ void Render::renderSprite(
|
||||
}
|
||||
}
|
||||
|
||||
// Draw checked background
|
||||
switch (m_bgType) {
|
||||
|
||||
case BgType::CHECKED:
|
||||
if (bgLayer && bgLayer->isVisible() && rgba_geta(bg_color) == 255) {
|
||||
fill_rect(dstImage, area.dstBounds(), bg_color);
|
||||
}
|
||||
else {
|
||||
renderBackground(dstImage, area);
|
||||
if (bgLayer && bgLayer->isVisible() && rgba_geta(bg_color) > 0) {
|
||||
blend_rect(dstImage,
|
||||
int(area.dst.x),
|
||||
int(area.dst.y),
|
||||
int(area.dst.x+area.size.w-1),
|
||||
int(area.dst.y+area.size.h-1),
|
||||
bg_color, 255);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BgType::TRANSPARENT:
|
||||
fill_rect(dstImage, area.dstBounds(), bg_color);
|
||||
break;
|
||||
if (m_newBlendMethod) {
|
||||
// New Blending Method:
|
||||
// Generate temporal background image. It will merge with dstImage.
|
||||
if (!m_tmpBuf)
|
||||
m_tmpBuf.reset(new doc::ImageBuffer);
|
||||
ImageRef tmpBackground(Image::create(dstImage->spec(), m_tmpBuf));
|
||||
renderBg(tmpBackground.get(), bgLayer, bg_color, area);
|
||||
// Clear dstImage
|
||||
fill_rect(dstImage, area.dstBounds(), bg_color);
|
||||
// Draw Background - Onion skin behind the sprite - Transparent Layers
|
||||
renderSpriteLayers(dstImage, area, frame, compositeImage);
|
||||
// Draw the background on each pixel which opacity is different to 255
|
||||
composite_image(dstImage, tmpBackground.get(), sprite->palette(frame),
|
||||
0, 0, 255, BlendMode::DST_OVER);
|
||||
}
|
||||
else {
|
||||
// Old Blending Method:
|
||||
renderBg(dstImage, bgLayer, bg_color, area);
|
||||
renderSpriteLayers(dstImage, area, frame, compositeImage);
|
||||
}
|
||||
|
||||
// Draw the background layer.
|
||||
m_globalOpacity = 255;
|
||||
renderLayer(
|
||||
m_sprite->root(), dstImage,
|
||||
area, frame, compositeImage,
|
||||
true,
|
||||
false,
|
||||
BlendMode::UNSPECIFIED,
|
||||
false);
|
||||
|
||||
// Draw onion skin behind the sprite.
|
||||
if (m_onionskin.position() == OnionskinPosition::BEHIND)
|
||||
renderOnionskin(dstImage, area, frame, compositeImage);
|
||||
|
||||
// Draw the transparent layers.
|
||||
m_globalOpacity = 255;
|
||||
renderLayer(
|
||||
m_sprite->root(), dstImage,
|
||||
area, frame, compositeImage,
|
||||
false,
|
||||
true,
|
||||
BlendMode::UNSPECIFIED, false);
|
||||
|
||||
// Draw onion skin in front of the sprite.
|
||||
if (m_onionskin.position() == OnionskinPosition::INFRONT)
|
||||
@ -766,6 +750,57 @@ void Render::renderSprite(
|
||||
}
|
||||
}
|
||||
|
||||
void Render::renderSpriteLayers(Image* dstImage,
|
||||
const gfx::ClipF& area,
|
||||
frame_t frame,
|
||||
CompositeImageFunc compositeImage) {
|
||||
// Draw the background layer.
|
||||
m_globalOpacity = 255;
|
||||
renderLayer(m_sprite->root(), dstImage,
|
||||
area, frame, compositeImage,
|
||||
true,
|
||||
false,
|
||||
BlendMode::UNSPECIFIED,
|
||||
false);
|
||||
|
||||
// Draw onion skin behind the sprite.
|
||||
if (m_onionskin.position() == OnionskinPosition::BEHIND)
|
||||
renderOnionskin(dstImage, area, frame, compositeImage);
|
||||
|
||||
// Draw the transparent layers.
|
||||
m_globalOpacity = 255;
|
||||
renderLayer(m_sprite->root(), dstImage,
|
||||
area, frame, compositeImage,
|
||||
false,
|
||||
true,
|
||||
BlendMode::UNSPECIFIED, false);
|
||||
}
|
||||
|
||||
void Render::renderBg(Image* image, const Layer* bgLayer, color_t bg_color, const gfx::ClipF& area) {
|
||||
switch (m_bgType) {
|
||||
case BgType::CHECKED:
|
||||
if (bgLayer && bgLayer->isVisible() && rgba_geta(bg_color) == 255) {
|
||||
fill_rect(image, area.dstBounds(), bg_color);
|
||||
}
|
||||
else {
|
||||
renderBackground(image, area);
|
||||
if (bgLayer && bgLayer->isVisible() && rgba_geta(bg_color) > 0) {
|
||||
blend_rect(image,
|
||||
int(area.dst.x),
|
||||
int(area.dst.y),
|
||||
int(area.dst.x+area.size.w-1),
|
||||
int(area.dst.y+area.size.h-1),
|
||||
bg_color, 255);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BgType::TRANSPARENT:
|
||||
fill_rect(image, area.dstBounds(), bg_color);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Render::renderOnionskin(
|
||||
Image* dstImage,
|
||||
const gfx::Clip& area,
|
||||
@ -906,7 +941,8 @@ void Render::renderImage(
|
||||
m_proj.applyY(src_image->height())),
|
||||
opacity, blendMode,
|
||||
m_proj.scaleX(),
|
||||
m_proj.scaleY());
|
||||
m_proj.scaleY(),
|
||||
m_newBlendMethod);
|
||||
}
|
||||
|
||||
void Render::renderLayer(
|
||||
@ -1148,7 +1184,8 @@ void Render::renderImage(
|
||||
opacity,
|
||||
blendMode,
|
||||
m_proj.scaleX() * celBounds.w / double(cel_image->width()),
|
||||
m_proj.scaleY() * celBounds.h / double(cel_image->height()));
|
||||
m_proj.scaleY() * celBounds.h / double(cel_image->height()),
|
||||
m_newBlendMethod);
|
||||
}
|
||||
|
||||
CompositeImageFunc Render::getImageComposition(
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite Render Library
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (c) 2001-2018 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -8,6 +9,7 @@
|
||||
#define RENDER_RENDER_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "doc/doc.h"
|
||||
#include "doc/anidir.h"
|
||||
#include "doc/blend_mode.h"
|
||||
#include "doc/color.h"
|
||||
@ -41,7 +43,8 @@ namespace render {
|
||||
const int opacity,
|
||||
const BlendMode blendMode,
|
||||
const double sx,
|
||||
const double sy);
|
||||
const double sy,
|
||||
const bool newBlend);
|
||||
|
||||
class Render {
|
||||
enum Flags {
|
||||
@ -53,6 +56,7 @@ namespace render {
|
||||
|
||||
void setRefLayersVisiblity(const bool visible);
|
||||
void setNonactiveLayersOpacity(const int opacity);
|
||||
void setNewBlend(const bool newBlend);
|
||||
|
||||
// Viewport configuration
|
||||
void setProjection(const Projection& projection);
|
||||
@ -127,6 +131,18 @@ namespace render {
|
||||
const int opacity,
|
||||
const BlendMode blendMode);
|
||||
|
||||
void renderSpriteLayers(
|
||||
Image* dstImage,
|
||||
const gfx::ClipF& area,
|
||||
frame_t frame,
|
||||
CompositeImageFunc compositeImage);
|
||||
|
||||
void renderBg(
|
||||
Image* image,
|
||||
const Layer* bgLayer,
|
||||
color_t bg_color,
|
||||
const gfx::ClipF& area);
|
||||
|
||||
private:
|
||||
void renderOnionskin(
|
||||
Image* image,
|
||||
@ -180,6 +196,7 @@ namespace render {
|
||||
const Cel* m_extraCel;
|
||||
const Image* m_extraImage;
|
||||
BlendMode m_extraBlendMode;
|
||||
bool m_newBlendMethod;
|
||||
BgType m_bgType;
|
||||
bool m_bgZoom;
|
||||
color_t m_bgColor1;
|
||||
@ -193,6 +210,7 @@ namespace render {
|
||||
gfx::Point m_previewPos;
|
||||
BlendMode m_previewBlendMode;
|
||||
OnionskinOptions m_onionskin;
|
||||
ImageBufferPtr m_tmpBuf;
|
||||
};
|
||||
|
||||
void composite_image(Image* dst,
|
||||
|
Loading…
x
Reference in New Issue
Block a user