From 8c7b94a934de4b48720df6ff7c1ccc86fcebe79d Mon Sep 17 00:00:00 2001 From: David Capello Date: Tue, 20 Sep 2022 19:28:17 -0300 Subject: [PATCH] Add support to render the background directly on screen Renderer::renderCheckeredBackground() function was used only for the FullscreenPreviewCommand, but now we use ShaderRenderer::renderCheckeredBackground() to render the background in the Editor too. So the sprite is painted in a backbuffer and then composited with the already painted background using Graphics::drawSurface(). --- src/app/commands/cmd_fullscreen_preview.cpp | 117 ++++++++++++-------- src/app/render/renderer.h | 30 ++++- src/app/render/shader_renderer.cpp | 78 +++++++------ src/app/render/shader_renderer.h | 10 +- src/app/render/simple_renderer.cpp | 19 ++-- src/app/render/simple_renderer.h | 9 +- src/app/ui/editor/editor.cpp | 48 +++++--- src/app/ui/editor/editor_render.cpp | 13 +-- src/app/ui/editor/editor_render.h | 13 ++- src/ui/graphics.cpp | 5 + src/ui/graphics.h | 3 + 11 files changed, 215 insertions(+), 130 deletions(-) diff --git a/src/app/commands/cmd_fullscreen_preview.cpp b/src/app/commands/cmd_fullscreen_preview.cpp index 67745069c..c91f38b8e 100644 --- a/src/app/commands/cmd_fullscreen_preview.cpp +++ b/src/app/commands/cmd_fullscreen_preview.cpp @@ -28,9 +28,11 @@ #include "doc/palette.h" #include "doc/primitives.h" #include "doc/sprite.h" +#include "gfx/matrix.h" #include "os/surface.h" #include "os/system.h" +#include #include #define PREVIEW_TILED 1 @@ -52,14 +54,7 @@ public: , m_sprite(editor->sprite()) , m_pal(m_sprite->palette(editor->frame())) , m_proj(editor->projection()) - , m_index_bg_color(-1) - , m_doublebuf(Image::create( - IMAGE_RGB, - editor->display()->size().w, - editor->display()->size().h)) - , m_doublesur(os::instance()->makeRgbaSurface( - editor->display()->size().w, - editor->display()->size().h)) { + , m_index_bg_color(-1) { // Do not use DocWriter (do not lock the document) because we // will call other sub-commands (e.g. previous frame, next frame, // etc.). @@ -133,8 +128,8 @@ protected: command->id() == CommandId::GotoNextFrame() || command->id() == CommandId::GotoLastFrame())) { m_context->executeCommand(command, params); + m_repaint = true; // Re-render invalidate(); - m_render.reset(nullptr); // Re-render } #if 0 // Play the animation @@ -177,71 +172,100 @@ protected: } virtual void onPaint(PaintEvent& ev) override { - gfx::Size displaySize = display()->size(); Graphics* g = ev.graphics(); EditorRender& render = m_editor->renderEngine(); render.setRefLayersVisiblity(false); - render.setProjection(render::Projection()); render.disableOnionskin(); render.setTransparentBackground(); // Render sprite and leave the result in 'm_render' variable if (m_render == nullptr) { - ImageBufferPtr buf = render.getRenderImageBuffer(); - m_render.reset(Image::create(IMAGE_RGB, - m_sprite->width(), m_sprite->height(), buf)); - - render.renderSprite( - m_render.get(), m_sprite, m_editor->frame()); + m_render = os::instance()->makeRgbaSurface(m_sprite->width(), + m_sprite->height()); + m_repaint = true; } - int x, y, w, h, u, v; - x = m_pos.x + m_proj.applyX(m_proj.removeX(m_delta.x)); - y = m_pos.y + m_proj.applyY(m_proj.removeY(m_delta.y)); + if (m_repaint) { + m_repaint = false; + + m_render->clear(); + render.setProjection(render::Projection()); + render.renderSprite( + m_render.get(), m_sprite, m_editor->frame(), + gfx::ClipF(0, 0, 0, 0, m_sprite->width(), m_sprite->height())); + } + + float x, y, w, h, u, v; + x = m_pos.x + m_delta.x; + y = m_pos.y + m_delta.y; w = m_proj.applyX(m_sprite->width()); h = m_proj.applyY(m_sprite->height()); - if (int(m_tiled) & int(TiledMode::X_AXIS)) x = SGN(x) * (ABS(x)%w); - if (int(m_tiled) & int(TiledMode::Y_AXIS)) y = SGN(y) * (ABS(y)%h); + if (int(m_tiled) & int(TiledMode::X_AXIS)) x = SGN(x) * std::fmod(ABS(x), w); + if (int(m_tiled) & int(TiledMode::Y_AXIS)) y = SGN(y) * std::fmod(ABS(y), h); - render.setProjection(m_proj); if (m_index_bg_color == -1) { - render.setupBackground(m_doc, m_doublebuf->pixelFormat()); + render.setProjection(m_proj); + render.setupBackground(m_doc, IMAGE_RGB); render.renderCheckeredBackground( - m_doublebuf.get(), - gfx::Clip(0, 0, -m_pos.x, -m_pos.y, - m_doublebuf->width(), m_doublebuf->height())); + g->getInternalSurface(), m_sprite, + gfx::Clip(g->getInternalDeltaX(), + g->getInternalDeltaY(), clientBounds())); + + // Invalidate the whole Graphics (as we've just modified its + // internal os::Surface directly). + g->invalidate(g->getClipBounds()); } else { - doc::clear_image(m_doublebuf.get(), m_pal->getEntry(m_index_bg_color)); + auto col = m_pal->getEntry(m_index_bg_color); + g->fillRect(gfx::rgba(doc::rgba_getr(col), + doc::rgba_getg(col), + doc::rgba_getb(col), + doc::rgba_geta(col)), + clientBounds()); } + const double sx = m_proj.scaleX(); + const double sy = m_proj.scaleY(); + + gfx::RectF tiledBounds; + tiledBounds.w = (2+std::ceil(float(clientBounds().w)/w))*w; + tiledBounds.h = (2+std::ceil(float(clientBounds().h)/h))*h; + tiledBounds.x = x-w; + tiledBounds.y = y-h; + g->save(); + switch (m_tiled) { case TiledMode::NONE: - render.renderImage(m_doublebuf.get(), m_render.get(), m_pal, x, y, - 255, doc::BlendMode::NORMAL); + g->setMatrix(gfx::Matrix::MakeTrans(x, y)); + g->concat(gfx::Matrix::MakeScale(sx, sy)); + g->drawRgbaSurface(m_render.get(), 0, 0); break; case TiledMode::X_AXIS: - for (u=x-w; usetMatrix(gfx::Matrix::MakeTrans(u, y)); + g->concat(gfx::Matrix::MakeScale(sx, sy)); + g->drawRgbaSurface(m_render.get(), 0, 0); + } break; case TiledMode::Y_AXIS: - for (v=y-h; vsetMatrix(gfx::Matrix::MakeTrans(x, v)); + g->concat(gfx::Matrix::MakeScale(sx, sy)); + g->drawRgbaSurface(m_render.get(), 0, 0); + } break; case TiledMode::BOTH: - for (v=y-h; vsetMatrix(gfx::Matrix::MakeTrans(u, v)); + g->concat(gfx::Matrix::MakeScale(sx, sy)); + g->drawRgbaSurface(m_render.get(), 0, 0); + } + } break; } - - convert_image_to_surface(m_doublebuf.get(), m_pal, - m_doublesur.get(), 0, 0, 0, 0, m_doublebuf->width(), m_doublebuf->height()); - g->blit(m_doublesur.get(), 0, 0, 0, 0, m_doublesur->width(), m_doublesur->height()); + g->restore(); } private: @@ -255,9 +279,8 @@ private: gfx::Point m_delta; render::Projection m_proj; int m_index_bg_color; - std::unique_ptr m_render; - std::unique_ptr m_doublebuf; - os::SurfaceRef m_doublesur; + os::SurfaceRef m_render; + bool m_repaint = true; filters::TiledMode m_tiled; }; diff --git a/src/app/render/renderer.h b/src/app/render/renderer.h index da28170e8..dd99652c7 100644 --- a/src/app/render/renderer.h +++ b/src/app/render/renderer.h @@ -26,16 +26,38 @@ namespace app { // using render::Render). class Renderer { public: + struct Properties { + // True if the background should be rendered first with a + // renderCheckeredBackground() call (in other case + // renderSprite() will render the background too). This allows + // to draw a background directly on the screen and then the + // sprite in a backbuffer. + bool renderBgOnScreen = false; + + // True if the backbuffer should has alpha channel, i.e. to + // composite the background already painted on the screen with + // the sprite painted in the backbuffer. + bool requiresRgbaBackbuffer = false; + }; + virtual ~Renderer() { } + // Returns properties of the renderer (modifies how the editor + // uses the renderer). + virtual const Properties& properties() const = 0; + + // ---------------------------------------------------------------------- // Basic configuration + virtual void setRefLayersVisiblity(const bool visible) = 0; virtual void setNonactiveLayersOpacity(const int opacity) = 0; virtual void setNewBlendMethod(const bool newBlend) = 0; virtual void setBgOptions(const render::BgOptions& bg) = 0; virtual void setProjection(const render::Projection& projection) = 0; + // ---------------------------------------------------------------------- // Advance configuration (for preview/brushes purposes) + virtual void setSelectedLayer(const doc::Layer* layer) = 0; virtual void setPreviewImage(const doc::Layer* layer, const doc::frame_t frame, @@ -54,15 +76,15 @@ namespace app { virtual void setOnionskin(const render::OnionskinOptions& options) = 0; virtual void disableOnionskin() = 0; + // ---------------------------------------------------------------------- // Compositing - virtual void renderSprite(doc::Image* dstImage, - const doc::Sprite* sprite, - const doc::frame_t frame) = 0; + virtual void renderSprite(os::Surface* dstSurface, const doc::Sprite* sprite, const doc::frame_t frame, const gfx::ClipF& area) = 0; - virtual void renderCheckeredBackground(doc::Image* dstImage, + virtual void renderCheckeredBackground(os::Surface* dstSurface, + const doc::Sprite* sprite, const gfx::Clip& area) = 0; virtual void renderImage(doc::Image* dstImage, const doc::Image* srcImage, diff --git a/src/app/render/shader_renderer.cpp b/src/app/render/shader_renderer.cpp index 8fd6a98a3..718169f57 100644 --- a/src/app/render/shader_renderer.cpp +++ b/src/app/render/shader_renderer.cpp @@ -24,12 +24,11 @@ namespace app { namespace { const char* kBgShaderCode = R"( -uniform half3 iRes, iCanvas, iSrcPos; uniform half4 iBg1, iBg2; uniform half2 iStripeSize; half4 main(vec2 fragcoord) { - vec2 u = (iSrcPos.xy+fragcoord.xy) / iStripeSize.xy; + vec2 u = fragcoord.xy / iStripeSize.xy; return (mod(mod(floor(u.x), 2) + mod(floor(u.y), 2), 2) != 0.0 ? iBg2: iBg1); } )"; @@ -63,6 +62,9 @@ inline SkBlendMode to_skia(const doc::BlendMode bm) { ShaderRenderer::ShaderRenderer() { + m_properties.renderBgOnScreen = true; + m_properties.requiresRgbaBackbuffer = true; + auto result = SkRuntimeEffect::MakeForShader(SkString(kBgShaderCode)); if (!result.errorText.isEmpty()) { LOG(ERROR, "Shader error: %s\n", result.errorText.c_str()); @@ -96,7 +98,7 @@ void ShaderRenderer::setBgOptions(const render::BgOptions& bg) void ShaderRenderer::setProjection(const render::Projection& projection) { - // TODO impl + m_proj = projection; } void ShaderRenderer::setSelectedLayer(const doc::Layer* layer) @@ -144,44 +146,25 @@ void ShaderRenderer::disableOnionskin() // TODO impl } -void ShaderRenderer::renderSprite(doc::Image* dstImage, - const doc::Sprite* sprite, - const doc::frame_t frame) -{ - // TODO impl -} - void ShaderRenderer::renderSprite(os::Surface* dstSurface, const doc::Sprite* sprite, const doc::frame_t frame, const gfx::ClipF& area) { - SkRuntimeShaderBuilder builder(m_bgEffect); - builder.uniform("iRes") = SkV3{float(area.size.w), float(area.size.h), 0.0f}; - builder.uniform("iCanvas") = SkV3{float(sprite->width()), float(sprite->height()), 0.0f}; - builder.uniform("iSrcPos") = SkV3{float(area.src.x), float(area.src.y), 0.0f}; - builder.uniform("iBg1") = gfxColor_to_SkV4( - color_utils::color_for_ui( - app::Color::fromImage(sprite->pixelFormat(), - m_bgOptions.color1))); - builder.uniform("iBg2") = gfxColor_to_SkV4( - color_utils::color_for_ui( - app::Color::fromImage(sprite->pixelFormat(), - m_bgOptions.color2))); - builder.uniform("iStripeSize") = SkV2{ - float(m_bgOptions.stripeSize.w), - float(m_bgOptions.stripeSize.h)}; - SkCanvas* canvas = &static_cast(dstSurface)->canvas(); canvas->save(); { SkPaint p; p.setStyle(SkPaint::kFill_Style); - p.setShader(builder.makeShader()); - + p.setColor(SK_ColorTRANSPARENT); + p.setBlendMode(SkBlendMode::kSrc); canvas->drawRect(SkRect::MakeXYWH(area.dst.x, area.dst.y, area.size.w, area.size.h), p); // Draw cels + canvas->translate(area.dst.x - area.src.x, + area.dst.y - area.src.y); + canvas->scale(m_proj.scaleX(), m_proj.scaleY()); + drawLayerGroup(canvas, sprite, sprite->root(), frame, area); } canvas->restore(); @@ -225,8 +208,8 @@ void ShaderRenderer::drawLayerGroup(SkCanvas* canvas, p.setAlpha(opacity); p.setBlendMode(to_skia(imgLayer->blendMode())); canvas->drawImage(skImg.get(), - SkIntToScalar(area.dst.x + cel->x() - area.src.x), - SkIntToScalar(area.dst.y + cel->y() - area.src.y), + SkIntToScalar(cel->x()), + SkIntToScalar(cel->y()), SkSamplingOptions(), &p); } @@ -247,10 +230,41 @@ void ShaderRenderer::drawLayerGroup(SkCanvas* canvas, } } -void ShaderRenderer::renderCheckeredBackground(doc::Image* dstImage, +void ShaderRenderer::renderCheckeredBackground(os::Surface* dstSurface, + const doc::Sprite* sprite, const gfx::Clip& area) { - // TODO impl + SkRuntimeShaderBuilder builder(m_bgEffect); + builder.uniform("iBg1") = gfxColor_to_SkV4( + color_utils::color_for_ui( + app::Color::fromImage(sprite->pixelFormat(), + m_bgOptions.color1))); + builder.uniform("iBg2") = gfxColor_to_SkV4( + color_utils::color_for_ui( + app::Color::fromImage(sprite->pixelFormat(), + m_bgOptions.color2))); + + float sx = (m_bgOptions.zoom ? m_proj.scaleX(): 1.0); + float sy = (m_bgOptions.zoom ? m_proj.scaleY(): 1.0); + + builder.uniform("iStripeSize") = SkV2{ + float(m_bgOptions.stripeSize.w) * sx, + float(m_bgOptions.stripeSize.h) * sy}; + + SkCanvas* canvas = &static_cast(dstSurface)->canvas(); + canvas->save(); + { + SkPaint p; + p.setStyle(SkPaint::kFill_Style); + p.setShader(builder.makeShader()); + + canvas->translate( + SkIntToScalar(area.dst.x - area.src.x), + SkIntToScalar(area.dst.y - area.src.y)); + canvas->drawRect( + SkRect::MakeXYWH(area.src.x, area.src.y, area.size.w, area.size.h), p); + } + canvas->restore(); } void ShaderRenderer::renderImage(doc::Image* dstImage, diff --git a/src/app/render/shader_renderer.h b/src/app/render/shader_renderer.h index d37fc33f2..60d7a179d 100644 --- a/src/app/render/shader_renderer.h +++ b/src/app/render/shader_renderer.h @@ -26,6 +26,8 @@ namespace app { ShaderRenderer(); ~ShaderRenderer(); + const Properties& properties() const override { return m_properties; } + void setRefLayersVisiblity(const bool visible) override; void setNonactiveLayersOpacity(const int opacity) override; void setNewBlendMethod(const bool newBlend) override; @@ -50,14 +52,12 @@ namespace app { void setOnionskin(const render::OnionskinOptions& options) override; void disableOnionskin() override; - void renderSprite(doc::Image* dstImage, - const doc::Sprite* sprite, - const doc::frame_t frame) override; void renderSprite(os::Surface* dstSurface, const doc::Sprite* sprite, const doc::frame_t frame, const gfx::ClipF& area) override; - void renderCheckeredBackground(doc::Image* dstImage, + void renderCheckeredBackground(os::Surface* dstSurface, + const doc::Sprite* sprite, const gfx::Clip& area) override; void renderImage(doc::Image* dstImage, const doc::Image* srcImage, @@ -74,7 +74,9 @@ namespace app { const doc::frame_t frame, const gfx::ClipF& area); + Properties m_properties; render::BgOptions m_bgOptions; + render::Projection m_proj; sk_sp m_bgEffect; }; diff --git a/src/app/render/simple_renderer.cpp b/src/app/render/simple_renderer.cpp index c0f5109f1..835af6c4b 100644 --- a/src/app/render/simple_renderer.cpp +++ b/src/app/render/simple_renderer.cpp @@ -89,13 +89,6 @@ void SimpleRenderer::disableOnionskin() m_render.disableOnionskin(); } -void SimpleRenderer::renderSprite(doc::Image* dstImage, - const doc::Sprite* sprite, - const doc::frame_t frame) -{ - m_render.renderSprite(dstImage, sprite, frame); -} - void SimpleRenderer::renderSprite(os::Surface* dstSurface, const doc::Sprite* sprite, const doc::frame_t frame, @@ -110,10 +103,18 @@ void SimpleRenderer::renderSprite(os::Surface* dstSurface, dstSurface, 0, 0, 0, 0, area.size.w, area.size.h); } -void SimpleRenderer::renderCheckeredBackground(doc::Image* dstImage, +void SimpleRenderer::renderCheckeredBackground(os::Surface* dstSurface, + const doc::Sprite* sprite, const gfx::Clip& area) { - m_render.renderCheckeredBackground(dstImage, area); + ImageRef dstImage(Image::create( + IMAGE_RGB, area.size.w, area.size.h, + EditorRender::getRenderImageBuffer())); + + m_render.renderCheckeredBackground(dstImage.get(), area); + + convert_image_to_surface(dstImage.get(), sprite->palette(0), + dstSurface, 0, 0, 0, 0, area.size.w, area.size.h); } void SimpleRenderer::renderImage(doc::Image* dstImage, diff --git a/src/app/render/simple_renderer.h b/src/app/render/simple_renderer.h index 61cf2df88..f81eafaa1 100644 --- a/src/app/render/simple_renderer.h +++ b/src/app/render/simple_renderer.h @@ -17,6 +17,8 @@ namespace app { // CPU-only. class SimpleRenderer : public Renderer { public: + const Properties& properties() const override { return m_properties; } + void setRefLayersVisiblity(const bool visible) override; void setNonactiveLayersOpacity(const int opacity) override; void setNewBlendMethod(const bool newBlend) override; @@ -41,14 +43,12 @@ namespace app { void setOnionskin(const render::OnionskinOptions& options) override; void disableOnionskin() override; - void renderSprite(doc::Image* dstImage, - const doc::Sprite* sprite, - const doc::frame_t frame) override; void renderSprite(os::Surface* dstSurface, const doc::Sprite* sprite, const doc::frame_t frame, const gfx::ClipF& area) override; - void renderCheckeredBackground(doc::Image* dstImage, + void renderCheckeredBackground(os::Surface* dstSurface, + const doc::Sprite* sprite, const gfx::Clip& area) override; void renderImage(doc::Image* dstImage, const doc::Image* srcImage, @@ -58,6 +58,7 @@ namespace app { const int opacity, const doc::BlendMode blendMode) override; private: + Properties m_properties; render::Render m_render; }; diff --git a/src/app/ui/editor/editor.cpp b/src/app/ui/editor/editor.cpp index 0299a4b7f..6f0ecfec5 100644 --- a/src/app/ui/editor/editor.cpp +++ b/src/app/ui/editor/editor.cpp @@ -662,23 +662,13 @@ void Editor::drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& sprite // Convert the render to a os::Surface static os::SurfaceRef rendered = nullptr; // TODO move this to other centralized place + const auto& renderProperties = m_renderEngine->properties(); try { // Generate a "expose sprite pixels" notification. This is used by // tool managers that need to validate this region (copy pixels from // the original cel) before it can be used by the RenderEngine. m_document->notifyExposeSpritePixels(m_sprite, gfx::Region(expose)); - // Create a temporary surface to draw the sprite on it - if (!rendered || - rendered->width() < rc2.w || - rendered->height() < rc2.h || - rendered->colorSpace() != m_document->osColorSpace()) { - const int maxw = std::max(rc2.w, rendered ? rendered->width(): 0); - const int maxh = std::max(rc2.h, rendered ? rendered->height(): 0); - rendered = os::instance()->makeSurface( - maxw, maxh, m_document->osColorSpace()); - } - m_renderEngine->setNewBlendMethod(pref.experimental.newBlend()); m_renderEngine->setRefLayersVisiblity(true); m_renderEngine->setSelectedLayer(m_layer); @@ -686,8 +676,6 @@ void Editor::drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& sprite m_renderEngine->setNonactiveLayersOpacity(pref.experimental.nonactiveLayersOpacity()); else m_renderEngine->setNonactiveLayersOpacity(255); - m_renderEngine->setProjection( - newEngine ? render::Projection(): m_proj); m_renderEngine->setupBackground(m_document, IMAGE_RGB); m_renderEngine->disableOnionskin(); @@ -727,6 +715,32 @@ void Editor::drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& sprite m_layer, m_frame); } + // Render background first (e.g. new ShaderRenderer will paint the + // background on the screen first and then composite the rendered + // sprite on it.) + if (renderProperties.renderBgOnScreen) { + m_renderEngine->setProjection(m_proj); + m_renderEngine->renderCheckeredBackground( + g->getInternalSurface(), + m_sprite, + gfx::Clip(dest.x + g->getInternalDeltaX(), + dest.y + g->getInternalDeltaY(), + m_proj.apply(rc2))); + } + + // Create a temporary surface to draw the sprite on it + if (!rendered || + rendered->width() < rc2.w || + rendered->height() < rc2.h || + rendered->colorSpace() != m_document->osColorSpace()) { + const int maxw = std::max(rc2.w, rendered ? rendered->width(): 0); + const int maxh = std::max(rc2.h, rendered ? rendered->height(): 0); + rendered = os::instance()->makeRgbaSurface( + maxw, maxh, m_document->osColorSpace()); + } + + m_renderEngine->setProjection( + newEngine ? render::Projection(): m_proj); m_renderEngine->renderSprite( rendered.get(), m_sprite, m_frame, gfx::Clip(0, 0, rc2)); @@ -763,11 +777,17 @@ void Editor::drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& sprite } } + os::Paint p; + if (renderProperties.requiresRgbaBackbuffer) + p.blendMode(os::BlendMode::SrcOver); + else + p.blendMode(os::BlendMode::Src); + g->drawSurface(rendered.get(), gfx::Rect(0, 0, rc2.w, rc2.h), dest, sampling, - nullptr); + &p); } else { g->blit(rendered.get(), 0, 0, dest.x, dest.y, dest.w, dest.h); diff --git a/src/app/ui/editor/editor_render.cpp b/src/app/ui/editor/editor_render.cpp index f0879be48..b29261ff8 100644 --- a/src/app/ui/editor/editor_render.cpp +++ b/src/app/ui/editor/editor_render.cpp @@ -175,14 +175,6 @@ void EditorRender::disableOnionskin() m_renderer->disableOnionskin(); } -void EditorRender::renderSprite( - doc::Image* dstImage, - const doc::Sprite* sprite, - doc::frame_t frame) -{ - m_renderer->renderSprite(dstImage, sprite, frame); -} - void EditorRender::renderSprite( os::Surface* dstSurface, const doc::Sprite* sprite, @@ -193,10 +185,11 @@ void EditorRender::renderSprite( } void EditorRender::renderCheckeredBackground( - doc::Image* image, + os::Surface* dstSurface, + const doc::Sprite* sprite, const gfx::Clip& area) { - m_renderer->renderCheckeredBackground(image, area); + m_renderer->renderCheckeredBackground(dstSurface, sprite, area); } void EditorRender::renderImage( diff --git a/src/app/ui/editor/editor_render.h b/src/app/ui/editor/editor_render.h index dc18b70f3..1e48f83e8 100644 --- a/src/app/ui/editor/editor_render.h +++ b/src/app/ui/editor/editor_render.h @@ -9,6 +9,7 @@ #define APP_UI_EDITOR_RENDER_H_INCLUDED #pragma once +#include "app/render/renderer.h" #include "doc/blend_mode.h" #include "doc/color.h" #include "doc/frame.h" @@ -35,7 +36,6 @@ namespace os { namespace app { class Doc; - class Renderer; class EditorRender { public: @@ -50,6 +50,10 @@ namespace app { Type type() const; void setType(const Type type); + const Renderer::Properties& properties() const { + return m_renderer->properties(); + } + void setRefLayersVisiblity(const bool visible); void setNonactiveLayersOpacity(const int opacity); void setNewBlendMethod(const bool newBlend); @@ -81,17 +85,14 @@ namespace app { void setOnionskin(const render::OnionskinOptions& options); void disableOnionskin(); - void renderSprite( - doc::Image* dstImage, - const doc::Sprite* sprite, - doc::frame_t frame); void renderSprite( os::Surface* dstSurface, const doc::Sprite* sprite, doc::frame_t frame, const gfx::ClipF& area); void renderCheckeredBackground( - doc::Image* image, + os::Surface* dstSurface, + const doc::Sprite* sprite, const gfx::Clip& area); void renderImage( doc::Image* dst_image, diff --git a/src/ui/graphics.cpp b/src/ui/graphics.cpp index d99faa92a..bd6b537c9 100644 --- a/src/ui/graphics.cpp +++ b/src/ui/graphics.cpp @@ -589,6 +589,11 @@ gfx::Size Graphics::doUIStringAlgorithm(const std::string& str, gfx::Color fg, g return calculatedSize; } +void Graphics::invalidate(const gfx::Rect& bounds) +{ + dirty(gfx::Rect(bounds).offset(m_dx, m_dy)); +} + void Graphics::dirty(const gfx::Rect& bounds) { gfx::Rect rc = m_surface->getClipBounds(); diff --git a/src/ui/graphics.h b/src/ui/graphics.h index ef8aa5f97..f80495327 100644 --- a/src/ui/graphics.h +++ b/src/ui/graphics.h @@ -116,6 +116,9 @@ namespace ui { static int measureUITextLength(const std::string& str, os::Font* font); gfx::Size fitString(const std::string& str, int maxWidth, int align); + // Can be used in case you access/modify getInternalSurface() directly. + void invalidate(const gfx::Rect& bounds); + private: gfx::Size doUIStringAlgorithm(const std::string& str, gfx::Color fg, gfx::Color bg, const gfx::Rect& rc, int align, bool draw); void dirty(const gfx::Rect& bounds);