ide: IconDes optimisations

This commit is contained in:
Mirek Fidler 2024-07-08 02:38:58 +02:00
parent 91165d0400
commit 81ebe5dbee
13 changed files with 290 additions and 215 deletions

View file

@ -8,7 +8,8 @@ enum ImageKind {
IMAGE_OPAQUE,
};
inline void Fill(RGBA *t, RGBA c, size_t n) { memset32(t, *(dword *)&c, n); }
inline void Fill(RGBA *t, RGBA c, size_t n) { memset32(t, *(dword *)&c, n); }
void FillDown(RGBA *t, int linecy, RGBA c, int cy);
inline void Copy(RGBA *t, const RGBA *s, int n) { memcpy_t(t, s, n); }
int Premultiply(RGBA *t, const RGBA *s, size_t len);
@ -256,6 +257,7 @@ struct ImageIml : Moveable<ImageIml> {
dword flags = 0;
};
Vector<ImageIml> UnpackImlDataUncompressed(const String& data);
Vector<ImageIml> UnpackImlData(const void *ptr, int len);
Vector<ImageIml> UnpackImlData(const String& d);

View file

@ -115,6 +115,25 @@ int Premultiply(RGBA *t, const RGBA *s, size_t len)
return IMAGE_OPAQUE;
}
void FillDown(RGBA *t, int linecy, RGBA c, int cy)
{
for(int n = cy >> 3; n; n--) {
t[0] = t[linecy] = t[2 * linecy] = t[3 * linecy] =
t[4 * linecy] = t[5 * linecy] = t[6 * linecy] = t[7 * linecy] = c;
t += 8 * linecy;
}
if(cy & 4) {
t[0] = t[linecy] = t[2 * linecy] = t[3 * linecy] = c;
t += 4 * linecy;
}
if(cy & 2) {
t[0] = t[linecy] = c;
t += 2 * linecy;
}
if(cy & 1)
t[0] = c;
}
int um_table__[256];
void sInitUmTable__()

View file

