mirror of
https://github.com/aseprite/aseprite.git
synced 2025-02-11 00:40:08 +00:00
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().
This commit is contained in:
parent
3c099dc4dc
commit
8c7b94a934
@ -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 <cmath>
|
||||
#include <cstring>
|
||||
|
||||
#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; u<displaySize.w+w; u+=w)
|
||||
render.renderImage(m_doublebuf.get(), m_render.get(), m_pal, u, y,
|
||||
255, doc::BlendMode::NORMAL);
|
||||
for (u=tiledBounds.x; u<tiledBounds.x2(); u+=w) {
|
||||
g->setMatrix(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; v<displaySize.h+h; v+=h)
|
||||
render.renderImage(m_doublebuf.get(), m_render.get(), m_pal, x, v,
|
||||
255, doc::BlendMode::NORMAL);
|
||||
for (v=tiledBounds.y; v<tiledBounds.y2(); v+=h) {
|
||||
g->setMatrix(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; v<displaySize.h+h; v+=h)
|
||||
for (u=x-w; u<displaySize.w+w; u+=w)
|
||||
render.renderImage(m_doublebuf.get(), m_render.get(), m_pal, u, v,
|
||||
255, doc::BlendMode::NORMAL);
|
||||
for (v=tiledBounds.y; v<tiledBounds.y2(); v+=h) {
|
||||
for (u=tiledBounds.x; u<tiledBounds.x2(); u+=w) {
|
||||
g->setMatrix(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<Image> m_render;
|
||||
std::unique_ptr<Image> m_doublebuf;
|
||||
os::SurfaceRef m_doublesur;
|
||||
os::SurfaceRef m_render;
|
||||
bool m_repaint = true;
|
||||
filters::TiledMode m_tiled;
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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<os::SkiaSurface*>(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<os::SkiaSurface*>(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,
|
||||
|
@ -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<SkRuntimeEffect> m_bgEffect;
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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(
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user