mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-30 13:20:28 +00:00
Fix issue #237: fix pen size for square shape
+ Add Pen::getBounds(). + Add options to increment/decrement angle with ChangePen command. + Add App:PenAngleBefore/AfterChange signals.
This commit is contained in:
parent
e90f86727b
commit
9259dd49d1
@ -66,6 +66,8 @@ public:
|
||||
Signal0<void> PaletteChange;
|
||||
Signal0<void> PenSizeBeforeChange;
|
||||
Signal0<void> PenSizeAfterChange;
|
||||
Signal0<void> PenAngleBeforeChange;
|
||||
Signal0<void> PenAngleAfterChange;
|
||||
Signal0<void> CurrentToolChange;
|
||||
|
||||
private:
|
||||
|
@ -33,6 +33,8 @@ class ChangePenCommand : public Command
|
||||
None,
|
||||
IncrementSize,
|
||||
DecrementSize,
|
||||
IncrementAngle,
|
||||
DecrementAngle,
|
||||
};
|
||||
|
||||
Change m_change;
|
||||
@ -58,6 +60,8 @@ void ChangePenCommand::onLoadParams(Params* params)
|
||||
std::string change = params->get("change");
|
||||
if (change == "increment-size") m_change = IncrementSize;
|
||||
else if (change == "decrement-size") m_change = DecrementSize;
|
||||
else if (change == "increment-angle") m_change = IncrementAngle;
|
||||
else if (change == "decrement-angle") m_change = DecrementAngle;
|
||||
}
|
||||
|
||||
void ChangePenCommand::onExecute(Context* context)
|
||||
@ -78,6 +82,14 @@ void ChangePenCommand::onExecute(Context* context)
|
||||
if (pen->getSize() > 1)
|
||||
pen->setSize(pen->getSize()-1);
|
||||
break;
|
||||
case IncrementAngle:
|
||||
if (pen->getAngle() < 180)
|
||||
pen->setAngle(pen->getAngle()+1);
|
||||
break;
|
||||
case DecrementAngle:
|
||||
if (pen->getAngle() > 0)
|
||||
pen->setAngle(pen->getAngle()-1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,17 +97,18 @@ void image_putpixel(Image* image, int x, int y, int color)
|
||||
void image_putpen(Image* image, Pen* pen, int x, int y, int fg_color, int bg_color)
|
||||
{
|
||||
Image* pen_image = pen->get_image();
|
||||
int u, v, size = pen->get_size();
|
||||
const gfx::Rect& penBounds = pen->getBounds();
|
||||
|
||||
x -= size/2;
|
||||
y -= size/2;
|
||||
x += penBounds.x;
|
||||
y += penBounds.y;
|
||||
|
||||
if (fg_color == bg_color) {
|
||||
image_rectfill(image, x, y, x+pen_image->w-1, y+pen_image->h-1, bg_color);
|
||||
image_rectfill(image, x, y, x+penBounds.w-1, y+penBounds.h-1, bg_color);
|
||||
}
|
||||
else {
|
||||
for (v=0; v<pen_image->h; v++) {
|
||||
for (u=0; u<pen_image->w; u++) {
|
||||
int u, v;
|
||||
for (v=0; v<penBounds.h; v++) {
|
||||
for (u=0; u<penBounds.w; u++) {
|
||||
if (image_getpixel(pen_image, u, v))
|
||||
image_putpixel(image, x+u, y+v, fg_color);
|
||||
else
|
||||
|
@ -95,63 +95,75 @@ static void algo_hline(int x1, int y, int x2, void *data)
|
||||
// Regenerates the pen bitmap and its rectangle's region.
|
||||
void Pen::regenerate_pen()
|
||||
{
|
||||
int x, y;
|
||||
|
||||
clean_pen();
|
||||
|
||||
m_image = Image::create(IMAGE_BITMAP, m_size, m_size);
|
||||
image_clear(m_image, 0);
|
||||
ASSERT(m_size > 0);
|
||||
|
||||
switch (m_type) {
|
||||
int size = m_size;
|
||||
if (m_type == PEN_TYPE_SQUARE && m_angle != 0 && m_size > 2)
|
||||
size = std::sqrt(2*m_size*m_size)+2;
|
||||
|
||||
case PEN_TYPE_CIRCLE:
|
||||
image_ellipsefill(m_image, 0, 0, m_size-1, m_size-1, 1);
|
||||
break;
|
||||
m_image = Image::create(IMAGE_BITMAP, size, size);
|
||||
|
||||
case PEN_TYPE_SQUARE: {
|
||||
double a = PI * m_angle / 180;
|
||||
int r = m_size/2;
|
||||
int x1, y1, x2, y2, x3, y3, x4, y4;
|
||||
if (size == 1) {
|
||||
image_clear(m_image, 1);
|
||||
}
|
||||
else {
|
||||
image_clear(m_image, 0);
|
||||
|
||||
x1 = cos(a+ PI/4) * r;
|
||||
y1 = -sin(a+ PI/4) * r;
|
||||
x2 = cos(a+3*PI/4) * r;
|
||||
y2 = -sin(a+3*PI/4) * r;
|
||||
x3 = cos(a-3*PI/4) * r;
|
||||
y3 = -sin(a-3*PI/4) * r;
|
||||
x4 = cos(a- PI/4) * r;
|
||||
y4 = -sin(a- PI/4) * r;
|
||||
switch (m_type) {
|
||||
|
||||
image_line(m_image, r+x1, r+y1, r+x2, r+y2, 1);
|
||||
image_line(m_image, r+x2, r+y2, r+x3, r+y3, 1);
|
||||
image_line(m_image, r+x3, r+y3, r+x4, r+y4, 1);
|
||||
image_line(m_image, r+x4, r+y4, r+x1, r+y1, 1);
|
||||
case PEN_TYPE_CIRCLE:
|
||||
image_ellipsefill(m_image, 0, 0, size-1, size-1, 1);
|
||||
break;
|
||||
|
||||
algo_floodfill(m_image, r, r, 0, m_image, algo_hline);
|
||||
break;
|
||||
}
|
||||
case PEN_TYPE_SQUARE:
|
||||
if (m_angle == 0 || size <= 2) {
|
||||
image_clear(m_image, 1);
|
||||
}
|
||||
else {
|
||||
double a = PI * m_angle / 180;
|
||||
int c = size/2;
|
||||
int r = m_size/2;
|
||||
int d = m_size;
|
||||
int x1 = c + r*cos(a-PI/2) + r*cos(a-PI);
|
||||
int y1 = c - r*sin(a-PI/2) - r*sin(a-PI);
|
||||
int x2 = x1 + d*cos(a);
|
||||
int y2 = y1 - d*sin(a);
|
||||
int x3 = x2 + d*cos(a+PI/2);
|
||||
int y3 = y2 - d*sin(a+PI/2);
|
||||
int x4 = x3 + d*cos(a+PI);
|
||||
int y4 = y3 - d*sin(a+PI);
|
||||
int points[8] = { x1, y1, x2, y2, x3, y3, x4, y4 };
|
||||
|
||||
case PEN_TYPE_LINE: {
|
||||
double a = PI * m_angle / 180;
|
||||
int r = m_size/2;
|
||||
algo_polygon(4, points, m_image, algo_hline);
|
||||
}
|
||||
break;
|
||||
|
||||
x = cos(a) * r;
|
||||
y = -sin(a) * r;
|
||||
image_line(m_image, r-x, r-y, r+x, r+y, 1);
|
||||
image_line(m_image, r-x-1, r-y, r+x-1, r+y, 1);
|
||||
break;
|
||||
case PEN_TYPE_LINE: {
|
||||
double a = PI * m_angle / 180;
|
||||
float r = m_size/2;
|
||||
float d = m_size;
|
||||
int x1 = r + r*cos(a+PI);
|
||||
int y1 = r - r*sin(a+PI);
|
||||
int x2 = x1 + d*cos(a);
|
||||
int y2 = y1 - d*sin(a);
|
||||
|
||||
image_line(m_image, x1, y1, x2, y2, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_scanline.resize(m_size);
|
||||
for (y=0; y<m_size; y++) {
|
||||
m_scanline.resize(m_image->h);
|
||||
for (int y=0; y<m_image->h; y++) {
|
||||
m_scanline[y].state = false;
|
||||
|
||||
for (x=0; x<m_size; x++) {
|
||||
for (int x=0; x<m_image->w; x++) {
|
||||
if (image_getpixel(m_image, x, y)) {
|
||||
m_scanline[y].x1 = x;
|
||||
|
||||
for (; x<m_size; x++)
|
||||
for (; x<m_image->w; x++)
|
||||
if (!image_getpixel(m_image, x, y))
|
||||
break;
|
||||
|
||||
@ -161,4 +173,7 @@ void Pen::regenerate_pen()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_bounds = gfx::Rect(-m_image->w/2, -m_image->h/2,
|
||||
m_image->w, m_image->h);
|
||||
}
|
||||
|
@ -19,6 +19,8 @@
|
||||
#ifndef RASTER_PEN_H_INCLUDED
|
||||
#define RASTER_PEN_H_INCLUDED
|
||||
|
||||
#include "gfx/point.h"
|
||||
#include "gfx/rect.h"
|
||||
#include "raster/pen_type.h"
|
||||
#include <vector>
|
||||
|
||||
@ -43,6 +45,8 @@ public:
|
||||
Image* get_image() { return m_image; }
|
||||
const std::vector<PenScanline>& get_scanline() const { return m_scanline; }
|
||||
|
||||
const gfx::Rect& getBounds() const { return m_bounds; }
|
||||
|
||||
void set_type(PenType type);
|
||||
void set_size(int size);
|
||||
void set_angle(int angle);
|
||||
@ -51,11 +55,12 @@ private:
|
||||
void clean_pen();
|
||||
void regenerate_pen();
|
||||
|
||||
PenType m_type; /* type of pen */
|
||||
int m_size; /* size (diameter) */
|
||||
int m_angle; /* angle in degrees 0-360 */
|
||||
Image* m_image; /* image of the pen */
|
||||
PenType m_type; // Type of pen
|
||||
int m_size; // Size (diameter)
|
||||
int m_angle; // Angle in degrees 0-360
|
||||
Image* m_image; // Image of the pen
|
||||
std::vector<PenScanline> m_scanline;
|
||||
gfx::Rect m_bounds;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -209,14 +209,16 @@ void UISettingsImpl::setBgColor(const app::Color& color)
|
||||
void UISettingsImpl::setCurrentTool(tools::Tool* tool)
|
||||
{
|
||||
if (m_currentTool != tool) {
|
||||
// Fire PenSizeBeforeChange signal (maybe the new selected tool has a different pen size)
|
||||
// Fire signals (maybe the new selected tool has a different pen size)
|
||||
App::instance()->PenSizeBeforeChange();
|
||||
App::instance()->PenAngleBeforeChange();
|
||||
|
||||
// Change the tool
|
||||
m_currentTool = tool;
|
||||
|
||||
App::instance()->CurrentToolChange(); // Fire CurrentToolChange signal
|
||||
App::instance()->PenSizeAfterChange(); // Fire PenSizeAfterChange signal
|
||||
App::instance()->PenAngleAfterChange(); // Fire PenAngleAfterChange signal
|
||||
}
|
||||
}
|
||||
|
||||
@ -446,7 +448,15 @@ public:
|
||||
|
||||
void setAngle(int angle)
|
||||
{
|
||||
// Trigger PenAngleBeforeChange signal
|
||||
if (m_fireSignals)
|
||||
App::instance()->PenAngleBeforeChange();
|
||||
|
||||
m_angle = MID(0, angle, 360);
|
||||
|
||||
// Trigger PenAngleAfterChange signal
|
||||
if (m_fireSignals)
|
||||
App::instance()->PenAngleAfterChange();
|
||||
}
|
||||
|
||||
void enableSignals(bool state)
|
||||
|
@ -49,23 +49,23 @@ public:
|
||||
{
|
||||
Pen* pen = loop->getPen();
|
||||
std::vector<PenScanline>::const_iterator scanline = pen->get_scanline().begin();
|
||||
register int h = pen->get_size();
|
||||
register int c = h/2;
|
||||
register int v, h = pen->getBounds().h;
|
||||
|
||||
x -= c;
|
||||
y -= c;
|
||||
x += pen->getBounds().x;
|
||||
y += pen->getBounds().y;
|
||||
|
||||
for (c=0; c<h; c++) {
|
||||
for (v=0; v<h; ++v) {
|
||||
if (scanline->state)
|
||||
doInkHline(x+scanline->x1, y+c, x+scanline->x2, loop);
|
||||
doInkHline(x+scanline->x1, y+v, x+scanline->x2, loop);
|
||||
++scanline;
|
||||
}
|
||||
}
|
||||
void getModifiedArea(ToolLoop* loop, int x, int y, Rect& area)
|
||||
{
|
||||
Pen* pen = loop->getPen();
|
||||
int size = pen->get_size();
|
||||
area = Rect(x-size/2, y-size/2, size, size);
|
||||
area = pen->getBounds();
|
||||
area.x += x;
|
||||
area.y += y;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -363,7 +363,8 @@ ContextBar::ContextBar()
|
||||
tooltipManager->addTooltipFor(m_sprayWidth, "Spray Width", JI_CENTER | JI_BOTTOM);
|
||||
tooltipManager->addTooltipFor(m_spraySpeed, "Spray Speed", JI_CENTER | JI_BOTTOM);
|
||||
|
||||
App::instance()->PenSizeAfterChange.connect(&ContextBar::onPenSizeAfterChange, this);
|
||||
App::instance()->PenSizeAfterChange.connect(&ContextBar::onPenSizeChange, this);
|
||||
App::instance()->PenAngleAfterChange.connect(&ContextBar::onPenAngleChange, this);
|
||||
App::instance()->CurrentToolChange.connect(&ContextBar::onCurrentToolChange, this);
|
||||
|
||||
onCurrentToolChange();
|
||||
@ -378,7 +379,7 @@ bool ContextBar::onProcessMessage(Message* msg)
|
||||
return Box::onProcessMessage(msg);
|
||||
}
|
||||
|
||||
void ContextBar::onPenSizeAfterChange()
|
||||
void ContextBar::onPenSizeChange()
|
||||
{
|
||||
ISettings* settings = UIContext::instance()->getSettings();
|
||||
Tool* currentTool = settings->getCurrentTool();
|
||||
@ -389,6 +390,17 @@ void ContextBar::onPenSizeAfterChange()
|
||||
m_brushSize->setTextf("%d", penSettings->getSize());
|
||||
}
|
||||
|
||||
void ContextBar::onPenAngleChange()
|
||||
{
|
||||
ISettings* settings = UIContext::instance()->getSettings();
|
||||
Tool* currentTool = settings->getCurrentTool();
|
||||
IToolSettings* toolSettings = settings->getToolSettings(currentTool);
|
||||
IPenSettings* penSettings = toolSettings->getPen();
|
||||
|
||||
m_brushType->setPenSettings(penSettings);
|
||||
m_brushAngle->setTextf("%d", penSettings->getAngle());
|
||||
}
|
||||
|
||||
void ContextBar::onCurrentToolChange()
|
||||
{
|
||||
ISettings* settings = UIContext::instance()->getSettings();
|
||||
|
@ -37,7 +37,8 @@ protected:
|
||||
bool onProcessMessage(ui::Message* msg) OVERRIDE;
|
||||
|
||||
private:
|
||||
void onPenSizeAfterChange();
|
||||
void onPenSizeChange();
|
||||
void onPenAngleChange();
|
||||
void onCurrentToolChange();
|
||||
|
||||
class BrushTypeField;
|
||||
|
@ -150,7 +150,7 @@ static void on_palette_change_update_cursor_color()
|
||||
update_cursor_color();
|
||||
}
|
||||
|
||||
static void on_pen_size_before_change()
|
||||
static void on_pen_before_change()
|
||||
{
|
||||
if (current_editor != NULL) {
|
||||
pen_size_thick = current_editor->getCursorThick();
|
||||
@ -159,7 +159,7 @@ static void on_pen_size_before_change()
|
||||
}
|
||||
}
|
||||
|
||||
static void on_pen_size_after_change()
|
||||
static void on_pen_after_change()
|
||||
{
|
||||
if (current_editor != NULL) {
|
||||
// Show drawing cursor
|
||||
@ -205,8 +205,10 @@ void Editor::editor_cursor_init()
|
||||
set_cursor_color(get_config_color("Tools", "CursorColor", app::Color::fromMask()));
|
||||
|
||||
App::instance()->PaletteChange.connect(&on_palette_change_update_cursor_color);
|
||||
App::instance()->PenSizeBeforeChange.connect(&on_pen_size_before_change);
|
||||
App::instance()->PenSizeAfterChange.connect(&on_pen_size_after_change);
|
||||
App::instance()->PenSizeBeforeChange.connect(&on_pen_before_change);
|
||||
App::instance()->PenSizeAfterChange.connect(&on_pen_after_change);
|
||||
App::instance()->PenAngleBeforeChange.connect(&on_pen_before_change);
|
||||
App::instance()->PenAngleAfterChange.connect(&on_pen_after_change);
|
||||
}
|
||||
|
||||
void Editor::editor_cursor_exit()
|
||||
@ -284,12 +286,11 @@ void Editor::editor_draw_cursor(int x, int y, bool refresh)
|
||||
int pen_color = get_pen_color(m_sprite, m_layer);
|
||||
uint32_t new_mask_color;
|
||||
Pen* pen = editor_get_current_pen();
|
||||
int half = pen->get_size()/2;
|
||||
gfx::Rect penBounds = pen->getBounds();
|
||||
|
||||
// Create the extra cel to show the pen preview
|
||||
m_document->prepareExtraCel(x-half,
|
||||
y-half,
|
||||
pen->get_size(), pen->get_size(),
|
||||
m_document->prepareExtraCel(x+penBounds.x, y+penBounds.y,
|
||||
penBounds.w, penBounds.h,
|
||||
tool_settings->getOpacity());
|
||||
|
||||
// In 'indexed' images, if the current color is 0, we have to use
|
||||
@ -304,15 +305,15 @@ void Editor::editor_draw_cursor(int x, int y, bool refresh)
|
||||
Image* extraImage = m_document->getExtraCelImage();
|
||||
if (extraImage->mask_color != new_mask_color)
|
||||
image_clear(extraImage, extraImage->mask_color = new_mask_color);
|
||||
image_putpen(extraImage, pen, half, half, pen_color, extraImage->mask_color);
|
||||
image_putpen(extraImage, pen, -penBounds.x, -penBounds.y,
|
||||
pen_color, extraImage->mask_color);
|
||||
|
||||
if (refresh) {
|
||||
m_document->notifySpritePixelsModified
|
||||
(m_sprite,
|
||||
gfx::Region(gfx::Rect(x-half,
|
||||
y-half,
|
||||
pen->get_size(),
|
||||
pen->get_size())));
|
||||
gfx::Region(gfx::Rect(x+penBounds.x,
|
||||
y+penBounds.y,
|
||||
penBounds.w, penBounds.h)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -362,9 +363,9 @@ void Editor::editor_move_cursor(int x, int y, bool refresh)
|
||||
|
||||
if (cursor_type & CURSOR_PENCIL && m_state->requirePenPreview()) {
|
||||
Pen* pen = editor_get_current_pen();
|
||||
int half = pen->get_size()/2;
|
||||
gfx::Rect rc1(old_x-half, old_y-half, pen->get_size(), pen->get_size());
|
||||
gfx::Rect rc2(new_x-half, new_y-half, pen->get_size(), pen->get_size());
|
||||
gfx::Rect penBounds = pen->getBounds();
|
||||
gfx::Rect rc1(old_x+penBounds.x, old_y+penBounds.y, penBounds.w, penBounds.h);
|
||||
gfx::Rect rc2(new_x+penBounds.x, new_y+penBounds.y, penBounds.w, penBounds.h);
|
||||
m_document->notifySpritePixelsModified
|
||||
(m_sprite, gfx::Region(rc1.createUnion(rc2)));
|
||||
}
|
||||
@ -417,19 +418,18 @@ void Editor::editor_clean_cursor(bool refresh)
|
||||
// clean pixel/pen preview
|
||||
if (cursor_type & CURSOR_PENCIL && m_state->requirePenPreview()) {
|
||||
Pen* pen = editor_get_current_pen();
|
||||
gfx::Rect penBounds = pen->getBounds();
|
||||
|
||||
m_document->prepareExtraCel(x-pen->get_size()/2,
|
||||
y-pen->get_size()/2,
|
||||
pen->get_size(), pen->get_size(),
|
||||
m_document->prepareExtraCel(x+penBounds.x, y+penBounds.y,
|
||||
penBounds.w, penBounds.h,
|
||||
0); // Opacity = 0
|
||||
|
||||
if (refresh) {
|
||||
m_document->notifySpritePixelsModified
|
||||
(m_sprite,
|
||||
gfx::Region(gfx::Rect(x-pen->get_size()/2,
|
||||
y-pen->get_size()/2,
|
||||
pen->get_size(),
|
||||
pen->get_size())));
|
||||
gfx::Region(gfx::Rect(x+penBounds.x,
|
||||
y+penBounds.y,
|
||||
penBounds.w, penBounds.h)));
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user