mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-29 12:32:52 +00:00
Add zoom out (related to issue #33)
Before the zoom was handle as a bits shift (scaled = value << zoom), now the zoom is a fraction (scaled = value * zoom.num / zoom.den). Changes: * Add Zoom class to apply/remove zoom factor * Split merge_zoomed_image template function into merge_zoomed_image_scale_down and merge_zoomed_image_scale_up to handle the special case where zoom.num/zoom.den < 1.0
This commit is contained in:
parent
17b0bee0ae
commit
4fc28d5639
@ -259,4 +259,5 @@ add_library(app-lib
|
|||||||
webserver.cpp
|
webserver.cpp
|
||||||
widget_loader.cpp
|
widget_loader.cpp
|
||||||
xml_document.cpp
|
xml_document.cpp
|
||||||
xml_exception.cpp)
|
xml_exception.cpp
|
||||||
|
zoom.cpp)
|
||||||
|
@ -99,13 +99,13 @@ void MoveMaskCommand::onExecute(Context* context)
|
|||||||
pixels = gridBounds.h;
|
pixels = gridBounds.h;
|
||||||
break;
|
break;
|
||||||
case ZoomedPixel:
|
case ZoomedPixel:
|
||||||
pixels = 1 << current_editor->zoom();
|
pixels = current_editor->zoom().apply(1);
|
||||||
break;
|
break;
|
||||||
case ZoomedTileWidth:
|
case ZoomedTileWidth:
|
||||||
pixels = gridBounds.w << current_editor->zoom();
|
pixels = current_editor->zoom().apply(gridBounds.w);
|
||||||
break;
|
break;
|
||||||
case ZoomedTileHeight:
|
case ZoomedTileHeight:
|
||||||
pixels = gridBounds.h << current_editor->zoom();
|
pixels = current_editor->zoom().apply(gridBounds.h);
|
||||||
break;
|
break;
|
||||||
case ViewportWidth:
|
case ViewportWidth:
|
||||||
pixels = vp.h;
|
pixels = vp.h;
|
||||||
|
@ -63,7 +63,8 @@ public:
|
|||||||
, m_pal(m_sprite->getPalette(editor->frame()))
|
, m_pal(m_sprite->getPalette(editor->frame()))
|
||||||
, 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()))
|
||||||
|
, m_zoom(editor->zoom()) {
|
||||||
// Do not use DocumentWriter (do not lock the document) because we
|
// Do not use DocumentWriter (do not lock the document) because we
|
||||||
// will call other sub-commands (e.g. previous frame, next frame,
|
// will call other sub-commands (e.g. previous frame, next frame,
|
||||||
// etc.).
|
// etc.).
|
||||||
@ -83,7 +84,6 @@ public:
|
|||||||
m_oldMousePos = ui::get_mouse_position();
|
m_oldMousePos = ui::get_mouse_position();
|
||||||
m_pos.x = -scroll.x + vp.x + editor->offsetX();
|
m_pos.x = -scroll.x + vp.x + editor->offsetX();
|
||||||
m_pos.y = -scroll.y + vp.y + editor->offsetY();
|
m_pos.y = -scroll.y + vp.y + editor->offsetY();
|
||||||
m_zoom = editor->zoom();
|
|
||||||
|
|
||||||
setFocusStop(true);
|
setFocusStop(true);
|
||||||
captureMouse();
|
captureMouse();
|
||||||
@ -193,14 +193,14 @@ protected:
|
|||||||
m_render.reset(
|
m_render.reset(
|
||||||
renderEngine.renderSprite(
|
renderEngine.renderSprite(
|
||||||
0, 0, m_sprite->width(), m_sprite->height(),
|
0, 0, m_sprite->width(), m_sprite->height(),
|
||||||
m_editor->frame(), 0, false, false));
|
m_editor->frame(), Zoom(1, 1), false, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
int x, y, w, h, u, v;
|
int x, y, w, h, u, v;
|
||||||
x = m_pos.x + ((m_delta.x >> m_zoom) << m_zoom);
|
x = m_pos.x + m_zoom.apply(m_zoom.remove(m_delta.x));
|
||||||
y = m_pos.y + ((m_delta.y >> m_zoom) << m_zoom);
|
y = m_pos.y + m_zoom.apply(m_zoom.remove(m_delta.y));
|
||||||
w = (m_sprite->width()<<m_zoom);
|
w = m_zoom.apply(m_sprite->width());
|
||||||
h = (m_sprite->height()<<m_zoom);
|
h = m_zoom.apply(m_sprite->height());
|
||||||
|
|
||||||
if (m_tiled & TILED_X_AXIS) x = SGN(x) * (ABS(x)%w);
|
if (m_tiled & TILED_X_AXIS) x = SGN(x) * (ABS(x)%w);
|
||||||
if (m_tiled & TILED_Y_AXIS) y = SGN(y) * (ABS(y)%h);
|
if (m_tiled & TILED_Y_AXIS) y = SGN(y) * (ABS(y)%h);
|
||||||
@ -243,7 +243,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;
|
||||||
int m_zoom;
|
Zoom m_zoom;
|
||||||
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;
|
||||||
|
@ -117,13 +117,13 @@ void ScrollCommand::onExecute(Context* context)
|
|||||||
pixels = gridBounds.h;
|
pixels = gridBounds.h;
|
||||||
break;
|
break;
|
||||||
case ZoomedPixel:
|
case ZoomedPixel:
|
||||||
pixels = 1 << current_editor->zoom();
|
pixels = current_editor->zoom().apply(1);
|
||||||
break;
|
break;
|
||||||
case ZoomedTileWidth:
|
case ZoomedTileWidth:
|
||||||
pixels = gridBounds.w << current_editor->zoom();
|
pixels = current_editor->zoom().apply(gridBounds.w);
|
||||||
break;
|
break;
|
||||||
case ZoomedTileHeight:
|
case ZoomedTileHeight:
|
||||||
pixels = gridBounds.h << current_editor->zoom();
|
pixels = current_editor->zoom().apply(gridBounds.h);
|
||||||
break;
|
break;
|
||||||
case ViewportWidth:
|
case ViewportWidth:
|
||||||
pixels = vp.h;
|
pixels = vp.h;
|
||||||
|
@ -74,25 +74,23 @@ bool ZoomCommand::onEnabled(Context* context)
|
|||||||
|
|
||||||
void ZoomCommand::onExecute(Context* context)
|
void ZoomCommand::onExecute(Context* context)
|
||||||
{
|
{
|
||||||
int zoom = current_editor->zoom();
|
Zoom zoom = current_editor->zoom();
|
||||||
|
|
||||||
switch (m_action) {
|
switch (m_action) {
|
||||||
case In:
|
case In:
|
||||||
if (zoom < 5)
|
zoom.in();
|
||||||
++zoom;
|
|
||||||
break;
|
break;
|
||||||
case Out:
|
case Out:
|
||||||
if (zoom > 0)
|
zoom.out();
|
||||||
--zoom;
|
|
||||||
break;
|
break;
|
||||||
case Set:
|
case Set:
|
||||||
switch (m_percentage) {
|
switch (m_percentage) {
|
||||||
case 3200: zoom = 5; break;
|
case 3200: zoom = Zoom(32, 1); break;
|
||||||
case 1600: zoom = 4; break;
|
case 1600: zoom = Zoom(16, 1); break;
|
||||||
case 800: zoom = 3; break;
|
case 800: zoom = Zoom(8, 1); break;
|
||||||
case 400: zoom = 2; break;
|
case 400: zoom = Zoom(4, 1); break;
|
||||||
case 200: zoom = 1; break;
|
case 200: zoom = Zoom(2, 1); break;
|
||||||
default: zoom = 0; break;
|
default: zoom = Zoom(1, 1); break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -257,8 +257,8 @@ 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(
|
||||||
(m_w << editor->zoom()),
|
editor->zoom().apply(m_w),
|
||||||
(1 << editor->zoom())));
|
editor->zoom().apply(1)));
|
||||||
|
|
||||||
gfx::Region reg1(rect);
|
gfx::Region reg1(rect);
|
||||||
gfx::Region reg2;
|
gfx::Region reg2;
|
||||||
|
@ -85,7 +85,7 @@ private:
|
|||||||
|
|
||||||
base::UniquePtr<Image> image(renderEngine.renderSprite(
|
base::UniquePtr<Image> image(renderEngine.renderSprite(
|
||||||
0, 0, sprite->width(), sprite->height(),
|
0, 0, sprite->width(), sprite->height(),
|
||||||
FrameNumber(0), 0, true, false));
|
FrameNumber(0), Zoom(1, 1), true, false));
|
||||||
|
|
||||||
// Calculate the thumbnail size
|
// Calculate the thumbnail size
|
||||||
int thumb_w = MAX_THUMBNAIL_SIZE * image->width() / MAX(image->width(), image->height());
|
int thumb_w = MAX_THUMBNAIL_SIZE * image->width() / MAX(image->width(), image->height());
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include "app/settings/selection_mode.h"
|
#include "app/settings/selection_mode.h"
|
||||||
#include "app/tools/trace_policy.h"
|
#include "app/tools/trace_policy.h"
|
||||||
|
#include "app/zoom.h"
|
||||||
#include "doc/frame_number.h"
|
#include "doc/frame_number.h"
|
||||||
#include "filters/tiled_mode.h"
|
#include "filters/tiled_mode.h"
|
||||||
#include "gfx/point.h"
|
#include "gfx/point.h"
|
||||||
@ -104,6 +105,9 @@ namespace app {
|
|||||||
// Gets mask X,Y origin coordinates
|
// Gets mask X,Y origin coordinates
|
||||||
virtual gfx::Point getMaskOrigin() = 0;
|
virtual gfx::Point getMaskOrigin() = 0;
|
||||||
|
|
||||||
|
// Returns the zoom
|
||||||
|
virtual const Zoom& zoom() = 0;
|
||||||
|
|
||||||
// Return the mouse button which start the tool-loop. It can be used
|
// Return the mouse button which start the tool-loop. It can be used
|
||||||
// by some tools that instead of using the primary/secondary color
|
// by some tools that instead of using the primary/secondary color
|
||||||
// uses the pressed button for different behavior (like selection
|
// uses the pressed button for different behavior (like selection
|
||||||
|
@ -213,7 +213,7 @@ void ToolLoopManager::doLoopStep(bool last_step)
|
|||||||
|
|
||||||
// Calculate the area to be updated in all document observers.
|
// Calculate the area to be updated in all document observers.
|
||||||
Region& dirty_area = m_toolLoop->getDirtyArea();
|
Region& dirty_area = m_toolLoop->getDirtyArea();
|
||||||
calculateDirtyArea(m_toolLoop, points_to_interwine, dirty_area);
|
calculateDirtyArea(points_to_interwine, dirty_area);
|
||||||
|
|
||||||
if (m_toolLoop->getTracePolicy() == TracePolicyLast) {
|
if (m_toolLoop->getTracePolicy() == TracePolicyLast) {
|
||||||
Region prev_dirty_area = dirty_area;
|
Region prev_dirty_area = dirty_area;
|
||||||
@ -235,7 +235,7 @@ void ToolLoopManager::snapToGrid(Point& point)
|
|||||||
m_toolLoop->getDocumentSettings()->snapToGrid(point);
|
m_toolLoop->getDocumentSettings()->snapToGrid(point);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToolLoopManager::calculateDirtyArea(ToolLoop* loop, const Points& points, Region& dirty_area)
|
void ToolLoopManager::calculateDirtyArea(const Points& points, Region& dirty_area)
|
||||||
{
|
{
|
||||||
dirty_area.clear();
|
dirty_area.clear();
|
||||||
|
|
||||||
@ -245,21 +245,21 @@ void ToolLoopManager::calculateDirtyArea(ToolLoop* loop, const Points& points, R
|
|||||||
|
|
||||||
// Expand the dirty-area with the pen width
|
// Expand the dirty-area with the pen width
|
||||||
Rect r1, r2;
|
Rect r1, r2;
|
||||||
loop->getPointShape()->getModifiedArea(loop, minpt.x, minpt.y, r1);
|
m_toolLoop->getPointShape()->getModifiedArea(m_toolLoop, minpt.x, minpt.y, r1);
|
||||||
loop->getPointShape()->getModifiedArea(loop, maxpt.x, maxpt.y, r2);
|
m_toolLoop->getPointShape()->getModifiedArea(m_toolLoop, maxpt.x, maxpt.y, r2);
|
||||||
|
|
||||||
dirty_area.createUnion(dirty_area, Region(r1.createUnion(r2)));
|
dirty_area.createUnion(dirty_area, Region(r1.createUnion(r2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply offset mode
|
// Apply offset mode
|
||||||
Point offset(loop->getOffset());
|
Point offset(m_toolLoop->getOffset());
|
||||||
dirty_area.offset(-offset);
|
dirty_area.offset(-offset);
|
||||||
|
|
||||||
// Apply tiled mode
|
// Apply tiled mode
|
||||||
TiledMode tiledMode = loop->getDocumentSettings()->getTiledMode();
|
TiledMode tiledMode = m_toolLoop->getDocumentSettings()->getTiledMode();
|
||||||
if (tiledMode != TILED_NONE) {
|
if (tiledMode != TILED_NONE) {
|
||||||
int w = loop->sprite()->width();
|
int w = m_toolLoop->sprite()->width();
|
||||||
int h = loop->sprite()->height();
|
int h = m_toolLoop->sprite()->height();
|
||||||
Region sprite_area(Rect(0, 0, w, h));
|
Region sprite_area(Rect(0, 0, w, h));
|
||||||
Region outside;
|
Region outside;
|
||||||
outside.createSubtraction(dirty_area, sprite_area);
|
outside.createSubtraction(dirty_area, sprite_area);
|
||||||
@ -312,6 +312,11 @@ void ToolLoopManager::calculateMinMax(const Points& points, Point& minpt, Point&
|
|||||||
maxpt.x = MAX(maxpt.x, points[c].x);
|
maxpt.x = MAX(maxpt.x, points[c].x);
|
||||||
maxpt.y = MAX(maxpt.y, points[c].y);
|
maxpt.y = MAX(maxpt.y, points[c].y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_toolLoop->zoom().scale() < 1.0) {
|
||||||
|
maxpt.x += m_toolLoop->zoom().remove(1);
|
||||||
|
maxpt.y += m_toolLoop->zoom().remove(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace tools
|
} // namespace tools
|
||||||
|
@ -103,13 +103,13 @@ namespace app {
|
|||||||
void doLoopStep(bool last_step);
|
void doLoopStep(bool last_step);
|
||||||
void snapToGrid(gfx::Point& point);
|
void snapToGrid(gfx::Point& point);
|
||||||
|
|
||||||
static void calculateDirtyArea(ToolLoop* loop,
|
void calculateDirtyArea(
|
||||||
const Points& points,
|
const Points& points,
|
||||||
gfx::Region& dirty_area);
|
gfx::Region& dirty_area);
|
||||||
|
|
||||||
static void calculateMinMax(const Points& points,
|
void calculateMinMax(const Points& points,
|
||||||
gfx::Point& minpt,
|
gfx::Point& minpt,
|
||||||
gfx::Point& maxpt);
|
gfx::Point& maxpt);
|
||||||
|
|
||||||
ToolLoop* m_toolLoop;
|
ToolLoop* m_toolLoop;
|
||||||
Points m_points;
|
Points m_points;
|
||||||
|
@ -55,7 +55,7 @@ namespace app {
|
|||||||
using namespace ui;
|
using namespace ui;
|
||||||
|
|
||||||
// Returns true if the cursor of the editor needs subpixel movement.
|
// Returns true if the cursor of the editor needs subpixel movement.
|
||||||
#define IS_SUBPIXEL(editor) ((editor)->m_zoom >= 2)
|
#define IS_SUBPIXEL(editor) ((editor)->m_zoom.scale() >= 4.0)
|
||||||
|
|
||||||
// Maximum quantity of colors to save pixels overlapped by the cursor.
|
// Maximum quantity of colors to save pixels overlapped by the cursor.
|
||||||
#define MAX_SAVED 4096
|
#define MAX_SAVED 4096
|
||||||
@ -514,25 +514,22 @@ static void trace_thickcross_pixels(ui::Graphics* g, Editor* editor,
|
|||||||
0, 0, 1, 1, 0, 0,
|
0, 0, 1, 1, 0, 0,
|
||||||
0, 0, 1, 1, 0, 0,
|
0, 0, 1, 1, 0, 0,
|
||||||
};
|
};
|
||||||
gfx::Point out;
|
gfx::Point out, outpt = editor->editorToScreen(pt);
|
||||||
int u, v;
|
int u, v;
|
||||||
int zoom = editor->zoom();
|
int size = editor->zoom().apply(thickness/2);
|
||||||
|
int size2 = editor->zoom().apply(thickness);
|
||||||
|
if (size2 == 0) size2 = 1;
|
||||||
|
|
||||||
for (v=0; v<6; v++) {
|
for (v=0; v<6; v++) {
|
||||||
for (u=0; u<6; u++) {
|
for (u=0; u<6; u++) {
|
||||||
if (cursor_cross[v*6+u]) {
|
if (!cursor_cross[v*6+u])
|
||||||
out = editor->editorToScreen(pt);
|
continue;
|
||||||
|
|
||||||
out.x += ((u<3) ?
|
out = outpt;
|
||||||
u-((thickness>>1)<<zoom)-3:
|
out.x += ((u<3) ? u-size-3: u-size-3+size2);
|
||||||
u-((thickness>>1)<<zoom)-3+(thickness<<zoom));
|
out.y += ((v<3) ? v-size-3: v-size-3+size2);
|
||||||
|
|
||||||
out.y += ((v<3)?
|
pixelDelegate(g, out, color);
|
||||||
v-((thickness>>1)<<zoom)-3:
|
|
||||||
v-((thickness>>1)<<zoom)-3+(thickness<<zoom));
|
|
||||||
|
|
||||||
pixelDelegate(g, out, color);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ using namespace ui;
|
|||||||
|
|
||||||
class EditorPreRenderImpl : public EditorPreRender {
|
class EditorPreRenderImpl : public EditorPreRender {
|
||||||
public:
|
public:
|
||||||
EditorPreRenderImpl(Editor* editor, Image* image, const Point& offset, int zoom)
|
EditorPreRenderImpl(Editor* editor, Image* image, const Point& offset, Zoom zoom)
|
||||||
: m_editor(editor)
|
: m_editor(editor)
|
||||||
, m_image(image)
|
, m_image(image)
|
||||||
, m_offset(offset)
|
, m_offset(offset)
|
||||||
@ -92,17 +92,17 @@ public:
|
|||||||
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_image,
|
||||||
m_offset.x + (rect.x << m_zoom),
|
m_offset.x + m_zoom.apply(rect.x),
|
||||||
m_offset.y + (rect.y << m_zoom),
|
m_offset.y + m_zoom.apply(rect.y),
|
||||||
m_offset.x + ((rect.x+rect.w) << m_zoom) - 1,
|
m_offset.x + m_zoom.apply(rect.x+rect.w) - 1,
|
||||||
m_offset.y + ((rect.y+rect.h) << m_zoom) - 1, rgbaColor, opacity);
|
m_offset.y + m_zoom.apply(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;
|
||||||
int m_zoom;
|
Zoom m_zoom;
|
||||||
};
|
};
|
||||||
|
|
||||||
class EditorPostRenderImpl : public EditorPostRender {
|
class EditorPostRenderImpl : public EditorPostRender {
|
||||||
@ -145,7 +145,7 @@ 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(FrameNumber(0))
|
, m_frame(FrameNumber(0))
|
||||||
, m_zoom(0)
|
, m_zoom(1, 1)
|
||||||
, m_cursorThick(0)
|
, m_cursorThick(0)
|
||||||
, m_cursorScreen(0, 0)
|
, m_cursorScreen(0, 0)
|
||||||
, m_cursorEditor(0, 0)
|
, m_cursorEditor(0, 0)
|
||||||
@ -324,7 +324,7 @@ void Editor::setEditorScroll(const gfx::Point& scroll, bool blit_valid_rgn)
|
|||||||
drawBrushPreview(m_cursorScreen);
|
drawBrushPreview(m_cursorScreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Editor::setEditorZoom(int zoom)
|
void Editor::setEditorZoom(Zoom zoom)
|
||||||
{
|
{
|
||||||
setZoomAndCenterInMouse(zoom,
|
setZoomAndCenterInMouse(zoom,
|
||||||
ui::get_mouse_position(), Editor::kCofiguredZoomBehavior);
|
ui::get_mouse_position(), Editor::kCofiguredZoomBehavior);
|
||||||
@ -338,12 +338,12 @@ void Editor::updateEditor()
|
|||||||
void Editor::drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& rc, int dx, int dy)
|
void Editor::drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& rc, int dx, int dy)
|
||||||
{
|
{
|
||||||
// Output information
|
// Output information
|
||||||
int source_x = rc.x << m_zoom;
|
int source_x = m_zoom.apply(rc.x);
|
||||||
int source_y = rc.y << m_zoom;
|
int source_y = m_zoom.apply(rc.y);
|
||||||
int dest_x = dx + m_offset_x + source_x;
|
int dest_x = dx + m_offset_x + source_x;
|
||||||
int dest_y = dy + m_offset_y + source_y;
|
int dest_y = dy + m_offset_y + source_y;
|
||||||
int width = rc.w << m_zoom;
|
int width = m_zoom.apply(rc.w);
|
||||||
int height = rc.h << m_zoom;
|
int height = m_zoom.apply(rc.h);
|
||||||
|
|
||||||
// Clip from graphics/screen
|
// Clip from graphics/screen
|
||||||
const gfx::Rect& clip = g->getClipBounds();
|
const gfx::Rect& clip = g->getClipBounds();
|
||||||
@ -375,11 +375,11 @@ void Editor::drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& rc, in
|
|||||||
dest_y -= source_y;
|
dest_y -= source_y;
|
||||||
source_y = 0;
|
source_y = 0;
|
||||||
}
|
}
|
||||||
if (source_x+width > (m_sprite->width() << m_zoom)) {
|
if (source_x+width > m_zoom.apply(m_sprite->width())) {
|
||||||
width = (m_sprite->width() << m_zoom) - source_x;
|
width = m_zoom.apply(m_sprite->width()) - source_x;
|
||||||
}
|
}
|
||||||
if (source_y+height > (m_sprite->height() << m_zoom)) {
|
if (source_y+height > m_zoom.apply(m_sprite->height())) {
|
||||||
height = (m_sprite->height() << m_zoom) - source_y;
|
height = m_zoom.apply(m_sprite->height()) - source_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw the sprite
|
// Draw the sprite
|
||||||
@ -402,7 +402,7 @@ void Editor::drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& rc, in
|
|||||||
// 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(-source_x, -source_y), m_zoom);
|
Point(-source_x, -source_y), m_zoom);
|
||||||
m_decorator->preRenderDecorator(&preRender);
|
m_decorator->preRenderDecorator(&preRender);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -423,8 +423,8 @@ void Editor::drawSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& rc)
|
|||||||
gfx::Rect spriteRect(
|
gfx::Rect spriteRect(
|
||||||
client.x + m_offset_x,
|
client.x + m_offset_x,
|
||||||
client.y + m_offset_y,
|
client.y + m_offset_y,
|
||||||
(m_sprite->width() << m_zoom),
|
m_zoom.apply(m_sprite->width()),
|
||||||
(m_sprite->height() << m_zoom));
|
m_zoom.apply(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.
|
||||||
@ -473,7 +473,7 @@ void Editor::drawSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& rc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Draw the pixel grid
|
// Draw the pixel grid
|
||||||
if ((m_zoom > 1) && docSettings->getPixelGridVisible()) {
|
if ((m_zoom.scale() > 1.0) && docSettings->getPixelGridVisible()) {
|
||||||
drawGrid(g, enclosingRect, Rect(0, 0, 1, 1), docSettings->getPixelGridColor());
|
drawGrid(g, enclosingRect, Rect(0, 0, 1, 1), docSettings->getPixelGridColor());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -544,10 +544,10 @@ void Editor::drawMask(Graphics* g)
|
|||||||
CheckedDrawMode checked(g, m_offset_count);
|
CheckedDrawMode checked(g, m_offset_count);
|
||||||
|
|
||||||
for (int c=0; c<nseg; ++c, ++seg) {
|
for (int c=0; c<nseg; ++c, ++seg) {
|
||||||
x1 = seg->x1 << m_zoom;
|
x1 = m_zoom.apply(seg->x1);
|
||||||
y1 = seg->y1 << m_zoom;
|
y1 = m_zoom.apply(seg->y1);
|
||||||
x2 = seg->x2 << m_zoom;
|
x2 = m_zoom.apply(seg->x2);
|
||||||
y2 = seg->y2 << m_zoom;
|
y2 = m_zoom.apply(seg->y2);
|
||||||
|
|
||||||
#if 1 // Bounds inside mask
|
#if 1 // Bounds inside mask
|
||||||
if (!seg->open)
|
if (!seg->open)
|
||||||
@ -863,8 +863,8 @@ gfx::Point Editor::screenToEditor(const gfx::Point& pt)
|
|||||||
Point scroll = view->getViewScroll();
|
Point scroll = view->getViewScroll();
|
||||||
|
|
||||||
return gfx::Point(
|
return gfx::Point(
|
||||||
(pt.x - vp.x + scroll.x - m_offset_x) >> m_zoom,
|
m_zoom.remove(pt.x - vp.x + scroll.x - m_offset_x),
|
||||||
(pt.y - vp.y + scroll.y - m_offset_y) >> m_zoom);
|
m_zoom.remove(pt.y - vp.y + scroll.y - m_offset_y));
|
||||||
}
|
}
|
||||||
|
|
||||||
Point Editor::editorToScreen(const gfx::Point& pt)
|
Point Editor::editorToScreen(const gfx::Point& pt)
|
||||||
@ -874,8 +874,8 @@ Point Editor::editorToScreen(const gfx::Point& pt)
|
|||||||
Point scroll = view->getViewScroll();
|
Point scroll = view->getViewScroll();
|
||||||
|
|
||||||
return Point(
|
return Point(
|
||||||
(vp.x - scroll.x + m_offset_x + (pt.x << m_zoom)),
|
(vp.x - scroll.x + m_offset_x + m_zoom.apply(pt.x)),
|
||||||
(vp.y - scroll.y + m_offset_y + (pt.y << m_zoom)));
|
(vp.y - scroll.y + m_offset_y + m_zoom.apply(pt.y)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Rect Editor::screenToEditor(const Rect& rc)
|
Rect Editor::screenToEditor(const Rect& rc)
|
||||||
@ -968,8 +968,8 @@ void Editor::centerInSpritePoint(const gfx::Point& spritePos)
|
|||||||
hideDrawingCursor();
|
hideDrawingCursor();
|
||||||
|
|
||||||
gfx::Point scroll(
|
gfx::Point scroll(
|
||||||
m_offset_x - (vp.w/2) + ((1<<m_zoom)>>1) + (spritePos.x << m_zoom),
|
m_offset_x - (vp.w/2) + m_zoom.apply(1)/2 + m_zoom.apply(spritePos.x),
|
||||||
m_offset_y - (vp.h/2) + ((1<<m_zoom)>>1) + (spritePos.y << m_zoom));
|
m_offset_y - (vp.h/2) + m_zoom.apply(1)/2 + m_zoom.apply(spritePos.y));
|
||||||
|
|
||||||
updateEditor();
|
updateEditor();
|
||||||
setEditorScroll(scroll, false);
|
setEditorScroll(scroll, false);
|
||||||
@ -1212,8 +1212,8 @@ void Editor::onPreferredSize(PreferredSizeEvent& ev)
|
|||||||
m_offset_x = std::max<int>(vp.w/2, vp.w - m_sprite->width()/2);
|
m_offset_x = std::max<int>(vp.w/2, vp.w - m_sprite->width()/2);
|
||||||
m_offset_y = std::max<int>(vp.h/2, vp.h - m_sprite->height()/2);
|
m_offset_y = std::max<int>(vp.h/2, vp.h - m_sprite->height()/2);
|
||||||
|
|
||||||
sz.w = (m_sprite->width() << m_zoom) + m_offset_x*2;
|
sz.w = m_zoom.apply(m_sprite->width()) + m_offset_x*2;
|
||||||
sz.h = (m_sprite->height() << m_zoom) + m_offset_y*2;
|
sz.h = m_zoom.apply(m_sprite->height()) + m_offset_y*2;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sz.w = 4;
|
sz.w = 4;
|
||||||
@ -1311,7 +1311,7 @@ bool Editor::isInsideSelection()
|
|||||||
m_document->mask()->containsPoint(spritePos.x, spritePos.y);
|
m_document->mask()->containsPoint(spritePos.x, spritePos.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Editor::setZoomAndCenterInMouse(int zoom,
|
void Editor::setZoomAndCenterInMouse(Zoom zoom,
|
||||||
const gfx::Point& mousePos, ZoomBehavior zoomBehavior)
|
const gfx::Point& mousePos, ZoomBehavior zoomBehavior)
|
||||||
{
|
{
|
||||||
View* view = View::getView(this);
|
View* view = View::getView(this);
|
||||||
@ -1343,8 +1343,8 @@ void Editor::setZoomAndCenterInMouse(int zoom,
|
|||||||
mid.y = mousePos.y;
|
mid.y = mousePos.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
spritePos.x = m_offset_x - (mid.x - vp.x) + ((1<<zoom)>>1) + (spritePos.x << zoom);
|
spritePos.x = m_offset_x - (mid.x - vp.x) + (zoom.apply(1)/2) + zoom.apply(spritePos.x);
|
||||||
spritePos.y = m_offset_y - (mid.y - vp.y) + ((1<<zoom)>>1) + (spritePos.y << zoom);
|
spritePos.y = m_offset_y - (mid.y - vp.y) + (zoom.apply(1)/2) + zoom.apply(spritePos.y);
|
||||||
|
|
||||||
if ((m_zoom != zoom) || (m_cursorEditor != mid)) {
|
if ((m_zoom != zoom) || (m_cursorEditor != mid)) {
|
||||||
bool blit_valid_rgn = (m_zoom == zoom);
|
bool blit_valid_rgn = (m_zoom == zoom);
|
||||||
|
@ -27,16 +27,14 @@
|
|||||||
#include "app/ui/editor/editor_observers.h"
|
#include "app/ui/editor/editor_observers.h"
|
||||||
#include "app/ui/editor/editor_state.h"
|
#include "app/ui/editor/editor_state.h"
|
||||||
#include "app/ui/editor/editor_states_history.h"
|
#include "app/ui/editor/editor_states_history.h"
|
||||||
|
#include "app/zoom.h"
|
||||||
#include "base/connection.h"
|
#include "base/connection.h"
|
||||||
#include "gfx/fwd.h"
|
|
||||||
#include "doc/frame_number.h"
|
#include "doc/frame_number.h"
|
||||||
|
#include "gfx/fwd.h"
|
||||||
#include "ui/base.h"
|
#include "ui/base.h"
|
||||||
#include "ui/timer.h"
|
#include "ui/timer.h"
|
||||||
#include "ui/widget.h"
|
#include "ui/widget.h"
|
||||||
|
|
||||||
#define MIN_ZOOM 0
|
|
||||||
#define MAX_ZOOM 5
|
|
||||||
|
|
||||||
namespace doc {
|
namespace doc {
|
||||||
class Sprite;
|
class Sprite;
|
||||||
class Layer;
|
class Layer;
|
||||||
@ -122,18 +120,18 @@ namespace app {
|
|||||||
void setLayer(const Layer* layer);
|
void setLayer(const Layer* layer);
|
||||||
void setFrame(FrameNumber frame);
|
void setFrame(FrameNumber frame);
|
||||||
|
|
||||||
int zoom() const { return m_zoom; }
|
const Zoom& zoom() const { return m_zoom; }
|
||||||
int offsetX() const { return m_offset_x; }
|
int offsetX() const { return m_offset_x; }
|
||||||
int offsetY() const { return m_offset_y; }
|
int offsetY() const { return m_offset_y; }
|
||||||
int cursorThick() { return m_cursorThick; }
|
int cursorThick() { return m_cursorThick; }
|
||||||
|
|
||||||
void setZoom(int zoom) { m_zoom = zoom; }
|
void setZoom(Zoom zoom) { m_zoom = zoom; }
|
||||||
void setOffsetX(int x) { m_offset_x = x; }
|
void setOffsetX(int x) { m_offset_x = x; }
|
||||||
void setOffsetY(int y) { m_offset_y = y; }
|
void setOffsetY(int y) { m_offset_y = y; }
|
||||||
|
|
||||||
void setDefaultScroll();
|
void setDefaultScroll();
|
||||||
void setEditorScroll(const gfx::Point& scroll, bool blit_valid_rgn);
|
void setEditorScroll(const gfx::Point& scroll, bool blit_valid_rgn);
|
||||||
void setEditorZoom(int zoom);
|
void setEditorZoom(Zoom zoom);
|
||||||
|
|
||||||
// Updates the Editor's view.
|
// Updates the Editor's view.
|
||||||
void updateEditor();
|
void updateEditor();
|
||||||
@ -187,7 +185,7 @@ namespace app {
|
|||||||
// Returns true if the cursor is inside the active mask/selection.
|
// Returns true if the cursor is inside the active mask/selection.
|
||||||
bool isInsideSelection();
|
bool isInsideSelection();
|
||||||
|
|
||||||
void setZoomAndCenterInMouse(int zoom,
|
void setZoomAndCenterInMouse(Zoom zoom,
|
||||||
const gfx::Point& mousePos, ZoomBehavior zoomBehavior);
|
const gfx::Point& mousePos, ZoomBehavior zoomBehavior);
|
||||||
|
|
||||||
void pasteImage(const Image* image, const gfx::Point& pos);
|
void pasteImage(const Image* image, const gfx::Point& pos);
|
||||||
@ -260,7 +258,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
|
||||||
FrameNumber m_frame; // Active frame in the editor
|
FrameNumber m_frame; // Active frame in the editor
|
||||||
int m_zoom; // Zoom in the editor
|
Zoom m_zoom; // Zoom in the editor
|
||||||
|
|
||||||
// Drawing cursor
|
// Drawing cursor
|
||||||
int m_cursorThick;
|
int m_cursorThick;
|
||||||
|
@ -179,10 +179,10 @@ void SelectBoxState::preRenderDecorator(EditorPreRender* render)
|
|||||||
void SelectBoxState::postRenderDecorator(EditorPostRender* render)
|
void SelectBoxState::postRenderDecorator(EditorPostRender* render)
|
||||||
{
|
{
|
||||||
Editor* editor = render->getEditor();
|
Editor* editor = render->getEditor();
|
||||||
int zoom = editor->zoom();
|
Zoom zoom = editor->zoom();
|
||||||
gfx::Rect vp = View::getView(editor)->getViewportBounds();
|
gfx::Rect vp = View::getView(editor)->getViewportBounds();
|
||||||
vp.w += 1<<zoom;
|
vp.w += zoom.apply(1);
|
||||||
vp.h += 1<<zoom;
|
vp.h += zoom.apply(1);
|
||||||
vp = editor->screenToEditor(vp);
|
vp = editor->screenToEditor(vp);
|
||||||
|
|
||||||
// Paint a grid generated by the box
|
// Paint a grid generated by the box
|
||||||
|
@ -360,10 +360,20 @@ bool StandbyState::onMouseWheel(Editor* editor, MouseMessage* msg)
|
|||||||
|
|
||||||
case WHEEL_ZOOM: {
|
case WHEEL_ZOOM: {
|
||||||
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
|
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
|
||||||
int zoom = MID(MIN_ZOOM, editor->zoom()-dz, MAX_ZOOM);
|
Zoom zoom = editor->zoom();
|
||||||
if (editor->zoom() != zoom)
|
if (dz < 0) {
|
||||||
|
while (dz++ < 0)
|
||||||
|
zoom.in();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
while (dz-- > 0)
|
||||||
|
zoom.out();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (editor->zoom() != zoom) {
|
||||||
editor->setZoomAndCenterInMouse(zoom,
|
editor->setZoomAndCenterInMouse(zoom,
|
||||||
mouseMsg->position(), Editor::kDontCenterOnZoom);
|
mouseMsg->position(), Editor::kDontCenterOnZoom);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,6 +223,7 @@ public:
|
|||||||
bool useMask() override { return m_useMask; }
|
bool useMask() override { return m_useMask; }
|
||||||
Mask* getMask() override { return m_mask; }
|
Mask* getMask() override { return m_mask; }
|
||||||
gfx::Point getMaskOrigin() override { return m_maskOrigin; }
|
gfx::Point getMaskOrigin() override { return m_maskOrigin; }
|
||||||
|
const Zoom& zoom() override { return m_editor->zoom(); }
|
||||||
ToolLoop::Button getMouseButton() override { return m_button; }
|
ToolLoop::Button getMouseButton() override { return m_button; }
|
||||||
int getPrimaryColor() override { return m_primary_color; }
|
int getPrimaryColor() override { return m_primary_color; }
|
||||||
void setPrimaryColor(int color) override { m_primary_color = color; }
|
void setPrimaryColor(int color) override { m_primary_color = color; }
|
||||||
|
@ -196,8 +196,8 @@ gfx::Rect TransformHandles::getPivotHandleBounds(Editor* editor,
|
|||||||
she::Surface* part = theme->get_part(PART_PIVOT_HANDLE);
|
she::Surface* part = theme->get_part(PART_PIVOT_HANDLE);
|
||||||
gfx::Point screenPivotPos = editor->editorToScreen(transform.pivot());
|
gfx::Point screenPivotPos = editor->editorToScreen(transform.pivot());
|
||||||
|
|
||||||
screenPivotPos.x += (1 << editor->zoom()) / 2;
|
screenPivotPos.x += editor->zoom().apply(1) / 2;
|
||||||
screenPivotPos.y += (1 << editor->zoom()) / 2;
|
screenPivotPos.y += editor->zoom().apply(1) / 2;
|
||||||
|
|
||||||
return gfx::Rect(
|
return gfx::Rect(
|
||||||
screenPivotPos.x-part->width()/2,
|
screenPivotPos.x-part->width()/2,
|
||||||
|
@ -53,12 +53,12 @@ bool ZoomingState::onMouseDown(Editor* editor, MouseMessage* msg)
|
|||||||
|
|
||||||
bool ZoomingState::onMouseUp(Editor* editor, MouseMessage* msg)
|
bool ZoomingState::onMouseUp(Editor* editor, MouseMessage* msg)
|
||||||
{
|
{
|
||||||
int zoom = editor->zoom();
|
Zoom zoom = editor->zoom();
|
||||||
|
|
||||||
if (msg->left() && zoom < 5)
|
if (msg->left())
|
||||||
++zoom;
|
zoom.in();
|
||||||
else if (msg->right() && zoom > 0)
|
else if (msg->right())
|
||||||
--zoom;
|
zoom.out();
|
||||||
|
|
||||||
editor->setZoomAndCenterInMouse(zoom,
|
editor->setZoomAndCenterInMouse(zoom,
|
||||||
msg->position(), Editor::kCofiguredZoomBehavior);
|
msg->position(), Editor::kCofiguredZoomBehavior);
|
||||||
|
@ -245,7 +245,7 @@ void MiniEditorWindow::updateUsingEditor(Editor* editor)
|
|||||||
addChild(m_docView);
|
addChild(m_docView);
|
||||||
|
|
||||||
miniEditor = m_docView->getEditor();
|
miniEditor = m_docView->getEditor();
|
||||||
miniEditor->setZoom(0);
|
miniEditor->setZoom(Zoom(1, 1));
|
||||||
miniEditor->setState(EditorStatePtr(new EditorState));
|
miniEditor->setState(EditorStatePtr(new EditorState));
|
||||||
layout();
|
layout();
|
||||||
}
|
}
|
||||||
|
@ -115,9 +115,8 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<class DstTraits, class SrcTraits>
|
template<class DstTraits, class SrcTraits>
|
||||||
static void merge_zoomed_image(Image* dst, const Image* src, const Palette* pal,
|
static void merge_zoomed_image_scale_up(Image* dst, const Image* src, const Palette* pal,
|
||||||
int x, int y, int opacity,
|
int x, int y, int opacity, int blend_mode, Zoom zoom)
|
||||||
int blend_mode, int zoom)
|
|
||||||
{
|
{
|
||||||
BlenderHelper<DstTraits, SrcTraits> blender(src, pal, blend_mode);
|
BlenderHelper<DstTraits, SrcTraits> blender(src, pal, blend_mode);
|
||||||
int src_x, src_y, src_w, src_h;
|
int src_x, src_y, src_w, src_h;
|
||||||
@ -126,8 +125,8 @@ static void merge_zoomed_image(Image* dst, const Image* src, const Palette* pal,
|
|||||||
int first_box_w, first_box_h;
|
int first_box_w, first_box_h;
|
||||||
int line_h, bottom;
|
int line_h, bottom;
|
||||||
|
|
||||||
box_w = 1<<zoom;
|
box_w = zoom.apply(1);
|
||||||
box_h = 1<<zoom;
|
box_h = zoom.apply(1);
|
||||||
|
|
||||||
src_x = 0;
|
src_x = 0;
|
||||||
src_y = 0;
|
src_y = 0;
|
||||||
@ -136,13 +135,13 @@ static void merge_zoomed_image(Image* dst, const Image* src, const Palette* pal,
|
|||||||
|
|
||||||
dst_x = x;
|
dst_x = x;
|
||||||
dst_y = y;
|
dst_y = y;
|
||||||
dst_w = src->width()<<zoom;
|
dst_w = zoom.apply(src->width());
|
||||||
dst_h = src->height()<<zoom;
|
dst_h = zoom.apply(src->height());
|
||||||
|
|
||||||
// clipping...
|
// clipping...
|
||||||
if (dst_x < 0) {
|
if (dst_x < 0) {
|
||||||
src_x += (-dst_x)>>zoom;
|
src_x += zoom.remove(-dst_x);
|
||||||
src_w -= (-dst_x)>>zoom;
|
src_w -= zoom.remove(-dst_x);
|
||||||
dst_w -= (-dst_x);
|
dst_w -= (-dst_x);
|
||||||
first_box_w = box_w - ((-dst_x) % box_w);
|
first_box_w = box_w - ((-dst_x) % box_w);
|
||||||
dst_x = 0;
|
dst_x = 0;
|
||||||
@ -151,8 +150,8 @@ static void merge_zoomed_image(Image* dst, const Image* src, const Palette* pal,
|
|||||||
first_box_w = 0;
|
first_box_w = 0;
|
||||||
|
|
||||||
if (dst_y < 0) {
|
if (dst_y < 0) {
|
||||||
src_y += (-dst_y)>>zoom;
|
src_y += zoom.remove(-dst_y);
|
||||||
src_h -= (-dst_y)>>zoom;
|
src_h -= zoom.remove(-dst_y);
|
||||||
dst_h -= (-dst_y);
|
dst_h -= (-dst_y);
|
||||||
first_box_h = box_h - ((-dst_y) % box_h);
|
first_box_h = box_h - ((-dst_y) % box_h);
|
||||||
dst_y = 0;
|
dst_y = 0;
|
||||||
@ -161,12 +160,12 @@ static void merge_zoomed_image(Image* dst, const Image* src, const Palette* pal,
|
|||||||
first_box_h = 0;
|
first_box_h = 0;
|
||||||
|
|
||||||
if (dst_x+dst_w > dst->width()) {
|
if (dst_x+dst_w > dst->width()) {
|
||||||
src_w -= (dst_x+dst_w-dst->width()) >> zoom;
|
src_w -= zoom.remove(dst_x+dst_w-dst->width());
|
||||||
dst_w = dst->width() - dst_x;
|
dst_w = dst->width() - dst_x;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dst_y+dst_h > dst->height()) {
|
if (dst_y+dst_h > dst->height()) {
|
||||||
src_h -= (dst_y+dst_h-dst->height()) >> zoom;
|
src_h -= zoom.remove(dst_y+dst_h-dst->height());
|
||||||
dst_h = dst->height() - dst_y;
|
dst_h = dst->height() - dst_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,6 +278,107 @@ done_with_line:;
|
|||||||
done_with_blit:;
|
done_with_blit:;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class DstTraits, class SrcTraits>
|
||||||
|
static void merge_zoomed_image_scale_down(Image* dst, const Image* src, const Palette* pal,
|
||||||
|
int x, int y, int opacity, int blend_mode, Zoom zoom)
|
||||||
|
{
|
||||||
|
BlenderHelper<DstTraits, SrcTraits> blender(src, pal, blend_mode);
|
||||||
|
int src_x, src_y, src_w, src_h;
|
||||||
|
int dst_x, dst_y, dst_w, dst_h;
|
||||||
|
int unbox_w, unbox_h;
|
||||||
|
int bottom;
|
||||||
|
|
||||||
|
unbox_w = zoom.remove(1);
|
||||||
|
unbox_h = zoom.remove(1);
|
||||||
|
|
||||||
|
src_x = 0;
|
||||||
|
src_y = 0;
|
||||||
|
src_w = src->width();
|
||||||
|
src_h = src->height();
|
||||||
|
|
||||||
|
dst_x = x;
|
||||||
|
dst_y = y;
|
||||||
|
dst_w = zoom.apply(src->width());
|
||||||
|
dst_h = zoom.apply(src->height());
|
||||||
|
|
||||||
|
// clipping...
|
||||||
|
if (dst_x < 0) {
|
||||||
|
src_x += zoom.remove(-dst_x);
|
||||||
|
src_w -= zoom.remove(-dst_x);
|
||||||
|
dst_w -= (-dst_x);
|
||||||
|
dst_x = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dst_y < 0) {
|
||||||
|
src_y += zoom.remove(-dst_y);
|
||||||
|
src_h -= zoom.remove(-dst_y);
|
||||||
|
dst_h -= (-dst_y);
|
||||||
|
dst_y = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dst_x+dst_w > dst->width()) {
|
||||||
|
src_w -= zoom.remove(dst_x+dst_w-dst->width());
|
||||||
|
dst_w = dst->width() - dst_x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dst_y+dst_h > dst->height()) {
|
||||||
|
src_h -= zoom.remove(dst_y+dst_h-dst->height());
|
||||||
|
dst_h = dst->height() - dst_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
src_w = zoom.remove(zoom.apply(src_w));
|
||||||
|
src_h = zoom.remove(zoom.apply(src_h));
|
||||||
|
|
||||||
|
if ((src_w <= 0) || (src_h <= 0) ||
|
||||||
|
(dst_w <= 0) || (dst_h <= 0))
|
||||||
|
return;
|
||||||
|
|
||||||
|
bottom = dst_y+dst_h-1;
|
||||||
|
|
||||||
|
// Lock all necessary bits
|
||||||
|
const LockImageBits<SrcTraits> srcBits(src, gfx::Rect(src_x, src_y, src_w, src_h));
|
||||||
|
LockImageBits<DstTraits> dstBits(dst, gfx::Rect(dst_x, dst_y, dst_w, dst_h));
|
||||||
|
typename LockImageBits<SrcTraits>::const_iterator src_it = srcBits.begin();
|
||||||
|
typename LockImageBits<SrcTraits>::const_iterator src_end = srcBits.end();
|
||||||
|
typename LockImageBits<DstTraits>::iterator dst_it, dst_end;
|
||||||
|
|
||||||
|
// For each line to draw of the source image...
|
||||||
|
for (y=0; y<src_h; y+=unbox_h) {
|
||||||
|
dst_it = dstBits.begin_area(gfx::Rect(dst_x, dst_y, dst_w, 1));
|
||||||
|
dst_end = dstBits.end_area(gfx::Rect(dst_x, dst_y, dst_w, 1));
|
||||||
|
|
||||||
|
for (x=0; x<src_w; x+=unbox_w) {
|
||||||
|
ASSERT(src_it >= srcBits.begin() && src_it < src_end);
|
||||||
|
ASSERT(dst_it >= dstBits.begin() && dst_it < dst_end);
|
||||||
|
|
||||||
|
blender(*dst_it, *dst_it, *src_it, opacity);
|
||||||
|
|
||||||
|
// Skip source pixels
|
||||||
|
for (int delta=0; delta < unbox_w && src_it != src_end; ++delta)
|
||||||
|
++src_it;
|
||||||
|
|
||||||
|
++dst_it;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (++dst_y > bottom)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Skip lines
|
||||||
|
for (int delta=0; delta < src_w * (unbox_h-1) && src_it != src_end; ++delta)
|
||||||
|
++src_it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class DstTraits, class SrcTraits>
|
||||||
|
static void merge_zoomed_image(Image* dst, const Image* src, const Palette* pal,
|
||||||
|
int x, int y, int opacity, int blend_mode, Zoom zoom)
|
||||||
|
{
|
||||||
|
if (zoom.scale() >= 1.0)
|
||||||
|
merge_zoomed_image_scale_up<DstTraits, SrcTraits>(dst, src, pal, x, y, opacity, blend_mode, zoom);
|
||||||
|
else
|
||||||
|
merge_zoomed_image_scale_down<DstTraits, SrcTraits>(dst, src, pal, x, y, opacity, blend_mode, zoom);
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// Render Engine
|
// Render Engine
|
||||||
|
|
||||||
@ -380,15 +480,15 @@ void RenderEngine::setPreviewImage(const Layer* layer, FrameNumber frame, Image*
|
|||||||
in a new image and return it.
|
in a new image and return it.
|
||||||
|
|
||||||
Positions source_x, source_y, width and height must have the
|
Positions source_x, source_y, width and height must have the
|
||||||
zoom applied (sorce_x<<zoom, source_y<<zoom, width<<zoom, etc.)
|
zoom applied (zoom.apply(sorce_x), zoom.apply(source_y), zoom.apply(width), etc.)
|
||||||
*/
|
*/
|
||||||
Image* RenderEngine::renderSprite(int source_x, int source_y,
|
Image* RenderEngine::renderSprite(int source_x, int source_y,
|
||||||
int width, int height,
|
int width, int height,
|
||||||
FrameNumber frame, int zoom,
|
FrameNumber frame, Zoom zoom,
|
||||||
bool draw_tiled_bg,
|
bool draw_tiled_bg,
|
||||||
bool enable_onionskin)
|
bool enable_onionskin)
|
||||||
{
|
{
|
||||||
void (*zoomed_func)(Image*, const Image*, const Palette*, int, int, int, int, int);
|
void (*zoomed_func)(Image*, const Image*, const Palette*, int, int, int, int, Zoom);
|
||||||
const LayerImage* background = m_sprite->backgroundLayer();
|
const LayerImage* background = m_sprite->backgroundLayer();
|
||||||
bool need_checked_bg = (background != NULL ? !background->isVisible(): true);
|
bool need_checked_bg = (background != NULL ? !background->isVisible(): true);
|
||||||
uint32_t bg_color = 0;
|
uint32_t bg_color = 0;
|
||||||
@ -471,7 +571,7 @@ Image* RenderEngine::renderSprite(int source_x, int source_y,
|
|||||||
// static
|
// static
|
||||||
void RenderEngine::renderCheckedBackground(Image* image,
|
void RenderEngine::renderCheckedBackground(Image* image,
|
||||||
int source_x, int source_y,
|
int source_x, int source_y,
|
||||||
int zoom)
|
Zoom zoom)
|
||||||
{
|
{
|
||||||
int x, y, u, v;
|
int x, y, u, v;
|
||||||
int tile_w = 16;
|
int tile_w = 16;
|
||||||
@ -504,13 +604,13 @@ void RenderEngine::renderCheckedBackground(Image* image,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (checked_bg_zoom) {
|
if (checked_bg_zoom) {
|
||||||
tile_w <<= zoom;
|
tile_w = zoom.apply(tile_w);
|
||||||
tile_h <<= zoom;
|
tile_h = zoom.apply(tile_h);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tile size
|
// Tile size
|
||||||
if (tile_w < (1<<zoom)) tile_w = (1<<zoom);
|
if (tile_w < zoom.apply(1)) tile_w = zoom.apply(1);
|
||||||
if (tile_h < (1<<zoom)) tile_h = (1<<zoom);
|
if (tile_h < zoom.apply(1)) tile_h = zoom.apply(1);
|
||||||
|
|
||||||
// Tile position (u,v) is the number of tile we start in (source_x,source_y) coordinate
|
// Tile position (u,v) is the number of tile we start in (source_x,source_y) coordinate
|
||||||
u = (source_x / tile_w);
|
u = (source_x / tile_w);
|
||||||
@ -535,9 +635,9 @@ void RenderEngine::renderCheckedBackground(Image* image,
|
|||||||
|
|
||||||
// static
|
// static
|
||||||
void RenderEngine::renderImage(Image* rgb_image, Image* src_image, const Palette* pal,
|
void RenderEngine::renderImage(Image* rgb_image, Image* src_image, const Palette* pal,
|
||||||
int x, int y, int zoom)
|
int x, int y, Zoom zoom)
|
||||||
{
|
{
|
||||||
void (*zoomed_func)(Image*, const Image*, const Palette*, int, int, int, int, int);
|
void (*zoomed_func)(Image*, const Image*, const Palette*, int, int, int, int, Zoom);
|
||||||
|
|
||||||
ASSERT(rgb_image->pixelFormat() == IMAGE_RGB && "renderImage accepts RGB destination images only");
|
ASSERT(rgb_image->pixelFormat() == IMAGE_RGB && "renderImage accepts RGB destination images only");
|
||||||
|
|
||||||
@ -566,8 +666,8 @@ void RenderEngine::renderLayer(
|
|||||||
const Layer* layer,
|
const Layer* layer,
|
||||||
Image *image,
|
Image *image,
|
||||||
int source_x, int source_y,
|
int source_x, int source_y,
|
||||||
FrameNumber frame, int zoom,
|
FrameNumber frame, Zoom zoom,
|
||||||
void (*zoomed_func)(Image*, const Image*, const Palette*, int, int, int, int, int),
|
void (*zoomed_func)(Image*, const Image*, const Palette*, int, int, int, int, Zoom),
|
||||||
bool render_background,
|
bool render_background,
|
||||||
bool render_transparent,
|
bool render_transparent,
|
||||||
int blend_mode)
|
int blend_mode)
|
||||||
@ -607,8 +707,8 @@ void RenderEngine::renderLayer(
|
|||||||
ASSERT(src_image->maskColor() == m_sprite->transparentColor());
|
ASSERT(src_image->maskColor() == m_sprite->transparentColor());
|
||||||
|
|
||||||
(*zoomed_func)(image, src_image, m_sprite->getPalette(frame),
|
(*zoomed_func)(image, src_image, m_sprite->getPalette(frame),
|
||||||
(cel->x() << zoom) - source_x,
|
zoom.apply(cel->x()) - source_x,
|
||||||
(cel->y() << zoom) - source_y,
|
zoom.apply(cel->y()) - source_y,
|
||||||
output_opacity,
|
output_opacity,
|
||||||
(blend_mode < 0 ?
|
(blend_mode < 0 ?
|
||||||
static_cast<const LayerImage*>(layer)->getBlendMode():
|
static_cast<const LayerImage*>(layer)->getBlendMode():
|
||||||
@ -645,8 +745,8 @@ void RenderEngine::renderLayer(
|
|||||||
Image* extraImage = m_document->getExtraCelImage();
|
Image* extraImage = m_document->getExtraCelImage();
|
||||||
|
|
||||||
(*zoomed_func)(image, extraImage, m_sprite->getPalette(frame),
|
(*zoomed_func)(image, extraImage, m_sprite->getPalette(frame),
|
||||||
(extraCel->x() << zoom) - source_x,
|
zoom.apply(extraCel->x()) - source_x,
|
||||||
(extraCel->y() << zoom) - source_y,
|
zoom.apply(extraCel->y()) - source_y,
|
||||||
extraCel->opacity(),
|
extraCel->opacity(),
|
||||||
m_document->getExtraCelBlendMode(), zoom);
|
m_document->getExtraCelBlendMode(), zoom);
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "app/color.h"
|
#include "app/color.h"
|
||||||
|
#include "app/zoom.h"
|
||||||
#include "doc/frame_number.h"
|
#include "doc/frame_number.h"
|
||||||
|
|
||||||
namespace doc {
|
namespace doc {
|
||||||
@ -70,7 +71,7 @@ namespace app {
|
|||||||
|
|
||||||
Image* renderSprite(int source_x, int source_y,
|
Image* renderSprite(int source_x, int source_y,
|
||||||
int width, int height,
|
int width, int height,
|
||||||
FrameNumber frame, int zoom,
|
FrameNumber frame, Zoom zoom,
|
||||||
bool draw_tiled_bg,
|
bool draw_tiled_bg,
|
||||||
bool enable_onionskin);
|
bool enable_onionskin);
|
||||||
|
|
||||||
@ -79,18 +80,18 @@ namespace app {
|
|||||||
|
|
||||||
static void renderCheckedBackground(Image* image,
|
static void renderCheckedBackground(Image* image,
|
||||||
int source_x, int source_y,
|
int source_x, int source_y,
|
||||||
int zoom);
|
Zoom zoom);
|
||||||
|
|
||||||
static void renderImage(Image* rgb_image, Image* src_image, const Palette* pal,
|
static void renderImage(Image* rgb_image, Image* src_image, const Palette* pal,
|
||||||
int x, int y, int zoom);
|
int x, int y, Zoom zoom);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void renderLayer(
|
void renderLayer(
|
||||||
const Layer* layer,
|
const Layer* layer,
|
||||||
Image* image,
|
Image* image,
|
||||||
int source_x, int source_y,
|
int source_x, int source_y,
|
||||||
FrameNumber frame, int zoom,
|
FrameNumber frame, Zoom zoom,
|
||||||
void (*zoomed_func)(Image*, const Image*, const Palette*, int, int, int, int, int),
|
void (*zoomed_func)(Image*, const Image*, const Palette*, int, int, int, int, Zoom),
|
||||||
bool render_background,
|
bool render_background,
|
||||||
bool render_transparent,
|
bool render_transparent,
|
||||||
int blend_mode);
|
int blend_mode);
|
||||||
|
47
src/app/zoom.cpp
Normal file
47
src/app/zoom.cpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/* Aseprite
|
||||||
|
* Copyright (C) 2001-2014 David Capello
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "app/zoom.h"
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
void Zoom::in()
|
||||||
|
{
|
||||||
|
if (m_den > 1) {
|
||||||
|
m_den--;
|
||||||
|
}
|
||||||
|
else if (m_num < 64) {
|
||||||
|
m_num++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Zoom::out()
|
||||||
|
{
|
||||||
|
if (m_num > 1) {
|
||||||
|
m_num--;
|
||||||
|
}
|
||||||
|
else if (m_den < 32) {
|
||||||
|
m_den++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace app
|
57
src/app/zoom.h
Normal file
57
src/app/zoom.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/* Aseprite
|
||||||
|
* Copyright (C) 2001-2014 David Capello
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef APP_ZOOM_H_INCLUDED
|
||||||
|
#define APP_ZOOM_H_INCLUDED
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
class Zoom {
|
||||||
|
public:
|
||||||
|
Zoom(int num, int den)
|
||||||
|
: m_num(num), m_den(den) {
|
||||||
|
}
|
||||||
|
|
||||||
|
double scale() const { return static_cast<double>(m_num) / static_cast<double>(m_den); }
|
||||||
|
|
||||||
|
int apply(int x) const { return x * m_num / m_den; }
|
||||||
|
int remove(int x) const { return x * m_den / m_num; }
|
||||||
|
|
||||||
|
double apply(double x) const { return x * m_num / m_den; }
|
||||||
|
double remove(double x) const { return x * m_den / m_num; }
|
||||||
|
|
||||||
|
void in();
|
||||||
|
void out();
|
||||||
|
|
||||||
|
bool operator==(const Zoom& other) const {
|
||||||
|
return m_num == other.m_num && m_den == other.m_den;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const Zoom& other) const {
|
||||||
|
return !operator==(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_num;
|
||||||
|
int m_den;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace app
|
||||||
|
|
||||||
|
#endif // APP_ZOOM_H_INCLUDED
|
Loading…
x
Reference in New Issue
Block a user