mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-26 03:35:23 +00:00
Add layer blending modes (fix #318)
- Added doc::BlendMode enum and doc::BlendFunc type - Renamed LayerImage::getBlendMode() -> blendMode() - BLEND_MODE_COPY is BlendMode::SRC now - BLEND_MODE_NORMAL is BlendMode::NORMAL now - Added app::cmd::SetLayerBlendMode
This commit is contained in:
parent
8da36f990b
commit
21ca87862c
@ -6,6 +6,9 @@
|
||||
<grid columns="2">
|
||||
<label text="Name:" />
|
||||
<entry text="" id="name" magnet="true" maxsize="256" minwidth="64" cell_align="horizontal" />
|
||||
|
||||
<label text="Mode:" />
|
||||
<combobox id="mode" />
|
||||
</grid>
|
||||
<separator horizontal="true" />
|
||||
<hbox>
|
||||
|
@ -150,26 +150,23 @@ Layer Chunk (0x2004)
|
||||
WORD Layer child level (see NOTE.1)
|
||||
WORD Default layer width in pixels (ignored)
|
||||
WORD Default layer height in pixels (ignored)
|
||||
WORD DEPRECATED This field is not used anymore.
|
||||
Blend mode (always 0 for layer set)
|
||||
BLEND_MODE_NORMAL = 0
|
||||
BLEND_MODE_DISSOLVE = 1
|
||||
BLEND_MODE_MULTIPLY = 2
|
||||
BLEND_MODE_SCREEN = 3
|
||||
BLEND_MODE_OVERLAY = 4
|
||||
BLEND_MODE_HARD_LIGHT = 5
|
||||
BLEND_MODE_DODGE = 6
|
||||
BLEND_MODE_BURN = 7
|
||||
BLEND_MODE_DARKEN = 8
|
||||
BLEND_MODE_LIGHTEN = 9
|
||||
BLEND_MODE_ADDITION = 10
|
||||
BLEND_MODE_SUBTRACT = 11
|
||||
BLEND_MODE_DIFFERENCE = 12
|
||||
BLEND_MODE_HUE = 13
|
||||
BLEND_MODE_SATURATION = 14
|
||||
BLEND_MODE_COLOR = 15
|
||||
BLEND_MODE_LUMINOSITY = 16
|
||||
BLEND_MODE_COPY = 17
|
||||
WORD Blend mode (always 0 for layer set)
|
||||
Normal = 0
|
||||
Multiply = 1
|
||||
Screen = 2
|
||||
Overlay = 3
|
||||
Darken = 4
|
||||
Lighten = 5
|
||||
Color Dodge = 6
|
||||
Color Burn = 7
|
||||
Hard Light = 8
|
||||
Soft Light = 9
|
||||
Difference = 10
|
||||
Exclusion = 11
|
||||
Hue = 12
|
||||
Saturation = 13
|
||||
Color = 14
|
||||
Luminosity = 15
|
||||
BYTE[4] For future (set to zero)
|
||||
STRING Layer name
|
||||
|
||||
|
@ -113,6 +113,7 @@ add_library(app-lib
|
||||
cmd/set_frame_tag_color.cpp
|
||||
cmd/set_frame_tag_name.cpp
|
||||
cmd/set_frame_tag_range.cpp
|
||||
cmd/set_layer_blend_mode.cpp
|
||||
cmd/set_layer_flags.cpp
|
||||
cmd/set_layer_name.cpp
|
||||
cmd/set_mask.cpp
|
||||
|
@ -61,7 +61,7 @@ void BackgroundFromLayer::onExecute()
|
||||
render::composite_image(bg_image.get(), cel_image,
|
||||
cel->x(), cel->y(),
|
||||
MID(0, cel->opacity(), 255),
|
||||
static_cast<LayerImage*>(layer)->getBlendMode());
|
||||
static_cast<LayerImage*>(layer)->blendMode());
|
||||
|
||||
// now we have to copy the new image (bg_image) to the cel...
|
||||
executeAndAdd(new cmd::SetCelPosition(cel, 0, 0));
|
||||
|
@ -92,12 +92,13 @@ void CopyCel::onExecute()
|
||||
executeAndAdd(new cmd::SetCelData(dstCel, srcCel->dataRef()));
|
||||
}
|
||||
else {
|
||||
int blend = (srcLayer->isBackground() ?
|
||||
BLEND_MODE_COPY: BLEND_MODE_NORMAL);
|
||||
BlendMode blend = (srcLayer->isBackground() ?
|
||||
BlendMode::SRC:
|
||||
BlendMode::NORMAL);
|
||||
|
||||
ImageRef tmp(Image::createCopy(dstImage.get()));
|
||||
render::composite_image(tmp.get(), srcImage,
|
||||
srcCel->x(), srcCel->y(), 255, blend);
|
||||
srcCel->x(), srcCel->y(), 255, blend);
|
||||
executeAndAdd(new cmd::CopyRect(dstImage.get(), tmp.get(), gfx::Clip(tmp->bounds())));
|
||||
}
|
||||
}
|
||||
|
@ -95,8 +95,9 @@ void MoveCel::onExecute()
|
||||
executeAndAdd(new cmd::UnlinkCel(srcCel));
|
||||
}
|
||||
else {
|
||||
int blend = (srcLayer->isBackground() ?
|
||||
BLEND_MODE_COPY: BLEND_MODE_NORMAL);
|
||||
BlendMode blend = (srcLayer->isBackground() ?
|
||||
BlendMode::SRC:
|
||||
BlendMode::NORMAL);
|
||||
|
||||
ImageRef tmp(Image::createCopy(dstImage.get()));
|
||||
render::composite_image(tmp.get(), srcImage,
|
||||
|
39
src/app/cmd/set_layer_blend_mode.cpp
Normal file
39
src/app/cmd/set_layer_blend_mode.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/cmd/set_layer_blend_mode.h"
|
||||
|
||||
#include "doc/layer.h"
|
||||
|
||||
namespace app {
|
||||
namespace cmd {
|
||||
|
||||
SetLayerBlendMode::SetLayerBlendMode(LayerImage* layer, BlendMode blendMode)
|
||||
: WithLayer(layer)
|
||||
, m_oldBlendMode(layer->blendMode())
|
||||
, m_newBlendMode(blendMode)
|
||||
{
|
||||
}
|
||||
|
||||
void SetLayerBlendMode::onExecute()
|
||||
{
|
||||
static_cast<LayerImage*>(layer())->setBlendMode(m_newBlendMode);
|
||||
layer()->incrementVersion();
|
||||
}
|
||||
|
||||
void SetLayerBlendMode::onUndo()
|
||||
{
|
||||
static_cast<LayerImage*>(layer())->setBlendMode(m_oldBlendMode);
|
||||
layer()->incrementVersion();
|
||||
}
|
||||
|
||||
} // namespace cmd
|
||||
} // namespace app
|
44
src/app/cmd/set_layer_blend_mode.h
Normal file
44
src/app/cmd/set_layer_blend_mode.h
Normal file
@ -0,0 +1,44 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#ifndef APP_CMD_SET_LAYER_BLEND_MODE_H_INCLUDED
|
||||
#define APP_CMD_SET_LAYER_BLEND_MODE_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "app/cmd.h"
|
||||
#include "app/cmd/with_layer.h"
|
||||
#include "doc/blend_mode.h"
|
||||
|
||||
namespace doc {
|
||||
class LayerImage;
|
||||
}
|
||||
|
||||
namespace app {
|
||||
namespace cmd {
|
||||
using namespace doc;
|
||||
|
||||
class SetLayerBlendMode : public Cmd
|
||||
, public WithLayer {
|
||||
public:
|
||||
SetLayerBlendMode(LayerImage* layer, BlendMode blendMode);
|
||||
|
||||
protected:
|
||||
void onExecute() override;
|
||||
void onUndo() override;
|
||||
size_t onMemSize() const override {
|
||||
return sizeof(*this);
|
||||
}
|
||||
|
||||
private:
|
||||
BlendMode m_oldBlendMode;
|
||||
BlendMode m_newBlendMode;
|
||||
};
|
||||
|
||||
} // namespace cmd
|
||||
} // namespace app
|
||||
|
||||
#endif
|
@ -209,23 +209,23 @@ protected:
|
||||
switch (m_tiled) {
|
||||
case TiledMode::NONE:
|
||||
render.renderImage(m_doublebuf, m_render, m_pal, x, y,
|
||||
m_zoom, 255, BLEND_MODE_NORMAL);
|
||||
m_zoom, 255, BlendMode::NORMAL);
|
||||
break;
|
||||
case TiledMode::X_AXIS:
|
||||
for (u=x-w; u<ui::display_w()+w; u+=w)
|
||||
render.renderImage(m_doublebuf, m_render, m_pal, u, y,
|
||||
m_zoom, 255, BLEND_MODE_NORMAL);
|
||||
m_zoom, 255, BlendMode::NORMAL);
|
||||
break;
|
||||
case TiledMode::Y_AXIS:
|
||||
for (v=y-h; v<ui::display_h()+h; v+=h)
|
||||
render.renderImage(m_doublebuf, m_render, m_pal, x, v,
|
||||
m_zoom, 255, BLEND_MODE_NORMAL);
|
||||
m_zoom, 255, BlendMode::NORMAL);
|
||||
break;
|
||||
case TiledMode::BOTH:
|
||||
for (v=y-h; v<ui::display_h()+h; v+=h)
|
||||
for (u=x-w; u<ui::display_w()+w; u+=w)
|
||||
render.renderImage(m_doublebuf, m_render, m_pal, u, v,
|
||||
m_zoom, 255, BLEND_MODE_NORMAL);
|
||||
m_zoom, 255, BlendMode::NORMAL);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -13,9 +13,12 @@
|
||||
#include "ui/ui.h"
|
||||
|
||||
#include "app/app.h"
|
||||
#include "app/cmd/set_layer_blend_mode.h"
|
||||
#include "app/cmd/set_layer_name.h"
|
||||
#include "app/commands/command.h"
|
||||
#include "app/context_access.h"
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/transaction.h"
|
||||
#include "doc/image.h"
|
||||
#include "doc/layer.h"
|
||||
|
||||
@ -51,18 +54,55 @@ bool LayerPropertiesCommand::onEnabled(Context* context)
|
||||
void LayerPropertiesCommand::onExecute(Context* context)
|
||||
{
|
||||
const ContextReader reader(context);
|
||||
const Layer* layer = reader.layer();
|
||||
const LayerImage* layer = static_cast<const LayerImage*>(reader.layer());
|
||||
|
||||
app::gen::LayerProperties window;
|
||||
|
||||
window.name()->setText(layer->name().c_str());
|
||||
window.name()->setMinSize(gfx::Size(128, 0));
|
||||
window.name()->setExpansive(true);
|
||||
|
||||
window.mode()->addItem("Normal");
|
||||
window.mode()->addItem("Multiply");
|
||||
window.mode()->addItem("Screen");
|
||||
window.mode()->addItem("Overlay");
|
||||
window.mode()->addItem("Darken");
|
||||
window.mode()->addItem("Lighten");
|
||||
window.mode()->addItem("Color Dodge");
|
||||
window.mode()->addItem("Color Burn");
|
||||
window.mode()->addItem("Hard Light");
|
||||
window.mode()->addItem("Soft Light");
|
||||
window.mode()->addItem("Difference");
|
||||
window.mode()->addItem("Exclusion");
|
||||
window.mode()->addItem("Hue");
|
||||
window.mode()->addItem("Saturation");
|
||||
window.mode()->addItem("Color");
|
||||
window.mode()->addItem("Luminosity");
|
||||
window.mode()->setSelectedItemIndex((int)layer->blendMode());
|
||||
window.mode()->setEnabled(!layer->isBackground());
|
||||
|
||||
window.openWindowInForeground();
|
||||
|
||||
if (window.getKiller() == window.ok()) {
|
||||
ContextWriter writer(reader);
|
||||
writer.layer()->setName(window.name()->getText());
|
||||
update_screen_for_document(writer.document());
|
||||
std::string newName = window.name()->getText();
|
||||
BlendMode newBlendMode = (BlendMode)window.mode()->getSelectedItemIndex();
|
||||
|
||||
if (newName != layer->name() ||
|
||||
newBlendMode != layer->blendMode()) {
|
||||
ContextWriter writer(reader);
|
||||
{
|
||||
Transaction transaction(writer.context(), "Set Layer Properties");
|
||||
|
||||
if (newName != layer->name())
|
||||
transaction.execute(new cmd::SetLayerName(writer.layer(), newName));
|
||||
|
||||
if (newBlendMode != layer->blendMode())
|
||||
transaction.execute(new cmd::SetLayerBlendMode(static_cast<LayerImage*>(writer.layer()), newBlendMode));
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
update_screen_for_document(writer.document());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,7 +133,7 @@ void MergeDownLayerCommand::onExecute(Context* context)
|
||||
src_cel->x()-bounds.x,
|
||||
src_cel->y()-bounds.y,
|
||||
src_cel->opacity(),
|
||||
static_cast<LayerImage*>(src_layer)->getBlendMode());
|
||||
static_cast<LayerImage*>(src_layer)->blendMode());
|
||||
|
||||
transaction.execute(new cmd::SetCelPosition(dst_cel,
|
||||
bounds.x, bounds.y));
|
||||
|
@ -53,7 +53,7 @@ Document::Document(Sprite* sprite)
|
||||
// Extra cel
|
||||
, m_extraCel(NULL)
|
||||
, m_extraImage(NULL)
|
||||
, m_extraCelBlendMode(BLEND_MODE_NORMAL)
|
||||
, m_extraCelBlendMode(BlendMode::NORMAL)
|
||||
, m_extraCelType(render::ExtraType::NONE)
|
||||
// Mask
|
||||
, m_mask(new Mask())
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "base/observable.h"
|
||||
#include "base/shared_ptr.h"
|
||||
#include "base/unique_ptr.h"
|
||||
#include "doc/blend_mode.h"
|
||||
#include "doc/color.h"
|
||||
#include "doc/document.h"
|
||||
#include "doc/frame.h"
|
||||
@ -127,8 +128,8 @@ namespace app {
|
||||
Cel* getExtraCel() const;
|
||||
Image* getExtraCelImage() const;
|
||||
render::ExtraType getExtraCelType() const { return m_extraCelType; }
|
||||
int getExtraCelBlendMode() const { return m_extraCelBlendMode; }
|
||||
void setExtraCelBlendMode(int mode) { m_extraCelBlendMode = mode; }
|
||||
BlendMode getExtraCelBlendMode() const { return m_extraCelBlendMode; }
|
||||
void setExtraCelBlendMode(BlendMode mode) { m_extraCelBlendMode = mode; }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Mask
|
||||
@ -212,7 +213,7 @@ namespace app {
|
||||
|
||||
// Image of the extra cel.
|
||||
ImageRef m_extraImage;
|
||||
int m_extraCelBlendMode;
|
||||
BlendMode m_extraCelBlendMode;
|
||||
render::ExtraType m_extraCelType;
|
||||
|
||||
// Current mask.
|
||||
|
@ -59,7 +59,6 @@
|
||||
|
||||
#include <set>
|
||||
|
||||
|
||||
namespace app {
|
||||
|
||||
DocumentApi::DocumentApi(Document* document, Transaction& transaction)
|
||||
|
@ -663,16 +663,17 @@ static Layer* ase_file_read_layer_chunk(FILE* f, Sprite* sprite, Layer** previou
|
||||
child_level = fgetw(f);
|
||||
fgetw(f); // default width
|
||||
fgetw(f); // default height
|
||||
fgetw(f); // blend mode
|
||||
int blendmode = fgetw(f); // blend mode
|
||||
|
||||
ase_file_read_padding(f, 4);
|
||||
name = ase_file_read_string(f);
|
||||
|
||||
/* image layer */
|
||||
// Image layer
|
||||
if (layer_type == 0) {
|
||||
layer = new LayerImage(sprite);
|
||||
static_cast<LayerImage*>(layer)->setBlendMode((BlendMode)blendmode);
|
||||
}
|
||||
/* layer set */
|
||||
// Layer set
|
||||
else if (layer_type == 1) {
|
||||
layer = new LayerFolder(sprite);
|
||||
}
|
||||
@ -684,7 +685,7 @@ static Layer* ase_file_read_layer_chunk(FILE* f, Sprite* sprite, Layer** previou
|
||||
// name
|
||||
layer->setName(name.c_str());
|
||||
|
||||
// child level...
|
||||
// Child level
|
||||
if (child_level == *current_level)
|
||||
(*previous_layer)->parent()->addLayer(layer);
|
||||
else if (child_level > *current_level)
|
||||
@ -718,10 +719,10 @@ static void ase_file_write_layer_chunk(FILE* f, ASE_FrameHeader* frame_header, L
|
||||
}
|
||||
fputw(child_level, f);
|
||||
|
||||
/* default width & height, and blend mode */
|
||||
// Default width & height, and blend mode
|
||||
fputw(0, f);
|
||||
fputw(0, f);
|
||||
fputw(layer->isImage() ? static_cast<LayerImage*>(layer)->getBlendMode(): 0, f);
|
||||
fputw(layer->isImage() ? (int)static_cast<LayerImage*>(layer)->blendMode(): 0, f);
|
||||
|
||||
/* padding */
|
||||
ase_file_write_padding(f, 4);
|
||||
|
@ -75,10 +75,10 @@ TEST_F(GifFormat, OpaqueIndexed)
|
||||
doc->setFilename(fn);
|
||||
|
||||
Palette* pal = sprite->palette(frame_t(0));
|
||||
pal->setEntry(0, rgb(255, 255, 255));
|
||||
pal->setEntry(1, rgb(255, 13, 254));
|
||||
pal->setEntry(2, rgb(129, 255, 32));
|
||||
pal->setEntry(3, rgb(0, 0, 255));
|
||||
pal->setEntry(0, rgba(255, 255, 255, 255));
|
||||
pal->setEntry(1, rgba(255, 13, 254, 255));
|
||||
pal->setEntry(2, rgba(129, 255, 32, 255));
|
||||
pal->setEntry(3, rgba(0, 0, 255, 255));
|
||||
|
||||
LayerImage* layer = dynamic_cast<LayerImage*>(sprite->folder()->getFirstLayer());
|
||||
layer->setBackground(true);
|
||||
@ -105,10 +105,10 @@ TEST_F(GifFormat, OpaqueIndexed)
|
||||
EXPECT_TRUE(layer->isBackground());
|
||||
|
||||
Palette* pal = sprite->palette(frame_t(0));
|
||||
EXPECT_EQ(rgb(255, 255, 255), pal->getEntry(0));
|
||||
EXPECT_EQ(rgb(255, 13, 254), pal->getEntry(1));
|
||||
EXPECT_EQ(rgb(129, 255, 32), pal->getEntry(2));
|
||||
EXPECT_EQ(rgb(0, 0, 255), pal->getEntry(3));
|
||||
EXPECT_EQ(rgba(255, 255, 255, 255), pal->getEntry(0));
|
||||
EXPECT_EQ(rgba(255, 13, 254, 255), pal->getEntry(1));
|
||||
EXPECT_EQ(rgba(129, 255, 32, 255), pal->getEntry(2));
|
||||
EXPECT_EQ(rgba(0, 0, 255, 255), pal->getEntry(3));
|
||||
|
||||
Image* image = layer->cel(frame_t(0))->image();
|
||||
EXPECT_EQ(0, sprite->transparentColor());
|
||||
@ -132,10 +132,10 @@ TEST_F(GifFormat, TransparentIndexed)
|
||||
doc->setFilename(fn);
|
||||
|
||||
Palette* pal = sprite->palette(frame_t(0));
|
||||
pal->setEntry(0, rgb(255, 255, 255));
|
||||
pal->setEntry(1, rgb(255, 13, 254));
|
||||
pal->setEntry(2, rgb(129, 255, 32));
|
||||
pal->setEntry(3, rgb(0, 0, 255));
|
||||
pal->setEntry(0, rgba(255, 255, 255, 255));
|
||||
pal->setEntry(1, rgba(255, 13, 254, 255));
|
||||
pal->setEntry(2, rgba(129, 255, 32, 255));
|
||||
pal->setEntry(3, rgba(0, 0, 255, 255));
|
||||
|
||||
LayerImage* layer = dynamic_cast<LayerImage*>(sprite->folder()->getFirstLayer());
|
||||
ASSERT_NE((LayerImage*)NULL, layer);
|
||||
@ -161,10 +161,10 @@ TEST_F(GifFormat, TransparentIndexed)
|
||||
EXPECT_FALSE(layer->isBackground());
|
||||
|
||||
Palette* pal = sprite->palette(frame_t(0));
|
||||
EXPECT_EQ(rgb(255, 255, 255), pal->getEntry(0));
|
||||
EXPECT_EQ(rgb(255, 13, 254), pal->getEntry(1));
|
||||
EXPECT_EQ(rgb(129, 255, 32), pal->getEntry(2));
|
||||
EXPECT_EQ(rgb(0, 0, 255), pal->getEntry(3));
|
||||
EXPECT_EQ(rgba(255, 255, 255, 255), pal->getEntry(0));
|
||||
EXPECT_EQ(rgba(255, 13, 254, 255), pal->getEntry(1));
|
||||
EXPECT_EQ(rgba(129, 255, 32, 255), pal->getEntry(2));
|
||||
EXPECT_EQ(rgba(0, 0, 255, 255), pal->getEntry(3));
|
||||
|
||||
Image* image = layer->cel(frame_t(0))->image();
|
||||
EXPECT_EQ(0, sprite->transparentColor());
|
||||
@ -192,9 +192,9 @@ TEST_F(GifFormat, TransparentRgbQuantization)
|
||||
|
||||
Image* image = layer->cel(frame_t(0))->image();
|
||||
image->putPixel(0, 0, rgba(0, 0, 0, 0));
|
||||
image->putPixel(0, 1, rgb(255, 0, 0));
|
||||
image->putPixel(1, 0, rgb(0, 255, 0));
|
||||
image->putPixel(1, 1, rgb(0, 0, 255));
|
||||
image->putPixel(0, 1, rgba(255, 0, 0, 255));
|
||||
image->putPixel(1, 0, rgba(0, 255, 0, 255));
|
||||
image->putPixel(1, 1, rgba(0, 0, 255, 255));
|
||||
|
||||
save_document(&m_ctx, doc);
|
||||
|
||||
@ -213,9 +213,9 @@ TEST_F(GifFormat, TransparentRgbQuantization)
|
||||
Image* image = layer->cel(frame_t(0))->image();
|
||||
EXPECT_EQ(0, sprite->transparentColor());
|
||||
EXPECT_EQ(0, image->getPixel(0, 0));
|
||||
EXPECT_EQ(rgb(255, 0, 0), pal->getEntry(image->getPixel(0, 1)));
|
||||
EXPECT_EQ(rgb(0, 255, 0), pal->getEntry(image->getPixel(1, 0)));
|
||||
EXPECT_EQ(rgb(0, 0, 255), pal->getEntry(image->getPixel(1, 1)));
|
||||
EXPECT_EQ(rgba(255, 0, 0, 255), pal->getEntry(image->getPixel(0, 1)));
|
||||
EXPECT_EQ(rgba(0, 255, 0, 255), pal->getEntry(image->getPixel(1, 0)));
|
||||
EXPECT_EQ(rgba(0, 0, 255, 255), pal->getEntry(image->getPixel(1, 1)));
|
||||
|
||||
doc->close();
|
||||
delete doc;
|
||||
@ -237,10 +237,10 @@ TEST_F(GifFormat, OpaqueRgbQuantization)
|
||||
EXPECT_NE((LayerImage*)NULL, sprite->backgroundLayer());
|
||||
|
||||
Image* image = layer->cel(frame_t(0))->image();
|
||||
image->putPixel(0, 0, rgb(0, 0, 0));
|
||||
image->putPixel(0, 1, rgb(255, 0, 0));
|
||||
image->putPixel(1, 0, rgb(0, 255, 0));
|
||||
image->putPixel(1, 1, rgb(0, 0, 255));
|
||||
image->putPixel(0, 0, rgba(0, 0, 0, 255));
|
||||
image->putPixel(0, 1, rgba(255, 0, 0, 255));
|
||||
image->putPixel(1, 0, rgba(0, 255, 0, 255));
|
||||
image->putPixel(1, 1, rgba(0, 0, 255, 255));
|
||||
|
||||
save_document(&m_ctx, doc);
|
||||
|
||||
@ -260,10 +260,10 @@ TEST_F(GifFormat, OpaqueRgbQuantization)
|
||||
Palette* pal = sprite->palette(frame_t(0));
|
||||
Image* image = layer->cel(frame_t(0))->image();
|
||||
EXPECT_EQ(0, sprite->transparentColor());
|
||||
EXPECT_EQ(rgb(0, 0, 0), pal->getEntry(image->getPixel(0, 0)));
|
||||
EXPECT_EQ(rgb(255, 0, 0), pal->getEntry(image->getPixel(0, 1)));
|
||||
EXPECT_EQ(rgb(0, 255, 0), pal->getEntry(image->getPixel(1, 0)));
|
||||
EXPECT_EQ(rgb(0, 0, 255), pal->getEntry(image->getPixel(1, 1)));
|
||||
EXPECT_EQ(rgba(0, 0, 0, 255), pal->getEntry(image->getPixel(0, 0)));
|
||||
EXPECT_EQ(rgba(255, 0, 0, 255), pal->getEntry(image->getPixel(0, 1)));
|
||||
EXPECT_EQ(rgba(0, 255, 0, 255), pal->getEntry(image->getPixel(1, 0)));
|
||||
EXPECT_EQ(rgba(0, 0, 255, 255), pal->getEntry(image->getPixel(1, 1)));
|
||||
|
||||
doc->close();
|
||||
delete doc;
|
||||
|
@ -24,7 +24,6 @@
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "gfx/point.h"
|
||||
#include "gfx/rect.h"
|
||||
#include "doc/blend.h"
|
||||
#include "doc/image.h"
|
||||
#include "doc/palette.h"
|
||||
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include "app/resource_finder.h"
|
||||
#include "base/fs.h"
|
||||
#include "base/path.h"
|
||||
#include "doc/blend.h"
|
||||
#include "doc/image.h"
|
||||
#include "doc/palette.h"
|
||||
#include "doc/sprite.h"
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "app/modules/palettes.h"
|
||||
#include "app/tools/shade_table.h"
|
||||
#include "app/tools/shading_options.h"
|
||||
#include "doc/blend_funcs.h"
|
||||
#include "doc/image_impl.h"
|
||||
#include "doc/palette.h"
|
||||
#include "doc/rgbmap.h"
|
||||
@ -181,7 +182,7 @@ private:
|
||||
|
||||
template<>
|
||||
void LockAlphaInkProcessing<RgbTraits>::processPixel(int x, int y) {
|
||||
color_t result = rgba_blend_normal(*m_srcAddress, m_color, m_opacity);
|
||||
color_t result = rgba_blender_normal(*m_srcAddress, m_color, m_opacity);
|
||||
*m_dstAddress = rgba(
|
||||
rgba_getr(result),
|
||||
rgba_getg(result),
|
||||
@ -191,7 +192,7 @@ void LockAlphaInkProcessing<RgbTraits>::processPixel(int x, int y) {
|
||||
|
||||
template<>
|
||||
void LockAlphaInkProcessing<GrayscaleTraits>::processPixel(int x, int y) {
|
||||
color_t result = graya_blend_normal(*m_srcAddress, m_color, m_opacity);
|
||||
color_t result = graya_blender_normal(*m_srcAddress, m_color, m_opacity);
|
||||
*m_dstAddress = graya(
|
||||
graya_getv(result),
|
||||
graya_geta(*m_srcAddress));
|
||||
@ -225,12 +226,12 @@ private:
|
||||
|
||||
template<>
|
||||
void TransparentInkProcessing<RgbTraits>::processPixel(int x, int y) {
|
||||
*m_dstAddress = rgba_blend_normal(*m_srcAddress, m_color, m_opacity);
|
||||
*m_dstAddress = rgba_blender_normal(*m_srcAddress, m_color, m_opacity);
|
||||
}
|
||||
|
||||
template<>
|
||||
void TransparentInkProcessing<GrayscaleTraits>::processPixel(int x, int y) {
|
||||
*m_dstAddress = graya_blend_normal(*m_srcAddress, m_color, m_opacity);
|
||||
*m_dstAddress = graya_blender_normal(*m_srcAddress, m_color, m_opacity);
|
||||
}
|
||||
|
||||
template<>
|
||||
@ -244,7 +245,7 @@ public:
|
||||
}
|
||||
|
||||
void processPixel(int x, int y) {
|
||||
color_t c = rgba_blend_normal(m_palette->getEntry(*m_srcAddress), m_color, m_opacity);
|
||||
color_t c = rgba_blender_normal(m_palette->getEntry(*m_srcAddress), m_color, m_opacity);
|
||||
*m_dstAddress = m_rgbmap->mapColor(rgba_getr(c),
|
||||
rgba_getg(c),
|
||||
rgba_getb(c));
|
||||
@ -472,7 +473,7 @@ void ReplaceInkProcessing<RgbTraits>::processPixel(int x, int y) {
|
||||
if ((rgba_geta(src) == 0 && rgba_geta(m_color1) == 0) ||
|
||||
(rgba_geta(src) > 0 && rgba_geta(m_color1) > 0 &&
|
||||
((src & rgba_rgb_mask) == (m_color1 & rgba_rgb_mask)))) {
|
||||
*m_dstAddress = rgba_blend_merge(src, m_color2, m_opacity);
|
||||
*m_dstAddress = rgba_blender_merge(src, m_color2, m_opacity);
|
||||
}
|
||||
}
|
||||
|
||||
@ -483,7 +484,7 @@ void ReplaceInkProcessing<GrayscaleTraits>::processPixel(int x, int y) {
|
||||
if ((graya_geta(src) == 0 && graya_geta(m_color1) == 0) ||
|
||||
(graya_geta(src) > 0 && graya_geta(m_color1) > 0 &&
|
||||
((src & graya_v_mask) == (m_color1 & graya_v_mask)))) {
|
||||
*m_dstAddress = graya_blend_merge(src, m_color2, m_opacity);
|
||||
*m_dstAddress = graya_blender_merge(src, m_color2, m_opacity);
|
||||
}
|
||||
}
|
||||
|
||||
@ -505,7 +506,7 @@ public:
|
||||
if (m_opacity == 255)
|
||||
*m_dstAddress = m_color2;
|
||||
else {
|
||||
color_t c = rgba_blend_normal(
|
||||
color_t c = rgba_blender_normal(
|
||||
m_palette->getEntry(*m_srcAddress), m_color2, m_opacity);
|
||||
|
||||
*m_dstAddress = m_rgbmap->mapColor(
|
||||
@ -586,14 +587,14 @@ template<>
|
||||
void JumbleInkProcessing<RgbTraits>::processPixel(int x, int y)
|
||||
{
|
||||
pickColorFromArea(x, y);
|
||||
*m_dstAddress = rgba_blend_merge(*m_srcAddress, m_color, m_opacity);
|
||||
*m_dstAddress = rgba_blender_merge(*m_srcAddress, m_color, m_opacity);
|
||||
}
|
||||
|
||||
template<>
|
||||
void JumbleInkProcessing<GrayscaleTraits>::processPixel(int x, int y)
|
||||
{
|
||||
pickColorFromArea(x, y);
|
||||
*m_dstAddress = graya_blend_merge(*m_srcAddress, m_color, m_opacity);
|
||||
*m_dstAddress = graya_blender_merge(*m_srcAddress, m_color, m_opacity);
|
||||
}
|
||||
|
||||
template<>
|
||||
@ -602,9 +603,9 @@ void JumbleInkProcessing<IndexedTraits>::processPixel(int x, int y)
|
||||
pickColorFromArea(x, y);
|
||||
|
||||
color_t tc = (m_color != 0 ? m_palette->getEntry(m_color): 0);
|
||||
color_t c = rgba_blend_merge(*m_srcAddress != 0 ?
|
||||
m_palette->getEntry(*m_srcAddress): 0,
|
||||
tc, m_opacity);
|
||||
color_t c = rgba_blender_merge(*m_srcAddress != 0 ?
|
||||
m_palette->getEntry(*m_srcAddress): 0,
|
||||
tc, m_opacity);
|
||||
|
||||
if (rgba_geta(c) >= 128)
|
||||
*m_dstAddress = m_rgbmap->mapColor(rgba_getr(c),
|
||||
@ -670,12 +671,12 @@ private:
|
||||
|
||||
template<>
|
||||
void XorInkProcessing<RgbTraits>::processPixel(int x, int y) {
|
||||
*m_dstAddress = rgba_blend_blackandwhite(*m_srcAddress, m_color, 255);
|
||||
*m_dstAddress = rgba_blender_neg_bw(*m_srcAddress, m_color, 255);
|
||||
}
|
||||
|
||||
template<>
|
||||
void XorInkProcessing<GrayscaleTraits>::processPixel(int x, int y) {
|
||||
*m_dstAddress = graya_blend_blackandwhite(*m_srcAddress, m_color, 255);
|
||||
*m_dstAddress = graya_blender_neg_bw(*m_srcAddress, m_color, 255);
|
||||
}
|
||||
|
||||
template<>
|
||||
@ -688,7 +689,7 @@ public:
|
||||
}
|
||||
|
||||
void processPixel(int x, int y) {
|
||||
color_t c = rgba_blend_blackandwhite(m_palette->getEntry(*m_srcAddress), m_color, 255);
|
||||
color_t c = rgba_blender_neg_bw(m_palette->getEntry(*m_srcAddress), m_color, 255);
|
||||
*m_dstAddress = m_rgbmap->mapColor(rgba_getr(c),
|
||||
rgba_getg(c),
|
||||
rgba_getb(c));
|
||||
@ -771,7 +772,7 @@ void BrushInkProcessing<RgbTraits>::processPixel(int x, int y) {
|
||||
return;
|
||||
}
|
||||
|
||||
*m_dstAddress = rgba_blend_normal(*m_srcAddress, c, m_opacity);
|
||||
*m_dstAddress = rgba_blender_normal(*m_srcAddress, c, m_opacity);
|
||||
}
|
||||
|
||||
template<>
|
||||
@ -807,7 +808,7 @@ void BrushInkProcessing<GrayscaleTraits>::processPixel(int x, int y) {
|
||||
return;
|
||||
}
|
||||
|
||||
*m_dstAddress = graya_blend_normal(*m_srcAddress, c, m_opacity);
|
||||
*m_dstAddress = graya_blender_normal(*m_srcAddress, c, m_opacity);
|
||||
}
|
||||
|
||||
template<>
|
||||
|
@ -187,7 +187,8 @@ void Editor::drawBrushPreview(const gfx::Point& pos)
|
||||
cel ? cel->opacity(): 255);
|
||||
m_document->setExtraCelType(render::ExtraType::NONE);
|
||||
m_document->setExtraCelBlendMode(
|
||||
m_layer ? static_cast<LayerImage*>(m_layer)->getBlendMode(): BLEND_MODE_NORMAL);
|
||||
(m_layer ? static_cast<LayerImage*>(m_layer)->blendMode():
|
||||
BlendMode::NORMAL));
|
||||
|
||||
// In 'indexed' images, if the current color is 0, we have to use
|
||||
// a different mask color (different from 0) to draw the extra layer
|
||||
@ -202,7 +203,7 @@ void Editor::drawBrushPreview(const gfx::Point& pos)
|
||||
render::Render().renderLayer(
|
||||
extraImage, m_layer, m_frame,
|
||||
gfx::Clip(0, 0, brushBounds),
|
||||
BLEND_MODE_COPY);
|
||||
BlendMode::SRC);
|
||||
|
||||
// This extra cel is a patch for the current layer/frame
|
||||
m_document->setExtraCelType(render::ExtraType::PATCH);
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include "app/ui/editor/scoped_cursor.h"
|
||||
#include "app/ui/keyboard_shortcuts.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "doc/blend.h"
|
||||
#include "ui/message.h"
|
||||
#include "ui/system.h"
|
||||
|
||||
|
@ -785,13 +785,13 @@ void Editor::flashCurrentLayer()
|
||||
|
||||
clear_image(flash_image, flash_image->maskColor());
|
||||
copy_image(flash_image, src_image, x, y);
|
||||
m_document->setExtraCelBlendMode(BLEND_MODE_BLACKANDWHITE);
|
||||
m_document->setExtraCelBlendMode(BlendMode::NEG_BW);
|
||||
|
||||
drawSpriteClipped(gfx::Region(
|
||||
gfx::Rect(0, 0, m_sprite->width(), m_sprite->height())));
|
||||
gui_feedback();
|
||||
|
||||
m_document->setExtraCelBlendMode(BLEND_MODE_NORMAL);
|
||||
m_document->setExtraCelBlendMode(BlendMode::NORMAL);
|
||||
m_document->destroyExtraCel();
|
||||
invalidate();
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ PixelsMovement::PixelsMovement(Context* context,
|
||||
m_document->prepareExtraCel(m_sprite->bounds(), opacity);
|
||||
m_document->setExtraCelType(render::ExtraType::COMPOSITE);
|
||||
m_document->setExtraCelBlendMode(
|
||||
static_cast<LayerImage*>(m_layer)->getBlendMode());
|
||||
static_cast<LayerImage*>(m_layer)->blendMode());
|
||||
|
||||
redrawExtraImage();
|
||||
|
||||
@ -465,7 +465,7 @@ void PixelsMovement::stampImage()
|
||||
expand.getDestCanvas(), image,
|
||||
-expand.getCel()->x(),
|
||||
-expand.getCel()->y(),
|
||||
cel->opacity(), BLEND_MODE_NORMAL);
|
||||
cel->opacity(), BlendMode::NORMAL);
|
||||
|
||||
expand.commit();
|
||||
}
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include "app/ui/skin/style.h"
|
||||
#include "app/ui/status_bar.h"
|
||||
#include "app/util/clipboard.h"
|
||||
#include "doc/blend.h"
|
||||
#include "doc/image.h"
|
||||
#include "doc/palette.h"
|
||||
#include "doc/remap.h"
|
||||
|
@ -10,7 +10,7 @@ add_library(doc-lib
|
||||
algorithm/rotate.cpp
|
||||
algorithm/rotsprite.cpp
|
||||
algorithm/shrink_bounds.cpp
|
||||
blend.cpp
|
||||
blend_funcs.cpp
|
||||
brush.cpp
|
||||
cel.cpp
|
||||
cel_data.cpp
|
||||
|
@ -12,7 +12,7 @@
|
||||
#endif
|
||||
|
||||
#include "fixmath/fixmath.h"
|
||||
#include "doc/blend.h"
|
||||
#include "doc/blend_funcs.h"
|
||||
#include "doc/image_impl.h"
|
||||
#include "doc/primitives.h"
|
||||
#include "doc/primitives_fast.h"
|
||||
@ -49,11 +49,11 @@ static void image_scale_tpl(Image* dst, const Image* src, int x, int y, int w, i
|
||||
}
|
||||
|
||||
static color_t rgba_blender(color_t back, color_t front) {
|
||||
return rgba_blenders[BLEND_MODE_NORMAL](back, front, 255);
|
||||
return rgba_blender_normal(back, front, 255);
|
||||
}
|
||||
|
||||
static color_t grayscale_blender(color_t back, color_t front) {
|
||||
return graya_blenders[BLEND_MODE_NORMAL](back, front, 255);
|
||||
return graya_blender_normal(back, front, 255);
|
||||
}
|
||||
|
||||
class if_blender {
|
||||
@ -182,7 +182,6 @@ protected:
|
||||
class RgbDelegate : public GenericDelegate<RgbTraits> {
|
||||
public:
|
||||
RgbDelegate(color_t mask_color) {
|
||||
m_blender = rgba_blenders[BLEND_MODE_NORMAL];
|
||||
m_mask_color = mask_color;
|
||||
}
|
||||
|
||||
@ -191,20 +190,18 @@ public:
|
||||
|
||||
int c = spr->getPixel(spr_x, spr_y);
|
||||
if ((rgba_geta(m_mask_color) == 0) || ((c & rgba_rgb_mask) != (m_mask_color & rgba_rgb_mask)))
|
||||
*m_it = m_blender(*m_it, c, 255);
|
||||
*m_it = rgba_blender_normal(*m_it, c, 255);
|
||||
|
||||
++m_it;
|
||||
}
|
||||
|
||||
private:
|
||||
BLEND_COLOR m_blender;
|
||||
color_t m_mask_color;
|
||||
};
|
||||
|
||||
class GrayscaleDelegate : public GenericDelegate<GrayscaleTraits> {
|
||||
public:
|
||||
GrayscaleDelegate(color_t mask_color) {
|
||||
m_blender = graya_blenders[BLEND_MODE_NORMAL];
|
||||
m_mask_color = mask_color;
|
||||
}
|
||||
|
||||
@ -213,13 +210,12 @@ public:
|
||||
|
||||
int c = spr->getPixel(spr_x, spr_y);
|
||||
if ((graya_geta(m_mask_color) == 0) || ((c & graya_v_mask) != (m_mask_color & graya_v_mask)))
|
||||
*m_it = m_blender(*m_it, c, 255);
|
||||
*m_it = graya_blender_normal(*m_it, c, 255);
|
||||
|
||||
++m_it;
|
||||
}
|
||||
|
||||
private:
|
||||
BLEND_COLOR m_blender;
|
||||
color_t m_mask_color;
|
||||
};
|
||||
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
#include "base/unique_ptr.h"
|
||||
#include "doc/algorithm/rotate.h"
|
||||
#include "doc/blend.h"
|
||||
#include "doc/image_impl.h"
|
||||
#include "doc/primitives.h"
|
||||
|
||||
@ -177,7 +176,7 @@ void rotsprite_image(Image* bmp, Image* spr,
|
||||
spr_copy->copy(spr, gfx::Clip(spr->bounds()));
|
||||
|
||||
for (int i=0; i<3; ++i) {
|
||||
tmp_copy->clear(maskColor);
|
||||
clear_image(tmp_copy, maskColor);
|
||||
image_scale2x(tmp_copy, spr_copy, spr->width()*(1<<i), spr->height()*(1<<i));
|
||||
spr_copy->copy(tmp_copy, gfx::Clip(tmp_copy->bounds()));
|
||||
}
|
||||
|
@ -1,317 +0,0 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2001-2014 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "doc/blend.h"
|
||||
#include "doc/image.h"
|
||||
|
||||
namespace doc {
|
||||
|
||||
BLEND_COLOR rgba_blenders[] =
|
||||
{
|
||||
rgba_blend_normal,
|
||||
rgba_blend_copy,
|
||||
rgba_blend_merge,
|
||||
rgba_blend_red_tint,
|
||||
rgba_blend_blue_tint,
|
||||
rgba_blend_blackandwhite,
|
||||
};
|
||||
|
||||
BLEND_COLOR graya_blenders[] =
|
||||
{
|
||||
graya_blend_normal,
|
||||
graya_blend_copy,
|
||||
graya_blend_copy,
|
||||
graya_blend_copy,
|
||||
graya_blend_copy,
|
||||
graya_blend_blackandwhite,
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// RGB blenders
|
||||
|
||||
int rgba_blend_normal(int back, int front, int opacity)
|
||||
{
|
||||
int t;
|
||||
|
||||
if ((back & 0xff000000) == 0) {
|
||||
return
|
||||
(front & 0xffffff) |
|
||||
(INT_MULT(rgba_geta(front), opacity, t) << rgba_a_shift);
|
||||
}
|
||||
else if ((front & 0xff000000) == 0) {
|
||||
return back;
|
||||
}
|
||||
else {
|
||||
int B_r, B_g, B_b, B_a;
|
||||
int F_r, F_g, F_b, F_a;
|
||||
int D_r, D_g, D_b, D_a;
|
||||
|
||||
B_r = rgba_getr(back);
|
||||
B_g = rgba_getg(back);
|
||||
B_b = rgba_getb(back);
|
||||
B_a = rgba_geta(back);
|
||||
|
||||
F_r = rgba_getr(front);
|
||||
F_g = rgba_getg(front);
|
||||
F_b = rgba_getb(front);
|
||||
F_a = rgba_geta(front);
|
||||
F_a = INT_MULT(F_a, opacity, t);
|
||||
|
||||
D_a = B_a + F_a - INT_MULT(B_a, F_a, t);
|
||||
D_r = B_r + (F_r-B_r) * F_a / D_a;
|
||||
D_g = B_g + (F_g-B_g) * F_a / D_a;
|
||||
D_b = B_b + (F_b-B_b) * F_a / D_a;
|
||||
|
||||
return rgba(D_r, D_g, D_b, D_a);
|
||||
}
|
||||
}
|
||||
|
||||
int rgba_blend_copy(int back, int front, int opacity)
|
||||
{
|
||||
return front;
|
||||
}
|
||||
|
||||
int rgba_blend_forpath(int back, int front, int opacity)
|
||||
{
|
||||
int t, F_r, F_g, F_b, F_a;
|
||||
|
||||
F_r = rgba_getr(front);
|
||||
F_g = rgba_getg(front);
|
||||
F_b = rgba_getb(front);
|
||||
F_a = rgba_geta(front);
|
||||
F_a = INT_MULT(F_a, opacity, t);
|
||||
|
||||
return rgba(F_r, F_g, F_b, F_a);
|
||||
}
|
||||
|
||||
int rgba_blend_merge(int back, int front, int opacity)
|
||||
{
|
||||
int B_r, B_g, B_b, B_a;
|
||||
int F_r, F_g, F_b, F_a;
|
||||
int D_r, D_g, D_b, D_a;
|
||||
int t;
|
||||
|
||||
B_r = rgba_getr(back);
|
||||
B_g = rgba_getg(back);
|
||||
B_b = rgba_getb(back);
|
||||
B_a = rgba_geta(back);
|
||||
|
||||
F_r = rgba_getr(front);
|
||||
F_g = rgba_getg(front);
|
||||
F_b = rgba_getb(front);
|
||||
F_a = rgba_geta(front);
|
||||
|
||||
if (B_a == 0) {
|
||||
D_r = F_r;
|
||||
D_g = F_g;
|
||||
D_b = F_b;
|
||||
}
|
||||
else if (F_a == 0) {
|
||||
D_r = B_r;
|
||||
D_g = B_g;
|
||||
D_b = B_b;
|
||||
}
|
||||
else {
|
||||
D_r = B_r + INT_MULT((F_r - B_r), opacity, t);
|
||||
D_g = B_g + INT_MULT((F_g - B_g), opacity, t);
|
||||
D_b = B_b + INT_MULT((F_b - B_b), opacity, t);
|
||||
}
|
||||
D_a = B_a + INT_MULT((F_a - B_a), opacity, t);
|
||||
if (D_a == 0)
|
||||
D_r = D_g = D_b = 0;
|
||||
|
||||
return rgba(D_r, D_g, D_b, D_a);
|
||||
}
|
||||
|
||||
// Part of this code comes from pixman library
|
||||
// Copyright (C) 2000 Keith Packard, member of The XFree86 Project, Inc.
|
||||
// 2005 Lars Knoll & Zack Rusin, Trolltech
|
||||
|
||||
#define ONE_HALF 0x80
|
||||
#define G_SHIFT 8
|
||||
#define DIV_ONE_UN8(x) \
|
||||
(((x) + ONE_HALF + (((x) + ONE_HALF) >> G_SHIFT)) >> G_SHIFT)
|
||||
|
||||
static inline uint32_t
|
||||
blend_overlay(uint32_t d, uint32_t ad, uint32_t s, uint32_t as)
|
||||
{
|
||||
uint32_t r;
|
||||
|
||||
if (2 * d < ad)
|
||||
r = 2 * s * d;
|
||||
else
|
||||
r = as * ad - 2 * (ad - d) * (as - s);
|
||||
|
||||
return DIV_ONE_UN8(r);
|
||||
}
|
||||
|
||||
int rgba_blend_color_tint(int back, int front, int opacity, int color)
|
||||
{
|
||||
int F_r, F_g, F_b, F_a;
|
||||
int B_r, B_g, B_b, B_a;
|
||||
|
||||
B_r = rgba_getr(front);
|
||||
B_g = rgba_getg(front);
|
||||
B_b = rgba_getb(front);
|
||||
B_a = rgba_geta(front);
|
||||
|
||||
F_r = rgba_getr(color);
|
||||
F_g = rgba_getg(color);
|
||||
F_b = rgba_getb(color);
|
||||
F_a = rgba_geta(color);
|
||||
|
||||
F_r = blend_overlay(B_r, B_a, F_r, F_a);
|
||||
F_g = blend_overlay(B_g, B_a, F_g, F_a);
|
||||
F_b = blend_overlay(B_b, B_a, F_b, F_a);
|
||||
|
||||
F_a = (B_a * (~B_a) + F_a * (~F_a)) / 255;
|
||||
F_a += DIV_ONE_UN8(F_a * B_a);
|
||||
|
||||
return rgba_blend_normal(back, rgba(F_r, F_g, F_b, F_a), opacity);
|
||||
}
|
||||
|
||||
int rgba_blend_red_tint(int back, int front, int opacity)
|
||||
{
|
||||
return rgba_blend_color_tint(back, front, opacity, rgba(255, 0, 0, 128));
|
||||
}
|
||||
|
||||
int rgba_blend_blue_tint(int back, int front, int opacity)
|
||||
{
|
||||
return rgba_blend_color_tint(back, front, opacity, rgba(0, 0, 255, 128));
|
||||
}
|
||||
|
||||
int rgba_blend_blackandwhite(int back, int front, int opacity)
|
||||
{
|
||||
int B_r, B_g, B_b, B_a;
|
||||
int D_v;
|
||||
|
||||
B_a = rgba_geta(back);
|
||||
if (B_a == 0)
|
||||
return front;
|
||||
|
||||
B_r = rgba_getr(back);
|
||||
B_g = rgba_getg(back);
|
||||
B_b = rgba_getb(back);
|
||||
|
||||
if ((B_r*30 + B_g*59 + B_b*11)/100 < 128)
|
||||
D_v = 255;
|
||||
else
|
||||
D_v = 0;
|
||||
|
||||
return rgba(D_v, D_v, D_v, 255);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Grayscale blenders
|
||||
|
||||
int graya_blend_normal(int back, int front, int opacity)
|
||||
{
|
||||
int t;
|
||||
|
||||
if ((back & 0xff00) == 0) {
|
||||
return
|
||||
(front & 0xff) |
|
||||
(INT_MULT(graya_geta (front), opacity, t) << graya_a_shift);
|
||||
}
|
||||
else if ((front & 0xff00) == 0) {
|
||||
return back;
|
||||
}
|
||||
else {
|
||||
int B_g, B_a;
|
||||
int F_g, F_a;
|
||||
int D_g, D_a;
|
||||
|
||||
B_g = graya_getv(back);
|
||||
B_a = graya_geta(back);
|
||||
|
||||
F_g = graya_getv(front);
|
||||
F_a = graya_geta(front);
|
||||
F_a = INT_MULT(F_a, opacity, t);
|
||||
|
||||
D_a = B_a + F_a - INT_MULT(B_a, F_a, t);
|
||||
D_g = B_g + (F_g-B_g) * F_a / D_a;
|
||||
|
||||
return graya(D_g, D_a);
|
||||
}
|
||||
}
|
||||
|
||||
int graya_blend_copy(int back, int front, int opacity)
|
||||
{
|
||||
return front;
|
||||
}
|
||||
|
||||
int graya_blend_forpath(int back, int front, int opacity)
|
||||
{
|
||||
int t, F_k, F_a;
|
||||
|
||||
F_k = graya_getv(front);
|
||||
F_a = graya_geta(front);
|
||||
F_a = INT_MULT(F_a, opacity, t);
|
||||
|
||||
return graya(F_k, F_a);
|
||||
}
|
||||
|
||||
int graya_blend_merge(int back, int front, int opacity)
|
||||
{
|
||||
int B_k, B_a;
|
||||
int F_k, F_a;
|
||||
int D_k, D_a;
|
||||
int t;
|
||||
|
||||
B_k = graya_getv(back);
|
||||
B_a = graya_geta(back);
|
||||
|
||||
F_k = graya_getv(front);
|
||||
F_a = graya_geta(front);
|
||||
|
||||
if (B_a == 0) {
|
||||
D_k = F_k;
|
||||
}
|
||||
else if (F_a == 0) {
|
||||
D_k = B_k;
|
||||
}
|
||||
else {
|
||||
D_k = B_k + INT_MULT((F_k-B_k), opacity, t);
|
||||
}
|
||||
D_a = B_a + INT_MULT((F_a-B_a), opacity, t);
|
||||
if (D_a == 0)
|
||||
D_k = 0;
|
||||
|
||||
return graya(D_k, D_a);
|
||||
}
|
||||
|
||||
int graya_blend_blackandwhite(int back, int front, int opacity)
|
||||
{
|
||||
int B_k, B_a;
|
||||
int D_k;
|
||||
|
||||
B_a = graya_geta(back);
|
||||
if (B_a == 0)
|
||||
return front;
|
||||
|
||||
B_k = graya_getv(back);
|
||||
|
||||
if (B_k < 128)
|
||||
D_k = 255;
|
||||
else
|
||||
D_k = 0;
|
||||
|
||||
return graya(D_k, 255);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Indexed blenders
|
||||
|
||||
int indexed_blend_direct(int back, int front, int opacity)
|
||||
{
|
||||
return front;
|
||||
}
|
||||
|
||||
} // namespace doc
|
@ -1,49 +0,0 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2001-2014 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifndef DOC_BLEND_H_INCLUDED
|
||||
#define DOC_BLEND_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#define INT_MULT(a, b, t) \
|
||||
((t) = (a) * (b) + 0x80, ((((t) >> 8) + (t)) >> 8))
|
||||
|
||||
namespace doc {
|
||||
|
||||
enum {
|
||||
BLEND_MODE_NORMAL,
|
||||
BLEND_MODE_COPY,
|
||||
BLEND_MODE_MERGE,
|
||||
BLEND_MODE_RED_TINT,
|
||||
BLEND_MODE_BLUE_TINT,
|
||||
BLEND_MODE_BLACKANDWHITE,
|
||||
BLEND_MODE_MAX,
|
||||
};
|
||||
|
||||
typedef int (*BLEND_COLOR)(int back, int front, int opacity);
|
||||
|
||||
extern BLEND_COLOR rgba_blenders[];
|
||||
extern BLEND_COLOR graya_blenders[];
|
||||
|
||||
int rgba_blend_normal(int back, int front, int opacity);
|
||||
int rgba_blend_copy(int back, int front, int opacity);
|
||||
int rgba_blend_forpath(int back, int front, int opacity);
|
||||
int rgba_blend_merge(int back, int front, int opacity);
|
||||
int rgba_blend_red_tint(int back, int front, int opacity);
|
||||
int rgba_blend_blue_tint(int back, int front, int opacity);
|
||||
int rgba_blend_blackandwhite(int back, int front, int opacity);
|
||||
|
||||
int graya_blend_normal(int back, int front, int opacity);
|
||||
int graya_blend_copy(int back, int front, int opacity);
|
||||
int graya_blend_forpath(int back, int front, int opacity);
|
||||
int graya_blend_merge(int back, int front, int opacity);
|
||||
int graya_blend_blackandwhite(int back, int front, int opacity);
|
||||
|
||||
int indexed_blend_direct(int back, int front, int opacity);
|
||||
|
||||
} // namespace doc
|
||||
|
||||
#endif
|
661
src/doc/blend_funcs.cpp
Normal file
661
src/doc/blend_funcs.cpp
Normal file
@ -0,0 +1,661 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2001-2015 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
//
|
||||
// --
|
||||
//
|
||||
// Some references about alpha compositing and blend modes:
|
||||
//
|
||||
// http://dev.w3.org/fxtf/compositing-1/
|
||||
// http://www.adobe.com/devnet/pdf/pdf_reference.html
|
||||
//
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "doc/blend_funcs.h"
|
||||
|
||||
#include "doc/blend_internals.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace {
|
||||
|
||||
#define blend_multiply(b, s, t) (MUL_UN8((b), (s), (t)))
|
||||
#define blend_screen(b, s, t) ((b) + (s) - MUL_UN8((b), (s), (t)))
|
||||
#define blend_overlay(b, s, t) (blend_hard_light(s, b, t))
|
||||
#define blend_darken(b, s) (MIN((b), (s)))
|
||||
#define blend_lighten(b, s) (MAX((b), (s)))
|
||||
#define blend_hard_light(b, s, t) ((s) < 128 ? \
|
||||
blend_multiply((b), (s)<<1, (t)): \
|
||||
blend_screen((b), ((s)<<1)-255, (t)))
|
||||
#define blend_difference(b, s) (ABS((b) - (s)))
|
||||
#define blend_exclusion(b, s, t) ((t) = MUL_UN8((b), (s), (t)), ((b) + (s) - 2*(t)))
|
||||
|
||||
inline uint32_t blend_color_dodge(uint32_t b, uint32_t s)
|
||||
{
|
||||
if (b == 0)
|
||||
return 0;
|
||||
|
||||
s = (255 - s);
|
||||
if (b >= s)
|
||||
return 255;
|
||||
else
|
||||
return DIV_UN8(b, s); // return b / (1-s)
|
||||
}
|
||||
|
||||
inline uint32_t blend_color_burn(uint32_t b, uint32_t s)
|
||||
{
|
||||
if (b == 255)
|
||||
return 255;
|
||||
|
||||
b = (255 - b);
|
||||
if (b >= s)
|
||||
return 0;
|
||||
else
|
||||
return 255 - DIV_UN8(b, s); // return 1 - ((1-b)/s)
|
||||
}
|
||||
|
||||
inline uint32_t blend_soft_light(uint32_t _b, uint32_t _s)
|
||||
{
|
||||
double b = _b / 255.0;
|
||||
double s = _s / 255.0;
|
||||
double r, d;
|
||||
|
||||
if (b <= 0.25)
|
||||
d = ((16*b-12)*b+4)*b;
|
||||
else
|
||||
d = std::sqrt(b);
|
||||
|
||||
if (s <= 0.5)
|
||||
r = b - (1.0 - 2.0*s) * b * (1.0 - b);
|
||||
else
|
||||
r = b - (1.0 - 2.0*s) * b * (1.0 - b);
|
||||
|
||||
return (uint32_t)(r * 255 + 0.5);
|
||||
}
|
||||
|
||||
} // annonymous namespace
|
||||
|
||||
namespace doc {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// RGB blenders
|
||||
|
||||
color_t rgba_blender_src(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
return src;
|
||||
}
|
||||
|
||||
color_t rgba_blender_merge(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int Br, Bg, Bb, Ba;
|
||||
int Sr, Sg, Sb, Sa;
|
||||
int Rr, Rg, Rb, Ra;
|
||||
int t;
|
||||
|
||||
Br = rgba_getr(backdrop);
|
||||
Bg = rgba_getg(backdrop);
|
||||
Bb = rgba_getb(backdrop);
|
||||
Ba = rgba_geta(backdrop);
|
||||
|
||||
Sr = rgba_getr(src);
|
||||
Sg = rgba_getg(src);
|
||||
Sb = rgba_getb(src);
|
||||
Sa = rgba_geta(src);
|
||||
|
||||
if (Ba == 0) {
|
||||
Rr = Sr;
|
||||
Rg = Sg;
|
||||
Rb = Sb;
|
||||
}
|
||||
else if (Sa == 0) {
|
||||
Rr = Br;
|
||||
Rg = Bg;
|
||||
Rb = Bb;
|
||||
}
|
||||
else {
|
||||
Rr = Br + MUL_UN8((Sr - Br), opacity, t);
|
||||
Rg = Bg + MUL_UN8((Sg - Bg), opacity, t);
|
||||
Rb = Bb + MUL_UN8((Sb - Bb), opacity, t);
|
||||
}
|
||||
Ra = Ba + MUL_UN8((Sa - Ba), opacity, t);
|
||||
if (Ra == 0)
|
||||
Rr = Rg = Rb = 0;
|
||||
|
||||
return rgba(Rr, Rg, Rb, Ra);
|
||||
}
|
||||
|
||||
color_t rgba_blender_neg_bw(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
if (!(backdrop & rgba_a_mask))
|
||||
return src;
|
||||
else if (rgba_luma(backdrop) < 128)
|
||||
return rgba(255, 255, 255, 255);
|
||||
else
|
||||
return rgba(0, 0, 0, 255);
|
||||
}
|
||||
|
||||
color_t rgba_blender_red_tint(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int v = rgba_luma(src);
|
||||
src = rgba(v, 0, 0, rgba_geta(src));
|
||||
return rgba_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t rgba_blender_blue_tint(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int v = rgba_luma(src);
|
||||
src = rgba(0, 0, v, rgba_geta(src));
|
||||
return rgba_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t rgba_blender_normal(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int t;
|
||||
|
||||
if ((backdrop & rgba_a_mask) == 0) {
|
||||
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) {
|
||||
return backdrop;
|
||||
}
|
||||
|
||||
int Br, Bg, Bb, Ba;
|
||||
int Sr, Sg, Sb, Sa;
|
||||
int Rr, Rg, Rb, Ra;
|
||||
|
||||
Br = rgba_getr(backdrop);
|
||||
Bg = rgba_getg(backdrop);
|
||||
Bb = rgba_getb(backdrop);
|
||||
Ba = rgba_geta(backdrop);
|
||||
|
||||
Sr = rgba_getr(src);
|
||||
Sg = rgba_getg(src);
|
||||
Sb = rgba_getb(src);
|
||||
Sa = rgba_geta(src);
|
||||
Sa = MUL_UN8(Sa, opacity, t);
|
||||
|
||||
Ra = Ba + Sa - MUL_UN8(Ba, Sa, t);
|
||||
Rr = Br + (Sr-Br) * Sa / Ra;
|
||||
Rg = Bg + (Sg-Bg) * Sa / Ra;
|
||||
Rb = Bb + (Sb-Bb) * Sa / Ra;
|
||||
|
||||
return rgba(Rr, Rg, Rb, Ra);
|
||||
}
|
||||
|
||||
color_t rgba_blender_multiply(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int t;
|
||||
int r = blend_multiply(rgba_getr(backdrop), rgba_getr(src), t);
|
||||
int g = blend_multiply(rgba_getg(backdrop), rgba_getg(src), t);
|
||||
int b = blend_multiply(rgba_getb(backdrop), rgba_getb(src), t);
|
||||
src = rgba(r, g, b, 0) | (src & rgba_a_mask);
|
||||
return rgba_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t rgba_blender_screen(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int t;
|
||||
int r = blend_screen(rgba_getr(backdrop), rgba_getr(src), t);
|
||||
int g = blend_screen(rgba_getg(backdrop), rgba_getg(src), t);
|
||||
int b = blend_screen(rgba_getb(backdrop), rgba_getb(src), t);
|
||||
src = rgba(r, g, b, 0) | (src & rgba_a_mask);
|
||||
return rgba_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t rgba_blender_overlay(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int t;
|
||||
int r = blend_overlay(rgba_getr(backdrop), rgba_getr(src), t);
|
||||
int g = blend_overlay(rgba_getg(backdrop), rgba_getg(src), t);
|
||||
int b = blend_overlay(rgba_getb(backdrop), rgba_getb(src), t);
|
||||
src = rgba(r, g, b, 0) | (src & rgba_a_mask);
|
||||
return rgba_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t rgba_blender_darken(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int r = blend_darken(rgba_getr(backdrop), rgba_getr(src));
|
||||
int g = blend_darken(rgba_getg(backdrop), rgba_getg(src));
|
||||
int b = blend_darken(rgba_getb(backdrop), rgba_getb(src));
|
||||
src = rgba(r, g, b, 0) | (src & rgba_a_mask);
|
||||
return rgba_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t rgba_blender_lighten(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int r = blend_lighten(rgba_getr(backdrop), rgba_getr(src));
|
||||
int g = blend_lighten(rgba_getg(backdrop), rgba_getg(src));
|
||||
int b = blend_lighten(rgba_getb(backdrop), rgba_getb(src));
|
||||
src = rgba(r, g, b, 0) | (src & rgba_a_mask);
|
||||
return rgba_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t rgba_blender_color_dodge(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int r = blend_color_dodge(rgba_getr(backdrop), rgba_getr(src));
|
||||
int g = blend_color_dodge(rgba_getg(backdrop), rgba_getg(src));
|
||||
int b = blend_color_dodge(rgba_getb(backdrop), rgba_getb(src));
|
||||
src = rgba(r, g, b, 0) | (src & rgba_a_mask);
|
||||
return rgba_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t rgba_blender_color_burn(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int r = blend_color_burn(rgba_getr(backdrop), rgba_getr(src));
|
||||
int g = blend_color_burn(rgba_getg(backdrop), rgba_getg(src));
|
||||
int b = blend_color_burn(rgba_getb(backdrop), rgba_getb(src));
|
||||
src = rgba(r, g, b, 0) | (src & rgba_a_mask);
|
||||
return rgba_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t rgba_blender_hard_light(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int t;
|
||||
int r = blend_hard_light(rgba_getr(backdrop), rgba_getr(src), t);
|
||||
int g = blend_hard_light(rgba_getg(backdrop), rgba_getg(src), t);
|
||||
int b = blend_hard_light(rgba_getb(backdrop), rgba_getb(src), t);
|
||||
src = rgba(r, g, b, 0) | (src & rgba_a_mask);
|
||||
return rgba_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t rgba_blender_soft_light(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int r = blend_soft_light(rgba_getr(backdrop), rgba_getr(src));
|
||||
int g = blend_soft_light(rgba_getg(backdrop), rgba_getg(src));
|
||||
int b = blend_soft_light(rgba_getb(backdrop), rgba_getb(src));
|
||||
src = rgba(r, g, b, 0) | (src & rgba_a_mask);
|
||||
return rgba_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t rgba_blender_difference(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int r = blend_difference(rgba_getr(backdrop), rgba_getr(src));
|
||||
int g = blend_difference(rgba_getg(backdrop), rgba_getg(src));
|
||||
int b = blend_difference(rgba_getb(backdrop), rgba_getb(src));
|
||||
src = rgba(r, g, b, 0) | (src & rgba_a_mask);
|
||||
return rgba_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t rgba_blender_exclusion(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int t;
|
||||
int r = blend_exclusion(rgba_getr(backdrop), rgba_getr(src), t);
|
||||
int g = blend_exclusion(rgba_getg(backdrop), rgba_getg(src), t);
|
||||
int b = blend_exclusion(rgba_getb(backdrop), rgba_getb(src), t);
|
||||
src = rgba(r, g, b, 0) | (src & rgba_a_mask);
|
||||
return rgba_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// HSV blenders
|
||||
|
||||
static double lum(double r, double g, double b)
|
||||
{
|
||||
return 0.3*r + 0.59*g + 0.11*b;
|
||||
}
|
||||
|
||||
static double sat(double r, double g, double b)
|
||||
{
|
||||
return MAX(r, MAX(g, b)) - MIN(r, MIN(g, b));
|
||||
}
|
||||
|
||||
static void clip_color(double& r, double& g, double& b)
|
||||
{
|
||||
double l = lum(r, g, b);
|
||||
double n = MIN(r, MIN(g, b));
|
||||
double x = MAX(r, MAX(g, b));
|
||||
|
||||
if (n < 0) {
|
||||
r = l + (((r - l) * l) / (l - n));
|
||||
g = l + (((g - l) * l) / (l - n));
|
||||
b = l + (((b - l) * l) / (l - n));
|
||||
}
|
||||
|
||||
if (x > 1) {
|
||||
r = l + (((r - l) * (1 - l)) / (x - l));
|
||||
g = l + (((g - l) * (1 - l)) / (x - l));
|
||||
b = l + (((b - l) * (1 - l)) / (x - l));
|
||||
}
|
||||
}
|
||||
|
||||
static void set_lum(double& r, double& g, double& b, double l)
|
||||
{
|
||||
double d = l - lum(r, g, b);
|
||||
r += d;
|
||||
g += d;
|
||||
b += d;
|
||||
clip_color(r, g, b);
|
||||
}
|
||||
|
||||
static void set_sat(double& r, double& g, double& b, double s)
|
||||
{
|
||||
double& min = MIN(r, MIN(g, b));
|
||||
double& mid = MID(r, g, b);
|
||||
double& max = MAX(r, MAX(g, b));
|
||||
|
||||
if (max > min) {
|
||||
mid = ((mid - min)*s) / (max - min);
|
||||
max = s;
|
||||
}
|
||||
else
|
||||
mid = max = 0;
|
||||
|
||||
min = 0;
|
||||
}
|
||||
|
||||
color_t rgba_blender_hsl_hue(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
double r = rgba_getr(backdrop)/255.0;
|
||||
double g = rgba_getg(backdrop)/255.0;
|
||||
double b = rgba_getb(backdrop)/255.0;
|
||||
double s = sat(r, g, b);
|
||||
double l = lum(r, g, b);
|
||||
|
||||
r = rgba_getr(src)/255.0;
|
||||
g = rgba_getg(src)/255.0;
|
||||
b = rgba_getb(src)/255.0;
|
||||
|
||||
set_sat(r, g, b, s);
|
||||
set_lum(r, g, b, l);
|
||||
|
||||
src = rgba(int(255.0*r), int(255.0*g), int(255.0*b), 0) | (src & rgba_a_mask);
|
||||
return rgba_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t rgba_blender_hsl_saturation(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
double r = rgba_getr(src)/255.0;
|
||||
double g = rgba_getg(src)/255.0;
|
||||
double b = rgba_getb(src)/255.0;
|
||||
double s = sat(r, g, b);
|
||||
|
||||
r = rgba_getr(backdrop)/255.0;
|
||||
g = rgba_getg(backdrop)/255.0;
|
||||
b = rgba_getb(backdrop)/255.0;
|
||||
double l = lum(r, g, b);
|
||||
|
||||
set_sat(r, g, b, s);
|
||||
set_lum(r, g, b, l);
|
||||
|
||||
src = rgba(int(255.0*r), int(255.0*g), int(255.0*b), 0) | (src & rgba_a_mask);
|
||||
return rgba_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t rgba_blender_hsl_color(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
double r = rgba_getr(backdrop)/255.0;
|
||||
double g = rgba_getg(backdrop)/255.0;
|
||||
double b = rgba_getb(backdrop)/255.0;
|
||||
double l = lum(r, g, b);
|
||||
|
||||
r = rgba_getr(src)/255.0;
|
||||
g = rgba_getg(src)/255.0;
|
||||
b = rgba_getb(src)/255.0;
|
||||
|
||||
set_lum(r, g, b, l);
|
||||
|
||||
src = rgba(int(255.0*r), int(255.0*g), int(255.0*b), 0) | (src & rgba_a_mask);
|
||||
return rgba_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t rgba_blender_hsl_luminosity(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
double r = rgba_getr(src)/255.0;
|
||||
double g = rgba_getg(src)/255.0;
|
||||
double b = rgba_getb(src)/255.0;
|
||||
double l = lum(r, g, b);
|
||||
|
||||
r = rgba_getr(backdrop)/255.0;
|
||||
g = rgba_getg(backdrop)/255.0;
|
||||
b = rgba_getb(backdrop)/255.0;
|
||||
|
||||
set_lum(r, g, b, l);
|
||||
|
||||
src = rgba(int(255.0*r), int(255.0*g), int(255.0*b), 0) | (src & rgba_a_mask);
|
||||
return rgba_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// GRAY blenders
|
||||
|
||||
color_t graya_blender_src(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
return src;
|
||||
}
|
||||
|
||||
color_t graya_blender_merge(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int Bk, Ba;
|
||||
int Sk, Sa;
|
||||
int Rk, Ra;
|
||||
int t;
|
||||
|
||||
Bk = graya_getv(backdrop);
|
||||
Ba = graya_geta(backdrop);
|
||||
|
||||
Sk = graya_getv(src);
|
||||
Sa = graya_geta(src);
|
||||
|
||||
if (Ba == 0) {
|
||||
Rk = Sk;
|
||||
}
|
||||
else if (Sa == 0) {
|
||||
Rk = Bk;
|
||||
}
|
||||
else {
|
||||
Rk = Bk + MUL_UN8((Sk-Bk), opacity, t);
|
||||
}
|
||||
Ra = Ba + MUL_UN8((Sa-Ba), opacity, t);
|
||||
if (Ra == 0)
|
||||
Rk = 0;
|
||||
|
||||
return graya(Rk, Ra);
|
||||
}
|
||||
|
||||
color_t graya_blender_neg_bw(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
if ((backdrop & graya_a_mask) == 0)
|
||||
return src;
|
||||
else if (graya_getv(backdrop) < 128)
|
||||
return graya(255, 255);
|
||||
else
|
||||
return graya(0, 255);
|
||||
}
|
||||
|
||||
color_t graya_blender_normal(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int t;
|
||||
|
||||
if ((backdrop & graya_a_mask) == 0) {
|
||||
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)
|
||||
return backdrop;
|
||||
|
||||
int Bg, Ba;
|
||||
int Sg, Sa;
|
||||
int Rg, Ra;
|
||||
|
||||
Bg = graya_getv(backdrop);
|
||||
Ba = graya_geta(backdrop);
|
||||
|
||||
Sg = graya_getv(src);
|
||||
Sa = graya_geta(src);
|
||||
Sa = MUL_UN8(Sa, opacity, t);
|
||||
|
||||
Ra = Ba + Sa - MUL_UN8(Ba, Sa, t);
|
||||
Rg = Bg + (Sg-Bg) * Sa / Ra;
|
||||
|
||||
return graya(Rg, Ra);
|
||||
}
|
||||
|
||||
color_t graya_blender_multiply(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int t;
|
||||
int v = blend_multiply(graya_getv(backdrop), graya_getv(src), t);
|
||||
src = graya(v, 0) | (src & graya_a_mask);
|
||||
return graya_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t graya_blender_screen(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int t;
|
||||
int v = blend_screen(graya_getv(backdrop), graya_getv(src), t);
|
||||
src = graya(v, 0) | (src & graya_a_mask);
|
||||
return graya_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t graya_blender_overlay(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int t;
|
||||
int v = blend_overlay(graya_getv(backdrop), graya_getv(src), t);
|
||||
src = graya(v, 0) | (src & graya_a_mask);
|
||||
return graya_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t graya_blender_darken(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int v = blend_darken(graya_getv(backdrop), graya_getv(src));
|
||||
src = graya(v, 0) | (src & graya_a_mask);
|
||||
return graya_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t graya_blender_lighten(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int v = blend_lighten(graya_getv(backdrop), graya_getv(src));
|
||||
src = graya(v, 0) | (src & graya_a_mask);
|
||||
return graya_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t graya_blender_color_dodge(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int v = blend_color_dodge(graya_getv(backdrop), graya_getv(src));
|
||||
src = graya(v, 0) | (src & graya_a_mask);
|
||||
return graya_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t graya_blender_color_burn(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int v = blend_color_burn(graya_getv(backdrop), graya_getv(src));
|
||||
src = graya(v, 0) | (src & graya_a_mask);
|
||||
return graya_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t graya_blender_hard_light(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int t;
|
||||
int v = blend_hard_light(graya_getv(backdrop), graya_getv(src), t);
|
||||
src = graya(v, 0) | (src & graya_a_mask);
|
||||
return graya_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t graya_blender_soft_light(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int v = blend_soft_light(graya_getv(backdrop), graya_getv(src));
|
||||
src = graya(v, 0) | (src & graya_a_mask);
|
||||
return graya_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t graya_blender_difference(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int v = blend_difference(graya_getv(backdrop), graya_getv(src));
|
||||
src = graya(v, 0) | (src & graya_a_mask);
|
||||
return graya_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t graya_blender_exclusion(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int t;
|
||||
int v = blend_exclusion(graya_getv(backdrop), graya_getv(src), t);
|
||||
src = graya(v, 0) | (src & graya_a_mask);
|
||||
return graya_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// indexed
|
||||
|
||||
color_t indexed_blender_src(color_t dst, color_t src, int opacity)
|
||||
{
|
||||
return src;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// getters
|
||||
|
||||
BlendFunc get_rgba_blender(BlendMode blendmode)
|
||||
{
|
||||
switch (blendmode) {
|
||||
case BlendMode::SRC: return rgba_blender_src;
|
||||
case BlendMode::MERGE: return rgba_blender_merge;
|
||||
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::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;
|
||||
}
|
||||
ASSERT(false);
|
||||
return rgba_blender_src;
|
||||
}
|
||||
|
||||
BlendFunc get_graya_blender(BlendMode blendmode)
|
||||
{
|
||||
switch (blendmode) {
|
||||
case BlendMode::SRC: return graya_blender_src;
|
||||
case BlendMode::MERGE: return graya_blender_merge;
|
||||
case BlendMode::NEG_BW: return graya_blender_neg_bw;
|
||||
case BlendMode::RED_TINT: return graya_blender_normal;
|
||||
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::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;
|
||||
}
|
||||
ASSERT(false);
|
||||
return graya_blender_src;
|
||||
}
|
||||
|
||||
BlendFunc get_indexed_blender(BlendMode blendmode)
|
||||
{
|
||||
return indexed_blender_src;
|
||||
}
|
||||
|
||||
} // namespace doc
|
32
src/doc/blend_funcs.h
Normal file
32
src/doc/blend_funcs.h
Normal file
@ -0,0 +1,32 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2001-2015 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifndef DOC_BLEND_FUNCS_H_INCLUDED
|
||||
#define DOC_BLEND_FUNCS_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "doc/blend_mode.h"
|
||||
#include "doc/color.h"
|
||||
|
||||
namespace doc {
|
||||
|
||||
typedef color_t (*BlendFunc)(color_t backdrop, color_t src, int opacity);
|
||||
|
||||
color_t rgba_blender_normal(color_t backdrop, color_t src, int opacity);
|
||||
color_t rgba_blender_merge(color_t backdrop, color_t src, int opacity);
|
||||
color_t rgba_blender_neg_bw(color_t backdrop, color_t src, int opacity);
|
||||
|
||||
color_t graya_blender_normal(color_t backdrop, color_t src, int opacity);
|
||||
color_t graya_blender_merge(color_t backdrop, color_t src, int opacity);
|
||||
color_t graya_blender_neg_bw(color_t backdrop, color_t src, int opacity);
|
||||
|
||||
BlendFunc get_rgba_blender(BlendMode blendmode);
|
||||
BlendFunc get_graya_blender(BlendMode blendmode);
|
||||
BlendFunc get_indexed_blender(BlendMode blendmode);
|
||||
|
||||
} // namespace doc
|
||||
|
||||
#endif
|
17
src/doc/blend_internals.h
Normal file
17
src/doc/blend_internals.h
Normal file
@ -0,0 +1,17 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2001-2015 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifndef DOC_BLEND_INTERNALS_H_INCLUDED
|
||||
#define DOC_BLEND_INTERNALS_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "../../third_party/pixman/pixman/pixman-combine32.h"
|
||||
|
||||
#if !defined(MUL_UN8) || !defined(DIV_UN8)
|
||||
#error Invalid Pixman library
|
||||
#endif
|
||||
|
||||
#endif
|
43
src/doc/blend_mode.h
Normal file
43
src/doc/blend_mode.h
Normal file
@ -0,0 +1,43 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2001-2015 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifndef DOC_BLEND_MODE_H_INCLUDED
|
||||
#define DOC_BLEND_MODE_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
namespace doc {
|
||||
|
||||
enum class BlendMode {
|
||||
// Special internal/undocumented alpha compositing and blend modes
|
||||
UNSPECIFIED = -1,
|
||||
SRC = -2,
|
||||
MERGE = -3,
|
||||
NEG_BW = -4, // Negative Black & White
|
||||
RED_TINT = -5,
|
||||
BLUE_TINT = -6,
|
||||
|
||||
// Aseprite (.ase files) blend modes
|
||||
NORMAL = 0,
|
||||
MULTIPLY = 1,
|
||||
SCREEN = 2,
|
||||
OVERLAY = 3,
|
||||
DARKEN = 4,
|
||||
LIGHTEN = 5,
|
||||
COLOR_DODGE = 6,
|
||||
COLOR_BURN = 7,
|
||||
HARD_LIGHT = 8,
|
||||
SOFT_LIGHT = 9,
|
||||
DIFFERENCE = 10,
|
||||
EXCLUSION = 11,
|
||||
HSL_HUE = 12,
|
||||
HSL_SATURATION = 13,
|
||||
HSL_COLOR = 14,
|
||||
HSL_LUMINOSITY = 15
|
||||
};
|
||||
|
||||
} // namespace doc
|
||||
|
||||
#endif
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2001-2014 David Capello
|
||||
// Copyright (c) 2001-2015 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -51,8 +51,12 @@ namespace doc {
|
||||
(a << rgba_a_shift));
|
||||
}
|
||||
|
||||
inline uint32_t rgb(uint8_t r, uint8_t g, uint8_t b) {
|
||||
return rgba(0, 0, 0, 255);
|
||||
inline int rgb_luma(int r, int g, int b) {
|
||||
return (r*2126 + g*7152 + b*722) / 10000;
|
||||
}
|
||||
|
||||
inline uint8_t rgba_luma(uint32_t c) {
|
||||
return rgb_luma(rgba_getr(c), rgba_getg(c), rgba_getb(c));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
@ -12,7 +12,6 @@
|
||||
|
||||
#include "base/24bits.h"
|
||||
#include "doc/algo.h"
|
||||
#include "doc/blend.h"
|
||||
#include "doc/color_scales.h"
|
||||
#include "doc/image_impl.h"
|
||||
#include "doc/palette.h"
|
||||
|
@ -8,7 +8,8 @@
|
||||
#define DOC_DOC_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "doc/blend.h"
|
||||
#include "doc/blend_funcs.h"
|
||||
#include "doc/blend_mode.h"
|
||||
#include "doc/brush.h"
|
||||
#include "doc/cel.h"
|
||||
#include "doc/color.h"
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2001-2014 David Capello
|
||||
// Copyright (c) 2001-2015 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -11,7 +11,6 @@
|
||||
#include "doc/image.h"
|
||||
|
||||
#include "doc/algo.h"
|
||||
#include "doc/blend.h"
|
||||
#include "doc/brush.h"
|
||||
#include "doc/image_impl.h"
|
||||
#include "doc/palette.h"
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2001-2014 David Capello
|
||||
// Copyright (c) 2001-2015 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -8,7 +8,6 @@
|
||||
#define DOC_IMAGE_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "doc/blend.h"
|
||||
#include "doc/color.h"
|
||||
#include "doc/image_buffer.h"
|
||||
#include "doc/object.h"
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "doc/blend.h"
|
||||
#include "doc/blend_funcs.h"
|
||||
#include "doc/image.h"
|
||||
#include "doc/image_bits.h"
|
||||
#include "doc/image_iterator.h"
|
||||
@ -248,7 +248,7 @@ namespace doc {
|
||||
for (y=y1; y<=y2; ++y) {
|
||||
addr = (address_t)getPixelAddress(x1, y);
|
||||
for (x=x1; x<=x2; ++x) {
|
||||
*addr = rgba_blend_normal(*addr, color, opacity);
|
||||
*addr = rgba_blender_normal(*addr, color, opacity);
|
||||
++addr;
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
#define DOC_IMAGE_TRAITS_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "doc/blend_funcs.h"
|
||||
#include "doc/pixel_format.h"
|
||||
|
||||
namespace doc {
|
||||
@ -30,15 +31,12 @@ namespace doc {
|
||||
static const pixel_t min_value = 0x00000000l;
|
||||
static const pixel_t max_value = 0xffffffffl;
|
||||
|
||||
static inline int getRowStrideBytes(int pixels_per_row)
|
||||
{
|
||||
static inline int getRowStrideBytes(int pixels_per_row) {
|
||||
return bytes_per_pixel * pixels_per_row;
|
||||
}
|
||||
|
||||
static inline BLEND_COLOR get_blender(int blend_mode)
|
||||
{
|
||||
ASSERT(blend_mode >= 0 && blend_mode < BLEND_MODE_MAX);
|
||||
return rgba_blenders[blend_mode];
|
||||
static inline BlendFunc get_blender(BlendMode blend_mode) {
|
||||
return get_rgba_blender(blend_mode);
|
||||
}
|
||||
};
|
||||
|
||||
@ -60,15 +58,12 @@ namespace doc {
|
||||
static const pixel_t min_value = 0x0000;
|
||||
static const pixel_t max_value = 0xffff;
|
||||
|
||||
static inline int getRowStrideBytes(int pixels_per_row)
|
||||
{
|
||||
static inline int getRowStrideBytes(int pixels_per_row) {
|
||||
return bytes_per_pixel * pixels_per_row;
|
||||
}
|
||||
|
||||
static inline BLEND_COLOR get_blender(int blend_mode)
|
||||
{
|
||||
ASSERT(blend_mode >= 0 && blend_mode < BLEND_MODE_MAX);
|
||||
return graya_blenders[blend_mode];
|
||||
static inline BlendFunc get_blender(BlendMode blend_mode) {
|
||||
return get_graya_blender(blend_mode);
|
||||
}
|
||||
};
|
||||
|
||||
@ -90,14 +85,12 @@ namespace doc {
|
||||
static const pixel_t min_value = 0x00;
|
||||
static const pixel_t max_value = 0xff;
|
||||
|
||||
static inline int getRowStrideBytes(int pixels_per_row)
|
||||
{
|
||||
static inline int getRowStrideBytes(int pixels_per_row) {
|
||||
return bytes_per_pixel * pixels_per_row;
|
||||
}
|
||||
|
||||
static inline BLEND_COLOR get_blender(int blend_mode)
|
||||
{
|
||||
return indexed_blend_direct;
|
||||
static inline BlendFunc get_blender(BlendMode blend_mode) {
|
||||
return get_indexed_blender(blend_mode);
|
||||
}
|
||||
};
|
||||
|
||||
@ -119,8 +112,7 @@ namespace doc {
|
||||
static const pixel_t min_value = 0;
|
||||
static const pixel_t max_value = 1;
|
||||
|
||||
static inline int getRowStrideBytes(int pixels_per_row)
|
||||
{
|
||||
static inline int getRowStrideBytes(int pixels_per_row) {
|
||||
return ((pixels_per_row+7) / 8);
|
||||
}
|
||||
};
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
#include "doc/layer.h"
|
||||
|
||||
#include "doc/blend.h"
|
||||
#include "doc/cel.h"
|
||||
#include "doc/image.h"
|
||||
#include "doc/primitives.h"
|
||||
@ -85,6 +84,7 @@ Cel* Layer::cel(frame_t frame) const
|
||||
|
||||
LayerImage::LayerImage(Sprite* sprite)
|
||||
: Layer(ObjectType::LayerImage, sprite)
|
||||
, m_blendmode(BlendMode::NORMAL)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
#define DOC_LAYER_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "doc/blend.h"
|
||||
#include "doc/blend_mode.h"
|
||||
#include "doc/cel_list.h"
|
||||
#include "doc/frame.h"
|
||||
#include "doc/layer_list.h"
|
||||
@ -116,7 +116,8 @@ namespace doc {
|
||||
|
||||
virtual int getMemSize() const override;
|
||||
|
||||
int getBlendMode() const { return BLEND_MODE_NORMAL; }
|
||||
BlendMode blendMode() const { return m_blendmode; }
|
||||
void setBlendMode(BlendMode blendmode) { m_blendmode = blendmode; }
|
||||
|
||||
void addCel(Cel *cel);
|
||||
void removeCel(Cel *cel);
|
||||
@ -137,6 +138,7 @@ namespace doc {
|
||||
private:
|
||||
void destroyAllCels();
|
||||
|
||||
BlendMode m_blendmode;
|
||||
CelList m_cels; // List of all cels inside this layer used by frames.
|
||||
};
|
||||
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "doc/blend.h"
|
||||
#include "doc/image.h"
|
||||
#include "doc/path.h"
|
||||
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "doc/primitives.h"
|
||||
|
||||
#include "doc/algo.h"
|
||||
#include "doc/blend.h"
|
||||
#include "doc/brush.h"
|
||||
#include "doc/image_impl.h"
|
||||
#include "doc/palette.h"
|
||||
|
@ -100,8 +100,8 @@ struct PalEntryWithIndexPredicate {
|
||||
}
|
||||
|
||||
case SortPaletteBy::LUMA: {
|
||||
value1 = (rgba_getr(c1)*299 + rgba_getg(c1)*587 + rgba_getb(c1)*114); // do not /1000 (so we get more precission)
|
||||
value2 = (rgba_getr(c2)*299 + rgba_getg(c2)*587 + rgba_getb(c2)*114);
|
||||
value1 = rgb_luma(rgba_getr(c1), rgba_getg(c1), rgba_getb(c1));
|
||||
value2 = rgb_luma(rgba_getr(c2), rgba_getg(c2), rgba_getb(c2));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
#include "render/quantization.h"
|
||||
|
||||
#include "doc/blend.h"
|
||||
#include "doc/image_impl.h"
|
||||
#include "doc/images_collector.h"
|
||||
#include "doc/layer.h"
|
||||
|
@ -10,6 +10,8 @@
|
||||
|
||||
#include "render/render.h"
|
||||
|
||||
#include "doc/blend_internals.h"
|
||||
#include "doc/blend_mode.h"
|
||||
#include "doc/doc.h"
|
||||
#include "doc/handle_anidir.h"
|
||||
#include "doc/image_impl.h"
|
||||
@ -23,12 +25,12 @@ namespace render {
|
||||
|
||||
template<class DstTraits, class SrcTraits>
|
||||
class BlenderHelper {
|
||||
BLEND_COLOR m_blend_color;
|
||||
BlendFunc m_blend_func;
|
||||
color_t m_mask_color;
|
||||
public:
|
||||
BlenderHelper(const Image* src, const Palette* pal, int blend_mode)
|
||||
BlenderHelper(const Image* src, const Palette* pal, BlendMode blend_mode)
|
||||
{
|
||||
m_blend_color = SrcTraits::get_blender(blend_mode);
|
||||
m_blend_func = SrcTraits::get_blender(blend_mode);
|
||||
m_mask_color = src->maskColor();
|
||||
}
|
||||
inline void operator()(typename DstTraits::pixel_t& scanline,
|
||||
@ -37,7 +39,7 @@ public:
|
||||
int opacity)
|
||||
{
|
||||
if (src != m_mask_color)
|
||||
scanline = (*m_blend_color)(dst, src, opacity);
|
||||
scanline = (*m_blend_func)(dst, src, opacity);
|
||||
else
|
||||
scanline = dst;
|
||||
}
|
||||
@ -45,12 +47,12 @@ public:
|
||||
|
||||
template<>
|
||||
class BlenderHelper<RgbTraits, GrayscaleTraits> {
|
||||
BLEND_COLOR m_blend_color;
|
||||
BlendFunc m_blend_func;
|
||||
color_t m_mask_color;
|
||||
public:
|
||||
BlenderHelper(const Image* src, const Palette* pal, int blend_mode)
|
||||
BlenderHelper(const Image* src, const Palette* pal, BlendMode blend_mode)
|
||||
{
|
||||
m_blend_color = RgbTraits::get_blender(blend_mode);
|
||||
m_blend_func = RgbTraits::get_blender(blend_mode);
|
||||
m_mask_color = src->maskColor();
|
||||
}
|
||||
inline void operator()(RgbTraits::pixel_t& scanline,
|
||||
@ -60,7 +62,7 @@ public:
|
||||
{
|
||||
if (src != m_mask_color) {
|
||||
int v = graya_getv(src);
|
||||
scanline = (*m_blend_color)(dst, rgba(v, v, v, graya_geta(src)), opacity);
|
||||
scanline = (*m_blend_func)(dst, rgba(v, v, v, graya_geta(src)), opacity);
|
||||
}
|
||||
else
|
||||
scanline = dst;
|
||||
@ -70,14 +72,14 @@ public:
|
||||
template<>
|
||||
class BlenderHelper<RgbTraits, IndexedTraits> {
|
||||
const Palette* m_pal;
|
||||
int m_blend_mode;
|
||||
BLEND_COLOR m_blend_color;
|
||||
BlendMode m_blend_mode;
|
||||
BlendFunc m_blend_func;
|
||||
color_t m_mask_color;
|
||||
public:
|
||||
BlenderHelper(const Image* src, const Palette* pal, int blend_mode)
|
||||
BlenderHelper(const Image* src, const Palette* pal, BlendMode blend_mode)
|
||||
{
|
||||
m_blend_mode = blend_mode;
|
||||
m_blend_color = RgbTraits::get_blender(blend_mode);
|
||||
m_blend_func = RgbTraits::get_blender(blend_mode);
|
||||
m_mask_color = src->maskColor();
|
||||
m_pal = pal;
|
||||
}
|
||||
@ -86,12 +88,12 @@ public:
|
||||
const IndexedTraits::pixel_t& src,
|
||||
int opacity)
|
||||
{
|
||||
if (m_blend_mode == BLEND_MODE_COPY) {
|
||||
if (m_blend_mode == BlendMode::SRC) {
|
||||
scanline = m_pal->getEntry(src);
|
||||
}
|
||||
else {
|
||||
if (src != m_mask_color) {
|
||||
scanline = (*m_blend_color)(dst, m_pal->getEntry(src), opacity);
|
||||
scanline = (*m_blend_func)(dst, m_pal->getEntry(src), opacity);
|
||||
}
|
||||
else
|
||||
scanline = dst;
|
||||
@ -101,10 +103,10 @@ public:
|
||||
|
||||
template<>
|
||||
class BlenderHelper<IndexedTraits, IndexedTraits> {
|
||||
int m_blend_mode;
|
||||
BlendMode m_blend_mode;
|
||||
color_t m_mask_color;
|
||||
public:
|
||||
BlenderHelper(const Image* src, const Palette* pal, int blend_mode)
|
||||
BlenderHelper(const Image* src, const Palette* pal, BlendMode blend_mode)
|
||||
{
|
||||
m_blend_mode = blend_mode;
|
||||
m_mask_color = src->maskColor();
|
||||
@ -114,7 +116,7 @@ public:
|
||||
const IndexedTraits::pixel_t& src,
|
||||
int opacity)
|
||||
{
|
||||
if (m_blend_mode == BLEND_MODE_COPY) {
|
||||
if (m_blend_mode == BlendMode::SRC) {
|
||||
scanline = src;
|
||||
}
|
||||
else {
|
||||
@ -130,7 +132,7 @@ template<class DstTraits, class SrcTraits>
|
||||
static void compose_scaled_image_scale_up(
|
||||
Image* dst, const Image* src, const Palette* pal,
|
||||
gfx::Clip area,
|
||||
int opacity, int blend_mode, Zoom zoom)
|
||||
int opacity, BlendMode blend_mode, Zoom zoom)
|
||||
{
|
||||
BlenderHelper<DstTraits, SrcTraits> blender(src, pal, blend_mode);
|
||||
int px_x, px_y;
|
||||
@ -257,7 +259,7 @@ template<class DstTraits, class SrcTraits>
|
||||
static void compose_scaled_image_scale_down(
|
||||
Image* dst, const Image* src, const Palette* pal,
|
||||
gfx::Clip area,
|
||||
int opacity, int blend_mode, Zoom zoom)
|
||||
int opacity, BlendMode blend_mode, Zoom zoom)
|
||||
{
|
||||
BlenderHelper<DstTraits, SrcTraits> blender(src, pal, blend_mode);
|
||||
int unbox_w = zoom.remove(1);
|
||||
@ -314,7 +316,7 @@ template<class DstTraits, class SrcTraits>
|
||||
static void compose_scaled_image(
|
||||
Image* dst, const Image* src, const Palette* pal,
|
||||
const gfx::Clip& area,
|
||||
int opacity, int blend_mode, Zoom zoom)
|
||||
int opacity, BlendMode blend_mode, Zoom zoom)
|
||||
{
|
||||
if (zoom.scale() >= 1.0)
|
||||
compose_scaled_image_scale_up<DstTraits, SrcTraits>(dst, src, pal, area, opacity, blend_mode, zoom);
|
||||
@ -373,7 +375,7 @@ void Render::setPreviewImage(const Layer* layer, frame_t frame, Image* image)
|
||||
|
||||
void Render::setExtraImage(
|
||||
ExtraType type,
|
||||
const Cel* cel, const Image* image, int blendMode,
|
||||
const Cel* cel, const Image* image, BlendMode blendMode,
|
||||
const Layer* currentLayer,
|
||||
frame_t currentFrame)
|
||||
{
|
||||
@ -438,7 +440,7 @@ void Render::renderLayer(
|
||||
const Layer* layer,
|
||||
frame_t frame,
|
||||
const gfx::Clip& area,
|
||||
int blend_mode)
|
||||
BlendMode blend_mode)
|
||||
{
|
||||
m_sprite = layer->sprite();
|
||||
|
||||
@ -506,7 +508,7 @@ void Render::renderSprite(
|
||||
renderLayer(
|
||||
m_sprite->folder(), dstImage,
|
||||
area, frame, zoom, scaled_func,
|
||||
true, true, -1);
|
||||
true, true, BlendMode::UNSPECIFIED);
|
||||
|
||||
// Onion-skin feature: Draw previous/next frames with different
|
||||
// opacity (<255)
|
||||
@ -544,11 +546,11 @@ void Render::renderSprite(
|
||||
if (m_globalOpacity > 0) {
|
||||
m_globalOpacity = MID(0, m_globalOpacity, 255);
|
||||
|
||||
int blend_mode = -1;
|
||||
BlendMode blend_mode = BlendMode::UNSPECIFIED;
|
||||
if (m_onionskin.type() == OnionskinType::MERGE)
|
||||
blend_mode = BLEND_MODE_NORMAL;
|
||||
blend_mode = BlendMode::NORMAL;
|
||||
else if (m_onionskin.type() == OnionskinType::RED_BLUE_TINT)
|
||||
blend_mode = (frameOut < frame ? BLEND_MODE_RED_TINT: BLEND_MODE_BLUE_TINT);
|
||||
blend_mode = (frameOut < frame ? BlendMode::RED_TINT: BlendMode::BLUE_TINT);
|
||||
|
||||
renderLayer(m_sprite->folder(), dstImage,
|
||||
area, frameIn, zoom, scaled_func,
|
||||
@ -605,7 +607,7 @@ void Render::renderBackground(Image* image,
|
||||
}
|
||||
|
||||
void Render::renderImage(Image* dst_image, const Image* src_image,
|
||||
const Palette* pal, int x, int y, Zoom zoom, int opacity, int blend_mode)
|
||||
const Palette* pal, int x, int y, Zoom zoom, int opacity, BlendMode blend_mode)
|
||||
{
|
||||
RenderScaledImage scaled_func = getRenderScaledImageFunc(
|
||||
dst_image->pixelFormat(),
|
||||
@ -628,7 +630,7 @@ void Render::renderLayer(
|
||||
RenderScaledImage scaled_func,
|
||||
bool render_background,
|
||||
bool render_transparent,
|
||||
int blend_mode)
|
||||
BlendMode blend_mode)
|
||||
{
|
||||
// we can't read from this layer
|
||||
if (!layer->isVisible())
|
||||
@ -681,14 +683,14 @@ void Render::renderLayer(
|
||||
int t, output_opacity;
|
||||
|
||||
output_opacity = MID(0, cel->opacity(), 255);
|
||||
output_opacity = INT_MULT(output_opacity, m_globalOpacity, t);
|
||||
output_opacity = MUL_UN8(output_opacity, m_globalOpacity, t);
|
||||
|
||||
ASSERT(src_image->maskColor() == m_sprite->transparentColor());
|
||||
|
||||
int layer_blend_mode =
|
||||
(blend_mode < 0 ?
|
||||
static_cast<const LayerImage*>(layer)->getBlendMode():
|
||||
blend_mode);
|
||||
BlendMode layer_blend_mode =
|
||||
(blend_mode == BlendMode::UNSPECIFIED ?
|
||||
static_cast<const LayerImage*>(layer)->blendMode():
|
||||
blend_mode);
|
||||
|
||||
// Draw parts outside the "m_extraCel" area
|
||||
if (drawExtra && m_extraType == ExtraType::PATCH) {
|
||||
@ -758,7 +760,7 @@ void Render::renderCel(
|
||||
const Cel* cel,
|
||||
const gfx::Clip& area,
|
||||
RenderScaledImage scaled_func,
|
||||
int opacity, int blend_mode, Zoom zoom)
|
||||
int opacity, BlendMode blend_mode, Zoom zoom)
|
||||
{
|
||||
int cel_x = zoom.apply(cel->x());
|
||||
int cel_y = zoom.apply(cel->y());
|
||||
@ -820,7 +822,7 @@ Render::RenderScaledImage Render::getRenderScaledImageFunc(
|
||||
}
|
||||
|
||||
void composite_image(Image* dst, const Image* src,
|
||||
int x, int y, int opacity, int blend_mode)
|
||||
int x, int y, int opacity, BlendMode blend_mode)
|
||||
{
|
||||
// As the background is not rendered in renderImage(), we don't need
|
||||
// to configure the Render instance's BgType.
|
||||
|
@ -9,6 +9,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "doc/anidir.h"
|
||||
#include "doc/blend_mode.h"
|
||||
#include "doc/color.h"
|
||||
#include "doc/frame.h"
|
||||
#include "doc/pixel_format.h"
|
||||
@ -99,7 +100,7 @@ namespace render {
|
||||
// layer/frame.
|
||||
void setExtraImage(
|
||||
ExtraType type,
|
||||
const Cel* cel, const Image* image, int blendMode,
|
||||
const Cel* cel, const Image* image, BlendMode blendMode,
|
||||
const Layer* currentLayer,
|
||||
frame_t currentFrame);
|
||||
void removeExtraImage();
|
||||
@ -128,7 +129,7 @@ namespace render {
|
||||
const Layer* layer,
|
||||
frame_t frame,
|
||||
const gfx::Clip& area,
|
||||
int blend_mode = -1);
|
||||
BlendMode blend_mode = BlendMode::UNSPECIFIED);
|
||||
|
||||
// Main function used to render the sprite. Draws the given sprite
|
||||
// frame in a new image and return it. Note: zoomedRect must have
|
||||
@ -147,13 +148,13 @@ namespace render {
|
||||
|
||||
void renderImage(Image* dst_image, const Image* src_image,
|
||||
const Palette* pal, int x, int y, Zoom zoom,
|
||||
int opacity, int blend_mode);
|
||||
int opacity, BlendMode blend_mode);
|
||||
|
||||
private:
|
||||
typedef void (*RenderScaledImage)(
|
||||
Image* dst, const Image* src, const Palette* pal,
|
||||
const gfx::Clip& area,
|
||||
int opacity, int blend_mode, Zoom zoom);
|
||||
int opacity, BlendMode blend_mode, Zoom zoom);
|
||||
|
||||
void renderLayer(
|
||||
const Layer* layer,
|
||||
@ -163,7 +164,7 @@ namespace render {
|
||||
RenderScaledImage renderScaledImage,
|
||||
bool render_background,
|
||||
bool render_transparent,
|
||||
int blend_mode);
|
||||
BlendMode blend_mode);
|
||||
|
||||
void renderCel(
|
||||
Image* dst_image,
|
||||
@ -172,7 +173,7 @@ namespace render {
|
||||
const Cel* cel,
|
||||
const gfx::Clip& area,
|
||||
RenderScaledImage scaled_func,
|
||||
int opacity, int blend_mode, Zoom zoom);
|
||||
int opacity, BlendMode blend_mode, Zoom zoom);
|
||||
|
||||
static RenderScaledImage getRenderScaledImageFunc(
|
||||
PixelFormat dstFormat,
|
||||
@ -184,7 +185,7 @@ namespace render {
|
||||
ExtraType m_extraType;
|
||||
const Cel* m_extraCel;
|
||||
const Image* m_extraImage;
|
||||
int m_extraBlendMode;
|
||||
BlendMode m_extraBlendMode;
|
||||
|
||||
BgType m_bgType;
|
||||
bool m_bgZoom;
|
||||
@ -199,7 +200,7 @@ namespace render {
|
||||
};
|
||||
|
||||
void composite_image(Image* dst, const Image* src,
|
||||
int x, int y, int opacity, int blend_mode);
|
||||
int x, int y, int opacity, BlendMode blend_mode);
|
||||
|
||||
} // namespace render
|
||||
|
||||
|
@ -562,7 +562,7 @@ void ComboBox::onButtonClick(Event& ev)
|
||||
|
||||
void ComboBox::openListBox()
|
||||
{
|
||||
if (m_window)
|
||||
if (!isEnabled() || m_window)
|
||||
return;
|
||||
|
||||
m_window = new Window(Window::WithoutTitleBar);
|
||||
|
Loading…
x
Reference in New Issue
Block a user