@ -86,22 +86,28 @@ force_inline Size DstSrc(ImageBuffer& dest, Point& p, const Image& src, Rect& sr
}
void DstSrcOp(ImageBuffer& dest, Point p, const Image& src, const Rect& srect,
void (*op)(RGBA *t, const RGBA *s, int n))
void (*op)(RGBA *t, const RGBA *s, int n), bool co)
{
dest.SetResolution(src.GetResolution());
Rect sr = srect;
Size sz = DstSrc(dest, p, src, sr);
if(sz.cx > 0)
while(--sz.cy >= 0)
(*op)(dest[p.y++] + p.x, src[sr.top++] + sr.left, sz.cx);
if(sz.cx > 0) {
if(co)
CoFor(sz.cy, [&](int i) {
(*op)(dest[p.y + i] + p.x, src[sr.top + i] + sr.left, sz.cx);
});
else
while(--sz.cy >= 0)
(*op)(dest[p.y++] + p.x, src[sr.top++] + sr.left, sz.cx);
}
}
void Copy(ImageBuffer& dest, Point p, const Image& src, const Rect& srect)
void Copy(ImageBuffer& dest, Point p, const Image& src, const Rect& srect, bool co)
{
DstSrcOp(dest, p, src, srect, Copy);
}
void Over(ImageBuffer& dest, Point p, const Image& src, const Rect& srect)
void Over(ImageBuffer& dest, Point p, const Image& src, const Rect& srect, bool co)
{
DstSrcOp(dest, p, src, srect, AlphaBlend);
}
@ -113,7 +119,7 @@ Image GetOver(const Image& dest, const Image& src)
return r;
}
Image Copy(const Image& src, const Rect& srect)
Image Copy(const Image& src, const Rect& srect, bool co)
{
ImageBuffer ib(srect.GetSize());
Copy(ib, Point(0, 0), src, srect);
@ -129,30 +135,30 @@ void Fill(ImageBuffer& dest, const Rect& rect, RGBA color)
Fill(dest[y] + r.left, color, cx);
}
void OverStraightOpaque(ImageBuffer& dest, Point p, const Image& src, const Rect& srect)
void OverStraightOpaque(ImageBuffer& dest, Point p, const Image& src, const Rect& srect, bool co)
{
DstSrcOp(dest, p, src, srect, AlphaBlendStraightOpaque);
}
void Copy(Image& dest, Point p, const Image& _src, const Rect& srect)
void Copy(Image& dest, Point p, const Image& _src, const Rect& srect, bool co)
{
Image src = _src;
ImageBuffer b(dest);
Copy(b, p, src, srect);
Copy(b, p, src, srect, co);
dest = b;
}
void Over(Image& dest, Point p, const Image& _src, const Rect& srect)
void Over(Image& dest, Point p, const Image& _src, const Rect& srect, bool co)
{
Image src = _src;
ImageBuffer b(dest);
Over(b, p, src, srect);
Over(b, p, src, srect, co);
dest = b;
}
void Over(Image& dest, const Image& _src)
void Over(Image& dest, const Image& _src, bool co)
{
Over(dest, Point(0, 0), _src, _src.GetSize());
Over(dest, Point(0, 0), _src, _src.GetSize(), co);
}
void Fill(Image& dest, const Rect& rect, RGBA color)
@ -162,11 +168,11 @@ void Fill(Image& dest, const Rect& rect, RGBA color)
dest = b;
}
void OverStraightOpaque(Image& dest, Point p, const Image& _src, const Rect& srect)
void OverStraightOpaque(Image& dest, Point p, const Image& _src, const Rect& srect, bool co)
{
Image src = _src;
ImageBuffer b(dest);
OverStraightOpaque(b, p, src, srect);
OverStraightOpaque(b, p, src, srect, co);
dest = b;
}
@ -190,7 +196,7 @@ Image Crop(const Image& img, const Rect& rc)
return WithResolution(tgt, img);
}
Image AddMargins(const Image& img, int left, int top, int right, int bottom, RGBA color)
Image AddMargins(const Image& img, int left, int top, int right, int bottom, RGBA color, bool co)
{
Size sz = img.GetSize();
ImageBuffer ib(sz.cx + left + right, sz.cy + top + bottom);

View file

@ -13,22 +13,24 @@ Image WithResolution(const Image& m, const Image& res);
void ScanOpaque(Image& m);
void DstSrcOp(ImageBuffer& dest, Point p, const Image& src, const Rect& srect,
void (*op)(RGBA *t, const RGBA *s, int n));
void (*op)(RGBA *t, const RGBA *s, int n), bool co = false);
void Copy(ImageBuffer& dest, Point p, const Image& src, const Rect& srect, bool co = false);
void Over(ImageBuffer& dest, Point p, const Image& src, const Rect& srect, bool co = false);
void Over(Image& dest, Point p, const Image& _src, const Rect& srect, bool co = false);
void Over(Image& dest, const Image& _src, bool co = false);
void Over(ImageBuffer& dest, Point p, const Image& src, const Rect& srect);
void Over(Image& dest, const Image& src);
void Copy(ImageBuffer& dest, Point p, const Image& src, const Rect& srect);
void Fill(ImageBuffer& dest, const Rect& rect, RGBA color);
void Copy(Image& dest, Point p, const Image& src, const Rect& srect);
void Over(Image& dest, Point p, const Image& src, const Rect& srect);
void Copy(Image& dest, Point p, const Image& src, const Rect& srect, bool co = false);
Image GetOver(const Image& dest, const Image& src);
void Fill(Image& dest, const Rect& rect, RGBA color);
Image Copy(const Image& src, const Rect& srect);
void OverStraightOpaque(ImageBuffer& dest, Point p, const Image& src, const Rect& srect);
void OverStraightOpaque(Image& dest, Point p, const Image& _src, const Rect& srect);
void OverStraightOpaque(ImageBuffer& dest, Point p, const Image& src, const Rect& srect, bool co = false);
void OverStraightOpaque(Image& dest, Point p, const Image& _src, const Rect& srect, bool co = false);
void Crop(RasterEncoder& tgt, Raster& img, const Rect& rc);
Image Crop(const Image& img, const Rect& rc);
@ -241,6 +243,7 @@ Image CachedRescalePaintOnly(const Image& m, Size sz, int filter = Null);
Image CachedSetColorKeepAlpha(const Image& img, Color color);
Image CachedSetColorKeepAlphaPaintOnly(const Image& img, Color color);
Image Magnify(const Image& img, const Rect& src, int nx, int ny, bool co);
Image Magnify(const Image& img, int nx, int ny);
Image Minify(const Image& img, int nx, int ny, bool co = false);
Image MinifyCached(const Image& img, int nx, int ny, bool co = false);

