mirror of https://github.com/aseprite/aseprite.git
				
				
				
			Add pixel ratio support to the Editor & Render
This commit is contained in:
		
							parent
							
								
									73bda9bd19
								
							
						
					
					
						commit
						37209a0f5b
					
				|  | @ -1,5 +1,5 @@ | ||||||
| // Aseprite
 | // 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
 | // 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
 | // it under the terms of the GNU General Public License version 2 as
 | ||||||
|  | @ -51,7 +51,7 @@ public: | ||||||
|     , m_doc(editor->document()) |     , m_doc(editor->document()) | ||||||
|     , m_sprite(editor->sprite()) |     , m_sprite(editor->sprite()) | ||||||
|     , m_pal(m_sprite->palette(editor->frame())) |     , m_pal(m_sprite->palette(editor->frame())) | ||||||
|     , m_zoom(editor->zoom()) |     , m_proj(editor->projection()) | ||||||
|     , m_index_bg_color(-1) |     , m_index_bg_color(-1) | ||||||
|     , m_doublebuf(Image::create(IMAGE_RGB, ui::display_w(), ui::display_h())) |     , m_doublebuf(Image::create(IMAGE_RGB, ui::display_w(), ui::display_h())) | ||||||
|     , m_doublesur(she::instance()->createRgbaSurface(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 { |   virtual void onPaint(PaintEvent& ev) override { | ||||||
|     Graphics* g = ev.graphics(); |     Graphics* g = ev.graphics(); | ||||||
|     AppRender& render = m_editor->renderEngine(); |     AppRender& render = m_editor->renderEngine(); | ||||||
|  |     render.setProjection(render::Projection()); | ||||||
|     render.disableOnionskin(); |     render.disableOnionskin(); | ||||||
|     render.setBgType(render::BgType::TRANSPARENT); |     render.setBgType(render::BgType::TRANSPARENT); | ||||||
| 
 | 
 | ||||||
|     // Render sprite and leave the result in 'm_render' variable
 |     // Render sprite and leave the result in 'm_render' variable
 | ||||||
|     if (m_render == NULL) { |     if (m_render == nullptr) { | ||||||
|       ImageBufferPtr buf = Editor::getRenderImageBuffer(); |       ImageBufferPtr buf = Editor::getRenderImageBuffer(); | ||||||
|       m_render.reset(Image::create(IMAGE_RGB, |       m_render.reset(Image::create(IMAGE_RGB, | ||||||
|           m_sprite->width(), m_sprite->height(), buf)); |           m_sprite->width(), m_sprite->height(), buf)); | ||||||
|  | @ -188,19 +189,20 @@ protected: | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     int x, y, w, h, u, v; |     int x, y, w, h, u, v; | ||||||
|     x = m_pos.x + m_zoom.apply(m_zoom.remove(m_delta.x)); |     x = m_pos.x + m_proj.applyX(m_proj.removeX(m_delta.x)); | ||||||
|     y = m_pos.y + m_zoom.apply(m_zoom.remove(m_delta.y)); |     y = m_pos.y + m_proj.applyY(m_proj.removeY(m_delta.y)); | ||||||
|     w = m_zoom.apply(m_sprite->width()); |     w = m_proj.applyX(m_sprite->width()); | ||||||
|     h = m_zoom.apply(m_sprite->height()); |     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::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::Y_AXIS)) y = SGN(y) * (ABS(y)%h); | ||||||
| 
 | 
 | ||||||
|  |     render.setProjection(m_proj); | ||||||
|     if (m_index_bg_color == -1) { |     if (m_index_bg_color == -1) { | ||||||
|       render.setupBackground(m_doc, m_doublebuf->pixelFormat()); |       render.setupBackground(m_doc, m_doublebuf->pixelFormat()); | ||||||
|       render.renderBackground(m_doublebuf, |       render.renderBackground(m_doublebuf, | ||||||
|         gfx::Clip(0, 0, -m_pos.x, -m_pos.y, |         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 { |     else { | ||||||
|       doc::clear_image(m_doublebuf, m_pal->getEntry(m_index_bg_color)); |       doc::clear_image(m_doublebuf, m_pal->getEntry(m_index_bg_color)); | ||||||
|  | @ -209,23 +211,23 @@ protected: | ||||||
|     switch (m_tiled) { |     switch (m_tiled) { | ||||||
|       case TiledMode::NONE: |       case TiledMode::NONE: | ||||||
|         render.renderImage(m_doublebuf, m_render, m_pal, x, y, |         render.renderImage(m_doublebuf, m_render, m_pal, x, y, | ||||||
|                            m_zoom, 255, BlendMode::NORMAL); |                            255, BlendMode::NORMAL); | ||||||
|         break; |         break; | ||||||
|       case TiledMode::X_AXIS: |       case TiledMode::X_AXIS: | ||||||
|         for (u=x-w; u<ui::display_w()+w; u+=w) |         for (u=x-w; u<ui::display_w()+w; u+=w) | ||||||
|           render.renderImage(m_doublebuf, m_render, m_pal, u, y, |           render.renderImage(m_doublebuf, m_render, m_pal, u, y, | ||||||
|                              m_zoom, 255, BlendMode::NORMAL); |                              255, BlendMode::NORMAL); | ||||||
|         break; |         break; | ||||||
|       case TiledMode::Y_AXIS: |       case TiledMode::Y_AXIS: | ||||||
|         for (v=y-h; v<ui::display_h()+h; v+=h) |         for (v=y-h; v<ui::display_h()+h; v+=h) | ||||||
|           render.renderImage(m_doublebuf, m_render, m_pal, x, v, |           render.renderImage(m_doublebuf, m_render, m_pal, x, v, | ||||||
|                              m_zoom, 255, BlendMode::NORMAL); |                              255, BlendMode::NORMAL); | ||||||
|         break; |         break; | ||||||
|       case TiledMode::BOTH: |       case TiledMode::BOTH: | ||||||
|         for (v=y-h; v<ui::display_h()+h; v+=h) |         for (v=y-h; v<ui::display_h()+h; v+=h) | ||||||
|           for (u=x-w; u<ui::display_w()+w; u+=w) |           for (u=x-w; u<ui::display_w()+w; u+=w) | ||||||
|             render.renderImage(m_doublebuf, m_render, m_pal, u, v, |             render.renderImage(m_doublebuf, m_render, m_pal, u, v, | ||||||
|                                m_zoom, 255, BlendMode::NORMAL); |                                255, BlendMode::NORMAL); | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -243,7 +245,7 @@ private: | ||||||
|   gfx::Point m_pos; |   gfx::Point m_pos; | ||||||
|   gfx::Point m_oldMousePos; |   gfx::Point m_oldMousePos; | ||||||
|   gfx::Point m_delta; |   gfx::Point m_delta; | ||||||
|   render::Zoom m_zoom; |   render::Projection m_proj; | ||||||
|   int m_index_bg_color; |   int m_index_bg_color; | ||||||
|   base::UniquePtr<Image> m_render; |   base::UniquePtr<Image> m_render; | ||||||
|   base::UniquePtr<Image> m_doublebuf; |   base::UniquePtr<Image> m_doublebuf; | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| // Aseprite
 | // 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
 | // 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
 | // 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_x+m_offset_x, | ||||||
|           m_y+m_offset_y+m_row-1)), |           m_y+m_offset_y+m_row-1)), | ||||||
|       gfx::Size( |       gfx::Size( | ||||||
|         editor->zoom().apply(m_w), |         editor->projection().applyX(m_w), | ||||||
|         (editor->zoom().scale() >= 1 ? editor->zoom().apply(1): |         (editor->projection().scaleY() >= 1 ? editor->projection().applyY(1): | ||||||
|                                        editor->zoom().remove(1)))); |                                               editor->projection().removeY(1)))); | ||||||
| 
 | 
 | ||||||
|     gfx::Region reg1(rect); |     gfx::Region reg1(rect); | ||||||
|     gfx::Region reg2; |     gfx::Region reg2; | ||||||
|  |  | ||||||
|  | @ -408,19 +408,22 @@ void BrushPreview::traceSelectionCrossPixels( | ||||||
|     0, 0, 1, 1, 0, 0, |     0, 0, 1, 1, 0, 0, | ||||||
|   }; |   }; | ||||||
|   gfx::Point out, outpt = m_editor->editorToScreen(pt); |   gfx::Point out, outpt = m_editor->editorToScreen(pt); | ||||||
|   int u, v; |   const render::Projection& proj = m_editor->projection(); | ||||||
|   int size = m_editor->zoom().apply(thickness/2); |   gfx::Size size(proj.applyX(thickness/2), | ||||||
|   int size2 = m_editor->zoom().apply(thickness); |                  proj.applyY(thickness/2)); | ||||||
|   if (size2 == 0) size2 = 1; |   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 (int v=0; v<6; v++) { | ||||||
|     for (u=0; u<6; u++) { |     for (int u=0; u<6; u++) { | ||||||
|       if (!cross[v*6+u]) |       if (!cross[v*6+u]) | ||||||
|         continue; |         continue; | ||||||
| 
 | 
 | ||||||
|       out = outpt; |       out = outpt; | ||||||
|       out.x += ((u<3) ? u-size-3: u-size-3+size2); |       out.x += ((u<3) ? u-size.w-3: u-size.w-3+size2.w); | ||||||
|       out.y += ((v<3) ? v-size-3: v-size-3+size2); |       out.y += ((v<3) ? v-size.h-3: v-size.h-3+size2.h); | ||||||
| 
 | 
 | ||||||
|       (this->*pixelDelegate)(g, out, color); |       (this->*pixelDelegate)(g, out, color); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -66,38 +66,38 @@ using namespace render; | ||||||
| 
 | 
 | ||||||
| class EditorPreRenderImpl : public EditorPreRender { | class EditorPreRenderImpl : public EditorPreRender { | ||||||
| public: | 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_editor(editor) | ||||||
|     , m_image(image) |     , m_image(image) | ||||||
|     , m_offset(offset) |     , m_offset(offset) | ||||||
|     , m_zoom(zoom) |     , m_proj(proj) { | ||||||
|   { |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   Editor* getEditor() override |   Editor* getEditor() override { | ||||||
|   { |  | ||||||
|     return m_editor; |     return m_editor; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   Image* getImage() override |   Image* getImage() override { | ||||||
|   { |  | ||||||
|     return m_image; |     return m_image; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   void fillRect(const gfx::Rect& rect, uint32_t rgbaColor, int opacity) override |   void fillRect(const gfx::Rect& rect, uint32_t rgbaColor, int opacity) override | ||||||
|   { |   { | ||||||
|     blend_rect(m_image, |     blend_rect( | ||||||
|       m_offset.x + m_zoom.apply(rect.x), |       m_image, | ||||||
|       m_offset.y + m_zoom.apply(rect.y), |       m_offset.x + m_proj.applyX(rect.x), | ||||||
|       m_offset.x + m_zoom.apply(rect.x+rect.w) - 1, |       m_offset.y + m_proj.applyY(rect.y), | ||||||
|       m_offset.y + m_zoom.apply(rect.y+rect.h) - 1, rgbaColor, opacity); |       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: | private: | ||||||
|   Editor* m_editor; |   Editor* m_editor; | ||||||
|   Image* m_image; |   Image* m_image; | ||||||
|   Point m_offset; |   Point m_offset; | ||||||
|   Zoom m_zoom; |   Projection m_proj; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class EditorPostRenderImpl : public EditorPostRender { | class EditorPostRenderImpl : public EditorPostRender { | ||||||
|  | @ -154,7 +154,6 @@ Editor::Editor(Document* document, EditorFlags flags) | ||||||
|   , m_sprite(m_document->sprite()) |   , m_sprite(m_document->sprite()) | ||||||
|   , m_layer(m_sprite->folder()->getFirstLayer()) |   , m_layer(m_sprite->folder()->getFirstLayer()) | ||||||
|   , m_frame(frame_t(0)) |   , m_frame(frame_t(0)) | ||||||
|   , m_zoom(1, 1) |  | ||||||
|   , m_docPref(Preferences::instance().document(document)) |   , m_docPref(Preferences::instance().document(document)) | ||||||
|   , m_brushPreview(this) |   , m_brushPreview(this) | ||||||
|   , m_lastDrawingPosition(-1, -1) |   , m_lastDrawingPosition(-1, -1) | ||||||
|  | @ -169,6 +168,8 @@ Editor::Editor(Document* document, EditorFlags flags) | ||||||
|   , m_secondaryButton(false) |   , m_secondaryButton(false) | ||||||
|   , m_aniSpeed(1.0) |   , m_aniSpeed(1.0) | ||||||
| { | { | ||||||
|  |   m_proj.setPixelRatio(m_sprite->pixelRatio()); | ||||||
|  | 
 | ||||||
|   // Add the first state into the history.
 |   // Add the first state into the history.
 | ||||||
|   m_statesHistory.push(m_state); |   m_statesHistory.push(m_state); | ||||||
| 
 | 
 | ||||||
|  | @ -365,15 +366,15 @@ Site Editor::getSite() const | ||||||
| 
 | 
 | ||||||
| void Editor::setZoom(const render::Zoom& zoom) | void Editor::setZoom(const render::Zoom& zoom) | ||||||
| { | { | ||||||
|   if (m_zoom != zoom) { |   if (m_proj.zoom() != zoom) { | ||||||
|     m_zoom = zoom; |     m_proj.setZoom(zoom); | ||||||
|     notifyZoomChanged(); |     notifyZoomChanged(); | ||||||
|   } |   } | ||||||
|   else { |   else { | ||||||
|     // Just copy the zoom as the internal "Zoom::m_internalScale"
 |     // Just copy the zoom as the internal "Zoom::m_internalScale"
 | ||||||
|     // value might be different and we want to keep this value updated
 |     // value might be different and we want to keep this value updated
 | ||||||
|     // for better zooming experience in StateWithWheelBehavior.
 |     // for better zooming experience in StateWithWheelBehavior.
 | ||||||
|     m_zoom = zoom; |     m_proj.setZoom(zoom); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -384,8 +385,8 @@ void Editor::setDefaultScroll() | ||||||
| 
 | 
 | ||||||
|   setEditorScroll( |   setEditorScroll( | ||||||
|     gfx::Point( |     gfx::Point( | ||||||
|       m_padding.x - vp.w/2 + m_zoom.apply(m_sprite->width())/2, |       m_padding.x - vp.w/2 + m_proj.applyX(m_sprite->width())/2, | ||||||
|       m_padding.y - vp.h/2 + m_zoom.apply(m_sprite->height())/2)); |       m_padding.y - vp.h/2 + m_proj.applyY(m_sprite->height())/2)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Sets the scroll position of the editor
 | // 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
 |   // Clip from sprite and apply zoom
 | ||||||
|   gfx::Rect rc = m_sprite->bounds().createIntersection(spriteRectToDraw); |   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_x = dx + m_padding.x + rc.x; | ||||||
|   int dest_y = dy + m_padding.y + rc.y; |   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
 |     // tool managers that need to validate this region (copy pixels from
 | ||||||
|     // the original cel) before it can be used by the RenderEngine.
 |     // 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
 |       // If the zoom level is less than 100%, we add extra pixels to
 | ||||||
|       // the exposed area. Those pixels could be shown in the
 |       // the exposed area. Those pixels could be shown in the
 | ||||||
|       // rendering process depending on each cel position.
 |       // rendering process depending on each cel position.
 | ||||||
|       // E.g. when we are drawing in a cel with position < (0,0)
 |       // E.g. when we are drawing in a cel with position < (0,0)
 | ||||||
|       if (m_zoom.scale() < 1.0) { |       if (m_proj.scaleX() < 1.0) | ||||||
|         expose.enlarge(int(1./m_zoom.scale())); |         expose.enlargeXW(int(1./m_proj.scaleX())); | ||||||
|       } |  | ||||||
|       // If the zoom level is more than %100 we add an extra pixel to
 |       // 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:
 |       // expose just in case the zoom requires to display it.  Note:
 | ||||||
|       // this is really necessary to avoid showing invalid destination
 |       // this is really necessary to avoid showing invalid destination
 | ||||||
|       // areas in ToolLoopImpl.
 |       // areas in ToolLoopImpl.
 | ||||||
|       else if (m_zoom.scale() > 1.0) { |       else if (m_proj.scaleX() > 1.0) | ||||||
|         expose.enlarge(1); |         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)); |       m_document->notifyExposeSpritePixels(m_sprite, gfx::Region(expose)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Create a temporary RGB bitmap to draw all to it
 |     // Create a temporary RGB bitmap to draw all to it
 | ||||||
|     rendered.reset(Image::create(IMAGE_RGB, rc.w, rc.h, m_renderBuffer)); |     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.setupBackground(m_document, rendered->pixelFormat()); | ||||||
|     m_renderEngine.disableOnionskin(); |     m_renderEngine.disableOnionskin(); | ||||||
| 
 | 
 | ||||||
|  | @ -505,8 +513,8 @@ void Editor::drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& sprite | ||||||
|         m_layer, m_frame); |         m_layer, m_frame); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     m_renderEngine.renderSprite(rendered, m_sprite, m_frame, |     m_renderEngine.renderSprite( | ||||||
|       gfx::Clip(0, 0, rc), m_zoom); |       rendered, m_sprite, m_frame, gfx::Clip(0, 0, rc)); | ||||||
| 
 | 
 | ||||||
|     m_renderEngine.removeExtraImage(); |     m_renderEngine.removeExtraImage(); | ||||||
|   } |   } | ||||||
|  | @ -518,7 +526,7 @@ void Editor::drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& sprite | ||||||
|     // Pre-render decorator.
 |     // Pre-render decorator.
 | ||||||
|     if ((m_flags & kShowDecorators) && m_decorator) { |     if ((m_flags & kShowDecorators) && m_decorator) { | ||||||
|       EditorPreRenderImpl preRender(this, rendered, |       EditorPreRenderImpl preRender(this, rendered, | ||||||
|         Point(-rc.x, -rc.y), m_zoom); |                                     Point(-rc.x, -rc.y), m_proj); | ||||||
|       m_decorator->preRenderDecorator(&preRender); |       m_decorator->preRenderDecorator(&preRender); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -549,15 +557,15 @@ void Editor::drawSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& _rc) | ||||||
|   gfx::Rect rc = _rc; |   gfx::Rect rc = _rc; | ||||||
|   // For odd zoom scales minor than 100% we have to add an extra window
 |   // For odd zoom scales minor than 100% we have to add an extra window
 | ||||||
|   // just to make sure the whole rectangle is drawn.
 |   // just to make sure the whole rectangle is drawn.
 | ||||||
|   if (m_zoom.scale() < 1.0) |   if (m_proj.scaleX() < 1.0) rc.w += int(1./m_proj.scaleX()); | ||||||
|     rc.inflate(int(1./m_zoom.scale()), int(1./m_zoom.scale())); |   if (m_proj.scaleY() < 1.0) rc.h += int(1./m_proj.scaleY()); | ||||||
| 
 | 
 | ||||||
|   gfx::Rect client = clientBounds(); |   gfx::Rect client = clientBounds(); | ||||||
|   gfx::Rect spriteRect( |   gfx::Rect spriteRect( | ||||||
|     client.x + m_padding.x, |     client.x + m_padding.x, | ||||||
|     client.y + m_padding.y, |     client.y + m_padding.y, | ||||||
|     m_zoom.apply(m_sprite->width()), |     m_proj.applyX(m_sprite->width()), | ||||||
|     m_zoom.apply(m_sprite->height())); |     m_proj.applyY(m_sprite->height())); | ||||||
|   gfx::Rect enclosingRect = spriteRect; |   gfx::Rect enclosingRect = spriteRect; | ||||||
| 
 | 
 | ||||||
|   // Draw the main sprite at the center.
 |   // 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); |       IntersectClip clip(g, cliprc); | ||||||
| 
 | 
 | ||||||
|       // Draw the pixel grid
 |       // 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(); |         int alpha = m_docPref.pixelGrid.opacity(); | ||||||
| 
 | 
 | ||||||
|         if (m_docPref.pixelGrid.autoOpacity()) { |         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); |           alpha = MID(0, alpha, 255); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -626,12 +634,13 @@ void Editor::drawSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& _rc) | ||||||
|       // Draw the grid
 |       // Draw the grid
 | ||||||
|       if (m_docPref.show.grid()) { |       if (m_docPref.show.grid()) { | ||||||
|         gfx::Rect gridrc = m_docPref.grid.bounds(); |         gfx::Rect gridrc = m_docPref.grid.bounds(); | ||||||
|         if (m_zoom.apply(gridrc.w) > 2 && |         if (m_proj.applyX(gridrc.w) > 2 && | ||||||
|           m_zoom.apply(gridrc.h) > 2) { |             m_proj.applyY(gridrc.h) > 2) { | ||||||
|           int alpha = m_docPref.grid.opacity(); |           int alpha = m_docPref.grid.opacity(); | ||||||
| 
 | 
 | ||||||
|           if (m_docPref.grid.autoOpacity()) { |           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 = int(alpha * len / 32.); | ||||||
|             alpha = MID(0, alpha, 255); |             alpha = MID(0, alpha, 255); | ||||||
|           } |           } | ||||||
|  | @ -657,7 +666,7 @@ void Editor::drawSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& _rc) | ||||||
|         if (x > 0) { |         if (x > 0) { | ||||||
|           gfx::Color color = color_utils::color_for_ui(m_docPref.grid.color()); |           gfx::Color color = color_utils::color_for_ui(m_docPref.grid.color()); | ||||||
|           g->drawVLine(color, |           g->drawVLine(color, | ||||||
|                        spriteRect.x + m_zoom.apply(x), |                        spriteRect.x + m_proj.applyX(x), | ||||||
|                        enclosingRect.y, |                        enclosingRect.y, | ||||||
|                        enclosingRect.h); |                        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()); |           gfx::Color color = color_utils::color_for_ui(m_docPref.grid.color()); | ||||||
|           g->drawHLine(color, |           g->drawHLine(color, | ||||||
|                        enclosingRect.x, |                        enclosingRect.x, | ||||||
|                        spriteRect.y + m_zoom.apply(y), |                        spriteRect.y + m_proj.applyY(y), | ||||||
|                        enclosingRect.w); |                        enclosingRect.w); | ||||||
|         } |         } | ||||||
|         break; |         break; | ||||||
|  | @ -747,13 +756,16 @@ void Editor::drawMask(Graphics* g) | ||||||
| 
 | 
 | ||||||
|   for (const auto& seg : *m_document->getMaskBoundaries()) { |   for (const auto& seg : *m_document->getMaskBoundaries()) { | ||||||
|     CheckedDrawMode checked(g, m_antsOffset); |     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 (m_proj.scaleX() >= 1.0) { | ||||||
|       if (!seg.open()) { |       if (!seg.open() && seg.vertical()) | ||||||
|         if (seg.vertical()) --bounds.x; |         --bounds.x; | ||||||
|         else --bounds.y; |  | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     if (m_proj.scaleY() >= 1.0) { | ||||||
|  |       if (!seg.open() && !seg.vertical()) | ||||||
|  |         --bounds.y; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // The color doesn't matter, we are using CheckedDrawMode
 |     // 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(); |   Point scroll = view->viewScroll(); | ||||||
| 
 | 
 | ||||||
|   return gfx::Point( |   return gfx::Point( | ||||||
|     m_zoom.remove(pt.x - vp.x + scroll.x - m_padding.x), |     m_proj.removeX(pt.x - vp.x + scroll.x - m_padding.x), | ||||||
|     m_zoom.remove(pt.y - vp.y + scroll.y - m_padding.y)); |     m_proj.removeY(pt.y - vp.y + scroll.y - m_padding.y)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Point Editor::editorToScreen(const gfx::Point& pt) | Point Editor::editorToScreen(const gfx::Point& pt) | ||||||
|  | @ -956,8 +968,8 @@ Point Editor::editorToScreen(const gfx::Point& pt) | ||||||
|   Point scroll = view->viewScroll(); |   Point scroll = view->viewScroll(); | ||||||
| 
 | 
 | ||||||
|   return Point( |   return Point( | ||||||
|     (vp.x - scroll.x + m_padding.x + m_zoom.apply(pt.x)), |     (vp.x - scroll.x + m_padding.x + m_proj.applyX(pt.x)), | ||||||
|     (vp.y - scroll.y + m_padding.y + m_zoom.apply(pt.y))); |     (vp.y - scroll.y + m_padding.y + m_proj.applyY(pt.y))); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Rect Editor::screenToEditor(const Rect& rc) | Rect Editor::screenToEditor(const Rect& rc) | ||||||
|  | @ -1013,8 +1025,8 @@ void Editor::centerInSpritePoint(const gfx::Point& spritePos) | ||||||
|   Rect vp = view->viewportBounds(); |   Rect vp = view->viewportBounds(); | ||||||
| 
 | 
 | ||||||
|   gfx::Point scroll( |   gfx::Point scroll( | ||||||
|     m_padding.x - (vp.w/2) + m_zoom.apply(1)/2 + m_zoom.apply(spritePos.x), |     m_padding.x - (vp.w/2) + m_proj.applyX(1)/2 + m_proj.applyX(spritePos.x), | ||||||
|     m_padding.y - (vp.h/2) + m_zoom.apply(1)/2 + m_zoom.apply(spritePos.y)); |     m_padding.y - (vp.h/2) + m_proj.applyY(1)/2 + m_proj.applyY(spritePos.y)); | ||||||
| 
 | 
 | ||||||
|   updateEditor(); |   updateEditor(); | ||||||
|   setEditorScroll(scroll); |   setEditorScroll(scroll); | ||||||
|  | @ -1316,9 +1328,9 @@ void Editor::onSizeHint(SizeHintEvent& ev) | ||||||
|   gfx::Size sz(0, 0); |   gfx::Size sz(0, 0); | ||||||
| 
 | 
 | ||||||
|   if (m_sprite) { |   if (m_sprite) { | ||||||
|     gfx::Point padding = calcExtraPadding(m_zoom); |     gfx::Point padding = calcExtraPadding(m_proj); | ||||||
|     sz.w = m_zoom.apply(m_sprite->width()) + padding.x*2; |     sz.w = m_proj.applyX(m_sprite->width()) + padding.x*2; | ||||||
|     sz.h = m_zoom.apply(m_sprite->height()) + padding.y*2; |     sz.h = m_proj.applyY(m_sprite->height()) + padding.y*2; | ||||||
|   } |   } | ||||||
|   else { |   else { | ||||||
|     sz.w = 4; |     sz.w = 4; | ||||||
|  | @ -1330,7 +1342,7 @@ void Editor::onSizeHint(SizeHintEvent& ev) | ||||||
| void Editor::onResize(ui::ResizeEvent& ev) | void Editor::onResize(ui::ResizeEvent& ev) | ||||||
| { | { | ||||||
|   Widget::onResize(ev); |   Widget::onResize(ev); | ||||||
|   m_padding = calcExtraPadding(m_zoom); |   m_padding = calcExtraPadding(m_proj); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Editor::onPaint(ui::PaintEvent& ev) | void Editor::onPaint(ui::PaintEvent& ev) | ||||||
|  | @ -1440,11 +1452,14 @@ bool Editor::isInsideSelection() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Editor::setZoomAndCenterInMouse(const Zoom& zoom, | void Editor::setZoomAndCenterInMouse(const Zoom& zoom, | ||||||
|   const gfx::Point& mousePos, ZoomBehavior zoomBehavior) |                                      const gfx::Point& mousePos, | ||||||
|  |                                      ZoomBehavior zoomBehavior) | ||||||
| { | { | ||||||
|   HideBrushPreview hide(m_brushPreview); |   HideBrushPreview hide(m_brushPreview); | ||||||
|   View* view = View::getView(this); |   View* view = View::getView(this); | ||||||
|   Rect vp = view->viewportBounds(); |   Rect vp = view->viewportBounds(); | ||||||
|  |   Projection proj = m_proj; | ||||||
|  |   proj.setZoom(zoom); | ||||||
| 
 | 
 | ||||||
|   gfx::Point screenPos; |   gfx::Point screenPos; | ||||||
|   gfx::Point spritePos; |   gfx::Point spritePos; | ||||||
|  | @ -1461,27 +1476,36 @@ void Editor::setZoomAndCenterInMouse(const Zoom& zoom, | ||||||
|   } |   } | ||||||
|   spritePos = screenToEditor(screenPos); |   spritePos = screenToEditor(screenPos); | ||||||
| 
 | 
 | ||||||
|   if (zoomBehavior == ZoomBehavior::MOUSE && |   if (zoomBehavior == ZoomBehavior::MOUSE) { | ||||||
|       m_zoom.scale() > 1.0) { |  | ||||||
|     gfx::Point screenPos2 = editorToScreen(spritePos); |     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()) { |     if (m_proj.scaleX() > 1.0) { | ||||||
|       double t = 1.0 / zoom.scale(); |       subpixelPos.x = (0.5 + screenPos.x - screenPos2.x) / m_proj.scaleX(); | ||||||
|       if (subpixelPos.x >= 0.5-t && subpixelPos.x <= 0.5+t) subpixelPos.x = 0.5; |       if (proj.scaleX() > m_proj.scaleX()) { | ||||||
|       if (subpixelPos.y >= 0.5-t && subpixelPos.y <= 0.5+t) subpixelPos.y = 0.5; |         double t = 1.0 / proj.scaleX(); | ||||||
|  |         if (subpixelPos.x >= 0.5-t && subpixelPos.x <= 0.5+t) | ||||||
|  |           subpixelPos.x = 0.5; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|   gfx::Point padding = calcExtraPadding(zoom); |     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(proj); | ||||||
|   gfx::Point scrollPos( |   gfx::Point scrollPos( | ||||||
|     padding.x - (screenPos.x-vp.x) + zoom.apply(spritePos.x+zoom.remove(1)/2) + int(zoom.apply(subpixelPos.x)), |     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) + zoom.apply(spritePos.y+zoom.remove(1)/2) + int(zoom.apply(subpixelPos.y))); |     padding.y - (screenPos.y-vp.y) + proj.applyY(spritePos.y+proj.removeY(1)/2) + int(proj.applyY(subpixelPos.y))); | ||||||
| 
 | 
 | ||||||
|   setZoom(zoom); |   setZoom(zoom); | ||||||
| 
 | 
 | ||||||
|   if ((m_zoom != zoom) || (screenPos != view->viewScroll())) { |   if ((m_proj.zoom() != zoom) || (screenPos != view->viewScroll())) { | ||||||
|     updateEditor(); |     updateEditor(); | ||||||
|     setEditorScroll(scrollPos); |     setEditorScroll(scrollPos); | ||||||
|   } |   } | ||||||
|  | @ -1675,14 +1699,14 @@ ImageBufferPtr Editor::getRenderImageBuffer() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // static
 | // static
 | ||||||
| gfx::Point Editor::calcExtraPadding(const Zoom& zoom) | gfx::Point Editor::calcExtraPadding(const Projection& proj) | ||||||
| { | { | ||||||
|   View* view = View::getView(this); |   View* view = View::getView(this); | ||||||
|   if (view) { |   if (view) { | ||||||
|     Rect vp = view->viewportBounds(); |     Rect vp = view->viewportBounds(); | ||||||
|     return gfx::Point( |     return gfx::Point( | ||||||
|       std::max<int>(vp.w/2, vp.w - zoom.apply(m_sprite->width())), |       std::max<int>(vp.w/2, vp.w - proj.applyX(m_sprite->width())), | ||||||
|       std::max<int>(vp.h/2, vp.h - zoom.apply(m_sprite->height()))); |       std::max<int>(vp.h/2, vp.h - proj.applyY(m_sprite->height()))); | ||||||
|   } |   } | ||||||
|   else |   else | ||||||
|     return gfx::Point(0, 0); |     return gfx::Point(0, 0); | ||||||
|  |  | ||||||
|  | @ -131,7 +131,8 @@ namespace app { | ||||||
|     void setLayer(const Layer* layer); |     void setLayer(const Layer* layer); | ||||||
|     void setFrame(frame_t frame); |     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; } |     const gfx::Point& padding() const { return m_padding; } | ||||||
| 
 | 
 | ||||||
|     void setZoom(const render::Zoom& zoom); |     void setZoom(const render::Zoom& zoom); | ||||||
|  | @ -260,7 +261,7 @@ namespace app { | ||||||
|     // routine.
 |     // routine.
 | ||||||
|     void drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& rc, int dx, int dy); |     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(); |     void invalidateIfActive(); | ||||||
| 
 | 
 | ||||||
|  | @ -278,7 +279,7 @@ namespace app { | ||||||
|     Sprite* m_sprite;             // Active sprite in the editor
 |     Sprite* m_sprite;             // Active sprite in the editor
 | ||||||
|     Layer* m_layer;               // Active layer in the editor
 |     Layer* m_layer;               // Active layer in the editor
 | ||||||
|     frame_t m_frame;              // Active frame 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; |     DocumentPreferences& m_docPref; | ||||||
| 
 | 
 | ||||||
|     // Brush preview
 |     // Brush preview
 | ||||||
|  |  | ||||||
|  | @ -266,11 +266,11 @@ void SelectBoxState::preRenderDecorator(EditorPreRender* render) | ||||||
| void SelectBoxState::postRenderDecorator(EditorPostRender* render) | void SelectBoxState::postRenderDecorator(EditorPostRender* render) | ||||||
| { | { | ||||||
|   Editor* editor = render->getEditor(); |   Editor* editor = render->getEditor(); | ||||||
|   render::Zoom zoom = editor->zoom(); |   render::Projection proj = editor->projection(); | ||||||
|   gfx::Rect sp = editor->sprite()->bounds(); |   gfx::Rect sp = editor->sprite()->bounds(); | ||||||
|   gfx::Rect vp = View::getView(editor)->viewportBounds(); |   gfx::Rect vp = View::getView(editor)->viewportBounds(); | ||||||
|   vp.w += zoom.apply(1); |   vp.w += proj.applyX(1); | ||||||
|   vp.h += zoom.apply(1); |   vp.h += proj.applyY(1); | ||||||
|   vp = editor->screenToEditor(vp); |   vp = editor->screenToEditor(vp); | ||||||
| 
 | 
 | ||||||
|   // Paint a grid generated by the box
 |   // Paint a grid generated by the box
 | ||||||
|  |  | ||||||
|  | @ -312,8 +312,7 @@ public: | ||||||
|           m_floodfillSrcImage, |           m_floodfillSrcImage, | ||||||
|           m_sprite, |           m_sprite, | ||||||
|           m_frame, |           m_frame, | ||||||
|           gfx::Clip(m_sprite->bounds()), |           gfx::Clip(m_sprite->bounds())); | ||||||
|           render::Zoom(1, 1)); |  | ||||||
|       } |       } | ||||||
|       else { |       else { | ||||||
|         Cel* cel = m_layer->cel(m_frame); |         Cel* cel = m_layer->cel(m_frame); | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| // Aseprite
 | // 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
 | // 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
 | // 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::Size partSize = theme->parts.pivotHandle()->size(); | ||||||
|   gfx::Point screenPivotPos = editor->editorToScreen(transform.pivot()); |   gfx::Point screenPivotPos = editor->editorToScreen(transform.pivot()); | ||||||
| 
 | 
 | ||||||
|   screenPivotPos.x += editor->zoom().apply(1) / 2; |   screenPivotPos.x += editor->projection().applyX(1) / 2; | ||||||
|   screenPivotPos.y += editor->zoom().apply(1) / 2; |   screenPivotPos.y += editor->projection().applyY(1) / 2; | ||||||
| 
 | 
 | ||||||
|   return gfx::Rect( |   return gfx::Rect( | ||||||
|     screenPivotPos.x-partSize.w/2, |     screenPivotPos.x-partSize.w/2, | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| // Aseprite Document Library
 | // 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.
 | // This file is released under the terms of the MIT license.
 | ||||||
| // Read LICENSE.txt for more information.
 | // Read LICENSE.txt for more information.
 | ||||||
|  | @ -28,6 +28,7 @@ | ||||||
| #include "doc/palette.h" | #include "doc/palette.h" | ||||||
| #include "doc/palette_picks.h" | #include "doc/palette_picks.h" | ||||||
| #include "doc/pixel_format.h" | #include "doc/pixel_format.h" | ||||||
|  | #include "doc/pixel_ratio.h" | ||||||
| #include "doc/primitives.h" | #include "doc/primitives.h" | ||||||
| #include "doc/primitives_fast.h" | #include "doc/primitives_fast.h" | ||||||
| #include "doc/remap.h" | #include "doc/remap.h" | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| // Aseprite Gfx Library
 | // 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.
 | // This file is released under the terms of the MIT license.
 | ||||||
| // Read LICENSE.txt for more information.
 | // Read LICENSE.txt for more information.
 | ||||||
|  | @ -175,6 +175,18 @@ public: | ||||||
|     return *this; |     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) { |   RectT& shrink(const T& unit) { | ||||||
|     x += unit; |     x += unit; | ||||||
|     y += unit; |     y += unit; | ||||||
|  | @ -259,6 +271,22 @@ public: | ||||||
|     return *this; |     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) { |   const RectT& operator|=(const RectT& rc) { | ||||||
|     return *this = createUnion(rc); |     return *this = createUnion(rc); | ||||||
|   } |   } | ||||||
|  | @ -283,6 +311,16 @@ public: | ||||||
|     return createIntersection(other); |     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 { |   bool operator==(const RectT& rc) const { | ||||||
|     return |     return | ||||||
|       x == rc.x && w == rc.w && |       x == rc.x && w == rc.w && | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
|  | @ -29,9 +29,9 @@ class BlenderHelper { | ||||||
|   BlendFunc m_blend_func; |   BlendFunc m_blend_func; | ||||||
|   color_t m_mask_color; |   color_t m_mask_color; | ||||||
| public: | 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(); |     m_mask_color = src->maskColor(); | ||||||
|   } |   } | ||||||
|   inline typename DstTraits::pixel_t |   inline typename DstTraits::pixel_t | ||||||
|  | @ -51,9 +51,9 @@ class BlenderHelper<RgbTraits, GrayscaleTraits> { | ||||||
|   BlendFunc m_blend_func; |   BlendFunc m_blend_func; | ||||||
|   color_t m_mask_color; |   color_t m_mask_color; | ||||||
| public: | 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(); |     m_mask_color = src->maskColor(); | ||||||
|   } |   } | ||||||
|   inline RgbTraits::pixel_t |   inline RgbTraits::pixel_t | ||||||
|  | @ -73,14 +73,14 @@ public: | ||||||
| template<> | template<> | ||||||
| class BlenderHelper<RgbTraits, IndexedTraits> { | class BlenderHelper<RgbTraits, IndexedTraits> { | ||||||
|   const Palette* m_pal; |   const Palette* m_pal; | ||||||
|   BlendMode m_blend_mode; |   BlendMode m_blendMode; | ||||||
|   BlendFunc m_blend_func; |   BlendFunc m_blend_func; | ||||||
|   color_t m_mask_color; |   color_t m_mask_color; | ||||||
| public: | 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_blend_func = RgbTraits::get_blender(blend_mode); |     m_blend_func = RgbTraits::get_blender(blendMode); | ||||||
|     m_mask_color = src->maskColor(); |     m_mask_color = src->maskColor(); | ||||||
|     m_pal = pal; |     m_pal = pal; | ||||||
|   } |   } | ||||||
|  | @ -89,7 +89,7 @@ public: | ||||||
|              const IndexedTraits::pixel_t& src, |              const IndexedTraits::pixel_t& src, | ||||||
|                          int opacity) |                          int opacity) | ||||||
|   { |   { | ||||||
|     if (m_blend_mode == BlendMode::SRC) { |     if (m_blendMode == BlendMode::SRC) { | ||||||
|       return m_pal->getEntry(src); |       return m_pal->getEntry(src); | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|  | @ -104,12 +104,12 @@ public: | ||||||
| 
 | 
 | ||||||
| template<> | template<> | ||||||
| class BlenderHelper<IndexedTraits, IndexedTraits> { | class BlenderHelper<IndexedTraits, IndexedTraits> { | ||||||
|   BlendMode m_blend_mode; |   BlendMode m_blendMode; | ||||||
|   color_t m_mask_color; |   color_t m_mask_color; | ||||||
| public: | 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(); |     m_mask_color = src->maskColor(); | ||||||
|   } |   } | ||||||
|   inline IndexedTraits::pixel_t |   inline IndexedTraits::pixel_t | ||||||
|  | @ -117,7 +117,7 @@ public: | ||||||
|              const IndexedTraits::pixel_t& src, |              const IndexedTraits::pixel_t& src, | ||||||
|              int opacity) |              int opacity) | ||||||
|   { |   { | ||||||
|     if (m_blend_mode == BlendMode::SRC) { |     if (m_blendMode == BlendMode::SRC) { | ||||||
|       return src; |       return src; | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|  | @ -130,39 +130,39 @@ public: | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| template<class DstTraits, class SrcTraits> | 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, |   Image* dst, const Image* src, const Palette* pal, | ||||||
|   gfx::Clip area, |   gfx::Clip area, | ||||||
|   int opacity, BlendMode blend_mode, Zoom zoom) |   int opacity, BlendMode blendMode, | ||||||
|  |   const Projection& proj) | ||||||
| { | { | ||||||
|   ASSERT(dst); |   ASSERT(dst); | ||||||
|   ASSERT(src); |   ASSERT(src); | ||||||
|   ASSERT(DstTraits::pixel_format == dst->pixelFormat()); |   ASSERT(DstTraits::pixel_format == dst->pixelFormat()); | ||||||
|   ASSERT(SrcTraits::pixel_format == src->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(), |   if (!area.clip(dst->width(), dst->height(), | ||||||
|       zoom.apply(src->width()), |                  proj.applyX(src->width()), | ||||||
|       zoom.apply(src->height()))) |                  proj.applyY(src->height()))) | ||||||
|     return; |     return; | ||||||
| 
 | 
 | ||||||
|   int px_w = zoom.apply(1); |   BlenderHelper<DstTraits, SrcTraits> blender(src, pal, blendMode); | ||||||
|   int px_h = zoom.apply(1); |   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_w = px_w - (area.src.x % px_w); | ||||||
|   int first_px_h = px_h - (area.src.y % px_h); |   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(); |   gfx::Rect dstBounds = area.dstBounds(); | ||||||
|   int bottom = area.dst.y+area.size.h-1; |   int bottom = area.dst.y+area.size.h-1; | ||||||
|   int line_h; |   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
 |   // the scanline variable is used to blend src/dst pixels one time for each pixel
 | ||||||
|   typedef std::vector<typename DstTraits::pixel_t> Scanline; |   typedef std::vector<typename DstTraits::pixel_t> Scanline; | ||||||
|   Scanline scanline(srcBounds.w); |   Scanline scanline(srcBounds.w); | ||||||
|  | @ -262,32 +262,34 @@ done_with_blit:; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template<class DstTraits, class SrcTraits> | 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, |   Image* dst, const Image* src, const Palette* pal, | ||||||
|   gfx::Clip area, |   gfx::Clip area, int opacity, BlendMode blendMode, | ||||||
|   int opacity, BlendMode blend_mode, Zoom zoom) |   const Projection& proj) | ||||||
| { | { | ||||||
|   ASSERT(dst); |   ASSERT(dst); | ||||||
|   ASSERT(src); |   ASSERT(src); | ||||||
|   ASSERT(DstTraits::pixel_format == dst->pixelFormat()); |   ASSERT(DstTraits::pixel_format == dst->pixelFormat()); | ||||||
|   ASSERT(SrcTraits::pixel_format == src->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(), |   if (!area.clip(dst->width(), dst->height(), | ||||||
|       zoom.apply(src->width()), |                  proj.applyX(src->width()), | ||||||
|       zoom.apply(src->height()))) |                  proj.applyY(src->height()))) | ||||||
|     return; |     return; | ||||||
| 
 | 
 | ||||||
|   gfx::Rect srcBounds = zoom.remove(area.srcBounds()); |   BlenderHelper<DstTraits, SrcTraits> blender(src, pal, blendMode); | ||||||
|   gfx::Rect dstBounds = area.dstBounds(); |   int unbox_w = proj.removeX(1); | ||||||
|   int bottom = area.dst.y+area.size.h-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()) |   if (srcBounds.isEmpty()) | ||||||
|     return; |     return; | ||||||
| 
 | 
 | ||||||
|  |   gfx::Rect dstBounds = area.dstBounds(); | ||||||
|  |   int bottom = area.dst.y+area.size.h-1; | ||||||
|  | 
 | ||||||
|   // Lock all necessary bits
 |   // Lock all necessary bits
 | ||||||
|   const LockImageBits<SrcTraits> srcBits(src, srcBounds); |   const LockImageBits<SrcTraits> srcBits(src, srcBounds); | ||||||
|   LockImageBits<DstTraits> dstBits(dst, dstBounds); |   LockImageBits<DstTraits> dstBits(dst, dstBounds); | ||||||
|  | @ -327,12 +329,14 @@ template<class DstTraits, class SrcTraits> | ||||||
| static void compose_scaled_image( | static void compose_scaled_image( | ||||||
|   Image* dst, const Image* src, const Palette* pal, |   Image* dst, const Image* src, const Palette* pal, | ||||||
|   const gfx::Clip& area, |   const gfx::Clip& area, | ||||||
|   int opacity, BlendMode blend_mode, Zoom zoom) |   int opacity, | ||||||
|  |   BlendMode blendMode, | ||||||
|  |   const Projection& proj) | ||||||
| { | { | ||||||
|   if (zoom.scale() >= 1.0) |   if (proj.zoom().scale() >= 1.0) | ||||||
|     compose_scaled_image_scale_up<DstTraits, SrcTraits>(dst, src, pal, area, opacity, blend_mode, zoom); |     compose_scaled_image_zoom_in<DstTraits, SrcTraits>(dst, src, pal, area, opacity, blendMode, proj); | ||||||
|   else |   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() | Render::Render() | ||||||
|  | @ -353,6 +357,11 @@ Render::Render() | ||||||
| { | { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void Render::setProjection(const Projection& projection) | ||||||
|  | { | ||||||
|  |   m_proj = projection; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void Render::setBgType(BgType type) | void Render::setBgType(BgType type) | ||||||
| { | { | ||||||
|   m_bgType = type; |   m_bgType = type; | ||||||
|  | @ -427,17 +436,9 @@ void Render::renderSprite( | ||||||
|   const Sprite* sprite, |   const Sprite* sprite, | ||||||
|   frame_t frame) |   frame_t frame) | ||||||
| { | { | ||||||
|   renderSprite(dstImage, sprite, frame, |   renderSprite( | ||||||
|     gfx::Clip(sprite->bounds()), Zoom(1, 1)); |     dstImage, sprite, frame, | ||||||
| } |     gfx::Clip(sprite->bounds())); | ||||||
| 
 |  | ||||||
| void Render::renderSprite( |  | ||||||
|   Image* dstImage, |  | ||||||
|   const Sprite* sprite, |  | ||||||
|   frame_t frame, |  | ||||||
|   const gfx::Clip& area) |  | ||||||
| { |  | ||||||
|   renderSprite(dstImage, sprite, frame, area, Zoom(1, 1)); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Render::renderLayer( | void Render::renderLayer( | ||||||
|  | @ -454,7 +455,7 @@ void Render::renderLayer( | ||||||
|   const Layer* layer, |   const Layer* layer, | ||||||
|   frame_t frame, |   frame_t frame, | ||||||
|   const gfx::Clip& area, |   const gfx::Clip& area, | ||||||
|   BlendMode blend_mode) |   BlendMode blendMode) | ||||||
| { | { | ||||||
|   m_sprite = layer->sprite(); |   m_sprite = layer->sprite(); | ||||||
| 
 | 
 | ||||||
|  | @ -467,17 +468,15 @@ void Render::renderLayer( | ||||||
| 
 | 
 | ||||||
|   m_globalOpacity = 255; |   m_globalOpacity = 255; | ||||||
|   renderLayer( |   renderLayer( | ||||||
|     layer, dstImage, area, |     layer, dstImage, area, frame, | ||||||
|     frame, Zoom(1, 1), scaled_func, |     scaled_func, true, true, blendMode); | ||||||
|     true, true, blend_mode); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Render::renderSprite( | void Render::renderSprite( | ||||||
|   Image* dstImage, |   Image* dstImage, | ||||||
|   const Sprite* sprite, |   const Sprite* sprite, | ||||||
|   frame_t frame, |   frame_t frame, | ||||||
|   const gfx::Clip& area, |   const gfx::Clip& area) | ||||||
|   Zoom zoom) |  | ||||||
| { | { | ||||||
|   m_sprite = sprite; |   m_sprite = sprite; | ||||||
| 
 | 
 | ||||||
|  | @ -511,7 +510,7 @@ void Render::renderSprite( | ||||||
|         fill_rect(dstImage, area.dstBounds(), bg_color); |         fill_rect(dstImage, area.dstBounds(), bg_color); | ||||||
|       } |       } | ||||||
|       else { |       else { | ||||||
|         renderBackground(dstImage, area, zoom); |         renderBackground(dstImage, area); | ||||||
|         if (bgLayer && bgLayer->isVisible() && rgba_geta(bg_color) > 0) { |         if (bgLayer && bgLayer->isVisible() && rgba_geta(bg_color) > 0) { | ||||||
|           blend_rect(dstImage, area.dst.x, area.dst.y, |           blend_rect(dstImage, area.dst.x, area.dst.y, | ||||||
|                      area.dst.x+area.size.w-1, |                      area.dst.x+area.size.w-1, | ||||||
|  | @ -530,27 +529,27 @@ void Render::renderSprite( | ||||||
|   m_globalOpacity = 255; |   m_globalOpacity = 255; | ||||||
|   renderLayer( |   renderLayer( | ||||||
|     m_sprite->folder(), dstImage, |     m_sprite->folder(), dstImage, | ||||||
|     area, frame, zoom, scaled_func, |     area, frame, scaled_func, | ||||||
|     true, |     true, | ||||||
|     false, |     false, | ||||||
|     BlendMode::UNSPECIFIED); |     BlendMode::UNSPECIFIED); | ||||||
| 
 | 
 | ||||||
|   // Draw onion skin behind the sprite.
 |   // Draw onion skin behind the sprite.
 | ||||||
|   if (m_onionskin.position() == OnionskinPosition::BEHIND) |   if (m_onionskin.position() == OnionskinPosition::BEHIND) | ||||||
|     renderOnionskin(dstImage, area, frame, zoom, scaled_func); |     renderOnionskin(dstImage, area, frame, scaled_func); | ||||||
| 
 | 
 | ||||||
|   // Draw the transparent layers.
 |   // Draw the transparent layers.
 | ||||||
|   m_globalOpacity = 255; |   m_globalOpacity = 255; | ||||||
|   renderLayer( |   renderLayer( | ||||||
|     m_sprite->folder(), dstImage, |     m_sprite->folder(), dstImage, | ||||||
|     area, frame, zoom, scaled_func, |     area, frame, scaled_func, | ||||||
|     false, |     false, | ||||||
|     true, |     true, | ||||||
|     BlendMode::UNSPECIFIED); |     BlendMode::UNSPECIFIED); | ||||||
| 
 | 
 | ||||||
|   // Draw onion skin in front of the sprite.
 |   // Draw onion skin in front of the sprite.
 | ||||||
|   if (m_onionskin.position() == OnionskinPosition::INFRONT) |   if (m_onionskin.position() == OnionskinPosition::INFRONT) | ||||||
|     renderOnionskin(dstImage, area, frame, zoom, scaled_func); |     renderOnionskin(dstImage, area, frame, scaled_func); | ||||||
| 
 | 
 | ||||||
|   // Overlay preview image
 |   // Overlay preview image
 | ||||||
|   if (m_previewImage && |   if (m_previewImage && | ||||||
|  | @ -564,15 +563,14 @@ void Render::renderSprite( | ||||||
|       area, |       area, | ||||||
|       scaled_func, |       scaled_func, | ||||||
|       255, |       255, | ||||||
|       m_previewBlendMode, |       m_previewBlendMode); | ||||||
|       zoom); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Render::renderOnionskin( | void Render::renderOnionskin( | ||||||
|   Image* dstImage, |   Image* dstImage, | ||||||
|   const gfx::Clip& area, |   const gfx::Clip& area, | ||||||
|   frame_t frame, Zoom zoom, |   frame_t frame, | ||||||
|   RenderScaledImage scaled_func) |   RenderScaledImage scaled_func) | ||||||
| { | { | ||||||
|   // Onion-skin feature: Draw previous/next frames with different
 |   // Onion-skin feature: Draw previous/next frames with different
 | ||||||
|  | @ -612,43 +610,42 @@ void Render::renderOnionskin( | ||||||
| 
 | 
 | ||||||
|       m_globalOpacity = MID(0, m_globalOpacity, 255); |       m_globalOpacity = MID(0, m_globalOpacity, 255); | ||||||
|       if (m_globalOpacity > 0) { |       if (m_globalOpacity > 0) { | ||||||
|         BlendMode blend_mode = BlendMode::UNSPECIFIED; |         BlendMode blendMode = BlendMode::UNSPECIFIED; | ||||||
|         if (m_onionskin.type() == OnionskinType::MERGE) |         if (m_onionskin.type() == OnionskinType::MERGE) | ||||||
|           blend_mode = BlendMode::NORMAL; |           blendMode = BlendMode::NORMAL; | ||||||
|         else if (m_onionskin.type() == OnionskinType::RED_BLUE_TINT) |         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( |         renderLayer( | ||||||
|           onionLayer, dstImage, |           onionLayer, dstImage, | ||||||
|           area, frameIn, zoom, scaled_func, |           area, frameIn, scaled_func, | ||||||
|           // Render background only for "in-front" onion skinning and
 |           // Render background only for "in-front" onion skinning and
 | ||||||
|           // when opacity is < 255
 |           // when opacity is < 255
 | ||||||
|           (m_globalOpacity < 255 && |           (m_globalOpacity < 255 && | ||||||
|            m_onionskin.position() == OnionskinPosition::INFRONT), |            m_onionskin.position() == OnionskinPosition::INFRONT), | ||||||
|           true, |           true, | ||||||
|           blend_mode); |           blendMode); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Render::renderBackground(Image* image, | void Render::renderBackground( | ||||||
|   const gfx::Clip& area, |   Image* image, | ||||||
|   Zoom zoom) |   const gfx::Clip& area) | ||||||
| { | { | ||||||
|   int x, y, u, v; |   int x, y, u, v; | ||||||
|   int tile_w = m_bgCheckedSize.w; |   int tile_w = m_bgCheckedSize.w; | ||||||
|   int tile_h = m_bgCheckedSize.h; |   int tile_h = m_bgCheckedSize.h; | ||||||
| 
 | 
 | ||||||
|   if (m_bgZoom) { |   if (m_bgZoom) { | ||||||
|     tile_w = zoom.apply(tile_w); |     tile_w = m_proj.zoom().apply(tile_w); | ||||||
|     tile_h = zoom.apply(tile_h); |     tile_h = m_proj.zoom().apply(tile_h); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // Tile size
 |   // Tile size
 | ||||||
|   if (tile_w < zoom.apply(1)) tile_w = zoom.apply(1); |   if (tile_w < m_proj.applyX(1)) tile_w = m_proj.applyX(1); | ||||||
|   if (tile_h < zoom.apply(1)) tile_h = zoom.apply(1); |   if (tile_h < m_proj.applyY(1)) tile_h = m_proj.applyY(1); | ||||||
| 
 |  | ||||||
|   if (tile_w < 1) tile_w = 1; |   if (tile_w < 1) tile_w = 1; | ||||||
|   if (tile_h < 1) tile_h = 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, | void Render::renderImage( | ||||||
|  |   Image* dst_image, const Image* src_image, | ||||||
|   const Palette* pal, |   const Palette* pal, | ||||||
|   int x, int y, |   int x, int y, | ||||||
|                          Zoom zoom, int opacity, BlendMode blend_mode) |   int opacity, BlendMode blendMode) | ||||||
| { | { | ||||||
|   RenderScaledImage scaled_func = getRenderScaledImageFunc( |   RenderScaledImage scaled_func = getRenderScaledImageFunc( | ||||||
|     dst_image->pixelFormat(), |     dst_image->pixelFormat(), | ||||||
|  | @ -689,22 +687,24 @@ void Render::renderImage(Image* dst_image, const Image* src_image, | ||||||
|   if (!scaled_func) |   if (!scaled_func) | ||||||
|     return; |     return; | ||||||
| 
 | 
 | ||||||
|   scaled_func(dst_image, src_image, pal, |   scaled_func( | ||||||
|  |     dst_image, src_image, pal, | ||||||
|     gfx::Clip(x, y, 0, 0, |     gfx::Clip(x, y, 0, 0, | ||||||
|       zoom.apply(src_image->width()), |               m_proj.applyX(src_image->width()), | ||||||
|       zoom.apply(src_image->height())), |               m_proj.applyY(src_image->height())), | ||||||
|     opacity, blend_mode, zoom); |     opacity, blendMode, | ||||||
|  |     m_proj); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Render::renderLayer( | void Render::renderLayer( | ||||||
|   const Layer* layer, |   const Layer* layer, | ||||||
|   Image *image, |   Image *image, | ||||||
|   const gfx::Clip& area, |   const gfx::Clip& area, | ||||||
|   frame_t frame, Zoom zoom, |   frame_t frame, | ||||||
|   RenderScaledImage scaled_func, |   RenderScaledImage scaled_func, | ||||||
|   bool render_background, |   bool render_background, | ||||||
|   bool render_transparent, |   bool render_transparent, | ||||||
|   BlendMode blend_mode) |   BlendMode blendMode) | ||||||
| { | { | ||||||
|   // we can't read from this layer
 |   // we can't read from this layer
 | ||||||
|   if (!layer->isVisible()) |   if (!layer->isVisible()) | ||||||
|  | @ -724,11 +724,9 @@ void Render::renderLayer( | ||||||
|       m_extraCel->y(), |       m_extraCel->y(), | ||||||
|       m_extraImage->width(), |       m_extraImage->width(), | ||||||
|       m_extraImage->height()); |       m_extraImage->height()); | ||||||
|     extraArea = zoom.apply(extraArea); |     extraArea = m_proj.apply(extraArea); | ||||||
|     if (zoom.scale() < 1.0) { |     if (m_proj.scaleX() < 1.0) extraArea.w--; | ||||||
|       extraArea.w--; |     if (m_proj.scaleY() < 1.0) extraArea.h--; | ||||||
|       extraArea.h--; |  | ||||||
|     } |  | ||||||
|     if (extraArea.w < 1) extraArea.w = 1; |     if (extraArea.w < 1) extraArea.w = 1; | ||||||
|     if (extraArea.h < 1) extraArea.h = 1; |     if (extraArea.h < 1) extraArea.h = 1; | ||||||
|   } |   } | ||||||
|  | @ -761,9 +759,9 @@ void Render::renderLayer( | ||||||
|         if (src_image) { |         if (src_image) { | ||||||
|           const LayerImage* imgLayer = static_cast<const LayerImage*>(layer); |           const LayerImage* imgLayer = static_cast<const LayerImage*>(layer); | ||||||
|           BlendMode layerBlendMode = |           BlendMode layerBlendMode = | ||||||
|             (blend_mode == BlendMode::UNSPECIFIED ? |             (blendMode == BlendMode::UNSPECIFIED ? | ||||||
|              imgLayer->blendMode(): |              imgLayer->blendMode(): | ||||||
|              blend_mode); |              blendMode); | ||||||
| 
 | 
 | ||||||
|           ASSERT(cel->opacity() >= 0); |           ASSERT(cel->opacity() >= 0); | ||||||
|           ASSERT(cel->opacity() <= 255); |           ASSERT(cel->opacity() <= 255); | ||||||
|  | @ -789,7 +787,7 @@ void Render::renderLayer( | ||||||
|                 image, src_image, pal, |                 image, src_image, pal, | ||||||
|                 cel, gfx::Clip(area.dst.x+rc.x-area.src.x, |                 cel, gfx::Clip(area.dst.x+rc.x-area.src.x, | ||||||
|                                area.dst.y+rc.y-area.src.y, rc), scaled_func, |                                area.dst.y+rc.y-area.src.y, rc), scaled_func, | ||||||
|                 opacity, layerBlendMode, zoom); |                 opacity, layerBlendMode); | ||||||
|             } |             } | ||||||
|           } |           } | ||||||
|           // Draw the whole cel
 |           // Draw the whole cel
 | ||||||
|  | @ -797,7 +795,7 @@ void Render::renderLayer( | ||||||
|             renderCel( |             renderCel( | ||||||
|               image, src_image, pal, |               image, src_image, pal, | ||||||
|               cel, area, scaled_func, |               cel, area, scaled_func, | ||||||
|               opacity, layerBlendMode, zoom); |               opacity, layerBlendMode); | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|  | @ -809,11 +807,13 @@ void Render::renderLayer( | ||||||
|       LayerConstIterator end = static_cast<const LayerFolder*>(layer)->getLayerEnd(); |       LayerConstIterator end = static_cast<const LayerFolder*>(layer)->getLayerEnd(); | ||||||
| 
 | 
 | ||||||
|       for (; it != end; ++it) { |       for (; it != end; ++it) { | ||||||
|         renderLayer(*it, image, |         renderLayer( | ||||||
|           area, frame, zoom, scaled_func, |           *it, image, | ||||||
|  |           area, frame, | ||||||
|  |           scaled_func, | ||||||
|           render_background, |           render_background, | ||||||
|           render_transparent, |           render_transparent, | ||||||
|           blend_mode); |           blendMode); | ||||||
|       } |       } | ||||||
|       break; |       break; | ||||||
|     } |     } | ||||||
|  | @ -832,7 +832,7 @@ void Render::renderLayer( | ||||||
|                   extraArea), |                   extraArea), | ||||||
|         scaled_func, |         scaled_func, | ||||||
|         m_extraCel->opacity(), |         m_extraCel->opacity(), | ||||||
|         m_extraBlendMode, zoom); |         m_extraBlendMode); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | @ -844,7 +844,7 @@ void Render::renderCel( | ||||||
|   const Cel* cel, |   const Cel* cel, | ||||||
|   const gfx::Clip& area, |   const gfx::Clip& area, | ||||||
|   RenderScaledImage scaled_func, |   RenderScaledImage scaled_func, | ||||||
|   int opacity, BlendMode blend_mode, Zoom zoom) |   int opacity, BlendMode blendMode) | ||||||
| { | { | ||||||
|   renderImage(dst_image, |   renderImage(dst_image, | ||||||
|               cel_image, |               cel_image, | ||||||
|  | @ -854,8 +854,7 @@ void Render::renderCel( | ||||||
|               area, |               area, | ||||||
|               scaled_func, |               scaled_func, | ||||||
|               opacity, |               opacity, | ||||||
|               blend_mode, |               blendMode); | ||||||
|               zoom); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Render::renderImage( | void Render::renderImage( | ||||||
|  | @ -866,30 +865,32 @@ void Render::renderImage( | ||||||
|   const int y, |   const int y, | ||||||
|   const gfx::Clip& area, |   const gfx::Clip& area, | ||||||
|   RenderScaledImage scaled_func, |   RenderScaledImage scaled_func, | ||||||
|   int opacity, BlendMode blend_mode, Zoom zoom) |   int opacity, BlendMode blendMode) | ||||||
| { | { | ||||||
|   int cel_x = zoom.apply(x); |   int cel_x = m_proj.applyX(x); | ||||||
|   int cel_y = zoom.apply(y); |   int cel_y = m_proj.applyY(y); | ||||||
| 
 | 
 | ||||||
|   gfx::Rect src_bounds = |   gfx::Rect srcBounds = | ||||||
|     area.srcBounds().createIntersection( |     area.srcBounds().createIntersection( | ||||||
|       gfx::Rect( |       gfx::Rect( | ||||||
|         cel_x, |         cel_x, | ||||||
|         cel_y, |         cel_y, | ||||||
|         zoom.apply(cel_image->width()), |         m_proj.applyX(cel_image->width()), | ||||||
|         zoom.apply(cel_image->height()))); |         m_proj.applyY(cel_image->height()))); | ||||||
|   if (src_bounds.isEmpty()) |   if (srcBounds.isEmpty()) | ||||||
|     return; |     return; | ||||||
| 
 | 
 | ||||||
|   (*scaled_func)(dst_image, cel_image, pal, |   (*scaled_func)( | ||||||
|  |     dst_image, cel_image, pal, | ||||||
|     gfx::Clip( |     gfx::Clip( | ||||||
|       area.dst.x + src_bounds.x - area.src.x, |       area.dst.x + srcBounds.x - area.src.x, | ||||||
|       area.dst.y + src_bounds.y - area.src.y, |       area.dst.y + srcBounds.y - area.src.y, | ||||||
|       src_bounds.x - cel_x, |       srcBounds.x - cel_x, | ||||||
|       src_bounds.y - cel_y, |       srcBounds.y - cel_y, | ||||||
|       src_bounds.w, |       srcBounds.w, | ||||||
|       src_bounds.h), |       srcBounds.h), | ||||||
|     opacity, blend_mode, zoom); |     opacity, blendMode, | ||||||
|  |     m_proj); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // static
 | // static
 | ||||||
|  | @ -931,13 +932,13 @@ Render::RenderScaledImage Render::getRenderScaledImageFunc( | ||||||
| void composite_image(Image* dst, const Image* src, | void composite_image(Image* dst, const Image* src, | ||||||
|                      const Palette* pal, |                      const Palette* pal, | ||||||
|                      int x, int y, |                      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
 |   // As the background is not rendered in renderImage(), we don't need
 | ||||||
|   // to configure the Render instance's BgType.
 |   // to configure the Render instance's BgType.
 | ||||||
|   Render().renderImage( |   Render().renderImage( | ||||||
|     dst, src, pal, x, y, Zoom(1, 1), |     dst, src, pal, x, y, | ||||||
|     opacity, blend_mode); |     opacity, blendMode); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace render
 | } // namespace render
 | ||||||
|  |  | ||||||
|  | @ -17,7 +17,7 @@ | ||||||
| #include "gfx/size.h" | #include "gfx/size.h" | ||||||
| #include "render/extra_type.h" | #include "render/extra_type.h" | ||||||
| #include "render/onionskin_position.h" | #include "render/onionskin_position.h" | ||||||
| #include "render/zoom.h" | #include "render/projection.h" | ||||||
| 
 | 
 | ||||||
| namespace gfx { | namespace gfx { | ||||||
|   class Clip; |   class Clip; | ||||||
|  | @ -93,6 +93,9 @@ namespace render { | ||||||
|   public: |   public: | ||||||
|     Render(); |     Render(); | ||||||
| 
 | 
 | ||||||
|  |     // Viewport configuration
 | ||||||
|  |     void setProjection(const Projection& projection); | ||||||
|  | 
 | ||||||
|     // Background configuration
 |     // Background configuration
 | ||||||
|     void setBgType(BgType type); |     void setBgType(BgType type); | ||||||
|     void setBgZoom(bool state); |     void setBgZoom(bool state); | ||||||
|  | @ -123,12 +126,6 @@ namespace render { | ||||||
|       const Sprite* sprite, |       const Sprite* sprite, | ||||||
|       frame_t frame); |       frame_t frame); | ||||||
| 
 | 
 | ||||||
|     void renderSprite( |  | ||||||
|       Image* dstImage, |  | ||||||
|       const Sprite* sprite, |  | ||||||
|       frame_t frame, |  | ||||||
|       const gfx::Clip& area); |  | ||||||
| 
 |  | ||||||
|     void renderLayer( |     void renderLayer( | ||||||
|       Image* dstImage, |       Image* dstImage, | ||||||
|       const Layer* layer, |       const Layer* layer, | ||||||
|  | @ -139,7 +136,7 @@ namespace render { | ||||||
|       const Layer* layer, |       const Layer* layer, | ||||||
|       frame_t frame, |       frame_t frame, | ||||||
|       const gfx::Clip& area, |       const gfx::Clip& area, | ||||||
|       BlendMode blend_mode = BlendMode::UNSPECIFIED); |       BlendMode blendMode = BlendMode::UNSPECIFIED); | ||||||
| 
 | 
 | ||||||
|     // Main function used to render the sprite. Draws the given sprite
 |     // Main function used to render the sprite. Draws the given sprite
 | ||||||
|     // frame in a new image and return it. Note: zoomedRect must have
 |     // frame in a new image and return it. Note: zoomedRect must have
 | ||||||
|  | @ -148,39 +145,41 @@ namespace render { | ||||||
|       Image* dstImage, |       Image* dstImage, | ||||||
|       const Sprite* sprite, |       const Sprite* sprite, | ||||||
|       frame_t frame, |       frame_t frame, | ||||||
|       const gfx::Clip& area, |       const gfx::Clip& area); | ||||||
|       Zoom zoom); |  | ||||||
| 
 | 
 | ||||||
|     // Extra functions
 |     // Extra functions
 | ||||||
|     void renderBackground(Image* image, |     void renderBackground( | ||||||
|       const gfx::Clip& area, |       Image* image, | ||||||
|       Zoom zoom); |       const gfx::Clip& area); | ||||||
| 
 | 
 | ||||||
|     void renderImage(Image* dst_image, const Image* src_image, |     void renderImage( | ||||||
|       const Palette* pal, int x, int y, Zoom zoom, |       Image* dst_image, const Image* src_image, | ||||||
|       int opacity, BlendMode blend_mode); |       const Palette* pal, int x, int y, | ||||||
|  |       int opacity, BlendMode blendMode); | ||||||
| 
 | 
 | ||||||
|   private: |   private: | ||||||
|     typedef void (*RenderScaledImage)( |     typedef void (*RenderScaledImage)( | ||||||
|       Image* dst, const Image* src, const Palette* pal, |       Image* dst, const Image* src, const Palette* pal, | ||||||
|       const gfx::Clip& area, |       const gfx::Clip& area, | ||||||
|       int opacity, BlendMode blend_mode, Zoom zoom); |       int opacity, | ||||||
|  |       BlendMode blendMode, | ||||||
|  |       const Projection& proj); | ||||||
| 
 | 
 | ||||||
|     void renderOnionskin( |     void renderOnionskin( | ||||||
|       Image* image, |       Image* image, | ||||||
|       const gfx::Clip& area, |       const gfx::Clip& area, | ||||||
|       frame_t frame, Zoom zoom, |       frame_t frame, | ||||||
|       RenderScaledImage scaled_func); |       RenderScaledImage scaled_func); | ||||||
| 
 | 
 | ||||||
|     void renderLayer( |     void renderLayer( | ||||||
|       const Layer* layer, |       const Layer* layer, | ||||||
|       Image* image, |       Image* image, | ||||||
|       const gfx::Clip& area, |       const gfx::Clip& area, | ||||||
|       frame_t frame, Zoom zoom, |       frame_t frame, | ||||||
|       RenderScaledImage renderScaledImage, |       RenderScaledImage renderScaledImage, | ||||||
|       bool render_background, |       bool render_background, | ||||||
|       bool render_transparent, |       bool render_transparent, | ||||||
|       BlendMode blend_mode); |       BlendMode blendMode); | ||||||
| 
 | 
 | ||||||
|     void renderCel( |     void renderCel( | ||||||
|       Image* dst_image, |       Image* dst_image, | ||||||
|  | @ -189,7 +188,7 @@ namespace render { | ||||||
|       const Cel* cel, |       const Cel* cel, | ||||||
|       const gfx::Clip& area, |       const gfx::Clip& area, | ||||||
|       RenderScaledImage scaled_func, |       RenderScaledImage scaled_func, | ||||||
|       int opacity, BlendMode blend_mode, Zoom zoom); |       int opacity, BlendMode blendMode); | ||||||
| 
 | 
 | ||||||
|     void renderImage( |     void renderImage( | ||||||
|       Image* dst_image, |       Image* dst_image, | ||||||
|  | @ -199,7 +198,7 @@ namespace render { | ||||||
|       const int y, |       const int y, | ||||||
|       const gfx::Clip& area, |       const gfx::Clip& area, | ||||||
|       RenderScaledImage scaled_func, |       RenderScaledImage scaled_func, | ||||||
|       int opacity, BlendMode blend_mode, Zoom zoom); |       int opacity, BlendMode blendMode); | ||||||
| 
 | 
 | ||||||
|     static RenderScaledImage getRenderScaledImageFunc( |     static RenderScaledImage getRenderScaledImageFunc( | ||||||
|       PixelFormat dstFormat, |       PixelFormat dstFormat, | ||||||
|  | @ -208,11 +207,11 @@ namespace render { | ||||||
|     const Sprite* m_sprite; |     const Sprite* m_sprite; | ||||||
|     const Layer* m_currentLayer; |     const Layer* m_currentLayer; | ||||||
|     frame_t m_currentFrame; |     frame_t m_currentFrame; | ||||||
|  |     Projection m_proj; | ||||||
|     ExtraType m_extraType; |     ExtraType m_extraType; | ||||||
|     const Cel* m_extraCel; |     const Cel* m_extraCel; | ||||||
|     const Image* m_extraImage; |     const Image* m_extraImage; | ||||||
|     BlendMode m_extraBlendMode; |     BlendMode m_extraBlendMode; | ||||||
| 
 |  | ||||||
|     BgType m_bgType; |     BgType m_bgType; | ||||||
|     bool m_bgZoom; |     bool m_bgZoom; | ||||||
|     color_t m_bgColor1; |     color_t m_bgColor1; | ||||||
|  | @ -229,7 +228,7 @@ namespace render { | ||||||
|   void composite_image(Image* dst, const Image* src, |   void composite_image(Image* dst, const Image* src, | ||||||
|                        const Palette* pal, |                        const Palette* pal, | ||||||
|                        int x, int y, |                        int x, int y, | ||||||
|                        int opacity, BlendMode blend_mode); |                        int opacity, BlendMode blendMode); | ||||||
| 
 | 
 | ||||||
| } // namespace render
 | } // namespace render
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| // Aseprite Document Library
 | // 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.
 | // This file is released under the terms of the MIT license.
 | ||||||
| // Read LICENSE.txt for more information.
 | // Read LICENSE.txt for more information.
 | ||||||
|  | @ -169,11 +169,9 @@ TEST(Render, CheckedBackground) | ||||||
|     1, 1, 1, 2, |     1, 1, 1, 2, | ||||||
|     2, 2, 2, 1); |     2, 2, 2, 1); | ||||||
| 
 | 
 | ||||||
|  |   render.setProjection(Projection(PixelRatio(1, 1), Zoom(2, 1))); | ||||||
|   render.setBgCheckedSize(gfx::Size(1, 1)); |   render.setBgCheckedSize(gfx::Size(1, 1)); | ||||||
|   render.renderSprite(dst, |   render.renderSprite(dst, doc->sprite(), frame_t(0)); | ||||||
|     doc->sprite(), frame_t(0), |  | ||||||
|     gfx::Clip(dst->bounds()), |  | ||||||
|     Zoom(2, 1)); |  | ||||||
|   EXPECT_4X4_PIXELS(dst, |   EXPECT_4X4_PIXELS(dst, | ||||||
|     1, 1, 2, 2, |     1, 1, 2, 2, | ||||||
|     1, 1, 2, 2, |     1, 1, 2, 2, | ||||||
|  | @ -204,9 +202,9 @@ TEST(Render, ZoomAndDstBounds) | ||||||
|   render.setBgColor2(2); |   render.setBgColor2(2); | ||||||
|   render.setBgCheckedSize(gfx::Size(1, 1)); |   render.setBgCheckedSize(gfx::Size(1, 1)); | ||||||
| 
 | 
 | ||||||
|   render.renderSprite(dst, doc->sprite(), frame_t(0), |   render.renderSprite( | ||||||
|     gfx::Clip(1, 1, 0, 0, 2, 2), |     dst, doc->sprite(), frame_t(0), | ||||||
|     Zoom(1, 1)); |     gfx::Clip(1, 1, 0, 0, 2, 2)); | ||||||
|   EXPECT_4X4_PIXELS(dst, |   EXPECT_4X4_PIXELS(dst, | ||||||
|     0, 0, 0, 0, |     0, 0, 0, 0, | ||||||
|     0, 1, 2, 0, |     0, 1, 2, 0, | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue