//+----------------------------------------------------------------------------+ //| Description: Magic Set Editor - Program to make Magic (tm) cards | //| Copyright: (C) 2001 - 2010 Twan van Laarhoven and Sean Hunt | //| License: GNU General Public License 2 or later (see file COPYING) | //+----------------------------------------------------------------------------+ // ----------------------------------------------------------------------------- : Includes #include #include #include // ----------------------------------------------------------------------------- : AlphaMask AlphaMask::AlphaMask() : alpha(nullptr), lefts(nullptr), rights(nullptr) {} AlphaMask::AlphaMask(const Image& img) : alpha(nullptr), lefts(nullptr), rights(nullptr) { load(img); } AlphaMask::~AlphaMask() { clear(); } void AlphaMask::clear() { delete[] alpha; alpha = nullptr; delete[] lefts; lefts = nullptr; delete[] rights; rights = nullptr; } void AlphaMask::load(const Image& img) { size_t old_n = alpha ? size.x * size.y : 0; size.x = img.GetWidth(); size.y = img.GetHeight(); // Memory size_t n = size.x * size.y; if (n != old_n) { delete[] alpha; alpha = new Byte[n]; } delete[] lefts; lefts = nullptr; delete[] rights; rights = nullptr; // Copy red chanel to alpha Byte* from = img.GetData(), *to = alpha; for (size_t i = 0 ; i < n ; ++i) { to[i] = from[3*i]; } } void AlphaMask::setAlpha(Image& img) const { if (!alpha) return; set_alpha(img, alpha, size); } void AlphaMask::setAlpha(Bitmap& bmp) const { if (!alpha) return; Image img = bmp.ConvertToImage(); setAlpha(img); bmp = Bitmap(img); } bool AlphaMask::isOpaque(int x, int y) const { if (x < 0 || y < 0 || x >= size.x || y >= size.y) return false; if (alpha) { return alpha[x + y * size.x] >= 20; } else { return true; } } bool AlphaMask::isOpaque(const RealPoint& p, const RealSize& resize) const { if (p.x < 0 || p.y < 0 || p.x >= resize.width || p.y >= resize.height) return false; if (alpha) { int x = (int)(p.x * size.x / resize.width); int y = (int)(p.y * size.y / resize.height); return alpha[x + y * size.x] >= 20; } else { return true; } } /// Do the points form a (counter??)clockwise angle? bool convex(const wxPoint& p, const wxPoint& q, const wxPoint& r) { return p.y*q.x - p.x*q.y - p.y*r.x + q.y*r.x + p.x*r.y - q.x*r.y > 0; } void make_convex(vector& points) { while (points.size() > 2 && !convex(points[points.size() - 3] ,points[points.size() - 2] ,points[points.size() - 1])) { points.erase(points.end() - 2); } } void add_convex_point(vector& points, int x, int y) { points.push_back(wxPoint(x,y)); make_convex(points); } void AlphaMask::convexHull(vector& points) const { if (!alpha) throw InternalError(_("AlphaMask::convexHull")); // Left side, top to bottom int miny = size.y, maxy = -1, lastx = 0; for (int y = 0 ; y < size.y ; ++y) { for (int x = 0 ; x < size.x ; ++x) { if (alpha[x + y * size.x] >= 20) { // opaque pixel miny = min(miny,y); maxy = y; if (y == miny) { add_convex_point(points, x-1, y-1); } add_convex_point(points, x-1, y); lastx = x; break; } } } if (maxy == -1) return; // No image add_convex_point(points, lastx-1, maxy+1); // Right side, bottom to top for (int y = maxy ; y >= miny ; --y) { for (int x = size.x - 1 ; x >= 0 ; --x) { if (alpha[x + y * size.x] >= 20) { // opaque pixel if (y == maxy) { add_convex_point(points, x+1, y+1); } add_convex_point(points, x+1, y); lastx = x; break; } } } add_convex_point(points, lastx+1, miny-1); } Image AlphaMask::colorImage(const Color& color) const { Image image(size.x, size.y); fill_image(image, color); setAlpha(image); return image; } // ----------------------------------------------------------------------------- : Contour Mask void AlphaMask::loadRowSizes() const { if (lefts || !alpha) return; lefts = new int[size.y]; rights = new int[size.y]; // for each row: determine left and rightmost white pixel for (int y = 0 ; y < size.y ; ++y) { lefts[y] = size.x; rights[y] = 0; for (int x = 0 ; x < size.x ; ++x) { if (alpha[y * size.x + x] >= 128) { // white enough rights[y] = x; if (x < lefts[y]) lefts[y] = x; } } } } double AlphaMask::rowLeft (double y, const RealSize& resize) const { loadRowSizes(); if (!lefts || y < 0 || y >= resize.height) { // no mask, or outside it return 0; } return lefts[(int)(y * size.y / resize.height)] * resize.width / size.x; } double AlphaMask::rowRight(double y, const RealSize& resize) const { loadRowSizes(); if (!rights || y < 0 || y >= resize.height) { // no mask, or outside it return resize.width; } return rights[(int)(y * size.y / resize.height)] * resize.width / size.x; }