diff --git a/src/app/commands/filters/filter_preview.cpp b/src/app/commands/filters/filter_preview.cpp index 5ea245015..41fc463f4 100644 --- a/src/app/commands/filters/filter_preview.cpp +++ b/src/app/commands/filters/filter_preview.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2016 David Capello // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as @@ -14,6 +14,7 @@ #include "app/commands/filters/filter_manager_impl.h" #include "app/modules/editors.h" #include "app/ui/editor/editor.h" +#include "doc/layer.h" #include "doc/sprite.h" #include "ui/manager.h" #include "ui/message.h" @@ -68,7 +69,8 @@ bool FilterPreview::onProcessMessage(Message* msg) current_editor->renderEngine().setPreviewImage( m_filterMgr->layer(), m_filterMgr->frame(), - m_filterMgr->destinationImage()); + m_filterMgr->destinationImage(), + static_cast(m_filterMgr->layer())->blendMode()); break; case kCloseMessage: diff --git a/src/app/ui/editor/drawing_state.cpp b/src/app/ui/editor/drawing_state.cpp index 75f26bbb2..d8a75dd44 100644 --- a/src/app/ui/editor/drawing_state.cpp +++ b/src/app/ui/editor/drawing_state.cpp @@ -24,6 +24,7 @@ #include "app/ui/editor/glue.h" #include "app/ui/keyboard_shortcuts.h" #include "app/ui_context.h" +#include "doc/layer.h" #include "ui/message.h" #include "ui/system.h" @@ -61,7 +62,11 @@ void DrawingState::initToolLoop(Editor* editor, MouseMessage* msg) editor->renderEngine().setPreviewImage( m_toolLoop->getLayer(), m_toolLoop->getFrame(), - m_toolLoop->getDstImage()); + m_toolLoop->getDstImage(), + (m_toolLoop->getLayer() && + m_toolLoop->getLayer()->isImage() ? + static_cast(m_toolLoop->getLayer())->blendMode(): + BlendMode::NEG_BW)); m_lastPoint = editor->lastDrawingPosition(); diff --git a/src/app/ui/editor/pixels_movement.cpp b/src/app/ui/editor/pixels_movement.cpp index 2509867c6..f6d4989f9 100644 --- a/src/app/ui/editor/pixels_movement.cpp +++ b/src/app/ui/editor/pixels_movement.cpp @@ -479,7 +479,8 @@ void PixelsMovement::stampImage() { // Expand the canvas to paste the image in the fully visible // portion of sprite. - ExpandCelCanvas expand(m_site, + ExpandCelCanvas expand( + m_site, m_site.layer(), TiledMode::NONE, m_transaction, ExpandCelCanvas::None); diff --git a/src/app/ui/editor/standby_state.cpp b/src/app/ui/editor/standby_state.cpp index 3ae205abc..c4e82318a 100644 --- a/src/app/ui/editor/standby_state.cpp +++ b/src/app/ui/editor/standby_state.cpp @@ -378,9 +378,10 @@ bool StandbyState::onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos) editor->showMouseCursor(kArrowPlusCursor); else editor->showMouseCursor(kMoveCursor); - - return true; } + else + editor->showBrushPreview(mouseScreenPos); + return true; } else if (ink->isEyedropper()) { editor->showMouseCursor(kEyedropperCursor); diff --git a/src/app/ui/editor/tool_loop_impl.cpp b/src/app/ui/editor/tool_loop_impl.cpp index cc4a24509..c787455e9 100644 --- a/src/app/ui/editor/tool_loop_impl.cpp +++ b/src/app/ui/editor/tool_loop_impl.cpp @@ -81,6 +81,7 @@ protected: tools::TracePolicy m_tracePolicy; base::UniquePtr m_symmetry; base::UniquePtr m_shadingRemap; + app::ColorTarget m_colorTarget; doc::color_t m_fgColor; doc::color_t m_bgColor; doc::color_t m_primaryColor; @@ -89,6 +90,7 @@ protected: public: ToolLoopBase(Editor* editor, + Layer* layer, tools::Tool* tool, tools::Ink* ink, Document* document, @@ -100,7 +102,7 @@ public: , m_brush(App::instance()->contextBar()->activeBrush(m_tool)) , m_document(document) , m_sprite(editor->sprite()) - , m_layer(editor->layer()) + , m_layer(layer) , m_frame(editor->frame()) , m_rgbMap(nullptr) , m_docPref(Preferences::instance().document(m_document)) @@ -115,8 +117,12 @@ public: , m_intertwine(m_tool->getIntertwine(m_button)) , m_tracePolicy(m_tool->getTracePolicy(m_button)) , m_symmetry(nullptr) - , m_fgColor(color_utils::color_for_target_mask(fgColor, ColorTarget(m_layer))) - , m_bgColor(color_utils::color_for_target_mask(bgColor, ColorTarget(m_layer))) + , m_colorTarget(m_layer ? ColorTarget(m_layer): + ColorTarget(ColorTarget::BackgroundLayer, + m_sprite->pixelFormat(), + m_sprite->transparentColor())) + , m_fgColor(color_utils::color_for_target_mask(fgColor, m_colorTarget)) + , m_bgColor(color_utils::color_for_target_mask(bgColor, m_colorTarget)) , m_primaryColor(button == tools::ToolLoop::Left ? m_fgColor: m_bgColor) , m_secondaryColor(button == tools::ToolLoop::Left ? m_bgColor: m_fgColor) { @@ -184,7 +190,8 @@ public: RgbMap* getRgbMap() override { if (!m_rgbMap) { Sprite::RgbMapFor forLayer = - ((m_layer->isBackground() || + ((!m_layer || + m_layer->isBackground() || m_sprite->pixelFormat() == IMAGE_RGB) ? Sprite::RgbMapFor::OpaqueLayer: Sprite::RgbMapFor::TransparentLayer); @@ -265,6 +272,7 @@ class ToolLoopImpl : public ToolLoopBase { public: ToolLoopImpl(Editor* editor, + Layer* layer, Context* context, tools::Tool* tool, tools::Ink* ink, @@ -272,7 +280,7 @@ public: tools::ToolLoop::Button button, const app::Color& fgColor, const app::Color& bgColor) - : ToolLoopBase(editor, tool, ink, document, + : ToolLoopBase(editor, layer, tool, ink, document, button, fgColor, bgColor) , m_context(context) , m_canceled(false) @@ -284,7 +292,9 @@ public: getInk()->isSlice() || getInk()->isZoom()) ? DoesntModifyDocument: ModifyDocument)) - , m_expandCelCanvas(editor->getSite(), + , m_expandCelCanvas( + editor->getSite(), + layer, m_docPref.tiled.mode(), m_transaction, ExpandCelCanvas::Flags( @@ -424,24 +434,39 @@ tools::ToolLoop* create_tool_loop(Editor* editor, Context* context) if (!current_tool || !current_ink) return NULL; - Layer* layer = editor->layer(); - if (!layer) { - StatusBar::instance()->showTip(1000, - "There is no active layer"); - return NULL; - } + Layer* layer; - // If the active layer is not visible. - if (!layer->isVisible()) { - StatusBar::instance()->showTip(1000, - "Layer '%s' is hidden", layer->name().c_str()); - return NULL; + // For selection tools, we can use any layer (even without layers at + // all), so we specify a nullptr here as the active layer. This is + // used as a special case by the render::Render class to show the + // preview image/selection stroke as a xor'd overlay in the render + // result. + // + // Anyway this cannot be used in 'magic wand' tool (isSelection + + // isFloodFill) because we need the original layer source + // image/pixels to stop the flood-fill algorithm. + if (current_ink->isSelection() && + !current_tool->getPointShape(editor->isSecondaryButton() ? 1: 0)->isFloodFill()) { + layer = nullptr; } - // If the active layer is read-only. - else if (!layer->isEditable()) { - StatusBar::instance()->showTip(1000, - "Layer '%s' is locked", layer->name().c_str()); - return NULL; + else { + layer = editor->layer(); + if (!layer) { + StatusBar::instance()->showTip( + 1000, "There is no active layer"); + return nullptr; + } + else if (!layer->isVisible()) { + StatusBar::instance()->showTip( + 1000, "Layer '%s' is hidden", layer->name().c_str()); + return nullptr; + } + // If the active layer is read-only. + else if (!layer->isEditable()) { + StatusBar::instance()->showTip( + 1000, "Layer '%s' is locked", layer->name().c_str()); + return nullptr; + } } // Get fg/bg colors @@ -463,7 +488,7 @@ tools::ToolLoop* create_tool_loop(Editor* editor, Context* context) // Create the new tool loop try { return new ToolLoopImpl( - editor, context, + editor, layer, context, current_tool, current_ink, editor->document(), @@ -496,7 +521,7 @@ public: const app::Color& bgColor, Image* image, const gfx::Point& celOrigin) - : ToolLoopBase(editor, tool, ink, document, + : ToolLoopBase(editor, editor->layer(), tool, ink, document, tools::ToolLoop::Left, fgColor, bgColor) , m_image(image) { diff --git a/src/app/util/expand_cel_canvas.cpp b/src/app/util/expand_cel_canvas.cpp index 7206392d0..3cc41c25c 100644 --- a/src/app/util/expand_cel_canvas.cpp +++ b/src/app/util/expand_cel_canvas.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2016 David Capello // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as @@ -27,6 +27,7 @@ #include "doc/primitives.h" #include "doc/site.h" #include "doc/sprite.h" +#include "render/render.h" namespace { @@ -57,11 +58,13 @@ static void create_buffers() namespace app { -ExpandCelCanvas::ExpandCelCanvas(Site site, +ExpandCelCanvas::ExpandCelCanvas( + Site site, Layer* layer, TiledMode tiledMode, Transaction& transaction, Flags flags) : m_document(static_cast(site.document())) , m_sprite(site.sprite()) - , m_layer(site.layer()) + , m_layer(layer) + , m_frame(site.frame()) , m_cel(NULL) , m_celImage(NULL) , m_celCreated(false) @@ -77,14 +80,14 @@ ExpandCelCanvas::ExpandCelCanvas(Site site, create_buffers(); - if (m_layer->isImage()) { + if (m_layer && m_layer->isImage()) { m_cel = m_layer->cel(site.frame()); if (m_cel) m_celImage = m_cel->imageRef(); } // Create a new cel - if (m_cel == NULL) { + if (!m_cel) { m_celCreated = true; m_cel = new Cel(site.frame(), ImageRef(NULL)); } @@ -117,7 +120,9 @@ ExpandCelCanvas::ExpandCelCanvas(Site site, if (m_celCreated) { getDestCanvas(); m_cel->data()->setImage(m_dstImage); - static_cast(m_layer)->addCel(m_cel); + + if (m_layer && m_layer->isImage()) + static_cast(m_layer)->addCel(m_cel); } } @@ -140,6 +145,11 @@ void ExpandCelCanvas::commit() ASSERT(!m_closed); ASSERT(!m_committed); + if (!m_layer) { + m_committed = true; + return; + } + // Was the cel created in the start of the tool-loop? if (m_celCreated) { ASSERT(m_cel); @@ -150,6 +160,7 @@ void ExpandCelCanvas::commit() validateDestCanvas(gfx::Region(m_bounds)); // We can temporary remove the cel. + ASSERT(m_layer->isImage()); static_cast(m_layer)->removeCel(m_cel); // Add a copy of m_dstImage in the sprite's image stock @@ -213,7 +224,9 @@ void ExpandCelCanvas::rollback() m_cel->setPosition(m_origCelPos); if (m_celCreated) { - static_cast(m_layer)->removeCel(m_cel); + if (m_layer && m_layer->isImage()) + static_cast(m_layer)->removeCel(m_cel); + delete m_cel; m_celImage.reset(NULL); } diff --git a/src/app/util/expand_cel_canvas.h b/src/app/util/expand_cel_canvas.h index f2339a39b..9c2bf2825 100644 --- a/src/app/util/expand_cel_canvas.h +++ b/src/app/util/expand_cel_canvas.h @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2016 David Capello // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as @@ -9,6 +9,7 @@ #define APP_UTIL_EXPAND_CEL_CANVAS_H_INCLUDED #pragma once +#include "doc/frame.h" #include "doc/image_ref.h" #include "filters/tiled_mode.h" #include "gfx/point.h" @@ -45,7 +46,7 @@ namespace app { UseModifiedRegionAsUndoInfo = 2, }; - ExpandCelCanvas(Site site, + ExpandCelCanvas(Site site, Layer* layer, TiledMode tiledMode, Transaction& undo, Flags flags); ~ExpandCelCanvas(); @@ -73,6 +74,7 @@ namespace app { Document* m_document; Sprite* m_sprite; Layer* m_layer; + frame_t m_frame; Cel* m_cel; ImageRef m_celImage; bool m_celCreated; diff --git a/src/render/render.cpp b/src/render/render.cpp index da7d29d7c..3e0ad3505 100644 --- a/src/render/render.cpp +++ b/src/render/render.cpp @@ -348,6 +348,7 @@ Render::Render() , m_selectedLayer(nullptr) , m_selectedFrame(-1) , m_previewImage(nullptr) + , m_previewBlendMode(BlendMode::NORMAL) , m_onionskin(OnionskinType::NONE) { } @@ -377,11 +378,13 @@ void Render::setBgCheckedSize(const gfx::Size& size) m_bgCheckedSize = size; } -void Render::setPreviewImage(const Layer* layer, frame_t frame, Image* image) +void Render::setPreviewImage(const Layer* layer, frame_t frame, + Image* image, BlendMode blendMode) { m_selectedLayer = layer; m_selectedFrame = frame; m_previewImage = image; + m_previewBlendMode = blendMode; } void Render::setExtraImage( @@ -400,7 +403,7 @@ void Render::setExtraImage( void Render::removePreviewImage() { - m_previewImage = NULL; + m_previewImage = nullptr; } void Render::removeExtraImage() @@ -548,6 +551,22 @@ void Render::renderSprite( // Draw onion skin in front of the sprite. if (m_onionskin.position() == OnionskinPosition::INFRONT) renderOnionskin(dstImage, area, frame, zoom, scaled_func); + + // Overlay preview image + if (m_previewImage && + m_selectedLayer == nullptr && + m_selectedFrame == frame) { + renderImage( + dstImage, + m_previewImage, + m_sprite->palette(frame), + 0, 0, + area, + scaled_func, + 255, + m_previewBlendMode, + zoom); + } } void Render::renderOnionskin( @@ -827,13 +846,36 @@ void Render::renderCel( RenderScaledImage scaled_func, int opacity, BlendMode blend_mode, Zoom zoom) { - int cel_x = zoom.apply(cel->x()); - int cel_y = zoom.apply(cel->y()); + renderImage(dst_image, + cel_image, + pal, + cel->x(), + cel->y(), + area, + scaled_func, + opacity, + blend_mode, + zoom); +} + +void Render::renderImage( + Image* dst_image, + const Image* cel_image, + const Palette* pal, + const int x, + const int y, + const gfx::Clip& area, + RenderScaledImage scaled_func, + int opacity, BlendMode blend_mode, Zoom zoom) +{ + int cel_x = zoom.apply(x); + int cel_y = zoom.apply(y); gfx::Rect src_bounds = area.srcBounds().createIntersection( gfx::Rect( - cel_x, cel_y, + cel_x, + cel_y, zoom.apply(cel_image->width()), zoom.apply(cel_image->height()))); if (src_bounds.isEmpty()) diff --git a/src/render/render.h b/src/render/render.h index 5f41aedf3..93a6dbe1a 100644 --- a/src/render/render.h +++ b/src/render/render.h @@ -1,5 +1,5 @@ // Aseprite Render Library -// Copyright (c) 2001-2015 David Capello +// Copyright (c) 2001-2016 David Capello // // This file is released under the terms of the MIT license. // Read LICENSE.txt for more information. @@ -102,7 +102,8 @@ namespace render { // Sets the preview image. This preview image is an alternative // image to be used for the given layer/frame. - void setPreviewImage(const Layer* layer, frame_t frame, Image* drawable); + void setPreviewImage(const Layer* layer, frame_t frame, + Image* image, BlendMode blendMode); void removePreviewImage(); // Sets an extra cel/image to be drawn after the current @@ -190,6 +191,16 @@ namespace render { RenderScaledImage scaled_func, int opacity, BlendMode blend_mode, Zoom zoom); + void renderImage( + Image* dst_image, + const Image* cel_image, + const Palette* pal, + const int x, + const int y, + const gfx::Clip& area, + RenderScaledImage scaled_func, + int opacity, BlendMode blend_mode, Zoom zoom); + static RenderScaledImage getRenderScaledImageFunc( PixelFormat dstFormat, PixelFormat srcFormat); @@ -211,6 +222,7 @@ namespace render { const Layer* m_selectedLayer; frame_t m_selectedFrame; Image* m_previewImage; + BlendMode m_previewBlendMode; OnionskinOptions m_onionskin; };