mirror of
https://github.com/aseprite/aseprite.git
synced 2025-04-01 10:21:04 +00:00
Convert InkShadesField in a combobox-like widget to store several shades (#85)
Changes: * Added new ui::IconButton widget to create widgets with one skin icon that is colored depending on the button state. * ContextBar::InkShadesField was divided into a couple widgets (ShadeWidget and IconButton to drop-down a little menu with saved shades) * Fixed CommonLockedSurface::drawColoredRgbaSurface() impl. * Removed invalid gfx::setr/g/b/a() functions.
This commit is contained in:
parent
25a331c43a
commit
cf7c4754cc
Binary file not shown.
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
@ -406,6 +406,8 @@
|
||||
<part id="no_symmetry" x="144" y="240" w="13" h="13" />
|
||||
<part id="horizontal_symmetry" x="160" y="240" w="13" h="13" />
|
||||
<part id="vertical_symmetry" x="176" y="240" w="13" h="13" />
|
||||
<part id="icon_arrow_down" x="144" y="256" w="7" h="4" />
|
||||
<part id="icon_close" x="153" y="256" w="7" h="7" />
|
||||
</parts>
|
||||
|
||||
<stylesheet>
|
||||
|
@ -363,6 +363,7 @@ add_library(app-lib
|
||||
ui/frame_tag_window.cpp
|
||||
ui/hex_color_entry.cpp
|
||||
ui/home_view.cpp
|
||||
ui/icon_button.cpp
|
||||
ui/input_chain.cpp
|
||||
ui/keyboard_shortcuts.cpp
|
||||
ui/main_menu_bar.cpp
|
||||
|
@ -52,7 +52,7 @@ void SwitchColorsCommand::onExecute(Context* context)
|
||||
const auto& toolPref(Preferences::instance().tool(tool));
|
||||
if (toolPref.ink() == tools::InkType::SHADING) {
|
||||
App::instance()->getMainWindow()->
|
||||
getContextBar()->reverseShadesColors();
|
||||
getContextBar()->reverseShadeColors();
|
||||
}
|
||||
}
|
||||
|
||||
|
22
src/app/shade.h
Normal file
22
src/app/shade.h
Normal file
@ -0,0 +1,22 @@
|
||||
// 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_SHADE_H_INCLUDED
|
||||
#define APP_SHADE_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "app/color.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace app {
|
||||
|
||||
typedef std::vector<app::Color> Shade;
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif
|
@ -18,6 +18,7 @@
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/modules/palettes.h"
|
||||
#include "app/pref/preferences.h"
|
||||
#include "app/shade.h"
|
||||
#include "app/tools/controller.h"
|
||||
#include "app/tools/ink.h"
|
||||
#include "app/tools/ink_type.h"
|
||||
@ -28,6 +29,8 @@
|
||||
#include "app/ui/brush_popup.h"
|
||||
#include "app/ui/button_set.h"
|
||||
#include "app/ui/color_button.h"
|
||||
#include "app/ui/icon_button.h"
|
||||
#include "app/ui/skin/button_icon_impl.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "app/ui/skin/style.h"
|
||||
#include "app/ui_context.h"
|
||||
@ -429,122 +432,288 @@ protected:
|
||||
ContextBar* m_owner;
|
||||
};
|
||||
|
||||
class ContextBar::InkShadesField : public Widget {
|
||||
typedef std::vector<app::Color> Colors;
|
||||
public:
|
||||
class ContextBar::InkShadesField : public HBox {
|
||||
|
||||
InkShadesField() : Widget(kGenericWidget) {
|
||||
setText("Select colors in the palette");
|
||||
}
|
||||
class ShadeWidget : public Widget {
|
||||
public:
|
||||
enum ClickType { DragAndDrop, Select };
|
||||
|
||||
void reverseColors() {
|
||||
std::reverse(m_colors.begin(), m_colors.end());
|
||||
invalidate();
|
||||
}
|
||||
Signal0<void> Click;
|
||||
|
||||
doc::Remap* createShadesRemap(bool left) {
|
||||
base::UniquePtr<doc::Remap> remap;
|
||||
Colors colors = getColors();
|
||||
ShadeWidget(const Shade& colors, ClickType click)
|
||||
: Widget(kGenericWidget)
|
||||
, m_click(click)
|
||||
, m_shade(colors)
|
||||
, m_hotIndex(-1)
|
||||
, m_boxSize(12) {
|
||||
setText("Select colors in the palette");
|
||||
}
|
||||
|
||||
if (colors.size() > 0) {
|
||||
remap.reset(new doc::Remap(get_current_palette()->size()));
|
||||
void reverseShadeColors() {
|
||||
std::reverse(m_shade.begin(), m_shade.end());
|
||||
invalidate();
|
||||
}
|
||||
|
||||
for (int i=0; i<remap->size(); ++i)
|
||||
remap->map(i, i);
|
||||
doc::Remap* createShadeRemap(bool left) {
|
||||
base::UniquePtr<doc::Remap> remap;
|
||||
Shade colors = getShade();
|
||||
|
||||
if (left) {
|
||||
for (int i=1; i<int(colors.size()); ++i)
|
||||
remap->map(colors[i].getIndex(), colors[i-1].getIndex());
|
||||
if (colors.size() > 0) {
|
||||
remap.reset(new doc::Remap(get_current_palette()->size()));
|
||||
|
||||
for (int i=0; i<remap->size(); ++i)
|
||||
remap->map(i, i);
|
||||
|
||||
if (left) {
|
||||
for (int i=1; i<int(colors.size()); ++i)
|
||||
remap->map(colors[i].getIndex(), colors[i-1].getIndex());
|
||||
}
|
||||
else {
|
||||
for (int i=0; i<int(colors.size())-1; ++i)
|
||||
remap->map(colors[i].getIndex(), colors[i+1].getIndex());
|
||||
}
|
||||
}
|
||||
|
||||
return remap.release();
|
||||
}
|
||||
|
||||
int size() const {
|
||||
int colors = 0;
|
||||
for (const auto& color : m_shade) {
|
||||
if (color.getIndex() >= 0 &&
|
||||
color.getIndex() < get_current_palette()->size())
|
||||
++colors;
|
||||
}
|
||||
return colors;
|
||||
}
|
||||
|
||||
Shade getShade() const {
|
||||
Shade colors;
|
||||
for (const auto& color : m_shade) {
|
||||
if (color.getIndex() >= 0 &&
|
||||
color.getIndex() < get_current_palette()->size())
|
||||
colors.push_back(color);
|
||||
}
|
||||
return colors;
|
||||
}
|
||||
|
||||
void setShade(const Shade& shade) {
|
||||
m_shade = shade;
|
||||
invalidate();
|
||||
getParent()->getParent()->layout();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void onChangeColorBarSelection() {
|
||||
if (!isVisible())
|
||||
return;
|
||||
|
||||
doc::PalettePicks picks;
|
||||
ColorBar::instance()->getPaletteView()->getSelectedEntries(picks);
|
||||
|
||||
m_shade.resize(picks.picks());
|
||||
|
||||
int i = 0, j = 0;
|
||||
for (bool pick : picks) {
|
||||
if (pick)
|
||||
m_shade[j++] = app::Color::fromIndex(i);
|
||||
++i;
|
||||
}
|
||||
|
||||
getParent()->getParent()->layout();
|
||||
}
|
||||
|
||||
bool onProcessMessage(ui::Message* msg) override {
|
||||
switch (msg->type()) {
|
||||
|
||||
case kOpenMessage:
|
||||
ColorBar::instance()->ChangeSelection.connect(
|
||||
Bind<void>(&ShadeWidget::onChangeColorBarSelection, this));
|
||||
break;
|
||||
|
||||
case kMouseEnterMessage:
|
||||
case kMouseLeaveMessage:
|
||||
invalidate();
|
||||
break;
|
||||
|
||||
case kMouseUpMessage: {
|
||||
if (m_click == Select) {
|
||||
setSelected(true);
|
||||
Click();
|
||||
closeWindow();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case kMouseMoveMessage: {
|
||||
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
|
||||
gfx::Point mousePos = mouseMsg->position() - getBounds().getOrigin();
|
||||
gfx::Rect bounds = getClientBounds();
|
||||
int hot = -1;
|
||||
|
||||
bounds.shrink(3*guiscale());
|
||||
if (bounds.contains(mousePos)) {
|
||||
int count = size();
|
||||
hot = (mousePos.x - bounds.x) / m_boxSize;
|
||||
hot = MID(0, hot, count-1);
|
||||
}
|
||||
|
||||
if (m_hotIndex != hot) {
|
||||
m_hotIndex = hot;
|
||||
invalidate();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case kMouseDownMessage: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Widget::onProcessMessage(msg);
|
||||
}
|
||||
|
||||
void onPreferredSize(PreferredSizeEvent& ev) override {
|
||||
int size = this->size();
|
||||
if (size < 2)
|
||||
ev.setPreferredSize(Size((16+m_boxSize)*guiscale()+getTextWidth(), 18*guiscale()));
|
||||
else
|
||||
ev.setPreferredSize(Size(6+m_boxSize*size, 18)*guiscale());
|
||||
}
|
||||
|
||||
void onPaint(PaintEvent& ev) override {
|
||||
SkinTheme* theme = SkinTheme::instance();
|
||||
Graphics* g = ev.getGraphics();
|
||||
gfx::Rect bounds = getClientBounds();
|
||||
|
||||
gfx::Color bg = getBgColor();
|
||||
if (m_click == Select && hasMouseOver())
|
||||
bg = theme->colors.menuitemHighlightFace();
|
||||
g->fillRect(bg, bounds);
|
||||
|
||||
Shade colors = getShade();
|
||||
if (colors.size() >= 2) {
|
||||
int w = (6+m_boxSize*colors.size())*guiscale();
|
||||
if (bounds.w > w)
|
||||
bounds.w = w;
|
||||
}
|
||||
|
||||
skin::Style::State state;
|
||||
if (hasMouseOver()) state += Style::hover();
|
||||
theme->styles.view()->paint(g, bounds, nullptr, state);
|
||||
|
||||
bounds.shrink(3*guiscale());
|
||||
|
||||
gfx::Rect box(bounds.x, bounds.y, m_boxSize*guiscale(), bounds.h);
|
||||
|
||||
if (colors.size() >= 2) {
|
||||
for (int i=0; i<int(colors.size()); ++i) {
|
||||
if (i == int(colors.size())-1)
|
||||
box.w = bounds.x+bounds.w-box.x;
|
||||
|
||||
draw_color(g, box, colors[i]);
|
||||
box.x += box.w;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i=0; i<int(colors.size())-1; ++i)
|
||||
remap->map(colors[i].getIndex(), colors[i+1].getIndex());
|
||||
g->fillRect(theme->colors.editorFace(), bounds);
|
||||
g->drawAlignedUIString(getText(), theme->colors.face(), gfx::ColorNone, bounds,
|
||||
ui::CENTER | ui::MIDDLE);
|
||||
}
|
||||
}
|
||||
|
||||
return remap.release();
|
||||
ClickType m_click;
|
||||
Shade m_shade;
|
||||
int m_hotIndex;
|
||||
int m_boxSize;
|
||||
};
|
||||
|
||||
public:
|
||||
InkShadesField() :
|
||||
m_button(SkinTheme::instance()->parts.iconArrowDown()->getBitmap(0)),
|
||||
m_shade(Shade(), ShadeWidget::DragAndDrop) {
|
||||
SkinTheme* theme = SkinTheme::instance();
|
||||
m_shade.setBgColor(theme->colors.workspace());
|
||||
m_button.setBgColor(theme->colors.workspace());
|
||||
|
||||
noBorderNoChildSpacing();
|
||||
addChild(&m_button);
|
||||
addChild(&m_shade);
|
||||
|
||||
m_button.setFocusStop(false);
|
||||
m_button.Click.connect(Bind<void>(&InkShadesField::onShowMenu, this));
|
||||
}
|
||||
|
||||
void reverseShadeColors() {
|
||||
m_shade.reverseShadeColors();
|
||||
}
|
||||
|
||||
doc::Remap* createShadeRemap(bool left) {
|
||||
return m_shade.createShadeRemap(left);
|
||||
}
|
||||
|
||||
private:
|
||||
void onShowMenu() {
|
||||
gfx::Rect bounds = m_button.getBounds();
|
||||
|
||||
Colors getColors() const {
|
||||
Colors colors;
|
||||
for (const auto& color : m_colors) {
|
||||
if (color.getIndex() >= 0 &&
|
||||
color.getIndex() < get_current_palette()->size())
|
||||
colors.push_back(color);
|
||||
}
|
||||
return colors;
|
||||
}
|
||||
Menu menu;
|
||||
MenuItem
|
||||
reverse("Reverse Shade"),
|
||||
save("Save Shade");
|
||||
menu.addChild(&reverse);
|
||||
menu.addChild(&save);
|
||||
|
||||
void onChangeColorBarSelection() {
|
||||
if (!isVisible())
|
||||
return;
|
||||
bool hasShade = (m_shade.size() >= 2);
|
||||
reverse.setEnabled(hasShade);
|
||||
save.setEnabled(hasShade);
|
||||
reverse.Click.connect(Bind<void>(&InkShadesField::reverseShadeColors, this));
|
||||
save.Click.connect(Bind<void>(&InkShadesField::onSaveShade, this));
|
||||
|
||||
doc::PalettePicks picks;
|
||||
ColorBar::instance()->getPaletteView()->getSelectedEntries(picks);
|
||||
if (!m_shades.empty()) {
|
||||
SkinTheme* theme = SkinTheme::instance();
|
||||
|
||||
m_colors.resize(picks.picks());
|
||||
menu.addChild(new MenuSeparator);
|
||||
|
||||
int i = 0, j = 0;
|
||||
for (bool pick : picks) {
|
||||
if (pick)
|
||||
m_colors[j++] = app::Color::fromIndex(i);
|
||||
++i;
|
||||
}
|
||||
int i = 0;
|
||||
for (const Shade& shade : m_shades) {
|
||||
auto shadeWidget = new ShadeWidget(shade, ShadeWidget::Select);
|
||||
shadeWidget->setExpansive(true);
|
||||
shadeWidget->setBgColor(theme->colors.menuitemNormalFace());
|
||||
shadeWidget->Click.connect(
|
||||
[&]{
|
||||
m_shade.setShade(shade);
|
||||
});
|
||||
|
||||
getParent()->layout();
|
||||
}
|
||||
auto close = new IconButton(theme->parts.iconClose()->getBitmap(0));
|
||||
close->setBgColor(theme->colors.menuitemNormalFace());
|
||||
close->Click.connect(
|
||||
Bind<void>(
|
||||
[this, i, close]{
|
||||
m_shades.erase(m_shades.begin()+i);
|
||||
close->closeWindow();
|
||||
}));
|
||||
|
||||
bool onProcessMessage(ui::Message* msg) override {
|
||||
if (msg->type() == kOpenMessage) {
|
||||
ColorBar::instance()->ChangeSelection.connect(
|
||||
Bind<void>(&InkShadesField::onChangeColorBarSelection, this));
|
||||
}
|
||||
return Widget::onProcessMessage(msg);
|
||||
}
|
||||
|
||||
void onPreferredSize(PreferredSizeEvent& ev) override {
|
||||
int size = getColors().size();
|
||||
if (size < 2)
|
||||
ev.setPreferredSize(Size(16*guiscale()+getTextWidth(), 18*guiscale()));
|
||||
else
|
||||
ev.setPreferredSize(Size(6+12*size, 18)*guiscale());
|
||||
}
|
||||
|
||||
void onPaint(PaintEvent& ev) override {
|
||||
SkinTheme* theme = SkinTheme::instance();
|
||||
Graphics* g = ev.getGraphics();
|
||||
gfx::Rect bounds = getClientBounds();
|
||||
|
||||
skin::Style::State state;
|
||||
if (hasMouseOver()) state += Style::hover();
|
||||
|
||||
g->fillRect(theme->colors.workspace(), bounds);
|
||||
theme->styles.view()->paint(g, bounds, nullptr, state);
|
||||
|
||||
bounds.shrink(3*guiscale());
|
||||
|
||||
gfx::Rect box(bounds.x, bounds.y, 12*guiscale(), bounds.h);
|
||||
Colors colors = getColors();
|
||||
|
||||
if (colors.size() >= 2) {
|
||||
for (int i=0; i<int(colors.size()); ++i) {
|
||||
if (i == int(colors.size())-1)
|
||||
box.w = bounds.x+bounds.w-box.x;
|
||||
|
||||
draw_color(g, box, colors[i]);
|
||||
box.x += box.w;
|
||||
auto item = new HBox();
|
||||
item->noBorderNoChildSpacing();
|
||||
item->addChild(shadeWidget);
|
||||
item->addChild(close);
|
||||
menu.addChild(item);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
else {
|
||||
g->fillRect(theme->colors.editorFace(), bounds);
|
||||
g->drawAlignedUIString(getText(), theme->colors.face(), gfx::ColorNone, bounds,
|
||||
ui::CENTER | ui::MIDDLE);
|
||||
}
|
||||
|
||||
menu.showPopup(gfx::Point(bounds.x, bounds.y+bounds.h));
|
||||
m_button.invalidate();
|
||||
}
|
||||
|
||||
std::vector<app::Color> m_colors;
|
||||
void onSaveShade() {
|
||||
m_shades.push_back(m_shade.getShade());
|
||||
}
|
||||
|
||||
IconButton m_button;
|
||||
ShadeWidget m_shade;
|
||||
std::vector<Shade> m_shades;
|
||||
};
|
||||
|
||||
class ContextBar::InkOpacityField : public IntEntry
|
||||
@ -1502,14 +1671,14 @@ doc::BrushRef ContextBar::createBrushFromPreferences(ToolPreferences::Brush* bru
|
||||
return brush;
|
||||
}
|
||||
|
||||
doc::Remap* ContextBar::createShadesRemap(bool left)
|
||||
doc::Remap* ContextBar::createShadeRemap(bool left)
|
||||
{
|
||||
return m_inkShades->createShadesRemap(left);
|
||||
return m_inkShades->createShadeRemap(left);
|
||||
}
|
||||
|
||||
void ContextBar::reverseShadesColors()
|
||||
void ContextBar::reverseShadeColors()
|
||||
{
|
||||
m_inkShades->reverseColors();
|
||||
m_inkShades->reverseShadeColors();
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -70,8 +70,8 @@ namespace app {
|
||||
static doc::BrushRef createBrushFromPreferences(
|
||||
ToolPreferences::Brush* brushPref = nullptr);
|
||||
|
||||
doc::Remap* createShadesRemap(bool left);
|
||||
void reverseShadesColors();
|
||||
doc::Remap* createShadeRemap(bool left);
|
||||
void reverseShadeColors();
|
||||
|
||||
// Signals
|
||||
Signal0<void> BrushChange;
|
||||
|
@ -169,7 +169,7 @@ public:
|
||||
|
||||
if (m_toolPref.ink() == tools::InkType::SHADING) {
|
||||
m_shadingRemap.reset(
|
||||
App::instance()->getMainWindow()->getContextBar()->createShadesRemap(
|
||||
App::instance()->getMainWindow()->getContextBar()->createShadeRemap(
|
||||
button == tools::ToolLoop::Left));
|
||||
}
|
||||
}
|
||||
|
68
src/app/ui/icon_button.cpp
Normal file
68
src/app/ui/icon_button.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
// 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/ui/icon_button.h"
|
||||
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "she/surface.h"
|
||||
#include "ui/message.h"
|
||||
#include "ui/paint_event.h"
|
||||
#include "ui/preferred_size_event.h"
|
||||
#include "ui/system.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
using namespace ui;
|
||||
using namespace app::skin;
|
||||
|
||||
IconButton::IconButton(she::Surface* icon)
|
||||
: Button("")
|
||||
, m_icon(icon)
|
||||
{
|
||||
setBgColor(SkinTheme::instance()->colors.menuitemNormalFace());
|
||||
}
|
||||
|
||||
void IconButton::onPreferredSize(PreferredSizeEvent& ev)
|
||||
{
|
||||
ev.setPreferredSize(
|
||||
gfx::Size(m_icon->width(),
|
||||
m_icon->height()) + 4*guiscale());
|
||||
}
|
||||
|
||||
void IconButton::onPaint(PaintEvent& ev)
|
||||
{
|
||||
SkinTheme* theme = SkinTheme::instance();
|
||||
Graphics* g = ev.getGraphics();
|
||||
gfx::Color fg, bg;
|
||||
|
||||
if (isSelected()) {
|
||||
fg = theme->colors.menuitemHighlightText();
|
||||
bg = theme->colors.menuitemHighlightFace();
|
||||
}
|
||||
else if (isEnabled() && hasMouseOver()) {
|
||||
fg = theme->colors.menuitemHotText();
|
||||
bg = theme->colors.menuitemHotFace();
|
||||
}
|
||||
else {
|
||||
fg = theme->colors.menuitemNormalText();
|
||||
bg = getBgColor();
|
||||
}
|
||||
|
||||
g->fillRect(bg, g->getClipBounds());
|
||||
|
||||
gfx::Rect bounds = getClientBounds();
|
||||
g->drawColoredRgbaSurface(
|
||||
m_icon, fg,
|
||||
bounds.x+bounds.w/2-m_icon->width()/2,
|
||||
bounds.y+bounds.h/2-m_icon->height()/2);
|
||||
}
|
||||
|
||||
} // namespace app
|
31
src/app/ui/icon_button.h
Normal file
31
src/app/ui/icon_button.h
Normal file
@ -0,0 +1,31 @@
|
||||
// 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_UI_ICON_BUTTON_H_INCLUDED
|
||||
#define APP_UI_ICON_BUTTON_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "ui/button.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
class IconButton : public ui::Button {
|
||||
public:
|
||||
IconButton(she::Surface* icon);
|
||||
|
||||
protected:
|
||||
// bool onProcessMessage(ui::Message* msg) override;
|
||||
void onPreferredSize(ui::PreferredSizeEvent& ev) override;
|
||||
void onPaint(ui::PaintEvent& ev) override;
|
||||
|
||||
private:
|
||||
she::Surface* m_icon;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif
|
@ -940,7 +940,7 @@ void Tabs::createFloatingOverlay(Tab* tab)
|
||||
gfx::Color c = lock->getPixel(x, y);
|
||||
c = (c != gfx::rgba(255, 0, 255, 0) &&
|
||||
c != gfx::rgba(255, 0, 255, 255) ?
|
||||
gfx::seta(c, 255):
|
||||
gfx::rgba(gfx::getr(c), gfx::getg(c), gfx::getb(c), 255):
|
||||
gfx::ColorNone);
|
||||
lock->putPixel(c, x, y);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Gfx 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.
|
||||
@ -32,11 +32,6 @@ namespace gfx {
|
||||
inline ColorComponent getb(Color c) { return (c >> ColorBShift) & 0xff; }
|
||||
inline ColorComponent geta(Color c) { return (c >> ColorAShift) & 0xff; }
|
||||
|
||||
inline Color setr(Color c, ColorComponent v) { return Color((c & ~ColorRShift) | (v << ColorRShift)); }
|
||||
inline Color setg(Color c, ColorComponent v) { return Color((c & ~ColorGShift) | (v << ColorGShift)); }
|
||||
inline Color setb(Color c, ColorComponent v) { return Color((c & ~ColorBShift) | (v << ColorBShift)); }
|
||||
inline Color seta(Color c, ColorComponent v) { return Color((c & ~ColorAShift) | (v << ColorAShift)); }
|
||||
|
||||
inline bool is_transparent(Color c) { return geta(c) == 0; }
|
||||
|
||||
} // namespace gfx
|
||||
|
@ -15,43 +15,39 @@
|
||||
|
||||
namespace she {
|
||||
|
||||
namespace {
|
||||
namespace {
|
||||
|
||||
#define INT_MULT(a, b, t) \
|
||||
#define MUL_UN8(a, b, t) \
|
||||
((t) = (a) * (b) + 0x80, ((((t) >> 8) + (t)) >> 8))
|
||||
|
||||
gfx::Color blend(const gfx::Color back, gfx::Color front)
|
||||
gfx::Color blend(const gfx::Color backdrop, gfx::Color src)
|
||||
{
|
||||
if (gfx::geta(backdrop) == 0)
|
||||
return src;
|
||||
else if (gfx::geta(src) == 0)
|
||||
return backdrop;
|
||||
|
||||
int Br, Bg, Bb, Ba;
|
||||
int Sr, Sg, Sb, Sa;
|
||||
int Rr, Rg, Rb, Ra;
|
||||
|
||||
Br = gfx::getr(backdrop);
|
||||
Bg = gfx::getg(backdrop);
|
||||
Bb = gfx::getb(backdrop);
|
||||
Ba = gfx::geta(backdrop);
|
||||
|
||||
Sr = gfx::getr(src);
|
||||
Sg = gfx::getg(src);
|
||||
Sb = gfx::getb(src);
|
||||
Sa = gfx::geta(src);
|
||||
|
||||
int 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;
|
||||
|
||||
if (gfx::geta(back) == 0) {
|
||||
return front;
|
||||
}
|
||||
else if (gfx::geta(front) == 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 = gfx::getr(back);
|
||||
B_g = gfx::getg(back);
|
||||
B_b = gfx::getb(back);
|
||||
B_a = gfx::geta(back);
|
||||
|
||||
F_r = gfx::getr(front);
|
||||
F_g = gfx::getg(front);
|
||||
F_b = gfx::getb(front);
|
||||
F_a = gfx::geta(front);
|
||||
|
||||
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 gfx::rgba(D_r, D_g, D_b, D_a);
|
||||
}
|
||||
return gfx::rgba(Rr, Rg, Rb, Ra);
|
||||
}
|
||||
|
||||
} // anoynmous namespace
|
||||
@ -79,9 +75,13 @@ public:
|
||||
if (gfx::geta(bg) > 0)
|
||||
dstColor = blend(dstColor, bg);
|
||||
|
||||
int srcAlpha = (((*ptr) & format.alphaMask) >> format.alphaShift);
|
||||
if (srcAlpha > 0)
|
||||
dstColor = blend(dstColor, gfx::seta(fg, srcAlpha));
|
||||
uint32_t src = (((*ptr) & format.alphaMask) >> format.alphaShift);
|
||||
if (src > 0) {
|
||||
src = gfx::rgba(gfx::getr(fg),
|
||||
gfx::getg(fg),
|
||||
gfx::getb(fg), src);
|
||||
dstColor = blend(dstColor, src);
|
||||
}
|
||||
|
||||
putPixel(dstColor, clip.dst.x+u, clip.dst.y+v);
|
||||
++ptr;
|
||||
|
Loading…
x
Reference in New Issue
Block a user