Refactor filters (effects).

+ Added Filter, FilterManager, and FilterIndexedData interfaces.
+ Moved all widgets related to filters to src/commands/filters.
+ Added the filters library.
+ Added FilterWindow and one derived window for each filter.
This commit is contained in:
David Capello 2011-03-13 15:50:31 -03:00
parent d20bd1a31b
commit a8d9636467
69 changed files with 4761 additions and 4665 deletions

View File

@ -1,19 +1,6 @@
<!-- ASE - Allegro Sprite Editor -->
<!-- Copyright (C) 2001-2011 by David Capello -->
<jinete>
<window text="Color Curve" name="color_curve">
<box vertical="true">
<box horizontal="true" expansive="true">
<view expansive="true" name="curve" /><!-- custom widget -->
<box vertical="true">
<button text="&amp;OK" closewindow="true" name="button_ok" magnetic="true" />
<button text="&amp;Cancel" closewindow="true" />
<box name="target" />
<check text="&amp;Preview" name="preview" />
</box>
</box>
</box>
</window>
<window text="Point Properties" name="point_properties">
<box vertical="true">
<box horizontal="true" expansive="true">

View File

@ -1,64 +1,12 @@
<!-- ASE - Allegro Sprite Editor -->
<!-- Copyright (C) 2001-2011 by David Capello -->
<jinete>
<window text="Convolution Matrix" name="convolution_matrix">
<box vertical="true">
<box horizontal="true" expansive="true">
<view expansive="true" name="view" /><!-- custom widget -->
<box vertical="true">
<button text="&amp;OK" closewindow="true" name="button_ok" magnetic="true" />
<button text="&amp;Cancel" closewindow="true" />
<box name="target" />
<check text="&amp;Preview" name="preview" />
<check text="&amp;Tiled" name="tiled" />
</box>
</box>
<box vertical="true" name="controls" expansive="true">
<view expansive="true" name="view" minwidth="128" minheight="64">
<listbox name="stock" />
</view>
<box horizontal="true">
<button text="&amp;Reload Stock" name="reload" />
<button text="&amp;Generate" name="generate" />
</box>
</box>
</window>
<window text="Generate New Matrix" name="generate_convolution_matrix">
<box vertical="true">
<box horizontal="true" expansive="true" homogeneous="true">
<box vertical="true" expansive="true">
<label text="X axis" />
<view expansive="true" name="view_x" /><!-- custom widget -->
</box>
<box vertical="true" expansive="true">
<label text="Y axis" />
<view expansive="true" name="view_y" /><!-- custom widget -->
</box>
</box>
<box horizontal="true" homogeneous="true">
<box horizontal="true">
<box vertical="true" homogeneous="true">
<label text="Width:" />
<label text="Height:" />
</box>
<box vertical="true" homogeneous="true" expansive="true">
<slider min="1" max="31" name="width" />
<slider min="1" max="31" name="height" />
</box>
<box vertical="true" homogeneous="true">
<label text="Div:" />
<label text="Bias:" />
</box>
<box vertical="true" homogeneous="true" expansive="true">
<entry maxsize="32" name="div" />
<entry maxsize="32" name="bias" />
</box>
<box vertical="true" homogeneous="true">
<check text="Auto" name="div_auto" />
<check text="Auto" name="bias_auto" />
</box>
</box>
</box>
<box horizontal="true" homogeneous="true">
<button text="&amp;OK" closewindow="true" name="button_ok" magnetic="true" />
<button text="&amp;Cancel" closewindow="true" />
</box>
</box>
</window>
</jinete>

View File

@ -0,0 +1,10 @@
<!-- ASE - Allegro Sprite Editor -->
<!-- Copyright (C) 2001-2011 by David Capello -->
<jinete>
<grid columns="2" name="controls">
<label text="Width:" />
<entry name="width" maxsize="4" cell_align="horizontal" />
<label text="Height:" />
<entry name="height" maxsize="4" cell_align="horizontal" />
</grid>
</jinete>

View File

@ -1,14 +0,0 @@
<!-- ASE - Allegro Sprite Editor -->
<!-- Copyright (C) 2001-2011 by David Capello -->
<jinete>
<window text="Invert Color" name="invert_color">
<box vertical="true">
<box vertical="true" expansive="true" name="target" />
<check text="&amp;Preview" name="preview" />
<box horizontal="true" homogeneous="true">
<button text="&amp;OK" closewindow="true" name="button_ok" magnetic="true" />
<button text="&amp;Cancel" closewindow="true" />
</box>
</box>
</window>
</jinete>

View File

@ -1,29 +0,0 @@
<!-- ASE - Allegro Sprite Editor -->
<!-- Copyright (C) 2001-2011 by David Capello -->
<jinete>
<window text="Median Blur" name="median">
<box vertical="true">
<box horizontal="true">
<box horizontal="true" expansive="true">
<box vertical="true" homogeneous="true">
<label text="Width:" />
<label text="Height:" />
</box>
<box vertical="true" homogeneous="true" expansive="true">
<entry expansive="true" name="width" maxsize="4" />
<entry expansive="true" name="height" maxsize="4" />
</box>
</box>
<box vertical="true">
<box name="target" />
<check text="&amp;Preview" name="preview" />
<check text="&amp;Tiled" name="tiled" />
</box>
</box>
<box horizontal="true" homogeneous="true" expansive="true">
<button text="&amp;OK" closewindow="true" name="button_ok" magnetic="true" />
<button text="&amp;Cancel" closewindow="true" />
</box>
</box>
</window>
</jinete>

View File

@ -1,25 +1,16 @@
<!-- ASE - Allegro Sprite Editor -->
<!-- Copyright (C) 2001-2011 by David Capello -->
<jinete>
<window text="Replace Color" name="replace_color">
<box horizontal="true">
<box vertical="true" expansive="true">
<box horizontal="true" expansive="true">
<box vertical="true" homogeneous="true">
<label text="From:" />
<label text="To:" />
</box>
<box vertical="true" homogeneous="true" expansive="true" name="color_buttons_box" />
</box>
<label text="Tolerance:" />
<slider min="0" max="255" name="tolerance" />
</box>
<box vertical="true">
<button text="&amp;OK" closewindow="true" name="button_ok" magnetic="true" />
<button text="&amp;Cancel" closewindow="true" />
<box name="target" />
<check text="&amp;Preview" name="preview" />
<box vertical="true" expansive="true" name="controls">
<box horizontal="true" expansive="true">
<grid columns="2" name="controls">
<label text="From:" />
<colorpicker name="from" cell_align="horizontal" />
<label text="To:" />
<colorpicker name="to" cell_align="horizontal" />
</grid>
</box>
<label text="Tolerance:" />
<slider min="0" max="255" name="tolerance" />
</box>
</window>
</jinete>

View File

