mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-29 19:20:09 +00:00
Merge branch 'main' into beta
This commit is contained in:
commit
b83f2953f9
@ -473,7 +473,6 @@ FileOp* FileOp::createSaveDocumentOperation(const Context* context,
|
||||
#ifdef ENABLE_UI
|
||||
// Interative
|
||||
if (context && context->isUIAvailable()) {
|
||||
auto& showAlertOption = Preferences::instance().saveFile.showFileFormatDoesntSupportAlert;
|
||||
int ret;
|
||||
|
||||
// If the error is fatal, we cannot ignore a no-op, we always
|
||||
|
@ -313,7 +313,7 @@ public:
|
||||
|
||||
const double angle = loop->getController()->getShapeAngle();
|
||||
if (ABS(angle) < 0.001) {
|
||||
algo_ellipse(x1, y1, x2, y2, loop, (AlgoPixel)doPointshapePoint);
|
||||
algo_ellipse(x1, y1, x2, y2, 0, 0, loop, (AlgoPixel)doPointshapePoint);
|
||||
}
|
||||
else {
|
||||
draw_rotated_ellipse((x1+x2)/2, (y1+y2)/2,
|
||||
@ -343,7 +343,7 @@ public:
|
||||
|
||||
const double angle = loop->getController()->getShapeAngle();
|
||||
if (ABS(angle) < 0.001) {
|
||||
algo_ellipsefill(x1, y1, x2, y2, loop, (AlgoHLine)doPointshapeHline);
|
||||
algo_ellipsefill(x1, y1, x2, y2, 0, 0, loop, (AlgoHLine)doPointshapeHline);
|
||||
}
|
||||
else {
|
||||
fill_rotated_ellipse((x1+x2)/2, (y1+y2)/2,
|
||||
|
@ -1,4 +1,5 @@
|
||||
Copyright (C) 2017-2018 David Capello
|
||||
Copyright (C) 2021 Igara Studio S.A.
|
||||
Copyright (C) 2017-2018 David Capello
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
@ -1,7 +1,6 @@
|
||||
# Desktop Integration
|
||||
*Copyright (C) 2017-2018 David Capello*
|
||||
|
||||
> Distributed under [MIT license](LICENSE.txt)
|
||||
[](LICENSE.txt)
|
||||
|
||||
## Windows
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Desktop Integration
|
||||
// Copyright (C) 2021 Igara Studio S.A.
|
||||
// Copyright (C) 2017-2018 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -18,6 +19,7 @@
|
||||
|
||||
#include "desktop/win/thumbnail_handler.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <new>
|
||||
|
||||
@ -174,6 +176,9 @@ HRESULT ThumbnailHandler::Initialize(IStream* pStream, DWORD grfMode)
|
||||
// IThumbnailProvider
|
||||
HRESULT ThumbnailHandler::GetThumbnail(UINT cx, HBITMAP* phbmp, WTS_ALPHATYPE* pdwAlpha)
|
||||
{
|
||||
if (cx < 1 || !phbmp || !pdwAlpha)
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (!m_stream.get())
|
||||
return E_FAIL;
|
||||
|
||||
@ -186,16 +191,27 @@ HRESULT ThumbnailHandler::GetThumbnail(UINT cx, HBITMAP* phbmp, WTS_ALPHATYPE* p
|
||||
if (!dio::decode_file(&delegate, &adaptor))
|
||||
return E_FAIL;
|
||||
|
||||
doc::Sprite* spr = delegate.sprite();
|
||||
const doc::Sprite* spr = delegate.sprite();
|
||||
w = spr->width();
|
||||
h = spr->height();
|
||||
int wh = std::max<int>(w, h);
|
||||
|
||||
image.reset(doc::Image::create(doc::IMAGE_RGB, w, h));
|
||||
image.reset(doc::Image::create(doc::IMAGE_RGB,
|
||||
cx * w / wh,
|
||||
cx * h / wh));
|
||||
image->clear(0);
|
||||
|
||||
#undef TRANSPARENT // Windows defines TRANSPARENT macro
|
||||
render::Render render;
|
||||
render.setBgType(render::BgType::TRANSPARENT);
|
||||
render.renderSprite(image.get(), spr, 0);
|
||||
render.setProjection(render::Projection(doc::PixelRatio(1, 1),
|
||||
render::Zoom(cx, wh)));
|
||||
render.renderSprite(image.get(), spr, 0,
|
||||
gfx::ClipF(0, 0, 0, 0,
|
||||
image->width(), image->height()));
|
||||
|
||||
w = image->width();
|
||||
h = image->height();
|
||||
}
|
||||
catch (const std::exception&) {
|
||||
// TODO convert exception into a HRESULT
|
||||
|
145
src/doc/algo.cpp
145
src/doc/algo.cpp
@ -1,5 +1,5 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2018-2020 Igara Studio S.A.
|
||||
// Copyright (c) 2018-2021 Igara Studio S.A.
|
||||
// Copyright (c) 2001-2018 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -171,64 +171,147 @@ void algo_line_continuous_with_fix_for_line_brush(int x0, int y0, int x1, int y1
|
||||
}
|
||||
}
|
||||
|
||||
static int adjust_ellipse_args(int& x0, int& y0, int& x1, int& y1,
|
||||
int& hPixels, int& vPixels)
|
||||
{
|
||||
// hPixels : straight horizontal pixels added to mid region of the ellipse.
|
||||
hPixels = std::max(hPixels, 0);
|
||||
// vPixels : straight vertical pixels added to mid region of the ellipse.
|
||||
vPixels = std::max(vPixels, 0);
|
||||
|
||||
// Conditioning swapped points
|
||||
if (x0 > x1)
|
||||
std::swap(x0, x1);
|
||||
if (y0 > y1)
|
||||
std::swap(y0, y1);
|
||||
int w = x1 - x0 + 1;
|
||||
int h = y1 - y0 + 1;
|
||||
|
||||
// hDiameter is the horizontal diameter of a circunference
|
||||
// without the addition of straight pixels.
|
||||
int hDiameter = w - hPixels;
|
||||
// vDiameter is the vertical diameter of a circunference
|
||||
// without the addition of straight pixels.
|
||||
int vDiameter = h - vPixels;
|
||||
|
||||
// Manual adjustment
|
||||
if (w == 8 || w == 12 || w == 22)
|
||||
hPixels++;
|
||||
if (h == 8 || h == 12 || h == 22)
|
||||
vPixels++;
|
||||
|
||||
hPixels = (hDiameter > 5 ? hPixels : 0);
|
||||
vPixels = (vDiameter > 5 ? vPixels : 0);
|
||||
|
||||
if ((hDiameter % 2 == 0) && (hDiameter > 5))
|
||||
hPixels--;
|
||||
if ((vDiameter % 2 == 0) && (vDiameter > 5))
|
||||
vPixels--;
|
||||
|
||||
x1 -= hPixels;
|
||||
y1 -= vPixels;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
// Ellipse code based on Alois Zingl work released under the MIT
|
||||
// license http://members.chello.at/easyfilter/bresenham.html
|
||||
//
|
||||
// Adapted for Aseprite by David Capello
|
||||
|
||||
void algo_ellipse(int x0, int y0, int x1, int y1, void* data, AlgoPixel proc)
|
||||
void algo_ellipse(int x0, int y0, int x1, int y1,
|
||||
int hPixels, int vPixels,
|
||||
void* data, AlgoPixel proc)
|
||||
{
|
||||
long a = abs(x1-x0), b = abs(y1-y0), b1 = b&1; // diameter
|
||||
double dx = 4*(1.0-a)*b*b, dy = 4*(b1+1)*a*a; // error increment
|
||||
double err = dx+dy+b1*a*a, e2; // error of 1.step
|
||||
int h = adjust_ellipse_args(x0, y0, x1, y1, hPixels, vPixels);
|
||||
|
||||
if (x0 > x1) { x0 = x1; x1 += a; } // if called with swapped points
|
||||
if (y0 > y1) y0 = y1; // .. exchange them
|
||||
y0 += (b+1)/2; y1 = y0-b1; // starting pixel
|
||||
a = 8*a*a; b1 = 8*b*b;
|
||||
long a = abs(x1-x0);
|
||||
long b = abs(y1-y0); // diameter
|
||||
long b1 = b&1;
|
||||
double dx = 4*(1.0-a)*b*b; // error increment
|
||||
double dy = 4*(b1+1)*a*a; // error increment
|
||||
double err = dx + dy + b1*a*a; // error of 1.step
|
||||
double e2;
|
||||
|
||||
y0 += (b+1)/2;
|
||||
y1 = y0-b1; // starting pixel
|
||||
a = 8*a*a;
|
||||
b1 = 8*b*b;
|
||||
|
||||
int initialY0 = y0;
|
||||
int initialY1 = y1;
|
||||
int initialX0 = x0;
|
||||
int initialX1 = x1 + hPixels;
|
||||
do {
|
||||
proc(x1, y0, data); // I. Quadrant
|
||||
proc(x0, y0, data); // II. Quadrant
|
||||
proc(x0, y1, data); // III. Quadrant
|
||||
proc(x1, y1, data); // IV. Quadrant
|
||||
proc(x1 + hPixels, y0 + vPixels, data); // I. Quadrant
|
||||
proc(x0, y0 + vPixels, data); // II. Quadrant
|
||||
proc(x0, y1, data); // III. Quadrant
|
||||
proc(x1 + hPixels, y1, data); // IV. Quadrant
|
||||
|
||||
e2 = 2*err;
|
||||
if (e2 <= dy) { y0++; y1--; err += dy += a; } // y step
|
||||
if (e2 >= dx || 2*err > dy) { x0++; x1--; err += dx += b1; } // x step
|
||||
} while (x0 <= x1);
|
||||
|
||||
while (y0-y1 <= b) { // too early stop of flat ellipses a=1
|
||||
proc(x0-1, y0, data); // -> finish tip of ellipse
|
||||
proc(x1+1, y0++, data);
|
||||
proc(x0-1, y1, data);
|
||||
proc(x1+1, y1--, data);
|
||||
while (y0 + vPixels - y1 + 1 <= h) { // too early stop of flat ellipses a=1
|
||||
proc(x0 - 1, y0 + vPixels, data); // -> finish tip of ellipse
|
||||
proc(x1 + 1 + hPixels, y0++ + vPixels, data);
|
||||
proc(x0 - 1, y1, data);
|
||||
proc(x1 + 1 + hPixels, y1--, data);
|
||||
}
|
||||
|
||||
// Extra horizontal straight pixels
|
||||
if (hPixels > 0) {
|
||||
for (int i = x0; i < x1 + hPixels + 1; i++) {
|
||||
proc(i, y1 + 1, data);
|
||||
proc(i, y0 + vPixels - 1, data);
|
||||
}
|
||||
}
|
||||
// Extra vertical straight pixels
|
||||
if (vPixels > 0) {
|
||||
for (int i = initialY1 + 1; i < initialY0 + vPixels; i++) {
|
||||
proc(initialX0, i, data);
|
||||
proc(initialX1, i, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void algo_ellipsefill(int x0, int y0, int x1, int y1, void* data, AlgoHLine proc)
|
||||
void algo_ellipsefill(int x0, int y0, int x1, int y1,
|
||||
int hPixels, int vPixels,
|
||||
void* data, AlgoHLine proc)
|
||||
{
|
||||
long a = abs(x1-x0), b = abs(y1-y0), b1 = b&1; // diameter
|
||||
int h = adjust_ellipse_args(x0, y0, x1, y1, hPixels, vPixels);
|
||||
|
||||
long a = abs(x1-x0), b = abs(y1-y0), b1 = b&1; // diameter
|
||||
double dx = 4*(1.0-a)*b*b, dy = 4*(b1+1)*a*a; // error increment
|
||||
double err = dx+dy+b1*a*a, e2; // error of 1.step
|
||||
|
||||
if (x0 > x1) { x0 = x1; x1 += a; } // if called with swapped points
|
||||
if (y0 > y1) y0 = y1; // .. exchange them
|
||||
y0 += (b+1)/2; y1 = y0-b1; // starting pixel
|
||||
y0 += (b+1)/2; y1 = y0-b1; // starting pixel
|
||||
a = 8*a*a; b1 = 8*b*b;
|
||||
|
||||
int initialY0 = y0;
|
||||
int initialY1 = y1;
|
||||
int initialX0 = x0;
|
||||
int initialX1 = x1 + hPixels;
|
||||
|
||||
do {
|
||||
proc(x0, y0, x1, data);
|
||||
proc(x0, y1, x1, data);
|
||||
proc(x0, y0 + vPixels, x1 + hPixels, data);
|
||||
proc(x0, y1, x1 + hPixels, data);
|
||||
e2 = 2*err;
|
||||
if (e2 <= dy) { y0++; y1--; err += dy += a; } // y step
|
||||
if (e2 >= dx || 2*err > dy) { x0++; x1--; err += dx += b1; } // x step
|
||||
} while (x0 <= x1);
|
||||
|
||||
while (y0-y1 <= b) { // too early stop of flat ellipses a=1
|
||||
proc(x0-1, y0, x0-1, data); // -> finish tip of ellipse
|
||||
proc(x1+1, y0++, x1+1, data);
|
||||
proc(x0-1, y1, x0-1, data);
|
||||
proc(x1+1, y1--, x1+1, data);
|
||||
while (y0 + vPixels - y1 + 1 < h) { // too early stop of flat ellipses a=1
|
||||
proc(x0-1, ++y0 + vPixels, x0-1, data); // -> finish tip of ellipse
|
||||
proc(x1+1 + hPixels, y0 + vPixels, x1+1 + hPixels, data);
|
||||
proc(x0-1, --y1, x0-1, data);
|
||||
proc(x1+1 + hPixels, y1, x1+1 + hPixels, data);
|
||||
}
|
||||
|
||||
if (vPixels > 0) {
|
||||
for (int i = initialY1 + 1; i < initialY0 + vPixels; i++)
|
||||
proc(initialX0, i, initialX1, data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -324,7 +407,7 @@ static void draw_rotated_ellipse_rect(int x0, int y0, int x1, int y1, double zd,
|
||||
double w = xd*yd;
|
||||
|
||||
if (zd == 0)
|
||||
return algo_ellipse(x0, y0, x1, y1, data, proc);
|
||||
return algo_ellipse(x0, y0, x1, y1, 0, 0, data, proc);
|
||||
|
||||
if (w != 0.0)
|
||||
w = (w-zd) / (w+w); // squared weight of P1
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (C) 2018-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2021 Igara Studio S.A.
|
||||
// Copyright (c) 2001-2018 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -38,8 +38,8 @@ namespace doc {
|
||||
void algo_line_continuous(int x1, int y1, int x2, int y2, void *data, AlgoPixel proc);
|
||||
void algo_line_continuous_with_fix_for_line_brush(int x1, int y1, int x2, int y2, void *data, AlgoPixel proc);
|
||||
|
||||
void algo_ellipse(int x1, int y1, int x2, int y2, void *data, AlgoPixel proc);
|
||||
void algo_ellipsefill(int x1, int y1, int x2, int y2, void *data, AlgoHLine proc);
|
||||
void algo_ellipse(int x1, int y1, int x2, int y2, int hPixels, int vPixels, void *data, AlgoPixel proc);
|
||||
void algo_ellipsefill(int x1, int y1, int x2, int y2, int hPixels, int vPixels, void *data, AlgoHLine proc);
|
||||
|
||||
void draw_rotated_ellipse(int cx, int cy, int a, int b, double angle, void* data, AlgoPixel proc);
|
||||
void fill_rotated_ellipse(int cx, int cy, int a, int b, double angle, void* data, AlgoHLine proc);
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2021 Igara Studio S.A.
|
||||
// Copyright (c) 2018 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -41,7 +42,7 @@ void modify_selection(const SelectionModifier modifier,
|
||||
std::unique_ptr<doc::Image> kernel(doc::Image::create(IMAGE_BITMAP, size, size));
|
||||
doc::clear_image(kernel.get(), 0);
|
||||
if (brush == doc::kCircleBrushType)
|
||||
doc::fill_ellipse(kernel.get(), 0, 0, size-1, size-1, 1);
|
||||
doc::fill_ellipse(kernel.get(), 0, 0, size-1, size-1, 0, 0, 1);
|
||||
else
|
||||
doc::fill_rect(kernel.get(), 0, 0, size-1, size-1, 1);
|
||||
doc::put_pixel(kernel.get(), radius, radius, 0);
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -328,7 +328,7 @@ void Brush::regenerate()
|
||||
switch (m_type) {
|
||||
|
||||
case kCircleBrushType:
|
||||
fill_ellipse(m_image.get(), 0, 0, size-1, size-1, BitmapTraits::max_value);
|
||||
fill_ellipse(m_image.get(), 0, 0, size-1, size-1, 0, 0, BitmapTraits::max_value);
|
||||
break;
|
||||
|
||||
case kSquareBrushType:
|
||||
|
@ -292,16 +292,16 @@ void draw_line(Image* image, int x1, int y1, int x2, int y2, color_t color)
|
||||
algo_line_continuous(x1, y1, x2, y2, &data, (AlgoPixel)pixel_for_image);
|
||||
}
|
||||
|
||||
void draw_ellipse(Image* image, int x1, int y1, int x2, int y2, color_t color)
|
||||
void draw_ellipse(Image* image, int x1, int y1, int x2, int y2, int extraXPxs, int extraYPxs, color_t color)
|
||||
{
|
||||
Data data = { image, color };
|
||||
algo_ellipse(x1, y1, x2, y2, &data, (AlgoPixel)pixel_for_image);
|
||||
algo_ellipse(x1, y1, x2, y2, extraXPxs, extraYPxs, &data, (AlgoPixel)pixel_for_image);
|
||||
}
|
||||
|
||||
void fill_ellipse(Image* image, int x1, int y1, int x2, int y2, color_t color)
|
||||
void fill_ellipse(Image* image, int x1, int y1, int x2, int y2, int extraXPxs, int extraYPxs, color_t color)
|
||||
{
|
||||
Data data = { image, color };
|
||||
algo_ellipsefill(x1, y1, x2, y2, &data, (AlgoHLine)hline_for_image);
|
||||
algo_ellipsefill(x1, y1, x2, y2, extraXPxs, extraYPxs, &data, (AlgoHLine)hline_for_image);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -39,8 +39,8 @@ namespace doc {
|
||||
void fill_rect(Image* image, const gfx::Rect& rc, color_t c);
|
||||
void blend_rect(Image* image, int x1, int y1, int x2, int y2, color_t c, int opacity);
|
||||
void draw_line(Image* image, int x1, int y1, int x2, int y2, color_t c);
|
||||
void draw_ellipse(Image* image, int x1, int y1, int x2, int y2, color_t c);
|
||||
void fill_ellipse(Image* image, int x1, int y1, int x2, int y2, color_t c);
|
||||
void draw_ellipse(Image* image, int x1, int y1, int x2, int y2, int extraXPxs, int extraYPxs, color_t color);
|
||||
void fill_ellipse(Image* image, int x1, int y1, int x2, int y2, int extraXPxs, int extraYPxs, color_t color);
|
||||
|
||||
bool is_plain_image(const Image* img, color_t c);
|
||||
bool is_empty_image(const Image* img);
|
||||
|
Loading…
x
Reference in New Issue
Block a user