View file

@ -2,10 +2,9 @@
namespace Upp {
Vector<ImageIml> UnpackImlData(const void *ptr, int len)
Vector<ImageIml> UnpackImlDataUncompressed(const String& data)
{
Vector<ImageIml> img;
String data = ZDecompress(ptr, len);
const char *s = data;
while(s + 6 * 2 + 1 <= data.End()) {
ImageIml& m = img.Add();
@ -35,6 +34,11 @@ Vector<ImageIml> UnpackImlData(const void *ptr, int len)
return img;
}
Vector<ImageIml> UnpackImlData(const void *ptr, int len)
{
return UnpackImlDataUncompressed(ZDecompress(ptr, len));
}
Vector<ImageIml> UnpackImlData(const String& d)
{
return UnpackImlData(~d, d.GetLength());

View file

@ -179,24 +179,22 @@ Image MinifyCached(const Image& img, int nx, int ny, bool co)
return MakeImage(m);
}
Image Magnify(const Image& img, int nx, int ny)
Image Magnify(const Image& img, const Rect& src_, int nx, int ny, bool co)
{
if(nx == 1 && ny == 1)
return img;
if(nx == 0 || ny == 0)
return Image();
Size sz = img.GetSize();
Rect src = src_ & img.GetSize();
bool xdown = nx < 0;
nx = abs(nx);
int ncx = xdown ? sz.cx / nx : sz.cx * nx;
ImageBuffer b(ncx, sz.cy * ny);
const RGBA *s = ~img;
const RGBA *e = s + img.GetLength();
RGBA *t = ~b;
while(s < e) {
Size ssz = src.GetSize();
if(ssz.cx <= 0 || ssz.cy <= 0 || nx == 0 || ny == 0)
return Image();
int ncx = xdown ? ssz.cx / nx : ssz.cx * nx;
ImageBuffer b(ncx, ssz.cy * ny);
CoFor(co, ssz.cy, [&](int y) {
const RGBA *s = img[src.top + y] + src.left;
const RGBA *e = s + ssz.cx;
RGBA *t = ~b + y * ncx * ny;
RGBA *q = t;
const RGBA *le = s + sz.cx;
while(s < le) {
while(s < e) {
Fill(q, *s, nx);
q += nx;
s++;
@ -205,10 +203,16 @@ Image Magnify(const Image& img, int nx, int ny)
memcpy(q, t, ncx * sizeof(RGBA));
q += ncx;
}
t = q;
}
});
b.SetResolution(img.GetResolution());
return b;
}
Image Magnify(const Image& img, int nx, int ny)
{
if(nx == 1 && ny == 1)
return img;
return Magnify(img, img.GetSize(), nx, ny, false);
}
};

View file

@ -32,7 +32,7 @@ void IconDes::SetMagnify(int mag)
if( !IsCurrent() )
return;
magnify = minmax(mag, 1, 27);
magnify = minmax(mag, 1, 50);
sb = Point(0, 0);
SetSb();
@ -204,11 +204,11 @@ void IconDes::DrawBar(Bar& bar)
bar.Add(c, "Supersample 3x", IconDesImg::ResizeDown(), THISBACK(ResizeDown))
.Key(AK_RESIZEDOWN3);
bar.Add("Show UHD/Dark syntetics", IconDesImg::ShowOther(),
[=] { show_other = !show_other; show_small = false; SyncShow(); SetBar(); })
.Check(show_other);
[=] { show_synthetics = !show_synthetics; show_downscaled = false; SyncShow(); SetBar(); })
.Check(show_synthetics);
bar.Add("Show downscaled", IconDesImg::ShowSmall(),
[=] { show_small = !show_small; show_other = false; SyncShow(); SetBar(); })
.Check(show_small);
[=] { show_downscaled = !show_downscaled; show_synthetics = false; SyncShow(); SetBar(); })
.Check(show_downscaled);
bar.Add("Show secondardy grid", IconDesImg::grid2(),
[=] { show_grid2 = !show_grid2; Refresh(); SetBar(); })
.Check(show_grid2);
@ -324,12 +324,12 @@ void IconDes::SerializeSettings(Stream& s)
s % ImgFile();
if(version >= 3) {
bool b = false;
s % b % show_small;
s % b % show_downscaled;
}
if(version >= 4)
s % paste_mode;
if(version >= 5)
s % show_other;
s % show_synthetics;
if(version >= 6)
s % show_grid2;
}

