Add pixel ratio support to the Editor & Render

This commit is contained in:
David Capello 2016-05-23 19:22:02 -03:00
parent 73bda9bd19
commit 37209a0f5b
14 changed files with 413 additions and 274 deletions

View File

@ -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
@ -51,7 +51,7 @@ public:
, m_doc(editor->document())
, m_sprite(editor->sprite())
, m_pal(m_sprite->palette(editor->frame()))
, m_zoom(editor->zoom())
, m_proj(editor->projection())
, m_index_bg_color(-1)
, m_doublebuf(Image::create(IMAGE_RGB, ui::display_w(), ui::display_h()))
, m_doublesur(she::instance()->createRgbaSurface(ui::display_w(), ui::display_h())) {
@ -174,11 +174,12 @@ protected:
virtual void onPaint(PaintEvent& ev) override {
Graphics* g = ev.graphics();
AppRender& render = m_editor->renderEngine();
render.setProjection(render::Projection());
render.disableOnionskin();
render.setBgType(render::BgType::TRANSPARENT);
// Render sprite and leave the result in 'm_render' variable
if (m_render == NULL) {
if (m_render == nullptr) {
ImageBufferPtr buf = Editor::getRenderImageBuffer();
m_render.reset(Image::create(IMAGE_RGB,
m_sprite->width(), m_sprite->height(), buf));
@ -188,19 +189,20 @@ protected:
}
int x, y, w, h, u, v;
x = m_pos.x + m_zoom.apply(m_zoom.remove(m_delta.x));
y = m_pos.y + m_zoom.apply(m_zoom.remove(m_delta.y));
w = m_zoom.apply(m_sprite->width());
h = m_zoom.apply(m_sprite->height());
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));
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);
render.setProjection(m_proj);
if (m_index_bg_color == -1) {
render.setupBackground(m_doc, m_doublebuf->pixelFormat());
render.renderBackground(m_doublebuf,
gfx::Clip(0, 0, -m_pos.x, -m_pos.y,
m_doublebuf->width(), m_doublebuf->height()), m_zoom);
m_doublebuf->width(), m_doublebuf->height()));
}
else {
doc::clear_image(m_doublebuf, m_pal->getEntry(m_index_bg_color));
@ -209,23 +211,23 @@ protected:
switch (m_tiled) {
case TiledMode::NONE:
render.renderImage(m_doublebuf, m_render, m_pal, x, y,
m_zoom, 255, BlendMode::NORMAL);
255, BlendMode::NORMAL);
break;
case TiledMode::X_AXIS:
for (u=x-w; u<ui::display_w()+w; u+=w)
render.renderImage(m_doublebuf, m_render, m_pal, u, y,
m_zoom, 255, BlendMode::NORMAL);
255, BlendMode::NORMAL);
break;
case TiledMode::Y_AXIS:
for (v=y-h; v<ui::display_h()+h; v+=h)
render.renderImage(m_doublebuf, m_render, m_pal, x, v,
m_zoom, 255, BlendMode::NORMAL);
255, BlendMode::NORMAL);
break;
case TiledMode::BOTH:
for (v=y-h; v<ui::display_h()+h; v+=h)
for (u=x-w; u<ui::display_w()+w; u+=w)
render.renderImage(m_doublebuf, m_render, m_pal, u, v,
m_zoom, 255, BlendMode::NORMAL);
255, BlendMode::NORMAL);
break;
}
@ -243,7 +245,7 @@ private:
gfx::Point m_pos;
gfx::Point m_oldMousePos;
gfx::Point m_delta;
render::Zoom m_zoom;
render::Projection m_proj;
int m_index_bg_color;
base::UniquePtr<Image> m_render;
base::UniquePtr<Image> m_doublebuf;

View File

@ -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
@ -258,9 +258,9 @@ void FilterManagerImpl::flush()
m_x+m_offset_x,
m_y+m_offset_y+m_row-1)),
gfx::Size(
editor->zoom().apply(m_w),
(editor->zoom().scale() >= 1 ? editor->zoom().apply(1):
editor->zoom().remove(1))));
editor->projection().applyX(m_w),
(editor->projection().scaleY() >= 1 ? editor->projection().applyY(1):
editor->projection().removeY(1))));
gfx::Region reg1(rect);
gfx::Region reg2;

View File

