diff options
author | chai <chaifix@163.com> | 2019-08-14 22:50:43 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2019-08-14 22:50:43 +0800 |
commit | 15740faf9fe9fe4be08965098bbf2947e096aeeb (patch) | |
tree | a730ec236656cc8cab5b13f088adfaed6bb218fb /Runtime/Geometry/SpriteMeshGenerator.h |
Diffstat (limited to 'Runtime/Geometry/SpriteMeshGenerator.h')
-rw-r--r-- | Runtime/Geometry/SpriteMeshGenerator.h | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/Runtime/Geometry/SpriteMeshGenerator.h b/Runtime/Geometry/SpriteMeshGenerator.h new file mode 100644 index 0000000..927b629 --- /dev/null +++ b/Runtime/Geometry/SpriteMeshGenerator.h @@ -0,0 +1,269 @@ +#pragma once +#include "Configuration/UnityConfigure.h" + +#if ENABLE_SPRITES + +#include "Runtime/BaseClasses/NamedObject.h" +#include "Runtime/Math/Rect.h" +#include "Runtime/Serialize/TransferFunctions/SerializeTransfer.h" +#include "Runtime/Shaders/Material.h" +#include "Runtime/Graphics/Texture2D.h" +#include "Runtime/Utilities/dynamic_bitset.h" + + +class SpriteMeshGenerator +{ +public: + struct s_cost + { + s_cost(){}; + s_cost(float _c, float _w) + { + c=_c; + w=_w; + }; + float c; + float w; + }; + + struct vertex + { + vertex(){}; + vertex(Vector2f pos) + { + p = pos; + }; + Vector2f p; + Vector2f n; // normal + int s; // sign -> indicating concavity + float c; + struct s_cost cost; + }; + + class path_segment + { + public: + path_segment(std::vector<vertex> path, int i0, int i1) + { + m_i0 = i0; + m_i1 = i1; + m_mx = max_distance(path, i0, i1); + }; + + int m_i0; + int m_i1; + int m_mx; + int m_cnt; + private: + int max_distance(std::vector<vertex> path, int i0, int i1); + }; + + class compare_path_segment { + public: + bool operator()(path_segment& s0, path_segment& s1) + { + return (s0.m_cnt < s1.m_cnt); + } + }; + + class path + { + public: + path(){}; + path(const std::vector<vertex>& p, int w, int h, int sign, float area, float bias) + { + m_bx = w; + m_by = h; + m_area = area; + m_sign = sign; + m_path = p; + opt (bias); + bbox(); + m_path0 = m_path; + } + + std::vector<vertex> m_path; + + void bbox (); + void simplify (float q, int mode); + + bool isHole() const { return m_sign == '-'; } + + const Vector2f& GetMin() const { return m_min; } + const Vector2f& GetMax() const { return m_max; } + + private: + int find_max_distance(int i0); + + void fit (std::vector<int>& ci, int i0, int i1); + bool opt (float bias); + + bool dec (int i); + bool inf (int i); + bool select(); + bool cvx_cost(int i); + bool cve_cost(int i); + int min_cost(); + int self_intersect(Vector2f p0, Vector2f p1); + + void clip(); + void clip_edge(int e); + bool clip_test(Vector2f p, int side); + Vector2f clip_isec(Vector2f p, Vector2f q, int e); + + int m_bx; + int m_by; + int m_sign; + float m_area; + Vector2f m_min; + Vector2f m_max; + std::vector<vertex> m_path0; + std::vector<int> m_invalid; + }; + + struct mask + { + mask(){}; + mask(ColorRGBA32 *img, int width, int height, unsigned char acut, unsigned int dn) + { + w = width; + h = height; + int n = w*h; + dynamic_bitset bv; + bv.resize(n); + for (int y=0; y<height; y++) + for (int x=0; x<width; x++) { + if (img[x+y*width].a > acut) + bv.set(x+y*w); + } + + if (dn) + this->dilate(dn, bv); + + w+=1; + h+=1; + m_bv.resize(w*h); + for (int y=0; y<height; y++) + for (int x=0; x<width; x++) { + if (bv.test(x+y*width)) { + m_bv.set((x+0)+(y+0)*w); + m_bv.set((x+1)+(y+1)*w); + m_bv.set((x+0)+(y+1)*w); + m_bv.set((x+1)+(y+0)*w); + } + } + } + + bool tst(int x, int y) + { + if ((x<0) || (x>=w) || + (y<0) || (y>=h) ) + return 0; + int i=x+y*w; + return m_bv.test(i); + } + + void set(int x, int y) + { + if ((x<0) || (x>=w) || + (y<0) || (y>=h) ) + return; + int i=x+y*w; + m_bv.set(i); + } + + void rst(int x, int y) + { + if ((x<0) || (x>=w) || + (y<0) || (y>=h) ) + return; + int i=x+y*w; + m_bv[i]=0; + } + + void inv(int x, int y) + { + if ((x<0) || (x>=w) || + (y<0) || (y>=h) ) + return; + int i=x+y*w; + m_bv[i].flip(); + } + + int first() + { + int n=(int)m_bv.size(); + for (int i=0; i<n; i++) + if (m_bv.test(i)) + return i; + return -1; + } + + bool dilate(int n, dynamic_bitset &bv) + { + if ((w==0) || (h==0)) + return false; + UInt32 *md = new UInt32[w*h]; + if (!mdist(md, bv)) + return false; + + for (int i=0; i<w*h; i++) { + if (md[i] <= n) + bv.set(i); + } + delete md; + return true; + } + int w; + int h; + dynamic_bitset m_bv; + private: + bool mdist(UInt32 *md, dynamic_bitset& bv ) + { + if (!md) + return false; + + for (int y=0; y<h; y++) + for (int x=0; x<w; x++) { + int i = x+y*w; + if (bv.test(i)) + md[i] = 0; + else { + md[i] = w+h; + if (y>0) md[i] = min(md[i], md[i-w]+1); + if (x>0) md[i] = min(md[i], md[i-1]+1); + } + } + + for (int y=h-1; y>=0; y--) + for (int x=w-1; x>=0; x--) { + int i = x+y*w; + if ((y+1) < h) md[i] = min(md[i], md[i+w]+1); + if ((x+1) < w) md[i] = min(md[i], md[i+1]+1); + } + return true; + } + }; + +public: + void Decompose(std::vector<Vector2f>* vertices, std::vector<int>* indices); + void MakeShape(ColorRGBA32* image, int imageWidth, int imageHeight, float hullTolerance, unsigned char alphaTolerance, bool holeDetection, unsigned int extrude, float bias, int mode); + bool FindBounds(Rectf& bounds); + + const std::vector<path>& GetPaths() const { return m_paths; } + + +private: + bool trace(Vector2f p0, Vector2f p1, Vector2f &p); + bool invmask(std::vector<vertex>& outline); + bool contour(std::vector<vertex>& outline, int &sign, float &area); + + std::vector<path> m_paths; + + float evaluateLOD(const float areaHint, float area); + + struct mask m_mask_org; + struct mask m_mask_cur; +}; + +#endif //ENABLE_SPRITES |