View file

@ -44,8 +44,8 @@ void IconDes::SyncShow()
Slot& c = Current();
Image image = c.image;
iconshow.image = image;
iconshow.show_small = show_small;
iconshow.show_other = show_other;
iconshow.show_downscaled = show_downscaled;
iconshow.show_synthetics = show_synthetics;
ilist.Set(2, RawToValue(MakeTuple(image, c.flags)));
}
iconshow.Refresh();
@ -83,7 +83,7 @@ void IconDes::HorzMouseWheel(Point pt, int zdelta, dword keyflags)
void IconDes::Scroll()
{
magnify = max(magnify, 1);
scroller.Scroll(*this, GetSize(), sb, Size(magnify, magnify));
Refresh();
}
void IconDes::Layout()
@ -465,19 +465,29 @@ void IconDes::SelectRect()
SetBar();
}
String PackUndo(const Vector<ImageIml>& img)
{
return FastCompress(PackImlDataUncompressed(img));
}
Vector<ImageIml> UnpackUndo(const String& data)
{
return UnpackImlDataUncompressed(FastDecompress(data));
}
void IconDes::SaveUndo()
{
if(!IsCurrent())
return;
Slot& c = Current();
Vector<ImageIml> undo = UnpackImlData(c.undo);
int maxn = minmax((single_mode ? 4000000 : 400000) / max((int)c.image.GetLength(), 1), 4, 128);
Vector<ImageIml> undo = UnpackUndo(c.undo);
int maxn = minmax((single_mode ? 40000000 : 2000000) / max((int)c.image.GetLength(), 1), 4, 128);
while(undo.GetCount() > maxn)
undo.Remove(0);
if(undo.GetCount() && undo.Top().image == c.image)
return;
undo.Add().image = c.image;
c.undo = PackImlData(undo);
c.undo = PackUndo(undo);
c.redo.Clear();
SetBar();
undo.Clear();
@ -488,14 +498,14 @@ void IconDes::Undo()
if(!IsCurrent())
return;
Slot& c = Current();
Vector<ImageIml> undo = UnpackImlData(c.undo);
Vector<ImageIml> undo = UnpackUndo(c.undo);
if(undo.GetCount() == 0)
return;
Vector<ImageIml> redo = UnpackImlData(c.redo);
Vector<ImageIml> redo = UnpackUndo(c.redo);
redo.Add().image = c.image;
c.image = undo.Pop().image;
c.undo = PackImlData(undo);
c.redo = PackImlData(redo);
c.undo = PackUndo(undo);
c.redo = PackUndo(redo);
SyncImage();
SetBar();
}
@ -505,14 +515,14 @@ void IconDes::Redo()
if(!IsCurrent())
return;
Slot& c = Current();
Vector<ImageIml> redo = UnpackImlData(c.redo);
Vector<ImageIml> redo = UnpackUndo(c.redo);
if(redo.GetCount() == 0)
return;
Vector<ImageIml> undo = UnpackImlData(c.undo);
Vector<ImageIml> undo = UnpackUndo(c.undo);
undo.Add().image = c.image;
c.image = redo.Pop().image;
c.undo = PackImlData(undo);
c.redo = PackImlData(redo);
c.undo = PackUndo(undo);
c.redo = PackUndo(redo);
SyncImage();
SetBar();
}

View file