@ -408,19 +408,22 @@ void BrushPreview::traceSelectionCrossPixels(
0, 0, 1, 1, 0, 0,
};
gfx::Point out, outpt = m_editor->editorToScreen(pt);
int u, v;
int size = m_editor->zoom().apply(thickness/2);
int size2 = m_editor->zoom().apply(thickness);
if (size2 == 0) size2 = 1;
const render::Projection& proj = m_editor->projection();
gfx::Size size(proj.applyX(thickness/2),
proj.applyY(thickness/2));
gfx::Size size2(proj.applyX(thickness),
proj.applyY(thickness));
if (size2.w == 0) size2.w = 1;
if (size2.h == 0) size2.h = 1;
for (v=0; v<6; v++) {
for (u=0; u<6; u++) {
for (int v=0; v<6; v++) {
for (int u=0; u<6; u++) {
if (!cross[v*6+u])
continue;
out = outpt;
out.x += ((u<3) ? u-size-3: u-size-3+size2);
out.y += ((v<3) ? v-size-3: v-size-3+size2);
out.x += ((u<3) ? u-size.w-3: u-size.w-3+size2.w);
out.y += ((v<3) ? v-size.h-3: v-size.h-3+size2.h);
(this->*pixelDelegate)(g, out, color);
}

View File

@ -66,38 +66,38 @@ using namespace render;
class EditorPreRenderImpl : public EditorPreRender {
public:
EditorPreRenderImpl(Editor* editor, Image* image, const Point& offset, Zoom zoom)
EditorPreRenderImpl(Editor* editor, Image* image,
const Point& offset,
const Projection& proj)
: m_editor(editor)
, m_image(image)
, m_offset(offset)
, m_zoom(zoom)
{
, m_proj(proj) {
}
Editor* getEditor() override
{
Editor* getEditor() override {
return m_editor;
}
Image* getImage() override
{
Image* getImage() override {
return m_image;
}
void fillRect(const gfx::Rect& rect, uint32_t rgbaColor, int opacity) override
{
blend_rect(m_image,
m_offset.x + m_zoom.apply(rect.x),
m_offset.y + m_zoom.apply(rect.y),
m_offset.x + m_zoom.apply(rect.x+rect.w) - 1,
m_offset.y + m_zoom.apply(rect.y+rect.h) - 1, rgbaColor, opacity);
blend_rect(
m_image,
m_offset.x + m_proj.applyX(rect.x),
m_offset.y + m_proj.applyY(rect.y),
m_offset.x + m_proj.applyX(rect.x+rect.w) - 1,
m_offset.y + m_proj.applyY(rect.y+rect.h) - 1, rgbaColor, opacity);
}
private:
Editor* m_editor;
Image* m_image;
Point m_offset;
Zoom m_zoom;
Projection m_proj;
};
class EditorPostRenderImpl : public EditorPostRender {
@ -154,7 +154,6 @@ Editor::Editor(Document* document, EditorFlags flags)
, m_sprite(m_document->sprite())
, m_layer(m_sprite->folder()->getFirstLayer())
, m_frame(frame_t(0))
, m_zoom(1, 1)
, m_docPref(Preferences::instance().document(document))
, m_brushPreview(this)
, m_lastDrawingPosition(-1, -1)
@ -169,6 +168,8 @@ Editor::Editor(Document* document, EditorFlags flags)
, m_secondaryButton(false)
, m_aniSpeed(1.0)
{
m_proj.setPixelRatio(m_sprite->pixelRatio());
// Add the first state into the history.
m_statesHistory.push(m_state);
@ -365,15 +366,15 @@ Site Editor::getSite() const
void Editor::setZoom(const render::Zoom& zoom)
{
if (m_zoom != zoom) {
m_zoom = zoom;
if (m_proj.zoom() != zoom) {
m_proj.setZoom(zoom);
notifyZoomChanged();
}
else {
// Just copy the zoom as the internal "Zoom::m_internalScale"
// value might be different and we want to keep this value updated
// for better zooming experience in StateWithWheelBehavior.
m_zoom = zoom;
m_proj.setZoom(zoom);
}
}
@ -384,8 +385,8 @@ void Editor::setDefaultScroll()
setEditorScroll(
gfx::Point(
m_padding.x - vp.w/2 + m_zoom.apply(m_sprite->width())/2,
m_padding.y - vp.h/2 + m_zoom.apply(m_sprite->height())/2));
m_padding.x - vp.w/2 + m_proj.applyX(m_sprite->width())/2,
m_padding.y - vp.h/2 + m_proj.applyY(m_sprite->height())/2));
}
// Sets the scroll position of the editor
@ -410,7 +411,7 @@ void Editor::drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& sprite
{
// Clip from sprite and apply zoom
gfx::Rect rc = m_sprite->bounds().createIntersection(spriteRectToDraw);
rc = m_zoom.apply(rc);
rc = m_proj.apply(rc);
int dest_x = dx + m_padding.x + rc.x;
int dest_y = dy + m_padding.y + rc.y;
@ -447,26 +448,33 @@ void Editor::drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& sprite
// tool managers that need to validate this region (copy pixels from
// the original cel) before it can be used by the RenderEngine.
{
gfx::Rect expose = m_zoom.remove(rc);
gfx::Rect expose = m_proj.remove(rc);
// If the zoom level is less than 100%, we add extra pixels to
// the exposed area. Those pixels could be shown in the
// rendering process depending on each cel position.
// E.g. when we are drawing in a cel with position < (0,0)
if (m_zoom.scale() < 1.0) {
expose.enlarge(int(1./m_zoom.scale()));
}
if (m_proj.scaleX() < 1.0)
expose.enlargeXW(int(1./m_proj.scaleX()));
// If the zoom level is more than %100 we add an extra pixel to
// expose just in case the zoom requires to display it. Note:
// this is really necessary to avoid showing invalid destination
// areas in ToolLoopImpl.
else if (m_zoom.scale() > 1.0) {
expose.enlarge(1);
}
else if (m_proj.scaleX() > 1.0)
expose.enlargeXW(1);
if (m_proj.scaleY() < 1.0)
expose.enlargeYH(int(1./m_proj.scaleY()));
else if (m_proj.scaleY() > 1.0)
expose.enlargeYH(1);
m_document->notifyExposeSpritePixels(m_sprite, gfx::Region(expose));
}
// Create a temporary RGB bitmap to draw all to it
rendered.reset(Image::create(IMAGE_RGB, rc.w, rc.h, m_renderBuffer));
m_renderEngine.setProjection(m_proj);
m_renderEngine.setupBackground(m_document, rendered->pixelFormat());
m_renderEngine.disableOnionskin();
@ -505,8 +513,8 @@ void Editor::drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& sprite
m_layer, m_frame);
}
m_renderEngine.renderSprite(rendered, m_sprite, m_frame,
gfx::Clip(0, 0, rc), m_zoom);
m_renderEngine.renderSprite(
rendered, m_sprite, m_frame, gfx::Clip(0, 0, rc));
m_renderEngine.removeExtraImage();
}
@ -518,7 +526,7 @@ void Editor::drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& sprite
// Pre-render decorator.
if ((m_flags & kShowDecorators) && m_decorator) {
EditorPreRenderImpl preRender(this, rendered,
Point(-rc.x, -rc.y), m_zoom);
Point(-rc.x, -rc.y), m_proj);
m_decorator->preRenderDecorator(&preRender);
}
@ -549,15 +557,15 @@ void Editor::drawSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& _rc)
gfx::Rect rc = _rc;
// For odd zoom scales minor than 100% we have to add an extra window
// just to make sure the whole rectangle is drawn.
if (m_zoom.scale() < 1.0)
rc.inflate(int(1./m_zoom.scale()), int(1./m_zoom.scale()));
if (m_proj.scaleX() < 1.0) rc.w += int(1./m_proj.scaleX());
if (m_proj.scaleY() < 1.0) rc.h += int(1./m_proj.scaleY());
gfx::Rect client = clientBounds();
gfx::Rect spriteRect(
client.x + m_padding.x,
client.y + m_padding.y,
m_zoom.apply(m_sprite->width()),
m_zoom.apply(m_sprite->height()));
m_proj.applyX(m_sprite->width()),
m_proj.applyY(m_sprite->height()));
gfx::Rect enclosingRect = spriteRect;
// Draw the main sprite at the center.
@ -611,11 +619,11 @@ void Editor::drawSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& _rc)
IntersectClip clip(g, cliprc);
// Draw the pixel grid
if ((m_zoom.scale() > 2.0) && m_docPref.show.pixelGrid()) {
if ((m_proj.zoom().scale() > 2.0) && m_docPref.show.pixelGrid()) {
int alpha = m_docPref.pixelGrid.opacity();
if (m_docPref.pixelGrid.autoOpacity()) {
alpha = int(alpha * (m_zoom.scale()-2.) / (16.-2.));
alpha = int(alpha * (m_proj.zoom().scale()-2.) / (16.-2.));
alpha = MID(0, alpha, 255);
}
@ -626,12 +634,13 @@ void Editor::drawSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& _rc)
// Draw the grid
if (m_docPref.show.grid()) {
gfx::Rect gridrc = m_docPref.grid.bounds();
if (m_zoom.apply(gridrc.w) > 2 &&
m_zoom.apply(gridrc.h) > 2) {
if (m_proj.applyX(gridrc.w) > 2 &&
m_proj.applyY(gridrc.h) > 2) {
int alpha = m_docPref.grid.opacity();
if (m_docPref.grid.autoOpacity()) {
double len = (m_zoom.apply(gridrc.w) + m_zoom.apply(gridrc.h)) / 2.;
double len = (m_proj.applyX(gridrc.w) +
m_proj.applyY(gridrc.h)) / 2.;
alpha = int(alpha * len / 32.);
alpha = MID(0, alpha, 255);
}
@ -657,7 +666,7 @@ void Editor::drawSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& _rc)
if (x > 0) {
gfx::Color color = color_utils::color_for_ui(m_docPref.grid.color());
g->drawVLine(color,
spriteRect.x + m_zoom.apply(x),
spriteRect.x + m_proj.applyX(x),
enclosingRect.y,
enclosingRect.h);
}
@ -669,7 +678,7 @@ void Editor::drawSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& _rc)
gfx::Color color = color_utils::color_for_ui(m_docPref.grid.color());
g->drawHLine(color,
enclosingRect.x,
spriteRect.y + m_zoom.apply(y),
spriteRect.y + m_proj.applyY(y),
enclosingRect.w);
}
break;
@ -747,13 +756,16 @@ void Editor::drawMask(Graphics* g)
for (const auto& seg : *m_document->getMaskBoundaries()) {
CheckedDrawMode checked(g, m_antsOffset);
gfx::Rect bounds = m_zoom.apply(seg.bounds());
gfx::Rect bounds = m_proj.apply(seg.bounds());
if (m_zoom.scale() >= 1.0) {
if (!seg.open()) {
if (seg.vertical()) --bounds.x;
else --bounds.y;
}
if (m_proj.scaleX() >= 1.0) {
if (!seg.open() && seg.vertical())
--bounds.x;
}
if (m_proj.scaleY() >= 1.0) {
if (!seg.open() && !seg.vertical())
--bounds.y;
}
// The color doesn't matter, we are using CheckedDrawMode
@ -945,8 +957,8 @@ gfx::Point Editor::screenToEditor(const gfx::Point& pt)
Point scroll = view->viewScroll();
return gfx::Point(
m_zoom.remove(pt.x - vp.x + scroll.x - m_padding.x),
m_zoom.remove(pt.y - vp.y + scroll.y - m_padding.y));
m_proj.removeX(pt.x - vp.x + scroll.x - m_padding.x),
m_proj.removeY(pt.y - vp.y + scroll.y - m_padding.y));
}
Point Editor::editorToScreen(const gfx::Point& pt)
@ -956,8 +968,8 @@ Point Editor::editorToScreen(const gfx::Point& pt)
Point scroll = view->viewScroll();
return Point(
(vp.x - scroll.x + m_padding.x + m_zoom.apply(pt.x)),
(vp.y - scroll.y + m_padding.y + m_zoom.apply(pt.y)));
(vp.x - scroll.x + m_padding.x + m_proj.applyX(pt.x)),
(vp.y - scroll.y + m_padding.y + m_proj.applyY(pt.y)));
}
Rect Editor::screenToEditor(const Rect& rc)
@ -1013,8 +1025,8 @@ void Editor::centerInSpritePoint(const gfx::Point& spritePos)
Rect vp = view->viewportBounds();
gfx::Point scroll(
m_padding.x - (vp.w/2) + m_zoom.apply(1)/2 + m_zoom.apply(spritePos.x),
m_padding.y - (vp.h/2) + m_zoom.apply(1)/2 + m_zoom.apply(spritePos.y));
m_padding.x - (vp.w/2) + m_proj.applyX(1)/2 + m_proj.applyX(spritePos.x),
m_padding.y - (vp.h/2) + m_proj.applyY(1)/2 + m_proj.applyY(spritePos.y));
updateEditor();
setEditorScroll(scroll);
@ -1316,9 +1328,9 @@ void Editor::onSizeHint(SizeHintEvent& ev)
gfx::Size sz(0, 0);
if (m_sprite) {
gfx::Point padding = calcExtraPadding(m_zoom);
sz.w = m_zoom.apply(m_sprite->width()) + padding.x*2;
sz.h = m_zoom.apply(m_sprite->height()) + padding.y*2;
gfx::Point padding = calcExtraPadding(m_proj);
sz.w = m_proj.applyX(m_sprite->width()) + padding.x*2;
sz.h = m_proj.applyY(m_sprite->height()) + padding.y*2;
}
else {
sz.w = 4;
@ -1330,7 +1342,7 @@ void Editor::onSizeHint(SizeHintEvent& ev)
void Editor::onResize(ui::ResizeEvent& ev)
{
Widget::onResize(ev);
m_padding = calcExtraPadding(m_zoom);
m_padding = calcExtraPadding(m_proj);
}
void Editor::onPaint(ui::PaintEvent& ev)
@ -1440,11 +1452,14 @@ bool Editor::isInsideSelection()
}
void Editor::setZoomAndCenterInMouse(const Zoom& zoom,
const gfx::Point& mousePos, ZoomBehavior zoomBehavior)
const gfx::Point& mousePos,
ZoomBehavior zoomBehavior)
{
HideBrushPreview hide(m_brushPreview);
View* view = View::getView(this);
Rect vp = view->viewportBounds();
Projection proj = m_proj;
proj.setZoom(zoom);
gfx::Point screenPos;
gfx::Point spritePos;
@ -1461,27 +1476,36 @@ void Editor::setZoomAndCenterInMouse(const Zoom& zoom,
}
spritePos = screenToEditor(screenPos);
if (zoomBehavior == ZoomBehavior::MOUSE &&
m_zoom.scale() > 1.0) {
if (zoomBehavior == ZoomBehavior::MOUSE) {
gfx::Point screenPos2 = editorToScreen(spritePos);
subpixelPos.x = (0.5 + screenPos.x - screenPos2.x) / m_zoom.scale();
subpixelPos.y = (0.5 + screenPos.y - screenPos2.y) / m_zoom.scale();
if (zoom.scale() > m_zoom.scale()) {
double t = 1.0 / zoom.scale();
if (subpixelPos.x >= 0.5-t && subpixelPos.x <= 0.5+t) subpixelPos.x = 0.5;
if (subpixelPos.y >= 0.5-t && subpixelPos.y <= 0.5+t) subpixelPos.y = 0.5;
if (m_proj.scaleX() > 1.0) {
subpixelPos.x = (0.5 + screenPos.x - screenPos2.x) / m_proj.scaleX();
if (proj.scaleX() > m_proj.scaleX()) {
double t = 1.0 / proj.scaleX();
if (subpixelPos.x >= 0.5-t && subpixelPos.x <= 0.5+t)
subpixelPos.x = 0.5;
}
}
if (m_proj.scaleY() > 1.0) {
subpixelPos.y = (0.5 + screenPos.y - screenPos2.y) / m_proj.scaleY();
if (proj.scaleY() > m_proj.scaleY()) {
double t = 1.0 / proj.scaleY();
if (subpixelPos.y >= 0.5-t && subpixelPos.y <= 0.5+t)
subpixelPos.y = 0.5;
}
}
}
gfx::Point padding = calcExtraPadding(zoom);
gfx::Point padding = calcExtraPadding(proj);
gfx::Point scrollPos(
padding.x - (screenPos.x-vp.x) + zoom.apply(spritePos.x+zoom.remove(1)/2) + int(zoom.apply(subpixelPos.x)),
padding.y - (screenPos.y-vp.y) + zoom.apply(spritePos.y+zoom.remove(1)/2) + int(zoom.apply(subpixelPos.y)));
padding.x - (screenPos.x-vp.x) + proj.applyX(spritePos.x+proj.removeX(1)/2) + int(proj.applyX(subpixelPos.x)),
padding.y - (screenPos.y-vp.y) + proj.applyY(spritePos.y+proj.removeY(1)/2) + int(proj.applyY(subpixelPos.y)));
setZoom(zoom);
if ((m_zoom != zoom) || (screenPos != view->viewScroll())) {
if ((m_proj.zoom() != zoom) || (screenPos != view->viewScroll())) {
updateEditor();
setEditorScroll(scrollPos);
}
@ -1675,14 +1699,14 @@ ImageBufferPtr Editor::getRenderImageBuffer()
}
// static
gfx::Point Editor::calcExtraPadding(const Zoom& zoom)
gfx::Point Editor::calcExtraPadding(const Projection& proj)
{
View* view = View::getView(this);
if (view) {
Rect vp = view->viewportBounds();
return gfx::Point(
std::max<int>(vp.w/2, vp.w - zoom.apply(m_sprite->width())),
std::max<int>(vp.h/2, vp.h - zoom.apply(m_sprite->height())));
std::max<int>(vp.w/2, vp.w - proj.applyX(m_sprite->width())),
std::max<int>(vp.h/2, vp.h - proj.applyY(m_sprite->height())));
}
else
return gfx::Point(0, 0);

View File

@ -131,7 +131,8 @@ namespace app {
void setLayer(const Layer* layer);
void setFrame(frame_t frame);
const render::Zoom& zoom() const { return m_zoom; }
const render::Projection& projection() const { return m_proj; }
const render::Zoom& zoom() const { return m_proj.zoom(); }
const gfx::Point& padding() const { return m_padding; }
void setZoom(const render::Zoom& zoom);
@ -260,7 +261,7 @@ namespace app {
// routine.
void drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& rc, int dx, int dy);
gfx::Point calcExtraPadding(const render::Zoom& zoom);
gfx::Point calcExtraPadding(const render::Projection& proj);
void invalidateIfActive();
@ -278,7 +279,7 @@ namespace app {
Sprite* m_sprite; // Active sprite in the editor
Layer* m_layer; // Active layer in the editor
frame_t m_frame; // Active frame in the editor
render::Zoom m_zoom; // Zoom in the editor
render::Projection m_proj; // Zoom/pixel ratio in the editor
DocumentPreferences& m_docPref;
// Brush preview

View File

@ -266,11 +266,11 @@ void SelectBoxState::preRenderDecorator(EditorPreRender* render)
void SelectBoxState::postRenderDecorator(EditorPostRender* render)
{
Editor* editor = render->getEditor();
render::Zoom zoom = editor->zoom();
render::Projection proj = editor->projection();
gfx::Rect sp = editor->sprite()->bounds();
gfx::Rect vp = View::getView(editor)->viewportBounds();
vp.w += zoom.apply(1);
vp.h += zoom.apply(1);
vp.w += proj.applyX(1);
vp.h += proj.applyY(1);
vp = editor->screenToEditor(vp);
// Paint a grid generated by the box

View File

@ -312,8 +312,7 @@ public:
m_floodfillSrcImage,
m_sprite,
m_frame,
gfx::Clip(m_sprite->bounds()),
render::Zoom(1, 1));
gfx::Clip(m_sprite->bounds()));
}
else {
Cel* cel = m_layer->cel(m_frame);

View File

@ -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
@ -179,8 +179,8 @@ gfx::Rect TransformHandles::getPivotHandleBounds(Editor* editor,
gfx::Size partSize = theme->parts.pivotHandle()->size();
gfx::Point screenPivotPos = editor->editorToScreen(transform.pivot());
screenPivotPos.x += editor->zoom().apply(1) / 2;
screenPivotPos.y += editor->zoom().apply(1) / 2;
screenPivotPos.x += editor->projection().applyX(1) / 2;
screenPivotPos.y += editor->projection().applyY(1) / 2;
return gfx::Rect(
screenPivotPos.x-partSize.w/2,

View File

@ -1,5 +1,5 @@
// Aseprite Document 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.
@ -28,6 +28,7 @@
#include "doc/palette.h"
#include "doc/palette_picks.h"
#include "doc/pixel_format.h"
#include "doc/pixel_ratio.h"
#include "doc/primitives.h"
#include "doc/primitives_fast.h"
#include "doc/remap.h"

View File

@ -1,5 +1,5 @@
// Aseprite Gfx Library
// Copyright (C) 2001-2013, 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.
@ -175,6 +175,18 @@ public:
return *this;
}
RectT& enlargeXW(const T& unit) {
x -= unit;
w += unit<<1;
return *this;
}
RectT& enlargeYH(const T& unit) {
y -= unit;
h += unit<<1;
return *this;
}
RectT& shrink(const T& unit) {
x += unit;
y += unit;
@ -259,6 +271,22 @@ public:
return *this;
}
RectT& operator*=(const SizeT<T>& size) const {
x *= size.w;
y *= size.h;
w *= size.w;
h *= size.h;
return *this;
}
RectT& operator/=(const SizeT<T>& size) const {
x /= size.w;
y /= size.h;
w /= size.w;
h /= size.h;
return *this;
}
const RectT& operator|=(const RectT& rc) {
return *this = createUnion(rc);
}
@ -283,6 +311,16 @@ public:
return createIntersection(other);
}
RectT operator*(const SizeT<T>& size) const {
return RectT(x*size.w, y*size.h,
w*size.w, h*size.h);
}
RectT operator/(const SizeT<T>& size) const {
return RectT(x/size.w, y/size.h,
w/size.w, h/size.h);
}
bool operator==(const RectT& rc) const {
return
x == rc.x && w == rc.w &&

73
src/render/projection.h Normal file
View File

@ -0,0 +1,73 @@
// Aseprite Render Library
// Copyright (c) 2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef RENDER_PROJECTION_H_INCLUDED
#define RENDER_PROJECTION_H_INCLUDED
#pragma once
#include "doc/pixel_ratio.h"
#include "render/zoom.h"
namespace render {
class Projection {
public:
Projection()
: m_pixelRatio(1, 1),
m_zoom(1, 1) {
}
Projection(const doc::PixelRatio& pixelRatio,
const Zoom& zoom)
: m_pixelRatio(pixelRatio),
m_zoom(zoom) {
}
const doc::PixelRatio& pixelRatio() const { return m_pixelRatio; }
const Zoom& zoom() const { return m_zoom; }
void setPixelRatio(const doc::PixelRatio& pixelRatio) { m_pixelRatio = pixelRatio; }
void setZoom(const Zoom& zoom) { m_zoom = zoom; }
double scaleX() const { return m_zoom.scale() * m_pixelRatio.w; }
double scaleY() const { return m_zoom.scale() * m_pixelRatio.h; }
template<typename T>
T applyX(T x) const { return m_zoom.apply(x * m_pixelRatio.w); }
template<typename T>
T applyY(T y) const { return m_zoom.apply(y * m_pixelRatio.h); }
template<typename T>
T removeX(T x) const { return m_zoom.remove(x / m_pixelRatio.w); }
template<typename T>
T removeY(T y) const { return m_zoom.remove(y / m_pixelRatio.h); }
gfx::Rect apply(const gfx::Rect& r) const {
int u = applyX(r.x);
int v = applyY(r.y);
return gfx::Rect(u, v,
applyX(r.x+r.w) - u,
applyY(r.y+r.h) - v);
}
gfx::Rect remove(const gfx::Rect& r) const {
int u = removeX(r.x);
int v = removeY(r.y);
return gfx::Rect(u, v,
removeX(r.x+r.w) - u,
removeY(r.y+r.h) - v);
}
private:
doc::PixelRatio m_pixelRatio;
Zoom m_zoom;
};
} // namespace render
#endif

View File

@ -29,9 +29,9 @@ class BlenderHelper {
BlendFunc m_blend_func;
color_t m_mask_color;
public:
BlenderHelper(const Image* src, const Palette* pal, BlendMode blend_mode)
BlenderHelper(const Image* src, const Palette* pal, BlendMode blendMode)
{
m_blend_func = SrcTraits::get_blender(blend_mode);
m_blend_func = SrcTraits::get_blender(blendMode);
m_mask_color = src->maskColor();
}
inline typename DstTraits::pixel_t
@ -51,9 +51,9 @@ class BlenderHelper<RgbTraits, GrayscaleTraits> {
BlendFunc m_blend_func;
color_t m_mask_color;
public:
BlenderHelper(const Image* src, const Palette* pal, BlendMode blend_mode)
BlenderHelper(const Image* src, const Palette* pal, BlendMode blendMode)
{
m_blend_func = RgbTraits::get_blender(blend_mode);
m_blend_func = RgbTraits::get_blender(blendMode);
m_mask_color = src->maskColor();
}
inline RgbTraits::pixel_t
@ -73,14 +73,14 @@ public:
template<>
class BlenderHelper<RgbTraits, IndexedTraits> {
const Palette* m_pal;
BlendMode m_blend_mode;
BlendMode m_blendMode;
BlendFunc m_blend_func;
color_t m_mask_color;
public:
BlenderHelper(const Image* src, const Palette* pal, BlendMode blend_mode)
BlenderHelper(const Image* src, const Palette* pal, BlendMode blendMode)
{
m_blend_mode = blend_mode;
m_blend_func = RgbTraits::get_blender(blend_mode);
m_blendMode = blendMode;
m_blend_func = RgbTraits::get_blender(blendMode);
m_mask_color = src->maskColor();
m_pal = pal;
}
@ -89,7 +89,7 @@ public:
const IndexedTraits::pixel_t& src,
int opacity)
{
if (m_blend_mode == BlendMode::SRC) {
if (m_blendMode == BlendMode::SRC) {
return m_pal->getEntry(src);
}
else {
@ -104,12 +104,12 @@ public:
template<>
class BlenderHelper<IndexedTraits, IndexedTraits> {
BlendMode m_blend_mode;
BlendMode m_blendMode;
color_t m_mask_color;
public:
BlenderHelper(const Image* src, const Palette* pal, BlendMode blend_mode)
BlenderHelper(const Image* src, const Palette* pal, BlendMode blendMode)
{
m_blend_mode = blend_mode;
m_blendMode = blendMode;
m_mask_color = src->maskColor();
}
inline IndexedTraits::pixel_t
@ -117,7 +117,7 @@ public:
const IndexedTraits::pixel_t& src,
int opacity)
{
if (m_blend_mode == BlendMode::SRC) {
if (m_blendMode == BlendMode::SRC) {
return src;
}
else {
@ -130,39 +130,39 @@ public:
};
template<class DstTraits, class SrcTraits>
static void compose_scaled_image_scale_up(
static void compose_scaled_image_zoom_in(
Image* dst, const Image* src, const Palette* pal,
gfx::Clip area,
int opacity, BlendMode blend_mode, Zoom zoom)
int opacity, BlendMode blendMode,
const Projection& proj)
{
ASSERT(dst);
ASSERT(src);
ASSERT(DstTraits::pixel_format == dst->pixelFormat());
ASSERT(SrcTraits::pixel_format == src->pixelFormat());
BlenderHelper<DstTraits, SrcTraits> blender(src, pal, blend_mode);
int px_x, px_y;
if (!area.clip(dst->width(), dst->height(),
zoom.apply(src->width()),
zoom.apply(src->height())))
proj.applyX(src->width()),
proj.applyY(src->height())))
return;
int px_w = zoom.apply(1);
int px_h = zoom.apply(1);
BlenderHelper<DstTraits, SrcTraits> blender(src, pal, blendMode);
int px_x, px_y;
int px_w = proj.applyX(1);
int px_h = proj.applyY(1);
int first_px_w = px_w - (area.src.x % px_w);
int first_px_h = px_h - (area.src.y % px_h);
gfx::Rect srcBounds = zoom.remove(area.srcBounds());
gfx::Rect srcBounds = proj.remove(area.srcBounds());
if ((area.src.x+area.size.w) % px_w > 0) ++srcBounds.w;
if ((area.src.y+area.size.h) % px_h > 0) ++srcBounds.h;
if (srcBounds.isEmpty())
return;
gfx::Rect dstBounds = area.dstBounds();
int bottom = area.dst.y+area.size.h-1;
int line_h;
if ((area.src.x+area.size.w) % px_w > 0) ++srcBounds.w;
if ((area.src.y+area.size.h) % px_h > 0) ++srcBounds.h;
if (srcBounds.isEmpty())
return;
// the scanline variable is used to blend src/dst pixels one time for each pixel
typedef std::vector<typename DstTraits::pixel_t> Scanline;
Scanline scanline(srcBounds.w);
@ -262,32 +262,34 @@ done_with_blit:;
}
template<class DstTraits, class SrcTraits>
static void compose_scaled_image_scale_down(
static void compose_scaled_image_zoom_out(
Image* dst, const Image* src, const Palette* pal,
gfx::Clip area,
int opacity, BlendMode blend_mode, Zoom zoom)
gfx::Clip area, int opacity, BlendMode blendMode,
const Projection& proj)
{
ASSERT(dst);
ASSERT(src);
ASSERT(DstTraits::pixel_format == dst->pixelFormat());
ASSERT(SrcTraits::pixel_format == src->pixelFormat());
BlenderHelper<DstTraits, SrcTraits> blender(src, pal, blend_mode);
int unbox_w = zoom.remove(1);
int unbox_h = zoom.remove(1);
if (!area.clip(dst->width(), dst->height(),
zoom.apply(src->width()),
zoom.apply(src->height())))
proj.applyX(src->width()),
proj.applyY(src->height())))
return;
gfx::Rect srcBounds = zoom.remove(area.srcBounds());
gfx::Rect dstBounds = area.dstBounds();
int bottom = area.dst.y+area.size.h-1;
BlenderHelper<DstTraits, SrcTraits> blender(src, pal, blendMode);
int unbox_w = proj.removeX(1);
int unbox_h = proj.removeY(1);
if (unbox_w < 1 || unbox_h < 1)
return;
gfx::Rect srcBounds = proj.remove(area.srcBounds());
if (srcBounds.isEmpty())
return;
gfx::Rect dstBounds = area.dstBounds();
int bottom = area.dst.y+area.size.h-1;
// Lock all necessary bits
const LockImageBits<SrcTraits> srcBits(src, srcBounds);
LockImageBits<DstTraits> dstBits(dst, dstBounds);
@ -327,12 +329,14 @@ template<class DstTraits, class SrcTraits>
static void compose_scaled_image(
Image* dst, const Image* src, const Palette* pal,
const gfx::Clip& area,
int opacity, BlendMode blend_mode, Zoom zoom)
int opacity,
BlendMode blendMode,
const Projection& proj)
{
if (zoom.scale() >= 1.0)
compose_scaled_image_scale_up<DstTraits, SrcTraits>(dst, src, pal, area, opacity, blend_mode, zoom);
if (proj.zoom().scale() >= 1.0)
compose_scaled_image_zoom_in<DstTraits, SrcTraits>(dst, src, pal, area, opacity, blendMode, proj);
else
compose_scaled_image_scale_down<DstTraits, SrcTraits>(dst, src, pal, area, opacity, blend_mode, zoom);
compose_scaled_image_zoom_out<DstTraits, SrcTraits>(dst, src, pal, area, opacity, blendMode, proj);
}
Render::Render()
@ -353,6 +357,11 @@ Render::Render()
{
}
void Render::setProjection(const Projection& projection)
{
m_proj = projection;
}
void Render::setBgType(BgType type)
{
m_bgType = type;
@ -427,17 +436,9 @@ void Render::renderSprite(
const Sprite* sprite,
frame_t frame)
{
renderSprite(dstImage, sprite, frame,
gfx::Clip(sprite->bounds()), Zoom(1, 1));
}
void Render::renderSprite(
Image* dstImage,
const Sprite* sprite,
frame_t frame,
const gfx::Clip& area)
{
renderSprite(dstImage, sprite, frame, area, Zoom(1, 1));
renderSprite(
dstImage, sprite, frame,
gfx::Clip(sprite->bounds()));
}
void Render::renderLayer(
@ -454,7 +455,7 @@ void Render::renderLayer(
const Layer* layer,
frame_t frame,
const gfx::Clip& area,
BlendMode blend_mode)
BlendMode blendMode)
{
m_sprite = layer->sprite();
@ -467,17 +468,15 @@ void Render::renderLayer(
m_globalOpacity = 255;
renderLayer(
layer, dstImage, area,
frame, Zoom(1, 1), scaled_func,
true, true, blend_mode);
layer, dstImage, area, frame,
scaled_func, true, true, blendMode);
}
void Render::renderSprite(
Image* dstImage,
const Sprite* sprite,
frame_t frame,
const gfx::Clip& area,
Zoom zoom)
const gfx::Clip& area)
{
m_sprite = sprite;
@ -511,7 +510,7 @@ void Render::renderSprite(
fill_rect(dstImage, area.dstBounds(), bg_color);
}
else {
renderBackground(dstImage, area, zoom);
renderBackground(dstImage, area);
if (bgLayer && bgLayer->isVisible() && rgba_geta(bg_color) > 0) {
blend_rect(dstImage, area.dst.x, area.dst.y,
area.dst.x+area.size.w-1,
@ -530,27 +529,27 @@ void Render::renderSprite(
m_globalOpacity = 255;
renderLayer(
m_sprite->folder(), dstImage,
area, frame, zoom, scaled_func,
area, frame, scaled_func,
true,
false,
BlendMode::UNSPECIFIED);
// Draw onion skin behind the sprite.
if (m_onionskin.position() == OnionskinPosition::BEHIND)
renderOnionskin(dstImage, area, frame, zoom, scaled_func);
renderOnionskin(dstImage, area, frame, scaled_func);
// Draw the transparent layers.
m_globalOpacity = 255;
renderLayer(
m_sprite->folder(), dstImage,
area, frame, zoom, scaled_func,
area, frame, scaled_func,
false,
true,
BlendMode::UNSPECIFIED);
// Draw onion skin in front of the sprite.
if (m_onionskin.position() == OnionskinPosition::INFRONT)
renderOnionskin(dstImage, area, frame, zoom, scaled_func);
renderOnionskin(dstImage, area, frame, scaled_func);
// Overlay preview image
if (m_previewImage &&
@ -564,15 +563,14 @@ void Render::renderSprite(
area,
scaled_func,
255,
m_previewBlendMode,
zoom);
m_previewBlendMode);
}
}
void Render::renderOnionskin(
Image* dstImage,
const gfx::Clip& area,
frame_t frame, Zoom zoom,
frame_t frame,
RenderScaledImage scaled_func)
{
// Onion-skin feature: Draw previous/next frames with different
@ -612,43 +610,42 @@ void Render::renderOnionskin(
m_globalOpacity = MID(0, m_globalOpacity, 255);
if (m_globalOpacity > 0) {
BlendMode blend_mode = BlendMode::UNSPECIFIED;
BlendMode blendMode = BlendMode::UNSPECIFIED;
if (m_onionskin.type() == OnionskinType::MERGE)
blend_mode = BlendMode::NORMAL;
blendMode = BlendMode::NORMAL;
else if (m_onionskin.type() == OnionskinType::RED_BLUE_TINT)
blend_mode = (frameOut < frame ? BlendMode::RED_TINT: BlendMode::BLUE_TINT);
blendMode = (frameOut < frame ? BlendMode::RED_TINT: BlendMode::BLUE_TINT);
renderLayer(
onionLayer, dstImage,
area, frameIn, zoom, scaled_func,
area, frameIn, scaled_func,
// Render background only for "in-front" onion skinning and
// when opacity is < 255
(m_globalOpacity < 255 &&
m_onionskin.position() == OnionskinPosition::INFRONT),
true,
blend_mode);
blendMode);
}
}
}
}
void Render::renderBackground(Image* image,
const gfx::Clip& area,
Zoom zoom)
void Render::renderBackground(
Image* image,
const gfx::Clip& area)
{
int x, y, u, v;
int tile_w = m_bgCheckedSize.w;
int tile_h = m_bgCheckedSize.h;
if (m_bgZoom) {
tile_w = zoom.apply(tile_w);
tile_h = zoom.apply(tile_h);
tile_w = m_proj.zoom().apply(tile_w);
tile_h = m_proj.zoom().apply(tile_h);
}
// Tile size
if (tile_w < zoom.apply(1)) tile_w = zoom.apply(1);
if (tile_h < zoom.apply(1)) tile_h = zoom.apply(1);
if (tile_w < m_proj.applyX(1)) tile_w = m_proj.applyX(1);
if (tile_h < m_proj.applyY(1)) tile_h = m_proj.applyY(1);
if (tile_w < 1) tile_w = 1;
if (tile_h < 1) tile_h = 1;
@ -678,10 +675,11 @@ void Render::renderBackground(Image* image,
}
}
void Render::renderImage(Image* dst_image, const Image* src_image,
const Palette* pal,
int x, int y,
Zoom zoom, int opacity, BlendMode blend_mode)
void Render::renderImage(
Image* dst_image, const Image* src_image,
const Palette* pal,
int x, int y,
int opacity, BlendMode blendMode)
{
RenderScaledImage scaled_func = getRenderScaledImageFunc(
dst_image->pixelFormat(),
@ -689,22 +687,24 @@ void Render::renderImage(Image* dst_image, const Image* src_image,
if (!scaled_func)
return;
scaled_func(dst_image, src_image, pal,
scaled_func(
dst_image, src_image, pal,
gfx::Clip(x, y, 0, 0,
zoom.apply(src_image->width()),
zoom.apply(src_image->height())),
opacity, blend_mode, zoom);
m_proj.applyX(src_image->width()),
m_proj.applyY(src_image->height())),
opacity, blendMode,
m_proj);
}
void Render::renderLayer(
const Layer* layer,
Image *image,
const gfx::Clip& area,
frame_t frame, Zoom zoom,
frame_t frame,
RenderScaledImage scaled_func,
bool render_background,
bool render_transparent,
BlendMode blend_mode)
BlendMode blendMode)
{
// we can't read from this layer
if (!layer->isVisible())
@ -724,11 +724,9 @@ void Render::renderLayer(
m_extraCel->y(),
m_extraImage->width(),
m_extraImage->height());
extraArea = zoom.apply(extraArea);
if (zoom.scale() < 1.0) {
extraArea.w--;
extraArea.h--;
}
extraArea = m_proj.apply(extraArea);
if (m_proj.scaleX() < 1.0) extraArea.w--;
if (m_proj.scaleY() < 1.0) extraArea.h--;
if (extraArea.w < 1) extraArea.w = 1;
if (extraArea.h < 1) extraArea.h = 1;
}
@ -761,9 +759,9 @@ void Render::renderLayer(
if (src_image) {
const LayerImage* imgLayer = static_cast<const LayerImage*>(layer);
BlendMode layerBlendMode =
(blend_mode == BlendMode::UNSPECIFIED ?
(blendMode == BlendMode::UNSPECIFIED ?
imgLayer->blendMode():
blend_mode);
blendMode);
ASSERT(cel->opacity() >= 0);
ASSERT(cel->opacity() <= 255);
@ -789,7 +787,7 @@ void Render::renderLayer(
image, src_image, pal,
cel, gfx::Clip(area.dst.x+rc.x-area.src.x,
area.dst.y+rc.y-area.src.y, rc), scaled_func,
opacity, layerBlendMode, zoom);
opacity, layerBlendMode);
}
}
// Draw the whole cel
@ -797,7 +795,7 @@ void Render::renderLayer(
renderCel(
image, src_image, pal,
cel, area, scaled_func,
opacity, layerBlendMode, zoom);
opacity, layerBlendMode);
}
}
}
@ -809,11 +807,13 @@ void Render::renderLayer(
LayerConstIterator end = static_cast<const LayerFolder*>(layer)->getLayerEnd();
for (; it != end; ++it) {
renderLayer(*it, image,
area, frame, zoom, scaled_func,
renderLayer(
*it, image,
area, frame,
scaled_func,
render_background,
render_transparent,
blend_mode);
blendMode);
}
break;
}
@ -832,7 +832,7 @@ void Render::renderLayer(
extraArea),
scaled_func,
m_extraCel->opacity(),
m_extraBlendMode, zoom);
m_extraBlendMode);
}
}
}
@ -844,7 +844,7 @@ void Render::renderCel(
const Cel* cel,
const gfx::Clip& area,
RenderScaledImage scaled_func,
int opacity, BlendMode blend_mode, Zoom zoom)
int opacity, BlendMode blendMode)
{
renderImage(dst_image,
cel_image,
@ -854,8 +854,7 @@ void Render::renderCel(
area,
scaled_func,
opacity,
blend_mode,
zoom);
blendMode);
}
void Render::renderImage(
@ -866,30 +865,32 @@ void Render::renderImage(
const int y,
const gfx::Clip& area,
RenderScaledImage scaled_func,
int opacity, BlendMode blend_mode, Zoom zoom)
int opacity, BlendMode blendMode)
{
int cel_x = zoom.apply(x);
int cel_y = zoom.apply(y);
int cel_x = m_proj.applyX(x);
int cel_y = m_proj.applyY(y);
gfx::Rect src_bounds =
gfx::Rect srcBounds =
area.srcBounds().createIntersection(
gfx::Rect(
cel_x,
cel_y,
zoom.apply(cel_image->width()),
zoom.apply(cel_image->height())));
if (src_bounds.isEmpty())
m_proj.applyX(cel_image->width()),
m_proj.applyY(cel_image->height())));
if (srcBounds.isEmpty())
return;
(*scaled_func)(dst_image, cel_image, pal,
(*scaled_func)(
dst_image, cel_image, pal,
gfx::Clip(
area.dst.x + src_bounds.x - area.src.x,
area.dst.y + src_bounds.y - area.src.y,
src_bounds.x - cel_x,
src_bounds.y - cel_y,
src_bounds.w,
src_bounds.h),
opacity, blend_mode, zoom);
area.dst.x + srcBounds.x - area.src.x,
area.dst.y + srcBounds.y - area.src.y,
srcBounds.x - cel_x,
srcBounds.y - cel_y,
srcBounds.w,
srcBounds.h),
opacity, blendMode,
m_proj);
}
// static
@ -931,13 +932,13 @@ Render::RenderScaledImage Render::getRenderScaledImageFunc(
void composite_image(Image* dst, const Image* src,
const Palette* pal,
int x, int y,
int opacity, BlendMode blend_mode)
int opacity, BlendMode blendMode)
{
// As the background is not rendered in renderImage(), we don't need
// to configure the Render instance's BgType.
Render().renderImage(
dst, src, pal, x, y, Zoom(1, 1),
opacity, blend_mode);
dst, src, pal, x, y,
opacity, blendMode);
}
} // namespace render