@ -43,7 +43,7 @@ else()
endif()
# All libraries for .exe files
set(all_libs aseprite-library gui-lib gfx-lib base-lib ${libs3rdparty} allegro ${sys_libs})
set(all_libs filters-lib aseprite-library gui-lib gfx-lib base-lib ${libs3rdparty} allegro ${sys_libs})
# Directories where .h files can be found
include_directories(
@ -63,6 +63,7 @@ add_subdirectory(allegro)
add_subdirectory(base)
add_subdirectory(gfx)
add_subdirectory(gui)
add_subdirectory(filters)
######################################################################
# aseprite library
@ -151,12 +152,18 @@ add_library(aseprite-library
commands/cmd_undo.cpp
commands/command.cpp
commands/commands.cpp
commands/fx/cmd_color_curve.cpp
commands/fx/cmd_convolution_matrix.cpp
commands/fx/cmd_despeckle.cpp
commands/fx/cmd_invert_color.cpp
commands/fx/cmd_replace_color.cpp
commands/fx/effectbg.cpp
commands/filters/cmd_color_curve.cpp
commands/filters/cmd_convolution_matrix.cpp
commands/filters/cmd_despeckle.cpp
commands/filters/cmd_invert_color.cpp
commands/filters/cmd_replace_color.cpp
commands/filters/color_curve_editor.cpp
commands/filters/convolution_matrix_stock.cpp
commands/filters/filter_manager_impl.cpp
commands/filters/filter_preview.cpp
commands/filters/filter_target_buttons.cpp
commands/filters/filter_window.cpp
commands/filters/filter_worker.cpp
core/cfg.cpp
core/drop_files.cpp
core/file_system.cpp
@ -168,12 +175,6 @@ add_library(aseprite-library
dialogs/playfli.cpp
dialogs/repo.cpp
dialogs/vectmap.cpp
effect/colcurve.cpp
effect/convmatr.cpp
effect/effect.cpp
effect/invrtcol.cpp
effect/median.cpp
effect/replcol.cpp
file/ase_format.cpp
file/bmp_format.cpp
file/file.cpp
@ -234,7 +235,6 @@ add_library(aseprite-library
widgets/color_button.cpp
widgets/color_selector.cpp
widgets/color_sliders.cpp
widgets/curvedit.cpp
widgets/editor/click.cpp
widgets/editor/cursor.cpp
widgets/editor/editor.cpp
@ -245,10 +245,8 @@ add_library(aseprite-library
widgets/hex_color_entry.cpp
widgets/menuitem.cpp
widgets/palette_view.cpp
widgets/preview.cpp
widgets/statebar.cpp
widgets/tabs.cpp
widgets/target.cpp
widgets/toolbar.cpp)
######################################################################

View File

@ -0,0 +1,149 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "app.h"
#include "app/color.h"
#include "base/bind.h"
#include "commands/command.h"
#include "commands/filters/color_curve_editor.h"
#include "commands/filters/filter_manager_impl.h"
#include "commands/filters/filter_window.h"
#include "core/cfg.h"
#include "filters/color_curve.h"
#include "filters/color_curve_filter.h"
#include "gui/gui.h"
#include "modules/gui.h"
#include "raster/mask.h"
#include "raster/sprite.h"
#include "sprite_wrappers.h"
#include "widgets/color_button.h"
static ColorCurve* the_curve = NULL;
// Slot for App::Exit signal
static void on_exit_delete_curve()
{
delete the_curve;
}
//////////////////////////////////////////////////////////////////////
// Color Curve window
class ColorCurveWindow : public FilterWindow
{
public:
ColorCurveWindow(ColorCurveFilter& filter, FilterManagerImpl& filterMgr)
: FilterWindow("Color Curve", "ColorCurve", &filterMgr,
WithChannelsSelector,
WithoutTiledCheckBox)
, m_filter(filter)
, m_editor(filter.getCurve(), 0, 0, 255, 255)
{
m_view.attachToView(&m_editor);
jwidget_expansive(&m_view, true);
jwidget_set_min_size(&m_view, 128, 64);
jwidget_add_child(getContainer(), &m_view);
m_editor.CurveEditorChange.connect(&ColorCurveWindow::onCurveChange, this);
}
protected:
void onCurveChange()
{
// The color curve in the filter is the same refereced by the
// editor. But anyway, we have to re-set the same curve in the
// filter to regenerate the map used internally by the filter
// (which is calculated inside setCurve() method).
m_filter.setCurve(m_editor.getCurve());
restartPreview();
}
private:
ColorCurveFilter& m_filter;
View m_view;
ColorCurveEditor m_editor;
};
//////////////////////////////////////////////////////////////////////
// Color Curve command
class ColorCurveCommand : public Command
{
public:
ColorCurveCommand();
Command* clone() const { return new ColorCurveCommand(*this); }
protected:
bool onEnabled(Context* context);
void onExecute(Context* context);
};
ColorCurveCommand::ColorCurveCommand()
: Command("ColorCurve",
"Color Curve",
CmdRecordableFlag)
{
}
bool ColorCurveCommand::onEnabled(Context* context)
{
const CurrentSpriteReader sprite(context);
return sprite != NULL;
}
void ColorCurveCommand::onExecute(Context* context)
{
// Default curve
if (!the_curve) {
// TODO load the curve?
the_curve = new ColorCurve(ColorCurve::Linear);
the_curve->addPoint(gfx::Point(0, 0));
the_curve->addPoint(gfx::Point(255, 255));
App::instance()->Exit.connect(&on_exit_delete_curve);
}
ColorCurveFilter filter;
filter.setCurve(the_curve);
FilterManagerImpl filterMgr(context->getCurrentSprite(), &filter);
filterMgr.setTarget(TARGET_RED_CHANNEL |
TARGET_GREEN_CHANNEL |
TARGET_BLUE_CHANNEL |
TARGET_GRAY_CHANNEL |
TARGET_ALPHA_CHANNEL);
ColorCurveWindow window(filter, filterMgr);
if (window.doModal()) {
// TODO save the curve?
}
}
//////////////////////////////////////////////////////////////////////
// CommandFactory
Command* CommandFactory::createColorCurveCommand()
{
return new ColorCurveCommand;
}

View File

@ -0,0 +1,221 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <string.h>
#include "app/color.h"
#include "base/bind.h"
#include "commands/command.h"
#include "commands/filters/convolution_matrix_stock.h"
#include "commands/filters/filter_manager_impl.h"
#include "commands/filters/filter_window.h"
#include "core/cfg.h"
#include "filters/convolution_matrix.h"
#include "filters/convolution_matrix_filter.h"
#include "gui/button.h"
#include "gui/frame.h"
#include "gui/label.h"
#include "gui/list.h"
#include "gui/listbox.h"
#include "gui/slider.h"
#include "gui/view.h"
#include "gui/widget.h"
#include "modules/gui.h"
#include "raster/mask.h"
#include "raster/sprite.h"
#include "sprite_wrappers.h"
static const char* ConfigSection = "ConvolutionMatrix";
//////////////////////////////////////////////////////////////////////
// Convolution Matrix window
class ConvolutionMatrixWindow : public FilterWindow
{
public:
ConvolutionMatrixWindow(ConvolutionMatrixFilter& filter, FilterManagerImpl& filterMgr, ConvolutionMatrixStock& stock)
: FilterWindow("Convolution Matrix", ConfigSection, &filterMgr,
WithChannelsSelector,
WithTiledCheckBox,
filter.getTiledMode())
, m_filter(filter)
, m_controlsWidget(load_widget("convolution_matrix.xml", "controls"))
, m_stock(stock)
{
get_widgets(m_controlsWidget,
"view", &m_view,
"stock", &m_stockListBox,
"reload", &m_reloadButton, NULL);
jwidget_add_child(getContainer(), m_controlsWidget);
m_reloadButton->Click.connect(&ConvolutionMatrixWindow::onReloadStock, this);
// TODO convert listbox to c++ class ListBox
//m_stockListBox->Change.connect(Bind<void>(&ConvolutionMatrixWindow::onMatrixChange, this));
hook_signal(m_stockListBox, JI_SIGNAL_LISTBOX_CHANGE, &ConvolutionMatrixWindow::listboxChangeHandler, this);
fillStockListBox();
}
private:
void onReloadStock(Event& ev)
{
m_stock.reloadStock();
fillStockListBox();
}
void setupTiledMode(TiledMode tiledMode)
{
m_filter.setTiledMode(tiledMode);
}
void fillStockListBox()
{
const char* oldSelected = (m_filter.getMatrix() ? m_filter.getMatrix()->getName(): NULL);
JLink link, next;
// Clean the list
JI_LIST_FOR_EACH_SAFE(m_stockListBox->children, link, next) {
Widget* listitem = reinterpret_cast<Widget*>(link->data);
jwidget_remove_child(m_stockListBox, listitem);
jwidget_free(listitem);
}
for (ConvolutionMatrixStock::iterator it = m_stock.begin(), end = m_stock.end();
it != end; ++it) {
SharedPtr<ConvolutionMatrix> matrix = *it;
Widget* listitem = jlistitem_new(matrix->getName()); // TODO convert listitem to a class
jwidget_add_child(m_stockListBox, listitem);
}
selectMatrixByName(oldSelected);
}
void selectMatrixByName(const char* oldSelected)
{
Widget* select_this = reinterpret_cast<Widget*>(jlist_first_data(m_stockListBox->children));
if (oldSelected) {
JLink link;
JI_LIST_FOR_EACH(m_stockListBox->children, link) {
Widget* child = reinterpret_cast<Widget*>(link->data);
if (strcmp(child->getText(), oldSelected) == 0) {
select_this = child;
break;
}
}
}
if (select_this) {
select_this->setSelected(true);
onMatrixChange();
}
m_view->updateView();
}
void onMatrixChange()
{
Widget* selected = jlistbox_get_selected_child(m_stockListBox);
SharedPtr<ConvolutionMatrix> matrix = m_stock.getByName(selected->getText());
Target newTarget = matrix->getDefaultTarget();
m_filter.setMatrix(matrix);
setNewTarget(newTarget);
restartPreview();
}
// TODO This function must be removed if ListBox C++ class is added.
static bool listboxChangeHandler(Widget* widget, void *data)
{
ConvolutionMatrixWindow* window = (ConvolutionMatrixWindow*)data;
window->onMatrixChange();
return true;
}
ConvolutionMatrixFilter& m_filter;
WidgetPtr m_controlsWidget;
ConvolutionMatrixStock& m_stock;
View* m_view;
Widget* m_stockListBox;
Button* m_reloadButton;
};
//////////////////////////////////////////////////////////////////////
// Convolution Matrix command
class ConvolutionMatrixCommand : public Command
{
public:
ConvolutionMatrixCommand();
Command* clone() const { return new ConvolutionMatrixCommand(*this); }
protected:
bool onEnabled(Context* context);
void onExecute(Context* context);
};
ConvolutionMatrixCommand::ConvolutionMatrixCommand()
: Command("ConvolutionMatrix",
"Convolution Matrix",
CmdRecordableFlag)
{
}
bool ConvolutionMatrixCommand::onEnabled(Context* context)
{
const CurrentSpriteReader sprite(context);
return sprite != NULL;
}
void ConvolutionMatrixCommand::onExecute(Context* context)
{
// Load stock
ConvolutionMatrixStock m_stock;
// Get last used (selected) matrix
SharedPtr<ConvolutionMatrix> matrix =
m_stock.getByName(get_config_string(ConfigSection, "Selected", ""));
// Create the filter and setup initial settings
ConvolutionMatrixFilter filter;
filter.setTiledMode(context->getSettings()->getTiledMode());
if (matrix != 0)
filter.setMatrix(matrix);
FilterManagerImpl filterMgr(context->getCurrentSprite(), &filter);
ConvolutionMatrixWindow window(filter, filterMgr, m_stock);
if (window.doModal()) {
if (filter.getMatrix() != NULL)
set_config_string(ConfigSection, "Selected", filter.getMatrix()->getName());
}
}
//////////////////////////////////////////////////////////////////////
// CommandFactory
Command* CommandFactory::createConvolutionMatrixCommand()
{
return new ConvolutionMatrixCommand;
}

View File

@ -0,0 +1,142 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <stdio.h>
#include "base/bind.h"
#include "commands/command.h"
#include "commands/filters/filter_manager_impl.h"
#include "commands/filters/filter_window.h"
#include "core/cfg.h"
#include "filters/median_filter.h"
#include "gui/button.h"
#include "gui/entry.h"
#include "gui/frame.h"
#include "gui/grid.h"
#include "gui/widget.h"
#include "modules/gui.h"
#include "raster/mask.h"
#include "raster/sprite.h"
#include "settings/settings.h"
#include "sprite_wrappers.h"
static const char* ConfigSection = "Despeckle";
//////////////////////////////////////////////////////////////////////
// Despeckle window
class DespeckleWindow : public FilterWindow
{
public:
DespeckleWindow(MedianFilter& filter, FilterManagerImpl& filterMgr)
: FilterWindow("Median Blur", ConfigSection, &filterMgr,
WithChannelsSelector,
WithTiledCheckBox,
filter.getTiledMode())
, m_filter(filter)
, m_controlsWidget(load_widget("despeckle.xml", "controls"))
{
get_widgets(m_controlsWidget,
"width", &m_widthEntry,
"height", &m_heightEntry, NULL);
jwidget_add_child(getContainer(), m_controlsWidget);
m_widthEntry->setTextf("%d", m_filter.getWidth());
m_heightEntry->setTextf("%d", m_filter.getHeight());
m_widthEntry->EntryChange.connect(&DespeckleWindow::onSizeChange, this);
m_heightEntry->EntryChange.connect(&DespeckleWindow::onSizeChange, this);
}
private:
void onSizeChange()
{
m_filter.setSize(m_widthEntry->getTextInt(),
m_heightEntry->getTextInt());
restartPreview();
}
void setupTiledMode(TiledMode tiledMode)
{
m_filter.setTiledMode(tiledMode);
}
MedianFilter& m_filter;
WidgetPtr m_controlsWidget;
Entry* m_widthEntry;
Entry* m_heightEntry;
};
//////////////////////////////////////////////////////////////////////
// Despeckle command
class DespeckleCommand : public Command
{
public:
DespeckleCommand();
Command* clone() const { return new DespeckleCommand(*this); }
protected:
bool onEnabled(Context* context);
void onExecute(Context* context);
};
DespeckleCommand::DespeckleCommand()
: Command("Despeckle",
"Despeckle",
CmdRecordableFlag)
{
}
bool DespeckleCommand::onEnabled(Context* context)
{
const CurrentSpriteReader sprite(context);
return sprite != NULL;
}
void DespeckleCommand::onExecute(Context* context)
{
MedianFilter filter;
filter.setTiledMode(context->getSettings()->getTiledMode());
filter.setSize(get_config_int(ConfigSection, "Width", 3),
get_config_int(ConfigSection, "Height", 3));
FilterManagerImpl filterMgr(context->getCurrentSprite(), &filter);
filterMgr.setTarget(TARGET_RED_CHANNEL |
TARGET_GREEN_CHANNEL |
TARGET_BLUE_CHANNEL |
TARGET_GRAY_CHANNEL);
DespeckleWindow window(filter, filterMgr);
if (window.doModal()) {
set_config_int(ConfigSection, "Width", filter.getWidth());
set_config_int(ConfigSection, "Height", filter.getHeight());
context->getSettings()->setTiledMode(filter.getTiledMode());
}
}
//////////////////////////////////////////////////////////////////////
// CommandFactory
Command* CommandFactory::createDespeckleCommand()
{
return new DespeckleCommand;
}

View File

@ -0,0 +1,106 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "app/color.h"
#include "base/bind.h"
#include "commands/command.h"
#include "commands/filters/filter_manager_impl.h"
#include "commands/filters/filter_window.h"
#include "core/cfg.h"
#include "filters/invert_color_filter.h"
#include "gui/button.h"
#include "gui/frame.h"
#include "gui/label.h"
#include "gui/slider.h"
#include "gui/widget.h"
#include "modules/gui.h"
#include "raster/image.h"
#include "raster/mask.h"
#include "raster/sprite.h"
#include "sprite_wrappers.h"
#include "widgets/color_button.h"
static const char* ConfigSection = "InvertColor";
//////////////////////////////////////////////////////////////////////
// Invert Color window
class InvertColorWindow : public FilterWindow
{
public:
InvertColorWindow(InvertColorFilter& filter, FilterManagerImpl& filterMgr)
: FilterWindow("Invert Color", ConfigSection, &filterMgr,
WithChannelsSelector,
WithoutTiledCheckBox)
, m_filter(filter)
{
}
private:
InvertColorFilter& m_filter;
};
//////////////////////////////////////////////////////////////////////
// Invert Color command
class InvertColorCommand : public Command
{
public:
InvertColorCommand();
Command* clone() const { return new InvertColorCommand(*this); }
protected:
bool onEnabled(Context* context);
void onExecute(Context* context);
};
InvertColorCommand::InvertColorCommand()
: Command("InvertColor",
"Invert Color",
CmdRecordableFlag)
{
}
bool InvertColorCommand::onEnabled(Context* context)
{
const CurrentSpriteReader sprite(context);
return sprite != NULL;
}
void InvertColorCommand::onExecute(Context* context)
{
InvertColorFilter filter;
FilterManagerImpl filterMgr(context->getCurrentSprite(), &filter);
filterMgr.setTarget(TARGET_RED_CHANNEL |
TARGET_GREEN_CHANNEL |
TARGET_BLUE_CHANNEL |
TARGET_GRAY_CHANNEL);
InvertColorWindow window(filter, filterMgr);
window.doModal();
}
//////////////////////////////////////////////////////////////////////
// CommandFactory
Command* CommandFactory::createInvertColorCommand()
{
return new InvertColorCommand;
}

View File

@ -0,0 +1,182 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <stdio.h>
#include "app.h"
#include "app/color.h"
#include "app/color_utils.h"
#include "base/bind.h"
#include "commands/command.h"
#include "commands/filters/filter_window.h"
#include "commands/filters/filter_manager_impl.h"
#include "core/cfg.h"
#include "filters/replace_color_filter.h"
#include "gui/gui.h"
#include "modules/gui.h"
#include "raster/image.h"
#include "raster/mask.h"
#include "raster/sprite.h"
#include "sprite_wrappers.h"
#include "widgets/color_bar.h"
#include "widgets/color_button.h"
static const char* ConfigSection = "ReplaceColor";
//////////////////////////////////////////////////////////////////////
// Wrapper for ReplaceColorFilter to handle colors in an easy way
class ReplaceColorFilterWrapper : public ReplaceColorFilter
{
public:
ReplaceColorFilterWrapper(Layer* layer) : m_layer(layer) { }
void setFrom(const Color& from) {
m_from = from;
ReplaceColorFilter::setFrom(color_utils::color_for_layer(from, m_layer));
}
void setTo(const Color& to) {
m_to = to;
ReplaceColorFilter::setTo(color_utils::color_for_layer(to, m_layer));
}
Color getFrom() const { return m_from; }
Color getTo() const { return m_to; }
private:
Layer* m_layer;
Color m_from;
Color m_to;
};
//////////////////////////////////////////////////////////////////////
// Replace Color window
class ReplaceColorWindow : public FilterWindow
{
public:
ReplaceColorWindow(ReplaceColorFilterWrapper& filter, FilterManagerImpl& filterMgr)
: FilterWindow("Replace Color", ConfigSection, &filterMgr,
WithChannelsSelector,
WithoutTiledCheckBox)
, m_filter(filter)
, m_controlsWidget(load_widget("replace_color.xml", "controls"))
{
get_widgets(m_controlsWidget,
"from", &m_fromButton,
"to", &m_toButton,
"tolerance", &m_toleranceSlider, NULL);
jwidget_add_child(getContainer(), m_controlsWidget);
m_fromButton->setColor(m_filter.getFrom());
m_toButton->setColor(m_filter.getTo());
m_toleranceSlider->setValue(m_filter.getTolerance());
m_fromButton->Change.connect(&ReplaceColorWindow::onFromChange, this);
m_toButton->Change.connect(&ReplaceColorWindow::onToChange, this);
m_toleranceSlider->Change.connect(&ReplaceColorWindow::onToleranceChange, this);
}
protected:
void onFromChange(const Color& color)
{
m_filter.setFrom(color);
restartPreview();
}
void onToChange(const Color& color)
{
m_filter.setTo(color);
restartPreview();
}
void onToleranceChange()
{
m_filter.setTolerance(m_toleranceSlider->getValue());
restartPreview();
}
private:
ReplaceColorFilterWrapper& m_filter;
WidgetPtr m_controlsWidget;
ColorButton* m_fromButton;
ColorButton* m_toButton;
Slider* m_toleranceSlider;
};
//////////////////////////////////////////////////////////////////////
// Replace Color command
class ReplaceColorCommand : public Command
{
public:
ReplaceColorCommand();
Command* clone() const { return new ReplaceColorCommand(*this); }
protected:
bool onEnabled(Context* context);
void onExecute(Context* context);
};
ReplaceColorCommand::ReplaceColorCommand()
: Command("ReplaceColor",
"Replace Color",
CmdRecordableFlag)
{
}
bool ReplaceColorCommand::onEnabled(Context* context)
{
const CurrentSpriteReader sprite(context);
return sprite != NULL;
}
void ReplaceColorCommand::onExecute(Context* context)
{
Sprite* sprite = context->getCurrentSprite();
ReplaceColorFilterWrapper filter(sprite->getCurrentLayer());
filter.setFrom(get_config_color(ConfigSection, "Color1", app_get_colorbar()->getFgColor()));
filter.setTo(get_config_color(ConfigSection, "Color2", app_get_colorbar()->getBgColor()));
filter.setTolerance(get_config_int(ConfigSection, "Tolerance", 0));
FilterManagerImpl filterMgr(sprite, &filter);
filterMgr.setTarget(TARGET_RED_CHANNEL |
TARGET_GREEN_CHANNEL |
TARGET_BLUE_CHANNEL |
TARGET_GRAY_CHANNEL |
TARGET_ALPHA_CHANNEL);
ReplaceColorWindow window(filter, filterMgr);
if (window.doModal()) {
set_config_color(ConfigSection, "From", filter.getFrom());
set_config_color(ConfigSection, "To", filter.getTo());
set_config_int(ConfigSection, "Tolerance", filter.getTolerance());
}
}
//////////////////////////////////////////////////////////////////////
// CommandFactory
Command* CommandFactory::createReplaceColorCommand()
{
return new ReplaceColorCommand;
}

View File

@ -0,0 +1,381 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <allegro.h>
#include <cmath>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include "commands/filters/color_curve_editor.h"
#include "filters/color_curve.h"
#include "gui/alert.h"
#include "gui/entry.h"
#include "gui/frame.h"
#include "gui/manager.h"
#include "gui/message.h"
#include "gui/rect.h"
#include "gui/system.h"
#include "gui/view.h"
#include "gui/widget.h"
#include "modules/gui.h"
#define SCR2EDIT_X(xpos) \
(m_x1 + \
((m_x2 - m_x1 + 1) \
* ((xpos) - rc->x1 - border_width.l) \
/ (jrect_w(rc) - border_width.l - border_width.r)))
#define SCR2EDIT_Y(ypos) \
(m_y1 + \
((m_y2 - m_y1 + 1) \
* ((jrect_h(rc) - border_width.t - border_width.b) \
- ((ypos) - rc->y1 - border_width.t)) \
/ (jrect_h(rc) - border_width.t - border_width.b)))
#define EDIT2SCR_X(xpos) \
(rc->x1 + border_width.l \
+ ((jrect_w(rc) - border_width.l - border_width.r) \
* ((xpos) - m_x1) \
/ (m_x2 - m_x1 + 1)))
#define EDIT2SCR_Y(ypos) \
(rc->y1 \
+ (jrect_h(rc) - border_width.t - border_width.b) \
- ((jrect_h(rc) - border_width.t - border_width.b) \
* ((ypos) - m_y1) \
/ (m_y2 - m_y1 + 1)))
enum {
STATUS_STANDBY,
STATUS_MOVING_POINT,
STATUS_SCROLLING,
STATUS_SCALING,
};
ColorCurveEditor::ColorCurveEditor(ColorCurve* curve, int x1, int y1, int x2, int y2)
: Widget(JI_WIDGET)
, m_curve(curve)
{
jwidget_focusrest(this, true);
border_width.l = border_width.r = 1;
border_width.t = border_width.b = 1;
child_spacing = 0;
m_curve = curve;
m_x1 = x1;
m_y1 = y1;
m_x2 = x2;
m_y2 = y2;
m_status = STATUS_STANDBY;
m_editPoint = NULL;
/* TODO */
/* m_curve->type = CURVE_SPLINE; */
}
bool ColorCurveEditor::onProcessMessage(JMessage msg)
{
switch (msg->type) {
case JM_REQSIZE: {
#if 0
msg->reqsize.w =
+ border_width.l
+ ((m_x2 - m_x1 + 1))
+ border_width.r;
msg->reqsize.h =
+ border_width.t
+ ((m_y2 - m_y1 + 1))
+ border_width.b;
#else
msg->reqsize.w = border_width.l + 1 + border_width.r;
msg->reqsize.h = border_width.t + 1 + border_width.b;
#endif
return true;
}
case JM_KEYPRESSED: {
switch (msg->key.scancode) {
case KEY_INSERT: {
int x = SCR2EDIT_X(jmouse_x(0));
int y = SCR2EDIT_Y(jmouse_y(0));
// TODO undo?
m_curve->addPoint(gfx::Point(x, y));
invalidate();
CurveEditorChange();
break;
}
case KEY_DEL: {
gfx::Point* point = getClosestPoint(SCR2EDIT_X(jmouse_x(0)),
SCR2EDIT_Y(jmouse_y(0)),
NULL, NULL);
// TODO undo?
if (point) {
m_curve->removePoint(*point);
m_editPoint = NULL;
invalidate();
CurveEditorChange();
}
break;
}
default:
return false;
}
return true;
}
case JM_DRAW: {
BITMAP *bmp;
int x, y, u;
bmp = create_bitmap(jrect_w(rc), jrect_h(rc));
clear_to_color(bmp, makecol (0, 0, 0));
// Draw border
rect(bmp, 0, 0, bmp->w-1, bmp->h-1, makecol (255, 255, 0));
// Draw guides
for (x=1; x<=3; x++)
vline(bmp, x*bmp->w/4, 1, bmp->h-2, makecol (128, 128, 0));
for (y=1; y<=3; y++)
hline(bmp, 1, y*bmp->h/4, bmp->w-2, makecol (128, 128, 0));
// Get curve values
std::vector<int> values(m_x2-m_x1+1);
m_curve->getValues(m_x1, m_x2, values);
// Draw curve
for (x=border_width.l;
x<jrect_w(rc)-border_width.r; x++) {
u = SCR2EDIT_X(rc->x1+x);
u = MID(m_x1, u, m_x2);
y = values[u - m_x1];
y = MID(m_y1, y, m_y2);
putpixel(bmp, x, EDIT2SCR_Y(y)-rc->y1,
makecol(255, 255, 255));
}
// Draw nodes
for (ColorCurve::iterator it = m_curve->begin(), end = m_curve->end(); it != end; ++it) {
const gfx::Point& point = *it;
x = EDIT2SCR_X(point.x) - rc->x1;
y = EDIT2SCR_Y(point.y) - rc->y1;
rect(bmp, x-2, y-2, x+2, y+2,
m_editPoint == &point ? makecol(255, 255, 0):
makecol(0, 0, 255));
}
// Blit to screen
blit(bmp, ji_screen, 0, 0, rc->x1, rc->y1, bmp->w, bmp->h);
destroy_bitmap(bmp);
return true;
}
case JM_BUTTONPRESSED:
// Change scroll
if (msg->any.shifts & KB_SHIFT_FLAG) {
m_status = STATUS_SCROLLING;
jmouse_set_cursor(JI_CURSOR_SCROLL);
}
/* scaling */
/* else if (msg->shifts & KB_CTRL_FLAG) { */
/* m_status = STATUS_SCALING; */
/* jmouse_set_cursor(JI_CURSOR_SCROLL); */
/* } */
// Show manual-entry dialog
else if (msg->mouse.right) {
m_editPoint = getClosestPoint(SCR2EDIT_X(msg->mouse.x),
SCR2EDIT_Y(msg->mouse.y),
NULL, NULL);
if (m_editPoint) {
invalidate();
jwidget_flush_redraw(this);
if (editNodeManually(*m_editPoint))
CurveEditorChange();
m_editPoint = NULL;
invalidate();
}
return true;
}
// Edit node
else {
m_editPoint = getClosestPoint(SCR2EDIT_X(msg->mouse.x),
SCR2EDIT_Y(msg->mouse.y),
&m_editX,
&m_editY);
m_status = STATUS_MOVING_POINT;
jmouse_set_cursor(JI_CURSOR_HAND);
}
captureMouse();
// continue in motion message...
case JM_MOTION:
if (hasCapture()) {
switch (m_status) {
case STATUS_SCROLLING: {
View* view = View::getView(this);
gfx::Rect vp = view->getViewportBounds();
gfx::Point scroll = view->getViewScroll();
scroll.x += jmouse_x(1)-jmouse_x(0);
scroll.y += jmouse_y(1)-jmouse_y(0);
view->setViewScroll(scroll);
jmouse_control_infinite_scroll(vp);
break;
}
case STATUS_MOVING_POINT:
if (m_editPoint) {
*m_editX = SCR2EDIT_X(msg->mouse.x);
*m_editY = SCR2EDIT_Y(msg->mouse.y);
*m_editX = MID(m_x1, *m_editX, m_x2);
*m_editY = MID(m_y1, *m_editY, m_y2);
// TODO this should be optional
CurveEditorChange();
invalidate();
}
break;
}
return true;
}
#if 0 // TODO
// If the mouse move above a curve_editor, the focus change to
// this widget immediately
else if (!jwidget_has_focus(this)) {
jmanager_set_focus(this);
}
#endif
break;
case JM_BUTTONRELEASED:
if (hasCapture()) {
releaseMouse();
switch (m_status) {
case STATUS_SCROLLING:
jmouse_set_cursor(JI_CURSOR_NORMAL);
break;
/* case STATUS_SCALING: */
/* jmouse_set_cursor(JI_CURSOR_NORMAL); */
/* break; */
case STATUS_MOVING_POINT:
jmouse_set_cursor(JI_CURSOR_NORMAL);
CurveEditorChange();
m_editPoint = NULL;
invalidate();
break;
}
m_status = STATUS_STANDBY;
return true;
}
break;
}
return Widget::onProcessMessage(msg);
}
gfx::Point* ColorCurveEditor::getClosestPoint(int x, int y, int** edit_x, int** edit_y)
{
#define CALCDIST(xx, yy) \
dx = point->xx-x; \
dy = point->yy-y; \
dist = std::sqrt(static_cast<double>(dx*dx + dy*dy)); \
\
if (!point_found || dist <= dist_min) { \
point_found = point; \
dist_min = dist; \
\
if (edit_x) *edit_x = &point->xx; \
if (edit_y) *edit_y = &point->yy; \
}
gfx::Point* point;
gfx::Point* point_found = NULL;
int dx, dy;
double dist, dist_min = 0;
for (ColorCurve::iterator it = m_curve->begin(), end = m_curve->end(); it != end; ++it) {
point = &(*it);
CALCDIST(x, y);
}
return point_found;
}
int ColorCurveEditor::editNodeManually(gfx::Point& point)
{
JWidget entry_x, entry_y, button_ok;
gfx::Point point_copy = point;
int res;
FramePtr window(load_widget("color_curve.xml", "point_properties"));
entry_x = jwidget_find_name(window, "x");
entry_y = jwidget_find_name(window, "y");
button_ok = jwidget_find_name(window, "button_ok");
entry_x->setTextf("%d", point.x);
entry_y->setTextf("%d", point.y);
window->open_window_fg();
if (window->get_killer() == button_ok) {
point.x = entry_x->getTextDouble();
point.y = entry_y->getTextDouble();
res = true;
}
else {
point = point_copy;
res = false;
}
return res;
}

View File

@ -0,0 +1,53 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef COMMANDS_FILTERS_COLOR_CURVE_EDITOR_H_INCLUDED
#define COMMANDS_FILTERS_COLOR_CURVE_EDITOR_H_INCLUDED
#include "base/signal.h"
#include "gfx/point.h"
#include "gui/widget.h"
class ColorCurve;
class ColorCurveEditor : public Widget
{
public:
ColorCurveEditor(ColorCurve* curve, int x1, int y1, int x2, int y2);
ColorCurve* getCurve() const { return m_curve; }
Signal0<void> CurveEditorChange;
protected:
bool onProcessMessage(JMessage msg);
private:
gfx::Point* getClosestPoint(int x, int y, int** edit_x, int** edit_y);
int editNodeManually(gfx::Point& point);
ColorCurve* m_curve;
int m_x1, m_y1;
int m_x2, m_y2;
int m_status;
gfx::Point* m_editPoint;
int* m_editX;
int* m_editY;
};
#endif

View File

@ -0,0 +1,197 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <cstdlib>
#include "commands/filters/convolution_matrix_stock.h"
#include "filters/convolution_matrix.h"
#include "resource_finder.h"
#include "util/filetoks.h"
ConvolutionMatrixStock::ConvolutionMatrixStock()
{
reloadStock();
}
ConvolutionMatrixStock::~ConvolutionMatrixStock()
{
cleanStock();
}
SharedPtr<ConvolutionMatrix> ConvolutionMatrixStock::getByName(const char* name)
{
for (const_iterator it = begin(), end = this->end(); it != end; ++it) {
if (strcmp((*it)->getName(), name) == 0)
return *it;
}
return SharedPtr<ConvolutionMatrix>(0);
}
namespace {
class FileDestroyer {
public:
static void destroy(FILE* ptr) { fclose(ptr); }
};
}
void ConvolutionMatrixStock::reloadStock()
{
#define READ_TOK() { \
if (!tok_read(f, buf, leavings, sizeof (leavings))) \
break; \
}
#define READ_INT(var) { \
READ_TOK(); \
var = strtol(buf, NULL, 10); \
}
const char *names[] = { "convmatr.usr",
"convmatr.gen",
"convmatr.def", NULL };
char *s, buf[256], leavings[4096];
int i, c, x, y, w, h, div, bias;
SharedPtr<ConvolutionMatrix> matrix;
SharedPtr<FILE, FileDestroyer> f;
std::string name;
cleanStock();
for (i=0; names[i]; i++) {
ResourceFinder rf;
rf.findInDataDir(names[i]);
while (const char* path = rf.next()) {
// Open matrices stock file
f.reset(fopen(path, "r"));
if (!f)
continue;
tok_reset_line_num();
strcpy(leavings, "");
// Read the matrix name
while (tok_read(f, buf, leavings, sizeof(leavings))) {
// Name of the matrix
name = buf;
// Width and height
READ_INT(w);
READ_INT(h);
if ((w <= 0) || (w > 32) ||
(h <= 0) || (h > 32))
break;
// Create the matrix data
matrix.reset(new ConvolutionMatrix(w, h));
matrix->setName(name.c_str());
// Centre
READ_INT(x);
READ_INT(y);
if ((x < 0) || (x >= w) ||
(y < 0) || (y >= h))
break;
matrix->setCenterX(x);
matrix->setCenterY(y);
// Data
READ_TOK(); // Jump the `{' char
if (*buf != '{')
break;
c = 0;
div = 0;
for (y=0; y<h; ++y) {
for (x=0; x<w; ++x) {
READ_TOK();
int value = strtod(buf, NULL) * ConvolutionMatrix::Precision;
div += value;
matrix->value(x, y) = value;
}
}
READ_TOK(); // Jump the `}' char
if (*buf != '}')
break;
if (div > 0)
bias = 0;
else if (div == 0) {
div = ConvolutionMatrix::Precision;
bias = 128;
}
else {
div = ABS(div);
bias = 255;
}
// Div
READ_TOK();
if (strcmp(buf, "auto") != 0)
div = strtod(buf, NULL) * ConvolutionMatrix::Precision;
matrix->setDiv(div);
// Bias
READ_TOK();
if (strcmp(buf, "auto") != 0)
bias = strtod(buf, NULL);
matrix->setBias(bias);
// Target
READ_TOK();
Target target = 0;
for (s=buf; *s; s++) {
switch (*s) {
case 'r': target |= TARGET_RED_CHANNEL; break;
case 'g': target |= TARGET_GREEN_CHANNEL; break;
case 'b': target |= TARGET_BLUE_CHANNEL; break;
case 'a': target |= TARGET_ALPHA_CHANNEL; break;
}
}
if ((target & (TARGET_RED_CHANNEL |
TARGET_GREEN_CHANNEL |
TARGET_BLUE_CHANNEL)) != 0) {
target |= TARGET_GRAY_CHANNEL;
}
matrix->setDefaultTarget(target);
// Insert the new matrix in the list
m_matrices.push_back(matrix);
}
}
}
}
void ConvolutionMatrixStock::cleanStock()
{
m_matrices.clear();
}

View File

@ -0,0 +1,52 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef COMMANDS_FILTERS_CONVOLUTION_MATRIX_STOCK_H_INCLUDED
#define COMMANDS_FILTERS_CONVOLUTION_MATRIX_STOCK_H_INCLUDED
#include <vector>
#include "base/shared_ptr.h"
class ConvolutionMatrix;
// A container of all convolution matrices in the convmatr.def file.
class ConvolutionMatrixStock
{
public:
typedef std::vector<SharedPtr<ConvolutionMatrix> >::iterator iterator;
typedef std::vector<SharedPtr<ConvolutionMatrix> >::const_iterator const_iterator;
ConvolutionMatrixStock();
virtual ~ConvolutionMatrixStock();
iterator begin() { return m_matrices.begin(); }
iterator end() { return m_matrices.end(); }
const_iterator begin() const { return m_matrices.begin(); }
const_iterator end() const { return m_matrices.end(); }
SharedPtr<ConvolutionMatrix> getByName(const char* name);
void reloadStock();
void cleanStock();
private:
std::vector<SharedPtr<ConvolutionMatrix> > m_matrices;
};
#endif

View File

@ -0,0 +1,414 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "commands/filters/filter_manager_impl.h"
#include "core/cfg.h"
#include "filters/filter.h"
#include "gui/manager.h"
#include "gui/rect.h"
#include "gui/region.h"
#include "gui/view.h"
#include "gui/widget.h"
#include "modules/editors.h"
#include "raster/cel.h"
#include "raster/image.h"
#include "raster/images_collector.h"
#include "raster/layer.h"
#include "raster/mask.h"
#include "raster/sprite.h"
#include "raster/stock.h"
#include "raster/undo.h"
#include "widgets/editor.h"
#include <cstdlib>
#include <cstring>
using namespace std;
FilterManagerImpl::FilterManagerImpl(Sprite* sprite, Filter* filter)
: m_sprite(sprite)
, m_filter(filter)
, m_progressDelegate(NULL)
{
int offset_x, offset_y;
m_src = NULL;
m_dst = NULL;
m_row = 0;
m_offset_x = 0;
m_offset_y = 0;
m_mask = NULL;
m_preview_mask = NULL;
m_mask_address = NULL;
m_targetOrig = TARGET_ALL_CHANNELS;
m_target = TARGET_ALL_CHANNELS;
Image* image = m_sprite->getCurrentImage(&offset_x, &offset_y);
if (image == NULL)
throw NoImageException();
init(sprite->getCurrentLayer(), image, offset_x, offset_y);
}
FilterManagerImpl::~FilterManagerImpl()
{
if (m_preview_mask)
mask_free(m_preview_mask);
if (m_dst)
image_free(m_dst);
}
void FilterManagerImpl::setProgressDelegate(IProgressDelegate* progressDelegate)
{
m_progressDelegate = progressDelegate;
}
void FilterManagerImpl::setTarget(int target)
{
m_targetOrig = target;
m_target = target;
/* the alpha channel of the background layer can't be modified */
if (m_sprite->getCurrentLayer() &&
m_sprite->getCurrentLayer()->is_background())
m_target &= ~TARGET_ALPHA_CHANNEL;
}
void FilterManagerImpl::begin()
{
m_row = 0;
m_mask = m_sprite->getMask();
updateMask(m_mask, m_src);
}
void FilterManagerImpl::beginForPreview()
{
if (m_preview_mask) {
mask_free(m_preview_mask);
m_preview_mask = NULL;
}
if ((m_sprite->getMask()) && (m_sprite->getMask()->bitmap))
m_preview_mask = mask_new_copy(m_sprite->getMask());
else {
m_preview_mask = mask_new();
mask_replace(m_preview_mask,
m_offset_x, m_offset_y,
m_src->w, m_src->h);
}
m_row = 0;
m_mask = m_preview_mask;
{
Editor* editor = current_editor;
gfx::Rect vp = View::getView(editor)->getViewportBounds();
int x1, y1, x2, y2;
int x, y, w, h;
editor->screen_to_editor(vp.x, vp.y, &x1, &y1);
editor->screen_to_editor(vp.x+vp.w-1, vp.y+vp.h-1, &x2, &y2);
if (x1 < 0) x1 = 0;
if (y1 < 0) y1 = 0;
if (x2 >= m_sprite->getWidth()) x2 = m_sprite->getWidth()-1;
if (y2 >= m_sprite->getHeight()) y2 = m_sprite->getHeight()-1;
x = x1;
y = y1;
w = x2 - x1 + 1;
h = y2 - y1 + 1;
if ((w < 1) || (h < 1)) {
mask_free(m_preview_mask);
m_preview_mask = NULL;
m_row = -1;
return;
}
mask_intersect(m_preview_mask, x, y, w, h);
}
if (!updateMask(m_mask, m_src)) {
mask_free(m_preview_mask);
m_preview_mask = NULL;
m_row = -1;
return;
}
}
bool FilterManagerImpl::applyStep()
{
if ((m_row >= 0) && (m_row < m_h)) {
if ((m_mask) && (m_mask->bitmap)) {
m_d = div(m_x-m_mask->x+m_offset_x, 8);
m_mask_address = ((ase_uint8 **)m_mask->bitmap->line)[m_row+m_y-m_mask->y+m_offset_y]+m_d.quot;
}
else
m_mask_address = NULL;
switch (m_sprite->getImgType()) {
case IMAGE_RGB: m_filter->applyToRgba(this); break;
case IMAGE_GRAYSCALE: m_filter->applyToGrayscale(this); break;
case IMAGE_INDEXED: m_filter->applyToIndexed(this); break;
}
++m_row;
return true;
}
else {
return false;
}
}
void FilterManagerImpl::apply()
{
bool cancelled = false;
begin();
while (!cancelled && applyStep()) {
if (m_progressDelegate) {
// Report progress.
m_progressDelegate->reportProgress(m_progressBase + m_progressWidth * (m_row+1) / m_h);
// Does the user cancelled the whole process?
cancelled = m_progressDelegate->isCancelled();
}
}
if (!cancelled) {
// Undo stuff
if (m_sprite->getUndo()->isEnabled()) {
m_sprite->getUndo()->setLabel(m_filter->getName());
m_sprite->getUndo()->undo_image(m_src, m_x, m_y, m_w, m_h);
}
// Copy "dst" to "src"
image_copy(m_src, m_dst, 0, 0);
}
}
void FilterManagerImpl::applyToTarget()
{
bool cancelled = false;
ImagesCollector images(m_sprite,
(m_target & TARGET_ALL_LAYERS) == TARGET_ALL_LAYERS,
(m_target & TARGET_ALL_FRAMES) == TARGET_ALL_FRAMES,
true); // we will write in each image
if (images.empty())
return;
// Initialize writting operation
SpriteReader reader(m_sprite);
SpriteWriter writer(reader);
// Open group of undo operations
if (images.size() > 1) {
if (m_sprite->getUndo()->isEnabled())
m_sprite->getUndo()->undo_open();
}
m_progressBase = 0.0f;
m_progressWidth = 1.0f / images.size();
// For each target image
for (ImagesCollector::ItemsIterator it = images.begin();
it != images.end() && !cancelled;
++it) {
applyToImage(it->layer(), it->image(), it->cel()->x, it->cel()->y);
// Is there a delegate to know if the process was cancelled by the user?
if (m_progressDelegate)
cancelled = m_progressDelegate->isCancelled();
// Make progress
m_progressBase += m_progressWidth;
}
// Close group of undo operations
if (images.size() > 1) {
if (m_sprite->getUndo()->isEnabled())
m_sprite->getUndo()->undo_close();
}
}
void FilterManagerImpl::flush()
{
if (m_row >= 0) {
JRegion reg1, reg2;
struct jrect rect;
Editor* editor = current_editor;
reg1 = jregion_new(NULL, 0);
editor->editor_to_screen(m_x+m_offset_x,
m_y+m_offset_y+m_row-1,
&rect.x1, &rect.y1);
rect.x2 = rect.x1 + (m_w << editor->editor_get_zoom());
rect.y2 = rect.y1 + (1 << editor->editor_get_zoom());
reg2 = jregion_new(&rect, 1);
jregion_union(reg1, reg1, reg2);
jregion_free(reg2);
reg2 = jwidget_get_drawable_region(editor, JI_GDR_CUTTOPWINDOWS);
jregion_intersect(reg1, reg1, reg2);
jregion_free(reg2);
editor->invalidateRegion(reg1);
jregion_free(reg1);
}
}
const void* FilterManagerImpl::getSourceAddress()
{
switch (m_sprite->getImgType()) {
case IMAGE_RGB: return ((ase_uint32**)m_src->line)[m_row+m_y]+m_x;
case IMAGE_GRAYSCALE: return ((ase_uint16**)m_src->line)[m_row+m_y]+m_x;
case IMAGE_INDEXED: return ((ase_uint8**)m_src->line)[m_row+m_y]+m_x;
}
return NULL;
}
void* FilterManagerImpl::getDestinationAddress()
{
switch (m_sprite->getImgType()) {
case IMAGE_RGB: return ((ase_uint32**)m_dst->line)[m_row+m_y]+m_x;
case IMAGE_GRAYSCALE: return ((ase_uint16**)m_dst->line)[m_row+m_y]+m_x;
case IMAGE_INDEXED: return ((ase_uint8**)m_dst->line)[m_row+m_y]+m_x;
}
return NULL;
}
bool FilterManagerImpl::skipPixel()
{
bool skip = false;
if (m_mask_address) {
if (!((*m_mask_address) & (1<<m_d.rem)))
skip = true;
// Move to the next pixel in the mask.
_image_bitmap_next_bit(m_d, m_mask_address);
}
return skip;
}
Palette* FilterManagerImpl::getPalette()
{
return m_sprite->getCurrentPalette();
}
RgbMap* FilterManagerImpl::getRgbMap()
{
return m_sprite->getRgbMap();
}
void FilterManagerImpl::init(const Layer* layer, Image* image, int offset_x, int offset_y)
{
m_offset_x = offset_x;
m_offset_y = offset_y;
if (!updateMask(m_sprite->getMask(), image))
throw InvalidAreaException();
if (m_preview_mask) {
mask_free(m_preview_mask);
m_preview_mask = NULL;
}
if (m_dst) {
image_free(m_dst);
m_dst = NULL;
}
m_src = image;
m_dst = image_crop(image, 0, 0, image->w, image->h, 0);
m_row = -1;
m_mask = NULL;
m_preview_mask = NULL;
m_mask_address = NULL;
m_target = m_targetOrig;
/* the alpha channel of the background layer can't be modified */
if (layer->is_background())
m_target &= ~TARGET_ALPHA_CHANNEL;
}
void FilterManagerImpl::applyToImage(Layer* layer, Image* image, int x, int y)
{
init(layer, image, x, y);
apply();
}
bool FilterManagerImpl::updateMask(Mask* mask, const Image* image)
{
int x, y, w, h;
if ((mask) && (mask->bitmap)) {
x = mask->x - m_offset_x;
y = mask->y - m_offset_y;
w = mask->w;
h = mask->h;
if (x < 0) {
w += x;
x = 0;
}
if (y < 0) {
h += y;
y = 0;
}
if (x+w-1 >= image->w-1)
w = image->w-x;
if (y+h-1 >= image->h-1)
h = image->h-y;
}
else {
x = 0;
y = 0;
w = image->w;
h = image->h;
}
if ((w < 1) || (h < 1)) {
m_x = 0;
m_y = 0;
m_w = 0;
m_h = 0;
return false;
}
else {
m_x = x;
m_y = y;
m_w = w;
m_h = h;
return true;
}
}

View File

@ -0,0 +1,129 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef COMMANDS_FILTERS_FILTER_MANAGER_IMPL_H_INCLUDED
#define COMMANDS_FILTERS_FILTER_MANAGER_IMPL_H_INCLUDED
#include <cstring>
#include <stdlib.h>
#include "base/exception.h"
#include "filters/filter_indexed_data.h"
#include "filters/filter_manager.h"
#include "sprite_wrappers.h"
class Filter;
class Image;
class Layer;
class Mask;
class Sprite;
class InvalidAreaException : public base::Exception
{
public:
InvalidAreaException() throw()
: base::Exception("The current mask/area to apply the effect is completelly invalid.") { }
};
class NoImageException : public base::Exception
{
public:
NoImageException() throw()
: base::Exception("There are not an active image to apply the effect.\n"
"Please select a layer/cel with an image and try again.") { }
};
class FilterManagerImpl : public FilterManager
, public FilterIndexedData
{
public:
// Interface to report progress to the user and take input from him
// to cancel the whole process.
class IProgressDelegate {
public:
virtual ~IProgressDelegate() { }
// Called to report the progress of the filter (with progress from 0.0 to 1.0).
virtual void reportProgress(float progress) = 0;
// Should return true if the user wants to cancel the filter.
virtual bool isCancelled() = 0;
};
FilterManagerImpl(Sprite* sprite, Filter* filter);
~FilterManagerImpl();
void setProgressDelegate(IProgressDelegate* progressDelegate);
int getImgType() const { return m_sprite->getImgType(); };
void setTarget(Target target);
void begin();
void beginForPreview();
bool applyStep();
void apply();
void applyToTarget();
Sprite* getSprite() const { return m_sprite; }
Image* getDestinationImage() const { return m_dst; }
// Updates the current editor to show the progress of the preview.
void flush();
// FilterManager implementation
const void* getSourceAddress();
void* getDestinationAddress();
int getWidth() { return m_w; }
Target getTarget() { return m_target; }
FilterIndexedData* getIndexedData() { return this; }
bool skipPixel();
const Image* getSourceImage() { return m_src; }
int getX() { return m_x; }
int getY() { return m_y+m_row; }
// FilterIndexedData implementation
Palette* getPalette();
RgbMap* getRgbMap();
private:
void init(const Layer* layer, Image* image, int offset_x, int offset_y);
void applyToImage(Layer* layer, Image* image, int x, int y);
bool updateMask(Mask* mask, const Image* image);
Sprite* m_sprite;
Filter* m_filter;
Image* m_src;
Image* m_dst;
int m_row;
int m_x, m_y, m_w, m_h;
int m_offset_x, m_offset_y;
Mask* m_mask;
Mask* m_preview_mask;
unsigned char* m_mask_address;
div_t m_d;
Target m_targetOrig; // Original targets
Target m_target; // Filtered targets
// Hooks
float m_progressBase;
float m_progressWidth;
IProgressDelegate* m_progressDelegate;
};
#endif

View File

@ -0,0 +1,94 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "commands/filters/filter_preview.h"
#include "commands/filters/filter_manager_impl.h"
#include "gui/manager.h"
#include "gui/message.h"
#include "gui/widget.h"
#include "raster/sprite.h"
#include "util/render.h"
FilterPreview::FilterPreview(FilterManagerImpl* filterMgr)
: Widget(JI_WIDGET)
, m_filterMgr(filterMgr)
, m_timerId(-1)
{
setVisible(false);
}
FilterPreview::~FilterPreview()
{
stop();
}
void FilterPreview::stop()
{
m_filterMgr = NULL;
if (m_timerId >= 0) {
jmanager_remove_timer(m_timerId);
m_timerId = -1;
}
}
void FilterPreview::restartPreview()
{
m_filterMgr->beginForPreview();
if (m_timerId < 0)
m_timerId = jmanager_add_timer(this, 1);
jmanager_start_timer(m_timerId);
}
FilterManagerImpl* FilterPreview::getFilterManager() const
{
return m_filterMgr;
}
bool FilterPreview::onProcessMessage(JMessage msg)
{
switch (msg->type) {
case JM_OPEN:
RenderEngine::setPreviewImage(m_filterMgr->getSprite()->getCurrentLayer(),
m_filterMgr->getDestinationImage());
break;
case JM_CLOSE:
RenderEngine::setPreviewImage(NULL, NULL);
// Stop the preview timer.
jmanager_stop_timer(m_timerId);
break;
case JM_TIMER:
if (m_filterMgr) {
if (m_filterMgr->applyStep())
m_filterMgr->flush();
else
jmanager_stop_timer(m_timerId);
}
break;
}
return Widget::onProcessMessage(msg);
}

View File

@ -16,19 +16,30 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef WIDGETS_CURVEDIT_H_INCLUDED
#define WIDGETS_CURVEDIT_H_INCLUDED
#ifndef COMMANDS_FILTERS_FILTER_PREVIEW_H_INCLUDED
#define COMMANDS_FILTERS_FILTER_PREVIEW_H_INCLUDED
#include "gui/base.h"
#include "gui/widget.h"
// TODO use some JI_SIGNAL_USER
#define SIGNAL_CURVE_EDITOR_CHANGE 0x10004
class FilterManagerImpl;
struct Curve;
// Invisible widget to control a effect-preview in the current editor.
class FilterPreview : public Widget
{
public:
FilterPreview(FilterManagerImpl* filterMgr);
~FilterPreview();
JWidget curve_editor_new(Curve* curve, int x1, int y1, int x2, int y2);
int curve_editor_type();
void stop();
void restartPreview();
FilterManagerImpl* getFilterManager() const;
Curve* curve_editor_get_curve(JWidget curve_editor);
protected:
bool onProcessMessage(JMessage msg);
private:
FilterManagerImpl* m_filterMgr;
int m_timerId;
};
#endif

View File

@ -0,0 +1,212 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "commands/filters/filter_target_buttons.h"
#include <allegro.h>
#include <string.h>
#include "base/bind.h"
#include "gui/box.h"
#include "gui/button.h"
#include "gui/theme.h"
#include "gui/widget.h"
#include "modules/gfx.h"
#include "modules/gui.h"
#include "raster/image.h"
#include "skin/skin_parts.h"
FilterTargetButtons::FilterTargetButtons(int imgtype, bool withChannels)
: Box(JI_VERTICAL)
, m_target(0)
{
#define ADD(box, widget, hook) \
if (widget) { \
jwidget_set_border(widget, 2 * jguiscale()); \
jwidget_add_child(box, widget); \
widget->Click.connect(Bind<void>(&FilterTargetButtons::hook, this, widget)); \
}
Box* hbox;
CheckBox* r = NULL;
CheckBox* g = NULL;
CheckBox* b = NULL;
CheckBox* k = NULL;
CheckBox* a = NULL;
CheckBox* index = NULL;
Button* images = NULL;
hbox = new Box(JI_HORIZONTAL | JI_HOMOGENEOUS);
jwidget_noborders(this);
jwidget_noborders(hbox);
if (withChannels) {
switch (imgtype) {
case IMAGE_RGB:
case IMAGE_INDEXED:
r = check_button_new("R", 2, 0, 0, 0);
g = check_button_new("G", 0, 0, 0, 0);
b = check_button_new("B", 0, (imgtype == IMAGE_RGB) ? 0: 2, 0, 0);
r->setName("r");
g->setName("g");
b->setName("b");
if (imgtype == IMAGE_RGB) {
a = check_button_new("A", 0, 2, 0, 0);
a->setName("a");
}
else {
index = check_button_new("Index", 0, 0, 0, 0);
index->setName("i");
}
break;
case IMAGE_GRAYSCALE:
k = check_button_new("K", 2, 0, 0, 0);
a = check_button_new("A", 0, 2, 0, 0);
k->setName("k");
a->setName("a");
break;
}
}
// Create the button to select "image" target
images = new Button(NULL);
setup_bevels(images,
withChannels ? 0: 2,
withChannels ? 0: 2, 2, 2);
setup_mini_look(images);
set_gfxicon_to_button(images,
getTargetNormalIcon(),
getTargetSelectedIcon(), -1,
JI_CENTER | JI_MIDDLE);
// Make hierarchy
ADD(hbox, r, onChannelChange);
ADD(hbox, g, onChannelChange);
ADD(hbox, b, onChannelChange);
ADD(hbox, k, onChannelChange);
ADD(hbox, a, onChannelChange);
if (withChannels)
jwidget_add_child(this, hbox);
else
jwidget_free(hbox);
ADD(this, index, onChannelChange);
ADD(this, images, onImagesChange);
}
void FilterTargetButtons::setTarget(int target)
{
m_target = target;
selectTargetButton("r", TARGET_RED_CHANNEL);
selectTargetButton("g", TARGET_GREEN_CHANNEL);
selectTargetButton("b", TARGET_BLUE_CHANNEL);
selectTargetButton("a", TARGET_ALPHA_CHANNEL);
selectTargetButton("k", TARGET_GRAY_CHANNEL);
selectTargetButton("i", TARGET_INDEX_CHANNEL);
}
void FilterTargetButtons::selectTargetButton(const char* name, int specificTarget)
{
Widget* wgt = findChild(name);
if (wgt != NULL)
wgt->setSelected((m_target & specificTarget) == specificTarget);
}
void FilterTargetButtons::onChannelChange(ButtonBase* button)
{
int flag = 0;
switch (button->name[0]) {
case 'r': flag = TARGET_RED_CHANNEL; break;
case 'g': flag = TARGET_GREEN_CHANNEL; break;
case 'b': flag = TARGET_BLUE_CHANNEL; break;
case 'k': flag = TARGET_GRAY_CHANNEL; break;
case 'a': flag = TARGET_ALPHA_CHANNEL; break;
case 'i': flag = TARGET_INDEX_CHANNEL; break;
default:
return;
}
if (button->isSelected())
m_target |= flag;
else
m_target &= ~flag;
TargetChange();
}
void FilterTargetButtons::onImagesChange(ButtonBase* button)
{
// Rotate target
if (m_target & TARGET_ALL_FRAMES) {
m_target &= ~TARGET_ALL_FRAMES;
if (m_target & TARGET_ALL_LAYERS)
m_target &= ~TARGET_ALL_LAYERS;
else
m_target |= TARGET_ALL_LAYERS;
}
else {
m_target |= TARGET_ALL_FRAMES;
}
set_gfxicon_to_button(button,
getTargetNormalIcon(),
getTargetSelectedIcon(), -1,
JI_CENTER | JI_MIDDLE);
TargetChange();
}
int FilterTargetButtons::getTargetNormalIcon() const
{
if (m_target & TARGET_ALL_FRAMES) {
return (m_target & TARGET_ALL_LAYERS) ?
PART_TARGET_FRAMES_LAYERS:
PART_TARGET_FRAMES;
}
else {
return (m_target & TARGET_ALL_LAYERS) ?
PART_TARGET_LAYERS:
PART_TARGET_ONE;
}
}
int FilterTargetButtons::getTargetSelectedIcon() const
{
if (m_target & TARGET_ALL_FRAMES) {
return (m_target & TARGET_ALL_LAYERS) ?
PART_TARGET_FRAMES_LAYERS_SELECTED:
PART_TARGET_FRAMES_SELECTED;
}
else {
return (m_target & TARGET_ALL_LAYERS) ?
PART_TARGET_LAYERS_SELECTED:
PART_TARGET_ONE_SELECTED;
}
}

View File

@ -16,42 +16,37 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef EFFECT_COLCURVE_H_INCLUDED
#define EFFECT_COLCURVE_H_INCLUDED
#ifndef COMMANDS_FILTERS_FILTER_TARGET_BUTTONS_H_INCLUDED
#define COMMANDS_FILTERS_FILTER_TARGET_BUTTONS_H_INCLUDED
#include "gui/base.h"
#include "base/signal.h"
#include "filters/target.h"
#include "gui/box.h"
struct Effect;
class ButtonBase;
enum {
CURVE_LINEAR,
CURVE_SPLINE,
class FilterTargetButtons : public Box
{
public:
// Creates a new button to handle "targets" to apply some filter in
// the a sprite.
FilterTargetButtons(int imgtype, bool withChannels);
Target getTarget() const { return m_target; }
void setTarget(Target target);
Signal0<void> TargetChange;
protected:
void onChannelChange(ButtonBase* button);
void onImagesChange(ButtonBase* button);
private:
void selectTargetButton(const char* name, Target specificTarget);
int getTargetNormalIcon() const;
int getTargetSelectedIcon() const;
Target m_target;
};
typedef struct CurvePoint
{
int x, y;
} CurvePoint;
typedef struct Curve
{
int type;
JList points;
} Curve;
CurvePoint *curve_point_new(int x, int y);
void curve_point_free(CurvePoint *point);
Curve *curve_new(int type);
void curve_free(Curve *curve);
void curve_add_point(Curve *curve, CurvePoint *point);
void curve_remove_point(Curve *curve, CurvePoint *point);
void curve_get_values(Curve *curve, int x1, int x2, int *values);
void set_color_curve(Curve *curve);
void apply_color_curve4(struct Effect *effect);
void apply_color_curve2(struct Effect *effect);
void apply_color_curve1(struct Effect *effect);
#endif

View File

@ -0,0 +1,166 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "commands/filters/filter_window.h"
#include "base/bind.h"
#include "commands/filters/filter_manager_impl.h"
#include "commands/filters/filter_worker.h"
#include "core/cfg.h"
#include "modules/gui.h"
FilterWindow::FilterWindow(const char* title, const char* cfgSection,
FilterManagerImpl* filterMgr,
WithChannels withChannels,
WithTiled withTiled,
TiledMode tiledMode)
: Frame(false, title)
, m_cfgSection(cfgSection)
, m_filterMgr(filterMgr)
, m_hbox(JI_HORIZONTAL)
, m_container(JI_VERTICAL)
, m_vbox(JI_VERTICAL)
, m_okButton("&OK")
, m_cancelButton("&Cancel")
, m_preview(filterMgr)
, m_targetButton(filterMgr->getImgType(), (withChannels == WithChannelsSelector))
, m_showPreview("&Preview")
, m_tiledCheck(withTiled == WithTiledCheckBox ? new CheckBox("&Tiled") : NULL)
{
m_targetButton.setTarget(filterMgr->getTarget());
m_targetButton.TargetChange.connect(&FilterWindow::onTargetButtonChange, this);
m_okButton.Click.connect(&FilterWindow::onOk, this);
m_cancelButton.Click.connect(&FilterWindow::onCancel, this);
m_showPreview.Click.connect(&FilterWindow::onShowPreview, this);
jwidget_expansive(&m_container, true);
jwidget_add_child(&m_hbox, &m_container);
jwidget_add_child(&m_hbox, &m_vbox);
jwidget_add_child(&m_vbox, &m_okButton);
jwidget_add_child(&m_vbox, &m_cancelButton);
jwidget_add_child(&m_vbox, &m_targetButton);
jwidget_add_child(&m_vbox, &m_showPreview);
jwidget_add_child(this, &m_preview);
jwidget_add_child(this, &m_hbox);
if (m_tiledCheck) {
m_tiledCheck->setSelected(tiledMode != TILED_NONE);
m_tiledCheck->Click.connect(Bind<void>(&FilterWindow::onTiledChange, this));
jwidget_add_child(&m_vbox, m_tiledCheck);
}
// Load "Preview" check status.
m_showPreview.setSelected(get_config_bool(m_cfgSection, "Preview", true));
// OK is magnetic (the default button)
jwidget_magnetic(&m_okButton, true);
}
FilterWindow::~FilterWindow()
{
// Save window configuration
save_window_pos(this, m_cfgSection);
// Save "Preview" check status.
set_config_bool(m_cfgSection, "Preview", m_showPreview.isSelected());
}
bool FilterWindow::doModal()
{
bool result = false;
// Default position
remap_window();
center_window();
// Load window configuration
load_window_pos(this, m_cfgSection);
// Start first preview
restartPreview();
// Open in foreground
open_window_fg();
// Did the user press OK?
if (get_killer() == &m_okButton) {
m_preview.stop();
// Apply the filter in background
start_filter_worker(m_filterMgr);
result = true;
}
// Always update editors
update_screen_for_sprite(m_filterMgr->getSprite());
return result;
}
void FilterWindow::restartPreview()
{
if (m_showPreview.isSelected())
m_preview.restartPreview();
}
void FilterWindow::setNewTarget(Target target)
{
m_filterMgr->setTarget(target);
m_targetButton.setTarget(target);
}
void FilterWindow::onOk(Event& ev)
{
m_okButton.closeWindow();
}
void FilterWindow::onCancel(Event& ev)
{
m_cancelButton.closeWindow();
}
void FilterWindow::onShowPreview(Event& ev)
{
restartPreview();
}
// Called when the user changes the target-buttons.
void FilterWindow::onTargetButtonChange()
{
// Change the targets in the filter manager and restart the filter preview.
m_filterMgr->setTarget(m_targetButton.getTarget());
restartPreview();
}
void FilterWindow::onTiledChange()
{
ASSERT(m_tiledCheck != NULL);
// Call derived class implementation of setupTiledMode() so the
// filter is modified.
setupTiledMode(m_tiledCheck->isSelected() ? TILED_BOTH: TILED_NONE);
// Restart the preview.
restartPreview();
}

View File

@ -0,0 +1,87 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef COMMANDS_FILTERS_FILTER_WINDOW_H_INCLUDED
#define COMMANDS_FILTERS_FILTER_WINDOW_H_INCLUDED
#include "gui/box.h"
#include "gui/button.h"
#include "gui/frame.h"
#include "commands/filters/filter_preview.h"
#include "commands/filters/filter_target_buttons.h"
#include "filters/tiled_mode.h"
class FilterManagerImpl;
// A generic window to show parameters for a Filter with integrated
// preview in the current editor.
class FilterWindow : public Frame
{
public:
enum WithChannels { WithChannelsSelector, WithoutChannelsSelector };
enum WithTiled { WithTiledCheckBox, WithoutTiledCheckBox };
FilterWindow(const char* title, const char* cfgSection,
FilterManagerImpl* filterMgr,
WithChannels withChannels,
WithTiled withTiled,
TiledMode tiledMode = TILED_NONE);
~FilterWindow();
// Shows the window as modal (blocking interface), and returns true
// if the user pressed "OK" button (i.e. wants to apply the filter
// with the current settings).
bool doModal();
// Starts (or restart) the preview procedure. You should call this
// method each time the user modifies parameters of the Filter.
void restartPreview();
protected:
// Changes the target buttons. Used by convolution matrix filter
// which specified different targets for each matrix.
void setNewTarget(Target target);
// Returns the container where derived classes should put controls.
Widget* getContainer() { return &m_container; }
void onOk(Event& ev);
void onCancel(Event& ev);
void onShowPreview(Event& ev);
void onTargetButtonChange();
void onTiledChange();
// Derived classes WithTiledCheckBox should set its filter's tiled
// mode overriding this method.
virtual void setupTiledMode(TiledMode tiledMode) { }
private:
const char* m_cfgSection;
FilterManagerImpl* m_filterMgr;
Box m_hbox;
Box m_vbox;
Box m_container;
Button m_okButton;
Button m_cancelButton;
FilterPreview m_preview;
FilterTargetButtons m_targetButton;
CheckBox m_showPreview;
CheckBox* m_tiledCheck;
};
#endif

View File

@ -0,0 +1,186 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include "app.h"
#include "base/mutex.h"
#include "base/scoped_lock.h"
#include "base/thread.h"
#include "commands/filters/filter_manager_impl.h"
#include "core/cfg.h"
#include "gui/gui.h"
#include "modules/editors.h"
#include "modules/gui.h"
#include "raster/sprite.h"
#include "widgets/editor.h"
#include "widgets/statebar.h"
// Applies filters in two threads: a background worker thread to
// modify the sprite, and the main thread to monitoring the progress
// (and given to the user the possibility to cancel the process).
class FilterWorker : public FilterManagerImpl::IProgressDelegate
{
public:
FilterWorker(FilterManagerImpl* filterMgr);
~FilterWorker();
void run();
// IProgressDelegate implementation
void reportProgress(float progress);
bool isCancelled();
private:
void applyFilterInBackground();
void monitor();
static void thread_proxy(void* data) {
FilterWorker* filterWorker = (FilterWorker*)data;
filterWorker->applyFilterInBackground();
}
static void monitor_proxy(void* data) {
FilterWorker* filterWorker = (FilterWorker*)data;
filterWorker->monitor();
}
FilterManagerImpl* m_filterMgr; // Effect to be applied.
Mutex m_mutex; // Mutex to access to 'pos', 'done' and 'cancelled' fields in different threads.
float m_pos; // Current progress position
bool m_done : 1; // Was the effect completelly applied?
bool m_cancelled : 1; // Was the effect cancelled by the user?
Monitor* m_monitor; // Monitor to update the progress-bar
Progress* m_progressBar; // The progress-bar.
AlertPtr m_alertWindow; // Alert for the user to cancel the filter-progress if he wants.
};
FilterWorker::FilterWorker(FilterManagerImpl* filterMgr)
: m_filterMgr(filterMgr)
{
m_filterMgr->setProgressDelegate(this);
m_pos = 0.0;
m_done = false;
m_cancelled = false;
m_progressBar = app_get_statusbar()->addProgress();
m_alertWindow = Alert::create(PACKAGE
"<<Applying effect...||&Cancel");
m_monitor = add_gui_monitor(FilterWorker::monitor_proxy, NULL, this);
}
FilterWorker::~FilterWorker()
{
if (m_alertWindow != NULL)
m_alertWindow->closeWindow(NULL);
delete m_progressBar;
}
void FilterWorker::run()
{
// Launch the thread to apply the effect in background
base::thread thread(&FilterWorker::thread_proxy, this);
// Open the alert window in foreground (this is modal, locks the main thread)
m_alertWindow->open_window_fg();
// Remove the monitor
remove_gui_monitor(m_monitor);
{
ScopedLock lock(m_mutex);
if (!m_done)
m_cancelled = true;
}
// Wait the `effect_bg' thread
thread.join();
}
// Called by FilterManagerImpl to informate the progress of the filter.
//
// [effect thread]
//
void FilterWorker::reportProgress(float progress)
{
ScopedLock lock(m_mutex);
m_pos = progress;
}
// Called by effect_apply to know if the user cancelled the operation.
//
// [effect thread]
//
bool FilterWorker::isCancelled()
{
bool cancelled;
ScopedLock lock(m_mutex);
cancelled = m_cancelled;
return cancelled;
}
// Applies the effect to the sprite in a background thread.
//
// [effect thread]
//
void FilterWorker::applyFilterInBackground()
{
// Apply the filter
m_filterMgr->applyToTarget();
// Mark the work as 'done'.
ScopedLock lock(m_mutex);
m_done = true;
}
// Called by the GUI monitor (a timer in the gui module that is called
// every 100 milliseconds).
//
// [main thread]
//
void FilterWorker::monitor()
{
ScopedLock lock(m_mutex);
if (m_progressBar)
m_progressBar->setPos(m_pos);
if (m_done)
m_alertWindow->closeWindow(NULL);
}
// Applies the filter in a background thread meanwhile a progress bar
// is shown to the user.
//
// [main thread]
//
void start_filter_worker(FilterManagerImpl* filterMgr)
{
FilterWorker filterWorker(filterMgr);
filterWorker.run();
}

View File

@ -16,11 +16,11 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef COMMANDS_FX_EFFECTBG_H_INCLUDED
#define COMMANDS_FX_EFFECTBG_H_INCLUDED
#ifndef COMMANDS_FILTERS_FILTER_BG_H_INCLUDED
#define COMMANDS_FILTERS_FILTER_BG_H_INCLUDED
struct Effect;
class FilterManagerImpl;
void effect_apply_to_target_with_progressbar(struct Effect* effect);
void start_filter_worker(FilterManagerImpl* filterMgr);
#endif

View File

@ -1,193 +0,0 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "base/bind.h"
#include "gui/gui.h"
#include "app.h"
#include "app/color.h"
#include "commands/command.h"
#include "commands/fx/effectbg.h"
#include "console.h"
#include "core/cfg.h"
#include "effect/colcurve.h"
#include "effect/effect.h"
#include "modules/gui.h"
#include "raster/mask.h"
#include "raster/sprite.h"
#include "util/misc.h"
#include "widgets/color_button.h"
#include "widgets/curvedit.h"
#include "widgets/preview.h"
#include "widgets/target.h"
static Curve* the_curve = NULL;
static JWidget preview;
static CheckBox* check_preview;
static bool window_msg_proc(JWidget widget, JMessage msg);
static void preview_change_hook(Widget* widget);
static void make_preview();
// Slot for App::Exit signal
static void on_exit_delete_curve()
{
curve_free(the_curve);
}
//////////////////////////////////////////////////////////////////////
// ColorCurveCommand
class ColorCurveCommand : public Command
{
public:
ColorCurveCommand();
Command* clone() const { return new ColorCurveCommand(*this); }
protected:
bool onEnabled(Context* context);
void onExecute(Context* context);
};
ColorCurveCommand::ColorCurveCommand()
: Command("ColorCurve",
"Color Curve",
CmdRecordableFlag)
{
}
bool ColorCurveCommand::onEnabled(Context* context)
{
const CurrentSpriteReader sprite(context);
return
sprite != NULL;
}
void ColorCurveCommand::onExecute(Context* context)
{
const CurrentSpriteReader sprite(context);
Widget* button_ok;
Widget* curve_editor;
Widget* box_target;
Widget* target_button;
View* view_curve;
if (!the_curve) {
/* default curve */
the_curve = curve_new(CURVE_LINEAR);
curve_add_point(the_curve, curve_point_new(0, 0));
curve_add_point(the_curve, curve_point_new(255, 255));
App::instance()->Exit.connect(&on_exit_delete_curve);
}
FramePtr window(load_widget("color_curve.xml", "color_curve"));
get_widgets(window,
"preview", &check_preview,
"button_ok", &button_ok,
"curve", &view_curve,
"target", &box_target, NULL);
Effect effect(sprite, "color_curve");
effect_set_target(&effect, TARGET_RED_CHANNEL | TARGET_GREEN_CHANNEL |
TARGET_BLUE_CHANNEL | TARGET_ALPHA_CHANNEL);
preview = preview_new(&effect);
set_color_curve(the_curve);
curve_editor = curve_editor_new(the_curve, 0, 0, 255, 255);
target_button = target_button_new(sprite->getImgType(), true);
target_button_set_target(target_button, effect.target);
if (get_config_bool("ColorCurve", "Preview", true))
check_preview->setSelected(true);
view_curve->attachToView(curve_editor);
jwidget_set_min_size(view_curve, 128, 64);
jwidget_add_child(box_target, target_button);
jwidget_add_child(window, preview);
check_preview->Click.connect(Bind<void>(&preview_change_hook, check_preview));
jwidget_add_hook(window, -1, window_msg_proc, NULL);
/* default position */
window->remap_window();
window->center_window();
/* first preview */
make_preview();
/* load window configuration */
load_window_pos(window, "ColorCurve");
/* open the window */
window->open_window_fg();
if (window->get_killer() == button_ok)
effect_apply_to_target_with_progressbar(&effect);
/* update editors */
update_screen_for_sprite(sprite);
/* save window configuration */
save_window_pos(window, "ColorCurve");
}
static bool window_msg_proc(JWidget widget, JMessage msg)
{
if (msg->type == JM_SIGNAL) {
switch (msg->signal.num) {
case SIGNAL_CURVE_EDITOR_CHANGE:
set_color_curve(curve_editor_get_curve(msg->signal.from));
make_preview();
break;
case SIGNAL_TARGET_BUTTON_CHANGE:
effect_set_target(preview_get_effect(preview),
target_button_get_target(msg->signal.from));
make_preview();
break;
}
}
return false;
}
static void preview_change_hook(Widget* widget)
{
set_config_bool("ColorCurve", "Preview", widget->isSelected());
make_preview();
}
static void make_preview()
{
if (check_preview->isSelected())
preview_restart(preview);
}
//////////////////////////////////////////////////////////////////////
// CommandFactory
Command* CommandFactory::createColorCurveCommand()
{
return new ColorCurveCommand;
}

View File

@ -1,346 +0,0 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <string.h>
#include "base/bind.h"
#include "gui/button.h"
#include "gui/frame.h"
#include "gui/hook.h"
#include "gui/list.h"
#include "gui/listbox.h"
#include "gui/label.h"
#include "gui/slider.h"
#include "gui/view.h"
#include "gui/widget.h"
#include "app/color.h"
#include "commands/command.h"
#include "commands/fx/effectbg.h"
#include "console.h"
#include "core/cfg.h"
#include "effect/colcurve.h"
#include "effect/convmatr.h"
#include "effect/effect.h"
#include "modules/gui.h"
#include "raster/mask.h"
#include "raster/sprite.h"
#include "ui_context.h"
#include "util/misc.h"
#include "widgets/color_button.h"
#include "widgets/curvedit.h"
#include "widgets/preview.h"
#include "widgets/target.h"
static CheckBox* check_preview, *check_tiled;
static JWidget preview;
static JWidget target_button;
static void listbox_fill_convmatg(JWidget listbox);
static void listbox_select_current_convmatr(JWidget listbox);
static bool reload_select_hook(Widget* listbox);
static bool generate_select_hook();
static bool list_change_hook(JWidget widget, void *data);
static bool target_change_hook(JWidget widget, void *data);
static void preview_change_hook(Widget* widget);
static void tiled_change_hook(Widget* widget);
static void make_preview();
//////////////////////////////////////////////////////////////////////
// convolution_matrix
class ConvolutionMatrixCommand : public Command
{
public:
ConvolutionMatrixCommand();
Command* clone() const { return new ConvolutionMatrixCommand(*this); }
protected:
bool onEnabled(Context* context);
void onExecute(Context* context);
};
ConvolutionMatrixCommand::ConvolutionMatrixCommand()
: Command("ConvolutionMatrix",
"Convolution Matrix",
CmdRecordableFlag)
{
}
bool ConvolutionMatrixCommand::onEnabled(Context* context)
{
const CurrentSpriteReader sprite(context);
return
sprite != NULL;
}
void ConvolutionMatrixCommand::onExecute(Context* context)
{
const CurrentSpriteReader sprite(context);
Widget* button_ok;
View* view_convmatr;
Widget *list_convmatr;
Widget* box_target;
Button* reload, *generate;
FramePtr window(load_widget("convolution_matrix.xml", "convolution_matrix"));
get_widgets(window,
"preview", &check_preview,
"tiled", &check_tiled,
"button_ok", &button_ok,
"view", &view_convmatr,
"target", &box_target,
"reload", &reload,
"generate", &generate, NULL);
Effect effect(sprite, "convolution_matrix");
preview = preview_new(&effect);
list_convmatr = jlistbox_new();
listbox_fill_convmatg(list_convmatr);
target_button = target_button_new(sprite->getImgType(), true);
target_button_set_target(target_button, effect.target);
if (get_config_bool("ConvolutionMatrix", "Preview", true))
check_preview->setSelected(true);
if (context->getSettings()->getTiledMode() != TILED_NONE)
check_tiled->setSelected(true);
view_convmatr->attachToView(list_convmatr);
jwidget_set_min_size(view_convmatr, 128, 64);
jwidget_add_child(box_target, target_button);
jwidget_add_child(window, preview);
HOOK(list_convmatr, JI_SIGNAL_LISTBOX_CHANGE, list_change_hook, 0);
HOOK(target_button, SIGNAL_TARGET_BUTTON_CHANGE, target_change_hook, 0);
check_preview->Click.connect(Bind<void>(&preview_change_hook, check_preview));
check_tiled->Click.connect(Bind<void>(&tiled_change_hook, check_tiled));
reload->Click.connect(Bind<bool>(&reload_select_hook, list_convmatr));
generate->Click.connect(Bind<void>(&generate_select_hook));
// TODO enable this someday
generate->setEnabled(false);
/* default position */
window->remap_window();
window->center_window();
/* load window configuration */
load_window_pos(window, "ConvolutionMatrix");
/* select default convmatr */
listbox_select_current_convmatr(list_convmatr);
/* open the window */
window->open_window_fg();
if (window->get_killer() == button_ok)
effect_apply_to_target_with_progressbar(&effect);
/* update editors */
update_screen_for_sprite(sprite);
/* save window configuration */
save_window_pos(window, "ConvolutionMatrix");
}
static void listbox_fill_convmatg(JWidget listbox)
{
ConvMatr *convmatr;
JWidget listitem;
JLink link;
JI_LIST_FOR_EACH(get_convmatr_stock(), link) {
convmatr = reinterpret_cast<ConvMatr *>(link->data);
listitem = jlistitem_new(convmatr->name);
listitem->user_data[0] = convmatr;
jwidget_add_child(listbox, listitem);
}
}
static void listbox_select_current_convmatr(JWidget listbox)
{
const char *selected = get_config_string("ConvolutionMatrix",
"Selected", "");
JWidget select_this = reinterpret_cast<JWidget>(jlist_first_data(listbox->children));
JWidget child = NULL;
JLink link;
if (selected && *selected) {
JI_LIST_FOR_EACH(listbox->children, link) {
child = reinterpret_cast<JWidget>(link->data);
if (strcmp(child->getText(), selected) == 0) {
select_this = child;
break;
}
}
}
if (select_this) {
select_this->setSelected(true);
list_change_hook(listbox, 0);
}
}
static bool reload_select_hook(Widget* listbox)
{
JWidget listitem;
JLink link, next;
/* clean the list */
JI_LIST_FOR_EACH_SAFE(listbox->children, link, next) {
listitem = reinterpret_cast<JWidget>(link->data);
jwidget_remove_child(listbox, listitem);
jwidget_free(listitem);
}
/* re-load the convolution matrix stock */
reload_matrices_stock();
/* re-fill the list */
listbox_fill_convmatg(listbox);
listbox_select_current_convmatr(listbox);
View::getView(listbox)->updateView();
return true; /* do not close */
}
static bool generate_select_hook()
{
#if 0
JWidget view_x;
JWidget view_y;
JWidget curvedit_x;
JWidget curvedit_y;
Curve *curve_x;
Curve *curve_y;
JWidget div, div_auto;
JWidget bias, bias_auto;
JWidgetPtr window(load_widget("convolution_matrix.xml", "generate_convolution_matrix"));
get_widgets(window,
"view_x", &view_x,
"view_y", &view_y,
"div", &div,
"bias", &bias,
"div_auto", &div_auto,
"bias_auto", &bias_auto, NULL);
/* curve_x = curve_new(CURVE_SPLINE); */
/* curve_y = curve_new(CURVE_SPLINE); */
curve_x = curve_new(CURVE_LINEAR);
curve_y = curve_new(CURVE_LINEAR);
curve_add_point(curve_x, curve_point_new(-100, 0));
curve_add_point(curve_x, curve_point_new(0, +100));
curve_add_point(curve_x, curve_point_new(+100, 0));
curve_add_point(curve_y, curve_point_new(-100, 0));
curve_add_point(curve_y, curve_point_new(0, +100));
curve_add_point(curve_y, curve_point_new(+100, 0));
curvedit_x = curve_editor_new(curve_x, -200, -200, 200, 200);
curvedit_y = curve_editor_new(curve_y, -200, -200, 200, 200);
view_x->attachToView(curvedit_x);
view_y->attachToView(curvedit_y);
jwidget_set_min_size(view_x, 64, 64);
jwidget_set_min_size(view_y, 64, 64);
/* TODO fix this */
/* jwidget_get_vtable(div)->request_size = NULL; */
/* jwidget_get_vtable(bias)->request_size = NULL; */
jwidget_set_min_size(div, 1, 1);
jwidget_set_min_size(bias, 1, 1);
window->open_window_fg();
/* TODO do something */
curve_free(curve_x);
curve_free(curve_y);
#endif
return true;
}
static bool list_change_hook(JWidget widget, void *data)
{
JWidget selected = jlistbox_get_selected_child(widget);
ConvMatr *convmatr = reinterpret_cast<ConvMatr*>(selected->user_data[0]);
int new_target = convmatr->default_target;
set_config_string("ConvolutionMatrix", "Selected", convmatr->name);
// TODO avoid UIContext::instance, hold the context in some place
TiledMode tiled = UIContext::instance()->getSettings()->getTiledMode();
set_convmatr(convmatr, tiled);
target_button_set_target(target_button, new_target);
effect_set_target(preview_get_effect(preview), new_target);
make_preview();
return false;
}
static bool target_change_hook(JWidget widget, void *data)
{
effect_set_target(preview_get_effect(preview),
target_button_get_target(widget));
make_preview();
return false;
}
static void preview_change_hook(Widget* widget)
{
set_config_bool("ConvolutionMatrix", "Preview", widget->isSelected());
make_preview();
}
static void tiled_change_hook(Widget* widget)
{
TiledMode tiled = widget->isSelected() ? TILED_BOTH:
TILED_NONE;
// TODO avoid UIContext::instance, hold the context in some place
UIContext::instance()->getSettings()->setTiledMode(tiled);
make_preview();
}
static void make_preview()
{
if (check_preview->isSelected())
preview_restart(preview);
}
//////////////////////////////////////////////////////////////////////
// CommandFactory
Command* CommandFactory::createConvolutionMatrixCommand()
{
return new ConvolutionMatrixCommand;
}

View File

@ -1,211 +0,0 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <stdio.h>
#include "base/bind.h"
#include "gui/button.h"
#include "gui/entry.h"
#include "gui/frame.h"
#include "gui/hook.h"
#include "gui/widget.h"
#include "commands/command.h"
#include "commands/fx/effectbg.h"
#include "console.h"
#include "core/cfg.h"
#include "effect/effect.h"
#include "effect/median.h"
#include "modules/gui.h"
#include "raster/mask.h"
#include "raster/sprite.h"
#include "settings/settings.h"
#include "ui_context.h"
#include "util/misc.h"
#include "widgets/preview.h"
#include "widgets/target.h"
static JWidget entry_width, entry_height;
static JWidget preview;
static CheckBox* check_preview;
static CheckBox* check_tiled;
static bool width_change_hook(JWidget widget, void *data);
static bool height_change_hook(JWidget widget, void *data);
static bool target_change_hook(JWidget widget, void *data);
static void preview_change_hook(JWidget widget);
static bool tiled_change_hook(JWidget widget, void *data);
static void make_preview();
//////////////////////////////////////////////////////////////////////
// despeckle
class DespeckleCommand : public Command
{
public:
DespeckleCommand();
Command* clone() const { return new DespeckleCommand(*this); }
protected:
bool onEnabled(Context* context);
void onExecute(Context* context);
};
DespeckleCommand::DespeckleCommand()
: Command("Despeckle",
"Despeckle",
CmdRecordableFlag)
{
}
bool DespeckleCommand::onEnabled(Context* context)
{
const CurrentSpriteReader sprite(context);
return
sprite != NULL;
}
void DespeckleCommand::onExecute(Context* context)
{
const CurrentSpriteReader sprite(context);
JWidget box_target, target_button, button_ok;
FramePtr window(load_widget("median_blur.xml", "median"));
get_widgets(window,
"width", &entry_width,
"height", &entry_height,
"preview", &check_preview,
"tiled", &check_tiled,
"target", &box_target,
"button_ok", &button_ok, NULL);
Effect effect(sprite, "median");
effect_set_target(&effect, TARGET_RED_CHANNEL |
TARGET_GREEN_CHANNEL |
TARGET_BLUE_CHANNEL);
preview = preview_new(&effect);
target_button = target_button_new(sprite->getImgType(), true);
target_button_set_target(target_button, effect.target);
entry_width->setTextf("%d", get_config_int("Median", "Width", 3));
entry_height->setTextf("%d", get_config_int("Median", "Height", 3));
if (get_config_bool("Median", "Preview", true))
check_preview->setSelected(true);
if (context->getSettings()->getTiledMode() != TILED_NONE)
check_tiled->setSelected(true);
jwidget_add_child(box_target, target_button);
jwidget_add_child(window, preview);
HOOK(entry_width, JI_SIGNAL_ENTRY_CHANGE, width_change_hook, 0);
HOOK(entry_height, JI_SIGNAL_ENTRY_CHANGE, height_change_hook, 0);
HOOK(target_button, SIGNAL_TARGET_BUTTON_CHANGE, target_change_hook, 0);
HOOK(check_tiled, JI_SIGNAL_CHECK_CHANGE, tiled_change_hook, 0);
check_preview->Click.connect(Bind<void>(&preview_change_hook, check_preview));
/* default position */
window->remap_window();
window->center_window();
/* first preview */
make_preview();
/* load window configuration */
load_window_pos(window, "Median");
/* open the window */
window->open_window_fg();
if (window->get_killer() == button_ok)
effect_apply_to_target_with_progressbar(&effect);
/* update editors */
update_screen_for_sprite(sprite);
/* save window configuration */
save_window_pos(window, "Median");
}
static bool width_change_hook(JWidget widget, void *data)
{
set_config_int("Median", "Width", widget->getTextInt());
make_preview();
return true;
}
static bool height_change_hook(JWidget widget, void *data)
{
set_config_int("Median", "Height", widget->getTextInt());
make_preview();
return true;
}
static bool target_change_hook(JWidget widget, void *data)
{
effect_set_target(preview_get_effect(preview),
target_button_get_target(widget));
make_preview();
return false;
}
static void preview_change_hook(JWidget widget)
{
set_config_bool("Median", "Preview", widget->isSelected());
make_preview();
}
static bool tiled_change_hook(JWidget widget, void *data)
{
TiledMode tiled = widget->isSelected() ? TILED_BOTH:
TILED_NONE;
// TODO save context in some place, don't use UIContext directly
UIContext::instance()->getSettings()->setTiledMode(tiled);
make_preview();
return false;
}
static void make_preview()
{
int w, h;
w = get_config_int("Median", "Width", 3);
h = get_config_int("Median", "Height", 3);
// TODO do not use UIContext::instance
set_median_size(UIContext::instance()->getSettings()->getTiledMode(),
MID(1, w, 32), MID(1, h, 32));
if (check_preview->isSelected())
preview_restart(preview);
}
//////////////////////////////////////////////////////////////////////
// CommandFactory
Command* CommandFactory::createDespeckleCommand()
{
return new DespeckleCommand;
}

View File

@ -1,157 +0,0 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "base/bind.h"
#include "gui/button.h"
#include "gui/frame.h"
#include "gui/hook.h"
#include "gui/label.h"
#include "gui/slider.h"
#include "gui/widget.h"
#include "app/color.h"
#include "commands/command.h"
#include "commands/fx/effectbg.h"
#include "console.h"
#include "core/cfg.h"
#include "effect/effect.h"
#include "modules/gui.h"
#include "raster/image.h"
#include "raster/mask.h"
#include "raster/sprite.h"
#include "util/misc.h"
#include "widgets/color_button.h"
#include "widgets/preview.h"
#include "widgets/target.h"
static CheckBox* check_preview;
static JWidget preview;
static bool target_change_hook(JWidget widget, void *data);
static void preview_change_hook(Widget* widget);
static void make_preview();
//////////////////////////////////////////////////////////////////////
// invert_color
class InvertColorCommand : public Command
{
public:
InvertColorCommand();
Command* clone() const { return new InvertColorCommand(*this); }
protected:
bool onEnabled(Context* context);
void onExecute(Context* context);
};
InvertColorCommand::InvertColorCommand()
: Command("InvertColor",
"Invert Color",
CmdRecordableFlag)
{
}
bool InvertColorCommand::onEnabled(Context* context)
{
const CurrentSpriteReader sprite(context);
return
sprite != NULL;
}
void InvertColorCommand::onExecute(Context* context)
{
const CurrentSpriteReader sprite(context);
JWidget box_target, target_button, button_ok;
FramePtr window(load_widget("invert_color.xml", "invert_color"));
get_widgets(window,
"target", &box_target,
"preview", &check_preview,
"button_ok", &button_ok, NULL);
Effect effect(sprite, "invert_color");
effect_set_target(&effect, TARGET_RED_CHANNEL |
TARGET_GREEN_CHANNEL |
TARGET_BLUE_CHANNEL);
preview = preview_new(&effect);
target_button = target_button_new(sprite->getImgType(), true);
target_button_set_target(target_button, effect.target);
if (get_config_bool("InvertColor", "Preview", true))
check_preview->setSelected(true);
jwidget_add_child(box_target, target_button);
jwidget_add_child(window, preview);
HOOK(target_button, SIGNAL_TARGET_BUTTON_CHANGE, target_change_hook, 0);
check_preview->Click.connect(Bind<void>(&preview_change_hook, check_preview));
/* default position */
window->remap_window();
window->center_window();
/* first preview */
make_preview();
/* load window configuration */
load_window_pos(window, "InvertColor");
/* open the window */
window->open_window_fg();
if (window->get_killer() == button_ok)
effect_apply_to_target_with_progressbar(&effect);
/* update editors */
update_screen_for_sprite(sprite);
/* save window configuration */
save_window_pos(window, "InvertColor");
}
static bool target_change_hook(JWidget widget, void *data)
{
effect_set_target(preview_get_effect(preview),
target_button_get_target(widget));
make_preview();
return false;
}
static void preview_change_hook(Widget* widget)
{
set_config_bool("InvertColor", "Preview", widget->isSelected());
make_preview();
}
static void make_preview()
{
if (check_preview->isSelected())
preview_restart(preview);
}
//////////////////////////////////////////////////////////////////////
// CommandFactory
Command* CommandFactory::createInvertColorCommand()
{
return new InvertColorCommand;
}

View File

@ -1,211 +0,0 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <stdio.h>
#include "base/bind.h"
#include "gui/gui.h"
#include "app.h"
#include "app/color.h"
#include "app/color_utils.h"
#include "commands/command.h"
#include "commands/fx/effectbg.h"
#include "console.h"
#include "core/cfg.h"
#include "effect/effect.h"
#include "effect/replcol.h"
#include "modules/gui.h"
#include "raster/image.h"
#include "raster/mask.h"
#include "raster/sprite.h"
#include "util/misc.h"
#include "widgets/color_bar.h"
#include "widgets/color_button.h"
#include "widgets/preview.h"
#include "widgets/target.h"
static ColorButton* button_color1;
static ColorButton* button_color2;
static Slider* slider_tolerance;
static JWidget preview;
static CheckBox* check_preview;
static void color_change_hook(Widget* widget, int num);
static bool target_change_hook(Widget* widget, void *data);
static void slider_change_hook(Slider* tolerance_slider);
static void preview_change_hook(Widget* widget);
static void make_preview();
//////////////////////////////////////////////////////////////////////
// replace_color
class ReplaceColorCommand : public Command
{
public:
ReplaceColorCommand();
Command* clone() const { return new ReplaceColorCommand(*this); }
protected:
bool onEnabled(Context* context);
void onExecute(Context* context);
};
ReplaceColorCommand::ReplaceColorCommand()
: Command("ReplaceColor",
"Replace Color",
CmdRecordableFlag)
{
}
bool ReplaceColorCommand::onEnabled(Context* context)
{
const CurrentSpriteReader sprite(context);
return
sprite != NULL;
}
void ReplaceColorCommand::onExecute(Context* context)
{
const CurrentSpriteReader sprite(context);
JWidget color_buttons_box;
JWidget box_target, target_button;
JWidget button_ok;
FramePtr window(load_widget("replace_color.xml", "replace_color"));
get_widgets(window,
"color_buttons_box", &color_buttons_box,
"preview", &check_preview,
"tolerance", &slider_tolerance,
"target", &box_target,
"button_ok", &button_ok, NULL);
Effect effect(sprite, "replace_color");
effect_set_target(&effect, TARGET_RED_CHANNEL |
TARGET_GREEN_CHANNEL |
TARGET_BLUE_CHANNEL |
TARGET_ALPHA_CHANNEL);
preview = preview_new(&effect);
button_color1 = new ColorButton
(get_config_color("ReplaceColor", "Color1",
app_get_colorbar()->getFgColor()),
sprite->getImgType());
button_color2 = new ColorButton
(get_config_color("ReplaceColor", "Color2",
app_get_colorbar()->getBgColor()),
sprite->getImgType());
target_button = target_button_new(sprite->getImgType(), false);
target_button_set_target(target_button, effect.target);
slider_tolerance->setValue(get_config_int("ReplaceColor", "Tolerance", 0));
if (get_config_bool("ReplaceColor", "Preview", true))
check_preview->setSelected(true);
jwidget_add_child(color_buttons_box, button_color1);
jwidget_add_child(color_buttons_box, button_color2);
jwidget_add_child(box_target, target_button);
jwidget_add_child(window, preview);
button_color1->Change.connect(Bind<void>(&color_change_hook, button_color1, 1));
button_color2->Change.connect(Bind<void>(&color_change_hook, button_color2, 2));
HOOK(target_button, SIGNAL_TARGET_BUTTON_CHANGE, target_change_hook, 0);
slider_tolerance->Change.connect(Bind<void>(&slider_change_hook, slider_tolerance));
check_preview->Click.connect(Bind<void>(&preview_change_hook, check_preview));
/* default position */
window->remap_window();
window->center_window();
/* first preview */
make_preview();
/* load window configuration */
load_window_pos(window, "ReplaceColor");
/* open the window */
window->open_window_fg();
if (window->get_killer() == button_ok)
effect_apply_to_target_with_progressbar(&effect);
/* update editors */
update_screen_for_sprite(sprite);
/* save window configuration */
save_window_pos(window, "ReplaceColor");
}
static void color_change_hook(Widget* widget, int num)
{
char buf[64];
sprintf(buf, "Color%u", num);
set_config_color("ReplaceColor", buf, static_cast<ColorButton*>(widget)->getColor());
make_preview();
}
static bool target_change_hook(JWidget widget, void *data)
{
effect_set_target(preview_get_effect(preview),
target_button_get_target(widget));
make_preview();
return false;
}
static void slider_change_hook(Slider* tolerance_slider)
{
set_config_int("ReplaceColor", "Tolerance", tolerance_slider->getValue());
make_preview();
}
static void preview_change_hook(Widget* widget)
{
set_config_bool("ReplaceColor", "Preview", widget->isSelected());
make_preview();
}
static void make_preview()
{
Sprite* sprite = preview_get_effect(preview)->sprite;
int tolerance;
Color from = get_config_color("ReplaceColor", "Color1", Color::fromMask());
Color to = get_config_color("ReplaceColor", "Color2", Color::fromMask());
tolerance = get_config_int("ReplaceColor", "Tolerance", 0);
set_replace_colors(color_utils::color_for_layer(from, sprite->getCurrentLayer()),
color_utils::color_for_layer(to, sprite->getCurrentLayer()),
MID(0, tolerance, 255));
if (check_preview->isSelected())
preview_restart(preview);
}
//////////////////////////////////////////////////////////////////////
// CommandFactory
Command* CommandFactory::createReplaceColorCommand()
{
return new ReplaceColorCommand;
}

View File

@ -1,184 +0,0 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include "app.h"
#include "base/mutex.h"
#include "base/scoped_lock.h"
#include "base/thread.h"
#include "core/cfg.h"
#include "effect/effect.h"
#include "gui/gui.h"
#include "modules/editors.h"
#include "modules/gui.h"
#include "raster/sprite.h"
#include "widgets/editor.h"
#include "widgets/statebar.h"
/**********************************************************************
Apply effect in two threads: bg-thread to modify the sprite, and the
main thread to monitoring the progress.
**********************************************************************/
struct ThreadData
{
Effect* effect; /* effect to be applied */
Mutex mutex; /* mutex to access to 'pos', 'done'
and 'cancelled' fields in different
threads */
float pos; /* current progress position */
bool done : 1; /* was the effect completelly applied? */
bool cancelled : 1; /* was the effect cancelled by the user? */
Monitor* monitor; /* monitor to update the progress-bar */
Progress* progress; /* the progress-bar */
AlertPtr alert_window; /* alert for the user to cancel the
effect-progress if he wants */
};
/**
* Called by @ref effect_apply to informate the progress of the
* effect.
*
* [effect thread]
*/
static void effect_progress_hook(void *_data, float progress)
{
ThreadData *data = (ThreadData *)_data;
ScopedLock lock(data->mutex);
data->pos = progress;
}
/**
* Called by @ref effect_apply to know if the user cancelled the
* operation.
*
* [effect thread]
*/
static bool effect_is_cancelled_hook(void *_data)
{
ThreadData *data = (ThreadData *)_data;
bool cancelled;
ScopedLock lock(data->mutex);
cancelled = data->cancelled;
return cancelled;
}
/**
* Applies the effect to the sprite in a background thread.
*
* [effect thread]
*/
static void effect_bg(ThreadData* data)
{
/* apply the effect */
effect_apply_to_target(data->effect);
/* mark the work as 'done' */
ScopedLock lock(data->mutex);
data->done = true;
}
/**
* Called by the gui-monitor (a timer in the gui module that is called
* every 100 milliseconds).
*
* [main thread]
*/
static void monitor_effect_bg(void *_data)
{
ThreadData *data = (ThreadData *)_data;
float pos;
bool done;
{
ScopedLock lock(data->mutex);
pos = data->pos;
done = data->done;
}
if (data->progress)
data->progress->setPos(pos);
if (data->done)
remove_gui_monitor(data->monitor);
}
/**
* Called to destroy the data of the monitor.
*
* [main thread]
*/
static void monitor_free(void *_data)
{
ThreadData *data = (ThreadData *)_data;
if (data->alert_window != NULL)
data->alert_window->closeWindow(NULL);
}
/**
* Applies the effect in a background thread meanwhile the progress
* bar is shown to the user.
*
* [main thread]
*/
void effect_apply_to_target_with_progressbar(Effect* effect)
{
ThreadData* data = new ThreadData;
effect->progress_data = data;
effect->progress = effect_progress_hook;
effect->is_cancelled = effect_is_cancelled_hook;
data->effect = effect;
data->pos = 0.0;
data->done = false;
data->cancelled = false;
data->progress = app_get_statusbar()->addProgress();
data->alert_window = Alert::create(PACKAGE
"<<Applying effect...||&Cancel");
data->monitor = add_gui_monitor(monitor_effect_bg,
monitor_free, data);
// Launch the thread to apply the effect in background
base::thread thread(&effect_bg, data);
// Open the alert window in foreground (this is modal, locks the main thread)
data->alert_window->open_window_fg();
{
ScopedLock lock(data->mutex);
if (!data->done) {
remove_gui_monitor(data->monitor);
data->cancelled = true;
}
}
// Wait the `effect_bg' thread
thread.join();
delete data->progress;
delete data;
}

View File

@ -19,7 +19,6 @@
#include "config.h"
#include "core/modules.h"
#include "effect/effect.h"
#include "modules/editors.h"
#include "modules/gui.h"
#include "modules/palettes.h"
@ -43,7 +42,6 @@ static Module module[] =
first ones. */
DEF_MODULE(palette, 0),
DEF_MODULE(effect, 0),
DEF_MODULE(gui, REQUIRE_INTERFACE),
DEF_MODULE(rootmenu, REQUIRE_INTERFACE),
DEF_MODULE(editors, REQUIRE_INTERFACE),

View File

@ -1,362 +0,0 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <vector>
#include "effect/colcurve.h"
#include "effect/effect.h"
#include "gui/list.h"
#include "modules/palettes.h"
#include "raster/image.h"
#include "raster/palette.h"
#include "raster/rgbmap.h"
static struct {
Curve *curve;
int cmap[256];
} data;
CurvePoint *curve_point_new(int x, int y)
{
CurvePoint* point = new CurvePoint;
point->x = x;
point->y = y;
return point;
}
void curve_point_free(CurvePoint *point)
{
delete point;
}
Curve *curve_new(int type)
{
Curve* curve = new Curve;
curve->type = type;
curve->points = jlist_new();
return curve;
}
void curve_free(Curve *curve)
{
JLink link;
JI_LIST_FOR_EACH(curve->points, link)
curve_point_free(reinterpret_cast<CurvePoint*>(link->data));
jlist_free(curve->points);
delete curve;
}
void curve_add_point(Curve* curve, CurvePoint* point)
{
JLink link;
JI_LIST_FOR_EACH(curve->points, link)
if (((CurvePoint*)link->data)->x >= point->x)
break;
jlist_insert_before(curve->points, link, point);
}
void curve_remove_point(Curve *curve, CurvePoint *point)
{
jlist_remove(curve->points, point);
}
/**********************************************************************/
/* dacap: directly from GTK+ 2.2.2 source code */
/**********************************************************************/
/* Solve the tridiagonal equation system that determines the second
derivatives for the interpolation points. (Based on Numerical
Recipies 2nd Edition.) */
static void
spline_solve(int n, float x[], float y[], float y2[])
{
float p, sig;
int i, k;
std::vector<float> u(n - 1);
y2[0] = u[0] = 0.0; /* set lower boundary condition to "natural" */
for (i = 1; i < n - 1; ++i)
{
sig = (x[i] - x[i - 1]) / (x[i + 1] - x[i - 1]);
p = sig * y2[i - 1] + 2.0;
y2[i] = (sig - 1.0) / p;
u[i] = ((y[i + 1] - y[i])
/ (x[i + 1] - x[i]) - (y[i] - y[i - 1]) / (x[i] - x[i - 1]));
u[i] = (6.0 * u[i] / (x[i + 1] - x[i - 1]) - sig * u[i - 1]) / p;
}
y2[n - 1] = 0.0;
for (k = n - 2; k >= 0; --k)
y2[k] = y2[k] * y2[k + 1] + u[k];
}
static float
spline_eval(int n, float x[], float y[], float y2[], float val)
{
int k_lo, k_hi, k;
float h, b, a;
/* do a binary search for the right interval: */
k_lo = 0; k_hi = n - 1;
while (k_hi - k_lo > 1)
{
k = (k_hi + k_lo) / 2;
if (x[k] > val)
k_hi = k;
else
k_lo = k;
}
h = x[k_hi] - x[k_lo];
/* TODO */
/* ASSERT(h > 0.0); */
a = (x[k_hi] - val) / h;
b = (val - x[k_lo]) / h;
return a*y[k_lo] + b*y[k_hi] +
((a*a*a - a)*y2[k_lo] + (b*b*b - b)*y2[k_hi]) * (h*h)/6.0;
}
void curve_get_values(Curve *curve, int x1, int x2, int *values)
{
int x, num_points = jlist_length(curve->points);
if (num_points == 0) {
for (x=x1; x<=x2; x++)
values[x-x1] = 0;
}
else if (num_points == 1) {
for (x=x1; x<=x2; x++)
values[x-x1] = ((CurvePoint *)jlist_first_data(curve->points))->y;
}
else {
switch (curve->type) {
case CURVE_LINEAR: {
JLink link, last = jlist_last(curve->points);
CurvePoint *p, *n;
JI_LIST_FOR_EACH(curve->points, link)
if (((CurvePoint *)link->data)->x >= x1)
break;
for (x=x1; x<=x2; x++) {
while ((link != curve->points->end) &&
(x > ((CurvePoint *)link->data)->x))
link = link->next;
if (link != curve->points->end) {
if (link->prev != curve->points->end) {
p = reinterpret_cast<CurvePoint*>(link->prev->data);
n = reinterpret_cast<CurvePoint*>(link->data);
values[x-x1] = p->y + (n->y-p->y) * (x-p->x) / (n->x-p->x);
}
else {
values[x-x1] = ((CurvePoint *)link->data)->y;
}
}
else {
values[x-x1] = ((CurvePoint *)last->data)->y;
}
}
break;
}
case CURVE_SPLINE: {
/* dacap: almost all code from GTK+ 2.2.2 source code */
float rx, ry, dx, min_x, *xv, *yv, *y2v, prev;
int dst, veclen = x2-x1+1;
JLink link;
min_x = 0;
std::vector<float> mem(3 * num_points);
xv = &mem[0];
yv = &mem[num_points];
y2v = &mem[2*num_points];
prev = min_x - 1.0;
dst = 0;
JI_LIST_FOR_EACH(curve->points, link) {
if (((CurvePoint *)link->data)->x > prev) {
prev = ((CurvePoint*)link->data)->x;
xv[dst] = ((CurvePoint*)link->data)->x;
yv[dst] = ((CurvePoint*)link->data)->y;
++dst;
}
}
spline_solve(dst, xv, yv, y2v);
rx = min_x;
dx = (x2 - x1) / (veclen-1);
for (x=0; x<veclen; ++x, rx+=dx) {
ry = spline_eval(dst, xv, yv, y2v, rx);
#if 0
/* if (ry < curve->min_y) ry = curve->min_y; */
/* if (ry > curve->max_y) ry = curve->max_y; */
#else
/* if (ry < 0) ry = 0; */
/* else if (ry > 255) ry = 255; */
#endif
values[x] = ry;
}
break;
}
}
}
}
void set_color_curve(Curve *curve)
{
int c;
data.curve = curve;
/* generate the color convertion map */
curve_get_values(data.curve, 0, 255, data.cmap);
for (c=0; c<256; c++)
data.cmap[c] = MID(0, data.cmap[c], 255);
}
void apply_color_curve4(Effect *effect)
{
ase_uint32 *src_address;
ase_uint32 *dst_address;
int x, c, r, g, b, a;
src_address = ((ase_uint32 **)effect->src->line)[effect->row+effect->y]+effect->x;
dst_address = ((ase_uint32 **)effect->dst->line)[effect->row+effect->y]+effect->x;
for (x=0; x<effect->w; x++) {
if (effect->mask_address) {
if (!((*effect->mask_address) & (1<<effect->d.rem))) {
src_address++;
dst_address++;
_image_bitmap_next_bit(effect->d, effect->mask_address);
continue;
}
else
_image_bitmap_next_bit(effect->d, effect->mask_address);
}
c = *(src_address++);
r = _rgba_getr(c);
g = _rgba_getg(c);
b = _rgba_getb(c);
a = _rgba_geta(c);
if (effect->target & TARGET_RED_CHANNEL) r = data.cmap[r];
if (effect->target & TARGET_GREEN_CHANNEL) g = data.cmap[g];
if (effect->target & TARGET_BLUE_CHANNEL) b = data.cmap[b];
if (effect->target & TARGET_ALPHA_CHANNEL) a = data.cmap[a];
*(dst_address++) = _rgba(r, g, b, a);
}
}
void apply_color_curve2(Effect *effect)
{
ase_uint16 *src_address;
ase_uint16 *dst_address;
int x, c, k, a;
src_address = ((ase_uint16 **)effect->src->line)[effect->row+effect->y]+effect->x;
dst_address = ((ase_uint16 **)effect->dst->line)[effect->row+effect->y]+effect->x;
for (x=0; x<effect->w; x++) {
if (effect->mask_address) {
if (!((*effect->mask_address) & (1<<effect->d.rem))) {
src_address++;
dst_address++;
_image_bitmap_next_bit(effect->d, effect->mask_address);
continue;
}
else
_image_bitmap_next_bit(effect->d, effect->mask_address);
}
c = *(src_address++);
k = _graya_getv(c);
a = _graya_geta(c);
if (effect->target & TARGET_GRAY_CHANNEL) k = data.cmap[k];
if (effect->target & TARGET_ALPHA_CHANNEL) a = data.cmap[a];
*(dst_address++) = _graya(k, a);
}
}
void apply_color_curve1(Effect *effect)
{
Palette *pal = get_current_palette();
RgbMap* rgbmap = effect->sprite->getRgbMap();
ase_uint8* src_address;
ase_uint8* dst_address;
int x, c, r, g, b;
src_address = ((ase_uint8**)effect->src->line)[effect->row+effect->y]+effect->x;
dst_address = ((ase_uint8**)effect->dst->line)[effect->row+effect->y]+effect->x;
for (x=0; x<effect->w; x++) {
if (effect->mask_address) {
if (!((*effect->mask_address) & (1<<effect->d.rem))) {
src_address++;
dst_address++;
_image_bitmap_next_bit(effect->d, effect->mask_address);
continue;
}
else
_image_bitmap_next_bit(effect->d, effect->mask_address);
}
c = *(src_address++);
if (effect->target & TARGET_INDEX_CHANNEL) {
c = data.cmap[c];
}
else {
r = _rgba_getr(pal->getEntry(c));
g = _rgba_getg(pal->getEntry(c));
b = _rgba_getb(pal->getEntry(c));
if (effect->target & TARGET_RED_CHANNEL) r = data.cmap[r];
if (effect->target & TARGET_GREEN_CHANNEL) g = data.cmap[g];
if (effect->target & TARGET_BLUE_CHANNEL) b = data.cmap[b];
c = rgbmap->mapColor(r, g, b);
}
*(dst_address++) = MID(0, c, pal->size()-1);
}
}

View File

@ -1,539 +0,0 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <allegro.h>
#include <stdio.h>
#include <string.h>
#include "base/memory.h"
#include "core/cfg.h"
#include "effect/convmatr.h"
#include "effect/effect.h"
#include "gui/list.h"
#include "modules/palettes.h"
#include "raster/image.h"
#include "raster/palette.h"
#include "raster/rgbmap.h"
#include "resource_finder.h"
#include "util/filetoks.h"
/* TODO warning: this number could be dangerous for big filters */
#define PRECISION (256)
static struct { /* TODO warning: not thread safe */
JList matrices;
ConvMatr* convmatr;
TiledMode tiled;
unsigned char **lines;
} data;
void init_convolution_matrix()
{
data.matrices = jlist_new();
data.convmatr = NULL;
data.tiled = TILED_NONE;
data.lines = NULL;
reload_matrices_stock();
}
void exit_convolution_matrix()
{
clean_matrices_stock();
jlist_free(data.matrices);
if (data.lines != NULL)
base_free(data.lines);
}
ConvMatr* convmatr_new(int w, int h)
{
ConvMatr* convmatr = new ConvMatr;
convmatr->name = NULL;
convmatr->w = w;
convmatr->h = h;
convmatr->cx = convmatr->w/2;
convmatr->cy = convmatr->h/2;
int size = convmatr->w * convmatr->h;
convmatr->data = (int*)base_malloc(sizeof(int) * size);
if (!convmatr->data) {
convmatr_free(convmatr);
return NULL;
}
for (int c=0; c<size; c++)
convmatr->data[c] = 0;
convmatr->div = PRECISION;
convmatr->bias = 0;
return convmatr;
}
ConvMatr *convmatr_new_string(const char *format)
{
/* TODO */
return NULL;
}
void convmatr_free(ConvMatr *convmatr)
{
if (convmatr->name)
base_free(convmatr->name);
if (convmatr->data)
base_free(convmatr->data);
delete convmatr;
}
void set_convmatr(ConvMatr *convmatr, TiledMode tiled)
{
data.convmatr = convmatr;
data.tiled = tiled;
if (data.lines != NULL)
base_free(data.lines);
data.lines = (unsigned char**)base_malloc(sizeof(unsigned char*) * convmatr->h);
}
ConvMatr* get_convmatr()
{
return data.convmatr;
}
ConvMatr* get_convmatr_by_name(const char *name)
{
ConvMatr* convmatr;
JLink link;
JI_LIST_FOR_EACH(data.matrices, link) {
convmatr = reinterpret_cast<ConvMatr*>(link->data);
if (strcmp(convmatr->name, name) == 0)
return convmatr;
}
return NULL;
}
void reload_matrices_stock()
{
#define READ_TOK() { \
if (!tok_read(f, buf, leavings, sizeof (leavings))) \
break; \
}
#define READ_INT(var) { \
READ_TOK(); \
var = ustrtol(buf, NULL, 10); \
}
const char *names[] = { "convmatr.usr",
"convmatr.gen",
"convmatr.def", NULL };
char *s, buf[256], leavings[4096];
int i, c, w, h, div, bias;
ConvMatr *convmatr;
FILE *f;
char *name;
clean_matrices_stock();
for (i=0; names[i]; i++) {
ResourceFinder rf;
rf.findInDataDir(names[i]);
while (const char* path = rf.next()) {
// Open matrices stock file
f = fopen(path, "r");
if (!f)
continue;
tok_reset_line_num();
name = NULL;
convmatr = NULL;
strcpy(leavings, "");
/* read the matrix name */
while (tok_read(f, buf, leavings, sizeof(leavings))) {
/* name of the matrix */
name = base_strdup(buf);
/* width and height */
READ_INT(w);
READ_INT(h);
if ((w <= 0) || (w > 32) ||
(h <= 0) || (h > 32))
break;
/* create the matrix data */
convmatr = convmatr_new(w, h);
if (!convmatr)
break;
/* centre */
READ_INT(convmatr->cx);
READ_INT(convmatr->cy);
if ((convmatr->cx < 0) || (convmatr->cx >= w) ||
(convmatr->cy < 0) || (convmatr->cy >= h))
break;
/* data */
READ_TOK(); /* jump the `{' char */
if (*buf != '{')
break;
c = 0;
div = 0;
for (c=0; c<w*h; c++) {
READ_TOK();
convmatr->data[c] = ustrtod(buf, NULL) * PRECISION;
div += convmatr->data[c];
}
READ_TOK(); /* jump the `}' char */
if (*buf != '}')
break;
if (div > 0)
bias = 0;
else if (div == 0) {
div = PRECISION;
bias = 128;
}
else {
div = ABS(div);
bias = 255;
}
/* div */
READ_TOK();
if (ustricmp (buf, "auto") != 0)
div = ustrtod(buf, NULL) * PRECISION;
convmatr->div = div;
/* bias */
READ_TOK();
if (ustricmp (buf, "auto") != 0)
bias = ustrtod(buf, NULL);
convmatr->bias = bias;
/* target */
READ_TOK();
convmatr->default_target = 0;
for (s=buf; *s; s++) {
switch (*s) {
case 'r': convmatr->default_target |= TARGET_RED_CHANNEL; break;
case 'g': convmatr->default_target |= TARGET_GREEN_CHANNEL; break;
case 'b': convmatr->default_target |= TARGET_BLUE_CHANNEL; break;
case 'a': convmatr->default_target |= TARGET_ALPHA_CHANNEL; break;
}
}
if ((convmatr->default_target & (TARGET_RED_CHANNEL |
TARGET_GREEN_CHANNEL |
TARGET_BLUE_CHANNEL)) != 0) {
convmatr->default_target |= TARGET_GRAY_CHANNEL;
}
/* name */
convmatr->name = name;
/* insert the new matrix in the list */
jlist_append(data.matrices, convmatr);
name = NULL;
convmatr = NULL;
}
/* destroy the last invalid matrix in case of error */
if (name)
base_free(name);
if (convmatr)
convmatr_free(convmatr);
// Close the file
fclose(f);
}
}
}
void clean_matrices_stock()
{
JLink link;
JI_LIST_FOR_EACH(data.matrices, link)
convmatr_free(reinterpret_cast<ConvMatr*>(link->data));
jlist_clear(data.matrices);
}
JList get_convmatr_stock()
{
return data.matrices;
}
#define GET_CONVMATR_DATA(Traits, do_job) \
div = matrix->div; \
mdata = matrix->data; \
\
GET_MATRIX_DATA \
(Traits::pixel_t, \
src, src_address, \
matrix->w, matrix->h, \
matrix->cx, matrix->cy, \
data.tiled, \
if (*mdata) { \
color = *src_address; \
do_job; \
} \
mdata++; \
); \
\
color = image_getpixel_fast<Traits>(src, x, y); \
if (div == 0) { \
*(dst_address++) = color; \
continue; \
}
void apply_convolution_matrix4(Effect *effect)
{
ConvMatr* matrix = data.convmatr;
const Image* src = effect->src;
Image* dst = effect->dst;
ase_uint32* src_address;
ase_uint32* dst_address;
int x, y, dx, dy, color;
int getx, gety, addx, addy;
int r, g, b, a;
int *mdata;
int w, div;
if (matrix) {
w = effect->x+effect->w;
y = effect->y+effect->row;
dst_address = ((ase_uint32 **)dst->line)[y]+effect->x;
for (x=effect->x; x<w; x++) {
/* avoid the unmask region */
if (effect->mask_address) {
if (!((*effect->mask_address) & (1<<effect->d.rem))) {
dst_address++;
_image_bitmap_next_bit(effect->d, effect->mask_address);
continue;
}
else
_image_bitmap_next_bit(effect->d, effect->mask_address);
}
r = g = b = a = 0;
GET_CONVMATR_DATA
(RgbTraits,
if (_rgba_geta(color) == 0)
div -= *mdata;
else {
r += _rgba_getr(color) * (*mdata);
g += _rgba_getg(color) * (*mdata);
b += _rgba_getb(color) * (*mdata);
a += _rgba_geta(color) * (*mdata);
}
);
if (effect->target & TARGET_RED_CHANNEL) {
r = r / div + matrix->bias;
r = MID(0, r, 255);
}
else
r = _rgba_getr(color);
if (effect->target & TARGET_GREEN_CHANNEL) {
g = g / div + matrix->bias;
g = MID(0, g, 255);
}
else
g = _rgba_getg(color);
if (effect->target & TARGET_BLUE_CHANNEL) {
b = b / div + matrix->bias;
b = MID(0, b, 255);
}
else
b = _rgba_getb(color);
if (effect->target & TARGET_ALPHA_CHANNEL) {
a = a / matrix->div + matrix->bias;
a = MID(0, a, 255);
}
else
a = _rgba_geta(color);
*(dst_address++) = _rgba(r, g, b, a);
}
}
}
void apply_convolution_matrix2(Effect *effect)
{
ConvMatr* matrix = data.convmatr;
const Image* src = effect->src;
Image* dst = effect->dst;
ase_uint16* src_address;
ase_uint16* dst_address;
int x, y, dx, dy, color;
int getx, gety, addx, addy;
int k, a;
int *mdata;
int w, div;
if (matrix) {
w = effect->x+effect->w;
y = effect->y+effect->row;
dst_address = ((ase_uint16 **)dst->line)[y]+effect->x;
for (x=effect->x; x<w; x++) {
/* avoid the unmask region */
if (effect->mask_address) {
if (!((*effect->mask_address) & (1<<effect->d.rem))) {
dst_address++;
_image_bitmap_next_bit(effect->d, effect->mask_address);
continue;
}
else
_image_bitmap_next_bit(effect->d, effect->mask_address);
}
k = a = 0;
GET_CONVMATR_DATA
(GrayscaleTraits,
if (_graya_geta(color) == 0)
div -= *mdata;
else {
k += _graya_getv(color) * (*mdata);
a += _graya_geta(color) * (*mdata);
}
);
if (effect->target & TARGET_GRAY_CHANNEL) {
k = k / div + matrix->bias;
k = MID(0, k, 255);
}
else
k = _graya_getv(color);
if (effect->target & TARGET_ALPHA_CHANNEL) {
a = a / matrix->div + matrix->bias;
a = MID(0, a, 255);
}
else
a = _graya_geta(color);
*(dst_address++) = _graya(k, a);
}
}
}
void apply_convolution_matrix1(Effect *effect)
{
const Palette* pal = get_current_palette();
const RgbMap* rgbmap = effect->sprite->getRgbMap();
const ConvMatr* matrix = data.convmatr;
const Image* src = effect->src;
Image* dst = effect->dst;
ase_uint8* src_address;
ase_uint8* dst_address;
int x, y, dx, dy, color;
int getx, gety, addx, addy;
int r, g, b, index;
int *mdata;
int w, div;
if (matrix) {
w = effect->x+effect->w;
y = effect->y+effect->row;
dst_address = ((ase_uint8 **)dst->line)[y]+effect->x;
for (x=effect->x; x<w; x++) {
/* avoid the unmask region */
if (effect->mask_address) {
if (!((*effect->mask_address) & (1<<effect->d.rem))) {
dst_address++;
_image_bitmap_next_bit(effect->d, effect->mask_address);
continue;
}
else
_image_bitmap_next_bit(effect->d, effect->mask_address);
}
r = g = b = index = 0;
GET_CONVMATR_DATA
(IndexedTraits,
r += _rgba_getr(pal->getEntry(color)) * (*mdata);
g += _rgba_getg(pal->getEntry(color)) * (*mdata);
b += _rgba_getb(pal->getEntry(color)) * (*mdata);
index += color * (*mdata);
);
if (effect->target & TARGET_INDEX_CHANNEL) {
index = index / matrix->div + matrix->bias;
index = MID(0, index, 255);
*(dst_address++) = index;
}
else {
if (effect->target & TARGET_RED_CHANNEL) {
r = r / div + matrix->bias;
r = MID(0, r, 255);
}
else
r = _rgba_getr(pal->getEntry(color));
if (effect->target & TARGET_GREEN_CHANNEL) {
g = g / div + matrix->bias;
g = MID(0, g, 255);
}
else
g = _rgba_getg(pal->getEntry(color));
if (effect->target & TARGET_BLUE_CHANNEL) {
b = b / div + matrix->bias;
b = MID(0, b, 255);
}
else
b = _rgba_getb(pal->getEntry(color));
*(dst_address++) = rgbmap->mapColor(r, g, b);
}
}
}
}

View File

@ -1,58 +0,0 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef EFFECT_CONVMATR_H_INCLUDED
#define EFFECT_CONVMATR_H_INCLUDED
#include "gui/base.h"
#include "tiled_mode.h"
struct Effect;
typedef struct ConvMatr /* a convolution matrix */
{
char *name; /* name */
int w, h; /* size of the matrix */
int cx, cy; /* centre of the filter */
int *data; /* the matrix with the multiplication factors */
int div; /* division factor */
int bias; /* addition factor (for offset) */
int default_target; /* targets by default (look at
TARGET_RED_CHANNEL, etc. constants) */
} ConvMatr;
ConvMatr *convmatr_new(int w, int h);
ConvMatr *convmatr_new_string(const char *format);
void convmatr_free(ConvMatr *convmatr);
void set_convmatr(ConvMatr *convmatr, TiledMode tiled);
ConvMatr *get_convmatr();
ConvMatr *get_convmatr_by_name(const char *name);
void reload_matrices_stock();
void clean_matrices_stock();
JList get_convmatr_stock();
void init_convolution_matrix();
void exit_convolution_matrix();
void apply_convolution_matrix4(struct Effect *effect);
void apply_convolution_matrix2(struct Effect *effect);
void apply_convolution_matrix1(struct Effect *effect);
#endif

View File

@ -1,432 +0,0 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include "gui/manager.h"
#include "gui/rect.h"
#include "gui/region.h"
#include "gui/view.h"
#include "gui/widget.h"
#include "console.h"
#include "core/cfg.h"
#include "effect/colcurve.h"
#include "effect/convmatr.h"
#include "effect/effect.h"
#include "effect/invrtcol.h"
#include "effect/median.h"
#include "effect/replcol.h"
#include "modules/editors.h"
#include "raster/cel.h"
#include "raster/image.h"
#include "raster/images_collector.h"
#include "raster/layer.h"
#include "raster/mask.h"
#include "raster/sprite.h"
#include "raster/stock.h"
#include "raster/undo.h"
#include "util/misc.h"
#include "widgets/editor.h"
typedef struct EffectData
{
const char *name;
const char *label;
void (*apply_4)(Effect *effect);
void (*apply_2)(Effect *effect);
void (*apply_1)(Effect *effect);
} EffectData;
#define FXDATA(name, label) \
{ #name, label, apply_##name##4, apply_##name##2, apply_##name##1 }
static EffectData effects_data[] = {
FXDATA(color_curve, "Color Curve"),
FXDATA(convolution_matrix, "Convolution Matrix"),
FXDATA(invert_color, "Invert Color"),
FXDATA(median, "Median"),
FXDATA(replace_color, "Replace Color"),
{ NULL, NULL, NULL, NULL }
};
static EffectData *get_effect_data(const char *name);
static void effect_init(Effect* effect, const Layer* layer, Image* image, int offset_x, int offset_y);
static void effect_apply_to_image(Effect* effect, Layer* layer, Image* image, int x, int y);
static bool effect_update_mask(Effect* effect, Mask* mask, const Image* image);
int init_module_effect()
{
init_convolution_matrix();
return 0;
}
void exit_module_effect()
{
exit_convolution_matrix();
}
Effect::Effect(const SpriteReader& sprite, const char* name)
{
int offset_x, offset_y;
EffectData* effect_data;
void (*apply)(Effect*);
effect_data = get_effect_data(name);
apply = NULL;
switch (sprite->getImgType()) {
case IMAGE_RGB: apply = effect_data->apply_4; break;
case IMAGE_GRAYSCALE: apply = effect_data->apply_2; break;
case IMAGE_INDEXED: apply = effect_data->apply_1; break;
default:
throw invalid_imgtype_exception();
}
this->sprite = sprite;
this->src = NULL;
this->dst = NULL;
this->row = 0;
this->offset_x = 0;
this->offset_y = 0;
this->mask = NULL;
this->preview_mask = NULL;
this->mask_address = NULL;
this->effect_data = effect_data;
this->apply = apply;
this->_target = TARGET_ALL_CHANNELS;
this->target = TARGET_ALL_CHANNELS;
this->progress_data = NULL;
this->progress = NULL;
this->is_cancelled = NULL;
Image* image = this->sprite->getCurrentImage(&offset_x, &offset_y);
if (image == NULL)
throw no_image_exception();
effect_init(this, sprite->getCurrentLayer(), image, offset_x, offset_y);
}
Effect::~Effect()
{
if (this->preview_mask)
mask_free(this->preview_mask);
if (this->dst)
image_free(this->dst);
}
void effect_set_target(Effect *effect, int target)
{
effect->_target = target;
effect->target = target;
/* the alpha channel of the background layer can't be modified */
if (effect->sprite->getCurrentLayer() &&
effect->sprite->getCurrentLayer()->is_background())
effect->target &= ~TARGET_ALPHA_CHANNEL;
}
void effect_begin(Effect *effect)
{
effect->row = 0;
effect->mask = effect->sprite->getMask();
effect_update_mask(effect, effect->mask, effect->src);
}
void effect_begin_for_preview(Effect *effect)
{
if (effect->preview_mask) {
mask_free(effect->preview_mask);
effect->preview_mask = NULL;
}
if ((effect->sprite->getMask()) && (effect->sprite->getMask()->bitmap))
effect->preview_mask = mask_new_copy(effect->sprite->getMask());
else {
effect->preview_mask = mask_new();
mask_replace(effect->preview_mask,
effect->offset_x, effect->offset_y,
effect->src->w, effect->src->h);
}
effect->row = 0;
effect->mask = effect->preview_mask;
{
Editor* editor = current_editor;
gfx::Rect vp = View::getView(editor)->getViewportBounds();
int x1, y1, x2, y2;
int x, y, w, h;
editor->screen_to_editor(vp.x, vp.y, &x1, &y1);
editor->screen_to_editor(vp.x+vp.w-1, vp.y+vp.h-1, &x2, &y2);
if (x1 < 0) x1 = 0;
if (y1 < 0) y1 = 0;
if (x2 >= effect->sprite->getWidth()) x2 = effect->sprite->getWidth()-1;
if (y2 >= effect->sprite->getHeight()) y2 = effect->sprite->getHeight()-1;
x = x1;
y = y1;
w = x2 - x1 + 1;
h = y2 - y1 + 1;
if ((w < 1) || (h < 1)) {
mask_free(effect->preview_mask);
effect->preview_mask = NULL;
effect->row = -1;
return;
}
mask_intersect(effect->preview_mask, x, y, w, h);
}
if (!effect_update_mask(effect, effect->mask, effect->src)) {
mask_free(effect->preview_mask);
effect->preview_mask = NULL;
effect->row = -1;
return;
}
}
bool effect_apply_step(Effect *effect)
{
if ((effect->row >= 0) && (effect->row < effect->h)) {
if ((effect->mask) && (effect->mask->bitmap)) {
effect->d = div(effect->x-effect->mask->x+effect->offset_x, 8);
effect->mask_address =
((ase_uint8 **)effect->mask->bitmap->line)
[effect->row+effect->y-effect->mask->y+effect->offset_y]+effect->d.quot;
}
else
effect->mask_address = NULL;
(*effect->apply)(effect);
effect->row++;
return true;
}
else {
return false;
}
}
void effect_apply(Effect* effect)
{
bool cancelled = false;
effect_begin(effect);
while (!cancelled && effect_apply_step(effect)) {
if (effect->progress != NULL)
(effect->progress)(effect->progress_data,
effect->progress_base
+ effect->progress_width * (effect->row+1) / effect->h);
if (effect->is_cancelled != NULL)
cancelled = (effect->is_cancelled)(effect->progress_data);
}
if (!cancelled) {
// Undo stuff
if (effect->sprite->getUndo()->isEnabled()) {
effect->sprite->getUndo()->setLabel(effect->effect_data->label);
effect->sprite->getUndo()
->undo_image(effect->src, effect->x, effect->y, effect->w, effect->h);
}
// Copy "dst" to "src"
image_copy(effect->src, effect->dst, 0, 0);
}
}
/**
* Updates the current editor to show the progress of the preview.
*/
void effect_flush(Effect *effect)
{
if (effect->row >= 0) {
JRegion reg1, reg2;
struct jrect rect;
Editor* editor = current_editor;
reg1 = jregion_new(NULL, 0);
editor->editor_to_screen(effect->x+effect->offset_x,
effect->y+effect->offset_y+effect->row-1,
&rect.x1, &rect.y1);
rect.x2 = rect.x1 + (effect->w << editor->editor_get_zoom());
rect.y2 = rect.y1 + (1 << editor->editor_get_zoom());
reg2 = jregion_new(&rect, 1);
jregion_union(reg1, reg1, reg2);
jregion_free(reg2);
reg2 = jwidget_get_drawable_region(editor, JI_GDR_CUTTOPWINDOWS);
jregion_intersect(reg1, reg1, reg2);
jregion_free(reg2);
editor->invalidateRegion(reg1);
jregion_free(reg1);
}
}
void effect_apply_to_target(Effect *effect)
{
bool cancelled = false;
ImagesCollector images(effect->sprite,
(effect->target & TARGET_ALL_LAYERS) == TARGET_ALL_LAYERS,
(effect->target & TARGET_ALL_FRAMES) == TARGET_ALL_FRAMES,
true); // we will write in each image
if (images.empty())
return;
// Open group of undo operations
if (images.size() > 1) {
if (effect->sprite->getUndo()->isEnabled())
effect->sprite->getUndo()->undo_open();
}
effect->progress_base = 0.0f;
effect->progress_width = 1.0f / images.size();
// For each target image
for (ImagesCollector::ItemsIterator it = images.begin();
it != images.end() && !cancelled;
++it) {
effect_apply_to_image(effect, it->layer(), it->image(), it->cel()->x, it->cel()->y);
// There is a 'is_cancelled' hook?
if (effect->is_cancelled != NULL)
cancelled = (effect->is_cancelled)(effect->progress_data);
// Make progress
effect->progress_base += effect->progress_width;
}
// Close group of undo operations
if (images.size() > 1) {
if (effect->sprite->getUndo()->isEnabled())
effect->sprite->getUndo()->undo_close();
}
}
static EffectData *get_effect_data(const char *name)
{
int c;
for (c=0; effects_data[c].name; c++) {
if (strcmp(effects_data[c].name, name) == 0)
return effects_data+c;
}
throw invalid_effect_exception(name);
}
static void effect_init(Effect* effect, const Layer* layer, Image* image,
int offset_x, int offset_y)
{
effect->offset_x = offset_x;
effect->offset_y = offset_y;
if (!effect_update_mask(effect, effect->sprite->getMask(), image))
throw invalid_area_exception();
if (effect->preview_mask) {
mask_free(effect->preview_mask);
effect->preview_mask = NULL;
}
if (effect->dst) {
image_free(effect->dst);
effect->dst = NULL;
}
effect->src = image;
effect->dst = image_crop(image, 0, 0, image->w, image->h, 0);
effect->row = -1;
effect->mask = NULL;
effect->preview_mask = NULL;
effect->mask_address = NULL;
effect->target = effect->_target;
/* the alpha channel of the background layer can't be modified */
if (layer->is_background())
effect->target &= ~TARGET_ALPHA_CHANNEL;
}
static void effect_apply_to_image(Effect* effect, Layer* layer, Image* image, int x, int y)
{
effect_init(effect, layer, image, x, y);
effect_apply(effect);
}
static bool effect_update_mask(Effect* effect, Mask* mask, const Image* image)
{
int x, y, w, h;
if ((mask) && (mask->bitmap)) {
x = mask->x - effect->offset_x;
y = mask->y - effect->offset_y;
w = mask->w;
h = mask->h;
if (x < 0) {
w += x;
x = 0;
}
if (y < 0) {
h += y;
y = 0;
}
if (x+w-1 >= image->w-1)
w = image->w-x;
if (y+h-1 >= image->h-1)
h = image->h-y;
}
else {
x = 0;
y = 0;
w = image->w;
h = image->h;
}
if ((w < 1) || (h < 1)) {
effect->x = 0;
effect->y = 0;
effect->w = 0;
effect->h = 0;
return false;
}
else {
effect->x = x;
effect->y = y;
effect->w = w;
effect->h = h;
return true;
}
}

View File

@ -1,197 +0,0 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef EFFECT_EFFECT_H_INCLUDED
#define EFFECT_EFFECT_H_INCLUDED
#include <stdlib.h>
#include <cstring>
#include "sprite_wrappers.h"
#include "gui/base.h"
#include "tiled_mode.h"
class Image;
class Mask;
class Sprite;
#define TARGET_RED_CHANNEL 1
#define TARGET_GREEN_CHANNEL 2
#define TARGET_BLUE_CHANNEL 4
#define TARGET_ALPHA_CHANNEL 8
#define TARGET_GRAY_CHANNEL 16
#define TARGET_INDEX_CHANNEL 32
#define TARGET_ALL_FRAMES 64
#define TARGET_ALL_LAYERS 128
#define TARGET_ALL_CHANNELS \
(TARGET_RED_CHANNEL | \
TARGET_GREEN_CHANNEL | \
TARGET_BLUE_CHANNEL | \
TARGET_ALPHA_CHANNEL | \
TARGET_GRAY_CHANNEL )
class invalid_effect_exception : public base::Exception
{
public:
invalid_effect_exception(const char* effect_name) throw()
: base::Exception("Invalid effect specified: %s", effect_name) { }
};
class invalid_imgtype_exception : public base::Exception
{
public:
invalid_imgtype_exception() throw()
: base::Exception("Invalid image type specified.") { }
};
class invalid_area_exception : public base::Exception
{
public:
invalid_area_exception() throw()
: base::Exception("The current mask/area to apply the effect is completelly invalid.") { }
};
class no_image_exception : public base::Exception
{
public:
no_image_exception() throw()
: base::Exception("There are not an active image to apply the effect.\n"
"Please select a layer/cel with an image and try again.") { }
};
struct EffectData;
struct Effect
{
SpriteWriter sprite;
Image* src;
Image* dst;
int row;
int x, y, w, h;
int offset_x, offset_y;
Mask* mask;
Mask* preview_mask;
unsigned char *mask_address;
div_t d;
struct EffectData *effect_data;
void (*apply)(struct Effect* effect);
int _target; /* original targets */
int target; /* filtered targets */
/* hooks */
float progress_base, progress_width;
void *progress_data;
void (*progress)(void *data, float progress);
bool (*is_cancelled)(void *data);
Effect(const SpriteReader& sprite, const char* name);
~Effect();
};
int init_module_effect();
void exit_module_effect();
void effect_set_target(Effect* effect, int target);
void effect_begin(Effect* effect);
void effect_begin_for_preview(Effect* effect);
bool effect_apply_step(Effect* effect);
void effect_apply(Effect* effect);
void effect_flush(Effect* effect);
void effect_apply_to_target(Effect* effect);
/**
* Macro to get contiguos pixels from an image. It's useful to fill a
* matrix of pixels of "width x height" dimension.
*
* It needs some variables to be defined before to use this routines:
* x, y = pixel position
* getx, gety, addx, addy, dx, dy = auxiliars
*/
#define GET_MATRIX_DATA(ptr_type, src, src_address, \
width, height, cx, cy, tiled, do_job) \
/* Y position to get pixel */ \
gety = y-(cy); \
addy = 0; \
if (gety < 0) { \
if (tiled & TILED_Y_AXIS) \
gety = src->h - (-(gety+1) % src->h) - 1; \
else { \
addy = -gety; \
gety = 0; \
} \
} \
else if (gety >= src->h) { \
if (tiled & TILED_Y_AXIS) \
gety = gety % src->h; \
else \
gety = src->h-1; \
} \
\
for (dy=0; dy<(height); dy++) { \
/* X position to get pixel */ \
getx = x-(cx); \
addx = 0; \
if (getx < 0) { \
if (tiled & TILED_X_AXIS) \
getx = src->w - (-(getx+1) % src->w) - 1; \
else { \
addx = -getx; \
getx = 0; \
} \
} \
else if (getx >= src->w) { \
if (tiled & TILED_X_AXIS) \
getx = getx % src->w; \
else \
getx = src->w-1; \
} \
\
src_address = ((ptr_type **)src->line)[gety]+getx; \
\
for (dx=0; dx<width; dx++) { \
do_job \
\
/* update X position to get pixel */ \
if (getx < src->w-1) { \
getx++; \
if (addx == 0) \
src_address++; \
else \
addx--; \
} \
else if (tiled & TILED_X_AXIS) { \
getx = 0; \
src_address = ((ptr_type **)src->line)[gety]+getx; \
} \
} \
\
/* update Y position to get pixel */ \
if (gety < src->h-1) { \
if (addy == 0) \
gety++; \
else \
addy--; \
} \
else if (tiled & TILED_Y_AXIS) \
gety = 0; \
}
#endif

View File

@ -1,138 +0,0 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "effect/effect.h"
#include "modules/palettes.h"
#include "raster/image.h"
#include "raster/palette.h"
#include "raster/rgbmap.h"
void apply_invert_color4(Effect *effect)
{
ase_uint32 *src_address;
ase_uint32 *dst_address;
int x, c, r, g, b, a;
src_address = ((ase_uint32 **)effect->src->line)[effect->row+effect->y]+effect->x;
dst_address = ((ase_uint32 **)effect->dst->line)[effect->row+effect->y]+effect->x;
for (x=0; x<effect->w; x++) {
if (effect->mask_address) {
if (!((*effect->mask_address) & (1<<effect->d.rem))) {
src_address++;
dst_address++;
_image_bitmap_next_bit(effect->d, effect->mask_address);
continue;
}
else
_image_bitmap_next_bit(effect->d, effect->mask_address);
}
c = *(src_address++);
r = _rgba_getr(c);
g = _rgba_getg(c);
b = _rgba_getb(c);
a = _rgba_geta(c);
if (effect->target & TARGET_RED_CHANNEL) r ^= 0xff;
if (effect->target & TARGET_GREEN_CHANNEL) g ^= 0xff;
if (effect->target & TARGET_BLUE_CHANNEL) b ^= 0xff;
if (effect->target & TARGET_ALPHA_CHANNEL) a ^= 0xff;
*(dst_address++) = _rgba(r, g, b, a);
}
}
void apply_invert_color2(Effect *effect)
{
ase_uint16 *src_address;
ase_uint16 *dst_address;
int x, c, k, a;
src_address = ((ase_uint16 **)effect->src->line)[effect->row+effect->y]+effect->x;
dst_address = ((ase_uint16 **)effect->dst->line)[effect->row+effect->y]+effect->x;
for (x=0; x<effect->w; x++) {
if (effect->mask_address) {
if (!((*effect->mask_address) & (1<<effect->d.rem))) {
src_address++;
dst_address++;
_image_bitmap_next_bit(effect->d, effect->mask_address);
continue;
}
else
_image_bitmap_next_bit(effect->d, effect->mask_address);
}
c = *(src_address++);
k = _graya_getv(c);
a = _graya_geta(c);
if (effect->target & TARGET_GRAY_CHANNEL) k ^= 0xff;
if (effect->target & TARGET_ALPHA_CHANNEL) a ^= 0xff;
*(dst_address++) = _graya(k, a);
}
}
void apply_invert_color1(Effect *effect)
{
Palette *pal = get_current_palette();
RgbMap* rgbmap = effect->sprite->getRgbMap();
ase_uint8 *src_address;
ase_uint8 *dst_address;
int x, c, r, g, b;
src_address = ((ase_uint8 **)effect->src->line)[effect->row+effect->y]+effect->x;
dst_address = ((ase_uint8 **)effect->dst->line)[effect->row+effect->y]+effect->x;
for (x=0; x<effect->w; x++) {
if (effect->mask_address) {
if (!((*effect->mask_address) & (1<<effect->d.rem))) {
src_address++;
dst_address++;
_image_bitmap_next_bit(effect->d, effect->mask_address);
continue;
}
else
_image_bitmap_next_bit(effect->d, effect->mask_address);
}
c = *(src_address++);
if (effect->target & TARGET_INDEX_CHANNEL)
c ^= 0xff;
else {
r = _rgba_getr(pal->getEntry(c));
g = _rgba_getg(pal->getEntry(c));
b = _rgba_getb(pal->getEntry(c));
if (effect->target & TARGET_RED_CHANNEL ) r ^= 0xff;
if (effect->target & TARGET_GREEN_CHANNEL) g ^= 0xff;
if (effect->target & TARGET_BLUE_CHANNEL ) b ^= 0xff;
c = rgbmap->mapColor(r, g, b);
}
*(dst_address++) = c;
}
}

View File

@ -1,260 +0,0 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <allegro.h>
#include "base/memory.h"
#include "effect/effect.h"
#include "modules/palettes.h"
#include "raster/image.h"
#include "raster/palette.h"
#include "raster/rgbmap.h"
#include "tiled_mode.h"
static struct {
TiledMode tiled;
int w, h;
int ncolors;
unsigned char *channel[4];
} data = { TILED_NONE, 0, 0, 0, { NULL, NULL, NULL, NULL } };
void set_median_size(TiledMode tiled, int w, int h)
{
int c;
data.tiled = tiled;
data.w = w;
data.h = h;
data.ncolors = w*h;
for (c=0; c<4; c++) {
if (data.channel[c])
base_free(data.channel[c]);
data.channel[c] = (unsigned char*)base_malloc(sizeof(unsigned char) * data.ncolors);
}
}
static int cmp_channel(const void *p1, const void *p2)
{
return (*(unsigned char *)p2) -(*(unsigned char *)p1);
}
void apply_median4(Effect *effect)
{
const Image *src = effect->src;
Image *dst = effect->dst;
const ase_uint32 *src_address;
ase_uint32 *dst_address;
int x, y, dx, dy, color;
int c, w, r, g, b, a;
int getx, gety, addx, addy;
w = effect->x+effect->w;
y = effect->y+effect->row;
dst_address = ((ase_uint32 **)dst->line)[y]+effect->x;
for (x=effect->x; x<w; x++) {
/* avoid the unmask region */
if (effect->mask_address) {
if (!((*effect->mask_address) & (1<<effect->d.rem))) {
dst_address++;
_image_bitmap_next_bit(effect->d, effect->mask_address);
continue;
}
else
_image_bitmap_next_bit(effect->d, effect->mask_address);
}
c = 0;
GET_MATRIX_DATA
(ase_uint32, src, src_address,
data.w, data.h, data.w/2, data.h/2, data.tiled,
color = *src_address;
data.channel[0][c] = _rgba_getr(color);
data.channel[1][c] = _rgba_getg(color);
data.channel[2][c] = _rgba_getb(color);
data.channel[3][c] = _rgba_geta(color);
c++;
);
for (c=0; c<4; c++)
qsort(data.channel[c], data.ncolors, sizeof(unsigned char), cmp_channel);
color = image_getpixel_fast<RgbTraits>(src, x, y);
if (effect->target & TARGET_RED_CHANNEL)
r = data.channel[0][data.ncolors/2];
else
r = _rgba_getr(color);
if (effect->target & TARGET_GREEN_CHANNEL)
g = data.channel[1][data.ncolors/2];
else
g = _rgba_getg(color);
if (effect->target & TARGET_BLUE_CHANNEL)
b = data.channel[2][data.ncolors/2];
else
b = _rgba_getb(color);
if (effect->target & TARGET_ALPHA_CHANNEL)
a = data.channel[3][data.ncolors/2];
else
a = _rgba_geta(color);
*(dst_address++) = _rgba(r, g, b, a);
}
}
void apply_median2(Effect *effect)
{
const Image *src = effect->src;
Image *dst = effect->dst;
const ase_uint16 *src_address;
ase_uint16 *dst_address;
int x, y, dx, dy, color;
int c, w, k, a;
int getx, gety, addx, addy;
w = effect->x+effect->w;
y = effect->y+effect->row;
dst_address = ((ase_uint16 **)dst->line)[y]+effect->x;
for (x=effect->x; x<w; x++) {
/* avoid the unmask region */
if (effect->mask_address) {
if (!((*effect->mask_address) & (1<<effect->d.rem))) {
dst_address++;
_image_bitmap_next_bit(effect->d, effect->mask_address);
continue;
}
else
_image_bitmap_next_bit(effect->d, effect->mask_address);
}
c = 0;
GET_MATRIX_DATA
(ase_uint16, src, src_address,
data.w, data.h, data.w/2, data.h/2, data.tiled,
color = *src_address;
data.channel[0][c] = _graya_getv(color);
data.channel[1][c] = _graya_geta(color);
c++;
);
for (c=0; c<2; c++)
qsort(data.channel[c], data.ncolors, sizeof(unsigned char), cmp_channel);
color = image_getpixel_fast<GrayscaleTraits>(src, x, y);
if (effect->target & TARGET_GRAY_CHANNEL)
k = data.channel[0][data.ncolors/2];
else
k = _graya_getv(color);
if (effect->target & TARGET_ALPHA_CHANNEL)
a = data.channel[1][data.ncolors/2];
else
a = _graya_geta(color);
*(dst_address++) = _graya(k, a);
}
}
void apply_median1(Effect *effect)
{
const Palette* pal = get_current_palette();
const RgbMap* rgbmap = effect->sprite->getRgbMap();
const Image* src = effect->src;
Image* dst = effect->dst;
const ase_uint8* src_address;
ase_uint8* dst_address;
int x, y, dx, dy, color;
int c, w, r, g, b;
int getx, gety, addx, addy;
w = effect->x+effect->w;
y = effect->y+effect->row;
dst_address = ((ase_uint8 **)dst->line)[y]+effect->x;
for (x=effect->x; x<w; x++) {
/* avoid the unmask region */
if (effect->mask_address) {
if (!((*effect->mask_address) & (1<<effect->d.rem))) {
dst_address++;
_image_bitmap_next_bit(effect->d, effect->mask_address);
continue;
}
else
_image_bitmap_next_bit(effect->d, effect->mask_address);
}
c = 0;
GET_MATRIX_DATA
(ase_uint8, src, src_address,
data.w, data.h, data.w/2, data.h/2, data.tiled,
color = *src_address;
if (effect->target & TARGET_INDEX_CHANNEL) {
data.channel[0][c] = color;
}
else {
data.channel[0][c] = _rgba_getr(pal->getEntry(color));
data.channel[1][c] = _rgba_getg(pal->getEntry(color));
data.channel[2][c] = _rgba_getb(pal->getEntry(color));
}
c++;
);
if (effect->target & TARGET_INDEX_CHANNEL)
qsort(data.channel[0], data.ncolors, sizeof(unsigned char), cmp_channel);
else {
for (c=0; c<3; c++)
qsort(data.channel[c], data.ncolors, sizeof(unsigned char), cmp_channel);
}
if (effect->target & TARGET_INDEX_CHANNEL) {
*(dst_address++) = data.channel[0][data.ncolors/2];
}
else {
color = image_getpixel_fast<IndexedTraits>(src, x, y);
if (effect->target & TARGET_RED_CHANNEL)
r = data.channel[0][data.ncolors/2];
else
r = _rgba_getr(pal->getEntry(color));
if (effect->target & TARGET_GREEN_CHANNEL)
g = data.channel[1][data.ncolors/2];
else
g = _rgba_getg(pal->getEntry(color));
if (effect->target & TARGET_BLUE_CHANNEL)
b = data.channel[2][data.ncolors/2];
else
b = _rgba_getb(pal->getEntry(color));
*(dst_address++) = rgbmap->mapColor(r, g, b);
}
}
}

View File

@ -1,149 +0,0 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "app/color.h"
#include "effect/effect.h"
#include "raster/image.h"
static struct {
int from, to;
int tolerance;
} data;
void set_replace_colors(int from, int to, int tolerance)
{
data.from = from;
data.to = to;
data.tolerance = MID(0, tolerance, 255);
}
void apply_replace_color4(Effect *effect)
{
ase_uint32 *src_address;
ase_uint32 *dst_address;
int src_r, src_g, src_b, src_a;
int dst_r, dst_g, dst_b, dst_a;
int x, c;
src_address = ((ase_uint32 **)effect->src->line)[effect->row+effect->y]+effect->x;
dst_address = ((ase_uint32 **)effect->dst->line)[effect->row+effect->y]+effect->x;
dst_r = _rgba_getr(data.from);
dst_g = _rgba_getg(data.from);
dst_b = _rgba_getb(data.from);
dst_a = _rgba_geta(data.from);
for (x=0; x<effect->w; x++) {
if (effect->mask_address) {
if (!((*effect->mask_address) & (1<<effect->d.rem))) {
src_address++;
dst_address++;
_image_bitmap_next_bit(effect->d, effect->mask_address);
continue;
}
else
_image_bitmap_next_bit(effect->d, effect->mask_address);
}
c = *(src_address++);
src_r = _rgba_getr(c);
src_g = _rgba_getg(c);
src_b = _rgba_getb(c);
src_a = _rgba_geta(c);
if ((ABS(src_r-dst_r) <= data.tolerance) &&
(ABS(src_g-dst_g) <= data.tolerance) &&
(ABS(src_b-dst_b) <= data.tolerance) &&
(ABS(src_a-dst_a) <= data.tolerance))
*(dst_address++) = data.to;
else
*(dst_address++) = c;
}
}
void apply_replace_color2(Effect *effect)
{
ase_uint16 *src_address;
ase_uint16 *dst_address;
int src_k, src_a;
int dst_k, dst_a;
int x, c;
src_address = ((ase_uint16 **)effect->src->line)[effect->row+effect->y]+effect->x;
dst_address = ((ase_uint16 **)effect->dst->line)[effect->row+effect->y]+effect->x;
dst_k = _graya_getv(data.from);
dst_a = _graya_geta(data.from);
for (x=0; x<effect->w; x++) {
if (effect->mask_address) {
if (!((*effect->mask_address) & (1<<effect->d.rem))) {
src_address++;
dst_address++;
_image_bitmap_next_bit(effect->d, effect->mask_address);
continue;
}
else
_image_bitmap_next_bit(effect->d, effect->mask_address);
}
c = *(src_address++);
src_k = _graya_getv(c);
src_a = _graya_geta(c);
if ((ABS(src_k-dst_k) <= data.tolerance) &&
(ABS(src_a-dst_a) <= data.tolerance))
*(dst_address++) = data.to;
else
*(dst_address++) = c;
}
}
void apply_replace_color1(Effect *effect)
{
ase_uint8 *src_address;
ase_uint8 *dst_address;
int x, c;
src_address = ((ase_uint8 **)effect->src->line)[effect->row+effect->y]+effect->x;
dst_address = ((ase_uint8 **)effect->dst->line)[effect->row+effect->y]+effect->x;
for (x=0; x<effect->w; x++) {
if (effect->mask_address) {
if (!((*effect->mask_address) & (1<<effect->d.rem))) {
src_address++;
dst_address++;
_image_bitmap_next_bit(effect->d, effect->mask_address);
continue;
}
else
_image_bitmap_next_bit(effect->d, effect->mask_address);
}
c = *(src_address++);
if (ABS(c-data.from) <= data.tolerance)
*(dst_address++) = data.to;
else
*(dst_address++) = c;
}
}

View File

@ -0,0 +1,12 @@
# ASE - Allegro Sprite Editor
# Copyright (C) 2001-2011 David Capello
add_library(filters-lib
color_curve.cpp
color_curve_filter.cpp
convolution_matrix.cpp
convolution_matrix_filter.cpp
invert_color_filter.cpp
median_filter.cpp
replace_color_filter.cpp)

View File

@ -0,0 +1,95 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "filters/color_curve.h"
#include <algorithm>
ColorCurve::ColorCurve(Type type)
: m_type(type)
{
}
void ColorCurve::addPoint(const gfx::Point& point)
{
for (iterator it = begin(), end = this->end(); it != end; ++it) {
if (it->x >= point.x) {
m_points.insert(it, point);
return;
}
}
m_points.push_back(point);
}
void ColorCurve::removePoint(const gfx::Point& point)
{
iterator it = std::find(begin(), end(), point);
if (it != end())
m_points.erase(it);
}
void ColorCurve::getValues(int x1, int x2, std::vector<int>& values)
{
int x, num_points = (int)m_points.size();
if (num_points == 0) {
for (x=x1; x<=x2; x++)
values[x-x1] = 0;
}
else if (num_points == 1) {
for (x=x1; x<=x2; x++)
values[x-x1] = m_points[0].y;
}
else {
switch (m_type) {
case Linear: {
iterator it, begin = this->begin(), end = this->end();
for (it = begin; it != end; ++it)
if (it->x >= x1)
break;
for (x=x1; x<=x2; x++) {
while ((it != end) && (x > it->x))
++it;
if (it != end) {
if (it != begin) {
const gfx::Point& p = *(it-1);
const gfx::Point& n = *it;
values[x-x1] = p.y + (n.y-p.y) * (x-p.x) / (n.x-p.x);
}
else {
values[x-x1] = it->y;
}
}
else {
values[x-x1] = (end-1)->y;
}
}
break;
}
}
}
}

51
src/filters/color_curve.h Normal file
View File

@ -0,0 +1,51 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef FILTERS_COLOR_CURVE_H_INCLUDED
#define FILTERS_COLOR_CURVE_H_INCLUDED
#include <vector>
#include "gfx/point.h"
class ColorCurve
{
public:
enum Type {
Linear,
//Spline, // TODO for the future
};
typedef std::vector<gfx::Point>::iterator iterator;
ColorCurve(Type type);
iterator begin() { return m_points.begin(); }
iterator end() { return m_points.end(); }
void addPoint(const gfx::Point& point);
void removePoint(const gfx::Point& point);
void getValues(int x1, int x2, std::vector<int>& values);
private:
Type m_type;
std::vector<gfx::Point> m_points;
};
#endif

View File

@ -0,0 +1,150 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "filters/color_curve_filter.h"
#include <vector>
#include "filters/color_curve.h"
#include "filters/filter_indexed_data.h"
#include "filters/filter_manager.h"
#include "raster/image.h"
#include "raster/palette.h"
#include "raster/rgbmap.h"
#include "raster/sprite.h"
ColorCurveFilter::ColorCurveFilter()
: m_curve(NULL)
, m_cmap(256)
{
}
void ColorCurveFilter::setCurve(ColorCurve* curve)
{
ASSERT(curve != NULL);
m_curve = curve;
// Generate the color convertion map
m_curve->getValues(0, 255, m_cmap);
for (int c=0; c<256; c++)
m_cmap[c] = MID(0, m_cmap[c], 255);
}
const char* ColorCurveFilter::getName()
{
return "Color Curve";
}
void ColorCurveFilter::applyToRgba(FilterManager* filterMgr)
{
const ase_uint32* src_address = (ase_uint32*)filterMgr->getSourceAddress();
ase_uint32* dst_address = (ase_uint32*)filterMgr->getDestinationAddress();
int w = filterMgr->getWidth();
Target target = filterMgr->getTarget();
int x, c, r, g, b, a;
for (x=0; x<w; x++) {
if (filterMgr->skipPixel()) {
++src_address;
++dst_address;
continue;
}
c = *(src_address++);
r = _rgba_getr(c);
g = _rgba_getg(c);
b = _rgba_getb(c);
a = _rgba_geta(c);
if (target & TARGET_RED_CHANNEL) r = m_cmap[r];
if (target & TARGET_GREEN_CHANNEL) g = m_cmap[g];
if (target & TARGET_BLUE_CHANNEL) b = m_cmap[b];
if (target & TARGET_ALPHA_CHANNEL) a = m_cmap[a];
*(dst_address++) = _rgba(r, g, b, a);
}
}
void ColorCurveFilter::applyToGrayscale(FilterManager* filterMgr)
{
const ase_uint16* src_address = (ase_uint16*)filterMgr->getSourceAddress();
ase_uint16* dst_address = (ase_uint16*)filterMgr->getDestinationAddress();
int w = filterMgr->getWidth();
Target target = filterMgr->getTarget();
int x, c, k, a;
for (x=0; x<w; x++) {
if (filterMgr->skipPixel()) {
++src_address;
++dst_address;
continue;
}
c = *(src_address++);
k = _graya_getv(c);
a = _graya_geta(c);
if (target & TARGET_GRAY_CHANNEL) k = m_cmap[k];
if (target & TARGET_ALPHA_CHANNEL) a = m_cmap[a];
*(dst_address++) = _graya(k, a);
}
}
void ColorCurveFilter::applyToIndexed(FilterManager* filterMgr)
{
const ase_uint8* src_address = (ase_uint8*)filterMgr->getSourceAddress();
ase_uint8* dst_address = (ase_uint8*)filterMgr->getDestinationAddress();
int w = filterMgr->getWidth();
Target target = filterMgr->getTarget();
const Palette* pal = filterMgr->getIndexedData()->getPalette();
const RgbMap* rgbmap = filterMgr->getIndexedData()->getRgbMap();
int x, c, r, g, b;
for (x=0; x<w; x++) {
if (filterMgr->skipPixel()) {
++src_address;
++dst_address;
continue;
}
c = *(src_address++);
if (target & TARGET_INDEX_CHANNEL) {
c = m_cmap[c];
}
else {
r = _rgba_getr(pal->getEntry(c));
g = _rgba_getg(pal->getEntry(c));
b = _rgba_getb(pal->getEntry(c));
if (target & TARGET_RED_CHANNEL) r = m_cmap[r];
if (target & TARGET_GREEN_CHANNEL) g = m_cmap[g];
if (target & TARGET_BLUE_CHANNEL) b = m_cmap[b];
c = rgbmap->mapColor(r, g, b);
}
*(dst_address++) = MID(0, c, pal->size()-1);
}
}

View File

@ -16,17 +16,32 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef WIDGETS_PREVIEW_H_INCLUDED
#define WIDGETS_PREVIEW_H_INCLUDED
#ifndef FILTERS_COLOR_CURVE_FILTER_H_INCLUDED
#define FILTERS_COLOR_CURVE_FILTER_H_INCLUDED
#include "gui/base.h"
#include <vector>
struct Effect;
#include "filters/filter.h"
JWidget preview_new(struct Effect *effect);
int preview_type();
class ColorCurve;
void preview_restart(JWidget preview);
struct Effect *preview_get_effect(JWidget preview);
class ColorCurveFilter : public Filter
{
public:
ColorCurveFilter();
void setCurve(ColorCurve* curve);
ColorCurve* getCurve() const { return m_curve; }
// Filter implementation
const char* getName();
void applyToRgba(FilterManager* filterMgr);
void applyToGrayscale(FilterManager* filterMgr);
void applyToIndexed(FilterManager* filterMgr);
private:
ColorCurve* m_curve;
std::vector<int> m_cmap;
};
#endif

View File

@ -16,15 +16,18 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef EFFECT_REPLCOL_H_INCLUDED
#define EFFECT_REPLCOL_H_INCLUDED
#include "config.h"
struct Effect;
#include "filters/convolution_matrix.h"
void set_replace_colors(int from, int to, int tolerance);
void apply_replace_color4(struct Effect *effect);
void apply_replace_color2(struct Effect *effect);
void apply_replace_color1(struct Effect *effect);
#endif
ConvolutionMatrix::ConvolutionMatrix(int width, int height)
: m_data(width*height, 0)
, m_width(width)
, m_height(height)
, m_cx(width/2)
, m_cy(height/2)
, m_div(ConvolutionMatrix::Precision)
, m_bias(0)
, m_defaultTarget(0)
{
}

View File

@ -0,0 +1,77 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef FILTERS_CONVOLUTION_MATRIX_H_INCLUDED
#define FILTERS_CONVOLUTION_MATRIX_H_INCLUDED
#include "filters/target.h"
#include <vector>
#include <string>
// A convolution matrix which is used by ConvolutionMatrixFilter.
class ConvolutionMatrix
{
public:
// TODO warning: this number could be dangerous for big filters
static const int Precision = 256;
ConvolutionMatrix(int width, int height);
const char* getName() const { return m_name.c_str(); }
int getWidth() const { return m_width; }
int getHeight() const { return m_height; }
int getCenterX() const { return m_cx; }
int getCenterY() const { return m_cy; }
int getDiv() const { return m_div; }
int getBias() const { return m_bias; }
Target getDefaultTarget() const { return m_defaultTarget; }
void setName(const char* name) { m_name = name; }
void setWidth(int width) { m_width = width; }
void setHeight(int height) { m_height = height; }
void setCenterX(int cx) { m_cx = cx; }
void setCenterY(int cy) { m_cy = cy; }
void setDiv(int div) { m_div = div; }
void setBias(int bias) { m_bias = bias; }
void setDefaultTarget(Target target) { m_defaultTarget = target; }
// Returns a reference to a value in the matrix. It is very
// important that values of this matrix are sortered in the
// following way (e.g. m_width=4, m_height=3):
//
// x0 x1 x2 x3
// x4 x5 x6 x7
// x8 x9 x10 x11
//
// The ConvolutionMatrixFilter expects that memory layout.
//
int& value(int x, int y) { return m_data[y*m_width+x]; }
const int& value(int x, int y) const { return m_data[y*m_width+x]; }
private:
std::string m_name; // Name
int m_width, m_height; // Size of the matrix
int m_cx, m_cy; // Center of the filter
int m_div; // Division factor
int m_bias; // Addition factor (for offset)
Target m_defaultTarget; // Targets by default (look at TARGET_RED_CHANNEL, etc. constants)
std::vector<int> m_data; // The matrix with the multiplication factors
};
#endif

View File

@ -0,0 +1,333 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "filters/convolution_matrix_filter.h"
#include "filters/convolution_matrix.h"
#include "filters/filter_indexed_data.h"
#include "filters/filter_manager.h"
#include "filters/neighboring_pixels.h"
#include "raster/image.h"
#include "raster/palette.h"
#include "raster/rgbmap.h"
ConvolutionMatrixFilter::ConvolutionMatrixFilter()
: m_matrix(NULL)
, m_tiledMode(TILED_NONE)
{
}
void ConvolutionMatrixFilter::setMatrix(const SharedPtr<ConvolutionMatrix>& matrix)
{
m_matrix = matrix;
m_lines.resize(matrix->getHeight());
}
void ConvolutionMatrixFilter::setTiledMode(TiledMode tiledMode)
{
m_tiledMode = tiledMode;
}
namespace {
struct GetPixelsDelegate
{
ase_uint32 color;
int div;
const int* matrixData;
void reset(const ConvolutionMatrix* matrix) {
div = matrix->getDiv();
matrixData = &matrix->value(0, 0);
}
};
struct GetPixelsDelegateRgba : public GetPixelsDelegate
{
int r, g, b, a;
void reset(const ConvolutionMatrix* matrix) {
GetPixelsDelegate::reset(matrix);
r = g = b = a = 0;
}
void operator()(RgbTraits::pixel_t color)
{
if (*matrixData) {
if (_rgba_geta(color) == 0)
div -= *matrixData;
else {
r += _rgba_getr(color) * (*matrixData);
g += _rgba_getg(color) * (*matrixData);
b += _rgba_getb(color) * (*matrixData);
a += _rgba_geta(color) * (*matrixData);
}
}
matrixData++;
}
};
struct GetPixelsDelegateGrayscale : public GetPixelsDelegate
{
int v, a;
void reset(const ConvolutionMatrix* matrix) {
GetPixelsDelegate::reset(matrix);
v = a = 0;
}
void operator()(GrayscaleTraits::pixel_t color)
{
if (*matrixData) {
if (_graya_geta(color) == 0)
div -= *matrixData;
else {
v += _graya_getv(color) * (*matrixData);
a += _graya_geta(color) * (*matrixData);
}
}
matrixData++;
}
};
struct GetPixelsDelegateIndexed : public GetPixelsDelegate
{
const Palette* pal;
int r, g, b, index;
GetPixelsDelegateIndexed(const Palette* pal) : pal(pal) { }
void reset(const ConvolutionMatrix* matrix) {
GetPixelsDelegate::reset(matrix);
r = g = b = index = 0;
}
void operator()(GrayscaleTraits::pixel_t color)
{
if (*matrixData) {
r += _rgba_getr(pal->getEntry(color)) * (*matrixData);
g += _rgba_getg(pal->getEntry(color)) * (*matrixData);
b += _rgba_getb(pal->getEntry(color)) * (*matrixData);
index += color * (*matrixData);
}
matrixData++;
}
};
}
const char* ConvolutionMatrixFilter::getName()
{
return "Convolution Matrix";
}
void ConvolutionMatrixFilter::applyToRgba(FilterManager* filterMgr)
{
if (!m_matrix)
return;
const Image* src = filterMgr->getSourceImage();
ase_uint32* dst_address = (ase_uint32*)filterMgr->getDestinationAddress();
Target target = filterMgr->getTarget();
ase_uint32 color;
GetPixelsDelegateRgba delegate;
int x = filterMgr->getX();
int x2 = x+filterMgr->getWidth();
int y = filterMgr->getY();
for (; x<x2; ++x) {
// Avoid the non-selected region
if (filterMgr->skipPixel()) {
++dst_address;
continue;
}
delegate.reset(m_matrix);
get_neighboring_pixels<RgbTraits>(src, x, y,
m_matrix->getWidth(),
m_matrix->getHeight(),
m_matrix->getCenterX(),
m_matrix->getCenterY(),
m_tiledMode, delegate);
color = image_getpixel_fast<RgbTraits>(src, x, y);
if (delegate.div == 0) {
*(dst_address++) = color;
continue;
}
if (target & TARGET_RED_CHANNEL) {
delegate.r = delegate.r / delegate.div + m_matrix->getBias();
delegate.r = MID(0, delegate.r, 255);
}
else
delegate.r = _rgba_getr(color);
if (target & TARGET_GREEN_CHANNEL) {
delegate.g = delegate.g / delegate.div + m_matrix->getBias();
delegate.g = MID(0, delegate.g, 255);
}
else
delegate.g = _rgba_getg(color);
if (target & TARGET_BLUE_CHANNEL) {
delegate.b = delegate.b / delegate.div + m_matrix->getBias();
delegate.b = MID(0, delegate.b, 255);
}
else
delegate.b = _rgba_getb(color);
if (target & TARGET_ALPHA_CHANNEL) {
delegate.a = delegate.a / m_matrix->getDiv() + m_matrix->getBias();
delegate.a = MID(0, delegate.a, 255);
}
else
delegate.a = _rgba_geta(color);
*(dst_address++) = _rgba(delegate.r, delegate.g, delegate.b, delegate.a);
}
}
void ConvolutionMatrixFilter::applyToGrayscale(FilterManager* filterMgr)
{
if (!m_matrix)
return;
const Image* src = filterMgr->getSourceImage();
ase_uint16* dst_address = (ase_uint16*)filterMgr->getDestinationAddress();
Target target = filterMgr->getTarget();
ase_uint16 color;
GetPixelsDelegateGrayscale delegate;
int x = filterMgr->getX();
int x2 = x+filterMgr->getWidth();
int y = filterMgr->getY();
for (; x<x2; ++x) {
// Avoid the non-selected region
if (filterMgr->skipPixel()) {
++dst_address;
continue;
}
delegate.reset(m_matrix);
get_neighboring_pixels<GrayscaleTraits>(src, x, y,
m_matrix->getWidth(),
m_matrix->getHeight(),
m_matrix->getCenterX(),
m_matrix->getCenterY(),
m_tiledMode, delegate);
color = image_getpixel_fast<GrayscaleTraits>(src, x, y);
if (delegate.div == 0) {
*(dst_address++) = color;
continue;
}
if (target & TARGET_GRAY_CHANNEL) {
delegate.v = delegate.v / delegate.div + m_matrix->getBias();
delegate.v = MID(0, delegate.v, 255);
}
else
delegate.v = _graya_getv(color);
if (target & TARGET_ALPHA_CHANNEL) {
delegate.a = delegate.a / m_matrix->getDiv() + m_matrix->getBias();
delegate.a = MID(0, delegate.a, 255);
}
else
delegate.a = _graya_geta(color);
*(dst_address++) = _graya(delegate.v, delegate.a);
}
}
void ConvolutionMatrixFilter::applyToIndexed(FilterManager* filterMgr)
{
if (!m_matrix)
return;
const Image* src = filterMgr->getSourceImage();
ase_uint8* dst_address = (ase_uint8*)filterMgr->getDestinationAddress();
const Palette* pal = filterMgr->getIndexedData()->getPalette();
const RgbMap* rgbmap = filterMgr->getIndexedData()->getRgbMap();
Target target = filterMgr->getTarget();
ase_uint8 color;
GetPixelsDelegateIndexed delegate(pal);
int x = filterMgr->getX();
int x2 = x+filterMgr->getWidth();
int y = filterMgr->getY();
for (; x<x2; ++x) {
// Avoid the non-selected region
if (filterMgr->skipPixel()) {
++dst_address;
continue;
}
delegate.reset(m_matrix);
get_neighboring_pixels<IndexedTraits>(src, x, y,
m_matrix->getWidth(),
m_matrix->getHeight(),
m_matrix->getCenterX(),
m_matrix->getCenterY(),
m_tiledMode, delegate);
color = image_getpixel_fast<IndexedTraits>(src, x, y);
if (delegate.div == 0) {
*(dst_address++) = color;
continue;
}
if (target & TARGET_INDEX_CHANNEL) {
delegate.index = delegate.index / m_matrix->getDiv() + m_matrix->getBias();
delegate.index = MID(0, delegate.index, 255);
*(dst_address++) = delegate.index;
}
else {
if (target & TARGET_RED_CHANNEL) {
delegate.r = delegate.r / delegate.div + m_matrix->getBias();
delegate.r = MID(0, delegate.r, 255);
}
else
delegate.r = _rgba_getr(pal->getEntry(color));
if (target & TARGET_GREEN_CHANNEL) {
delegate.g = delegate.g / delegate.div + m_matrix->getBias();
delegate.g = MID(0, delegate.g, 255);
}
else
delegate.g = _rgba_getg(pal->getEntry(color));
if (target & TARGET_BLUE_CHANNEL) {
delegate.b = delegate.b / delegate.div + m_matrix->getBias();
delegate.b = MID(0, delegate.b, 255);
}
else
delegate.b = _rgba_getb(pal->getEntry(color));
*(dst_address++) = rgbmap->mapColor(delegate.r, delegate.g, delegate.b);
}
}
}

View File

@ -0,0 +1,53 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef FILTERS_CONVOLUTION_MATRIX_FILTER_H_INCLUDED
#define FILTERS_CONVOLUTION_MATRIX_FILTER_H_INCLUDED
#include <vector>
#include "base/shared_ptr.h"
#include "filters/filter.h"
#include "filters/tiled_mode.h"
class ConvolutionMatrix;
class ConvolutionMatrixFilter : public Filter
{
public:
ConvolutionMatrixFilter();
void setMatrix(const SharedPtr<ConvolutionMatrix>& matrix);
void setTiledMode(TiledMode tiledMode);
SharedPtr<ConvolutionMatrix> getMatrix() { return m_matrix; }
TiledMode getTiledMode() const { return m_tiledMode; }
// Filter implementation
const char* getName();
void applyToRgba(FilterManager* filterMgr);
void applyToGrayscale(FilterManager* filterMgr);
void applyToIndexed(FilterManager* filterMgr);
private:
SharedPtr<ConvolutionMatrix> m_matrix;
TiledMode m_tiledMode;
std::vector<ase_uint8*> m_lines;
};
#endif

52
src/filters/filter.h Normal file
View File

@ -0,0 +1,52 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef FILTERS_FILTER_H_INCLUDED
#define FILTERS_FILTER_H_INCLUDED
class FilterManager;
// Interface which applies a filter to a sprite given a FilterManager
// which indicates where we have to apply the filter.
class Filter
{
public:
virtual ~Filter() { }
// Returns a proper name for the filter. It is used to show a label
// with the Undo action.
virtual const char* getName() = 0;
// Applies the filter to one RGBA row. You must use
// FilterManager::getSourceAddress() and advance 32 bits to modify
// each pixel.
virtual void applyToRgba(FilterManager* filterMgr) = 0;
// Applies the filter to one grayscale row. You must use
// FilterManager::getSourceAddress() and advance 16 bits to modify
// each pixel.
virtual void applyToGrayscale(FilterManager* filterMgr) = 0;
// Applies the filter to one indexed row. You must use
// FilterManager::getSourceAddress() and advance 8 bits to modify
// each pixel.
virtual void applyToIndexed(FilterManager* filterMgr) = 0;
};
#endif

View File

@ -1,28 +1,35 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef EFFECT_INVRTCOL_H_INCLUDED
#define EFFECT_INVRTCOL_H_INCLUDED
struct Effect;
void apply_invert_color4 (struct Effect *effect);
void apply_invert_color2 (struct Effect *effect);
void apply_invert_color1 (struct Effect *effect);
#endif
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef FILTERS_FILTER_INDEXED_DATA_H_INCLUDED
#define FILTERS_FILTER_INDEXED_DATA_H_INCLUDED
class Palette;
class RgbMap;
// Provides a Palette and a RgbMap to help a Filter which operate
// over an indexed image.
class FilterIndexedData
{
public:
virtual ~FilterIndexedData() { }
virtual Palette* getPalette() = 0;
virtual RgbMap* getRgbMap() = 0;
};
#endif

View File

@ -0,0 +1,81 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef FILTERS_FILTER_MANAGER_H_INCLUDED
#define FILTERS_FILTER_MANAGER_H_INCLUDED
#include "filters/target.h"
class FilterIndexedData;
class Image;
// Information given to a filter (Filter interface) to apply it to a
// single row. Basically an Filter implementation has to obtain
// colors from getSourceAddress(), applies some kind of transformation
// to that color, and save the result in getDestinationAddress().
// This process must be repeated getWidth() times.
class FilterManager
{
public:
virtual ~FilterManager() { }
// Gets the address of the first pixel which has the original color
// to apply the filter.
virtual const void* getSourceAddress() = 0;
// Gets the address of the first pixel which is destination of the
// filter.
virtual void* getDestinationAddress() = 0;
// Returns the width of the row to apply the filter. You must apply
// the Filter "getWidth()" times, in each pixel from getSourceAddress().
virtual int getWidth() = 0;
// Returns the target of the Filter, i.e. what channels/components
// (e.g. Red, Green, or Blue) will be modified by the filter.
virtual Target getTarget() = 0;
// Returns a interface needed by filters which operate over indexed
// images. FilterIndexedData interface provides a Palette and a
// RgbMap to help the filter to make its job.
virtual FilterIndexedData* getIndexedData() = 0;
// Returns true if you should skip the current pixel (do not apply
// the filter). You must increment all your internal source and
// destination address pointers one pixel without applying the
// filter.
//
// This method is used to skip non-selected pixels (when the
// selection is actived).
virtual bool skipPixel() = 0;
//////////////////////////////////////////////////////////////////////
// Special members for 2D filters like convolution matrices.
// Returns the source image.
virtual const Image* getSourceImage() = 0;
// Returns the first X coordinate of the row to apply the filter.
virtual int getX() = 0;
// Returns the Y coordinate of the row.
virtual int getY() = 0;
};
#endif

View File

@ -0,0 +1,127 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "filters/invert_color_filter.h"
#include "filters/filter_indexed_data.h"
#include "filters/filter_manager.h"
#include "raster/image.h"
#include "raster/palette.h"
#include "raster/rgbmap.h"
const char* InvertColorFilter::getName()
{
return "Invert Color";
}
void InvertColorFilter::applyToRgba(FilterManager* filterMgr)
{
const ase_uint32* src_address = (ase_uint32*)filterMgr->getSourceAddress();
ase_uint32* dst_address = (ase_uint32*)filterMgr->getDestinationAddress();
int w = filterMgr->getWidth();
Target target = filterMgr->getTarget();
int x, c, r, g, b, a;
for (x=0; x<w; x++) {
if (filterMgr->skipPixel()) {
++src_address;
++dst_address;
continue;
}
c = *(src_address++);
r = _rgba_getr(c);
g = _rgba_getg(c);
b = _rgba_getb(c);
a = _rgba_geta(c);
if (target & TARGET_RED_CHANNEL) r ^= 0xff;
if (target & TARGET_GREEN_CHANNEL) g ^= 0xff;
if (target & TARGET_BLUE_CHANNEL) b ^= 0xff;
if (target & TARGET_ALPHA_CHANNEL) a ^= 0xff;
*(dst_address++) = _rgba(r, g, b, a);
}
}
void InvertColorFilter::applyToGrayscale(FilterManager* filterMgr)
{
const ase_uint16* src_address = (ase_uint16*)filterMgr->getSourceAddress();
ase_uint16* dst_address = (ase_uint16*)filterMgr->getDestinationAddress();
int w = filterMgr->getWidth();
Target target = filterMgr->getTarget();
int x, c, k, a;
for (x=0; x<w; x++) {
if (filterMgr->skipPixel()) {
++src_address;
++dst_address;
continue;
}
c = *(src_address++);
k = _graya_getv(c);
a = _graya_geta(c);
if (target & TARGET_GRAY_CHANNEL) k ^= 0xff;
if (target & TARGET_ALPHA_CHANNEL) a ^= 0xff;
*(dst_address++) = _graya(k, a);
}
}
void InvertColorFilter::applyToIndexed(FilterManager* filterMgr)
{
const ase_uint8* src_address = (ase_uint8*)filterMgr->getSourceAddress();
ase_uint8* dst_address = (ase_uint8*)filterMgr->getDestinationAddress();
const Palette* pal = filterMgr->getIndexedData()->getPalette();
const RgbMap* rgbmap = filterMgr->getIndexedData()->getRgbMap();
int w = filterMgr->getWidth();
Target target = filterMgr->getTarget();
int x, c, r, g, b;
for (x=0; x<w; x++) {
if (filterMgr->skipPixel()) {
++src_address;
++dst_address;
continue;
}
c = *(src_address++);
if (target & TARGET_INDEX_CHANNEL)
c ^= 0xff;
else {
r = _rgba_getr(pal->getEntry(c));
g = _rgba_getg(pal->getEntry(c));
b = _rgba_getb(pal->getEntry(c));
if (target & TARGET_RED_CHANNEL ) r ^= 0xff;
if (target & TARGET_GREEN_CHANNEL) g ^= 0xff;
if (target & TARGET_BLUE_CHANNEL ) b ^= 0xff;
c = rgbmap->mapColor(r, g, b);
}
*(dst_address++) = c;
}
}

View File

@ -16,17 +16,19 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef EFFECT_MEDIAN_H_INCLUDED
#define EFFECT_MEDIAN_H_INCLUDED
#ifndef FILTERS_INVERT_COLOR_FILTER_H_INCLUDED
#define FILTERS_INVERT_COLOR_FILTER_H_INCLUDED
#include "tiled_mode.h"
#include "filters/filter.h"
struct Effect;
void set_median_size(TiledMode tiled, int w, int h);
void apply_median4(Effect* effect);
void apply_median2(Effect* effect);
void apply_median1(Effect* effect);
class InvertColorFilter : public Filter
{
public:
// Filter implementation
const char* getName();
void applyToRgba(FilterManager* filterMgr);
void applyToGrayscale(FilterManager* filterMgr);
void applyToIndexed(FilterManager* filterMgr);
};
#endif

View File

@ -0,0 +1,281 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "filters/median_filter.h"
#include "base/memory.h"
#include "filters/filter_indexed_data.h"
#include "filters/filter_manager.h"
#include "filters/neighboring_pixels.h"
#include "filters/tiled_mode.h"
#include "raster/image.h"
#include "raster/palette.h"
#include "raster/rgbmap.h"
#include <algorithm>
MedianFilter::MedianFilter()
: m_tiledMode(TILED_NONE)
, m_width(0)
, m_height(0)
, m_ncolors(0)
, m_channel(4)
{
}
void MedianFilter::setTiledMode(TiledMode tiled)
{
m_tiledMode = tiled;
}
void MedianFilter::setSize(int width, int height)
{
m_width = width;
m_height = height;
m_ncolors = width*height;
for (int c = 0; c < 4; ++c)
m_channel[c].resize(m_ncolors);
}
const char* MedianFilter::getName()
{
return "Median Blur";
}
namespace {
struct GetPixelsDelegateRgba
{
std::vector<std::vector<ase_uint8> >& channel;
int c;
GetPixelsDelegateRgba(std::vector<std::vector<ase_uint8> >& channel) : channel(channel) { }
void reset() { c = 0; }
void operator()(RgbTraits::pixel_t color)
{
channel[0][c] = _rgba_getr(color);
channel[1][c] = _rgba_getg(color);
channel[2][c] = _rgba_getb(color);
channel[3][c] = _rgba_geta(color);
c++;
}
};
struct GetPixelsDelegateGrayscale
{
std::vector<std::vector<ase_uint8> >& channel;
int c;
GetPixelsDelegateGrayscale(std::vector<std::vector<ase_uint8> >& channel) : channel(channel) { }
void reset() { c = 0; }
void operator()(GrayscaleTraits::pixel_t color)
{
channel[0][c] = _graya_getv(color);
channel[1][c] = _graya_geta(color);
c++;
}
};
struct GetPixelsDelegateIndexed
{
const Palette* pal;
std::vector<std::vector<ase_uint8> >& channel;
Target target;
int c;
GetPixelsDelegateIndexed(const Palette* pal, std::vector<std::vector<ase_uint8> >& channel, Target target)
: pal(pal), channel(channel), target(target) { }
void reset() { c = 0; }
void operator()(IndexedTraits::pixel_t color)
{
if (target & TARGET_INDEX_CHANNEL) {
channel[0][c] = color;
}
else {
channel[0][c] = _rgba_getr(pal->getEntry(color));
channel[1][c] = _rgba_getg(pal->getEntry(color));
channel[2][c] = _rgba_getb(pal->getEntry(color));
}
c++;
}
};
};
void MedianFilter::applyToRgba(FilterManager* filterMgr)
{
const Image* src = filterMgr->getSourceImage();
ase_uint32* dst_address = (ase_uint32*)filterMgr->getDestinationAddress();
Target target = filterMgr->getTarget();
int color;
int r, g, b, a;
GetPixelsDelegateRgba delegate(m_channel);
int x = filterMgr->getX();
int x2 = x+filterMgr->getWidth();
int y = filterMgr->getY();
for (; x<x2; ++x) {
// Avoid the non-selected region
if (filterMgr->skipPixel()) {
++dst_address;
continue;
}
delegate.reset();
get_neighboring_pixels<RgbTraits>(src, x, y, m_width, m_height, m_width/2, m_height/2,
m_tiledMode, delegate);
color = image_getpixel_fast<RgbTraits>(src, x, y);
if (target & TARGET_RED_CHANNEL) {
std::sort(m_channel[0].begin(), m_channel[0].end());
r = m_channel[0][m_ncolors/2];
}
else
r = _rgba_getr(color);
if (target & TARGET_GREEN_CHANNEL) {
std::sort(m_channel[1].begin(), m_channel[1].end());
g = m_channel[1][m_ncolors/2];
}
else
g = _rgba_getg(color);
if (target & TARGET_BLUE_CHANNEL) {
std::sort(m_channel[2].begin(), m_channel[2].end());
b = m_channel[2][m_ncolors/2];
}
else
b = _rgba_getb(color);
if (target & TARGET_ALPHA_CHANNEL) {
std::sort(m_channel[3].begin(), m_channel[3].end());
a = m_channel[3][m_ncolors/2];
}
else
a = _rgba_geta(color);
*(dst_address++) = _rgba(r, g, b, a);
}
}
void MedianFilter::applyToGrayscale(FilterManager* filterMgr)
{
const Image* src = filterMgr->getSourceImage();
ase_uint16* dst_address = (ase_uint16*)filterMgr->getDestinationAddress();
Target target = filterMgr->getTarget();
int color, k, a;
GetPixelsDelegateGrayscale delegate(m_channel);
int x = filterMgr->getX();
int x2 = x+filterMgr->getWidth();
int y = filterMgr->getY();
for (; x<x2; ++x) {
// Avoid the non-selected region
if (filterMgr->skipPixel()) {
++dst_address;
continue;
}
delegate.reset();
get_neighboring_pixels<GrayscaleTraits>(src, x, y, m_width, m_height, m_width/2, m_height/2,
m_tiledMode, delegate);
color = image_getpixel_fast<GrayscaleTraits>(src, x, y);
if (target & TARGET_GRAY_CHANNEL) {
std::sort(m_channel[0].begin(), m_channel[0].end());
k = m_channel[0][m_ncolors/2];
}
else
k = _graya_getv(color);
if (target & TARGET_ALPHA_CHANNEL) {
std::sort(m_channel[1].begin(), m_channel[1].end());
a = m_channel[1][m_ncolors/2];
}
else
a = _graya_geta(color);
*(dst_address++) = _graya(k, a);
}
}
void MedianFilter::applyToIndexed(FilterManager* filterMgr)
{
const Image* src = filterMgr->getSourceImage();
ase_uint8* dst_address = (ase_uint8*)filterMgr->getDestinationAddress();
const Palette* pal = filterMgr->getIndexedData()->getPalette();
const RgbMap* rgbmap = filterMgr->getIndexedData()->getRgbMap();
Target target = filterMgr->getTarget();
int color, r, g, b;
GetPixelsDelegateIndexed delegate(pal, m_channel, target);
int x = filterMgr->getX();
int x2 = x+filterMgr->getWidth();
int y = filterMgr->getY();
for (; x<x2; ++x) {
// Avoid the non-selected region
if (filterMgr->skipPixel()) {
++dst_address;
continue;
}
delegate.reset();
get_neighboring_pixels<IndexedTraits>(src, x, y, m_width, m_height, m_width/2, m_height/2,
m_tiledMode, delegate);
if (target & TARGET_INDEX_CHANNEL) {
std::sort(m_channel[0].begin(), m_channel[0].end());
*(dst_address++) = m_channel[0][m_ncolors/2];
}
else {
color = image_getpixel_fast<IndexedTraits>(src, x, y);
if (target & TARGET_RED_CHANNEL) {
std::sort(m_channel[0].begin(), m_channel[0].end());
r = m_channel[0][m_ncolors/2];
}
else
r = _rgba_getr(pal->getEntry(color));
if (target & TARGET_GREEN_CHANNEL) {
std::sort(m_channel[1].begin(), m_channel[1].end());
g = m_channel[1][m_ncolors/2];
}
else
g = _rgba_getg(pal->getEntry(color));
if (target & TARGET_BLUE_CHANNEL) {
std::sort(m_channel[2].begin(), m_channel[2].end());
b = m_channel[2][m_ncolors/2];
}
else
b = _rgba_getb(pal->getEntry(color));
*(dst_address++) = rgbmap->mapColor(r, g, b);
}
}
}

View File

@ -0,0 +1,53 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef FILTERS_MEDIAN_FILTER_PROCESS_H_INCLUDED
#define FILTERS_MEDIAN_FILTER_PROCESS_H_INCLUDED
#include <vector>
#include "filters/filter.h"
#include "filters/tiled_mode.h"
class MedianFilter : public Filter
{
public:
MedianFilter();
void setTiledMode(TiledMode tiled);
void setSize(int width, int height);
TiledMode getTiledMode() const { return m_tiledMode; }
int getWidth() const { return m_width; }
int getHeight() const { return m_height; }
// Filter implementation
const char* getName();
void applyToRgba(FilterManager* filterMgr);
void applyToGrayscale(FilterManager* filterMgr);
void applyToIndexed(FilterManager* filterMgr);
private:
TiledMode m_tiledMode;
int m_width;
int m_height;
int m_ncolors;
std::vector<std::vector<ase_uint8> > m_channel;
};
#endif

View File

@ -0,0 +1,110 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef FILTERS_NEIGHBORING_PIXELS_H_INCLUDED
#define FILTERS_NEIGHBORING_PIXELS_H_INCLUDED
#include "filters/tiled_mode.h"
#include "raster/image.h"
#include "raster/image_traits.h"
#include <vector>
// Calls the specified "delegate" for all neighboring pixels in a 2D
// (width*height) matrix located in (x,y) where its center is the
// (centerX,centerY) element of the matrix.
template<typename Traits, typename Delegate>
inline void get_neighboring_pixels(const Image* sourceImage, int x, int y,
int width, int height,
int centerX, int centerY,
TiledMode tiledMode,
typename Delegate& delegate)
{
int dx, dy;
// Y position to get pixel.
int getx, gety = y - centerY;
int addx, addy = 0;
if (gety < 0) {
if (tiledMode & TILED_Y_AXIS)
gety = sourceImage->h - (-(gety+1) % sourceImage->h) - 1;
else {
addy = -gety;
gety = 0;
}
}
else if (gety >= sourceImage->h) {
if (tiledMode & TILED_Y_AXIS)
gety = gety % sourceImage->h;
else
gety = sourceImage->h-1;
}
for (dy=0; dy<height; ++dy) {
// X position to get pixel.
getx = x - centerX;
addx = 0;
if (getx < 0) {
if (tiledMode & TILED_X_AXIS)
getx = sourceImage->w - (-(getx+1) % sourceImage->w) - 1;
else {
addx = -getx;
getx = 0;
}
}
else if (getx >= sourceImage->w) {
if (tiledMode & TILED_X_AXIS)
getx = getx % sourceImage->w;
else
getx = sourceImage->w-1;
}
typename Traits::const_address_t srcAddress =
image_address_fast<Traits>(sourceImage, getx, gety);
for (dx=0; dx<width; dx++) {
// Call the delegate for each pixel value.
delegate(*srcAddress);
// Update X position to get pixel.
if (getx < sourceImage->w-1) {
++getx;
if (addx == 0)
++srcAddress;
else
--addx;
}
else if (tiledMode & TILED_X_AXIS) {
getx = 0;
srcAddress = image_address_fast<Traits>(sourceImage, getx, gety);
}
}
// Update Y position to get pixel
if (gety < sourceImage->h-1) {
if (addy == 0)
++gety;
else
--addy;
}
else if (tiledMode & TILED_Y_AXIS)
gety = 0;
}
}
#endif

View File

@ -0,0 +1,142 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "filters/replace_color_filter.h"
#include "filters/filter_manager.h"
#include "raster/image.h"
ReplaceColorFilter::ReplaceColorFilter()
{
m_from = m_to = m_tolerance = 0;
}
void ReplaceColorFilter::setFrom(int from)
{
m_from = from;
}
void ReplaceColorFilter::setTo(int to)
{
m_to = to;
}
void ReplaceColorFilter::setTolerance(int tolerance)
{
m_tolerance = MID(0, tolerance, 255);
}
const char* ReplaceColorFilter::getName()
{
return "Replace Color";
}
void ReplaceColorFilter::applyToRgba(FilterManager* filterMgr)
{
const ase_uint32* src_address = (ase_uint32*)filterMgr->getSourceAddress();
ase_uint32* dst_address = (ase_uint32*)filterMgr->getDestinationAddress();
int w = filterMgr->getWidth();
int src_r, src_g, src_b, src_a;
int dst_r, dst_g, dst_b, dst_a;
int x, c;
dst_r = _rgba_getr(m_from);
dst_g = _rgba_getg(m_from);
dst_b = _rgba_getb(m_from);
dst_a = _rgba_geta(m_from);
for (x=0; x<w; x++) {
if (filterMgr->skipPixel()) {
++src_address;
++dst_address;
continue;
}
c = *(src_address++);
src_r = _rgba_getr(c);
src_g = _rgba_getg(c);
src_b = _rgba_getb(c);
src_a = _rgba_geta(c);
if ((ABS(src_r-dst_r) <= m_tolerance) &&
(ABS(src_g-dst_g) <= m_tolerance) &&
(ABS(src_b-dst_b) <= m_tolerance) &&
(ABS(src_a-dst_a) <= m_tolerance))
*(dst_address++) = m_to;
else
*(dst_address++) = c;
}
}
void ReplaceColorFilter::applyToGrayscale(FilterManager* filterMgr)
{
const ase_uint16* src_address = (ase_uint16*)filterMgr->getSourceAddress();
ase_uint16* dst_address = (ase_uint16*)filterMgr->getDestinationAddress();
int w = filterMgr->getWidth();
int src_k, src_a;
int dst_k, dst_a;
int x, c;
dst_k = _graya_getv(m_from);
dst_a = _graya_geta(m_from);
for (x=0; x<w; x++) {
if (filterMgr->skipPixel()) {
++src_address;
++dst_address;
continue;
}
c = *(src_address++);
src_k = _graya_getv(c);
src_a = _graya_geta(c);
if ((ABS(src_k-dst_k) <= m_tolerance) &&
(ABS(src_a-dst_a) <= m_tolerance))
*(dst_address++) = m_to;
else
*(dst_address++) = c;
}
}
void ReplaceColorFilter::applyToIndexed(FilterManager* filterMgr)
{
const ase_uint8* src_address = (ase_uint8*)filterMgr->getSourceAddress();
ase_uint8* dst_address = (ase_uint8*)filterMgr->getDestinationAddress();
int w = filterMgr->getWidth();
int x, c;
for (x=0; x<w; x++) {
if (filterMgr->skipPixel()) {
++src_address;
++dst_address;
continue;
}
c = *(src_address++);
if (ABS(c-m_from) <= m_tolerance)
*(dst_address++) = m_to;
else
*(dst_address++) = c;
}
}

View File

@ -0,0 +1,49 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef FILTERS_REPLACE_COLOR_FILTER_H_INCLUDED
#define FILTERS_REPLACE_COLOR_FILTER_H_INCLUDED
#include "filters/filter.h"
class ReplaceColorFilter : public Filter
{
public:
ReplaceColorFilter();
void setFrom(int from);
void setTo(int to);
void setTolerance(int tolerance);
int getFrom() const { return m_from; }
int getTo() const { return m_to; }
int getTolerance() const { return m_tolerance; }
// Filter implementation
const char* getName();
void applyToRgba(FilterManager* filterMgr);
void applyToGrayscale(FilterManager* filterMgr);
void applyToIndexed(FilterManager* filterMgr);
private:
int m_from;
int m_to;
int m_tolerance;
};
#endif

View File

@ -1,32 +1,40 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef WIDGETS_TARGET_H_INCLUDED
#define WIDGETS_TARGET_H_INCLUDED
#include "gui/base.h"
/* TODO use some JI_SIGNAL_USER */
#define SIGNAL_TARGET_BUTTON_CHANGE 0x10003
JWidget target_button_new(int imgtype, bool with_channels);
int target_button_get_target(JWidget widget);
void target_button_set_target(JWidget widget, int target);
#endif
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef FILTERS_TARGET_H_INCLUDED
#define FILTERS_TARGET_H_INCLUDED
#define TARGET_RED_CHANNEL 1
#define TARGET_GREEN_CHANNEL 2
#define TARGET_BLUE_CHANNEL 4
#define TARGET_ALPHA_CHANNEL 8
#define TARGET_GRAY_CHANNEL 16
#define TARGET_INDEX_CHANNEL 32
#define TARGET_ALL_FRAMES 64
#define TARGET_ALL_LAYERS 128
#define TARGET_ALL_CHANNELS \
(TARGET_RED_CHANNEL | \
TARGET_GREEN_CHANNEL | \
TARGET_BLUE_CHANNEL | \
TARGET_ALPHA_CHANNEL | \
TARGET_GRAY_CHANNEL )
typedef int Target;
#endif

View File

@ -16,8 +16,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef TILED_MODE_H_INCLUDED
#define TILED_MODE_H_INCLUDED
#ifndef FILTERS_TILED_MODE_H_INCLUDED
#define FILTERS_TILED_MODE_H_INCLUDED
enum TiledMode {
TILED_NONE = 0,

View File

@ -19,9 +19,9 @@
#ifndef SETTINGS_SETTINGS_H_INCLUDED
#define SETTINGS_SETTINGS_H_INCLUDED
#include "gfx/rect.h"
#include "app/color.h"
#include "tiled_mode.h"
#include "filters/tiled_mode.h"
#include "gfx/rect.h"
#include "raster/pen_type.h"
class IToolSettings;

View File

@ -16,7 +16,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "effect/effect.h"
#include "filters/neighboring_pixels.h"
#include "modules/palettes.h"
#include "raster/palette.h"
#include "raster/rgbmap.h"
@ -158,49 +158,89 @@ static void ink_hline8_transparent(int x1, int y, int x2, IToolLoop* loop)
// Blur Ink
//////////////////////////////////////////////////////////////////////
namespace {
struct BlurGetPixelsDelegateRgba
{
int count, r, g, b, a;
void reset() { count = r = g = b = a = 0; }
void operator()(RgbTraits::pixel_t color)
{
if (_rgba_geta(color) != 0) {
r += _rgba_getr(color);
g += _rgba_getg(color);
b += _rgba_getb(color);
a += _rgba_geta(color);
++count;
}
}
};
struct BlurGetPixelsDelegateGrayscale
{
int count, v, a;
void reset() { count = v = a = 0; }
void operator()(GrayscaleTraits::pixel_t color)
{
if (_graya_geta(color) > 0) {
v += _graya_getv(color);
a += _graya_geta(color);
++count;
}
}
};
struct BlurGetPixelsDelegateIndexed
{
const Palette* pal;
int count, r, g, b, a;
BlurGetPixelsDelegateIndexed(const Palette* pal) : pal(pal) { }
void reset() { count = r = g = b = a = 0; }
void operator()(IndexedTraits::pixel_t color)
{
a += (color == 0 ? 0: 255);
color = pal->getEntry(color);
r += _rgba_getr(color);
g += _rgba_getg(color);
b += _rgba_getb(color);
count++;
}
};
};
static void ink_hline32_blur(int x1, int y, int x2, IToolLoop* loop)
{
int c, r, g, b, a;
int opacity = loop->getOpacity();
TiledMode tiled = loop->getTiledMode();
Image* src = loop->getSrcImage();
int getx, gety;
int addx, addy;
int dx, dy, color;
ase_uint32 *src_address2;
TiledMode tiledMode = loop->getTiledMode();
const Image* src = loop->getSrcImage();
BlurGetPixelsDelegateRgba delegate;
DEFINE_INK_PROCESSING_SRCDST
(RgbTraits,
{
c = 0;
r = g = b = a = 0;
delegate.reset();
get_neighboring_pixels<RgbTraits>(src, x, y, 3, 3, 1, 1, tiledMode, delegate);
GET_MATRIX_DATA
(ase_uint32, src, src_address2,
3, 3, 1, 1, tiled,
color = *src_address2;
if (_rgba_geta(color) != 0) {
r += _rgba_getr(color);
g += _rgba_getg(color);
b += _rgba_getb(color);
a += _rgba_geta(color);
++c;
}
);
if (delegate.count > 0) {
delegate.r /= delegate.count;
delegate.g /= delegate.count;
delegate.b /= delegate.count;
delegate.a /= 9;
if (c > 0) {
r /= c;
g /= c;
b /= c;
a /= 9;
c = *src_address;
r = _rgba_getr(c) + (r-_rgba_getr(c)) * opacity / 255;
g = _rgba_getg(c) + (g-_rgba_getg(c)) * opacity / 255;
b = _rgba_getb(c) + (b-_rgba_getb(c)) * opacity / 255;
a = _rgba_geta(c) + (a-_rgba_geta(c)) * opacity / 255;
RgbTraits::pixel_t c = *src_address;
delegate.r = _rgba_getr(c) + (delegate.r-_rgba_getr(c)) * opacity / 255;
delegate.g = _rgba_getg(c) + (delegate.g-_rgba_getg(c)) * opacity / 255;
delegate.b = _rgba_getb(c) + (delegate.b-_rgba_getb(c)) * opacity / 255;
delegate.a = _rgba_geta(c) + (delegate.a-_rgba_geta(c)) * opacity / 255;
*dst_address = _rgba(r, g, b, a);
*dst_address = _rgba(delegate.r, delegate.g, delegate.b, delegate.a);
}
else {
*dst_address = *src_address;
@ -210,41 +250,26 @@ static void ink_hline32_blur(int x1, int y, int x2, IToolLoop* loop)
static void ink_hline16_blur(int x1, int y, int x2, IToolLoop* loop)
{
int c, v, a;
int opacity = loop->getOpacity();
TiledMode tiled = loop->getTiledMode();
Image* src = loop->getSrcImage();
int getx, gety;
int addx, addy;
int dx, dy, color;
ase_uint16 *src_address2;
TiledMode tiledMode = loop->getTiledMode();
const Image* src = loop->getSrcImage();
BlurGetPixelsDelegateGrayscale delegate;
DEFINE_INK_PROCESSING_SRCDST
(GrayscaleTraits,
{
c = 0;
v = a = 0;
delegate.reset();
get_neighboring_pixels<GrayscaleTraits>(src, x, y, 3, 3, 1, 1, tiledMode, delegate);
GET_MATRIX_DATA
(ase_uint16, src, src_address2,
3, 3, 1, 1, tiled,
color = *src_address2;
if (_graya_geta(color) > 0) {
v += _graya_getv(color);
a += _graya_geta(color);
}
c++;
);
if (delegate.count > 0) {
delegate.v /= delegate.count;
delegate.a /= 9;
if (c > 0) {
v /= c;
a /= 9;
GrayscaleTraits::pixel_t c = *src_address;
delegate.v = _graya_getv(c) + (delegate.v-_graya_getv(c)) * opacity / 255;
delegate.a = _graya_geta(c) + (delegate.a-_graya_geta(c)) * opacity / 255;
c = *src_address;
v = _graya_getv(c) + (v-_graya_getv(c)) * opacity / 255;
a = _graya_geta(c) + (a-_graya_geta(c)) * opacity / 255;
*dst_address = _graya(v, a);
*dst_address = _graya(delegate.v, delegate.a);
}
else {
*dst_address = *src_address;
@ -254,48 +279,30 @@ static void ink_hline16_blur(int x1, int y, int x2, IToolLoop* loop)
static void ink_hline8_blur(int x1, int y, int x2, IToolLoop* loop)
{
Palette *pal = get_current_palette();
const Palette *pal = get_current_palette();
RgbMap* rgbmap = loop->getSprite()->getRgbMap();
int c, r, g, b, a;
int opacity = loop->getOpacity();
TiledMode tiled = loop->getTiledMode();
Image* src = loop->getSrcImage();
int getx, gety;
int addx, addy;
int dx, dy, color;
ase_uint8 *src_address2;
TiledMode tiledMode = loop->getTiledMode();
const Image* src = loop->getSrcImage();
BlurGetPixelsDelegateIndexed delegate(pal);
DEFINE_INK_PROCESSING_SRCDST
(IndexedTraits,
{
c = 0;
r = g = b = a = 0;
delegate.reset();
get_neighboring_pixels<IndexedTraits>(src, x, y, 3, 3, 1, 1, tiledMode, delegate);
GET_MATRIX_DATA
(ase_uint8, src, src_address2,
3, 3, 1, 1, tiled,
if (delegate.count > 0 && delegate.a/9 >= 128) {
delegate.r /= delegate.count;
delegate.g /= delegate.count;
delegate.b /= delegate.count;
color = *src_address2;
a += (color == 0 ? 0: 255);
IndexedTraits::pixel_t c = *src_address;
delegate.r = _rgba_getr(c) + (delegate.r-_rgba_getr(c)) * opacity / 255;
delegate.g = _rgba_getg(c) + (delegate.g-_rgba_getg(c)) * opacity / 255;
delegate.b = _rgba_getb(c) + (delegate.b-_rgba_getb(c)) * opacity / 255;
color = pal->getEntry(color);
r += _rgba_getr(color);
g += _rgba_getg(color);
b += _rgba_getb(color);
c++;
);
if (c > 0 && a/9 >= 128) {
r /= c;
g /= c;
b /= c;
c = pal->getEntry(*src_address);
r = _rgba_getr(c) + (r-_rgba_getr(c)) * opacity / 255;
g = _rgba_getg(c) + (g-_rgba_getg(c)) * opacity / 255;
b = _rgba_getb(c) + (b-_rgba_getb(c)) * opacity / 255;
*dst_address = rgbmap->mapColor(r, g, b);
*dst_address = rgbmap->mapColor(delegate.r, delegate.g, delegate.b);
}
else {
*dst_address = *src_address;
@ -336,7 +343,7 @@ static void ink_hline16_replace(int x1, int y, int x2, IToolLoop* loop)
static void ink_hline8_replace(int x1, int y, int x2, IToolLoop* loop)
{
int color1 = loop->getPrimaryColor();
Palette *pal = get_current_palette();
const Palette *pal = get_current_palette();
RgbMap* rgbmap = loop->getSprite()->getRgbMap();
ase_uint32 c;
ase_uint32 tc = pal->getEntry(loop->getSecondaryColor());

View File

@ -21,6 +21,7 @@
#include "raster/undo.h"
#include "tools/ink_processing.h"
#include "context.h"
// Ink used for tools which paint with primary/secondary
@ -51,8 +52,8 @@ public:
case WithBg:
{
int color = color_utils::color_for_layer(m_type == WithFg ?
loop->getContext()->getSettings()->getFgColor():
loop->getContext()->getSettings()->getBgColor(),
loop->getContext()->getSettings()->getFgColor():
loop->getContext()->getSettings()->getBgColor(),
loop->getLayer());
loop->setPrimaryColor(color);
loop->setSecondaryColor(color);

View File

@ -19,17 +19,16 @@
#ifndef TOOLS_TOOL_H_INCLUDED
#define TOOLS_TOOL_H_INCLUDED
#include <string>
#include <list>
#include <string>
#include <vector>
#include "filters/tiled_mode.h"
#include "gfx/point.h"
#include "gfx/rect.h"
#include "gui/message.h"
#include "gui/rect.h"
#include "tiled_mode.h"
class Context;
class Sprite;
class Image;

View File

@ -1,482 +0,0 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <allegro.h>
#include <cmath>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include "effect/colcurve.h"
#include "gui/alert.h"
#include "gui/entry.h"
#include "gui/frame.h"
#include "gui/list.h"
#include "gui/manager.h"
#include "gui/message.h"
#include "gui/rect.h"
#include "gui/system.h"
#include "gui/view.h"
#include "gui/widget.h"
#include "modules/gui.h"
#include "widgets/curvedit.h"
#define SCR2EDIT_X(xpos) \
(curve_editor->x1 + \
((curve_editor->x2 - curve_editor->x1 + 1) \
* ((xpos) - widget->rc->x1 - widget->border_width.l) \
/ (jrect_w(widget->rc) - widget->border_width.l - widget->border_width.r)))
#define SCR2EDIT_Y(ypos) \
(curve_editor->y1 + \
((curve_editor->y2 - curve_editor->y1 + 1) \
* ((jrect_h(widget->rc) - widget->border_width.t - widget->border_width.b) \
- ((ypos) - widget->rc->y1 - widget->border_width.t)) \
/ (jrect_h(widget->rc) - widget->border_width.t - widget->border_width.b)))
#define EDIT2SCR_X(xpos) \
(widget->rc->x1 + widget->border_width.l \
+ ((jrect_w(widget->rc) - widget->border_width.l - widget->border_width.r) \
* ((xpos) - curve_editor->x1) \
/ (curve_editor->x2 - curve_editor->x1 + 1)))
#define EDIT2SCR_Y(ypos) \
(widget->rc->y1 \
+ (jrect_h(widget->rc) - widget->border_width.t - widget->border_width.b) \
- ((jrect_h(widget->rc) - widget->border_width.t - widget->border_width.b) \
* ((ypos) - curve_editor->y1) \
/ (curve_editor->y2 - curve_editor->y1 + 1)))
enum {
STATUS_STANDBY,
STATUS_MOVING_POINT,
STATUS_SCROLLING,
STATUS_SCALING,
};
struct CurveEditor
{
Curve *curve;
int x1, y1;
int x2, y2;
int status;
CurvePoint* edit_point;
int *edit_x;
int *edit_y;
};
static CurveEditor* curve_editor_data(JWidget widget);
static bool curve_editor_msg_proc(JWidget widget, JMessage msg);
static CurvePoint* curve_editor_get_more_close_point(JWidget widget, int x, int y, int **edit_x, int **edit_y);
static int edit_node_manual(CurvePoint* point);
JWidget curve_editor_new(Curve *curve, int x1, int y1, int x2, int y2)
{
JWidget widget = new Widget(curve_editor_type());
CurveEditor* curve_editor = new CurveEditor;
jwidget_add_hook(widget, curve_editor_type(),
curve_editor_msg_proc, curve_editor);
jwidget_focusrest(widget, true);
widget->border_width.l = widget->border_width.r = 1;
widget->border_width.t = widget->border_width.b = 1;
widget->child_spacing = 0;
curve_editor->curve = curve;
curve_editor->x1 = x1;
curve_editor->y1 = y1;
curve_editor->x2 = x2;
curve_editor->y2 = y2;
curve_editor->status = STATUS_STANDBY;
curve_editor->edit_point = NULL;
/* TODO */
/* curve_editor->curve->type = CURVE_SPLINE; */
return widget;
}
int curve_editor_type()
{
static int type = 0;
if (!type)
type = ji_register_widget_type();
return type;
}
Curve *curve_editor_get_curve(JWidget widget)
{
CurveEditor* curve_editor = curve_editor_data(widget);
return curve_editor->curve;
}
static CurveEditor* curve_editor_data(JWidget widget)
{
return reinterpret_cast<CurveEditor*>
(jwidget_get_data(widget, curve_editor_type()));
}
static bool curve_editor_msg_proc(JWidget widget, JMessage msg)
{
CurveEditor* curve_editor = curve_editor_data(widget);
switch (msg->type) {
case JM_DESTROY:
delete curve_editor;
break;
case JM_REQSIZE: {
#if 0
msg->reqsize.w =
+ widget->border_width.l
+ ((curve_editor->x2 - curve_editor->x1 + 1))
+ widget->border_width.r;
msg->reqsize.h =
+ widget->border_width.t
+ ((curve_editor->y2 - curve_editor->y1 + 1))
+ widget->border_width.b;
#else
msg->reqsize.w = widget->border_width.l + 1 + widget->border_width.r;
msg->reqsize.h = widget->border_width.t + 1 + widget->border_width.b;
#endif
return true;
}
case JM_KEYPRESSED: {
switch (msg->key.scancode) {
case KEY_INSERT: {
int x = SCR2EDIT_X(jmouse_x(0));
int y = SCR2EDIT_Y(jmouse_y(0));
CurvePoint* point = curve_point_new(x, y);
/* TODO undo? */
curve_add_point(curve_editor->curve, point);
widget->invalidate();
jwidget_emit_signal(widget, SIGNAL_CURVE_EDITOR_CHANGE);
break;
}
case KEY_DEL: {
CurvePoint* point = curve_editor_get_more_close_point
(widget,
SCR2EDIT_X(jmouse_x(0)),
SCR2EDIT_Y(jmouse_y(0)),
NULL, NULL);
/* TODO undo? */
curve_remove_point(curve_editor->curve, point);
widget->invalidate();
jwidget_emit_signal(widget, SIGNAL_CURVE_EDITOR_CHANGE);
break;
}
default:
return false;
}
return true;
}
case JM_DRAW: {
BITMAP *bmp;
JLink link;
CurvePoint* point;
int x, y, u;
bmp = create_bitmap(jrect_w(widget->rc), jrect_h(widget->rc));
clear_to_color(bmp, makecol (0, 0, 0));
/* draw border */
rect(bmp, 0, 0, bmp->w-1, bmp->h-1, makecol (255, 255, 0));
/* draw guides */
for (x=1; x<=3; x++)
vline(bmp, x*bmp->w/4, 1, bmp->h-2, makecol (128, 128, 0));
for (y=1; y<=3; y++)
hline(bmp, 1, y*bmp->h/4, bmp->w-2, makecol (128, 128, 0));
/* get curve values */
std::vector<int> values(curve_editor->x2-curve_editor->x1+1);
curve_get_values(curve_editor->curve,
curve_editor->x1,
curve_editor->x2, &values[0]);
/* draw curve */
for (x=widget->border_width.l;
x<jrect_w(widget->rc)-widget->border_width.r; x++) {
u = SCR2EDIT_X(widget->rc->x1+x);
u = MID(curve_editor->x1, u, curve_editor->x2);
y = values[u - curve_editor->x1];
y = MID(curve_editor->y1, y, curve_editor->y2);
putpixel(bmp, x, EDIT2SCR_Y(y)-widget->rc->y1,
makecol(255, 255, 255));
}
/* draw nodes */
JI_LIST_FOR_EACH(curve_editor->curve->points, link) {
point = reinterpret_cast<CurvePoint*>(link->data);
x = EDIT2SCR_X(point->x) - widget->rc->x1;
y = EDIT2SCR_Y(point->y) - widget->rc->y1;
rect(bmp, x-2, y-2, x+2, y+2,
curve_editor->edit_point == point ?
makecol(255, 255, 0): makecol(0, 0, 255));
}
/* blit to screen */
blit(bmp, ji_screen,
0, 0, widget->rc->x1, widget->rc->y1, bmp->w, bmp->h);
destroy_bitmap(bmp);
return true;
}
case JM_BUTTONPRESSED:
/* change scroll */
if (msg->any.shifts & KB_SHIFT_FLAG) {
curve_editor->status = STATUS_SCROLLING;
jmouse_set_cursor(JI_CURSOR_SCROLL);
}
/* scaling */
/* else if (msg->shifts & KB_CTRL_FLAG) { */
/* curve_editor->status = STATUS_SCALING; */
/* jmouse_set_cursor(JI_CURSOR_SCROLL); */
/* } */
/* show manual-entry dialog */
else if (msg->mouse.right) {
curve_editor->edit_point =
curve_editor_get_more_close_point(widget,
SCR2EDIT_X(msg->mouse.x),
SCR2EDIT_Y(msg->mouse.y),
NULL, NULL);
if (curve_editor->edit_point) {
widget->invalidate();
jwidget_flush_redraw(widget);
if (edit_node_manual(curve_editor->edit_point))
jwidget_emit_signal(widget, SIGNAL_CURVE_EDITOR_CHANGE);
curve_editor->edit_point = NULL;
widget->invalidate();
}
return true;
}
/* edit node */
else {
curve_editor->edit_point =
curve_editor_get_more_close_point(widget,
SCR2EDIT_X(msg->mouse.x),
SCR2EDIT_Y(msg->mouse.y),
&curve_editor->edit_x,
&curve_editor->edit_y);
curve_editor->status = STATUS_MOVING_POINT;
jmouse_set_cursor(JI_CURSOR_HAND);
}
widget->captureMouse();
/* continue in motion message... */
case JM_MOTION:
if (widget->hasCapture()) {
switch (curve_editor->status) {
case STATUS_SCROLLING: {
View* view = View::getView(widget);
gfx::Rect vp = view->getViewportBounds();
gfx::Point scroll = view->getViewScroll();
scroll.x += jmouse_x(1)-jmouse_x(0);
scroll.y += jmouse_y(1)-jmouse_y(0);
view->setViewScroll(scroll);
jmouse_control_infinite_scroll(vp);
break;
}
case STATUS_MOVING_POINT:
if (curve_editor->edit_point) {
/* int old_x = *curve_editor->edit_x; */
/* int old_y = *curve_editor->edit_y; */
/* int offset_x, offset_y; */
*curve_editor->edit_x = SCR2EDIT_X(msg->mouse.x);
*curve_editor->edit_y = SCR2EDIT_Y(msg->mouse.y);
*curve_editor->edit_x = MID(curve_editor->x1,
*curve_editor->edit_x,
curve_editor->x2);
*curve_editor->edit_y = MID(curve_editor->y1,
*curve_editor->edit_y,
curve_editor->y2);
/* if (curve_editor->edit_x == &curve_editor->edit_key->x && */
/* curve_editor->edit_y == &curve_editor->edit_key->y) { */
/* offset_x = (*curve_editor->edit_x) - old_x; */
/* offset_y = (*curve_editor->edit_y) - old_y; */
/* curve_editor->edit_key->px += offset_x; */
/* curve_editor->edit_key->py += offset_y; */
/* curve_editor->edit_key->nx += offset_x; */
/* curve_editor->edit_key->ny += offset_y; */
/* } */
/* TODO this should be optional */
jwidget_emit_signal(widget, SIGNAL_CURVE_EDITOR_CHANGE);
widget->invalidate();
}
break;
}
return true;
}
#if 0 /* TODO */
/* if the mouse move above a curve_editor, the focus change to
this widget immediately */
else if (!jwidget_has_focus(widget)) {
jmanager_set_focus(widget);
}
#endif
break;
case JM_BUTTONRELEASED:
if (widget->hasCapture()) {
widget->releaseMouse();
switch (curve_editor->status) {
case STATUS_SCROLLING:
jmouse_set_cursor(JI_CURSOR_NORMAL);
break;
/* case STATUS_SCALING: */
/* jmouse_set_cursor(JI_CURSOR_NORMAL); */
/* break; */
case STATUS_MOVING_POINT:
jmouse_set_cursor(JI_CURSOR_NORMAL);
jwidget_emit_signal(widget, SIGNAL_CURVE_EDITOR_CHANGE);
curve_editor->edit_point = NULL;
widget->invalidate();
break;
}
curve_editor->status = STATUS_STANDBY;
return true;
}
break;
}
return false;
}
static CurvePoint* curve_editor_get_more_close_point(JWidget widget,
int x, int y,
int **edit_x,
int **edit_y)
{
#define CALCDIST(xx, yy) \
dx = point->xx-x; \
dy = point->yy-y; \
dist = std::sqrt(static_cast<double>(dx*dx + dy*dy)); \
\
if (!point_found || dist <= dist_min) { \
point_found = point; \
dist_min = dist; \
\
if (edit_x) *edit_x = &point->xx; \
if (edit_y) *edit_y = &point->yy; \
}
CurveEditor* curve_editor = curve_editor_data(widget);
CurvePoint* point;
CurvePoint* point_found = NULL;
JLink link;
int dx, dy;
double dist, dist_min = 0;
JI_LIST_FOR_EACH(curve_editor->curve->points, link) {
point = reinterpret_cast<CurvePoint*>(link->data);
CALCDIST(x, y);
}
/* if (curve_editor->curve->union_type == PROP_SPLINE && edit_x && edit_y) { */
/* for (it=curve_editor->curve->keys; it; it=it->next) { */
/* key = it->data; */
/* if (it->prev) { */
/* CALCDIST(px, py); */
/* } */
/* if (it->next) { */
/* CALCDIST(nx, ny); */
/* } */
/* } */
/* } */
return point_found;
}
static int edit_node_manual(CurvePoint* point)
{
JWidget entry_x, entry_y, button_ok;
CurvePoint point_copy = *point;
int res;
FramePtr window(load_widget("color_curve.xml", "point_properties"));
entry_x = jwidget_find_name(window, "x");
entry_y = jwidget_find_name(window, "y");
button_ok = jwidget_find_name(window, "button_ok");
entry_x->setTextf("%d", point->x);
entry_y->setTextf("%d", point->y);
window->open_window_fg();
if (window->get_killer() == button_ok) {
point->x = entry_x->getTextDouble();
point->y = entry_y->getTextDouble();
res = true;
}
else {
point->x = point_copy.x;
point->y = point_copy.y;
res = false;
}
return res;
}

View File

@ -1,117 +0,0 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "effect/effect.h"
#include "gui/manager.h"
#include "gui/message.h"
#include "gui/widget.h"
#include "raster/sprite.h"
#include "util/render.h"
#include "widgets/preview.h"
typedef struct Preview
{
Effect *effect;
int timer_id;
} Preview;
static bool preview_msg_proc(JWidget widget, JMessage msg);
/**
* Invisible widget to control a effect-preview.
*/
JWidget preview_new(Effect* effect)
{
Widget* widget = new Widget(preview_type());
Preview* preview = new Preview;
preview->effect = effect;
preview->timer_id = -1;
jwidget_add_hook(widget, preview_type(), preview_msg_proc, preview);
widget->setVisible(false);
return widget;
}
int preview_type()
{
static int type = 0;
if (!type)
type = ji_register_widget_type();
return type;
}
void preview_restart(JWidget widget)
{
ASSERT_VALID_WIDGET(widget);
Preview* preview = reinterpret_cast<Preview*>(jwidget_get_data(widget, preview_type()));
effect_begin_for_preview(preview->effect);
if (preview->timer_id < 0)
preview->timer_id = jmanager_add_timer(widget, 1);
jmanager_start_timer(preview->timer_id);
}
Effect *preview_get_effect(JWidget widget)
{
ASSERT_VALID_WIDGET(widget);
Preview* preview = reinterpret_cast<Preview*>(jwidget_get_data(widget, preview_type()));
return preview->effect;
}
static bool preview_msg_proc(JWidget widget, JMessage msg)
{
Preview* preview = reinterpret_cast<Preview*>(jwidget_get_data(widget, preview_type()));
Effect* effect = preview_get_effect(widget);
switch (msg->type) {
case JM_DESTROY:
if (preview->timer_id >= 0)
jmanager_remove_timer(preview->timer_id);
delete preview;
break;
case JM_OPEN:
RenderEngine::setPreviewImage(effect->sprite->getCurrentLayer(), effect->dst);
break;
case JM_CLOSE:
RenderEngine::setPreviewImage(NULL, NULL);
/* stop the preview timer */
jmanager_stop_timer(preview->timer_id);
break;
case JM_TIMER:
if (effect) {
if (effect_apply_step(effect))
effect_flush(effect);
else
jmanager_stop_timer(preview->timer_id);
}
break;
}
return false;
}

View File

@ -1,242 +0,0 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <allegro.h>
#include <string.h>
#include "base/bind.h"
#include "core/cfg.h"
#include "effect/effect.h"
#include "gui/box.h"
#include "gui/button.h"
#include "gui/hook.h"
#include "gui/theme.h"
#include "gui/widget.h"
#include "modules/gfx.h"
#include "modules/gui.h"
#include "raster/image.h"
#include "skin/skin_parts.h"
#include "widgets/target.h"
static bool channel_change_hook(ButtonBase* widget, Widget* data);
static bool images_change_hook(ButtonBase* widget, Widget* data);
static int get_target_normal_icon(int target);
static int get_target_selected_icon(int target);
/**
* Creates a new button to handle "targets" to apply some effect in
* the sprite
*
* user_data[0] = target flags (TARGET_RED_CHANNEL, etc.)
*/
JWidget target_button_new(int imgtype, bool with_channels)
{
#define ADD(box, widget, hook) \
if (widget) { \
jwidget_set_border(widget, 2 * jguiscale()); \
jwidget_add_child(box, widget); \
widget->Click.connect(Bind<bool>(&hook, widget, vbox)); \
}
int default_targets = 0;
Box* vbox, *hbox;
CheckBox* r = NULL;
CheckBox* g = NULL;
CheckBox* b = NULL;
CheckBox* k = NULL;
CheckBox* a = NULL;
CheckBox* index = NULL;
Button* images = NULL;
vbox = new Box(JI_VERTICAL);
hbox = new Box(JI_HORIZONTAL | JI_HOMOGENEOUS);
jwidget_noborders(vbox);
jwidget_noborders(hbox);
if (with_channels) {
switch (imgtype) {
case IMAGE_RGB:
case IMAGE_INDEXED:
r = check_button_new("R", 2, 0, 0, 0);
g = check_button_new("G", 0, 0, 0, 0);
b = check_button_new("B", 0, (imgtype == IMAGE_RGB) ? 0: 2, 0, 0);
r->setName("r");
g->setName("g");
b->setName("b");
if (imgtype == IMAGE_RGB) {
a = check_button_new("A", 0, 2, 0, 0);
a->setName("a");
}
else {
index = check_button_new("Index", 0, 0, 0, 0);
index->setName("i");
}
break;
case IMAGE_GRAYSCALE:
k = check_button_new("K", 2, 0, 0, 0);
a = check_button_new("A", 0, 2, 0, 0);
k->setName("k");
a->setName("a");
break;
}
}
/* create the button to select "image" target */
images = new Button(NULL);
setup_bevels(images,
with_channels ? 0: 2,
with_channels ? 0: 2, 2, 2);
setup_mini_look(images);
set_gfxicon_to_button(images,
get_target_normal_icon(default_targets),
get_target_selected_icon(default_targets), -1,
JI_CENTER | JI_MIDDLE);
/* make hierarchy */
ADD(hbox, r, channel_change_hook);
ADD(hbox, g, channel_change_hook);
ADD(hbox, b, channel_change_hook);
ADD(hbox, k, channel_change_hook);
ADD(hbox, a, channel_change_hook);
if (with_channels)
jwidget_add_child(vbox, hbox);
else
jwidget_free(hbox);
ADD(vbox, index, channel_change_hook);
ADD(vbox, images, images_change_hook);
vbox->user_data[0] = (void *)default_targets;
return vbox;
}
int target_button_get_target(JWidget widget)
{
return (size_t)widget->user_data[0];
}
void target_button_set_target(JWidget widget, int target)
{
JWidget w;
#define ACTIVATE_TARGET(name, TARGET) \
w = jwidget_find_name(widget, name); \
if (w != NULL) { \
w->setSelected((target & TARGET) == TARGET); \
}
ACTIVATE_TARGET("r", TARGET_RED_CHANNEL);
ACTIVATE_TARGET("g", TARGET_GREEN_CHANNEL);
ACTIVATE_TARGET("b", TARGET_BLUE_CHANNEL);
ACTIVATE_TARGET("a", TARGET_ALPHA_CHANNEL);
ACTIVATE_TARGET("k", TARGET_GRAY_CHANNEL);
ACTIVATE_TARGET("i", TARGET_INDEX_CHANNEL);
widget->user_data[0] = (void *)target;
}
static bool channel_change_hook(ButtonBase* widget, Widget* target_button)
{
int target = (size_t)target_button->user_data[0];
int flag = 0;
switch (*widget->name) {
case 'r': flag = TARGET_RED_CHANNEL; break;
case 'g': flag = TARGET_GREEN_CHANNEL; break;
case 'b': flag = TARGET_BLUE_CHANNEL; break;
case 'k': flag = TARGET_GRAY_CHANNEL; break;
case 'a': flag = TARGET_ALPHA_CHANNEL; break;
case 'i': flag = TARGET_INDEX_CHANNEL; break;
default:
return true;
}
if (widget->isSelected())
target |= flag;
else
target &= ~flag;
target_button->user_data[0] = (void *)target;
jwidget_emit_signal(target_button, SIGNAL_TARGET_BUTTON_CHANGE);
return true;
}
static bool images_change_hook(ButtonBase* widget, Widget* target_button)
{
int target = (size_t)target_button->user_data[0];
/* rotate target */
if (target & TARGET_ALL_FRAMES) {
target &= ~TARGET_ALL_FRAMES;
if (target & TARGET_ALL_LAYERS)
target &= ~TARGET_ALL_LAYERS;
else
target |= TARGET_ALL_LAYERS;
}
else {
target |= TARGET_ALL_FRAMES;
}
set_gfxicon_to_button(widget,
get_target_normal_icon(target),
get_target_selected_icon(target), -1,
JI_CENTER | JI_MIDDLE);
target_button->user_data[0] = (void *)target;
jwidget_emit_signal(target_button, SIGNAL_TARGET_BUTTON_CHANGE);
return true;
}
static int get_target_normal_icon(int target)
{
if (target & TARGET_ALL_FRAMES) {
return (target & TARGET_ALL_LAYERS) ?
PART_TARGET_FRAMES_LAYERS:
PART_TARGET_FRAMES;
}
else {
return (target & TARGET_ALL_LAYERS) ?
PART_TARGET_LAYERS:
PART_TARGET_ONE;
}
}
static int get_target_selected_icon(int target)
{
if (target & TARGET_ALL_FRAMES) {
return (target & TARGET_ALL_LAYERS) ?
PART_TARGET_FRAMES_LAYERS_SELECTED:
PART_TARGET_FRAMES_SELECTED;
}
else {
return (target & TARGET_ALL_LAYERS) ?
PART_TARGET_LAYERS_SELECTED:
PART_TARGET_ONE_SELECTED;
}
}