@ -93,8 +93,8 @@ public:
struct IconShow : public Ctrl {
Image image;
bool show_small;
bool show_other;
bool show_downscaled;
bool show_synthetics;
void Paint(Draw& w);
@ -105,9 +105,10 @@ void FloodFill(ImageBuffer& img, RGBA color, Point pt, const Rect& rc, int tol
void InterpolateImage(Image& img, const Rect& _rc);
void MirrorHorz(Image& img, const Rect& rect);
void MirrorVert(Image& img, const Rect& rect);
String PackImlDataUncompressed(const Vector<ImageIml>& image);
String PackImlData(const Vector<ImageIml>& image);
Image DownSample3x(const Image& src);
Image DownSample2x(const Image& src);
Image DownSample3x(const Image& src, bool co = false);
Image DownSample2x(const Image& src, bool co = false);
/*
struct IconDraw : ImagePainter {
@ -177,12 +178,11 @@ private:
bool doselection = false;
bool selectrect = false;
int paste_mode;
bool show_other = false;
bool show_small = false;
bool show_synthetics = false;
bool show_downscaled = false;
bool show_grid2 = false;
ScrollBars sb;
Scroller scroller;
ToolBar toolbar;
SplitterFrame leftpane;

View file

@ -40,7 +40,7 @@ void IconDes::KeyMove(int dx, int dy)
else {
Image h = c.image;
c.image = CreateImage(h.GetSize(), Null);
UPP::Copy(c.image, Point(dx, dy), h, h.GetSize());
UPP::Copy(c.image, Point(dx, dy), h, h.GetSize(), true);
}
Sync();
}

View file

@ -154,7 +154,7 @@ void MirrorVert(Image& img, const Rect& rect)
img = ib;
}
String PackImlData(const Vector<ImageIml>& image)
String PackImlDataUncompressed(const Vector<ImageIml>& image)
{
StringBuffer block;
for(const ImageIml& m : image) {
@ -181,16 +181,21 @@ String PackImlData(const Vector<ImageIml>& image)
s++;
}
}
return ZCompress(block);
return block;
}
Image DownSample3x(const Image& src)
String PackImlData(const Vector<ImageIml>& image)
{
return ZCompress(PackImlDataUncompressed(image));
}
Image DownSample3x(const Image& src, bool co)
{
Size tsz = src.GetSize() / 3;
ImageBuffer ib(tsz);
int w = src.GetSize().cx;
int w2 = 2 * w;
for(int y = 0; y < tsz.cy; y++) {
CoFor(co, tsz.cy, [&](int y) {
RGBA *t = ib[y];
RGBA *e = t + tsz.cx;
const RGBA *s = src[3 * y];
@ -210,17 +215,17 @@ Image DownSample3x(const Image& src)
t++;
s += 3;
}
}
});
ib.SetResolution(src.GetResolution());
return ib;
}
Image DownSample2x(const Image& src)
Image DownSample2x(const Image& src, bool co)
{
Size tsz = src.GetSize() / 2;
ImageBuffer ib(tsz);
int w = src.GetSize().cx;
for(int y = 0; y < tsz.cy; y++) {
CoFor(co, tsz.cy, [&](int y) {
RGBA *t = ib[y];
RGBA *e = t + tsz.cx;
const RGBA *s = src[2 * y];
@ -239,7 +244,7 @@ Image DownSample2x(const Image& src)
t++;
s += 2;
}
}
});
ib.SetResolution(src.GetResolution());
return ib;
}

View file

@ -9,36 +9,69 @@ namespace Upp {
void IconShow::Paint(Draw& w)
{
Size sz = GetSize();
static Color color[] = { White(), WhiteGray(), LtGray(), Gray(), Black(),
static Color color[] = { White(), Black(), WhiteGray(), LtGray(), Gray(),
Yellow(), Brown(), Red(), Green(), Blue(), Cyan(), Magenta() };
Size msz = image.GetSize();
Size isz = msz;
if(show_small)
isz.cx += isz.cx / 2 + DPI(4);
int n = msz.cx ? minmax(sz.cx / isz.cx, 1, __countof(color)) : 1;
Image m2, m3;
if(msz.cx && show_small) {
m2 = DownSample2x(image);
m3 = DownSample3x(image);
int gap = DPI(8);
double fits = msz.cx * msz.cy < 20000;
if(fits) {
if(show_downscaled) {
isz.cx += (isz.cx + 1) / 2 + gap;
isz.cy += max(isz.cy, (isz.cy + 1) / 2 + (isz.cy + 2) / 3 + gap);
}
if(show_synthetics) {
isz.cx += 3 * isz.cx + gap;
isz.cy += 2 * isz.cy + gap;
}
}
int n = sz.cx ? clamp(sz.cx / isz.cx, 1, __countof(color)) : 1;
int ncx = sz.cx / n;
Image m2, m3;
Image dk, up2, up2dk;
if(fits) {
if(msz.cx && show_downscaled) {
m2 = DownSample2x(image);
m3 = DownSample3x(image);
}
if(show_synthetics) {
dk = DarkTheme(image);
up2 = Upscale2x(image);
up2dk = Upscale2x(DarkTheme(image));
}
}
else
isz = msz;
for(int i = 0; i < n; i++) {
int x = i * sz.cx / n;
int cx = (i + 1) * sz.cx / n - x;
int x = i * ncx;
int cx = (i + 1) * ncx - x;
w.DrawRect(x, 0, cx, sz.cy, color[i]);
if(msz.cx) {
if(show_other) {
Point c(x + cx / 2, sz.cy / 2);
w.DrawImage(c.x - DPI(8) - isz.cx, c.y - DPI(8) - isz.cy, image);
w.DrawImage(c.x + DPI(8), c.y - DPI(8) - isz.cy, DarkTheme(image));
w.DrawImage(c.x - DPI(8) - isz.cx, c.y + DPI(8), Upscale2x(image));
w.DrawImage(c.x + DPI(8), c.y + DPI(8), Upscale2x(DarkTheme(image)));
Point pos(x + (cx - isz.cx) / 2, (sz.cy - isz.cy) / 2);
if(fits) {
if(show_synthetics) {
int x2 = pos.x + 2 * msz.cx + gap;
w.DrawImage(pos.x, pos.y, image);
w.DrawImage(x2, pos.y, dk);
pos.y += msz.cy + gap;
w.DrawImage(pos.x, pos.y, up2);
w.DrawImage(x2, pos.y, up2dk);
}
else {
int y = pos.y + (isz.cy - msz.cy) / 2;
w.DrawImage(pos.x, y, image);
if(show_downscaled) {
int x2 = pos.x + msz.cx + gap;
w.DrawImage(x2, y, m2);
w.DrawImage(x2, y + (msz.cx + 1) / 2 + gap, m3);
}
}
}
else {
w.DrawImage(x + (cx - isz.cx) / 2, (sz.cy - isz.cy) / 2, image);
if(show_small) {
w.DrawImage(x + (cx - isz.cx) / 2 + msz.cx + DPI(4), (sz.cy - isz.cy) / 2, m2);
w.DrawImage(x + (cx - isz.cx) / 2 + msz.cx + DPI(4), (sz.cy - isz.cy) / 2 + 2 * msz.cy / 3, m3);
}
w.Clip(x, 0, isz.cx, sz.cy);
w.DrawImage(x + DPI(2), DPI(2), image);
w.End();
}
}
}
@ -59,7 +92,6 @@ void IconDes::Paint(Draw& w)
const Image& image = Current().image;
const Image& selection = Current().selection;
Point spos = sb;
scroller.Set(spos);
Size isz = image.GetSize();
bool pastepaint = HasCapture() && IsPasting();
magnify = max(magnify, 1);
@ -68,17 +100,17 @@ void IconDes::Paint(Draw& w)
ImageBuffer pb(isz);
RGBA c1 = GrayColor(102);
RGBA c2 = GrayColor(153);
int xn = isz.cx / 4;
int xn = isz.cx / DPI(4);
for(int y = 0; y < isz.cy; y++) {
RGBA *b = pb[y];
RGBA cc1 = c1;
RGBA cc2 = c2;
if(y & 4)
if(y & DPI(4))
Swap(cc1, cc2);
for(int q = xn; q--;) {
b[0] = b[1] = b[2] = b[3] = cc1;
Fill(b, cc1, DPI(4));
Swap(cc1, cc2);
b += 4;
b += DPI(4);
}
while(b < pb[y] + isz.cx)
*b++ = cc1;
@ -99,126 +131,115 @@ void IconDes::Paint(Draw& w)
w.DrawImage(-spos.x, -spos.y, pb);
Rect r = pb.GetSize();
r.Offset(-spos);
w.DrawRect(r.right, 0, 1, r.bottom + 1, LtRed());
w.DrawRect(0, r.bottom, r.right, 1, LtRed());
if(show_grid2) {
w.DrawRect(r.right, 0, 1, r.bottom + 1, LtRed());
w.DrawRect(0, r.bottom, r.right, 1, LtRed());
}
m1refresh = Null;
if(IsPasting())
DrawFrame(w, Rect(Current().pastepos - spos, Current().paste_image.GetSize()), LtRed);
return;
}
Point hotspot = image.GetHotSpot();
Point spot2 = image.Get2ndSpot();
int m = isz.cx * magnify + 1;
Point mpos = magnify * spos;
int grid2 = 0;
if(max(isz.cx, isz.cy) > 16 && show_grid2) {
if(isz.cx % 3 == 0 && isz.cy % 3 == 0)
grid2 = 3;
else
if(isz.cx % 4 == 0 && isz.cy % 4 == 0)
grid2 = 4;
}
auto GridColor = [&](int x, int sz) -> Color {
if(grid2) {
if(x == sz / 2)
return LtMagenta();
if(x % grid2 == 0)
return LtRed();
}
return Black();
};
for(int y = isz.cy; y >= 0; y--)
w.DrawRect(-mpos.x, magnify * y - mpos.y, m, 1, GridColor(y, isz.cy));
m = isz.cy * magnify + 1;
for(int x = isz.cx; x >= 0; x--)
w.DrawRect(magnify * x - mpos.x, -mpos.y, 1, m, GridColor(x, isz.cx));
if(!IsHotSpot()) {
hotspot = Null;
spot2 = Null;
}
w.DrawRect(isz.cx * magnify - mpos.x + 1, 0, 9999, 9999, SColorPaper());
w.DrawRect(0, isz.cy * magnify - mpos.y + 1, 9999, 9999, SColorPaper());
int my0 = -magnify * spos.y;
int magnify4 = 4 * magnify;
int md = (magnify + 1) / 2;
int mc = (magnify - 1) / 2;
Image masked = Crop(IconDesImg::Masked(), Size(magnify - 1, magnify - 1));
for(int y0 = 0; y0 < isz.cy; y0 += 4, my0 += magnify4) {
int mx0 = -magnify * spos.x;
for(int x0 = 0; x0 < isz.cx; x0 += 4, mx0 += magnify4) {
if(w.IsPainting(mx0, my0, magnify4, magnify4)) {
int ex = min(x0 + 4, isz.cx);
int my = my0;
for(int y = y0; y < min(y0 + 4, isz.cy); y++, my += magnify) {
const RGBA *s = image[y] + x0;
const RGBA *k = selection[y] + x0;
const RGBA *pk = y ? selection[y - 1] + x0 : NULL;
const RGBA *nk = y + 1 < isz.cy ? selection[y + 1] + x0 : NULL;
int mx = mx0;
for(int x = x0; x < ex; x++) {
if(s->a == 255)
w.DrawRect(mx + 1, my + 1, magnify - 1, magnify - 1, *s);
else { // paint chequered background
Color c = StraightColor(*s);
Color c1 = Blend(GrayColor(102), c, s->a);
w.DrawRect(mx + 1, my + 1, magnify - 1, magnify - 1, c1);
Color c2 = Blend(GrayColor(153), c, s->a);
w.DrawRect(mx + md, my + 1, mc, mc, c2);
w.DrawRect(mx + 1, my + md, mc, mc, c2);
}
if(!pastepaint)
if(!k->r) {
w.DrawImage(mx + 1, my + 1, masked);
if(x > 0) {
if(pk && pk[-1].r)
sDrawChRect(w, mx + 1, my + 1, 4, 4);
if(k[-1].r)
sDrawChRect(w, mx + 1, my + 1, 4, magnify - 1);
if(nk && nk[-1].r)
sDrawChRect(w, mx + 1, my + magnify - 4, 4, 4, true);
}
if(pk && pk->r)
sDrawChRect(w, mx + 1, my + 1, magnify - 1, 4);
if(nk && nk->r)
sDrawChRect(w, mx + 1, my + magnify - 4, magnify - 1, 4, true);
if(x + 1 < isz.cx) {
if(pk && pk[1].r)
sDrawChRect(w, mx + magnify - 4, my + 1, 4, 4, true);
if(k[1].r)
sDrawChRect(w, mx + magnify - 4, my + 1, 4, magnify - 1, true);
if(nk && nk[1].r)
sDrawChRect(w, mx + magnify - 4, my + magnify - 4, 4, 4);
}
}
if(spot2.x == x && spot2.y == y)
w.DrawImage(mx + 1, my + 1, Rescale(IconDesImg::HotSpotB(), magnify - 1, magnify - 1));
if(hotspot.x == x && hotspot.y == y)
w.DrawImage(mx + 1, my + 1, Rescale(IconDesImg::HotSpotA(), magnify - 1, magnify - 1));
s++;
k++;
mx += magnify;
if(pk)
pk++;
if(nk)
nk++;
}
}
Rect src = Rect((sz + magnify) / magnify).Offseted(spos) & isz;
Size ssz = src.GetSize();
ImageBuffer b(src.GetSize() * magnify);
int m2 = magnify / 2;
CoFor(src.GetHeight(), [&](int y) { // paint chequered background
RGBA *q = b[y * magnify];
int i = 0;
Color c1 = GrayColor(102);
Color c2 = GrayColor(153);
int m = m2;
for(int pass = 0; pass < 2; pass++) {
RGBA *t = q;
for(int i = 0; i < src.GetWidth(); i++) {
Fill(q, c1, magnify);
Fill(q + 1, c2, m2);
q += magnify;
}
i++;
while(i < m) {
memcpy_t(q, t, b.GetWidth());
q += b.GetWidth();
i++;
}
m = magnify;
Swap(c1, c2);
}
});
w.DrawImage(0, 0, b); // paint chequered background
w.DrawImage(0, 0, Magnify(image, src, magnify, magnify, true)); // paint actual image
if(magnify > 6) {
int grid2 = 0;
if(max(isz.cx, isz.cy) > 16 && show_grid2) {
if(isz.cx % 3 == 0 && isz.cy % 3 == 0)
grid2 = 3;
else
if(isz.cx % 4 == 0 && isz.cy % 4 == 0)
grid2 = 4;
}
auto GridColor = [&](int x, int sz) -> Color {
if(grid2) {
if(x == sz / 2)
return LtMagenta();
if(x % grid2 == 0)
return LtRed();
}
return Black();
};
int m = ssz.cx * magnify + 1;
for(int y = 0; y <= src.GetHeight(); y++)
w.DrawRect(0, magnify * y, m, 1, GridColor(y + src.top, isz.cy));
m = ssz.cy * magnify + 1;
for(int x = 0; x <= src.GetWidth(); x++)
w.DrawRect(magnify * x, 0, 1, m, GridColor(x + src.left, isz.cx));
}
if(!pastepaint && !IsNull(selection)) { // paint selection
RGBA c1 = 120 * Black();
RGBA c2 = 120 * White();
int ncx = ssz.cx * magnify;
ImageBuffer b(ncx, ssz.cy * magnify);
CoFor(ssz.cy, [&](int y) {
const RGBA *s = selection[src.top + y] + src.left;
const RGBA *e = s + ssz.cx;
RGBA *t = ~b + y * ncx * magnify;
RGBA *q = t;
while(s < e) {
Fill(q, s->r ? RGBAZero() : c1, magnify);
Fill(q + ncx, s->r ? RGBAZero() : c2, magnify);
q += magnify;
s++;
}
for(int i = 2; i < magnify; i++) {
q += ncx;
memcpy_t(q, t, ncx);
t += ncx;
}
});
w.DrawImage(0, 0, b);
}
if(IsPasting() && !pastepaint)
DrawFatFrame(w, Rect(magnify * (Current().pastepos - spos),
magnify * Current().paste_image.GetSize() + Size(1, 1)),
Color(200, 200, 255), 3);
if(magnify < 9)
return;
auto PaintHotSpot = [&](Point hotspot, Color c) { // Show hotspots even if not designing them
if(hotspot.x > 0 || hotspot.y > 0)
DrawFatFrame(w, hotspot.x * magnify, hotspot.y * magnify, magnify + 1, magnify + 1, c, 1 + magnify / 8);
};
PaintHotSpot(image.GetHotSpot(), LtRed());
PaintHotSpot(image.Get2ndSpot(), LtBlue());
if(magnify > 8 || IsHotSpot()) {
auto PaintHotSpot = [&](Point hotspot, Color c) {
if(hotspot.x > 0 || hotspot.y > 0) {
hotspot = (hotspot - spos) * magnify;
DrawFatFrame(w, hotspot.x, hotspot.y, magnify + 1, magnify + 1, c, max(DPI(1), 1 + magnify / 8));
}
};
PaintHotSpot(image.GetHotSpot(), LtRed());
PaintHotSpot(image.Get2ndSpot(), LtBlue());
}
}
}

View file

@ -133,7 +133,8 @@ mainconfig
"" = "GUI CHECKCLIPBOARD",
"" = "GUI PEAKMEM",
"" = "GUI HEAPLOG",
"" = "GUI X11";
"" = "GUI X11",
"" = "GUI DEBUGCODE";
custom() "",
"ASDFASDFASDF",