View File

@ -17,7 +17,7 @@
#include "gfx/size.h"
#include "render/extra_type.h"
#include "render/onionskin_position.h"
#include "render/zoom.h"
#include "render/projection.h"
namespace gfx {
class Clip;
@ -93,6 +93,9 @@ namespace render {
public:
Render();
// Viewport configuration
void setProjection(const Projection& projection);
// Background configuration
void setBgType(BgType type);
void setBgZoom(bool state);
@ -123,12 +126,6 @@ namespace render {
const Sprite* sprite,
frame_t frame);
void renderSprite(
Image* dstImage,
const Sprite* sprite,
frame_t frame,
const gfx::Clip& area);
void renderLayer(
Image* dstImage,
const Layer* layer,
@ -139,7 +136,7 @@ namespace render {
const Layer* layer,
frame_t frame,
const gfx::Clip& area,
BlendMode blend_mode = BlendMode::UNSPECIFIED);
BlendMode blendMode = BlendMode::UNSPECIFIED);
// Main function used to render the sprite. Draws the given sprite
// frame in a new image and return it. Note: zoomedRect must have
@ -148,39 +145,41 @@ namespace render {
Image* dstImage,
const Sprite* sprite,
frame_t frame,
const gfx::Clip& area,
Zoom zoom);
const gfx::Clip& area);
// Extra functions
void renderBackground(Image* image,
const gfx::Clip& area,
Zoom zoom);
void renderBackground(
Image* image,
const gfx::Clip& area);
void renderImage(Image* dst_image, const Image* src_image,
const Palette* pal, int x, int y, Zoom zoom,
int opacity, BlendMode blend_mode);
void renderImage(
Image* dst_image, const Image* src_image,
const Palette* pal, int x, int y,
int opacity, BlendMode blendMode);
private:
typedef void (*RenderScaledImage)(
Image* dst, const Image* src, const Palette* pal,
const gfx::Clip& area,
int opacity, BlendMode blend_mode, Zoom zoom);
int opacity,
BlendMode blendMode,
const Projection& proj);
void renderOnionskin(
Image* image,
const gfx::Clip& area,
frame_t frame, Zoom zoom,
frame_t frame,
RenderScaledImage scaled_func);
void renderLayer(
const Layer* layer,
Image* image,
const gfx::Clip& area,
frame_t frame, Zoom zoom,
frame_t frame,
RenderScaledImage renderScaledImage,
bool render_background,
bool render_transparent,
BlendMode blend_mode);
BlendMode blendMode);
void renderCel(
Image* dst_image,
@ -189,7 +188,7 @@ namespace render {
const Cel* cel,
const gfx::Clip& area,
RenderScaledImage scaled_func,
int opacity, BlendMode blend_mode, Zoom zoom);
int opacity, BlendMode blendMode);
void renderImage(
Image* dst_image,
@ -199,7 +198,7 @@ namespace render {
const int y,
const gfx::Clip& area,
RenderScaledImage scaled_func,
int opacity, BlendMode blend_mode, Zoom zoom);
int opacity, BlendMode blendMode);
static RenderScaledImage getRenderScaledImageFunc(
PixelFormat dstFormat,
@ -208,11 +207,11 @@ namespace render {
const Sprite* m_sprite;
const Layer* m_currentLayer;
frame_t m_currentFrame;
Projection m_proj;
ExtraType m_extraType;
const Cel* m_extraCel;
const Image* m_extraImage;
BlendMode m_extraBlendMode;
BgType m_bgType;
bool m_bgZoom;
color_t m_bgColor1;
@ -229,7 +228,7 @@ namespace render {
void composite_image(Image* dst, const Image* src,
const Palette* pal,
int x, int y,
int opacity, BlendMode blend_mode);
int opacity, BlendMode blendMode);
} // namespace render

View File

@ -1,5 +1,5 @@
// Aseprite Document Library
// Copyright (c) 2001-2014 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.
@ -169,11 +169,9 @@ TEST(Render, CheckedBackground)
1, 1, 1, 2,
2, 2, 2, 1);
render.setProjection(Projection(PixelRatio(1, 1), Zoom(2, 1)));
render.setBgCheckedSize(gfx::Size(1, 1));
render.renderSprite(dst,
doc->sprite(), frame_t(0),
gfx::Clip(dst->bounds()),
Zoom(2, 1));
render.renderSprite(dst, doc->sprite(), frame_t(0));
EXPECT_4X4_PIXELS(dst,
1, 1, 2, 2,
1, 1, 2, 2,
@ -204,9 +202,9 @@ TEST(Render, ZoomAndDstBounds)
render.setBgColor2(2);
render.setBgCheckedSize(gfx::Size(1, 1));
render.renderSprite(dst, doc->sprite(), frame_t(0),
gfx::Clip(1, 1, 0, 0, 2, 2),
Zoom(1, 1));
render.renderSprite(
dst, doc->sprite(), frame_t(0),
gfx::Clip(1, 1, 0, 0, 2, 2));
EXPECT_4X4_PIXELS(dst,
0, 0, 0, 0,
0, 1, 2, 0,