├── .gitignore ├── LICENSE ├── README.md ├── exposition.md └── src ├── GL ├── eglew.h ├── glew.h ├── glxew.h └── wglew.h ├── camera.cpp ├── camera.h ├── common ├── color.cpp ├── color.h ├── common.cpp ├── common.h ├── entity.h ├── vector.h └── vector3.h ├── complex ├── canvas.cpp ├── complex.cpp ├── complex.h ├── config.cpp ├── contour.cpp ├── contour.h ├── edge.cpp ├── edge.h ├── equations.cpp ├── flip.cpp ├── flip.h ├── iterator.cpp ├── iterator.h ├── moveconcur.cpp ├── moveconsec.cpp ├── node.cpp ├── node.h ├── trigon.cpp └── trigon.h ├── config.h ├── config.json ├── femton.pro ├── glew.c ├── globals.cpp ├── globals.h ├── graphics ├── draw.cpp ├── graphics.cpp ├── graphics.h ├── shader.cpp ├── shader.h └── shaders │ ├── composition │ ├── fragment.glsl │ └── vertex.glsl │ ├── controlnet │ ├── fragment.glsl │ ├── geometry.glsl │ ├── tesscontrol.glsl │ ├── tesseval.glsl │ └── vertex.glsl │ ├── edges │ ├── fragment.glsl │ ├── geometry.glsl │ ├── tesscontrol.glsl │ ├── tesseval.glsl │ └── vertex.glsl │ ├── gaussian │ ├── fragment.glsl │ └── vertex.glsl │ ├── normals │ ├── fragment.glsl │ └── vertex.glsl │ ├── painting │ ├── fragment.glsl │ └── vertex.glsl │ ├── pickable │ ├── fragment.glsl │ └── vertex.glsl │ ├── points │ ├── fragment.glsl │ └── vertex.glsl │ ├── surface │ ├── fragment.glsl │ ├── geometry.glsl │ ├── tesscontrol.glsl │ ├── tesseval.glsl │ └── vertex.glsl │ └── wireframe │ └── fragment.glsl ├── info.cpp ├── info.h ├── init.cpp ├── init.h ├── input.cpp ├── json ├── json-forwards.h └── json.h ├── jsoncpp.cpp ├── main.cpp ├── mainwindow.h ├── mpir.dll ├── mpir.lib ├── mpir ├── mpir.h └── mpirxx.h ├── opengl32.lib ├── state.cpp ├── state.h ├── tool ├── tools.cpp └── tools.h ├── util.cpp ├── util.h ├── window.cpp └── window.h /.gitignore: -------------------------------------------------------------------------------- 1 | src/.qtc_clangd/ 2 | src/Users* 3 | 4 | *.o 5 | 6 | # Generated MOC, resource and UI files 7 | moc_*.cpp 8 | moc_*.h 9 | qrc_*.cpp 10 | ui_*.h 11 | 12 | Makefile 13 | femton 14 | femton.pro.user 15 | .qmake.stash 16 | 17 | *.fem 18 | /_tidigare 19 | *.autosave 20 | 21 | src/debug 22 | src/release 23 | src/out 24 | 25 | Makefile.Debug 26 | Makefile.Release 27 | 28 | *.png 29 | 30 | *.qua 31 | 32 | femton.pro.user.4.8-pre1 33 | 34 | ffmpeg.exe 35 | ffmpeg.bat -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Max Pihlström 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/camera.cpp: -------------------------------------------------------------------------------- 1 | #include "camera.h" 2 | #include "common/common.h" 3 | #include "complex/complex.h" 4 | #include "globals.h" 5 | 6 | Camera::Camera(Vec2 pos) : pos(pos), zrotzoom(Vec2(1,0)) {} 7 | Camera::Camera() { 8 | reset(); 9 | } 10 | 11 | void Camera::reset() { 12 | zrotzoom = Vec2(1,0); 13 | pos = Vec2(); 14 | } 15 | 16 | double Camera::rotz() const { 17 | return deg(atan2(zrotzoom.y, zrotzoom.x)); 18 | } 19 | 20 | Vec2 Camera::uni_can_v(Vec2 v) { 21 | return v.scalerotate_inv(zrotzoom) * com->Units; 22 | } 23 | 24 | Vec2 Camera::scr_can_v(Vec2 v) { 25 | return uni_can_v(scr_uni_v(v)); 26 | } 27 | 28 | Vec2 Camera::scr_uni_v(Vec2 v) { 29 | return Vec2((v.x / (double)scr_sz.w), -(v.y / (double)scr_sz.h)) * 2.0; 30 | } 31 | 32 | Vec2 Camera::scr_uni_p(Vec2 p) { 33 | return Vec2(p.x/(double)scr_sz.w - 0.5, (1.0 - p.y/(double)scr_sz.h) - 0.5) * 2.0; 34 | } 35 | 36 | Vec2 Camera::uni_scr(Vec2 p) { 37 | return Vec2((1.0 + p.x)*0.5 * (double)scr_sz.w, (1.0 - p.y)*0.5 * (double)scr_sz.h); 38 | } 39 | 40 | Vec2 Camera::scr_can_p(Vec2 p) { 41 | return scr_uni_p(p).scalerotate_inv(zrotzoom) * com->Units - pos; 42 | } 43 | 44 | Vec2 Camera::can_scr_p(Vec2 p) { 45 | return uni_scr(((p + pos) / com->Units).scalerotate(zrotzoom)); 46 | } 47 | 48 | double Camera::uni_can_s(double s) { return s*com->Units/zoom(); } 49 | 50 | 51 | void Cameratool::left_up(Vec2 p) { 52 | mouse = o_mouse = p; 53 | o_zrotz = view->zrotzoom; 54 | draw->update(); 55 | } 56 | 57 | void Cameratool::left_down(Vec2 p) { 58 | mouse = o_mouse = p; 59 | o_zrotz = view->zrotzoom; 60 | myDebug() << "coordinates:" << view->scr_can_p(cursor).x << view->scr_can_p(cursor).y; 61 | draw->update(); 62 | } 63 | 64 | void Cameratool::right_down(Vec2 p) { 65 | mouse = o_mouse = p; 66 | o_zrotz = view->zrotzoom; 67 | draw->update(); 68 | } 69 | 70 | void Cameratool::right_up(Vec2) { 71 | draw->update(); 72 | } 73 | 74 | void Cameratool::motion(Vec2 rel) { 75 | if (left && right) 76 | view->zrotzoom = o_zrotz * view->scr_uni_p(cursor).length()/view->scr_uni_p(o_mouse).length(); 77 | else if(right) 78 | view->zrotzoom = Vec2(o_zrotz).scalerotate(view->scr_uni_p(cursor).scalerotate_inv(view->scr_uni_p(o_mouse))); 79 | else if(left) 80 | view->pos += view->scr_can_v(rel); 81 | if(view->zrotzoom.length() < 0.01) view->zrotzoom = view->zrotzoom.unit() * 0.01; 82 | draw->update(); 83 | } 84 | 85 | void Cameratool::wheel_rot(double delta) { 86 | auto o = view->scr_can_p(cursor); 87 | view->zrotzoom *= pow(1.001, -delta); 88 | view->pos += view->scr_can_p(cursor) - o; 89 | draw->update(); 90 | } 91 | -------------------------------------------------------------------------------- /src/camera.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "common/vector.h" 3 | #include "common/vector3.h" 4 | #include "common/common.h" 5 | 6 | struct Angle { 7 | Angle() : angle_(0.) {} 8 | Angle(Angle const& a) : angle_(a()) {} 9 | Angle(double angle) : angle_(angle) {} 10 | 11 | static double rad_deg(double r) { 12 | return ((r / (2*M_PI)) * 360.0); 13 | } 14 | 15 | static double deg_rad(double d) { 16 | return ((d / 360.0) * (2*M_PI)); 17 | } 18 | 19 | static double fmod360(double angle) { 20 | if(angle > 360.) angle -= 360.*((int)angle % 360); 21 | else if(angle < 0.) angle += 360.*((int)-angle % 360 + 1); 22 | return angle; 23 | } 24 | 25 | Angle const& operator=(double angle) { 26 | angle_ = fmod360(angle); 27 | return *this; 28 | } 29 | 30 | Angle const& operator+=(double angle) { 31 | angle_ = fmod360(angle_ + angle); 32 | return *this; 33 | } 34 | 35 | Angle const& operator-=(double angle) { return operator+=(-angle); } 36 | 37 | double operator()() const { return angle_; } 38 | 39 | private: 40 | double angle_; 41 | }; 42 | 43 | struct Camera { 44 | Camera(Vec2 p); 45 | Camera(); 46 | void reset(); 47 | double uni_can_s(double s); 48 | Vec2 uni_scr(Vec2 p); 49 | Vec2 uni_can_v(Vec2 v); 50 | Vec2 scr_uni_v(Vec2 v); 51 | Vec2 scr_can_v(Vec2 v); 52 | Vec2 scr_uni_p(Vec2 p); 53 | Vec2 scr_can_p(Vec2 p); 54 | 55 | Vec2 can_scr_p(Vec2 p); 56 | 57 | double zoom() const { return zrotzoom.length(); } 58 | double rotz() const; 59 | 60 | Vec2 zrotzoom; 61 | Vec2 pos; 62 | }; 63 | 64 | 65 | -------------------------------------------------------------------------------- /src/common/color.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "common/color.h" 3 | #include "util.h" 4 | 5 | const Col Col::Red(1,0,0), Col::Yellow(1,1,0), Col::Green(0,1,0), Col::Cyan(0,1,1), Col::Blue(0,0,1), Col::Magenta(1,0,1), Col::White(1,1,1), Col::Black(0,0,0); 6 | const Col Col::Orange(1,0.5,0); 7 | const Col Col::Gray(0.5,0.5,0.5); 8 | 9 | Col::Col(Uint32 c) { 10 | r = (double)GET_R(c)/255.0; 11 | g = (double)GET_G(c)/255.0; 12 | b = (double)GET_B(c)/255.0; 13 | a = (double)GET_A(c)/255.0; 14 | } 15 | 16 | Uint32 Col::to32() const { 17 | return PUT_RGBA(r*255.0, g*255.0, b*255.0, a*255.0); 18 | } 19 | 20 | double Col::i() const { 21 | return intensity(); 22 | } 23 | double Col::intensity() const { 24 | return 0.21267*r + 0.71516*g + 0.07217*b; 25 | } 26 | 27 | void Col::delta(double d) { 28 | r = r + d; 29 | g = g + d; 30 | b = b + d; 31 | // clamp(); 32 | } 33 | 34 | 35 | 36 | double Col::dist() const { 37 | return sqrt(0.21267*0.21267*r*r + 0.71516*0.71516*g*g + 0.07217*0.07217*b*b); 38 | } 39 | 40 | bool Col::operator==(Col const& b) const { 41 | return dist(b) < 0.0001; 42 | } 43 | 44 | double Col::dist(Col const& s) const { 45 | //return sqrt(0.21267*0.21267*(s.r-r)*(s.r-r) + 0.71516*0.71516*(s.g-g)*(s.g-g) + 0.07217*0.07217*(s.b-b)*(s.b-b) + (s.a-a)*(s.a-a)); 46 | return sqrt(((s.r*s.a-r*a)*(s.r*s.a-r*a) + (s.g*s.a-g*a)*(s.g*s.a-g*a) + (s.b*s.a-b*a)*(s.b*s.a-b*a))/3.0); 47 | 48 | } 49 | 50 | Col Col::h120() const { 51 | return Col(b, r, g, a); 52 | } 53 | 54 | Col Col::inv() const { 55 | return Col(1.0 - r, 1.0 - g, 1.0 - b, a); 56 | } 57 | 58 | Col Col::semi() const { 59 | return Col((double)(Uint8)(128.0 + 255.0*r)/255.0, (double)(Uint8)(128.0 + 255.0*g)/255.0, (double)(Uint8)(128.0 + 255.0*b)/255.0, a); 60 | } 61 | 62 | Col Col::random() { 63 | return Col(rand_uni(), rand_uni(), rand_uni(), 1.0); 64 | } 65 | 66 | Col Col::random_a() { 67 | return Col(rand_uni(), rand_uni(), rand_uni(), rand_uni()); 68 | } 69 | 70 | Col Col::mod() { 71 | r = fmod(r, 1.0); 72 | g = fmod(g, 1.0); 73 | b = fmod(b, 1.0); 74 | return *this; 75 | } 76 | 77 | void Col::clamp() { 78 | if(r > 1.0) r = 1.0; 79 | else if(r < 0.0) r = 0.0; 80 | if(g > 1.0) g = 1.0; 81 | else if(g < 0.0) g = 0.0; 82 | if(b > 1.0) b = 1.0; 83 | else if(b < 0.0) b = 0.0; 84 | if(a > 1.0) a = 1.0; 85 | else if(a < 0.0) a = 0.0; 86 | } 87 | 88 | Col& Col::alpha_over(Col const& s) { 89 | //alpha compositing 90 | double oa = 1.0 - (1.0 - s.a)*(1.0 - a); 91 | double q = s.a/oa; 92 | double cq = 1.0 - s.a/oa; 93 | r = s.r*q + r*cq; 94 | g = s.g*q + g*cq; 95 | b = s.b*q + b*cq; 96 | a = oa; 97 | return *this; 98 | } 99 | 100 | Col& Col::blend(Col const& s, double q) { 101 | double cq = 1.0 - q; 102 | r = s.r*q + r*cq; 103 | g = s.g*q + g*cq; 104 | b = s.b*q + b*cq; 105 | a = s.a*q + a*cq; 106 | return *this; 107 | } 108 | 109 | std::ostream& operator<<(std::ostream &out, Col &c) { 110 | out << "(" << c.r << ", " << c.g << ", " << c.b << ")"; 111 | return out; 112 | } 113 | 114 | 115 | Col::Col(double i) : Vec3(i, i, i), a(1.0) { 116 | clamp(); 117 | } 118 | 119 | 120 | 121 | /* 122 | void Color::operator/=(double s) { 123 | *this = *this / s; 124 | } 125 | 126 | void Color::operator*=(double s) { 127 | *this = *this * s; 128 | } 129 | */ 130 | 131 | /* 132 | double Color::dist(Color const& f, Color const& s) { 133 | return (s.r-f.r)*(s.r-f.r) + (s.g-f.g)*(s.g-f.g) + (s.b-f.b)*(s.b-f.b) + (s.a-f.a)*(s.a-f.a); 134 | }*/ 135 | 136 | /* 137 | Color Color::operator*(double q) const { 138 | return Color(r*q, g*q, b*q, a*q); 139 | } 140 | 141 | Color Color::operator/(double d) const { 142 | return Color(r/d, g/d, b/d, a/d); 143 | } 144 | 145 | Color Color::operator-(Color const& s) const { 146 | return Color(r - s.r, g - s.g, b - s.b, a - s.a); 147 | } 148 | 149 | Color Color::operator+(Color const& s) const { 150 | return Color(r + s.r, g + s.g, b + s.b, a + s.a); 151 | } 152 | 153 | Color Color::operator-(int c) const { 154 | return Color(r - c, g - c, b - c, a - c); 155 | } 156 | 157 | Color Color::operator+(int c) const { 158 | return Color(r + c, g + c, b + c, a + c); 159 | } 160 | */ 161 | -------------------------------------------------------------------------------- /src/common/color.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common/common.h" 4 | #include "vector3.h" 5 | 6 | #include 7 | 8 | struct Col : Vec3 { 9 | 10 | static const Col Red, Yellow, Green, Cyan, Blue, Magenta, Black, White, Orange, Gray; 11 | 12 | Col() : a(1.0) {} 13 | Col(Vec3 const& v) : Vec3(v), a(1.0) {} 14 | Col(double r, double g, double b, double a) : Vec3(r, g, b), a(a) {} 15 | Col(double r, double g, double b) : Vec3(r, g, b), a(1.0) {} 16 | Col(double i); 17 | Col(Uint32 c); 18 | 19 | Col const& operator=(Col const& s) { 20 | r = s.r; g = s.g; b = s.b; a = s.a; 21 | return *this; 22 | } 23 | 24 | Col h120() const; 25 | Col inv() const; 26 | Col semi() const; 27 | Col mono() const; 28 | double dist(Col const& b) const; 29 | Uint32 to32() const; 30 | double intensity() const; 31 | double i() const; 32 | double dist() const; 33 | 34 | Col& blend(Col const& s, double q); 35 | Col& alpha_over(Col const& s) ; 36 | void setalpha(double a); 37 | 38 | void delta(double d); 39 | 40 | void clamp(); 41 | Col mod(); 42 | 43 | bool operator==(Col const& b) const; 44 | friend std::ostream& operator<<(std::ostream &out, Col &c); 45 | 46 | static void blend(Col &t, Col &s, double w, double f = 1.0); 47 | static double dist(Col const& f, Col const& s); 48 | static Col random(); 49 | static Col random_a(); 50 | 51 | double a; 52 | }; 53 | 54 | -------------------------------------------------------------------------------- /src/common/common.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | //the counter is used for keeping track of the random seed. 4 | int r_count = 0; 5 | int rand_count() 6 | { 7 | ++r_count; 8 | return rand(); 9 | } 10 | 11 | //pseudo-normal distribution 12 | double rand_binom(int n) 13 | { 14 | double acc = 0.0; 15 | for(auto i = 0; i < n*2; ++i) { 16 | acc += rand_uni(); 17 | } 18 | return acc - (double)n; 19 | } 20 | -------------------------------------------------------------------------------- /src/common/common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common/vector.h" 4 | #include 5 | 6 | struct Complex; 7 | struct Camera; 8 | struct Tool; 9 | struct iPointer; 10 | struct Col; 11 | 12 | #define Uint32 uint32_t 13 | #define Sint64 int64_t 14 | #define Uint8 uint8_t 15 | 16 | double rand_binom(int n = 10); 17 | int rand_count(); 18 | #define rand_uni() (((double) rand_count() / (RAND_MAX))) 19 | #define rand_int() (rand_count()) 20 | #define rand_pn1() (rand_uni()*2.0 - 1.0) 21 | 22 | #ifndef M_PI 23 | #define M_PI (3.14159265359) 24 | #endif 25 | 26 | 27 | #define rad(a) (2.*M_PI * (double)(a) / 360.0) 28 | #define deg(a) (360. * (double)(a) / (2.*M_PI)) 29 | 30 | #define my_max(x, y) (((x) > (y)) ? (x) : (y)) 31 | #define my_min(x, y) (((x) < (y)) ? (x) : (y)) 32 | 33 | template int sgn(T val) { 34 | return (T(0) < val) - (val < T(0)); 35 | } 36 | 37 | #define eqv (((x) && (y)) || (^(x) && ^(y))) 38 | 39 | struct NoDebug { 40 | NoDebug const& operator<<(int const&) const { return *this; } 41 | NoDebug const& operator<<(int64_t const&) const { return *this; } 42 | NoDebug const& operator<<(unsigned long long const&) const { return *this; } 43 | NoDebug const& operator<<(double const&) const { return *this; } 44 | NoDebug const& operator<<(std::string const&) const { return *this; } 45 | }; 46 | 47 | #define MY_DEBUG 48 | #ifdef MY_DEBUG 49 | #define myDebug qDebug 50 | #else 51 | #define myDebug NoDebug 52 | #endif 53 | 54 | #define myDebugS debug_strstr 55 | 56 | //#define _HAS_ITERATOR_DEBUGGING 0 57 | 58 | //#define _ITERATOR_DEBUG_LEVEL 0 59 | -------------------------------------------------------------------------------- /src/common/entity.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | extern unsigned int gid; 4 | 5 | struct Entity { 6 | Entity() : id(++gid) {} 7 | protected: 8 | Entity(uint32_t id) : id(id) {} 9 | public: 10 | mutable uint32_t id; 11 | }; 12 | 13 | struct Class : Entity { 14 | enum Name { 15 | Class_void = 0x00, 16 | Class_trigon = 0x01, 17 | Class_node = 0x02, 18 | }; 19 | Class() : name_(Class_void) {} 20 | virtual Name name() const = 0; 21 | protected: 22 | Class(uint32_t id) : Entity(id) {} 23 | private: 24 | Name name_; 25 | }; 26 | 27 | struct Void : Class { 28 | Void() : Class(0) {} 29 | virtual Name name() const { return Class_void; } 30 | }; 31 | 32 | struct Eumetry { 33 | virtual ~Eumetry() {} 34 | virtual bool invalid() const = 0; 35 | }; 36 | -------------------------------------------------------------------------------- /src/common/vector.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | template struct Vector3; 6 | 7 | template struct Vector2 { 8 | 9 | Vector2() : x(0), y(0) {} 10 | Vector2(S s) : x(s), y(s) {} 11 | Vector2(S x, S y) : x(x), y(y) {} 12 | Vector2(Vector3 const& v) : x(v.x), y(v.y) {} 13 | Vector2(Vector2 const& b) : x((S)b.x), y((S)b.y) {} 14 | Vector2(Vector2 const& b) : x((S)b.x), y((S)b.y) {} 15 | Vector2(Vector2 const& b) : x((S)b.x), y((S)b.y) {} 16 | 17 | Vector2 operator*(Vector2 const& b) const { return Vector2(x*b.x, y*b.y); } 18 | Vector2 operator/(Vector2 const& b) const { return Vector2(x/b.x, y/b.y); } 19 | Vector2 operator+(Vector2 const& b) const { return Vector2(x + b.x, y + b.y); } 20 | Vector2 operator-(Vector2 const& b) const { return Vector2(x - b.x, y - b.y); } 21 | S mx() const { return x >= y ? x : y; } 22 | S mn() const { return x <= y ? x : y; } 23 | 24 | //determinant, used for calculations of oriented area 25 | S operator^(Vector2 const& b) const { return x*b.y - y*b.x; } 26 | 27 | Vector2 operator*(S s) const { return Vector2(x*s, y*s); } 28 | Vector2 operator/(S s) const { return Vector2(x/s, y/s); } 29 | S operator&(Vector2 const& b) const { return x*b.x + y*b.y; } 30 | 31 | Vector2 unit() const { return *this / length(); } 32 | Vector2 unit0() const { auto l = length(); return l <= 0? Vector2() : *this / l; } 33 | 34 | Vector2 round() const { return Vector2(::round(x), ::round(y)); } 35 | 36 | bool operator!=(Vector2 const& b) const { return x != b.x || y != b.y; } 37 | bool operator==(Vector2 const& b) const { return x == b.x && y == b.y; } 38 | bool operator!=(double const& b) const { return x != b || y != b; } 39 | bool operator==(double const& b) const { return x == b && y == b; } 40 | bool is_zero() const { return x == 0 && y == 0; } 41 | 42 | S dot() const { return x*x + y*y; } 43 | S hypot() const { return sqrt(this->dot()); } 44 | S l2() const { return sqrt(this->dot()); } 45 | S dot(Vector2 const& b) const { return x*b.x + y*b.y; } 46 | S length() const { return (S)sqrt((double)(x*x + y*y)); } 47 | 48 | Vector2 const& operator=(Vector2 const& b) { x = b.x; y = b.y; return *this; } 49 | void operator+=(Vector2 const& b) { x += b.x; y += b.y; } 50 | void operator-=(Vector2 const& b) { x -= b.x; y -= b.y; } 51 | void operator*=(Vector2 const& b) { x *= b.x; y *= b.y; } 52 | void operator/=(Vector2 const& b) { x /= b.x; y /= b.y; } 53 | void operator*=(S s) { x *= s; y *= s; } 54 | void operator/=(S s) { x /= s; y /= s; } 55 | 56 | static S area(Vector2 const& a, Vector2 const& b, Vector2 const& c); 57 | static Vector2 solve2x2_col(Vector2 const& c1, Vector2 const& c2, Vector2 const& c3); 58 | 59 | Vector2& norm(); 60 | Vector2& rotate90(); 61 | Vector2& rot90(); 62 | //Vector const& rotate90_inv(); 63 | Vector2 const& scalerotate(Vector2 const& m); 64 | Vector2 const& scalerotate_inv(Vector2 const& m); 65 | 66 | union {S x; S u; S a; S w;}; 67 | union {S y; S v; S b; S h;}; 68 | }; 69 | 70 | typedef Vector2 Vec2i; 71 | typedef Vector2 Size; 72 | typedef Vector2 Vec2; 73 | 74 | template struct RectS { 75 | RectS() : x(0), y(0), w(0), h(0) {} 76 | RectS(S const& x, S const& y, S const& w, S const& h) : x(x), y(y), w(w), h(h) {} 77 | RectS(S const& w, S const& h) : x(0), y(0), w(w), h(h) {} 78 | RectS(Vector2 const& b) : x(0), y(0), w(b.x), h(b.y) {} 79 | bool contains(Vector2 const& p) const; 80 | S x,y,w,h; 81 | }; 82 | 83 | typedef RectS Rect; 84 | //typedef Rect Rectd; 85 | 86 | /* Definitions */ 87 | template Vector2 & Vector2::rotate90() { 88 | S tx = x; 89 | x = -y; 90 | y = tx; 91 | return *this; 92 | } 93 | 94 | template Vector2 & Vector2::rot90() { 95 | return rotate90(); 96 | } 97 | 98 | /* 99 | template Vector const& Vector::rotate90_inv() { 100 | S tx = x; 101 | x = y; 102 | y = -tx; 103 | return *this; 104 | } 105 | */ 106 | 107 | /* 108 | template Vector2 const& Vector2::scalerotate(Vector2 const& m) { 109 | S px = x; 110 | x = (S)((double) x*m.x - (double)y*m.y); 111 | y = (S)((double)px*m.y + (double)y*m.x); 112 | return *this; 113 | } 114 | */ 115 | 116 | template Vector2 const& Vector2::scalerotate(Vector2 const& m) { 117 | S px = x; 118 | x = (S)((double) x*m.x - (double)y*m.y); 119 | y = (S)((double)px*m.y + (double)y*m.x); 120 | return *this; 121 | } 122 | 123 | template Vector2 const& Vector2::scalerotate_inv(Vector2 const& m) { 124 | Vec2 fm(m); 125 | fm /= fm.dot(); 126 | S px = x; 127 | x = (S)((double)x*fm.x + (double)y*fm.y); 128 | y = (S)((double)-px*fm.y + (double)y*fm.x); 129 | return *this; 130 | } 131 | 132 | template Vector2 & Vector2::norm() { 133 | if(x == 0 && y == 0) return *this; 134 | double d = length(); 135 | x /= d; 136 | y /= d; 137 | return *this; 138 | } 139 | 140 | template bool RectS::contains(Vector2 const& p) const { 141 | return p.x >= x && p.x < w && p.y >= y && p.y < h; 142 | } 143 | 144 | template Vector2 Vector2::solve2x2_col(Vector2 const& a, Vector2 const& b, Vector2 const& c) { 145 | //return Vector2(c3^c1,c2^c3)/(c1^c2); 146 | return Vector2(c^b,a^c)/(a^b); 147 | 148 | } 149 | 150 | template S Vector2::area(Vector2 const& a, Vector2 const& b, Vector2 const& c) { 151 | return(b - a)^(c - a); 152 | } 153 | -------------------------------------------------------------------------------- /src/common/vector3.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "vector.h" 5 | 6 | template struct Vector3 { 7 | 8 | Vector3() : x(0), y(0), z(0) {} 9 | Vector3(S s) : x(s), y(s), z(s) {} 10 | Vector3(S x, S y, S z) : x(x), y(y), z(z) {} 11 | Vector3(const Vector2& b, S c) : x(b.x), y(b.y), z(c) {} 12 | Vector3(const Vector3& b) : x((S)b.x), y((S)b.y), z((S)b.z) {} 13 | Vector3(const Vector3& b) : x((S)b.x), y((S)b.y), z((S)b.z) {} 14 | Vector3(const Vector3& b) : x((S)b.x), y((S)b.y), z((S)b.z) {} 15 | Vector3& operator=(Vector3 const& b) { x = b.x; y = b.y; z = b.z; return *this; } 16 | 17 | Vector3 operator*(Vector3 const& b) const { return Vector3(x*b.x, y*b.y, z*b.z); } 18 | Vector3 operator/(Vector3 const& b) const { return Vector3(x/b.x, y/b.y, z/b.z); } 19 | Vector3 operator+(Vector3 const& b) const { return Vector3(x + b.x, y + b.y, z + b.z); } 20 | Vector3 operator-(Vector3 const& b) const { return Vector3(x - b.x, y - b.y, z - b.z); } 21 | Vector3 operator+(S const& s) const { return Vector3(x + s, y + s, z + s); } 22 | Vector3 operator-(S const& s) const { return Vector3(x - s, y - s, z - s); } 23 | S operator&(Vector3 const& b) const { return x*b.x + y*b.y + z*b.z; } 24 | Vector3 unit() const { return *this / length(); } 25 | 26 | Vector3 operator^(Vector3 const& s) const { return Vector3(y*s.z-z*s.y, z*s.x-x*s.z, x*s.y-y*s.x); } 27 | Vector3 operator*(S s) const { return Vector3(x*s, y*s, z*s); } 28 | Vector3 operator/(S s) const { return Vector3(x/s, y/s, z/s); } 29 | 30 | Vector3 const& rotate_x(double a); 31 | Vector3 const& rotate_y(double a); 32 | Vector3 const& rotate_z(double a); 33 | void mix(Vector3 const& b, double q) { *this = *this*(1-q) + b*q; } 34 | 35 | bool operator!=(Vector3 const& b) const { return x != b.x || y != b.y || z != b.z; } 36 | bool operator!=(double const& b) const { return x != b || y != b || z != b; } 37 | bool operator==(Vector3 const& b) const { return x == b.x && y == b.y && z == b.z; } 38 | bool operator==(double const& b) const { return x == b && y == b && z == b; } 39 | 40 | S dot() const { return x*x + y*y + z*z; } 41 | S l2() const { return length(); } 42 | S dot(Vector3 const& b) const { return x*b.x + y*b.y + z*b.z; } 43 | S length() const { return (S)sqrt((double)(x*x + y*y + z*z)); } 44 | 45 | static S mix(Vector3 const& a, Vector3 const& b, double q) { return a*(1-q) + b(q); } 46 | static S deter(Vector3 const& r1, Vector3 const& r2, Vector3 const& r3); 47 | static S deter_col(Vector3 const& c1, Vector3 const& c2, Vector3 const& c3); 48 | static Vector3 solve3x3(Vector3 const& r1, Vector3 const& r2, Vector3 const& r3, Vector3 const& c); 49 | static Vector3 solve3x3_col(Vector3 const& c1, Vector3 const& c2, Vector3 const& c3, Vector3 const& c4); 50 | static Vector3 planes_intersection(Vector3 const& n1, Vector3 const& p1, 51 | Vector3 const& n2, Vector3 const& p2, 52 | Vector3 const& n3, Vector3 const& p3); 53 | 54 | void operator+=(Vector3 const& b) { x += b.x; y += b.y; z += b.z; } 55 | void operator-=(Vector3 const& b) { x -= b.x; y -= b.y; z -= b.z; } 56 | void operator*=(Vector3 const& b) { x *= b.x; y *= b.y; z *= b.z; } 57 | void operator/=(Vector3 const& b) { x /= b.x; y /= b.y; z /= b.z; } 58 | void operator*=(S s) { x *= s; y *= s; z *= s; } 59 | void operator/=(S s) { x /= s; y /= s; z /= s; } 60 | S operator[](int i) const { 61 | switch(i % 3) { 62 | case 0: return x; 63 | case -2: case 1: return y; 64 | case -1: case 2: return z; 65 | default: return 0; 66 | } 67 | } 68 | 69 | Vector3& norm(); 70 | 71 | union {S x; S r; S u;}; 72 | union {S y; S g; S v;}; 73 | union {S z; S b; S w;}; 74 | }; 75 | 76 | typedef Vector3 Vec3; 77 | 78 | /* Definitions */ 79 | 80 | template Vector3 & Vector3::norm() { 81 | if(x == 0 && y == 0 && z==0) return *this; 82 | double d = length(); 83 | x /= d; 84 | y /= d; 85 | z /= d; 86 | return *this; 87 | } 88 | 89 | template Vector3 const& Vector3::rotate_x(double a) { 90 | S py = y; 91 | y = (S)((double) y*cos(a) - (double)z*sin(a)); 92 | z = (S)((double)py*sin(a) + (double)z*cos(a)); 93 | return *this; 94 | } 95 | 96 | template Vector3 const& Vector3::rotate_y(double a) { 97 | S pz = z; 98 | z = (S)((double) z*cos(a) - (double)x*sin(a)); 99 | x = (S)((double)pz*sin(a) + (double)x*cos(a)); 100 | return *this; 101 | } 102 | 103 | template Vector3 const& Vector3::rotate_z(double a) { 104 | S px = x; 105 | x = (S)((double) x*cos(a) - (double)y*sin(a)); 106 | y = (S)((double)px*sin(a) + (double)y*cos(a)); 107 | return *this; 108 | } 109 | 110 | template S Vector3::deter(Vector3 const& r1, Vector3 const& r2, Vector3 const& r3) { 111 | //r1.x r1.y r1.z 112 | //r2.x r2.y r2.z 113 | //r3.x r3.y r3.z 114 | 115 | return r1.x * (r2.y * r3.z - r2.z * r3.y) - 116 | r1.y * (r2.x * r3.z - r2.z * r3.x) + 117 | r1.z * (r2.x * r3.y - r2.y * r3.x); 118 | } 119 | 120 | template S Vector3::deter_col(Vector3 const& c1, Vector3 const& c2, Vector3 const& c3) { 121 | //c1.x c2.x c3.x 122 | //c1.y c2.y c3.y 123 | //c1.z c2.z c3.z 124 | return c1.x * (c2.y * c3.z - c3.y * c2.z) - 125 | c2.x * (c1.y * c3.z - c3.y * c1.z) + 126 | c3.x * (c1.y * c2.z - c2.y * c1.z); 127 | } 128 | 129 | template Vector3 Vector3::solve3x3(Vector3 const& r1, Vector3 const& r2, Vector3 const& r3, Vector3 const& c) { 130 | double d = deter(r1,r2,r3); 131 | 132 | if(d >= 0 && d <= 0) 133 | return Vector3(); 134 | 135 | double dx = deter(Vector3(c.x, r1.y, r1.z), 136 | Vector3(c.y, r2.y, r2.z), 137 | Vector3(c.z, r3.y, r3.z)); 138 | double dy = deter(Vector3(r1.x, c.x, r1.z), 139 | Vector3(r2.x, c.y, r2.z), 140 | Vector3(r3.x, c.z, r3.z)); 141 | double dz = deter(Vector3(r1.x, r1.y, c.x), 142 | Vector3(r2.x, r2.y, c.y), 143 | Vector3(r3.x, r3.y, c.z)); 144 | 145 | return Vector3(dx, dy, dz) / d; 146 | } 147 | 148 | template Vector3 Vector3::solve3x3_col(Vector3 const& c1, Vector3 const& c2, Vector3 const& c3, Vector3 const& c4) { 149 | double d = deter_col(c1,c2,c3); 150 | 151 | if(d >= 0 && d <= 0) 152 | return Vector3(); 153 | 154 | double 155 | dx = deter_col(c4,c2,c3), 156 | dy = deter_col(c1,c4,c3), 157 | dz = deter_col(c1,c2,c4); 158 | 159 | return Vector3(dx, dy, dz) / d; 160 | } 161 | 162 | template Vector3 Vector3::planes_intersection(Vector3 const& n1, Vector3 const& p1, 163 | Vector3 const& n2, Vector3 const& p2, 164 | Vector3 const& n3, Vector3 const& p3) { 165 | return solve3x3(n1, n2, n3, Vector3(n1.dot(p1), n2.dot(p2), n3.dot(p3))); 166 | } 167 | -------------------------------------------------------------------------------- /src/complex/complex.cpp: -------------------------------------------------------------------------------- 1 | #include "complex.h" 2 | #include "common/color.h" 3 | #include "util.h" 4 | #include "common/common.h" 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include "globals.h" 14 | 15 | #define ortsin(a,b) Vector3d::ort_sin((a),(b)) 16 | 17 | bool Complex::clip(Vec2i& c, Vec2i& p) { 18 | bool clipped = false; 19 | if(p.x <= -c.x) { p.x = -c.x; clipped = true; } 20 | else if(p.x >= c.x) { p.x = c.x; clipped = true; } 21 | if(p.y <= -c.y) { p.y = -c.y; clipped = true; } 22 | else if(p.y >= c.y) { p.y = c.y; clipped = true; } 23 | return clipped; 24 | } 25 | 26 | void Complex::clipd(Vec2i c, Vec2& p) 27 | { 28 | if(p.x < -c.x) p.x = -c.x; 29 | else if(p.x > c.x) p.x = c.x; 30 | if(p.y < -c.y) p.y = -c.y; 31 | else if(p.y > c.y) p.y = c.y; 32 | } 33 | 34 | void Complex::move_nodes() 35 | { 36 | if(move_mode == Concur) move_nodes_concur(); 37 | else if(move_mode == Consec) move_nodes_consec(); 38 | } 39 | 40 | double intersect(Vec2 a, Vec2 b, Vec2 p, Vec2 q) { 41 | double n = (b-a)^(a-p); 42 | double d = (b-a)^(q-p); 43 | return n / d; 44 | } 45 | 46 | Node* Complex::line_split_node(Node* n, Vec2 p1) 47 | { 48 | if(n->type == Node::Padding) 49 | return n; 50 | clipd(_canvas - Vec2(1), p1); 51 | if(n->cp == p1) 52 | return n; 53 | 54 | for(auto f : *n) { 55 | if(f->t->type != Tri::Regular) 56 | continue; 57 | auto e = f->nxt; 58 | double t = intersect(e->n->cp, e->nxt->n->cp, f->n->cp, p1); 59 | double s = intersect(p1, f->n->cp, e->n->cp, e->nxt->n->cp); 60 | 61 | if(s >= 0.0 && s <= 1.0 && t > 0) { 62 | if(t < 1.0) { 63 | Node* m = split_edge(e, (1-s)); 64 | if(m != nullptr) { 65 | return line_split_node(m, p1); 66 | } 67 | auto np = (Vec2(n->cp) + (p1 - Vec2(n->cp)) * t).round() + ((p1 - Vec2(n->cp)).unit()).round(); 68 | auto u = f->t->p2u(f->n->cp, e->n->cp, e->nxt->n->cp, np); 69 | if(u.x < u.y && u.x < u.z) { 70 | if(n->type == Node::Floating) { 71 | move_consec(*n, np); 72 | return line_split_node(n, p1); 73 | } 74 | return n; 75 | } 76 | return (u.y < u.x && u.y < u.z)? e->nxt->n : e->n; 77 | } 78 | Node* m = split(*e->t, Vec3(1.0/3.0)); 79 | if(m == nullptr) 80 | return n; 81 | move_consec(*m, p1); 82 | return m; 83 | } 84 | } 85 | return nullptr; 86 | } 87 | 88 | 89 | 90 | 91 | Node* Complex::split(Tri& t, Vec2 coord) { 92 | return split(t, Vec3(coord, 1.0-coord.x-coord.y)); 93 | } 94 | 95 | /* c1 o a3 o b2 96 | / \ /|\ 97 | / \ / | \ 98 | / \ / | \ 99 | / \ / | \ 100 | / \ / |c2 \ 101 | / \ -----> / c3.o. \ 102 | / \ / .´ c1`. \ 103 | / \ / .´ `. \ 104 | / \ / .´ `. \ 105 | / \ b3 /.´ `.\ a2 106 | o---------------------o b1 o´-------------------`o 107 | a1 a1 b1 */ 108 | Node* Complex::split(Tri &t, Vec3 u) { 109 | Node &na = *t.a.n, &nb = *t.b.n, &nc = *t.c.n; 110 | 111 | auto p = Vec2(t.a.n->p()*u.x + t.b.n->p()*u.y + t.c.n->p()*u.z); 112 | Vec2i p2 = p.round(); 113 | 114 | const int Min_ar = 0; 115 | int64_t ar1, ar2, ar3; 116 | if((ar1 = Vec2i::area(na.cp, nb.cp, p2)) <= Min_ar || (ar2 = Vec2i::area(nb.cp, nc.cp, p2)) <= Min_ar || (ar3 = Vec2i::area(nc.cp, na.cp, p2)) <= Min_ar) 117 | return nullptr; 118 | 119 | Edge* e = &t.a; 120 | 121 | double nmw = t.a.n->w_ * u.x + t.b.n->w_ * u.y + t.c.n->w_ * u.z; 122 | double nmcontrast = t.a.n->contrast * u.x + t.b.n->contrast * u.y + t.c.n->contrast * u.z; 123 | Vec2 nmv = t.a.n->v * u.x + t.b.n->v * u.y + t.c.n->v * u.z; 124 | 125 | Node &nm = *(new Node(p2, e->prv, Col(na.color*u[0] + nb.color*u[1] + nc.color*u[2]))); 126 | e->prv->n = &nm; //re-assign node c to the created node 127 | Tri &t1 = t, 128 | &t2 = *(new Tri(&nb, e->nxt->j, &nc, nullptr, &nm, e->nxt, e->t->type, t1.color)), 129 | &t3 = *(new Tri(&nc, e->prv->j, &na, e->prv, &nm, &t2.b, e->t->type, t1.color)); 130 | t1.id = ++gid; //though only a transmutation of trigon t, the trigon t1 should take on a new identity. 131 | if(nb.entry() == e->nxt) nb.setentry(&t2.a); //this will ensure entry nodes on 132 | if(nc.entry() == e->prv) nc.setentry(&t3.a); //border edges for border nodes. 133 | nm.w_ = nmw; 134 | nm.contrast = nmcontrast; 135 | nm.v = nmv; 136 | 137 | Col t1ac = t1.a.c; 138 | Col t1bc = t1.b.c; 139 | Col t1cc = t1.c.c; 140 | 141 | t2.a.c = t1bc; 142 | t2.b.c = t1cc; 143 | //Color mix = t1ac*(u.x+u.y-u.z) + t1bc*(u.y+u.z-u.x) + t1cc*(u.z+u.x-u.y); 144 | Col mix = t1ac*u.x + t1bc*u.y + t1cc*u.z; 145 | mix.a = 0; 146 | t2.c.c = mix; 147 | 148 | t3.a.c = t1cc; 149 | t3.b.c = t1ac; 150 | t3.c.c = mix; 151 | 152 | t1.c.c = mix; 153 | 154 | t2.a.w = t1.b.w; 155 | t3.a.w = t1.c.w; 156 | t1.b.w = t1.c.w = t2.b.w = t3.b.w = 0; 157 | 158 | t1._area = ar1; t2._area = ar2; t3._area = ar3; //set as a bonus. 159 | 160 | trigons.push_back(&t2); 161 | trigons.push_back(&t3); 162 | nodes.push_front(&nm); 163 | return &nm; 164 | } 165 | 166 | Node* Complex::split_edge(Tri &t, Vec2 u2) { 167 | double f; 168 | Edge const* e; 169 | t.u_2_e_q(Vec3(u2, 1-u2.x-u2.y), &e, &f); 170 | return split_edge(e, f); 171 | } 172 | 173 | /* s s 174 | / \ /|\ 175 | / \ / | \ 176 | / \ / c2 b2 177 | / \ / | \ 178 | / \ / | \ 179 | p-----e---->r ----> p--e--o-a2--r 180 | \ / \ | c4 / 181 | \ / \ | / 182 | \ / \ a4 b4 183 | \ / \ | / 184 | \ / \|/ 185 | q q 186 | 187 | Splits a pair along a given edge. 188 | calculates and stores trigon areas. 189 | maintains entry edges within the trigon pair that is split. */ 190 | Node* Complex::split_edge(Edge const* e, double f) { 191 | if(e->nxt->n->type == Node::Padding) 192 | return nullptr; 193 | if(isnan(f) || isinf(f)) 194 | return nullptr; 195 | 196 | Edge* j = e->j; 197 | 198 | Vec2 op = (e->n->p() * f + e->nxt->n->p() * (1-f)).round(); 199 | Vec2i opi = op; 200 | 201 | Node *p = e->n, *q = j->prv->n, *r = j->n, *s = e->prv->n; 202 | 203 | const int64_t ma = 0; 204 | //Pre-calculate areas (successful split). 205 | int64_t ar1, ar2, ar3, ar4; 206 | if((ar1 = Vec2i::area(p->p_(), opi, s->p_())) <= ma || (ar2 = Vec2i::area(opi, r->p_(), s->p_())) <= ma || (ar3 = Vec2i::area(p->p_(), q->p_(), opi)) <= ma || (ar4 = Vec2i::area(opi, q->p_(), r->p_())) <= ma) 207 | return nullptr; 208 | 209 | double ow = e->n->w_ * f + e->nxt->n->w_ * (1-f); 210 | double ocontrast = e->n->contrast * f + e->nxt->n->contrast * (1-f); 211 | 212 | Vec2 pv = p->v*f; 213 | Vec2 rv = r->v*(1-f); 214 | Vec2 ov = pv + rv; 215 | 216 | Node* o = new Node(opi, e->nxt, p->color*(1-f) + r->color*f); 217 | Tri *t1 = e->t, 218 | *t2 = new Tri(o, nullptr, r, e->nxt->j, e->prv->n, e->nxt, t1->type, t1->color); 219 | e->nxt->n = o; 220 | if(r->entry() == e->nxt) r->setentry(&t2->b); 221 | o->setentry(&t2->a); 222 | if(epadding(e) || jpadding(e)) o->type = Node::Border; 223 | j->n = o; 224 | Tri *t3 = j->t, 225 | *t4 = new Tri(o, j->prv, q, j->prv->j, r, &t2->a, t3->type, t3->color); 226 | if(r->entry() == j) r->setentry(&t4->c); 227 | if(q->entry() == j->prv) q->setentry(&t4->b); 228 | o->w_ = ow; 229 | o->contrast = ocontrast; 230 | 231 | o->v = ov; 232 | 233 | t2->a.w = e->w; 234 | t2->b.w = e->nxt->w; 235 | t4->c.w = j->w; 236 | t4->b.w = j->prv->w; 237 | e->nxt->w = j->prv->w = 0; 238 | 239 | t3->_area = ar3; 240 | t4->_area = ar4; 241 | t1->_area = ar1; 242 | t2->_area = ar2; 243 | 244 | trigons.push_back(t2); 245 | trigons.push_back(t4); 246 | nodes.push_front(o); 247 | return o; 248 | } 249 | 250 | void Complex::randomize() 251 | { 252 | for(auto t : ts) 253 | t->color = Col::random(); 254 | } 255 | 256 | Tri* Complex::inside(Vec2i const& p) const { 257 | for(Trigons::const_iterator i = trigons.begin(); i != trigons.end(); ++i) { 258 | Tri& t = **i; 259 | if(t.invalid()) continue; 260 | if(t.inside(p)) return &t; 261 | } 262 | return nullptr; 263 | } 264 | 265 | void Complex::waste() { 266 | for(Trigons::iterator it = trigons.begin(); it != trigons.end();) { 267 | if((*it)->status == Tri::Dead) { 268 | delete *it; 269 | it = trigons.erase(it); 270 | continue; 271 | } 272 | ++it; 273 | } 274 | 275 | for(Nodes::iterator it = nodes.begin(); it != nodes.end();) { 276 | if((*it)->status == Node::Dead) { 277 | delete *it; 278 | it = nodes.erase(it); 279 | continue; 280 | } 281 | ++it; 282 | } 283 | } 284 | 285 | Complex::~Complex() { 286 | for(Nodes::iterator i = nodes.begin(); i != nodes.end(); ++i) delete (*i); 287 | for(Trigons::iterator i = trigons.begin(); i != trigons.end(); ++i) delete (*i); 288 | } 289 | 290 | -------------------------------------------------------------------------------- /src/complex/complex.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "node.h" 3 | #include "trigon.h" 4 | #include "flip.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define epadding(e) (e->t->type == Tri::Padding) 11 | #define jpadding(e) (epadding(e->j)) 12 | #define ejpadding(e) (epadding((e)) || epadding((e)->j)) 13 | #define contour(e) ((e->t->color - e->j->t->color).dist() > ContourColorDist) 14 | 15 | template struct Euiterator { 16 | typedef std::list Eumetries; 17 | Euiterator(Eumetries* s, typename Eumetries::iterator const& a) : s(s), i(a) {} //potentially empty list 18 | bool operator!=(Euiterator const& a) const { return a.i != i; } 19 | bool operator==(Euiterator const& a) const { return a.i == i; } 20 | S* operator*() { while((static_cast(*i))->invalid()) ++i; return *i; } //first obj could be invalid 21 | Euiterator const& operator++() { do { ++i; } while(i != s->end() && (static_cast(*i))->invalid()); return *this; } 22 | Eumetries* s; 23 | typename Eumetries::iterator i; 24 | }; 25 | 26 | template struct Eulist { 27 | typedef std::list Eumetries; 28 | Eulist(Eumetries* s) : s(s) {} 29 | Euiterator begin() { return Euiterator(s, s->begin()); } 30 | Euiterator end() { return Euiterator(s, s->end()); } 31 | Eumetries* s; 32 | }; 33 | 34 | typedef Eulist Eunodes; 35 | typedef Eulist Eutris; 36 | 37 | struct Complex { 38 | enum Move { 39 | Concur = 0, 40 | Pseudo = 1, 41 | Consec = 2 42 | }; 43 | 44 | const int Units; 45 | const double color_dist_th; 46 | const double ev_quant; 47 | const double ar_quant; 48 | const double purge_cos_thresh; 49 | 50 | friend struct State; 51 | Complex(bool configure = false); 52 | //Complex(string filename); 53 | ~Complex(); 54 | 55 | Eunodes ns; 56 | Eutris ts; 57 | 58 | void load_config(); 59 | static Move str_to_move(std::string str); 60 | 61 | Node* split_label_edge(Edge* e, double q, Edge*& e1, Edge*& e2); 62 | Node* split(Tri& t, Vec3 u); 63 | Node* split(Tri& t, Vec2 coord); 64 | Node* split_edge(Tri& t, Vec2 coord); 65 | Node* split_edge(Edge const* e, double q); 66 | 67 | Node* line_split_node(Node* n, Vec2 p1); 68 | 69 | void move_nodes(); 70 | 71 | double area() { return 2*_canvas.x * 2*_canvas.y; } 72 | 73 | void move_nodes_concur(); 74 | bool move(Node &n, Vec2i np); 75 | void set_node_type(); 76 | bool cross_case(Tri* t, Tri::Cross* c = nullptr); 77 | void flip(Edge* e); 78 | bool merge(Edge* e); 79 | Node* remove(Cross* c); 80 | static bool remove_self_folded_tri(Edge* e); 81 | static bool remove_double_linked_tri(Edge* e); 82 | Cross* pop_cross(); 83 | void push_cross(Cross* c); 84 | void detach(Cross* c); 85 | 86 | Core::Result move_consec(Node& n, Vec2i p); 87 | void move_nodes_consec(); 88 | 89 | void refract(int iter = 1); 90 | bool automata(); 91 | 92 | void create_contours(); 93 | 94 | void waste(); 95 | Tri* inside(Vec2i const& p) const; 96 | Vec2 canvas() const { return _canvas; } 97 | 98 | void delaunay(Node& n); 99 | void delaunify(bool constrained = true); 100 | void unconstr_delaunify(); 101 | void color_to_line(); 102 | 103 | void purge(); 104 | void purge_nonlines(); 105 | void purge_small_trigons(); 106 | void purge_stars(); 107 | void purge_straight_lines(); 108 | void purge_spikes(); 109 | 110 | void randomize(); 111 | 112 | static bool clip(Vec2i& c, Vec2i& p); 113 | static void clipd(Vec2i c, Vec2& p); 114 | 115 | bool constrained(Edge* e); 116 | bool redelaunay(Edge* e); 117 | bool flip_delaunay(Edge* e, bool constrained = true); 118 | //bool flip_worse(Edge* e); 119 | 120 | bool do_rectify; 121 | 122 | Trigons trigons; 123 | Nodes nodes; 124 | 125 | Nodes mv_nodes; 126 | 127 | Move move_mode; 128 | 129 | Col cola, colb, colc; 130 | 131 | private: 132 | static bool jt_inside_circumcircle(Edge* e); 133 | public: 134 | Core core; 135 | 136 | std::vector mv_tris; 137 | int cross_counter; 138 | double curt; 139 | Vec2i _canvas; 140 | 141 | std::vector ccs; 142 | std::vector cntrs; 143 | 144 | int count; 145 | }; 146 | 147 | -------------------------------------------------------------------------------- /src/complex/config.cpp: -------------------------------------------------------------------------------- 1 | #include "complex.h" 2 | #include "common/common.h" 3 | #include "globals.h" 4 | #include "util.h" 5 | #include "json/json.h" 6 | 7 | #include 8 | #include 9 | 10 | Complex::Move Complex::str_to_move(std::string str) { 11 | if (str == "Concur" || str == "concur") return Concur; 12 | if (str == "Pseudo" || str == "pseudo") return Pseudo; 13 | if (str == "Consec" || str == "consec") return Consec; 14 | return Consec; 15 | } 16 | 17 | Complex::Complex(bool configure) : 18 | Units(1024*4), 19 | color_dist_th(0.25/255.0), 20 | ev_quant(0.0025 * Units), 21 | ar_quant(ev_quant*ev_quant * 1), 22 | purge_cos_thresh(-0.99995), 23 | ns(&nodes), 24 | ts(&trigons), 25 | move_mode(Concur), 26 | cross_counter(0), 27 | curt(1), 28 | _canvas(Units, Units) { 29 | 30 | if(!configure) 31 | return; 32 | 33 | Node *a = new Node(Vec2i(-_canvas.x, -_canvas.y), Node::Corner, Col::random()), 34 | *b = new Node(Vec2i(_canvas.x, -_canvas.y), Node::Corner, Col::random()), 35 | *c = new Node(Vec2i(-_canvas.x, _canvas.y), Node::Corner, Col::random()), 36 | *d = new Node(Vec2i(_canvas.x, _canvas.y), Node::Corner, Col::random()), 37 | *ab = new Node(Vec2i(0, -_canvas.y*3), Node::Padding, Col::random()), 38 | *bd = new Node(Vec2i(_canvas.x*3, 0), Node::Padding, Col::random()), 39 | *dc = new Node(Vec2i(0, _canvas.y*3), Node::Padding, Col::random()), 40 | *ca = new Node(Vec2i(-_canvas.x*3, 0), Node::Padding, Col::random()); 41 | 42 | Tri *t = new Tri(a, b, c, Tri::Regular, Col::random()), 43 | *u = new Tri(d, nullptr, c, &t->b, b, nullptr, Tri::Regular, Col::random()), 44 | *ab_t = new Tri(b, &t->a, a, nullptr, ab, nullptr, Tri::Padding), 45 | *bd_t = new Tri(d, &u->c, b, nullptr, bd, nullptr, Tri::Padding), 46 | *dc_t = new Tri(c, &u->a, d, nullptr, dc, nullptr, Tri::Padding), 47 | *ca_t = new Tri(a, &t->c, c, nullptr, ca, nullptr, Tri::Padding), 48 | *x = new Tri(ab, nullptr, bd, &bd_t->b, b, &ab_t->c, Tri::Padding), 49 | *y = new Tri(bd, nullptr, dc, &dc_t->b, d, &bd_t->c, Tri::Padding), 50 | *z = new Tri(dc, nullptr, ca, &ca_t->b, c, &dc_t->c, Tri::Padding), 51 | *w = new Tri(ca, nullptr, ab, &ab_t->b, a, &ca_t->c, Tri::Padding); 52 | 53 | a->setentry(&t->a); b->setentry(&u->c); c->setentry(&t->c); d->setentry(&u->a); 54 | ab->setentry(&x->a); bd->setentry(&y->a); dc->setentry(&z->a); ca->setentry(&w->a); 55 | 56 | t->a.c = Col(1,0,0); 57 | t->b.c = Col(0,1,0); 58 | t->c.c = Col(0,0,1); 59 | u->a.c = Col(1,1,0); 60 | u->b.c = Col(0,1,1); 61 | u->c.c = Col(1,0,1); 62 | 63 | ab_t->color = bd_t->color = dc_t->color = ca_t->color = x->color = y->color = z->color = w->color = Col(0,0,0); 64 | 65 | t->b.w = 1; 66 | u->b.w = 1; 67 | a->w_ = b->w_ = c->w_ = d->w_ = 0; 68 | a->contrast = b->contrast = c->contrast = d->contrast = ab->contrast = bd->contrast = dc->contrast = ca->contrast = 1; 69 | 70 | //u->color = t->color = Col::random(); 71 | 72 | c->contrast = 1; 73 | u->color = Col::random(); 74 | t->color = u->color;// * (1.+5./255.); 75 | 76 | nodes.push_back(a); nodes.push_back(b); nodes.push_back(c); nodes.push_back(d); 77 | nodes.push_back(ab); nodes.push_back(bd); nodes.push_back(dc); nodes.push_back(ca); 78 | trigons.push_back(t); trigons.push_back(u); 79 | trigons.push_back(ab_t); trigons.push_back(bd_t); trigons.push_back(dc_t); trigons.push_back(ca_t); 80 | trigons.push_back(x); trigons.push_back(y); trigons.push_back(z); trigons.push_back(w); 81 | 82 | delaunify(); 83 | randomize(); 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/complex/contour.cpp: -------------------------------------------------------------------------------- 1 | #include "contour.h" 2 | 3 | #include "complex/edge.h" 4 | #include "complex/trigon.h" 5 | #include "complex/node.h" 6 | #include "complex/complex.h" 7 | 8 | #include "common/common.h" 9 | 10 | Edge* Edge::relcntr(int i) { return (*cntr)[cntr_index + i]; } 11 | 12 | void Contour::add(Edge* e) { 13 | cntr.push_back(e); 14 | e->cntr = this; 15 | e->cntr_index = cntr.size() - 1; 16 | } 17 | 18 | Edge* Contour::operator[](int i) { 19 | return cntr[(i + cntr.size() - 1) % cntr.size()]; 20 | } 21 | 22 | int Contour::sz() { return count(); } 23 | int Contour::count() { return cntr.size(); } 24 | 25 | void Concomp::add(Tri* t) { 26 | ts.push_back(t); 27 | t->cc = this; 28 | } 29 | 30 | //pre-condition: e->j is in cc 31 | void recursive_fill(Concomp* cc, Edge* e) { 32 | if(e->t->cc != nullptr) return; 33 | if(e->line()) return; 34 | if(e->t->type != Tri::Regular) return; 35 | cc->add(e->t); 36 | recursive_fill(cc, e->nxt->j); 37 | recursive_fill(cc, e->prv->j); 38 | } 39 | 40 | void populate_neighbors(Tri* t) { 41 | for(auto e : *t) { 42 | auto neighbor_cc = e->j->t->cc; 43 | if(neighbor_cc == nullptr) 44 | continue; 45 | t->cc->neighbors.insert(neighbor_cc); 46 | } 47 | } 48 | 49 | bool contour_recursive(Contour *cntr, Edge* cur, Edge* start) { 50 | Node* n = cur->nxt->n; 51 | Edge* nxt = nullptr; 52 | for(auto ei = n->begin(); ei != n->end(); ++ei) { 53 | Edge* e = *ei; 54 | if(nxt == nullptr) { 55 | if(e->t->cc == start->t->cc && e->j->t->cc != start->t->cc) { 56 | if(e == start) 57 | return true; 58 | nxt = e; 59 | } 60 | } 61 | else if(e->t->cc != start->t->cc) { 62 | if(e->j == cur) 63 | break; 64 | nxt = nullptr; 65 | } 66 | } 67 | if(nxt == nullptr) //should not happen 68 | return false; 69 | cntr->add(nxt); 70 | return contour_recursive(cntr, nxt, start); 71 | } 72 | 73 | 74 | void Complex::create_contours() { 75 | //clean up buffers and pointers 76 | for(auto c : cntrs) 77 | delete c; 78 | cntrs.clear(); 79 | for(auto cc : ccs) 80 | delete cc; 81 | ccs.clear(); 82 | for(auto t : trigons) { 83 | for(auto e : *t) 84 | e->cntr = nullptr; 85 | t->cc = nullptr; 86 | } 87 | 88 | for(auto t : ts) { 89 | if(t->cc != nullptr) 90 | continue; 91 | auto cc = new Concomp(); 92 | cc->add(t); 93 | for(auto e : *t) 94 | recursive_fill(cc, e->j); 95 | ccs.push_back(cc); 96 | } 97 | for(auto cc : ccs) { 98 | for(auto t : cc->ts) { 99 | cc->area += t->area(); 100 | cc->mid += t->centroid(); 101 | } 102 | cc->mid /= cc->ts.size(); 103 | 104 | Vec3 covar; 105 | for(auto t : cc->ts) { 106 | for(auto e : *t) { 107 | auto d = cc->mid - e->n->p(); 108 | covar += Vec3(d.x*d.x, d.y*d.y, d.x*d.y); 109 | } 110 | 111 | populate_neighbors(t); 112 | } 113 | covar /= (3 * cc->ts.size()); 114 | cc->covar = covar; 115 | double T = covar.x + covar.y; 116 | double D = covar.x*covar.y - covar.z*covar.z; 117 | double sq = sqrt(fabs(T*T/4.0 - D)); 118 | 119 | cc->r = covar.z / (sqrt(covar.x)*sqrt(covar.y)); 120 | cc->eigv = Vec2(T/2 + sq, T/2 - sq); 121 | cc->eigvec1 = Vec2(covar.z, cc->eigv.x - covar.x).unit(); 122 | } 123 | 124 | for(auto t : ts) { 125 | for(auto e : *t) { 126 | if(e->cntr == nullptr && e->t->cc != e->j->t->cc) { 127 | auto cntr = new Contour; 128 | cntrs.push_back(cntr); 129 | cntr->add(e); 130 | auto ret = contour_recursive(cntr, e, e); 131 | e->t->cc->contours += 1; 132 | double sur = 0; 133 | for(auto c : cntr->cntr) { 134 | sur += c->v().l2(); 135 | } 136 | cntr->sur = sur; 137 | e->t->cc->sur += sur; 138 | } 139 | } 140 | } 141 | } 142 | 143 | Tri* Contour::t() { return cntr[0]->t; } 144 | -------------------------------------------------------------------------------- /src/complex/contour.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "common/vector.h" 7 | #include "common/vector3.h" 8 | struct Tri; 9 | struct Edge; 10 | 11 | struct Contour { 12 | void add(Edge* e); 13 | Edge* operator[](int i); 14 | Tri* t(); 15 | int sz(); 16 | int count(); 17 | std::vector cntr; 18 | double sur = 0.0; 19 | }; 20 | 21 | 22 | struct Concomp { 23 | void add(Tri*); 24 | std::vector ts; 25 | int64_t area; 26 | Vec2 mid; 27 | double cos; 28 | std::set neighbors; 29 | Vec3 covar; 30 | Vec2 eigv; 31 | Vec2 eigvec1; 32 | Vec2 eigvec2; 33 | double r; 34 | int contours = 0; 35 | double sur = 0.0; 36 | }; 37 | 38 | -------------------------------------------------------------------------------- /src/complex/edge.cpp: -------------------------------------------------------------------------------- 1 | #include "edge.h" 2 | #include "node.h" 3 | 4 | Edge::Edge() : n(nullptr), j(nullptr), nxt(nullptr), prv(nullptr), t(nullptr), w(0) {} 5 | Edge::Edge(Edge const& e) : n(e.n), j(e.j), nxt(e.nxt), prv(e.prv), t(nullptr), w(0) {} 6 | 7 | Edge::Edge(Node* en, Edge* ej, Edge* nxt, Edge* prv, Tri* t) 8 | : n(en), j(ej), nxt(nxt), prv(prv), t(t), w(0) { 9 | if(j) j->j = this; //This is always true and the operation must always be done. 10 | c = Col(1,0,0,1);//random(); 11 | } 12 | 13 | void Edge::link(Edge*e) { 14 | j = e; 15 | if(j) j->j = this; 16 | } 17 | 18 | Vec2 Edge::v() const { 19 | return Vec2(nxt->n->cp - n->cp); 20 | } 21 | 22 | double Edge::ang() const { 23 | Vec2 a(nxt->n->p_()-n->p_()), 24 | b(prv->n->p_()-n->p_()); 25 | return asin(a.unit()^b.unit()) / (2*M_PI); 26 | } 27 | 28 | double Edge::cos() const { 29 | Vec2 a(nxt->n->p_()-n->p_()), 30 | b(prv->n->p_()-n->p_()); 31 | return a.unit().dot(b.unit()); 32 | } 33 | 34 | double Edge::sin() const { 35 | Vec2 a(nxt->n->p_()-n->p_()), 36 | b(prv->n->p_()-n->p_()); 37 | return a.unit()^b.unit(); 38 | } 39 | 40 | /*Vec3 Edge::p2u(Vec2 const& q) const { 41 | double ar_pbc = (prv->n->p_() - nxt->n->p_()) ^(q - nxt->n->p_()), 42 | ar_apc = (n->p_() - prv->n->p_())^(q - prv->n->p_()), 43 | ar_abp = (nxt->n->p_() - n->p_())^(q - n->p_()), 44 | ar_abc = (nxt->n->p_() - n->p_())^(prv->n->p_() - n->p_()); 45 | return Vec3(ar_pbc,ar_apc,ar_abp)/ar_abc; 46 | }*/ 47 | 48 | void Edge::operator^=(double bw) { 49 | if(this->w < 1 && this->w < bw) this->w = bw; 50 | else if(this->w > 0 && bw > 0) this->w = 0; 51 | } 52 | 53 | void Edge::operator|=(double bw) { 54 | if(this->w > 0 || bw > 0) this->w = 1; 55 | //else if(this->w > 0 && bw > 0) this->w = 0; 56 | } 57 | 58 | bool Edge::line() const { 59 | return w > 0; 60 | } 61 | 62 | bool Edge_iterator::operator!=(Edge_iterator const& i) const { 63 | return e != i.e || first == i.first; 64 | } 65 | 66 | bool Edge_iterator::operator==(Edge_iterator const& i) const { 67 | return e == i.e && first != i.first; 68 | } 69 | 70 | 71 | Edge_iterator const& Node_iterator::operator++() { 72 | e = e->prv->j; 73 | first = false; 74 | return *this; 75 | } 76 | 77 | Edge_iterator const& Node_iterator::operator--() { 78 | e = e->j->nxt; 79 | first = false; 80 | return *this; 81 | } 82 | 83 | Edge_iterator const& Trigon_iterator::operator++() { 84 | e = e->nxt; 85 | first = false; 86 | return *this; 87 | } 88 | 89 | Edge_iterator const& Trigon_iterator::operator--() { 90 | e = e->prv; 91 | first = false; 92 | return *this; 93 | } 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /src/complex/edge.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "common/vector.h" 4 | #include "common/color.h" 5 | #include 6 | 7 | struct Tri; 8 | struct Node; 9 | struct Contour; 10 | 11 | struct Edge { 12 | Edge(); 13 | Edge(Edge const& e); 14 | Edge(Node* en, Edge* ej, Edge* nxt, Edge* prv, Tri* t); 15 | 16 | Edge* snxt() const { return prv->j; } 17 | Edge* sprv() const { return j->nxt; } 18 | Vec2 v() const; 19 | bool line() const; 20 | 21 | void link(Edge* e); 22 | void operator^=(double w); 23 | void operator|=(double w); 24 | Edge* relcntr(int i); 25 | 26 | Node* n; 27 | Edge* j; //adjacent (side-to-side) edge. 28 | Edge* nxt,* prv; 29 | Tri* t; 30 | 31 | //Vec3 p2u(Vec2 const& p) const; 32 | 33 | double ang() const; 34 | double cos() const; 35 | double sin() const; 36 | 37 | mutable double w; //weight 38 | 39 | mutable Col c; 40 | 41 | mutable double o1; 42 | mutable double o2; 43 | mutable double cost; 44 | 45 | Contour *cntr; 46 | int cntr_index; 47 | }; 48 | 49 | 50 | struct Edge_iterator { 51 | Edge_iterator() : first(true), e(0) {} 52 | Edge_iterator(Edge_iterator const& i) : first(i.first), e(i.e) {} 53 | Edge_iterator(Edge* e) : first(true), e(e) {} 54 | bool operator!=(Edge_iterator const& i) const; 55 | bool operator==(Edge_iterator const& i) const; 56 | Edge* operator*() const { return e; } 57 | 58 | virtual Edge_iterator const& operator++() = 0; 59 | virtual Edge_iterator const& operator--() = 0; 60 | protected: 61 | bool first; 62 | Edge* e; 63 | }; 64 | 65 | struct Node_iterator : Edge_iterator { 66 | Node_iterator() {} 67 | Node_iterator(Edge_iterator const& i) : Edge_iterator(i) {} 68 | Node_iterator(Edge* e) : Edge_iterator(e) {} 69 | Edge_iterator const& operator++(); 70 | Edge_iterator const& operator--(); 71 | }; 72 | 73 | struct Trigon_iterator : Edge_iterator { 74 | Trigon_iterator() {} 75 | Trigon_iterator(Edge_iterator const& i) : Edge_iterator(i) {} 76 | Trigon_iterator(Edge* e) : Edge_iterator(e) {} 77 | Edge_iterator const& operator++(); 78 | Edge_iterator const& operator--(); 79 | }; 80 | -------------------------------------------------------------------------------- /src/complex/equations.cpp: -------------------------------------------------------------------------------- 1 | #include "trigon.h" 2 | #include "mpir/mpir.h" 3 | #include "globals.h" 4 | 5 | mpz_t Root::t, Root::t1, Root::t2, Root::t3, Root::t4, Root::t5, Root::t6, Root::t7, Root::t8; 6 | 7 | void Root::init_mpzs() 8 | { 9 | mpz_init2(t, 512); 10 | mpz_init2(t1, 512); 11 | mpz_init2(t2, 512); 12 | mpz_init2(t3, 512); 13 | mpz_init2(t4, 512); 14 | mpz_init2(t5, 512); 15 | mpz_init2(t6, 512); 16 | mpz_init2(t7, 512); 17 | mpz_init2(t8, 512); 18 | } 19 | 20 | void Root::clear_mpzs() 21 | { 22 | mpz_clears(t, t1, t2, t3, t4, t5, t6, t7, t8, nullptr); 23 | } 24 | 25 | int Root::sqsq_sgn_rh1_big(Root const& f, Root const& s) 26 | { 27 | //sgn(s.sqrtsgn*s.B*s.B*f.A*f.A - 4*s.C*s.A*f.A*f.A) - f.sqrtsgn*(f.B*f.B*s.A*s.A - 4*f.C*f.A*s.A*s.A)) 28 | mpz_mul(t1, s.B_, s.B_); mpz_mul(t1, t1, f.A_); mpz_mul(t1, t1, f.A_); 29 | mpz_mul_si(t2, s.C_, 4); mpz_mul(t2, t2, s.A_); mpz_mul(t2, t2, f.A_); mpz_mul(t2, t2, f.A_); 30 | mpz_mul(t3, f.B_, f.B_); mpz_mul(t3, t3, s.A_); mpz_mul(t3, t3, s.A_); 31 | mpz_mul_si(t4, f.C_, 4); mpz_mul(t4, t4, f.A_); mpz_mul(t4, t4, s.A_); mpz_mul(t4, t4, s.A_); 32 | mpz_sub(t5, t1, t2); mpz_mul_si(t5, t5, (int)s.sqrtsgn); 33 | mpz_sub(t6, t3, t4); mpz_mul_si(t6, t6, (int)f.sqrtsgn); 34 | mpz_sub(t, t5, t6); 35 | return mpz_sgn(t); 36 | } 37 | 38 | int Root::sqsq_sgn_lh3_big(Root const& f, Root const& s) 39 | { 40 | //sgn(f.C*f.C*s.A*s.A + s.C*s.C*f.A*f.A - 2*f.C*s.C*f.A*s.A - f.B*s.B*f.C*s.A - f.B*s.B*s.C*f.A + f.B*f.B*s.C*s.A + s.B*s.B*f.C*f.A); 41 | mpz_mul(t1, f.C_, f.C_); mpz_mul(t1, t1, s.A_); mpz_mul(t1, t1, s.A_); 42 | mpz_mul(t2, s.C_, s.C_); mpz_mul(t2, t2, f.A_); mpz_mul(t2, t2, f.A_); 43 | mpz_mul(t3, f.C_, s.C_); mpz_mul(t3, t3, f.A_); mpz_mul(t3, t3, s.A_); 44 | mpz_mul(t4, f.C_, s.C_); mpz_mul(t4, t4, f.A_); mpz_mul(t4, t4, s.A_); 45 | mpz_mul(t5, f.B_, s.B_); mpz_mul(t5, t5, f.C_); mpz_mul(t5, t5, s.A_); 46 | mpz_mul(t6, f.B_, s.B_); mpz_mul(t6, t6, s.C_); mpz_mul(t6, t6, f.A_); 47 | mpz_mul(t7, f.B_, f.B_); mpz_mul(t7, t7, s.C_); mpz_mul(t7, t7, s.A_); 48 | mpz_mul(t8, s.B_, s.B_); mpz_mul(t8, t8, f.C_); mpz_mul(t8, t8, f.A_); 49 | mpz_add(t, t1, t2); mpz_sub(t, t, t3); mpz_sub(t, t, t4); mpz_sub(t, t, t5); mpz_sub(t, t, t6); mpz_add(t, t, t7); mpz_add(t, t, t8); 50 | return mpz_sgn(t); 51 | } 52 | 53 | int Cross::SqL2::operator()() const 54 | { 55 | if(t->kind == Cross::Root::Square) { 56 | //int64_t V = A*(t->B*t->B - 2*t->A*t->C) - t->A*t->B*B + 2*t->A*t->A*C; 57 | mpz_mul(Root::t1, t->B_, t->B_); mpz_mul_si(Root::t2, t->A_, 2);mpz_mul(Root::t2, Root::t2, t->C_); 58 | mpz_sub(Root::t1, Root::t1, Root::t2); mpz_mul(Root::t1, Root::t1, A_); 59 | mpz_mul(Root::t2, t->A_, t->B_); mpz_mul(Root::t2, Root::t2, B_); mpz_sub(Root::t1, Root::t1, Root::t2); 60 | mpz_mul_si(Root::t2, t->A_, 2); mpz_mul(Root::t2, Root::t2, t->A_); mpz_mul(Root::t2, Root::t2, C_); mpz_add(Root::t1, Root::t1, Root::t2); 61 | int sgnV = mpz_sgn(Root::t1); 62 | 63 | //int64_t sgn_R = sgn(t->B*t->B - 4*t->A*t->C); 64 | /*mpz_mul(Root::t1, t->B_, t->B_); mpz_mul_si(Root::t2, t->A_, 4); mpz_mul(Root::t2, Root::t2, t->C_); mpz_sub(Root::t1, Root::t1, Root::t2); 65 | int sgnR = mpz_sgn(Root::t1);*/ 66 | int sgnR = sgn(t->B*t->B - 4*t->A*t->C); 67 | 68 | //int64_t H = (int64_t)sgn(t->A)*-(int64_t)t->sqrtsgn*sgn_R*(t->A*B - A*t->B); 69 | /*mpz_mul(Root::t1, t->A_, B_); mpz_mul(Root::t2, A_, t->B_); mpz_sub(Root::t1, Root::t1, Root::t2); mpz_mul_si(Root::t1, Root::t1, -sgn(t->A)*t->sqrtsgn*sgnR); 70 | int sgnH = mpz_sgn(Root::t1);*/ 71 | int sgnH = sgn(sgn(t->A)*-t->sqrtsgn*sgnR*(t->A*B - A*t->B)); 72 | 73 | if(sgnV*sgnH <= 0) { 74 | return sgnV - sgnH; 75 | } else { 76 | mpz_mul_si(Root::t1, A_, (2*(t->B*t->B) - 4*t->A*t->C)); 77 | mpz_mul_si(Root::t2, C_, (4*t->A*t->A)); 78 | mpz_mul_si(Root::t3, B_, (2*t->A)*-(t->B)); 79 | mpz_add(Root::t4, Root::t1, Root::t2); mpz_add(Root::t4, Root::t4, Root::t3); 80 | //int64_t V2 = A*(2*(t->B*t->B) - 4*t->A*t->C) + (4*t->A*t->A)*C + (2*t->A)*-(t->B)*B; 81 | mpz_mul(Root::t4, Root::t4, Root::t4); //V2*V2 82 | 83 | mpz_init_set_si(Root::t1, (t->B*t->B - 4*t->A*t->C)); 84 | mpz_init_set_si(Root::t2, (2*t->A*B - 2*A*(t->B))); 85 | mpz_mul(Root::t3, Root::t1, Root::t2); mpz_mul(Root::t3, Root::t3, Root::t2); 86 | //int64_t H2 = (t->B*t->B - 4*t->A*t->C) * (2*t->A*B - 2*A*(t->B)) * (2*t->A*B - 2*A*(t->B)); 87 | 88 | mpz_mul_si(Root::t4, Root::t4, sgnV); 89 | mpz_mul_si(Root::t3, Root::t3, sgnH); 90 | mpz_sub(Root::t5, Root::t4, Root::t3); 91 | int s = mpz_sgn(Root::t5); 92 | 93 | return s; 94 | } 95 | 96 | } else if(t->kind == Cross::Root::Linear) { 97 | //sgn(A*t->C*t->C - B*t->C*t->B + C*t->B*t->B); 98 | mpz_mul(Root::t1, A_, t->C_); mpz_mul(Root::t1, Root::t1, t->C_); 99 | mpz_mul(Root::t2, B_, t->C_); mpz_mul(Root::t2, Root::t2, t->B_); mpz_sub(Root::t1, Root::t1, Root::t2); 100 | mpz_mul(Root::t2, C_, t->B_); mpz_mul(Root::t2, Root::t2, t->B_); mpz_add(Root::t1, Root::t1, Root::t2); 101 | int s = mpz_sgn(Root::t1); 102 | return s; 103 | } 104 | 105 | return 0; 106 | } 107 | 108 | 109 | int Root::sqsq_sgn_lh2_big(Root const& f, Root const& s) 110 | { 111 | //sgn(-f.B*s.B + 2*f.C*s.A + 2*s.C*f.A) 112 | mpz_mul(t1, f.B_, s.B_); 113 | mpz_mul_si(t2, f.C_, 2); mpz_mul(t2, t2, s.A_); 114 | mpz_mul_si(t3, s.C_, 2); mpz_mul(t3, t3, f.A_); 115 | mpz_sub(t, t2, t1); mpz_add(t, t, t3); 116 | return mpz_sgn(t); 117 | } 118 | 119 | int Root::sqsq_sgn_rh2_big_2(const Root &f, const Root &s) 120 | { 121 | //(B_s^2 - 4*A_s*C_s)*(B_f^2 - 4*A_f*C_f) 122 | mpz_mul(t1, s.B_, s.B_); 123 | mpz_mul(t2, f.B_, f.B_); 124 | mpz_mul_si(t3, s.A_, 4); mpz_mul(t3, t3, s.C_); 125 | mpz_mul_si(t4, f.A_, 4); mpz_mul(t4, t4, f.C_); 126 | mpz_sub(t1, t1, t3); 127 | mpz_sub(t2, t2, t4); 128 | mpz_mul(t3, t1, t2); 129 | return mpz_sgn(t3); 130 | } 131 | 132 | int Root::init_sq_sgn_lh1_big() 133 | { 134 | //sgn(B*B - 4*C*A) 135 | mpz_mul(t1, B_, B_); 136 | mpz_mul_si(t2, C_, 4); mpz_mul(t2, t2, A_); 137 | mpz_sub(t, t1, t2); 138 | return mpz_sgn(t); 139 | } 140 | 141 | int Root::linlin_sgn_lh1_big(Root const& f, Root const& s) 142 | { 143 | //sgn(s.C*f.B - f.C*s.B) 144 | mpz_mul(t1, s.C_, f.B_); 145 | mpz_mul(t2, f.C_, s.B_); 146 | mpz_sub(t, t1, t2); 147 | return mpz_sgn(t); 148 | } 149 | 150 | int Root::linsq_sgn_lh1_big(Root const& f, Root const& s) 151 | { 152 | //sgn(f.B*s.B - 2*f.C*s.A) 153 | mpz_mul(t1, f.B_, s.B_); 154 | mpz_mul_si(t2, f.C_, 2); mpz_mul(t2, t2, s.A_); 155 | mpz_sub(t, t1, t2); 156 | return mpz_sgn(t); 157 | } 158 | 159 | int Root::linsq_sgn_rh1_big(Root const& s) 160 | { 161 | //sgn(s.B*s.B - 4*s.C*s.A) 162 | mpz_mul(t1, s.B_, s.B_); 163 | mpz_mul_si(t2, s.C_, 4); mpz_mul(t2, t2, s.A_); 164 | mpz_sub(t, t1, t2); 165 | return mpz_sgn(t); 166 | } 167 | 168 | int Root::linsq_sgn_lh2_big(Root const& f, Root const& s) 169 | { 170 | //sgn(f.C*f.C*s.A - f.B*s.B*f.C + f.B*f.B*s.C) 171 | mpz_mul(t1, f.C_, f.C_); mpz_mul(t1, t1, s.A_); 172 | mpz_mul(t2, f.B_, s.B_); mpz_mul(t2, t2, f.C_); 173 | mpz_mul(t3, f.B_, f.B_); mpz_mul(t3, t3, s.C_); 174 | mpz_sub(t, t1, t2); mpz_add(t, t, t3); 175 | return mpz_sgn(t); 176 | } 177 | 178 | int Root::sqsq_sgn_lh1_big(Root const& f, Root const& s) 179 | { 180 | //sgn(s.B*f.A - f.B*s.A) 181 | //mpz_mul(t1, f.A_, s.A_); 182 | mpz_mul(t2, s.B_, f.A_); 183 | mpz_mul(t3, f.B_, s.A_); 184 | mpz_sub(t, t2, t3); 185 | return mpz_sgn(t); 186 | } 187 | 188 | -------------------------------------------------------------------------------- /src/complex/flip.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpihlstrom/femton/f97a345b7965ae98a51f52ad04c427872546aa79/src/complex/flip.cpp -------------------------------------------------------------------------------- /src/complex/flip.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "complex/edge.h" 3 | #include 4 | #include 5 | 6 | #define MAX_FLIPS 0x10000 7 | 8 | //The structure for sorting the flip cases. There are four orders of priority, 9 | //the first and main one being where on the travel line the trigon became non-positive. 10 | //Biggest first. 11 | struct Flip { 12 | 13 | /* 14 | UPDATE: The below comment is nonsense. Basically the degenerate case conditionals in the predicate take care of this. 15 | I'm keeping the comment for historical reasons and because it is an interesting case worth keeping in mind. 16 | ----- 17 | The order in Cross is important. It must be that Left < Right or else there will be a degenerate like this: 18 | 19 | *. 20 | /: `. 21 | / : `. 22 | / X `. 23 | / : `. 24 | *----*....*....* 25 | 26 | O 27 | */ 28 | 29 | enum Cross { 30 | AntiMid = 0, 31 | Left = 1, 32 | Right = 2, 33 | Mid = 3, 34 | }; 35 | 36 | Flip() : e(0), n(0), d(0), c(AntiMid), i(0), g(0) {} 37 | Flip(Edge* e) : e(e), n(0), d(0), c(AntiMid), i(0), g(0) {} 38 | 39 | //Computes n first, which is essentially the area. If it's positive, it returns false. Otherwise it proceeds to compute d. 40 | bool ndc(); 41 | 42 | //Calculates c for an Edge. The function is used for finding the AntiMid case on positive trigons. 43 | static Cross cross(Edge* e); 44 | 45 | //The compare predicate function. It uses several attributes to define an order. For instance, if a hull crossing of two edges occur at the same t' = n/d, 46 | //the function will proceed to check what type of crossing the two cases are for determining the predicate outcome. If further still the type of crossing is 47 | //also the same, the index will be compared, and so on. 48 | static bool comp(Flip *f, Flip *s); 49 | 50 | Edge* e; 51 | //We have that the quotient n/d = q \in [0, 1] represents where/when the hull was crossed. 52 | //This is the primary sorting value. q is reversed, bigger is earlier. 53 | int64_t n, d; 54 | Cross c; //The type of star hull crossing. Secondary sorting value. 55 | int i; //This is basically the index of the edge as ordered circularly around the star. Tertiary sorting value. 56 | int g; //The generation, increases for each time the star hull is penetrated and expands by means of a mid-flip. Quaternary sorting value. 57 | }; 58 | 59 | //The machinery that deals with re-triangulation. 60 | struct Core { 61 | 62 | enum Result { 63 | None = 0, 64 | NoFlip = 1, 65 | EqPos = 2, 66 | Flipped = 3, 67 | }; 68 | 69 | Core() : flip_cursor(), ri(None) {} 70 | 71 | Result rectify(Node& n); 72 | Result rectify_set(Node& n); 73 | 74 | static void remove(Edge* e); 75 | 76 | static bool remove_star(Node* n); 77 | static void iflip(Edge* e); 78 | static void oflip(Edge* e); 79 | 80 | private: 81 | bool prime(Node& n); 82 | void rectify_primed(); 83 | void rectify_primed_set(); 84 | Flip* newflip(Edge* e); 85 | Flip* popflip(); 86 | void pushflip(Flip* f); 87 | void pushflip(Flip* f, int i, int g); 88 | bool eqpos_prv(Edge** pe); 89 | bool eqpos_nxt(Edge** pe); 90 | bool antimid(); 91 | 92 | Flip flip_buf[MAX_FLIPS]; //Buffer for flips. 93 | Flip* flip_cursor; 94 | std::vector fh; //flip heap 95 | //Pre-negative Positives. This buffer is used for the case when the star 96 | //trigons are all positive, to avoid the overhead of finding the AntiMid edge. 97 | std::vector pp; 98 | Result ri; //storage for returning information from rectify() 99 | }; 100 | -------------------------------------------------------------------------------- /src/complex/iterator.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpihlstrom/femton/f97a345b7965ae98a51f52ad04c427872546aa79/src/complex/iterator.cpp -------------------------------------------------------------------------------- /src/complex/iterator.h: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/complex/moveconcur.cpp: -------------------------------------------------------------------------------- 1 | #include "complex.h" 2 | #include "common/color.h" 3 | #include "util.h" 4 | #include "common/common.h" 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include "globals.h" 14 | 15 | bool Complex::merge(Edge* e) 16 | { 17 | //todo: make sure that merge is not done across the canvas?? 18 | return move(*e->n, e->nxt->n->cp); 19 | } 20 | 21 | bool Complex::move(Node &n, Vec2i np) { 22 | if(n.invalid()) return false; 23 | if(n.type == Node::Corner) return false; 24 | 25 | if(n.type == Node::Border) { 26 | Vec2 b = n.border()->nxt->n->cp - n.cp; 27 | //move p as projected onto the border 28 | np = n.cp + Vec2i((b*b.dot(Vec2(np - n.cp))/b.dot(b))); 29 | } 30 | 31 | clip(_canvas, np); 32 | if(np == n.cp) 33 | return false; 34 | 35 | n.np = np; 36 | mv_nodes.push_back(&n); 37 | return true; 38 | } 39 | 40 | #define eq_o(o, t, c) ((t)->cross != nullptr && (t)->cross->overlap == (o) && ((t)->cross->crossroot - c->crossroot == 0)) 41 | 42 | Edge* detach_o1o3(Edge* e, Edge* stop, Node* m, Cross* c) 43 | { 44 | Edge *o1 = e->j, *i, *o; //1-overlap, inner, outer 45 | 46 | o1->t->retire(); 47 | o1->n = o1->nxt->n = o1->prv->n = e->n; //collapse to 3-overlap polygon 48 | 49 | for(i = e; eq_o(3, i->t, c); i = i->snxt()) 50 | i->t->cross->detached = true; 51 | 52 | for(o = i; o != o1->nxt; o = o->snxt()) 53 | if(o->j != stop) 54 | o->n = m; 55 | 56 | o1->prv->j->link(o1->nxt->j); 57 | 58 | if(i->j == stop) 59 | return o1->prv->j; 60 | 61 | return detach_o1o3(i->j, stop, m, c); 62 | } 63 | 64 | void Complex::detach(Cross* c) 65 | { 66 | c->detached = true; 67 | for(auto e : *c->t) { 68 | if(!eq_o(1, e->j->t, c)) 69 | continue; 70 | 71 | Node* n = new Node(*e->nxt->n); 72 | auto entry = detach_o1o3(e, e, n, c); 73 | n->setentry(entry->sprv()); 74 | nodes.push_front(n); 75 | mv_nodes.push_front(n); 76 | 77 | for(auto i = n->begin(); i != n->end(); ++i) { 78 | (*i)->nxt->n->setentry((*i)->nxt); 79 | cross_case((*i)->t, c); 80 | } 81 | 82 | break; 83 | } 84 | } 85 | 86 | void Complex::push_cross(Cross* c) { 87 | mv_tris.push_back(c); 88 | push_heap(mv_tris.begin(), mv_tris.end(), Cross::lt); 89 | } 90 | 91 | Cross* Complex::pop_cross() { 92 | auto c = mv_tris.front(); 93 | pop_heap(mv_tris.begin(), mv_tris.end(), Cross::lt); 94 | mv_tris.pop_back(); 95 | return c; 96 | } 97 | 98 | void Complex::move_nodes_concur() 99 | { 100 | for(auto n : mv_nodes) 101 | n->cp = n->np; 102 | for(auto n : mv_nodes) 103 | for(auto e : *n) 104 | cross_case(e->t); 105 | 106 | for(Tri::Cross* c; !mv_tris.empty();) { 107 | c = pop_cross(); 108 | 109 | if(!c->invalid) { 110 | if(c->overlap >= 2) { 111 | if(c->iter == 0) { 112 | if(!c->detached) detach(c); 113 | ++c->iter; 114 | push_cross(c); 115 | continue; //do not delete 116 | } 117 | c->t->retire_w_ns(); 118 | } else if(c->overlap == 1) { 119 | remove(c); 120 | } else { 121 | Edge *e = c->flip_e, *j = e->j; 122 | flip(e); 123 | cross_case(e->t, c); 124 | cross_case(j->t, c); 125 | } 126 | } 127 | 128 | delete c; 129 | } 130 | 131 | set_node_type(); 132 | 133 | for(auto *n : mv_nodes) 134 | n->pp = n->cp; 135 | 136 | mv_tris.clear(); 137 | mv_nodes.clear(); 138 | cross_counter = 0; 139 | } 140 | 141 | bool Complex::cross_case(Tri* t, Tri::Cross* c) 142 | { 143 | if(t->cross != nullptr) { 144 | if(c == nullptr) return false; //at init, don't replace any previous cross case 145 | else t->cross->invalid = true; //keep it on the heap, but de-activate it 146 | } 147 | 148 | t->cross = t->create_cross(c); 149 | if(t->cross == nullptr) 150 | return false; 151 | 152 | push_cross(t->cross); 153 | return true; 154 | } 155 | 156 | void Complex::set_node_type() 157 | { 158 | for(auto n : mv_nodes) { 159 | if(n->cp.x == -_canvas.x || n->cp.x == _canvas.x) n->type = Node::Border; 160 | if(n->cp.y == -_canvas.y || n->cp.y == _canvas.y) n->type = Node::Border; 161 | 162 | if(n->cp.x == -_canvas.x && n->cp.y == -_canvas.y) n->type = Node::Corner; 163 | if(n->cp.x == -_canvas.x && n->cp.y == _canvas.y) n->type = Node::Corner; 164 | if(n->cp.x == _canvas.x && n->cp.y == -_canvas.y) n->type = Node::Corner; 165 | if(n->cp.x == _canvas.x && n->cp.y == _canvas.y) n->type = Node::Corner; 166 | } 167 | } 168 | 169 | /* 170 | O = vertex 171 | 172 | O--------. 173 | | ,---. \ 174 | | / \ | 175 | | | O | | 176 | | | \j| / 177 | | \ e\|/ 178 | \ `----O 179 | `-----´ 180 | */ 181 | 182 | bool Complex::remove_self_folded_tri(Edge* e) 183 | { 184 | Edge* j = e->j; 185 | if (!(j == e->nxt && e->n == e->prv->n)) 186 | return false; 187 | 188 | e->nxt->n->status = Node::Dead; 189 | e->t->retire(); 190 | e->prv->j->t->retire(); 191 | 192 | e->prv->j->nxt->j->link(e->prv->j->prv->j); 193 | e->n->setentry(e->prv->j->snxt()); 194 | e->prv->j->prv->n->setentry(e->prv->j->prv->snxt()); 195 | 196 | return true; 197 | } 198 | 199 | /* 200 | O = vertex 201 | 202 | O----. 203 | |\ \ 204 | | \ | 205 | | O | 206 | | \j| 207 | \ e\| 208 | `----O 209 | */ 210 | 211 | bool Complex::remove_double_linked_tri(Edge* e) 212 | { 213 | Edge* j = e->j; 214 | if(e->nxt->j->nxt != j) 215 | return false; 216 | 217 | e->nxt->n->status = Node::Dead; 218 | e->t->retire(); 219 | j->t->retire(); 220 | 221 | e->prv->j->link(j->nxt->j); 222 | e->n->setentry(e->snxt()); 223 | e->prv->n->setentry(e->prv->sprv()); 224 | 225 | return true; 226 | } 227 | 228 | //Removes a pair of trigons sharing the edge e. The node e->n will be preserved 229 | //while e->nxt->n is made Dead. Affected node entries are adjusted accordingly. 230 | Node* Complex::remove(Cross* c) 231 | { 232 | Edge* e = c->flip_e; 233 | Node* n = e->n; 234 | Node* s = e->nxt->n; 235 | auto j = e->j; 236 | auto et = e->t; 237 | auto jt = j->t; 238 | 239 | 240 | if(remove_self_folded_tri(e)) { 241 | myDebug() << "self fold: e"; 242 | return nullptr; 243 | } 244 | if(remove_self_folded_tri(e->nxt)) { 245 | myDebug() << "self fold: e->nxt"; 246 | return nullptr; 247 | } 248 | if(remove_self_folded_tri(e->prv)) { 249 | myDebug() << "self fold: e->prv"; 250 | return nullptr; 251 | } 252 | 253 | 254 | if(remove_double_linked_tri(e) || remove_double_linked_tri(j)) { 255 | myDebug() << "double linked"; 256 | return nullptr; 257 | } 258 | 259 | Edge *eprv = e->prv, *enxt = e->nxt; 260 | Edge *jprv = j->prv, *jnxt = j->nxt; 261 | for(auto i = jprv->j; i != enxt; i = i->snxt()) { 262 | i->n = n; 263 | cross_case(i->t, c); 264 | } 265 | 266 | n->setentry(eprv->j); 267 | 268 | //Change entry nodes if they are pointing to trigons to be deleted. 269 | if(eprv->n->entry() == eprv) eprv->n->setentry(enxt->j); 270 | if(jprv->n->entry() == jprv) jprv->n->setentry(jnxt->j); 271 | 272 | enxt->j->link(eprv->j); 273 | jnxt->j->link(jprv->j); 274 | 275 | et->retire(); 276 | jt->retire(); 277 | 278 | s->status = Node::Dead; 279 | return n; 280 | } 281 | 282 | /* 283 | | | 284 | | | 285 | V V 286 | q .d. r q--.d.--r 287 | .´ `. |.´#|#j.| 288 | a---e-->c ---> a###|###c 289 | |\#####/| |\##|##/| 290 | | \###/ | | e#|#/ | 291 | | \#/ | | \|/ | 292 | t---b---s t---b---s 293 | 294 | Flipping a trigon pair and maintains entry edges within the trigon pair. */ 295 | void Complex::flip(Edge* e) { 296 | Edge* j = e->j; 297 | 298 | double acw = e->w, caw = j->w, abw = j->nxt->w, cdw = e->nxt->w; 299 | 300 | e->t->type = j->t->type; 301 | e->t->color = j->t->color; 302 | 303 | if(j->n->entry() == e->nxt) ++*j->n; 304 | e->nxt->n = j->prv->n; 305 | if(e->n->entry() == j->nxt) ++*e->n; 306 | j->nxt->n = e->prv->n; 307 | e->link(j->nxt->j); 308 | j->link(e->nxt->j); 309 | e->nxt->link(j->nxt); 310 | 311 | *e->prv->j |= acw; 312 | *j->j |= acw; 313 | *j |= cdw; 314 | *e->prv |= caw; 315 | e->w = abw; 316 | e->nxt->w = j->nxt->w = 0; 317 | } 318 | -------------------------------------------------------------------------------- /src/complex/node.cpp: -------------------------------------------------------------------------------- 1 | #include "node.h" 2 | #include "trigon.h" 3 | 4 | #include 5 | 6 | #include 7 | 8 | #include "globals.h" 9 | 10 | 11 | Node::Node() : type(Floating), status(Live), w_(0), contrast(0) {} 12 | Node::Node(Vec2i const& p, Edge* e) : cp(p), pp(p), np(Vec2(p)), entry_(e), type(Floating), status(Live), w_(0), contrast(0) {} 13 | Node::Node(Vec2i const& p, Type t, Col const& c) : cp(p), pp(p), np(Vec2(p)), type(t), status(Live), color(c), w_(0), contrast(0) {} 14 | Node::Node(Vec2i const& p, Edge* e, Col const& c) : cp(Vec2(p)), pp(Vec2(p)), np(Vec2(p)), entry_(e), type(Floating), status(Live), color(c), w_(0), contrast(0) {} //z(p.z) {} 15 | 16 | Node::iterator Node::operator++() { 17 | iterator a; 18 | entry_ = iterator((Edge*)*++entry_); //resets: first = true 19 | return entry_; 20 | } 21 | 22 | Node::iterator Node::operator--() { 23 | entry_ = iterator((Edge*)*--entry_); //resets: first = true 24 | return entry_; 25 | } 26 | 27 | Node::iterator Node::begin() const { 28 | if(type == Border || type == Corner) return border(); 29 | return entry_; 30 | } 31 | 32 | Node::iterator Node::end() const { 33 | if(type == Border || type == Corner) return border(); 34 | return entry_; 35 | } 36 | 37 | Edge* Node::setentry(Edge* e) { 38 | entry_ = iterator(e); 39 | return *entry_; 40 | } 41 | 42 | Edge* Node::border() const { 43 | iterator i(entry_); 44 | while(!((*i)->t->type_() == Tri::Regular && (*i)->j->t->type_() == Tri::Padding)) ++i; 45 | return *i; 46 | } 47 | 48 | 49 | void Node::swap_p() { 50 | Vec2i t = cp; 51 | cp = pp; 52 | pp = t; 53 | } 54 | 55 | 56 | Vec2 Node::min_edge() const { 57 | Vec2 v(0); 58 | for(iterator i = begin(); i != end(); ++i) { 59 | auto v1 = Vec2((**i).nxt->n->p_() - p_()); 60 | if(v.l2() <= 0 || v1.l2() < v.l2()) 61 | v = v1; 62 | } 63 | return v; 64 | } 65 | 66 | double Node::area() const { 67 | double ar = 0; 68 | for(iterator i = begin(); i != end(); ++i) { 69 | ar += (**i).t->area(); 70 | } 71 | return ar; 72 | } 73 | 74 | bool Node::operator<(Node const& s) { 75 | //return flip_t_acc > s.flip_t_acc; 76 | 77 | if(flip_t == s.flip_t) 78 | return (np - cp).dot() > (s.np - s.cp).dot(); 79 | return flip_t > s.flip_t; 80 | } 81 | 82 | std::tuple Node::calc_flip_t() { 83 | Edge* e = *entry_; 84 | double min_t1 = 1.0; 85 | double min_t2 = 1000000000.0;//DBL_MAX; 86 | Edge* min_e1 = e; 87 | Edge* min_e2 = e; 88 | do { 89 | Vec2i h1h2(e->prv->n->cp - e->nxt->n->cp); 90 | int64_t num = h1h2^(e->n->np - e->nxt->n->cp); 91 | double t = 1.0 - (double)num / (double)(h1h2^(e->n->np - e->n->cp)); 92 | if(num <= 0) { 93 | if (t <= min_t1) { 94 | min_t1 = t; 95 | min_e1 = e; 96 | } 97 | } 98 | if(t > 0) 99 | { 100 | if (t <= min_t2) { 101 | min_t2 = t; 102 | min_e2 = e; 103 | } 104 | } 105 | e = e->snxt(); 106 | } while(e != *entry_); 107 | return {min_t1, min_t2};//min(1.0, min_t1); 108 | } 109 | 110 | double Node::w() const { 111 | return w_;// c(); 112 | 113 | /* 114 | Vec2 gr; 115 | if(type == Padding) 116 | return 0.0; 117 | double wsum = 0.0; 118 | //Harris type covariance 119 | int count = 0; 120 | Vec3 co; 121 | for(auto e : *this) { 122 | if(nxtnpadding(e)) 123 | continue; 124 | double w = e->w; 125 | wsum += w; 126 | gr += e->v().norm()*w; 127 | 128 | Vec2 pdif(e->v().norm()); 129 | co += Vec3(pdif.x*pdif.x, pdif.y*pdif.y, pdif.x*pdif.y); 130 | ++count; 131 | } 132 | 133 | co /= count; 134 | double T = co.x + co.y; 135 | double D = co.x*co.y - co.z*co.z; 136 | double sq = sqrt(fabs(T*T/4.0 - D)); 137 | double ev1 = T/2 + sq; 138 | double ev2 = T/2 - sq; 139 | 140 | return w_*(ev1 / (ev1 + ev2)); 141 | // fVector e1 = fVector(co.z, ev1 - co.x).norm(); 142 | */ 143 | } 144 | 145 | Vec2 Node::g() const { 146 | return Vec2(1,1); 147 | 148 | /* 149 | Vec2 gr; 150 | if(type == Padding) 151 | return gr; 152 | double wsum = 1.0; 153 | for(auto e : *this) { 154 | //if(e->line()) 155 | { 156 | gr += e->v()*e->w; 157 | wsum += e->w; 158 | } 159 | } 160 | auto mean = gr / wsum; 161 | Vec2 gr_v; 162 | for(auto e : *this) { 163 | //if(e->line()) 164 | { 165 | auto dif = e->v().norm()*e->w - mean; 166 | gr_v += dif*dif; 167 | } 168 | } 169 | gr_v /= wsum; 170 | 171 | Vec2 gr_d = Vec2(sqrt(gr_v.x), sqrt(gr_v.y)); 172 | return gr_d.norm(); 173 | */ 174 | } 175 | 176 | 177 | double Node::c() const { 178 | return contrast; 179 | } 180 | 181 | -------------------------------------------------------------------------------- /src/complex/node.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "common/vector.h" 3 | #include "common/color.h" 4 | #include "complex/edge.h" 5 | #include "common/vector3.h" 6 | #include "common/entity.h" 7 | #include "iterator.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #define nxtnpadding(e) ((e)->nxt->n->type == Node::Padding) 14 | 15 | struct Node : Class, Eumetry { 16 | friend struct Complex; 17 | friend struct Core; 18 | friend struct Flip; 19 | friend struct Tri; 20 | friend struct Edge; 21 | friend struct State; 22 | 23 | typedef Node_iterator iterator; 24 | 25 | enum Status { Live, Dead }; 26 | enum Type { Floating, Border, Corner, Padding }; 27 | 28 | Node(); 29 | Node(Vec2i const& p_, Edge* e); 30 | Node(Vec2i const& p_, Edge* e, Col const& c); 31 | Node(Vec2i const& p_, Type t, Col const& c); 32 | virtual ~Node() {} 33 | 34 | bool operator<(Node const& s); 35 | 36 | inline int64_t x() const { return cp.x; } 37 | inline int64_t y() const { return cp.y; } 38 | inline Vec2i p_() const { return cp; } 39 | inline Vec2 p() const { return cp; } 40 | bool invalid() const { return status == Dead || type == Padding; } 41 | Status state() const { return status; } 42 | Type type_() const { return type; } 43 | Col col() const { return color; } 44 | double c() const; 45 | iterator begin() const; 46 | iterator end() const; 47 | Edge* entry() const { return *entry_; } 48 | Edge* border() const; 49 | double ctrst() const { return contrast; } 50 | 51 | Vec2 ppcp(double t) const { return Vec2(pp)*(1-t) + Vec2(cp)*t; } 52 | 53 | Vec3 wnu_init() const; 54 | 55 | Vec3 wn() const; 56 | double w() const; 57 | Vec2 g() const; 58 | Vec2 min_edge() const; 59 | double area() const; 60 | 61 | std::tuple calc_flip_t(); 62 | 63 | virtual Class::Name name() const { return Class_node; } 64 | 65 | void swap_p(); 66 | 67 | Vec2i cp; //current point/position 68 | Vec2i pp; //previous point/position 69 | Vec2i np; //new point/position 70 | 71 | Vec2 v; 72 | 73 | double flip_t; 74 | double flip_t_acc; 75 | 76 | private: 77 | //Anything that can be used to corrupt (or is relevant only to) the complex is private. 78 | iterator operator++(); 79 | iterator operator--(); 80 | public: 81 | Edge* setentry(Edge* e); 82 | 83 | iterator entry_; 84 | Type type; 85 | public: 86 | Status status; 87 | 88 | public: 89 | mutable Col color; 90 | double w_; //make private? 91 | Vec2 g_; 92 | double contrast; 93 | }; 94 | 95 | typedef std::list Nodes; 96 | typedef std::vector NodesV; 97 | typedef Nodes::iterator niterator; 98 | 99 | -------------------------------------------------------------------------------- /src/complex/trigon.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "common/color.h" 5 | #include "common/vector3.h" 6 | #include "common/entity.h" 7 | #include "edge.h" 8 | #include "mpir/mpir.h" 9 | #include 10 | #include 11 | 12 | struct Node; 13 | struct Tri; 14 | struct Concomp; 15 | 16 | typedef std::list Trigons; 17 | 18 | struct Tri : Class, Eumetry { 19 | struct Cross { 20 | struct Root { 21 | static Root root_t0; 22 | static Root root_t1; 23 | 24 | enum Kind { 25 | None = 0, 26 | Linear = 1, 27 | Square = 2, 28 | Imaginary = 3 29 | }; 30 | 31 | Root(Root const& s); 32 | Root(); 33 | Root(Tri const& t, Root const* cur, int sqrtsgn = 0); 34 | Root(int64_t A, int64_t B, int64_t C, Root const* cur, int sqrtsgn = 0); 35 | void init(Tri::Cross::Root const* cur ); 36 | void operator=(Root const& s); 37 | 38 | Root const& operator()(int s) { sqrtsgn = s; return *this; } 39 | int operator-(Root const& s) const; 40 | double root() const { return sqrtsgn <= 0? root1 : root2; } 41 | 42 | int init_sq_sgn_lh1_big(); 43 | static int linlin_sgn_lh1_big(Root const& f, Root const& s); 44 | static int linsq_sgn_lh1_big(Root const& f, Root const& s); 45 | static int linsq_sgn_rh1_big(Root const& s); 46 | static int linsq_sgn_lh2_big(Root const& f, Root const& s); 47 | static int sqsq_sgn_lh1_big(Root const& f, Root const& s); 48 | static int sqsq_sgn_rh1_big(Root const& f, Root const& s); 49 | static int sqsq_sgn_lh2_big(Root const& f, Root const& s); 50 | //static int sqsq_sgn_rh2_big(Root const& f, Root const& s); 51 | static int sqsq_sgn_rh2_big_2(Root const& f, Root const& s); 52 | static int sqsq_sgn_lh3_big(Root const& f, Root const& s); 53 | static void init_mpzs(); 54 | static void clear_mpzs(); 55 | 56 | int64_t A; 57 | int64_t B; 58 | int64_t C; 59 | mpz_t A_; 60 | mpz_t B_; 61 | mpz_t C_; 62 | 63 | Kind kind; 64 | int sqrtsgn; 65 | //bool colin; 66 | 67 | double root1; 68 | double root2; 69 | 70 | static mpz_t t, t1, t2, t3, t4, t5, t6, t7, t8; 71 | }; 72 | 73 | struct SqL2 74 | { 75 | SqL2(Edge* e, Root* t); 76 | SqL2(int64_t A, int64_t B, int64_t C, Root* t); 77 | SqL2 operator-(SqL2 const& s) const; 78 | void operator=(SqL2 const& s); 79 | int operator()() const; 80 | 81 | int64_t A; 82 | int64_t B; 83 | int64_t C; 84 | mpz_t A_; 85 | mpz_t B_; 86 | mpz_t C_; 87 | 88 | Root* t; 89 | }; 90 | 91 | Cross(Tri* t) : t(t), detached(true) {} 92 | Cross() : t(nullptr), flip_e(nullptr), invalid(true), nodecross(false), count(0), iter(0), crossroot(Root()), overlap(false), detached(false) {} 93 | Cross(Tri* t, Edge* flip_e, int count, Root const& cr, int overlap = 0) : 94 | t(t), flip_e(flip_e), invalid(false), nodecross(false), count(count), iter(0), crossroot(cr), overlap(overlap), detached(false) {} 95 | static bool lt(Tri::Cross* f, Tri::Cross* s); 96 | Cross* operator++() { ++iter; return this; } 97 | 98 | Tri* t; 99 | Edge* flip_e; 100 | bool invalid; 101 | bool nodecross; 102 | int count; 103 | int iter; 104 | 105 | Root crossroot; 106 | 107 | int overlap; 108 | bool detached; 109 | }; 110 | 111 | Tri::Cross* create_cross(Tri::Cross* curcr = nullptr); 112 | Cross* cross; 113 | 114 | typedef Trigon_iterator iterator; 115 | 116 | friend struct Complex; 117 | friend struct Core; 118 | friend struct Flip; 119 | friend struct State; 120 | 121 | enum Label { None = 0, A = 1, B = 2, C = 3, Aj = 4}; 122 | enum Status { Dead, Live }; 123 | enum Type { Regular, Padding }; 124 | 125 | Tri() : cross(nullptr), type(Regular), status(Dead), _area(1), entry(&a) {} 126 | Tri(Node* an, Edge* aj, Node* bn, Edge* bj, Node* cn, Edge* cj, Type type, Col const& col = Col()); 127 | Tri(Node* an, Node* bn, Node* cn, Type t, Col const& col); 128 | virtual ~Tri() {} 129 | 130 | Vec2 operator*(Vec3 const& s) const; 131 | 132 | static int64_t deter(Node& a, Node& b, Node& c); 133 | static void clamp(Vec3& cp, Vec2 const& a, Vec2 const& b, double q); 134 | 135 | static Vec3 p2u(Vec2 const& a, Vec2 const& b, Vec2 const& c, Vec2 const& q); 136 | 137 | iterator begin() const { return entry; } 138 | iterator end() const { return entry; } 139 | 140 | Edge const& ea() const { return a; } 141 | Edge const& eb() const { return b; } 142 | Edge const& ec() const { return c; } 143 | Node const& na() const { return *a.n; } 144 | Node const& nb() const { return *b.n; } 145 | Node const& nc() const { return *c.n; } 146 | Col const& col() const { return color; } 147 | Type type_() const { return type; } 148 | Status state() const { return status; } 149 | bool invalid() const { 150 | return status == Dead || type == Padding; 151 | } 152 | Label label(Node const& n) const; 153 | Label label(Edge const* e) const; 154 | bool inside(Vec2i const& p) const; 155 | Vec2 centroid() const; 156 | void join_cps(); 157 | Vec3 cntrst(); 158 | 159 | void clamp_cps(); 160 | 161 | Vec3 gcont_b111(); 162 | 163 | Vec3 p2u(Vec2 const& p) const; 164 | 165 | Vec2 ab() const; 166 | Vec2 bc() const; 167 | Vec2 ca() const; 168 | private: 169 | Vec2 clamp(Vec2 p); //clamp to trigon area 170 | public: 171 | virtual Class::Name name() const { return Class_trigon; } 172 | 173 | //This value is intended to always be the correct area/determinant 174 | //int64_t area() const { return _area; } 175 | int64_t area() const; 176 | double area3() const; 177 | void u_2_e_q(Vec2 const& u2, Edge const** e, double* q) const; 178 | 179 | mutable double w; 180 | 181 | void retire(); 182 | void retire_w_ns(); 183 | private: 184 | //Anything that can be used to corrupt the complex (or is relevant only to 185 | //the complex) is private. 186 | Edge* edge(Label l); 187 | 188 | public: 189 | Type type; 190 | Status status; 191 | 192 | Edge a, b, c; 193 | 194 | //Prefixed underline means that these are temporary storage variables. 195 | Sint64 _area; 196 | 197 | Col color; 198 | 199 | iterator entry; 200 | 201 | Concomp* cc; 202 | }; 203 | 204 | typedef Tri::Cross Cross; 205 | typedef Tri::Cross::Root Root; 206 | -------------------------------------------------------------------------------- /src/config.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpihlstrom/femton/f97a345b7965ae98a51f52ad04c427872546aa79/src/config.h -------------------------------------------------------------------------------- /src/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "line width" : 1, 3 | "point size" : 1, 4 | 5 | "surface" : true, 6 | "gaussian" : true, 7 | "painting" : true, 8 | "nodes" : false, 9 | "edges" : false, 10 | "control net" : false, 11 | 12 | 13 | "contrast" : 1.0, 14 | "gaussian_size" : 10, 15 | "min_gaussian_q" : 0.0, 16 | "contrast_scale" : 25, 17 | 18 | 19 | "camera_zoom" : 1, 20 | 21 | "move_mode" : "concur", 22 | 23 | "load" : "out" 24 | } 25 | -------------------------------------------------------------------------------- /src/femton.pro: -------------------------------------------------------------------------------- 1 | HEADERS = \ 2 | camera.h \ 3 | complex/contour.h \ 4 | graphics/shader.h \ 5 | init.h \ 6 | state.h \ 7 | complex/flip.h \ 8 | complex/complex.h \ 9 | complex/edge.h \ 10 | complex/node.h \ 11 | complex/trigon.h \ 12 | common/common.h \ 13 | graphics/graphics.h \ 14 | globals.h \ 15 | window.h \ 16 | graphics/shader.h \ 17 | common/color.h \ 18 | camera.h \ 19 | GL/eglew.h \ 20 | GL/glew.h \ 21 | GL/glxew.h \ 22 | GL/wglew.h \ 23 | common/entity.h \ 24 | tool/tools.h \ 25 | common/vector.h \ 26 | common/vector3.h \ 27 | 28 | SOURCES = \ 29 | camera.cpp \ 30 | common/common.cpp \ 31 | complex/canvas.cpp \ 32 | complex/contour.cpp \ 33 | complex/equations.cpp \ 34 | complex/flip.cpp \ 35 | complex/moveconcur.cpp \ 36 | complex/moveconsec.cpp \ 37 | graphics/shader.cpp \ 38 | main.cpp \ 39 | init.cpp \ 40 | jsoncpp.cpp \ 41 | state.cpp \ 42 | util.cpp \ 43 | complex/complex.cpp \ 44 | common/color.cpp \ 45 | complex/trigon.cpp \ 46 | complex/edge.cpp \ 47 | complex/node.cpp \ 48 | complex/config.cpp \ 49 | window.cpp \ 50 | globals.cpp \ 51 | glew.c \ 52 | tool/tools.cpp \ 53 | graphics/graphics.cpp \ 54 | graphics/draw.cpp \ 55 | input.cpp 56 | 57 | QT += widgets 58 | QT += opengl 59 | QT += openglwidgets 60 | 61 | DISTFILES += \ 62 | graphics/shaders/composition/fragment.glsl \ 63 | graphics/shaders/composition/vertex.glsl \ 64 | graphics/shaders/surface/fragment.glsl \ 65 | graphics/shaders/surface/vertex.glsl \ 66 | graphics/shaders/points/fragment.glsl \ 67 | graphics/shaders/points/vertex.glsl \ 68 | graphics/shaders/controlnet/fragment.glsl \ 69 | graphics/shaders/controlnet/vertex.glsl \ 70 | graphics/shaders/edges/fragment.glsl \ 71 | graphics/shaders/edges/vertex.glsl \ 72 | graphics/shaders/gaussian/fragment.glsl \ 73 | graphics/shaders/gaussian/vertex.glsl \ 74 | graphics/shaders/painting/fragment.glsl \ 75 | graphics/shaders/painting/vertex.glsl 76 | 77 | win32 { 78 | LIBS += libopengl32 79 | LIBS += mpir.lib 80 | } 81 | 82 | win32:LIBS += -luser32 83 | msvc: LIBS += -luser32 84 | 85 | QMAKE_CXXFLAGS += -Wall 86 | 87 | -------------------------------------------------------------------------------- /src/globals.cpp: -------------------------------------------------------------------------------- 1 | #include "globals.h" 2 | #include "window.h" 3 | #include "state.h" 4 | 5 | class Graphics; 6 | 7 | Complex* com; 8 | Camera* view; 9 | Graphics* draw; 10 | 11 | Void void_selection; 12 | 13 | Size init_scr_sz(640, 640); 14 | Size scr_sz(init_scr_sz); 15 | double pixelratio; 16 | 17 | Window* window; 18 | 19 | Tool* mousetool; 20 | 21 | Brush brush; 22 | Paintbrush paintbrush; 23 | Contrastbrush contrastbrush; 24 | Blurbrush blurbrush; 25 | Repelpinchbrush repelpinchbrush; 26 | Smoothbrush smoothbrush; 27 | Rubbrush rubbrush; 28 | Cameratool cameratool; 29 | Selecttool selecttool; 30 | Colorpicker colorpicker; 31 | 32 | std::unordered_map selectable; 33 | 34 | unsigned int gid = 0; 35 | 36 | bool interpolate_move = true; 37 | double manual_curt = 1.0; 38 | bool set_buffers = true; 39 | 40 | Edge* flipped_e; 41 | Edge* flipped_j; 42 | Node* flipped_en; 43 | Node* flipped_jn; 44 | 45 | Col brush_color; 46 | 47 | std::stringstream debug_strstr; 48 | 49 | 50 | 51 | bool load_file(std::string filename0) { 52 | auto filename = filename0 + ".qua"; 53 | if(Complex* new_com = State::load_from(filename)) { 54 | delete com; 55 | com = new_com; 56 | selecttool.reset(); 57 | return true; 58 | } 59 | return false; 60 | } 61 | 62 | bool save_file(std::string filename0) { 63 | auto filename = filename0 + ".qua"; 64 | return State::export_to(*com, filename); 65 | } 66 | 67 | 68 | void set_tool(Tool* mt) { 69 | if(mousetool) mousetool->reset(); 70 | mousetool = mt; 71 | draw->update(); 72 | } 73 | -------------------------------------------------------------------------------- /src/globals.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "camera.h" 7 | #include "graphics/graphics.h" 8 | #include "complex/complex.h" 9 | #include "tool/tools.h" 10 | 11 | extern Camera* view; 12 | extern Graphics* draw; 13 | extern Complex* com; 14 | 15 | extern Void void_selection; 16 | 17 | extern Size init_scr_sz; 18 | extern Size scr_sz; 19 | extern double pixelratio; 20 | 21 | class Window; 22 | extern Window* window; 23 | 24 | extern Vec2 cursor; 25 | extern Tool* mousetool; 26 | extern Brush brush; 27 | extern Cameratool cameratool; 28 | extern Selecttool selecttool; 29 | extern Paintbrush paintbrush; 30 | extern Contrastbrush contrastbrush; 31 | extern Blurbrush blurbrush; 32 | extern Repelpinchbrush repelpinchbrush; 33 | extern Smoothbrush smoothbrush; 34 | extern Rubbrush rubbrush; 35 | extern Colorpicker colorpicker; 36 | 37 | extern std::unordered_map selectable; 38 | 39 | extern float contrast_scale; 40 | 41 | extern unsigned int gid; 42 | 43 | extern bool interpolate_move; 44 | extern double manual_curt; 45 | 46 | extern int r_count; 47 | 48 | extern Edge* flipped_e; 49 | extern Edge* flipped_j; 50 | extern Node* flipped_en; 51 | extern Node* flipped_jn; 52 | 53 | extern bool draw_contours; 54 | extern bool draw_flat; 55 | extern float line_width; 56 | 57 | extern float gaussian_size; 58 | extern float min_gaussian_q; 59 | 60 | extern bool set_buffers; 61 | 62 | extern Col brush_color; 63 | 64 | bool load_file(std::string filename); 65 | bool save_file(std::string filename); 66 | 67 | void set_tool(Tool* mt); 68 | 69 | extern std::stringstream debug_strstr; 70 | -------------------------------------------------------------------------------- /src/graphics/graphics.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include "GL/glew.h" 11 | #include 12 | #include 13 | 14 | #include "json/json.h" 15 | 16 | #include "graphics.h" 17 | #include "graphics.h" 18 | #include "common/common.h" 19 | #include "complex/complex.h" 20 | #include "camera.h" 21 | #include "init.h" 22 | #include "util.h" 23 | #include "globals.h" 24 | #include "shader.h" 25 | #include "globals.h" 26 | 27 | float line_width; 28 | int tessellation_level; 29 | float point_size; 30 | Col bg; 31 | bool draw_cursor = false; 32 | 33 | 34 | Base_render::Base_render(uint8_t fbo_buffers) : active(true), fbo(0), fbo_buffers(fbo_buffers), program(0) { 35 | reset_fbo(scr_sz); 36 | } 37 | 38 | Base_render::Base_render(QOpenGLBuffer* pbuffer, uint8_t fbo_buffers) : pbuffer(pbuffer), active(true), fbo(0), fbo_buffers(fbo_buffers), program(0) { 39 | reset_fbo(scr_sz); 40 | } 41 | 42 | Base_render::~Base_render() { 43 | if(program) delete program; 44 | if(fbo) delete fbo; 45 | } 46 | 47 | void Base_render::reset_fbo(Size const& size) { 48 | if(fbo) 49 | delete fbo; 50 | 51 | if(!(fbo_buffers & FBO_buffer::Color)) { 52 | fbo = 0; 53 | return; 54 | } 55 | fbo = new Framebufferobject(size); 56 | 57 | if(fbo_buffers & FBO_buffer::Depth) 58 | fbo->attach_depth_buffer(); 59 | if(fbo_buffers & FBO_buffer::Id) 60 | fbo->attach_id_buffer(); 61 | if(fbo_buffers & FBO_buffer::Coordinate) 62 | fbo->attach_coordinate_buffer(); 63 | if(fbo_buffers & FBO_buffer::Color2) 64 | fbo->attach_color2_buffer(); 65 | } 66 | 67 | Render::Render(uint8_t fbo_buffers) : Base_render(fbo_buffers) { 68 | pbuffer = &buffer; 69 | pbuffer->create(); 70 | pbuffer->setUsagePattern(QOpenGLBuffer::DynamicDraw); 71 | } 72 | 73 | void Base_render::render() { 74 | if(!active) 75 | return; 76 | Shader_program::FBOBinder sp(program, fbo); 77 | QOpenGLVertexArrayObject vao; 78 | QOpenGLVertexArrayObject::Binder binder(&vao); 79 | Buffer_binder bufbinder(*pbuffer); 80 | draw(); 81 | } 82 | 83 | void Base_render::render_to_screen() { 84 | Shader_program::Binder sp(program); 85 | QOpenGLVertexArrayObject vao; 86 | QOpenGLVertexArrayObject::Binder binder(&vao); 87 | Buffer_binder bufbinder(*pbuffer); 88 | draw(); 89 | } 90 | 91 | void Graphics::composition_to_fbo() { 92 | makeCurrent(); //Very important, apparently, as toImage() will transform the entire window view otherwise. 93 | composition->render(); 94 | } 95 | 96 | QImage Graphics::grab_render2(Size size) { 97 | makeCurrent(); //Very important, apparently, as toImage() will transform the entire window view otherwise. 98 | glViewport(0, 0, size.w, size.h); 99 | draw_scene(); 100 | composition->render(); 101 | QImage img(composition->color_to_image()); 102 | return img; 103 | } 104 | 105 | QImage Graphics::grab_render(Size size) { 106 | makeCurrent(); //Very important, apparently, as toImage() will transform the entire window view otherwise. 107 | Size prev_size = render_sz; 108 | resizeGL(size); 109 | glViewport(0, 0, size.w, size.h); 110 | draw_scene(); 111 | composition->render(); 112 | QImage img(composition->color_to_image()); 113 | resizeGL(prev_size); 114 | return img; 115 | } 116 | 117 | Graphics::Graphics(QWidget *parent) : QOpenGLWidget(parent), render_sz(scr_sz) { 118 | /*core = */QCoreApplication::arguments().contains(QStringLiteral("--coreprofile")); 119 | bool transparent = QCoreApplication::arguments().contains(QStringLiteral("--transparent")); 120 | if (transparent) { 121 | QSurfaceFormat fmt = format(); 122 | fmt.setAlphaBufferSize(8); 123 | setFormat(fmt); 124 | } 125 | } 126 | 127 | void Graphics::add_render(Base_render* render, char const* name) { 128 | render->name = name; 129 | renders[name] = render; 130 | renders_order.push_back(render); 131 | } 132 | 133 | void Graphics::initializeGL() { 134 | //initializeOpenGLFunctions(); 135 | glewInit(); 136 | 137 | composition = new Composition_render(); 138 | composition->set_buffer(); 139 | 140 | add_render(new Surface_render(), "surface"); 141 | add_render(new Edges_render(), "edges"); 142 | add_render(new Control_net_render(renders["edges"]->pbuffer), "control_net"); 143 | add_render(new Nodes_render(renders["surface"]->pbuffer), "nodes"); 144 | add_render(new Gaussian_h_render(composition->pbuffer, renders["surface"]), "gaussian_h"); 145 | add_render(new Gaussian_v_render(composition->pbuffer, renders["gaussian_h"]), "gaussian_v"); 146 | //add_render(new Contour_h_render(composition->pbuffer, renders["surface"]), "contour_h"); 147 | //add_render(new Contour_v_render(composition->pbuffer, renders["contour_h"]), "contour_v"); 148 | add_render(new Painting_render(composition->pbuffer), "painting"); 149 | 150 | bg = Col(0.5,0.5,0.5);//Col::random(); 151 | 152 | glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); 153 | glEnable(GL_DEPTH_TEST); 154 | glFrontFace(GL_CCW); 155 | 156 | //resizeGL(scr_sz.w, scr_sz.h); 157 | //resizeGL(scr_sz); 158 | } 159 | 160 | void Graphics::set_selectables() { 161 | selectable.clear(); 162 | selectable[void_selection.id] = &void_selection; 163 | 164 | for(auto t0 : com->ts) { Tri const& t = *t0; 165 | //for(auto i = com->trigons.begin(); i != com->trigons.end(); ++i) { auto t = **i; 166 | selectable[t.id] = &t; 167 | selectable[t.na().id] = &t.na(); 168 | selectable[t.nb().id] = &t.nb(); 169 | selectable[t.nc().id] = &t.nc(); 170 | } 171 | } 172 | 173 | uint32_t* Base_render::fbo_buffer(FBO_buffer buffer, bool redraw) { 174 | if(!(fbo_buffers & buffer)) 175 | return nullptr; 176 | ::draw->makeCurrent(); 177 | int w = fbo->width(); 178 | int h = fbo->height(); 179 | uint32_t* pixel = new uint32_t[w*h]; 180 | Shader_program::FBOBinder sp(program, fbo); 181 | 182 | if(redraw) { 183 | Buffer_binder bufbinder(*pbuffer); 184 | QOpenGLVertexArrayObject vao; 185 | QOpenGLVertexArrayObject::Binder vaobinder(&vao); 186 | draw(); 187 | } 188 | 189 | GLenum mode, format, type; 190 | switch(buffer) { 191 | case FBO_buffer::Color: 192 | mode = GL_COLOR_ATTACHMENT0; 193 | format = GL_BGRA; 194 | type = GL_UNSIGNED_BYTE; 195 | break; 196 | case FBO_buffer::Id: 197 | mode = GL_COLOR_ATTACHMENT1; 198 | format = GL_RED_INTEGER; 199 | type = GL_UNSIGNED_INT; 200 | break; 201 | case FBO_buffer::Depth: 202 | mode = GL_DEPTH_ATTACHMENT; 203 | format = GL_DEPTH_COMPONENT; 204 | type = GL_FLOAT; 205 | break; 206 | case FBO_buffer::Coordinate: 207 | mode = GL_COLOR_ATTACHMENT2; 208 | format = GL_RG; 209 | type = GL_UNSIGNED_SHORT; 210 | break; 211 | default: 212 | return nullptr; 213 | } 214 | 215 | glReadBuffer(mode); 216 | glReadPixels(0, 0, w, h, format, type, pixel); 217 | return pixel; 218 | } 219 | 220 | uint32_t Base_render::id_at(int x, int y) { 221 | uint32_t* pixel = fbo_buffer(FBO_buffer::Id, true); 222 | int w = scr_sz.w, 223 | h = scr_sz.h; 224 | uint32_t id = *(pixel + (h-y)*w + x); 225 | delete[] pixel; 226 | return id; 227 | } 228 | 229 | Vec2 Base_render::coordinate_at(int x, int y) { 230 | uint32_t* pixel = fbo_buffer(FBO_buffer::Coordinate, true); 231 | int w = scr_sz.w, 232 | h = scr_sz.h; 233 | uint32_t p = *(pixel + (h-y)*w + x); 234 | uint16_t* coord = (uint16_t*)&p; 235 | delete[] pixel; 236 | return Vec2((double)coord[0], (double)coord[1]) / 65535.0; 237 | } 238 | 239 | void Graphics::resizeGL(Size const& sz) { 240 | render_sz = sz; 241 | composition->reset_fbo(render_sz); 242 | for(auto i : renders) 243 | i.second->reset_fbo(render_sz); 244 | } 245 | 246 | QSize Graphics::minimumSizeHint() const { 247 | return QSize(init_scr_sz.w, init_scr_sz.h) / 8; 248 | } 249 | 250 | QSize Graphics::sizeHint() const { 251 | auto ret = QSize(init_scr_sz.w, init_scr_sz.h); 252 | init_scr_sz *= pixelratio; 253 | scr_sz *= pixelratio; 254 | return ret; 255 | } 256 | 257 | void Graphics::resizeGL(int w, int h) { 258 | auto sz = Size(w*pixelratio, h*pixelratio); 259 | init_scr_sz = scr_sz = sz; 260 | resizeGL(sz); 261 | //resizeGL(Size(scr_sz.w, scr_sz.w)); 262 | } 263 | 264 | Graphics::~Graphics() { 265 | cleanup(); 266 | } 267 | 268 | void Graphics::cleanup() { 269 | makeCurrent(); 270 | for(auto i : renders) 271 | delete i.second; 272 | doneCurrent(); 273 | } 274 | -------------------------------------------------------------------------------- /src/graphics/graphics.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "GL/glew.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "common/common.h" 12 | #include "common/color.h" 13 | #include "shader.h" 14 | #include "complex/node.h" 15 | #include "complex/trigon.h" 16 | #include "common/entity.h" 17 | 18 | #pragma pack (push, 1) 19 | 20 | QT_FORWARD_DECLARE_CLASS(QOpenGLShaderProgram) 21 | 22 | extern int tessellation_level; 23 | extern float point_size; 24 | extern Col bg; 25 | extern bool draw_cursor; 26 | 27 | namespace G { 28 | 29 | struct Col { 30 | Col() : r(0), g(0), b(0), a(0) {} 31 | Col(float r, float g, float b) : r(r), g(g), b(b), a(1.0) {} 32 | Col(float r, float g, float b, float a) : r(r), g(g), b(b), a(a) {} 33 | Col(::Col const& c) : r((float)c.r), g((float)c.g), b((float)c.b), a((float)c.a) {} 34 | float r, g, b, a; 35 | }; 36 | 37 | struct Vec2 { 38 | Vec2() {} 39 | //Vec2(Vec2i const& v) : x((float)v.x), y((float)v.y) {} 40 | Vec2(::Vec2 const& v) : x((float)v.x), y((float)v.y) {} 41 | Vec2(float const& x, float const& y) : x(x), y(y) {} 42 | float x, y; 43 | }; 44 | 45 | struct Vec3 { 46 | Vec3() {} 47 | Vec3(Vec2i const& v) : x((float)v.x), y((float)v.y), z(0) {} 48 | Vec3(::Vec2 const& v) : x((float)v.x), y((float)v.y), z(0) {} 49 | Vec3(Vec3 const& v) : x((float)v.x), y((float)v.y), z((float)v.z) {} 50 | Vec3(float const& x, float const& y, float const& z) : x(x), y(y), z(z) {} 51 | float x, y, z; 52 | }; 53 | 54 | struct Vec3w : Vec3 { 55 | Vec3w() {} 56 | Vec3w(Vec3 const& v, float w) : Vec3(v), w(w) {} 57 | float w; 58 | }; 59 | 60 | struct Tri { 61 | Tri() {} 62 | Tri(Vec3 const& a, Vec3 const& b, Vec3 const& c) : a(a), b(b), c(c) {} 63 | Vec3 a, b, c; 64 | }; 65 | 66 | struct Edge : Entity { 67 | Edge() {} 68 | Edge(unsigned int id, Vec3 const& p, Col const& col, uint32_t l, Tri const& t, Vec3 const& ew, Vec3 const& nw) 69 | : Entity(id), p(p), col(col), l(l), t(t), ew(ew), nw(nw) {} 70 | Vec3 p; 71 | Col col; 72 | uint32_t l; 73 | Tri t; 74 | Vec3 ew; 75 | Vec3 nw; 76 | }; 77 | 78 | struct Node : Entity { 79 | Node(uint32_t id, Vec3 const& p, Col const& c1, float w, float ctrst) : Entity(id), p(p), c1(c1), w(w), ctrst(ctrst) {} 80 | Node(uint32_t id, Vec3 const& p, ::Node::Type t, float w, float ctrst) : Entity(id), p(p), w(w), ctrst(ctrst) { 81 | if(t == ::Node::Type::Corner) c1 = Col(0,0,0); 82 | else if(t == ::Node::Type::Border) c1 = Col(1,1,0); 83 | else c1 = Col(1,1,1); 84 | } 85 | Node(Vec3 const& p, Col const& c1, float w) : p(p), c1(c1),w(w) {} 86 | Vec3 p; 87 | Col c1; 88 | float w; 89 | float ctrst; 90 | }; 91 | 92 | struct Tri_patch : Entity { 93 | Tri_patch(unsigned int id, Node const& v, uint32_t l, Col const& c, Vec2 const& g) : Entity(id), v(v), l(l), c(c), g(g) {} 94 | Node v; 95 | uint32_t l; 96 | Col c; 97 | Vec2 g; 98 | }; 99 | } 100 | 101 | struct Base_render { 102 | enum FBO_buffer { 103 | Color = 1, 104 | Depth = 2, 105 | Id = 4, 106 | Coordinate = 8, 107 | Color2 = 16, 108 | Float = 32, 109 | None = 0 110 | }; 111 | 112 | Base_render(QOpenGLBuffer* pbuffer, uint8_t fbo_buffers); 113 | Base_render(uint8_t fbo_buffers = (FBO_buffer::Color | FBO_buffer::Depth | FBO_buffer::Id | FBO_buffer::Coordinate)); 114 | virtual ~Base_render(); 115 | virtual void set_buffer() {} 116 | void reset_fbo(Size const& size); 117 | virtual void render(); 118 | virtual void render_to_screen(); 119 | GLuint fbo_color() const { return fbo->texture(); } 120 | GLuint fbo_depth() const { return fbo->depth_id; } 121 | GLuint fbo_id() const { return fbo->id_id; } 122 | GLuint fbo_coordinate() const { return fbo->coordinate_id; } 123 | GLuint fbo_color2() const { return fbo->color2_id; } 124 | GLuint fbo_float() const { return fbo->float_id; } 125 | uint8_t fbos() const { return fbo_buffers; } 126 | QImage color_to_image() { return fbo->toImage(true); } 127 | 128 | uint32_t* id_buffer(); 129 | uint32_t* depth_buffer(); 130 | uint32_t* coord_buffer(); 131 | 132 | uint32_t* fbo_buffer(FBO_buffer buffer, bool redraw = false); 133 | uint32_t id_at(int x, int y); 134 | Vec2 coordinate_at(int x, int y); 135 | 136 | void render_to_buffer(QOpenGLBuffer* in_buf); 137 | 138 | std::string name; 139 | 140 | QOpenGLBuffer* pbuffer; 141 | bool active; 142 | 143 | protected: 144 | virtual void draw() = 0; 145 | Framebufferobject* fbo; 146 | uint8_t fbo_buffers; 147 | Shader_program* program; 148 | }; 149 | 150 | struct Render : Base_render { 151 | Render(uint8_t fbo_buffers = (FBO_buffer::Color | FBO_buffer::Depth | FBO_buffer::Id | FBO_buffer::Coordinate)); 152 | private: 153 | QOpenGLBuffer buffer; 154 | }; 155 | 156 | struct Surface_render : Render { 157 | Surface_render(uint8_t fbo_buffers); 158 | Surface_render(); 159 | protected: 160 | virtual void draw(); 161 | private: 162 | void set_buffer(); 163 | }; 164 | 165 | struct Composition_render : Render { 166 | Composition_render(); 167 | 168 | void set_buffer(); 169 | private: 170 | void draw(); 171 | }; 172 | 173 | struct Gaussian_render : Base_render { 174 | enum Direction { 175 | Horizontal = 0, 176 | Vertical = 1 177 | }; 178 | 179 | Gaussian_render(QOpenGLBuffer* pbuffer, Base_render* in_fbo_renderer, Direction dir); 180 | protected: 181 | void draw(); 182 | Base_render* in_fbo_renderer; 183 | Direction dir; 184 | }; 185 | 186 | struct Gaussian_h_render : Gaussian_render { 187 | Gaussian_h_render(QOpenGLBuffer* pbuffer, Base_render* in_fbo_renderer) : Gaussian_render(pbuffer, in_fbo_renderer, Horizontal) {} 188 | }; 189 | 190 | struct Gaussian_v_render : Gaussian_render { 191 | Gaussian_v_render(QOpenGLBuffer* pbuffer, Base_render* in_fbo_renderer) : Gaussian_render(pbuffer, in_fbo_renderer, Vertical) {} 192 | }; 193 | 194 | struct Painting_render : Base_render { 195 | Painting_render(QOpenGLBuffer* pbuffer); 196 | protected: 197 | void draw(); 198 | }; 199 | 200 | struct Nodes_render : Base_render { 201 | Nodes_render(QOpenGLBuffer* pbuffer); 202 | private: 203 | void draw(); 204 | }; 205 | 206 | struct Edges_render : Render { 207 | Edges_render(); 208 | private: 209 | void draw(); 210 | void set_buffer(); 211 | }; 212 | 213 | struct Control_net_render : Base_render { 214 | Control_net_render(QOpenGLBuffer* pbuffer); 215 | private: 216 | void draw(); 217 | }; 218 | 219 | struct Buffer_binder { 220 | Buffer_binder(QOpenGLBuffer& buf) : buf(buf) { buf.bind(); } 221 | ~Buffer_binder() { buf.release(); } 222 | QOpenGLBuffer& buf; 223 | }; 224 | 225 | class Graphics : public QOpenGLWidget { 226 | Q_OBJECT 227 | public: 228 | Graphics(QWidget *parent = 0); 229 | ~Graphics(); 230 | 231 | QSize minimumSizeHint() const Q_DECL_OVERRIDE; 232 | QSize sizeHint() const Q_DECL_OVERRIDE; 233 | 234 | void render_active(std::string s, bool b) { renders[s]->active = b; update(); } 235 | void toggle_render(std::string s) { renders[s]->active = !renders[s]->active; update(); } 236 | bool is_render_active(std::string s) { return renders[s]->active; } 237 | 238 | QImage grab_render(Size size); 239 | QImage grab_render2(Size size); 240 | uint32_t surface_id_at(int x, int y) { return ((Surface_render*)renders["surface"])->id_at(x, y); } 241 | uint32_t composition_id_at(int x, int y) { return composition->id_at(x, y); } 242 | Vec2 surface_coordinate_at(int x, int y) { return ((Surface_render*)renders["surface"])->coordinate_at(x, y); } 243 | 244 | public slots: 245 | void update() { QWidget::update(); } 246 | void cleanup(); 247 | 248 | protected: 249 | void initializeGL() Q_DECL_OVERRIDE; 250 | void paintGL() Q_DECL_OVERRIDE; 251 | void resizeGL(Size const& size); 252 | void resizeGL(int width, int height) Q_DECL_OVERRIDE; 253 | bool event(QEvent *event) Q_DECL_OVERRIDE; 254 | 255 | 256 | private: 257 | void hover_mouse_event(QHoverEvent* me); 258 | void add_render(Base_render* render, char const* name); 259 | 260 | public: 261 | void draw_scene(); 262 | 263 | void composition_to_fbo(); 264 | 265 | void set_selectables(); 266 | std::map renders; 267 | std::list renders_order; 268 | Composition_render* composition; 269 | Size render_sz; 270 | }; 271 | 272 | #pragma pack(pop) 273 | 274 | 275 | 276 | 277 | -------------------------------------------------------------------------------- /src/graphics/shader.cpp: -------------------------------------------------------------------------------- 1 | #include "shader.h" 2 | #include "globals.h" 3 | 4 | void Framebufferobject::attach_depth_buffer() { 5 | 6 | glGenTextures(1, &depth_id); 7 | glActiveTexture(GL_TEXTURE0); 8 | glBindTexture(GL_TEXTURE_2D, depth_id); 9 | glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, size().width(), size().height(), 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0); 10 | //functions->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 11 | //functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,d GL_CLAMP); 12 | //functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 13 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 14 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 15 | bind(); 16 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_id, 0); 17 | release(); 18 | glBindTexture(GL_TEXTURE_2D, 0); //reset to default texture 19 | } 20 | 21 | void Framebufferobject::attach_id_buffer() { 22 | 23 | glGenTextures(1, &id_id); 24 | glActiveTexture(GL_TEXTURE0); 25 | glBindTexture(GL_TEXTURE_2D, id_id); 26 | glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, size().width(), size().height(), 0, GL_RED_INTEGER, GL_UNSIGNED_INT, 0); 27 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 28 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 29 | bind(); 30 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, id_id, 0); 31 | release(); 32 | glBindTexture(GL_TEXTURE_2D, 0); //reset to default texture 33 | } 34 | 35 | void Framebufferobject::attach_coordinate_buffer() { 36 | 37 | glGenTextures(1, &coordinate_id); 38 | glActiveTexture(GL_TEXTURE0); 39 | glBindTexture(GL_TEXTURE_2D, coordinate_id); 40 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size().width(), size().height(), 0, GL_RG, GL_UNSIGNED_INT, 0); 41 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 42 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 43 | bind(); 44 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, coordinate_id, 0); 45 | release(); 46 | glBindTexture(GL_TEXTURE_2D, 0); //reset to default texture 47 | } 48 | 49 | void Framebufferobject::attach_color2_buffer() { 50 | glGenTextures(1, &color2_id); 51 | glActiveTexture(GL_TEXTURE0); 52 | glBindTexture(GL_TEXTURE_2D, color2_id); 53 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size().width(), size().height(), 0, GL_RGBA, GL_UNSIGNED_INT, 0); 54 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 55 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 56 | bind(); 57 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, color2_id, 0); 58 | release(); 59 | glBindTexture(GL_TEXTURE_2D, 0); //reset to default texture 60 | } 61 | 62 | void Framebufferobject::attach_float_buffer() { 63 | glGenTextures(1, &float_id); 64 | glActiveTexture(GL_TEXTURE0); 65 | glBindTexture(GL_TEXTURE_2D, float_id); 66 | glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, size().width(), size().height(), 0, GL_RED, GL_FLOAT, 0); 67 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 68 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 69 | bind(); 70 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT4, GL_TEXTURE_2D, float_id, 0); 71 | release(); 72 | glBindTexture(GL_TEXTURE_2D, 0); //reset to default texture 73 | } 74 | 75 | Shader_program::Shader_program(std::string v_path, std::string c_path, std::string e_path, std::string g_path, std::string f_path) { 76 | 77 | if(!v_path.empty()) add_shader(v_path, QOpenGLShader::Vertex); 78 | if(!c_path.empty()) add_shader(c_path, QOpenGLShader::TessellationControl); 79 | if(!e_path.empty()) add_shader(e_path, QOpenGLShader::TessellationEvaluation); 80 | if(!g_path.empty()) add_shader(g_path, QOpenGLShader::Geometry); 81 | if(!f_path.empty()) add_shader(f_path, QOpenGLShader::Fragment); 82 | 83 | if(!this->link()) qCritical() << QObject::tr( "Could not link shader program. Log:" ) << this->log(); 84 | } 85 | 86 | void Shader_program::add_shader(std::string path, QOpenGLShader::ShaderTypeBit type) { 87 | if(!this->addShaderFromSourceFile(type, path.c_str())) qCritical() << QObject::tr("Could not compile shader. Log:") << this->log(); 88 | } 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /src/graphics/shader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "GL/glew.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "common/common.h" 10 | 11 | struct Tri_patch; 12 | 13 | struct Framebufferobject : QOpenGLFramebufferObject { 14 | struct Binder { 15 | Binder(QOpenGLFramebufferObject* fbo) : fbo(fbo) { fbo->bind(); } 16 | ~Binder() { fbo->release(); } 17 | QOpenGLFramebufferObject* fbo; 18 | }; 19 | 20 | Framebufferobject(Size const& sz) : QOpenGLFramebufferObject(QSize(sz.w, sz.h)) {} 21 | //Though the QT parent class supports attaching a depth buffer attachment, it does not provide a 22 | //way to get the depth buffer id and bind it to a texture. Hence these additional fields. 23 | GLuint depth_id, 24 | id_id, 25 | coordinate_id, 26 | color2_id, 27 | float_id; 28 | 29 | void attach_depth_buffer(); 30 | void attach_id_buffer(); 31 | void attach_coordinate_buffer(); 32 | void attach_color2_buffer(); 33 | void attach_float_buffer(); 34 | }; 35 | 36 | struct Shader_program : QOpenGLShaderProgram { 37 | struct Binder { 38 | Binder() {} 39 | Binder(Shader_program* p) : program(p) { 40 | program->bind(); 41 | } 42 | ~Binder() { 43 | program->release(); 44 | } 45 | 46 | Shader_program* program; 47 | }; 48 | 49 | struct FBOBinder : Binder { 50 | FBOBinder(Shader_program* p, QOpenGLFramebufferObject* fbo) : framebuffer_object(fbo) { 51 | program = p; 52 | framebuffer_object->bind(); 53 | program->bind(); 54 | } 55 | ~FBOBinder() { 56 | program->release(); 57 | framebuffer_object->release(); 58 | } 59 | 60 | QOpenGLFramebufferObject* framebuffer_object; 61 | }; 62 | 63 | Shader_program(std::string v_path, std::string tc_path, std::string te_path, std::string g_path, std::string f_path); 64 | 65 | private: 66 | void add_shader(std::string path, QOpenGLShader::ShaderTypeBit type); 67 | }; 68 | 69 | -------------------------------------------------------------------------------- /src/graphics/shaders/composition/fragment.glsl: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | layout(location = 1) out uint f_id; 3 | layout(location = 0) out vec4 f_color; 4 | 5 | uniform sampler2D surface_buffer; 6 | uniform sampler2D surface_depth_buffer; 7 | uniform usampler2D surface_id_buffer; 8 | uniform sampler2D surface_color2_buffer; 9 | 10 | uniform sampler2D wireframe_buffer; 11 | uniform sampler2D wireframe_depth_buffer; 12 | 13 | uniform sampler2D control_points_buffer; 14 | uniform sampler2D control_points_depth_buffer; 15 | uniform usampler2D control_points_id_buffer; 16 | 17 | uniform sampler2D control_net_buffer; 18 | uniform sampler2D control_net_depth_buffer; 19 | 20 | uniform sampler2D normals_buffer; 21 | uniform sampler2D normals_depth_buffer; 22 | uniform usampler2D normals_id_buffer; 23 | 24 | uniform sampler2D edges_buffer; 25 | uniform sampler2D edges_depth_buffer; 26 | uniform usampler2D edges_id_buffer; 27 | 28 | uniform sampler2D nodes_buffer; 29 | uniform sampler2D nodes_depth_buffer; 30 | uniform usampler2D nodes_id_buffer; 31 | 32 | uniform sampler2D contour_buffer; 33 | uniform sampler2D contour_depth_buffer; 34 | 35 | uniform sampler2D gaussian_v_buffer; 36 | uniform sampler2D gaussian_v_color2_buffer; 37 | 38 | uniform sampler2D contour_v_buffer; 39 | uniform sampler2D painting_buffer; 40 | 41 | uniform int draw_surface; 42 | uniform int draw_wireframe; 43 | uniform int draw_control_points; 44 | uniform int draw_control_net; 45 | uniform int draw_normals; 46 | uniform int draw_edges; 47 | uniform int draw_nodes; 48 | uniform int draw_painting; 49 | 50 | uniform int draw_cursor; 51 | uniform int draw_flat; 52 | 53 | uniform int draw_gaussian_v; 54 | 55 | uniform vec2 cursor; 56 | uniform vec3 bg_color; 57 | uniform int render_counter; 58 | 59 | uniform float cursor_radius; 60 | 61 | uniform float line_width; 62 | 63 | uniform int H; 64 | uniform int W; 65 | 66 | uniform float zoom; 67 | 68 | uniform float screen_scale_x; 69 | uniform float screen_scale_y; 70 | 71 | uniform float gaussian_scale; 72 | uniform float contrast_scale; 73 | 74 | uniform int mousetool; 75 | uniform int mouse_left; 76 | uniform int mouse_right; 77 | 78 | 79 | in vec2 v_position; 80 | in vec4 gl_FragCoord; 81 | 82 | vec3 semi(vec3 c) { 83 | return vec3( 84 | c.r > 0.5? c.r - 0.5 : c.r + 0.5, 85 | c.g > 0.5? c.g - 0.5 : c.g + 0.5, 86 | c.b > 0.5? c.b - 0.5 : c.b + 0.5); 87 | } 88 | 89 | vec4 semi(vec4 c) { 90 | return vec4(semi(c.rgb), c.a); 91 | } 92 | 93 | vec4 h120(vec4 c) { 94 | return vec4(c.brg, c.a); 95 | } 96 | 97 | vec3 inv(vec3 c) { 98 | return vec3(1.0) -vec3(c); 99 | } 100 | 101 | vec4 inv(vec4 c) { 102 | return vec4(inv(c.rgb), c.a); 103 | } 104 | 105 | 106 | // Gold Noise ©2017-2018 dcerisano@standard3d.com 107 | // - based on the Golden Ratio, PI and Square Root of Two 108 | // - fastest noise generator function 109 | // - works with all chipsets (including low precision) 110 | //precision lowp float; 111 | 112 | float PHI = 1.61803398874989484820459 * 00000.1; // Golden Ratio 113 | float PI = 3.14159265358979323846264 * 00000.1; // PI 114 | float SQ2 = 1.41421356237309504880169 * 10000.0; // Square Root of Two 115 | 116 | float gold_noise(in vec2 coordinate, in float seed){ 117 | return fract(sin(dot(coordinate*(seed+PHI), vec2(PHI, PI)))*SQ2); 118 | } 119 | 120 | float rand(vec2 co){ 121 | return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); 122 | } 123 | 124 | vec3 rgb_noise(vec2 coord, int seed) { 125 | float r = gold_noise(coord, seed), g = gold_noise(coord,r), b = gold_noise(coord,g); 126 | return vec3(r,g,b); 127 | } 128 | 129 | float c_dist(vec4 c) { 130 | //vec4 w = vec4(0.21267, 0.71516, 0.07217, 1); 131 | vec4 w = vec4(1); 132 | vec4 wc = w*c; 133 | return dot(wc,wc); 134 | } 135 | 136 | float vsin(vec2 v1, vec2 v2) { 137 | return v1.x*v2.y - v1.y*v2.x; 138 | } 139 | 140 | void main() { 141 | 142 | vec2 viewport_coord = (v_position + vec2(1.0,1.0)) / 2.0; 143 | vec4 bgcolora = vec4(bg_color, 1); 144 | f_color = bgcolora; 145 | 146 | vec2 p = vec2(viewport_coord - vec2(0.5, 0.5)) * 2.0; 147 | float r = gold_noise(p,render_counter+100), g = gold_noise(p,r), b = gold_noise(p,g); 148 | 149 | /*vec2 rp1 = vec2(vec2(r,g) - vec2(0.5, 0.5)) * 2.0; 150 | vec2 rp2 = vec2(vec2(b, gold_noise(p,b)) - vec2(0.5, 0.5)) * 2.0; 151 | vec4 r_c = texture(surface_buffer, viewport_coord + rp1*rp2*0.1); 152 | f_color = r_c;*/ 153 | //if(int(render_counter*g) % 2 != 0) r = g = b; 154 | //r=round(r); g=round(g); b=round(b); 155 | float al = 0.1; 156 | 157 | 158 | f_color = vec4(vec3(0),1);//vec4(r,g,b, 1)*al + vec4(vec3(0.5),1)*(1.0-al); 159 | 160 | 161 | 162 | 163 | if(draw_surface == 1) 164 | { 165 | f_id = texture(surface_id_buffer, viewport_coord).r; 166 | if(f_id != 0) { 167 | vec4 col; 168 | if(draw_gaussian_v == 0) col = texture(surface_buffer, viewport_coord); 169 | else if(draw_painting == 1) col = texture(painting_buffer, viewport_coord); 170 | else col = texture(gaussian_v_buffer, viewport_coord); 171 | f_color = col*col.a + f_color*(1.0-col.a); 172 | } 173 | //f_color = texture(gaussian_v_buffer, viewport_coord); f_color.a = 1; 174 | } 175 | 176 | if(draw_control_net == 1) 177 | { 178 | vec4 c0 = texture(control_net_buffer, viewport_coord); 179 | vec4 c = vec4(vec3(0.3),1);//semi(f_color); 180 | c.a = c0.a; 181 | float al = c.a; 182 | //f_color = semi(f_color)*al + f_color*(1.0-al);//semi(f_color)*c.a + f_color*(1.0-c.a); 183 | f_color = c*al + f_color*(1.0-al); 184 | } 185 | 186 | if(draw_edges == 1) 187 | { 188 | vec4 c = texture(edges_buffer, viewport_coord); 189 | f_id = texture(edges_id_buffer, viewport_coord).r; 190 | f_color = vec4(1)*c.a + f_color*(1.0-c.a); 191 | //f_color = c*c.a + f_color*(1-c.a); 192 | } 193 | 194 | if(draw_nodes == 1) { 195 | vec4 col = h120(texture(nodes_buffer, viewport_coord)); 196 | col = vec4(1,1,1,col.a); 197 | 198 | //f_color = inv(f_color)*col.a + f_color*(1.0-col.a); 199 | float al = col.a; 200 | f_color = col*al + f_color*(1.0-al); 201 | if(col.a != 0) { 202 | f_id = texture(nodes_id_buffer, viewport_coord).r; 203 | } 204 | } 205 | 206 | if(draw_cursor == 1) { 207 | vec2 p = vec2(vec2(viewport_coord.xy) - vec2(0.5, 0.5)) * 2.0; 208 | vec2 cur = cursor;// / 2 + vec2(0.5,0.5); 209 | float len = length(p - cur); 210 | float r = cursor_radius; 211 | float r2 = 0.002; 212 | float w = 1.0/((W+H)/2); //pixel width 213 | int draw = 0; 214 | draw |= int(len < r+w && len > r-w); 215 | draw |= int(len < r2+w && len > r2-w); 216 | float draw_al = 1; 217 | 218 | if(mousetool == 1) { 219 | if(mouse_left == 1 && mouse_right == 1) 220 | draw |= int(abs(length(p) - length(cur)) < w); 221 | else if(mouse_right == 1) { 222 | //draw |= int(abs(vsin(normalize(cur),p)) < w && dot(normalize(cur), normalize(p)) >= 0 && length(p) <= length(cur)); 223 | draw |= int(abs(vsin(normalize(cur),p)) < w && dot(normalize(cur), normalize(p)) >= 0 && length(p) <= length(cur)); 224 | } 225 | 226 | } 227 | 228 | if(draw == 1) { 229 | float r = gold_noise(p,render_counter), g = gold_noise(p,r), b = gold_noise(p,g); 230 | f_color = vec4(r,g,b,1)*draw_al + f_color*(1-draw_al); 231 | } 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /src/graphics/shaders/composition/vertex.glsl: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | in vec2 position; 4 | //in vec2 texcoord; 5 | out vec2 v_position; 6 | 7 | void main() { 8 | gl_Position = vec4(position, 0.0, 1.0); 9 | v_position = position; 10 | } 11 | -------------------------------------------------------------------------------- /src/graphics/shaders/controlnet/fragment.glsl: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | //layout(location = 0, index = 0) out vec4 f_color; 3 | layout(location = 0) out vec4 f_color; 4 | 5 | uniform mat4 modelview; 6 | uniform float line_width; 7 | uniform float screen_scale_x; 8 | uniform float screen_scale_y; 9 | uniform float zoom; 10 | uniform int W; 11 | uniform int H; 12 | 13 | in vec4 v_c; 14 | in float v_w; 15 | in vec3 v_v; 16 | 17 | flat in vec3 v_v0; 18 | flat in vec3 v_v1; 19 | flat in vec3 v_v2; 20 | 21 | in vec3 v_pos; 22 | 23 | flat in vec3 v_ew; 24 | flat in vec3 v_nw; 25 | 26 | float min3(vec3 a3) { 27 | return min(min(a3.x, a3.y), a3.z); 28 | } 29 | 30 | float psin(vec2 v1, vec2 v2) { 31 | vec2 v1v2 = v2 - v1; 32 | vec2 v1p = vec2(v_pos) - v1; 33 | return (v1v2.x*v1p.y - v1v2.y*v1p.x) / length(v1v2); 34 | } 35 | 36 | void main(void) { 37 | //g_colors[0]*(p.x) + g_colors[1]*(p.y) + g_colors[2]*(p.z); 38 | f_color = v_c; 39 | f_color.a = 1; 40 | 41 | float sinab = psin(vec2(v_v0), vec2(v_v1)); 42 | float sinbc = psin(vec2(v_v1), vec2(v_v2)); 43 | float sinca = psin(vec2(v_v2), vec2(v_v0)); 44 | 45 | float WH = float(W+H)/2; 46 | float lw = line_width / zoom * (1.0/((screen_scale_x+screen_scale_y)/2.0)) * 1/WH; 47 | 48 | bool dis = true; 49 | if((sinab < lw) || (sinbc < lw) || (sinca < lw)) dis = false; 50 | 51 | if(dis) 52 | discard; 53 | } 54 | -------------------------------------------------------------------------------- /src/graphics/shaders/controlnet/geometry.glsl: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | layout(triangles) in; 4 | layout(triangle_strip, max_vertices = 3) out; 5 | //layout(line_strip, max_vertices = 3) out; 6 | 7 | in vec3 e_patch_coord[3]; 8 | in float e_w[3]; 9 | 10 | out vec3 g_primitive_coord; 11 | out vec3 g_patch_coord; 12 | 13 | out float g_w; 14 | 15 | void main(void) { 16 | gl_Position = gl_in[0].gl_Position; 17 | g_patch_coord = e_patch_coord[0]; 18 | g_primitive_coord = vec3(1, 0, 0); 19 | g_w = e_w[0]; 20 | EmitVertex(); 21 | 22 | gl_Position = gl_in[1].gl_Position; 23 | g_patch_coord = e_patch_coord[1]; 24 | g_primitive_coord = vec3(0, 1, 0); 25 | g_w = e_w[1]; 26 | EmitVertex(); 27 | 28 | gl_Position = gl_in[2].gl_Position; 29 | g_patch_coord = e_patch_coord[2]; 30 | g_primitive_coord = vec3(0, 0, 1); 31 | g_w = e_w[2]; 32 | EmitVertex(); 33 | 34 | EndPrimitive(); 35 | } 36 | -------------------------------------------------------------------------------- /src/graphics/shaders/controlnet/tesscontrol.glsl: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | #define ID gl_InvocationID 4 | 5 | layout(vertices = 3) out; 6 | 7 | in float v_w[]; 8 | out float c_w[]; 9 | 10 | void main(void) { 11 | gl_out[ID].gl_Position = gl_in[ID].gl_Position; 12 | c_w[ID] = v_w[ID]; 13 | 14 | int tess = 1; 15 | 16 | //only needs to be written once 17 | if(gl_InvocationID == 0) 18 | { 19 | gl_TessLevelOuter[0] = tess; 20 | gl_TessLevelOuter[1] = tess; 21 | gl_TessLevelOuter[2] = tess; 22 | gl_TessLevelInner[0] = tess; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/graphics/shaders/controlnet/tesseval.glsl: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | layout(triangles, equal_spacing, ccw) in; 4 | 5 | uniform mat4 modelview; 6 | uniform mat4 projection; 7 | 8 | in float c_w[]; 9 | 10 | out float e_w; 11 | 12 | out vec3 e_patch_coord; 13 | 14 | void main() { 15 | vec4 pos = 16 | gl_TessCoord.x * gl_in[0].gl_Position + 17 | gl_TessCoord.y * gl_in[1].gl_Position + 18 | gl_TessCoord.z * gl_in[2].gl_Position; 19 | 20 | gl_Position = projection * modelview * pos; 21 | e_patch_coord = gl_TessCoord; 22 | 23 | e_w = c_w[1] * (1-gl_TessCoord.x) 24 | + c_w[2] * (1-gl_TessCoord.y) 25 | + c_w[0] * (1-gl_TessCoord.z); 26 | } 27 | -------------------------------------------------------------------------------- /src/graphics/shaders/controlnet/vertex.glsl: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | uniform mat4 modelview; 4 | uniform mat4 projection; 5 | 6 | in uint id; 7 | 8 | in vec3 position; 9 | in vec4 color; 10 | in uint l; 11 | in float weight; 12 | in vec3 v0; 13 | in vec3 v1; 14 | in vec3 v2; 15 | 16 | in vec3 ew; 17 | in vec3 nw; 18 | 19 | out vec4 v_c; 20 | out vec3 v_v; 21 | flat out vec3 v_v0; 22 | flat out vec3 v_v1; 23 | flat out vec3 v_v2; 24 | out vec3 v_pos; 25 | 26 | void main(void) { 27 | 28 | gl_Position = projection * modelview * vec4(position, 1.0); 29 | v_c = color; 30 | v_v0 = vec3(projection * modelview * vec4(v0, 1.0)); 31 | v_v1 = vec3(projection * modelview * vec4(v1, 1.0)); 32 | v_v2 = vec3(projection * modelview * vec4(v2, 1.0)); 33 | v_pos = vec3(projection * modelview * vec4(position, 1.0)); 34 | 35 | v_v = l == 0? vec3(1,0,0) : l == 1? vec3(0,1,0) : vec3(0,0,1); 36 | } 37 | -------------------------------------------------------------------------------- /src/graphics/shaders/edges/fragment.glsl: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | //layout(location = 0, index = 0) out vec4 f_color; 4 | layout(location = 2) out vec2 f_coordinate; 5 | layout(location = 1) out uint f_id; 6 | layout(location = 0) out vec4 f_color; 7 | 8 | uniform mat4 modelview; 9 | uniform float line_width; 10 | uniform int W; 11 | uniform int H; 12 | uniform float screen_scale_x; 13 | uniform float screen_scale_y; 14 | uniform float zoom; 15 | 16 | in vec4 v_c; 17 | in float v_w; 18 | in vec3 v_v; 19 | 20 | flat in vec3 v_v0; 21 | flat in vec3 v_v1; 22 | flat in vec3 v_v2; 23 | in vec3 v_pos; 24 | 25 | flat in vec3 v_ew; 26 | flat in vec3 v_nw; 27 | 28 | flat in uint v_id; 29 | 30 | 31 | float min3(vec3 a3) { 32 | return min(min(a3.x, a3.y), a3.z); 33 | } 34 | 35 | int minlabel(vec3 a3) { 36 | if(a3.x < a3.y && a3.x < a3.z) return 0; 37 | if(a3.y < a3.z && a3.y < a3.x) return 1; 38 | if(a3.z < a3.x && a3.z < a3.y) return 2; 39 | } 40 | 41 | float psin(vec2 v1, vec2 v2) { 42 | vec2 v1v2 = v2 - v1; 43 | vec2 v1p = vec2(v_pos) - v1; 44 | return (v1v2.x*v1p.y - v1v2.y*v1p.x) / length(v1v2); 45 | } 46 | 47 | float pdist(vec2 v) { 48 | vec2 vp = vec2(v_pos) - v; 49 | return length(vp); 50 | } 51 | 52 | void main(void) { 53 | f_id = v_id; 54 | f_coordinate = vec2(v_v.xy); 55 | f_color = v_c; 56 | 57 | float sinab = psin(vec2(v_v0), vec2(v_v1)); 58 | float sinbc = psin(vec2(v_v1), vec2(v_v2)); 59 | float sinca = psin(vec2(v_v2), vec2(v_v0)); 60 | 61 | float WH = float(W+H)/2; 62 | float lw = 1.0 * line_width / zoom * (1.0/((screen_scale_x+screen_scale_y)/2.0)) * 1/WH; 63 | //float lw = 4.0 / zoom * (1.0/((screen_scale_x+screen_scale_y)/2.0)) * 1/WH; 64 | 65 | vec3 sins = vec3(sinab, sinbc, sinca); 66 | float min = minlabel(sins); 67 | 68 | bool dis = true; 69 | /* 70 | if(v_ew.x > 0 && sinab < lw) dis = false; 71 | if(v_ew.y > 0 && sinbc < lw) dis = false; 72 | if(v_ew.z > 0 && sinca < lw) dis = false; 73 | */ 74 | 75 | vec2 ab = vec2(v_v1 - v_v0), bc = vec2(v_v2 - v_v1), ca = vec2(v_v0 - v_v2); 76 | vec2 av = vec2(v_pos - v_v0), bv = vec2(v_pos - v_v1), cv = vec2(v_pos - v_v2); 77 | vec2 ab_u = normalize(ab), bc_u = normalize(bc), ca_u = normalize(ca), av_u = normalize(av), bv_u = normalize(bv), cv_u = normalize(cv); 78 | if((v_ew.x > 0 && sinab < lw) && dot(ab_u, av_u) > 0 && dot(bv_u, -ab_u) > 0) dis = false; 79 | if((v_ew.y > 0 && sinbc < lw) && dot(bc_u, bv_u) > 0 && dot(cv_u, -bc_u) > 0) dis = false; 80 | if((v_ew.z > 0 && sinca < lw) && dot(ca_u, cv_u) > 0 && dot(av_u, -ca_u) > 0) dis = false; 81 | 82 | /* 83 | if(v_nw.x > 0 && pdist(vec2(v_v0)) < lw) dis = false; 84 | if(v_nw.y > 0 && pdist(vec2(v_v1)) < lw) dis = false; 85 | if(v_nw.z > 0 && pdist(vec2(v_v2)) < lw) dis = false; 86 | */ 87 | 88 | if(dis) 89 | f_color.a = 0; 90 | } 91 | -------------------------------------------------------------------------------- /src/graphics/shaders/edges/geometry.glsl: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | layout(triangles) in; 4 | layout(triangle_strip, max_vertices = 3) out; 5 | //layout(line_strip, max_vertices = 3) out; 6 | 7 | in vec3 e_patch_coord[3]; 8 | in vec4 e_c[3]; 9 | in float e_w[3]; 10 | 11 | in vec4 e_c0[3]; 12 | in vec4 e_c1[3]; 13 | in vec4 e_c2[3]; 14 | in float e_w0[3]; 15 | in float e_w1[3]; 16 | in float e_w2[3]; 17 | 18 | out vec3 g_primitive_coord; 19 | out vec3 g_patch_coord; 20 | out vec4 g_c; 21 | out float g_w; 22 | out vec4 g_colors[3]; 23 | out float g_weights[3]; 24 | out vec4 g_vert_pos[3]; 25 | 26 | void common_out() { 27 | g_vert_pos[0] = gl_in[0].gl_Position;//gl_in[0].gl_Position; 28 | g_vert_pos[1] = gl_in[1].gl_Position; 29 | g_vert_pos[2] = gl_in[2].gl_Position; 30 | g_colors[0] = e_c0[0]; 31 | g_colors[1] = e_c1[0]; 32 | g_colors[2] = e_c2[0]; 33 | g_weights[0] = e_w0[0]; 34 | g_weights[1] = e_w1[0]; 35 | g_weights[2] = e_w2[0]; 36 | } 37 | 38 | void main(void) { 39 | gl_Position = gl_in[0].gl_Position; 40 | g_patch_coord = e_patch_coord[0]; 41 | g_primitive_coord = vec3(1, 0, 0); 42 | g_c = e_c[0]; 43 | g_w = e_w[0]; 44 | common_out(); 45 | EmitVertex(); 46 | 47 | gl_Position = gl_in[1].gl_Position; 48 | g_patch_coord = e_patch_coord[1]; 49 | g_primitive_coord = vec3(0, 1, 0); 50 | g_c = e_c[1]; 51 | g_w = e_w[1]; 52 | common_out(); 53 | EmitVertex(); 54 | 55 | gl_Position = gl_in[2].gl_Position; 56 | g_patch_coord = e_patch_coord[2]; 57 | g_primitive_coord = vec3(0, 0, 1); 58 | g_c = e_c[2]; 59 | g_w = e_w[2]; 60 | common_out(); 61 | EmitVertex(); 62 | 63 | EndPrimitive(); 64 | } 65 | -------------------------------------------------------------------------------- /src/graphics/shaders/edges/tesscontrol.glsl: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | #define ID gl_InvocationID 4 | 5 | layout(vertices = 3) out; 6 | 7 | in vec4 v_c[]; 8 | in float v_w[]; 9 | out vec4 c_c[]; 10 | out float c_w[]; 11 | 12 | void main(void) { 13 | gl_out[ID].gl_Position = gl_in[ID].gl_Position; 14 | c_c[ID] = v_c[ID]; 15 | c_w[ID] = v_w[ID]; 16 | 17 | int tess = 1; 18 | 19 | //only needs to be written once 20 | if(gl_InvocationID == 0) 21 | { 22 | gl_TessLevelOuter[0] = tess; 23 | gl_TessLevelOuter[1] = tess; 24 | gl_TessLevelOuter[2] = tess; 25 | gl_TessLevelInner[0] = tess; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/graphics/shaders/edges/tesseval.glsl: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | layout(triangles, equal_spacing, ccw) in; 4 | 5 | uniform mat4 modelview; 6 | uniform mat4 projection; 7 | 8 | in vec4 c_c[]; 9 | in float c_w[]; 10 | 11 | out vec4 e_c; 12 | out float e_w; 13 | 14 | out vec3 e_patch_coord; 15 | 16 | out vec4 e_c0; 17 | out vec4 e_c1; 18 | out vec4 e_c2; 19 | out float e_w0; 20 | out float e_w1; 21 | out float e_w2; 22 | 23 | void main() { 24 | vec4 pos = 25 | gl_TessCoord.x * gl_in[0].gl_Position + 26 | gl_TessCoord.y * gl_in[1].gl_Position + 27 | gl_TessCoord.z * gl_in[2].gl_Position; 28 | 29 | gl_Position = projection * modelview * pos; 30 | e_patch_coord = gl_TessCoord; 31 | 32 | e_c0 = c_c[0]; e_c1 = c_c[1]; e_c2 = c_c[2]; 33 | e_w0 = c_w[0]; e_w1 = c_w[1]; e_w2 = c_w[2]; 34 | 35 | e_c = c_c[0] * (gl_TessCoord.x) 36 | + c_c[1] * (gl_TessCoord.y) 37 | + c_c[2] * (gl_TessCoord.z); 38 | 39 | e_w = c_w[0] * (gl_TessCoord.x) 40 | + c_w[1] * (gl_TessCoord.y) 41 | + c_w[2] * (gl_TessCoord.z); 42 | } 43 | -------------------------------------------------------------------------------- /src/graphics/shaders/edges/vertex.glsl: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | uniform mat4 modelview; 4 | uniform mat4 projection; 5 | 6 | in uint id; 7 | 8 | in vec3 position; 9 | in vec4 color; 10 | in uint l; 11 | in vec3 v0; 12 | in vec3 v1; 13 | in vec3 v2; 14 | 15 | in vec3 ew; 16 | in vec3 nw; 17 | 18 | flat out uint v_id; 19 | 20 | out vec4 v_c; 21 | out vec3 v_v; 22 | flat out vec3 v_v0; 23 | flat out vec3 v_v1; 24 | flat out vec3 v_v2; 25 | out vec3 v_pos; 26 | 27 | flat out vec3 v_ew; 28 | flat out vec3 v_nw; 29 | 30 | void main(void) { 31 | 32 | v_id = id; 33 | gl_Position = projection * modelview * vec4(position, 1.0); 34 | v_c = color; 35 | v_v = l == 0? vec3(1,0,0) : l == 1? vec3(0,1,0) : vec3(0,0,1); 36 | 37 | v_v0 = vec3(projection * modelview * vec4(v0, 1.0)); 38 | v_v1 = vec3(projection * modelview * vec4(v1, 1.0)); 39 | v_v2 = vec3(projection * modelview * vec4(v2, 1.0)); 40 | v_pos = vec3(projection * modelview * vec4(position, 1.0)); 41 | 42 | v_ew = ew; 43 | v_nw = nw; 44 | } 45 | -------------------------------------------------------------------------------- /src/graphics/shaders/gaussian/fragment.glsl: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | layout(location = 3) out vec4 f_color2; 3 | layout(location = 2) out vec2 f_coordinate; 4 | layout(location = 1) out uint f_id; 5 | layout(location = 0) out vec4 f_color; 6 | 7 | uniform sampler2D in_buffer; 8 | uniform sampler2D in_color2_buffer; 9 | uniform sampler2D surface_color2_buffer; 10 | uniform usampler2D surface_id_buffer; 11 | 12 | uniform int H; 13 | uniform int W; 14 | 15 | uniform int dir; 16 | 17 | uniform float zoom; 18 | uniform float screen_scale_x; 19 | uniform float screen_scale_y; 20 | 21 | uniform float gaussian_size; 22 | uniform float min_gaussian_q; 23 | 24 | in vec2 v_position; 25 | in vec4 gl_FragCoord; 26 | 27 | //gaussian code from: https://dsp.stackexchange.com/questions/23460/how-to-calculate-gaussian-kernel-for-a-small-support-size 28 | 29 | void main() { 30 | vec2 viewport_coord = (v_position + vec2(1.0,1.0)) / 2.0; 31 | 32 | uint id = texture(surface_id_buffer, viewport_coord).r; 33 | if(id <= 0) 34 | discard; 35 | 36 | vec4 params = texture(surface_color2_buffer, viewport_coord); 37 | vec4 c = texture(in_buffer, viewport_coord); 38 | vec4 p = texture(in_color2_buffer, viewport_coord); 39 | 40 | float scr_scaling = (screen_scale_x + screen_scale_x) / 2.0; 41 | //float blur_weight = params.r; 42 | float blur_weight = (dir == 0)? params.r * params.b : params.r * params.a; 43 | //float blur_weight = (dir == 0)? params.b : params.a; 44 | float blur_scaling = zoom * scr_scaling;// * blur_weight; 45 | 46 | /*{ 47 | float al = pow(blur_weight, 1); 48 | float interpolated_size = gaussian_size * al + gaussian_size*min_gaussian_q*(1.0-al); 49 | int gaussianBlurRadius = int(ceil(blur_scaling * interpolated_size*1)); 50 | float stdToRadiusFactor = 3.0; 51 | float gaussianKernelStd = gaussianBlurRadius * stdToRadiusFactor; 52 | 53 | 54 | float WH = float(W + H) / 2.0; 55 | float neigh = 1.0/WH; 56 | vec2 stepdir = (dir == 0)? vec2(neigh, 0) : vec2(0, neigh); 57 | 58 | vec4 p_sum = p; 59 | float pw_sum = 1; 60 | 61 | if(gaussianBlurRadius > 0) { 62 | for(int i = 0; i < gaussianBlurRadius; ++i) { 63 | float exponent = -(float(i*i) / (2.0 * gaussianKernelStd * gaussianKernelStd)); 64 | float w = exp(exponent); 65 | vec2 step = stepdir * i; 66 | 67 | vec2 sample1_p = viewport_coord + step; 68 | vec4 p1 = texture(in_color2_buffer, sample1_p); 69 | uint id1 = texture(surface_id_buffer, sample1_p).r; 70 | if(id1 > 0) { 71 | p_sum += p1; 72 | pw_sum += w; 73 | } 74 | 75 | vec2 sample2_p = viewport_coord - step; 76 | vec4 p2 = texture(in_color2_buffer, sample2_p); 77 | uint id2 = texture(surface_id_buffer, sample2_p).r; 78 | if(id2 > 0) { 79 | p_sum += p2; 80 | pw_sum += w; 81 | } 82 | } 83 | } 84 | f_color2 = p_sum / pw_sum; 85 | }*/ 86 | f_color2 = texture(in_color2_buffer, viewport_coord); 87 | 88 | 89 | float al = pow(blur_weight, 1); 90 | float interpolated_size = gaussian_size * al + gaussian_size*min_gaussian_q*(1.0-al); 91 | int gaussianBlurRadius = int(ceil(blur_scaling * interpolated_size)); 92 | float stdToRadiusFactor = 3.0; 93 | float gaussianKernelStd = gaussianBlurRadius * stdToRadiusFactor; 94 | 95 | 96 | float WH = float(W + H) / 2.0; 97 | float neigh = 1.0/WH; 98 | vec2 stepdir = (dir == 0)? vec2(neigh, 0) : vec2(0, neigh); 99 | 100 | vec3 c_sum = c.rgb * c.a; 101 | float cw_sum = c.a; 102 | float a_sum = c.a; 103 | float aw_sum = 1; 104 | 105 | if(gaussianBlurRadius > 0) { 106 | for(int i = 0; i < gaussianBlurRadius; ++i) { 107 | float exponent = -(float(i*i) / (2.0 * gaussianKernelStd * gaussianKernelStd)); 108 | float w = exp(exponent); 109 | vec2 step = stepdir * i; 110 | 111 | vec2 sample1_p = viewport_coord + step; 112 | vec4 c1 = texture(in_buffer, sample1_p); 113 | uint id1 = texture(surface_id_buffer, sample1_p).r; 114 | if(id1 > 0) { 115 | float c1w = w*c1.a; 116 | c_sum += c1.rgb*c1w; 117 | cw_sum += c1w; 118 | a_sum += c1.a; 119 | aw_sum += w; 120 | } 121 | 122 | vec2 sample2_p = viewport_coord - step; 123 | vec4 c2 = texture(in_buffer, sample2_p); 124 | uint id2 = texture(surface_id_buffer, sample2_p).r; 125 | if(id2 > 0) { 126 | float c2w = w*c2.a; 127 | c_sum += c2.rgb*c2w; 128 | cw_sum += c2w; 129 | a_sum += c2.a; 130 | aw_sum += w; 131 | } 132 | } 133 | } 134 | 135 | f_color.rgb = c_sum / cw_sum; 136 | f_color.a = a_sum / aw_sum; 137 | 138 | } 139 | -------------------------------------------------------------------------------- /src/graphics/shaders/gaussian/vertex.glsl: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | in vec2 position; 4 | out vec2 v_position; 5 | 6 | void main() { 7 | gl_Position = vec4(position, 0.0, 1.0); 8 | v_position = position; 9 | } 10 | -------------------------------------------------------------------------------- /src/graphics/shaders/normals/fragment.glsl: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | layout(location = 0, index = 0) out vec4 f_color; 4 | layout(location = 1) out uint f_id; 5 | 6 | flat in uint v_id; 7 | 8 | void main(void) { 9 | f_id = v_id; 10 | f_color = vec4(1.); 11 | } 12 | -------------------------------------------------------------------------------- /src/graphics/shaders/normals/vertex.glsl: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | uniform mat4 modelview; 4 | uniform mat4 projection; 5 | 6 | in vec3 position; 7 | in uint id; 8 | 9 | flat out uint v_id; 10 | 11 | void main(void) { 12 | gl_Position = projection * modelview * vec4(position, 1.0); 13 | v_id = id; 14 | } 15 | -------------------------------------------------------------------------------- /src/graphics/shaders/painting/fragment.glsl: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | layout(location = 0) out vec4 f_color; 3 | 4 | uniform sampler2D surface_buffer; 5 | uniform sampler2D surface_color2_buffer; 6 | uniform usampler2D surface_id_buffer; 7 | uniform sampler2D gaussian_v_buffer; 8 | uniform sampler2D gaussian_v_color2_buffer; 9 | 10 | uniform int draw_gaussian_v; 11 | 12 | uniform int H; 13 | uniform int W; 14 | 15 | uniform int dir; 16 | 17 | uniform float zoom; 18 | uniform float screen_scale_x; 19 | uniform float screen_scale_y; 20 | 21 | uniform float gaussian_size; 22 | uniform float min_gaussian_q; 23 | uniform float contrast_scale; 24 | 25 | in vec2 v_position; 26 | in vec4 gl_FragCoord; 27 | 28 | //gaussian code from: https://dsp.stackexchange.com/questions/23460/how-to-calculate-gaussian-kernel-for-a-small-support-size 29 | 30 | 31 | float c_dist(vec4 f, vec4 s) { 32 | return sqrt(((s.r*s.a-f.r*f.a)*(s.r*s.a-f.r*f.a) + (s.g*s.a-f.g*f.a)*(s.g*s.a-f.g*f.a) + (s.b*s.a-f.b*f.a)*(s.b*s.a-f.b*f.a))/3.0); 33 | } 34 | 35 | 36 | /*float c_dist(vec4 c) { 37 | //return 38 | //vec4 w = vec4(0.21267, 0.71516, 0.07217, 1); 39 | vec3 w = vec3(1); 40 | vec3 wc = w.rgb*c.rgb; 41 | return pow(dot(wc,wc)/3.0,0.5); 42 | }*/ 43 | 44 | void main() 45 | { 46 | vec2 viewport_coord = (v_position + vec2(1.0,1.0)) / 2.0; 47 | 48 | uint id = texture(surface_id_buffer, viewport_coord).r; 49 | if(id <= 0) 50 | discard; 51 | 52 | vec4 surface_c = texture(surface_buffer, viewport_coord); 53 | 54 | vec4 col = surface_c; 55 | 56 | if(draw_gaussian_v == 1) { 57 | vec4 gaussian_c = texture(gaussian_v_buffer, viewport_coord); 58 | //vec4 params = texture(surface_color2_buffer, viewport_coord); 59 | vec4 params = texture(gaussian_v_color2_buffer, viewport_coord); 60 | 61 | col = gaussian_c; 62 | 63 | 64 | float scr_scaling = (screen_scale_x + screen_scale_x) / 2.0; 65 | //float blur_weight = params.r; 66 | float blur_weight = (dir == 0)? params.r * params.b : params.r * params.a; 67 | //float blur_weight = (dir == 0)? params.b : params.a; 68 | float blur_scaling = zoom * scr_scaling;// * blur_weight; 69 | 70 | float al = pow(blur_weight, 1); 71 | float interpolated_size = gaussian_size * al + gaussian_size*min_gaussian_q*(1.0-al); 72 | int gaussianBlurRadius = int(ceil(blur_scaling * interpolated_size)); 73 | float stdToRadiusFactor = 3.0; 74 | float gaussianKernelStd = gaussianBlurRadius * stdToRadiusFactor; 75 | 76 | float contrast_weight = params.g; 77 | float contrast = (contrast_scale);//* scr_scaling; 78 | 79 | if(gaussianBlurRadius > 0) { 80 | vec4 closest_c = surface_c; 81 | float min_dist = 1.0; 82 | 83 | vec4 goal = gaussian_c; 84 | 85 | float WH = float(W + H) / 2.0; 86 | float neigh = 1.0/WH; 87 | vec2 stepdirh = vec2(neigh, 0); 88 | vec2 stepdirv = vec2(0, neigh); 89 | 90 | //jump pixels when zoomed in for faster rendering but limit it when zoomed out. 91 | int stepsz = int(max(1.0, sqrt(zoom))); 92 | 93 | float cw = contrast_weight; 94 | 95 | vec3 c_sum = vec3(0); 96 | float cw_sum = 0; 97 | float a_sum = 0; 98 | float aw_sum = 0; 99 | 100 | float max_dist = 0; 101 | float dist_sum = 0; 102 | 103 | 104 | if(false) { 105 | int stepsz2 = stepsz; 106 | int radius2 = gaussianBlurRadius; 107 | int count = 0; 108 | for(int i = -radius2; i < radius2; i += stepsz2) { 109 | for(int j = -radius2; j < radius2; j += stepsz2, ++count) { 110 | vec2 step = stepdirh * i + stepdirv * j; 111 | vec2 sample1_p = viewport_coord + step; 112 | vec4 c1 = texture(surface_buffer, sample1_p); 113 | uint id1 = texture(surface_id_buffer, sample1_p).r; 114 | if(id1 > 0) { 115 | float dist = c_dist(goal, c1);// * w; 116 | if(dist < min_dist) { 117 | closest_c = c1; 118 | min_dist = dist; 119 | } 120 | dist_sum += dist; 121 | } 122 | } 123 | } 124 | 125 | al = contrast_weight;//*(1.0 - pow(c_dist(goal - closest_c),2));//contrast_weight; 126 | col = closest_c * al + gaussian_c * (1-al); 127 | } else { 128 | int stepsz2 = stepsz; 129 | int radius2 = gaussianBlurRadius; 130 | 131 | int count = 0; 132 | for(int i = -radius2; i < radius2; i += stepsz2) { 133 | for(int j = -radius2; j < radius2; j += stepsz2, ++count) { 134 | vec2 step = stepdirh * i + stepdirv * j; 135 | vec2 sample1_p = viewport_coord + step; 136 | vec4 c1 = texture(surface_buffer, sample1_p); 137 | uint id1 = texture(surface_id_buffer, sample1_p).r; 138 | if(id1 > 0) { 139 | //float w = 1 - sqrt(i*i + j*j) / (radius2); 140 | float dist = c_dist(goal, c1); 141 | 142 | if(dist > max_dist) { 143 | max_dist = dist; 144 | } 145 | 146 | if(dist < min_dist) { 147 | closest_c = c1; 148 | min_dist = dist; 149 | } 150 | dist_sum += dist; 151 | } 152 | } 153 | } 154 | dist_sum /= float(count); 155 | 156 | for(int count = 0, i = -gaussianBlurRadius; i < gaussianBlurRadius; i += stepsz) { 157 | for(int j = -gaussianBlurRadius; j < gaussianBlurRadius; j += stepsz, ++count) { 158 | vec2 step = stepdirh * i + stepdirv * j; 159 | float exp_w = -(pow((i*j),2) / (2.0 * gaussianKernelStd * gaussianKernelStd)); 160 | vec2 sample1_p = viewport_coord + step; 161 | vec4 c1 = texture(surface_buffer, sample1_p); 162 | vec4 g1 = texture(gaussian_v_buffer, sample1_p); 163 | uint id1 = texture(surface_id_buffer, sample1_p).r; 164 | if(id1 > 0) { 165 | //float dist = (c_dist(goal, c1) - min_dist) / (max_dist - min_dist); 166 | float dist = (c_dist(goal, c1)) / (max_dist); 167 | 168 | float exp_d = -dist * contrast; 169 | float exp_gd = exp_d * cw + exp_w * (1-cw); 170 | float w = exp(exp_gd); 171 | 172 | float c1w = w*c1.a; 173 | c_sum += c1.rgb*c1w; 174 | cw_sum += c1w; 175 | a_sum += c1.a; 176 | aw_sum += w; 177 | } 178 | } 179 | } 180 | 181 | const float epsilon = 0.00000001; 182 | if(cw_sum > epsilon) { 183 | col.rgb = c_sum / cw_sum; 184 | col.a = a_sum / aw_sum; 185 | } else { 186 | col = closest_c;//vec4(1,1,0,1); 187 | } 188 | } 189 | } 190 | } 191 | f_color = col; 192 | } 193 | -------------------------------------------------------------------------------- /src/graphics/shaders/painting/vertex.glsl: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | in vec2 position; 4 | //in vec2 texcoord; 5 | out vec2 v_position; 6 | 7 | void main() { 8 | gl_Position = vec4(position, 0.0, 1.0); 9 | v_position = position; 10 | } 11 | -------------------------------------------------------------------------------- /src/graphics/shaders/pickable/fragment.glsl: -------------------------------------------------------------------------------- 1 | #version 420 2 | //layout(binding=0) uniform sampler2D surface_buffer; 3 | //layout(binding=1) uniform sampler2D wireframe_buffer; 4 | 5 | uniform sampler2D surface_buffer; 6 | uniform sampler2D wireframe_buffer; 7 | uniform sampler2D control_points_buffer; 8 | uniform sampler2D control_nets_buffer; 9 | 10 | uniform sampler2D surface_depth_buffer; 11 | uniform sampler2D control_points_depth_buffer; 12 | uniform sampler2D control_net_depth_buffer; 13 | uniform sampler2D wireframe_depth_buffer; 14 | 15 | uniform int draw_surface; 16 | uniform int draw_wireframe; 17 | uniform int draw_control_points; 18 | uniform int draw_control_net; 19 | uniform vec3 bg_color; 20 | in vec2 v_position; 21 | in vec4 gl_FragCoord; 22 | 23 | out vec4 f_color; 24 | 25 | vec3 semi(vec3 c) { 26 | return vec3( 27 | c.r > 0.5? c.r - 0.5 : c.r + 0.5, 28 | c.g > 0.5? c.g - 0.5 : c.g + 0.5, 29 | c.b > 0.5? c.b - 0.5 : c.b + 0.5); 30 | } 31 | 32 | vec4 semi(vec4 c) { 33 | return vec4(semi(c.rgb), c.a); 34 | } 35 | 36 | vec4 h120(vec4 c) { 37 | return vec4(c.brg, c.a); 38 | } 39 | 40 | vec3 inv(vec3 c) { 41 | return vec3(1.0) -vec3(c); 42 | } 43 | 44 | vec4 inv(vec4 c) { 45 | return vec4(inv(c.rgb), c.a); 46 | } 47 | 48 | 49 | void main() { 50 | 51 | vec2 viewport_coord = (v_position + vec2(1.0,1.0)) / 2.0; 52 | f_color = vec4(bg_color, 1.0); 53 | 54 | if(draw_surface == 1) { 55 | vec4 c = texture(surface_buffer, viewport_coord); 56 | f_color = c*c.a + f_color*(1.0-c.a); 57 | } 58 | 59 | if(draw_control_net == 1) { 60 | vec4 db_surface = texture(surface_depth_buffer, viewport_coord); 61 | vec4 db_ctrl_wf = texture(control_net_depth_buffer, viewport_coord); 62 | vec4 c = texture(control_nets_buffer, viewport_coord); 63 | 64 | if(draw_surface == 0 || db_ctrl_wf.r < db_surface.r) { 65 | f_color = h120(inv(f_color))*c.a + f_color*(1.0-c.a); 66 | } 67 | } 68 | 69 | if(draw_wireframe == 1) { 70 | vec4 db_surface = texture(surface_depth_buffer, viewport_coord); 71 | vec4 db_wireframe = texture(wireframe_depth_buffer, viewport_coord); 72 | if(draw_surface == 0 || db_wireframe.r <= db_surface.r) { 73 | vec4 c = texture(wireframe_buffer, viewport_coord); 74 | f_color = c*c.a + f_color*(1.0-c.a); 75 | } 76 | } 77 | 78 | if(draw_control_points == 1) { 79 | vec4 cds = texture(surface_depth_buffer, viewport_coord); 80 | vec4 cdc = texture(control_points_depth_buffer, viewport_coord); 81 | vec4 c = texture(control_points_buffer, viewport_coord); 82 | 83 | if(draw_surface == 0 || cdc.r < cds.r) { 84 | f_color = semi(f_color)*c.a + f_color*(1.0-c.a); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/graphics/shaders/pickable/vertex.glsl: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | in vec2 position; 4 | //in vec2 texcoord; 5 | out vec2 v_position; 6 | 7 | void main() { 8 | gl_Position = vec4(position, 0.0, 1.0); 9 | v_position = position; 10 | } 11 | -------------------------------------------------------------------------------- /src/graphics/shaders/points/fragment.glsl: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | layout(location = 0, index = 0) out vec4 f_color; 4 | layout(location = 1) out uint f_id; 5 | 6 | flat in uint v_id; 7 | flat in float v_w; 8 | flat in vec4 v_c; 9 | flat in vec2 v_g; 10 | 11 | void main(void) { 12 | f_id = v_id; 13 | if(length(gl_PointCoord.xy - vec2(.5)) > 0.5) 14 | discard; 15 | //f_color = vec4(vec3(1.),pow(length(gl_PointCoord.xy),2.)); 16 | f_color = v_c; 17 | //f_color = vec4(v_w); 18 | //f_color.xy = v_g; //f_color.b = v_w; 19 | f_color.a = 1.0; 20 | } 21 | -------------------------------------------------------------------------------- /src/graphics/shaders/points/vertex.glsl: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | uniform mat4 modelview; 4 | uniform mat4 projection; 5 | uniform float point_size; 6 | 7 | in vec3 position; 8 | in uint id; 9 | in float weight; 10 | in float contrast; 11 | in vec4 nc; 12 | in vec2 g; 13 | 14 | flat out uint v_id; 15 | flat out float v_w; 16 | flat out vec4 v_c; 17 | flat out vec2 v_g; 18 | 19 | void main(void) { 20 | gl_Position = projection * modelview * vec4(position, 1.0); 21 | //gl_PointSize = (0.1+contrast)*point_size;// / modelview[3][3]; 22 | gl_PointSize = 1*point_size;// / modelview[3][3]; 23 | v_id = id; 24 | v_w = weight; 25 | //v_c = contrast; 26 | v_c = nc; 27 | v_g = g; 28 | } 29 | -------------------------------------------------------------------------------- /src/graphics/shaders/surface/fragment.glsl: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | layout(location = 3) out vec4 f_color2; 4 | layout(location = 2) out vec2 f_coordinate; 5 | layout(location = 1) out uint f_id; 6 | layout(location = 0) out vec4 f_color; 7 | 8 | uniform int selected; 9 | uniform vec3 wireframe_color; 10 | 11 | flat in uint v_id; 12 | 13 | in vec3 v_v; 14 | in vec4 v_tc; 15 | in float v_w; 16 | in float v_ctrst; 17 | in vec2 v_g; 18 | 19 | float rand(vec2 co){ 20 | return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); 21 | } 22 | 23 | vec3 semi(vec3 c) { 24 | return vec3( 25 | c.r > 0.5? c.r - 0.5 : c.r + 0.5, 26 | c.g > 0.5? c.g - 0.5 : c.g + 0.5, 27 | c.b > 0.5? c.b - 0.5 : c.b + 0.5); 28 | } 29 | 30 | vec4 semi(vec4 c) { 31 | return vec4(semi(c.rgb), c.a); 32 | } 33 | 34 | vec4 h120(vec4 c) { 35 | return vec4(c.brg, c.a); 36 | } 37 | 38 | vec3 inv(vec3 c) { 39 | return vec3(1.0) -vec3(c); 40 | } 41 | 42 | void main(void) { 43 | f_id = v_id; 44 | f_color = v_tc; 45 | //f_color.a += 0.0001; 46 | f_coordinate = vec2(v_v); 47 | 48 | //use channels for different parameters 49 | f_color2 = vec4(v_w, v_ctrst, v_g.x, v_g.y); 50 | } 51 | -------------------------------------------------------------------------------- /src/graphics/shaders/surface/geometry.glsl: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | layout(triangles) in; 4 | layout(triangle_strip, max_vertices = 3) out; 5 | //layout(line_strip, max_vertices = 3) out; 6 | 7 | in uint e_id[]; 8 | in vec4 e_color[]; 9 | in vec4 e_color2[]; 10 | in vec4 e_corner_color[]; 11 | in vec3 e_patch_coord[3]; 12 | in vec3 e_patch_distance[3]; 13 | in vec3 e_pos[]; 14 | in float e_weight[]; 15 | 16 | flat out uint g_id; 17 | out vec3 g_primitive_coord; 18 | out vec3 g_patch_coord; 19 | out vec4 g_color; 20 | out vec4 g_color2; 21 | out vec4 g_corner_color; 22 | out float g_weight; 23 | 24 | void main(void) { 25 | 26 | g_id = e_id[0]; 27 | gl_Position = gl_in[0].gl_Position; 28 | g_patch_coord = e_patch_coord[0]; 29 | g_primitive_coord = vec3(1, 0, 0); 30 | g_color = e_color[0]; 31 | g_color2 = e_color2[0]; 32 | g_corner_color = e_corner_color[0]; 33 | g_weight = e_weight[0]; 34 | EmitVertex(); 35 | 36 | g_id = e_id[1]; 37 | gl_Position = gl_in[1].gl_Position; 38 | g_patch_coord = e_patch_coord[1]; 39 | g_primitive_coord = vec3(0, 1, 0); 40 | g_corner_color = e_corner_color[1]; 41 | g_color = e_color[1]; 42 | g_color2 = e_color2[1]; 43 | g_weight = e_weight[1]; 44 | EmitVertex(); 45 | 46 | g_id = e_id[2]; 47 | gl_Position = gl_in[2].gl_Position; 48 | g_patch_coord = e_patch_coord[2]; 49 | g_primitive_coord = vec3(0, 0, 1); 50 | g_corner_color = e_corner_color[2]; 51 | g_color = e_color[2]; 52 | g_color2 = e_color2[2]; 53 | g_weight = e_weight[2]; 54 | EmitVertex(); 55 | 56 | EndPrimitive(); 57 | } 58 | -------------------------------------------------------------------------------- /src/graphics/shaders/surface/tesscontrol.glsl: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | #define ID gl_InvocationID 4 | 5 | layout(vertices = 3) out; 6 | 7 | uniform int tessellation_level; 8 | 9 | in uint v_id[]; 10 | in vec4 v_color[]; 11 | in vec4 v_color2[]; 12 | in vec3 v_b021[], v_b012[], v_b210[], v_b120[], v_b102[], v_b201[], v_b111[]; 13 | in float v_weight[]; 14 | 15 | out uint c_id[]; 16 | out vec4 c_color[]; 17 | out vec4 c_color2[]; 18 | out vec3 c_b021[], c_b012[], c_b210[], c_b120[], c_b102[], c_b201[], c_b111[]; 19 | out float c_weight[]; 20 | 21 | void main(void) { 22 | 23 | c_id[ID] = v_id[ID]; 24 | gl_out[ID].gl_Position = gl_in[ID].gl_Position; 25 | c_color[ID] = v_color[ID]; 26 | c_color2[ID] = v_color2[ID]; 27 | c_weight[ID] = v_weight[ID]; 28 | 29 | //perform only for one index? 30 | c_b021[ID] = v_b021[ID]; 31 | c_b012[ID] = v_b012[ID]; 32 | c_b210[ID] = v_b210[ID]; 33 | c_b120[ID] = v_b120[ID]; 34 | c_b102[ID] = v_b102[ID]; 35 | c_b201[ID] = v_b201[ID]; 36 | c_b111[ID] = v_b111[ID]; 37 | 38 | //only needs to be written once 39 | if(gl_InvocationID == 0) 40 | { 41 | gl_TessLevelOuter[0] = 1; 42 | gl_TessLevelOuter[1] = 1; 43 | gl_TessLevelOuter[2] = 1; 44 | gl_TessLevelInner[0] = 1; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/graphics/shaders/surface/tesseval.glsl: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | layout(triangles, equal_spacing, ccw) in; 4 | 5 | uniform mat4 modelview; 6 | uniform mat4 projection; 7 | uniform vec3 cps[]; 8 | uniform float z_units; 9 | uniform int is_surface2; 10 | 11 | in uint c_id[]; 12 | in vec4 c_color[]; 13 | in vec4 c_color2[]; 14 | in vec3 c_b021[], c_b012[], c_b210[], c_b120[], c_b102[], c_b201[], c_b111[]; 15 | in float c_weight[]; 16 | 17 | out uint e_id; 18 | out vec4 e_color; 19 | out vec4 e_color2; 20 | out vec4 e_corner_color; 21 | out float e_weight; 22 | out vec3 e_pos; 23 | 24 | struct ControlPoints 25 | { 26 | vec3 b300, b210, b120, b030, b021, b012, b003, b102, b201, b111; 27 | }; 28 | 29 | out vec3 e_patch_coord; 30 | out vec3 e_patch_distance; 31 | 32 | 33 | vec3 lerp_normal(vec3 u) { 34 | ControlPoints ctrl; 35 | ctrl.b300 = gl_in[0].gl_Position.xyz; 36 | ctrl.b210 = c_b210[0]; 37 | ctrl.b120 = c_b120[0]; 38 | ctrl.b030 = gl_in[1].gl_Position.xyz; 39 | ctrl.b021 = c_b021[0]; 40 | ctrl.b012 = c_b012[0]; 41 | ctrl.b003 = gl_in[2].gl_Position.xyz; 42 | ctrl.b102 = c_b102[0]; 43 | ctrl.b201 = c_b201[0]; 44 | ctrl.b111 = c_b111[0]; 45 | 46 | //degree1 47 | vec3 b300b210b201 = ctrl.b300*u.x + ctrl.b210*u.y + ctrl.b201*u.z; 48 | vec3 b120b030b021 = ctrl.b120*u.x + ctrl.b030*u.y + ctrl.b021*u.z; 49 | vec3 b102b012b003 = ctrl.b102*u.x + ctrl.b012*u.y + ctrl.b003*u.z; 50 | 51 | vec3 b210b120b111 = ctrl.b210*u.x + ctrl.b120*u.y + ctrl.b111*u.z; 52 | vec3 b111b021b012 = ctrl.b111*u.x + ctrl.b021*u.y + ctrl.b012*u.z; 53 | vec3 b201b111b102 = ctrl.b201*u.x + ctrl.b111*u.y + ctrl.b102*u.z; 54 | 55 | //degree 2 56 | vec3 bbb1 = b300b210b201*u.x + b210b120b111*u.y + b201b111b102*u.z; 57 | vec3 bbb2 = b210b120b111*u.x + b120b030b021*u.y + b111b021b012*u.z; 58 | vec3 bbb3 = b201b111b102*u.x + b111b021b012*u.y + b102b012b003*u.z; 59 | 60 | //degree 3 61 | //p = bbb1*u.u + bbb2*u.v + bbb3*u.w; 62 | 63 | vec3 r = vec3(bbb2-bbb1); 64 | vec3 s = vec3(bbb3-bbb1); 65 | return vec3(r.y*s.z - r.z*s.y, r.z*s.x - r.x*s.z, r.x*s.y - r.y*s.x); 66 | } 67 | 68 | vec3 bezier_triangle(vec3 u3) { 69 | float u = u3.x; 70 | float v = u3.y; 71 | float w = u3.z; 72 | 73 | return u*gl_in[0].gl_Position.xyz + 74 | v*gl_in[1].gl_Position.xyz + 75 | w*gl_in[2].gl_Position.xyz; 76 | /* 77 | ControlPoints ctrl; 78 | ctrl.b300 = gl_in[0].gl_Position.xyz; 79 | ctrl.b210 = c_b210[0]; 80 | ctrl.b120 = c_b120[0]; 81 | ctrl.b030 = gl_in[1].gl_Position.xyz; 82 | ctrl.b021 = c_b021[0]; 83 | ctrl.b012 = c_b012[0]; 84 | ctrl.b003 = gl_in[2].gl_Position.xyz; 85 | ctrl.b102 = c_b102[0]; 86 | ctrl.b201 = c_b201[0]; 87 | ctrl.b111 = c_b111[0]; 88 | 89 | float u_pow3 = pow(u, 3); 90 | float v_pow3 = pow(v, 3); 91 | float w_pow3 = pow(w, 3); 92 | float u_pow2 = pow(u, 2); 93 | float v_pow2 = pow(v, 2); 94 | float w_pow2 = pow(w, 2); 95 | 96 | return 97 | ctrl.b300 * w_pow3 + 98 | ctrl.b030 * u_pow3 + 99 | ctrl.b003 * v_pow3 + 100 | ctrl.b210 * 3.0 * w_pow2 * u + 101 | ctrl.b120 * 3.0 * w * u_pow2 + 102 | ctrl.b201 * 3.0 * w_pow2 * v + 103 | ctrl.b021 * 3.0 * u_pow2 * v + 104 | ctrl.b102 * 3.0 * w * v_pow2 + 105 | ctrl.b012 * 3.0 * u * v_pow2 + 106 | ctrl.b111 * 6.0 * w * u * v; 107 | */ 108 | } 109 | 110 | void main() { 111 | 112 | e_id = c_id[0]; 113 | 114 | vec3 pos = bezier_triangle(gl_TessCoord); 115 | 116 | gl_Position = projection * modelview * vec4(pos, 1.0); 117 | float i = pos.z / z_units; 118 | e_color = vec4(i, i, i, 1.0) + vec4(vec3(0.5),0.0); 119 | 120 | // I do not understand this index order. 121 | e_corner_color = c_color[1] * gl_TessCoord.x + c_color[2] * gl_TessCoord.y + c_color[0] * gl_TessCoord.z; 122 | e_weight = c_weight[1] * gl_TessCoord.x + c_weight[2] * gl_TessCoord.y + c_weight[0] * gl_TessCoord.z; 123 | 124 | float az = gl_in[0].gl_Position.z; 125 | float bz = gl_in[1].gl_Position.z; 126 | float cz = gl_in[2].gl_Position.z; 127 | 128 | 129 | vec4 color1[3]; 130 | vec4 color2[3]; 131 | vec3 u = gl_TessCoord.xyz; 132 | 133 | e_color = color1[1] * u.x + color1[2] * u.y + color1[0] * u.z; 134 | e_color2 = color2[1] * u.x + color2[2] * u.y + color2[0] * u.z; 135 | 136 | e_patch_distance = gl_TessCoord; 137 | e_patch_coord = gl_TessCoord; 138 | 139 | vec3 pos0 = 140 | gl_in[1].gl_Position.xyz * gl_TessCoord.x + 141 | gl_in[2].gl_Position.xyz * gl_TessCoord.y + 142 | gl_in[0].gl_Position.xyz * gl_TessCoord.z; 143 | 144 | e_pos = vec3(projection * modelview * vec4(pos0, 1)); 145 | } 146 | -------------------------------------------------------------------------------- /src/graphics/shaders/surface/vertex.glsl: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | uniform mat4 modelview; 4 | uniform mat4 projection; 5 | 6 | in uint id; 7 | in vec3 position; 8 | in uint l; 9 | in vec4 tc; 10 | in float weight; 11 | in float contrast; 12 | in vec2 g; 13 | 14 | flat out uint v_id; 15 | out vec3 v_v; 16 | out vec4 v_tc; 17 | out float v_w; 18 | out float v_ctrst; 19 | out vec2 v_g; 20 | 21 | void main(void) { 22 | v_id = id; 23 | gl_Position = projection * modelview * vec4(position, 1.0); 24 | v_v = l == 0? vec3(1,0,0) : l == 1? vec3(0,1,0) : vec3(0,0,1); 25 | v_tc = tc; 26 | v_w = weight; 27 | v_g = g; 28 | v_ctrst = contrast; 29 | } 30 | -------------------------------------------------------------------------------- /src/graphics/shaders/wireframe/fragment.glsl: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | 3 | layout(location = 0, index = 0) out vec4 f_color; 4 | 5 | in vec3 g_patch_coord; 6 | in vec3 g_primitive_coord; 7 | in vec4 g_color; 8 | in vec4 g_corner_color; 9 | 10 | uniform vec3 wireframe_color; 11 | uniform float line_width; 12 | 13 | float edgeFactor() { 14 | vec3 d = fwidth(g_primitive_coord); 15 | vec3 a3 = smoothstep(vec3(0), d * 40 * line_width /* / modelview[3][3]*/, g_primitive_coord); 16 | return min(min(a3.x, a3.y), a3.z); 17 | } 18 | 19 | void main(void) { 20 | f_color = vec4(0); 21 | f_color.a = 1.0-edgeFactor(); 22 | if(f_color.a <= 0) discard; 23 | } 24 | -------------------------------------------------------------------------------- /src/info.cpp: -------------------------------------------------------------------------------- 1 | #include "info.h" 2 | 3 | 4 | double minmax_angle_ratio(fVector const& av, fVector const& bv, fVector const& cv) 5 | { 6 | fVector a = (bv - av).norm(); 7 | fVector b = (cv - bv).norm(); 8 | fVector c = (av - cv).norm(); 9 | double ab = acos(-a.dot(b)); 10 | double bc = acos(-b.dot(c)); 11 | double ca = acos(-c.dot(a)); 12 | double max, min; 13 | max = min = ab; 14 | if(bc > max) max = bc; 15 | if(ca > max) max = ca; 16 | if(bc < min) min = bc; 17 | if(ca < min) min = ca; 18 | return min/max; 19 | } 20 | 21 | double minmax_length_ratio(fVector const& av, fVector const& bv, fVector const& cv) 22 | { 23 | double a = (bv - av).length(); 24 | double b = (cv - bv).length(); 25 | double c = (av - cv).length(); 26 | double max, min; 27 | max = min = a; 28 | if(b > max) max = b; 29 | if(c > max) max = c; 30 | if(b < min) min = b; 31 | if(c < min) min = c; 32 | return min/max; 33 | } 34 | 35 | double inscribedcircum_ratio(fVector const& av, fVector const& bv, fVector const& cv) 36 | { 37 | double a = (bv - av).length(); 38 | double b = (cv - bv).length(); 39 | double c = (av - cv).length(); 40 | double s = 0.5*(a+b+c); 41 | double in_r = sqrt((s-a)*(s-b)*(s-c)/s); 42 | double out_r = (a*b*c)/sqrt((a+b+c)*(-a+b+c)*(a-b+c)*(a+b-c)); 43 | double r = in_r/out_r; 44 | return r*r; 45 | } -------------------------------------------------------------------------------- /src/info.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "common/vector.h" 3 | 4 | double minmax_angle_ratio(Vec2 const& av, Vec2 const& bv, Vec2 const& cv); 5 | double minmax_length_ratio(Vec2 const& av, Vec2 const& bv, Vec2 const& cv); 6 | double inscribedcircum_ratio(Vec2 const& av, Vec2 const& bv, Vec2 const& cv); -------------------------------------------------------------------------------- /src/init.cpp: -------------------------------------------------------------------------------- 1 | #include "complex/complex.h" 2 | #include "graphics/graphics.h" 3 | #include "init.h" 4 | #include "common/color.h" 5 | #include "state.h" 6 | #include "globals.h" 7 | #include "window.h" 8 | 9 | #include "json/json.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "util.h" 21 | #include "globals.h" 22 | 23 | bool Tool::left = false; 24 | bool Tool::right = false; 25 | 26 | void pre_init() { 27 | //srand((unsigned int)time(0)); 28 | srand(0); 29 | Root::init_mpzs(); 30 | view = new Camera(); 31 | com = new Complex(true); 32 | brush_color = Col::random(); 33 | } 34 | 35 | void post_init() { 36 | window->connect_toggle_buttons(); 37 | window->reset_view(); 38 | 39 | Json::Value root; 40 | Json::Reader reader; 41 | std::string config(get_file_contents("config.json")); 42 | if(!config.empty() && !reader.parse(config, root)) 43 | std::cout << "Json failure: \n" << reader.getFormattedErrorMessages(); 44 | 45 | line_width = root.get("line width", .001).asFloat(); 46 | point_size = root.get("point size", 4.).asFloat(); 47 | window->set_surface(root.get("surface", true).asBool()); 48 | window->set_gaussian(root.get("gaussian", true).asBool()); 49 | window->set_contours(root.get("painting", true).asBool()); 50 | window->set_nodes(root.get("nodes", false).asBool()); 51 | window->set_edges(root.get("edges", false).asBool()); 52 | window->set_control_net(root.get("control net", false).asBool()); 53 | gaussian_size = root.get("gaussian_size", 10.).asFloat(); 54 | min_gaussian_q = root.get("min_gaussian_q", 10.).asFloat(); 55 | contrast_scale = root.get("contrast_scale", 200.).asFloat(); 56 | 57 | view->zrotzoom = Vec2(root.get("camera_zoom", 1.).asFloat(), 0.0); 58 | std::string loadfile = root.get("load", "").asString(); 59 | if(!loadfile.empty()) { 60 | load_file(loadfile); 61 | } 62 | 63 | com->move_mode = com->str_to_move(root.get("move_mode", "conseq").asString()); 64 | 65 | //view->pos = Vec2(-100, -100); 66 | view->zrotzoom = Vec2(0.99,0); 67 | 68 | brush_color = Col::White; 69 | window->set_colorpicker_button_color(); 70 | } 71 | 72 | void destroy() { 73 | Root::clear_mpzs(); 74 | delete com; 75 | } 76 | -------------------------------------------------------------------------------- /src/init.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void init_opengl(); 4 | void pre_init(/*int argc, char *argv[]*/); 5 | void post_init(); 6 | void destroy(); 7 | void init_toolsets(); 8 | void load_config(); 9 | 10 | //void load_configs(); 11 | //void load_complex_config(); 12 | //void load_graphics_config(); 13 | -------------------------------------------------------------------------------- /src/input.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "window.h" 9 | #include "state.h" 10 | 11 | #include 12 | 13 | #ifdef _WIN32 14 | #include 15 | #endif 16 | 17 | #include 18 | 19 | Vec2 cursor; 20 | 21 | unsigned long prev_pointer_time; 22 | Vec2 old_pos = Vec2(); 23 | 24 | 25 | void Graphics::hover_mouse_event(QHoverEvent* me) { 26 | 27 | #ifdef TEST_WIN32 28 | POINT point = {me->pos().x(), me->pos().y()}; 29 | HWND hWnd = (HWND)effectiveWinId(); 30 | 31 | ClientToScreen(hWnd, &point); 32 | 33 | MOUSEMOVEPOINT mmpoint = {point.x, point.y, (unsigned long)GetMessageTime()}; 34 | MOUSEMOVEPOINT mmpoints[64]; 35 | int num_points = GetMouseMovePointsEx(sizeof(mmpoint), &mmpoint, mmpoints, 64, GMMP_USE_DISPLAY_POINTS); 36 | 37 | POINT point0 = {(LONG)::cursor.x, (LONG)::cursor.y}; 38 | POINT point0scr = point0; 39 | ClientToScreen(hWnd, &point0scr); 40 | 41 | int i = 0; 42 | while(i < num_points && !(mmpoints[i].time < prev_pointer_time) && !(mmpoints[i].time == prev_pointer_time && mmpoints[i].x == point0scr.x && mmpoints[i].y == point0scr.y)) 43 | ++i; 44 | while(i-- > 0) { 45 | POINT point1 = { mmpoints[i].x, mmpoints[i].y }; 46 | ScreenToClient(hWnd, &point1); 47 | 48 | Vec2 rel(point1.x - point0.x, point1.y - point0.y); 49 | ::cursor = Vec2(point1.x, point1.y); 50 | mousetool->motion(Vec2(rel.x, rel.y)); 51 | point0 = point1; 52 | } 53 | 54 | prev_pointer_time = (unsigned long)GetMessageTime(); 55 | #else 56 | ::cursor = Vec2(me->position().x(), me->position().y()) * pixelratio; 57 | Vec2 pos(me->position().x(), me->position().y()); 58 | mousetool->motion((pos - old_pos) * pixelratio); 59 | old_pos = pos; 60 | #endif 61 | 62 | update(); 63 | } 64 | 65 | 66 | void Window::timerEvent(QTimerEvent*) 67 | { 68 | ++timer_counter; 69 | if(timer_counter % timer_modulo == 0) 70 | mousetool->timer_update(); 71 | } 72 | 73 | void Window::dump_canvas2(std::string name) { 74 | //QImage img = draw->grab_render(Size(2048, 2048)); 75 | QImage img = draw->grab_render2(Size(draw->render_sz.w, draw->render_sz.h)); 76 | 77 | QGraphicsScene* scene = new QGraphicsScene(); 78 | scene->setSceneRect(0, 0, 1, 1); 79 | QPainter painter(&img); 80 | scene->render(&painter); 81 | 82 | std::stringstream filename; 83 | 84 | filename << "series/" << name << ".png"; 85 | if(img.save(filename.str().c_str())) { 86 | std::cout << "'" << filename.str().c_str() << "' saved." << std::endl; 87 | } else { 88 | std::cout << "Failed to save '" << filename.str().c_str() << "'." << std::endl; 89 | } 90 | } 91 | 92 | void Window::dump_canvas() { 93 | //QImage img = draw->grab_render(Size(2048, 2048)); 94 | QImage img = draw->grab_render(Size(draw->render_sz.w, draw->render_sz.h)); 95 | 96 | QGraphicsScene* scene = new QGraphicsScene(); 97 | scene->setSceneRect(0, 0, 2, 2); 98 | QPainter painter(&img); 99 | scene->render(&painter); 100 | 101 | std::stringstream filename; 102 | 103 | QString time_str = QDateTime::currentDateTime().toString(QString("yyMMdd-hhmmss")); 104 | 105 | filename << "out/" << time_str.toStdString() << ".png"; 106 | if(img.save(filename.str().c_str())) { 107 | std::cout << "'" << filename.str().c_str() << "' saved." << std::endl; 108 | } else { 109 | std::cout << "Failed to save '" << filename.str().c_str() << "'." << std::endl; 110 | } 111 | } 112 | 113 | void Window::wasd_press(int key) { 114 | if(mousetool == &cameratool) { 115 | const double MoveSpeed = 0.03; 116 | Vec2 v; 117 | if(key == Qt::Key_W) v.y -= MoveSpeed; 118 | if(key == Qt::Key_S) v.y += MoveSpeed; 119 | if(key == Qt::Key_A) v.x += MoveSpeed; 120 | if(key == Qt::Key_D) v.x -= MoveSpeed; 121 | view->pos += view->uni_can_v(v); 122 | } 123 | } 124 | 125 | std::string Window::get_QLineEdit_string(QLineEdit* le) { 126 | return le->text().isEmpty() ? le->placeholderText().toStdString() : le->text().toStdString(); 127 | } 128 | 129 | void Window::reset_view() { 130 | view->reset(); 131 | draw->update(); 132 | } 133 | 134 | void Window::keyReleaseEvent(QKeyEvent *e) { 135 | switch(e->key()) { 136 | case Qt::Key_Control: 137 | space_down = false; 138 | break; 139 | } 140 | } 141 | 142 | bool stop = false; 143 | int frame = 1; 144 | 145 | void Window::keyPressEvent(QKeyEvent *e) { 146 | switch(e->key()) { 147 | 148 | case Qt::Key_Escape: 149 | close(); 150 | QCoreApplication::quit(); 151 | break; 152 | 153 | case Qt::Key_Control: 154 | space_down = true; 155 | break; 156 | 157 | case Qt::Key_0: { 158 | reset_view(); 159 | break; 160 | } 161 | 162 | /* 163 | case Qt::Key_B: 164 | set_buffers = !set_buffers; 165 | myDebug() << set_buffers; 166 | break; 167 | */ 168 | 169 | /* 170 | case Qt::Key_W: 171 | case Qt::Key_S: 172 | case Qt::Key_A: 173 | case Qt::Key_D: 174 | wasd_press(e->key()); 175 | break; 176 | */ 177 | 178 | case Qt::Key_A: 179 | if(com->move_mode == Complex::Concur) { 180 | com->move_mode = Complex::Consec; 181 | myDebug() << "consecutive mode"; 182 | } 183 | else { 184 | com->move_mode = Complex::Concur; 185 | myDebug() << "concurrent mode"; 186 | } 187 | break; 188 | 189 | case Qt::Key_G: 190 | com->waste(); 191 | break; 192 | 193 | case Qt::Key_E: 194 | { 195 | int i = 0; 196 | dump_canvas2(std::to_string(++i)); 197 | while(true) { 198 | com->automata(); 199 | dump_canvas2(std::to_string(++i)); 200 | Sleep(30); 201 | if(i > 6000*5) 202 | break; 203 | } 204 | dump_canvas2(std::to_string(++i)); 205 | 206 | 207 | /* 208 | int i = 0; 209 | for(int k = 0; k < 10; ++k) { 210 | new_canvas(); 211 | com->delaunify(false); 212 | com->randomize(); 213 | com->move_random(); 214 | //dump_canvas2(std::to_string(++i)); 215 | com->move_nodes_populate(); 216 | 217 | dump_canvas2(std::to_string(++i)); 218 | for(; !com->move_nodes();) { 219 | dump_canvas2(std::to_string(++i)); 220 | Sleep(10); 221 | } 222 | dump_canvas2(std::to_string(++i)); 223 | } 224 | */ 225 | 226 | break; 227 | } 228 | 229 | case Qt::Key_Q: 230 | { 231 | com->automata(); 232 | com->waste(); 233 | break; 234 | } 235 | 236 | case Qt::Key_T: 237 | com->delaunify(false); 238 | case Qt::Key_Y: 239 | com->delaunify(); 240 | break; 241 | case Qt::Key_U: 242 | com->refract(); 243 | break; 244 | case Qt::Key_H: 245 | load_file(get_QLineEdit_string(save_name)); 246 | break; 247 | 248 | /*case Qt::Key_K: { 249 | myDebug() << "\n ::mv_tris:: \n"; 250 | 251 | std::list mv; 252 | for(auto i = com->mv_tris.begin(); i != com->mv_tris.end(); ++i) { 253 | mv.push_back(*i); 254 | } 255 | 256 | mv.sort(cross_comp_lt); 257 | for(auto i = mv.begin(); i != mv.end(); ++i) { 258 | auto c = *i; 259 | if(!c->invalid) { 260 | myDebug() << "current cross case:" << c->g; 261 | myDebug() << "c->crossroot.kind:" << c->crossroot.kind; 262 | myDebug() << "c->overlap:" << c->overlap; 263 | myDebug() << "curt" << com->curt; 264 | myDebug() << "t" << c->t; 265 | myDebug() << ""; 266 | } 267 | } 268 | } 269 | break;*/ 270 | 271 | case Qt::Key_I: 272 | interpolate_move = !interpolate_move; 273 | break; 274 | 275 | case Qt::Key_N: 276 | new_canvas(); 277 | break; 278 | 279 | case Qt::Key_Z: 280 | myDebug() << "set_buffers" << set_buffers; 281 | set_buffers = !set_buffers; 282 | break; 283 | 284 | case Qt::Key_9: 285 | contrast_scale *= 1.05f; 286 | myDebug() << "contrast_scale"; 287 | myDebug() << contrast_scale; 288 | break; 289 | case Qt::Key_8: 290 | contrast_scale /= 1.05f; 291 | myDebug() << "contrast_scale"; 292 | myDebug() << contrast_scale; 293 | break; 294 | 295 | /* 296 | case Qt::Key_Plus: 297 | gaussian_size *= 1.05f; 298 | myDebug() << "gaussian_size"; 299 | myDebug() << gaussian_size; 300 | break; 301 | case Qt::Key_Minus: 302 | gaussian_size /= 1.05f; 303 | myDebug() << "gaussian_size"; 304 | myDebug() << gaussian_size; 305 | break; 306 | */ 307 | 308 | case Qt::Key_Plus: 309 | line_width *= 1.05f; 310 | myDebug() << "line_width"; 311 | myDebug() << line_width; 312 | break; 313 | case Qt::Key_Minus: 314 | line_width /= 1.05f; 315 | myDebug() << "line_width"; 316 | myDebug() << line_width; 317 | break; 318 | 319 | /* 320 | case Qt::Key_Plus: 321 | manual_curt = fmin(1.0, manual_curt + 0.01); 322 | myDebug() << "manual_curt" << manual_curt; 323 | break; 324 | case Qt::Key_Minus: 325 | manual_curt = fmax(0.0, manual_curt - 0.01); 326 | myDebug() << "manual_curt" << manual_curt; 327 | break; 328 | */ 329 | 330 | 331 | case Qt::Key_F3: 332 | draw->toggle_render("surface"); 333 | break; 334 | case Qt::Key_F4: 335 | draw->toggle_render("gaussian_v"); 336 | break; 337 | case Qt::Key_F5: 338 | draw->toggle_render("painting"); 339 | break; 340 | case Qt::Key_F6: 341 | draw->toggle_render("nodes"); 342 | break; 343 | case Qt::Key_F7: 344 | draw->toggle_render("edges"); 345 | break; 346 | case Qt::Key_F8: 347 | draw->toggle_render("control_net"); 348 | break; 349 | 350 | case Qt::Key_F9: 351 | save_file(get_QLineEdit_string(save_name)); 352 | break; 353 | 354 | case Qt::Key_F10: 355 | frame = 1; 356 | load_file(get_QLineEdit_string(save_name)); 357 | break; 358 | 359 | default: 360 | QWidget::keyPressEvent(e); 361 | return; 362 | } 363 | 364 | draw->update(); 365 | } 366 | 367 | 368 | 369 | bool Graphics::event(QEvent *event) { 370 | switch(event->type()) { 371 | case QEvent::Wheel: { 372 | QWheelEvent* we = (QWheelEvent*)event; 373 | //if(we->orientation() == Qt::Vertical) { 374 | mousetool->wheel_rot((double)we->angleDelta().y()); 375 | //} 376 | break; 377 | } 378 | case QEvent::MouseButtonPress: { 379 | QMouseEvent* me = (QMouseEvent*)event; 380 | if(me->button() == Qt::MouseButton::LeftButton) { 381 | Brush::left = true; 382 | mousetool->left_down(::cursor); 383 | } else if(me->button() == Qt::MouseButton::RightButton) { 384 | Brush::right = true; 385 | mousetool->right_down(::cursor); 386 | } 387 | break; 388 | } 389 | case QEvent::MouseButtonRelease: { 390 | QMouseEvent* me = (QMouseEvent*)event; 391 | if(me->button() == Qt::MouseButton::LeftButton) { 392 | Brush::left = false; 393 | mousetool->left_up(::cursor); 394 | } else if(me->button() == Qt::MouseButton::RightButton) { 395 | Brush::right = false; 396 | mousetool->right_up(::cursor); 397 | } 398 | break; 399 | } 400 | case QEvent::HoverEnter: 401 | setCursor(Qt::BlankCursor); 402 | draw_cursor = true; 403 | update(); 404 | break; 405 | case QEvent::HoverLeave: 406 | unsetCursor(); 407 | draw_cursor = false; 408 | update(); 409 | break; 410 | case QEvent::HoverMove: { 411 | hover_mouse_event((QHoverEvent*)event); 412 | if(false)//(Brush::left || Brush::right) 413 | { 414 | com->automata(); 415 | ::window->dump_canvas2(std::to_string(frame++)); 416 | } 417 | break; 418 | } 419 | default: 420 | break; 421 | } 422 | return QWidget::event(event); 423 | } 424 | -------------------------------------------------------------------------------- /src/json/json-forwards.h: -------------------------------------------------------------------------------- 1 | /// Json-cpp amalgated forward header (http://jsoncpp.sourceforge.net/). 2 | /// It is intended to be used with #include "json/json-forwards.h" 3 | /// This header provides forward declaration for all JsonCpp types. 4 | 5 | // ////////////////////////////////////////////////////////////////////// 6 | // Beginning of content of file: LICENSE 7 | // ////////////////////////////////////////////////////////////////////// 8 | 9 | /* 10 | The JsonCpp library's source code, including accompanying documentation, 11 | tests and demonstration applications, are licensed under the following 12 | conditions... 13 | 14 | The author (Baptiste Lepilleur) explicitly disclaims copyright in all 15 | jurisdictions which recognize such a disclaimer. In such jurisdictions, 16 | this software is released into the Public Domain. 17 | 18 | In jurisdictions which do not recognize Public Domain property (e.g. Germany as of 19 | 2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is 20 | released under the terms of the MIT License (see below). 21 | 22 | In jurisdictions which recognize Public Domain property, the user of this 23 | software may choose to accept it either as 1) Public Domain, 2) under the 24 | conditions of the MIT License (see below), or 3) under the terms of dual 25 | Public Domain/MIT License conditions described here, as they choose. 26 | 27 | The MIT License is about as close to Public Domain as a license can get, and is 28 | described in clear, concise terms at: 29 | 30 | http://en.wikipedia.org/wiki/MIT_License 31 | 32 | The full text of the MIT License follows: 33 | 34 | ======================================================================== 35 | Copyright (c) 2007-2010 Baptiste Lepilleur 36 | 37 | Permission is hereby granted, free of charge, to any person 38 | obtaining a copy of this software and associated documentation 39 | files (the "Software"), to deal in the Software without 40 | restriction, including without limitation the rights to use, copy, 41 | modify, merge, publish, distribute, sublicense, and/or sell copies 42 | of the Software, and to permit persons to whom the Software is 43 | furnished to do so, subject to the following conditions: 44 | 45 | The above copyright notice and this permission notice shall be 46 | included in all copies or substantial portions of the Software. 47 | 48 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 49 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 50 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 51 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 52 | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 53 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 54 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 55 | SOFTWARE. 56 | ======================================================================== 57 | (END LICENSE TEXT) 58 | 59 | The MIT license is compatible with both the GPL and commercial 60 | software, affording one all of the rights of Public Domain with the 61 | minor nuisance of being required to keep the above copyright notice 62 | and license text in the source code. Note also that by accepting the 63 | Public Domain "license" you can re-license your copy using whatever 64 | license you like. 65 | 66 | */ 67 | 68 | // ////////////////////////////////////////////////////////////////////// 69 | // End of content of file: LICENSE 70 | // ////////////////////////////////////////////////////////////////////// 71 | 72 | 73 | 74 | 75 | 76 | #ifndef JSON_FORWARD_AMALGATED_H_INCLUDED 77 | # define JSON_FORWARD_AMALGATED_H_INCLUDED 78 | /// If defined, indicates that the source file is amalgated 79 | /// to prevent private header inclusion. 80 | #define JSON_IS_AMALGAMATION 81 | 82 | // ////////////////////////////////////////////////////////////////////// 83 | // Beginning of content of file: include/json/config.h 84 | // ////////////////////////////////////////////////////////////////////// 85 | 86 | // Copyright 2007-2010 Baptiste Lepilleur 87 | // Distributed under MIT license, or public domain if desired and 88 | // recognized in your jurisdiction. 89 | // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE 90 | 91 | #ifndef JSON_CONFIG_H_INCLUDED 92 | #define JSON_CONFIG_H_INCLUDED 93 | #include 94 | #include //typedef String 95 | #include //typedef int64_t, uint64_t 96 | 97 | /// If defined, indicates that json library is embedded in CppTL library. 98 | //# define JSON_IN_CPPTL 1 99 | 100 | /// If defined, indicates that json may leverage CppTL library 101 | //# define JSON_USE_CPPTL 1 102 | /// If defined, indicates that cpptl vector based map should be used instead of 103 | /// std::map 104 | /// as Value container. 105 | //# define JSON_USE_CPPTL_SMALLMAP 1 106 | 107 | // If non-zero, the library uses exceptions to report bad input instead of C 108 | // assertion macros. The default is to use exceptions. 109 | #ifndef JSON_USE_EXCEPTION 110 | #define JSON_USE_EXCEPTION 1 111 | #endif 112 | 113 | /// If defined, indicates that the source file is amalgated 114 | /// to prevent private header inclusion. 115 | /// Remarks: it is automatically defined in the generated amalgated header. 116 | // #define JSON_IS_AMALGAMATION 117 | 118 | #ifdef JSON_IN_CPPTL 119 | #include 120 | #ifndef JSON_USE_CPPTL 121 | #define JSON_USE_CPPTL 1 122 | #endif 123 | #endif 124 | 125 | #ifdef JSON_IN_CPPTL 126 | #define JSON_API CPPTL_API 127 | #elif defined(JSON_DLL_BUILD) 128 | #if defined(_MSC_VER) || defined(__MINGW32__) 129 | #define JSON_API __declspec(dllexport) 130 | #define JSONCPP_DISABLE_DLL_INTERFACE_WARNING 131 | #endif // if defined(_MSC_VER) 132 | #elif defined(JSON_DLL) 133 | #if defined(_MSC_VER) || defined(__MINGW32__) 134 | #define JSON_API __declspec(dllimport) 135 | #define JSONCPP_DISABLE_DLL_INTERFACE_WARNING 136 | #endif // if defined(_MSC_VER) 137 | #endif // ifdef JSON_IN_CPPTL 138 | #if !defined(JSON_API) 139 | #define JSON_API 140 | #endif 141 | 142 | // If JSON_NO_INT64 is defined, then Json only support C++ "int" type for 143 | // integer 144 | // Storages, and 64 bits integer support is disabled. 145 | // #define JSON_NO_INT64 1 146 | 147 | #if defined(_MSC_VER) // MSVC 148 | # if _MSC_VER <= 1200 // MSVC 6 149 | // Microsoft Visual Studio 6 only support conversion from __int64 to double 150 | // (no conversion from unsigned __int64). 151 | # define JSON_USE_INT64_DOUBLE_CONVERSION 1 152 | // Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' 153 | // characters in the debug information) 154 | // All projects I've ever seen with VS6 were using this globally (not bothering 155 | // with pragma push/pop). 156 | # pragma warning(disable : 4786) 157 | # endif // MSVC 6 158 | 159 | # if _MSC_VER >= 1500 // MSVC 2008 160 | /// Indicates that the following function is deprecated. 161 | # define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) 162 | # endif 163 | 164 | #endif // defined(_MSC_VER) 165 | 166 | // In c++11 the override keyword allows you to explicity define that a function 167 | // is intended to override the base-class version. This makes the code more 168 | // managable and fixes a set of common hard-to-find bugs. 169 | #if __cplusplus >= 201103L 170 | # define JSONCPP_OVERRIDE override 171 | # define JSONCPP_NOEXCEPT noexcept 172 | #elif defined(_MSC_VER) && _MSC_VER > 1600 && _MSC_VER < 1900 173 | # define JSONCPP_OVERRIDE override 174 | # define JSONCPP_NOEXCEPT throw() 175 | #elif defined(_MSC_VER) && _MSC_VER >= 1900 176 | # define JSONCPP_OVERRIDE override 177 | # define JSONCPP_NOEXCEPT noexcept 178 | #else 179 | # define JSONCPP_OVERRIDE 180 | # define JSONCPP_NOEXCEPT throw() 181 | #endif 182 | 183 | #ifndef JSON_HAS_RVALUE_REFERENCES 184 | 185 | #if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010 186 | #define JSON_HAS_RVALUE_REFERENCES 1 187 | #endif // MSVC >= 2010 188 | 189 | #ifdef __clang__ 190 | #if __has_feature(cxx_rvalue_references) 191 | #define JSON_HAS_RVALUE_REFERENCES 1 192 | #endif // has_feature 193 | 194 | #elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) 195 | #if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L) 196 | #define JSON_HAS_RVALUE_REFERENCES 1 197 | #endif // GXX_EXPERIMENTAL 198 | 199 | #endif // __clang__ || __GNUC__ 200 | 201 | #endif // not defined JSON_HAS_RVALUE_REFERENCES 202 | 203 | #ifndef JSON_HAS_RVALUE_REFERENCES 204 | #define JSON_HAS_RVALUE_REFERENCES 0 205 | #endif 206 | 207 | #ifdef __clang__ 208 | #elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) 209 | # if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) 210 | # define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) 211 | # elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) 212 | # define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) 213 | # endif // GNUC version 214 | #endif // __clang__ || __GNUC__ 215 | 216 | #if !defined(JSONCPP_DEPRECATED) 217 | #define JSONCPP_DEPRECATED(message) 218 | #endif // if !defined(JSONCPP_DEPRECATED) 219 | 220 | #if __GNUC__ >= 6 221 | # define JSON_USE_INT64_DOUBLE_CONVERSION 1 222 | #endif 223 | 224 | #if !defined(JSON_IS_AMALGAMATION) 225 | 226 | # include "version.h" 227 | 228 | # if JSONCPP_USING_SECURE_MEMORY 229 | # include "allocator.h" //typedef Allocator 230 | # endif 231 | 232 | #endif // if !defined(JSON_IS_AMALGAMATION) 233 | 234 | namespace Json { 235 | typedef int Int; 236 | typedef unsigned int UInt; 237 | #if defined(JSON_NO_INT64) 238 | typedef int LargestInt; 239 | typedef unsigned int LargestUInt; 240 | #undef JSON_HAS_INT64 241 | #else // if defined(JSON_NO_INT64) 242 | // For Microsoft Visual use specific types as long long is not supported 243 | #if defined(_MSC_VER) // Microsoft Visual Studio 244 | typedef __int64 Int64; 245 | typedef unsigned __int64 UInt64; 246 | #else // if defined(_MSC_VER) // Other platforms, use long long 247 | typedef int64_t Int64; 248 | typedef uint64_t UInt64; 249 | #endif // if defined(_MSC_VER) 250 | typedef Int64 LargestInt; 251 | typedef UInt64 LargestUInt; 252 | #define JSON_HAS_INT64 253 | #endif // if defined(JSON_NO_INT64) 254 | #if JSONCPP_USING_SECURE_MEMORY 255 | #define JSONCPP_STRING std::basic_string, Json::SecureAllocator > 256 | #define JSONCPP_OSTRINGSTREAM std::basic_ostringstream, Json::SecureAllocator > 257 | #define JSONCPP_OSTREAM std::basic_ostream> 258 | #define JSONCPP_ISTRINGSTREAM std::basic_istringstream, Json::SecureAllocator > 259 | #define JSONCPP_ISTREAM std::istream 260 | #else 261 | #define JSONCPP_STRING std::string 262 | #define JSONCPP_OSTRINGSTREAM std::ostringstream 263 | #define JSONCPP_OSTREAM std::ostream 264 | #define JSONCPP_ISTRINGSTREAM std::istringstream 265 | #define JSONCPP_ISTREAM std::istream 266 | #endif // if JSONCPP_USING_SECURE_MEMORY 267 | } // end namespace Json 268 | 269 | #endif // JSON_CONFIG_H_INCLUDED 270 | 271 | // ////////////////////////////////////////////////////////////////////// 272 | // End of content of file: include/json/config.h 273 | // ////////////////////////////////////////////////////////////////////// 274 | 275 | 276 | 277 | 278 | 279 | 280 | // ////////////////////////////////////////////////////////////////////// 281 | // Beginning of content of file: include/json/forwards.h 282 | // ////////////////////////////////////////////////////////////////////// 283 | 284 | // Copyright 2007-2010 Baptiste Lepilleur 285 | // Distributed under MIT license, or public domain if desired and 286 | // recognized in your jurisdiction. 287 | // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE 288 | 289 | #ifndef JSON_FORWARDS_H_INCLUDED 290 | #define JSON_FORWARDS_H_INCLUDED 291 | 292 | #if !defined(JSON_IS_AMALGAMATION) 293 | #include "config.h" 294 | #endif // if !defined(JSON_IS_AMALGAMATION) 295 | 296 | namespace Json { 297 | 298 | // writer.h 299 | class FastWriter; 300 | class StyledWriter; 301 | 302 | // reader.h 303 | class Reader; 304 | 305 | // features.h 306 | class Features; 307 | 308 | // value.h 309 | typedef unsigned int ArrayIndex; 310 | class StaticString; 311 | class Path; 312 | class PathArgument; 313 | class Value; 314 | class ValueIteratorBase; 315 | class ValueIterator; 316 | class ValueConstIterator; 317 | 318 | } // namespace Json 319 | 320 | #endif // JSON_FORWARDS_H_INCLUDED 321 | 322 | // ////////////////////////////////////////////////////////////////////// 323 | // End of content of file: include/json/forwards.h 324 | // ////////////////////////////////////////////////////////////////////// 325 | 326 | 327 | 328 | 329 | 330 | #endif //ifndef JSON_FORWARD_AMALGATED_H_INCLUDED 331 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | //#include 3 | #include 4 | 5 | #include "common/vector.h" 6 | #include "globals.h" 7 | #include "complex/complex.h" 8 | #include "json/json.h" 9 | #include "util.h" 10 | #include "init.h" 11 | 12 | #include "window.h" 13 | 14 | void myMessageOutput(QtMsgType, const QMessageLogContext&, const QString&) {} 15 | 16 | int main(int argc, char **argv) { 17 | 18 | pre_init(); 19 | 20 | #ifdef QT_NO_DEBUG 21 | //qInstallMessageHandler(myMessageOutput); 22 | #endif 23 | QApplication app(argc, argv); 24 | app.setAttribute(Qt::AA_UseDesktopOpenGL); 25 | QSurfaceFormat fmt; 26 | fmt.setVersion(4, 2); 27 | fmt.setProfile(QSurfaceFormat::CoreProfile); 28 | QSurfaceFormat::setDefaultFormat(fmt); 29 | 30 | QMainWindow main_window; 31 | window = new Window(); 32 | 33 | main_window.setWindowTitle("qualia painter"); 34 | main_window.setCentralWidget(window); 35 | main_window.resize(main_window.sizeHint()); 36 | main_window.setMouseTracking(true); 37 | main_window.show(); 38 | 39 | post_init(); 40 | 41 | return app.exec(); 42 | } 43 | 44 | -------------------------------------------------------------------------------- /src/mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | 6 | class MainWindow : public QMainWindow 7 | { 8 | Q_OBJECT 9 | 10 | public: 11 | MainWindow(); 12 | 13 | 14 | private slots: 15 | void onAddNew(); 16 | 17 | }; 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /src/mpir.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpihlstrom/femton/f97a345b7965ae98a51f52ad04c427872546aa79/src/mpir.dll -------------------------------------------------------------------------------- /src/mpir.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpihlstrom/femton/f97a345b7965ae98a51f52ad04c427872546aa79/src/mpir.lib -------------------------------------------------------------------------------- /src/opengl32.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpihlstrom/femton/f97a345b7965ae98a51f52ad04c427872546aa79/src/opengl32.lib -------------------------------------------------------------------------------- /src/state.cpp: -------------------------------------------------------------------------------- 1 | #include "state.h" 2 | #include "common/common.h" 3 | #include "camera.h" 4 | #include "info.h" 5 | #include 6 | #include 7 | #include 8 | #include "util.h" 9 | 10 | #include "globals.h" 11 | 12 | bool State::export_to(Complex const& cmplx, std::string file) { 13 | State state(cmplx); 14 | return state.export_to(file); 15 | } 16 | 17 | Complex* State::load_from(std::string file) { 18 | State state; 19 | if(state.import_from(file)) { 20 | return state.load(); 21 | } 22 | return 0; 23 | } 24 | 25 | State::State(std::string const& file) { 26 | import_from(file); 27 | } 28 | 29 | State::State(Complex const& cmplx) { 30 | save(cmplx); 31 | } 32 | 33 | void State::save(Complex const& cmplx) { 34 | 35 | //used to associate each node's memory address with the node's index in the list 36 | std::unordered_map node_index_map; 37 | std::unordered_map trigon_index_map; //same for trigons 38 | 39 | //complex.waste(); //Not necessary. 40 | 41 | nodes.clear(); 42 | nodes.reserve(cmplx.nodes.size()); //potentially dead nodes also counted 43 | trigons.clear(); 44 | trigons.reserve(cmplx.trigons.size()); //potentially dead trigons also counted 45 | 46 | //set up trigon address-index map first 47 | uint32_t index = 0; 48 | for(Trigons::const_iterator i = cmplx.trigons.begin(); i != cmplx.trigons.end(); ++i) { 49 | Tri* t = *i; 50 | if(t->status == Tri::Dead) continue; 51 | trigon_index_map[t] = index; 52 | ++index; 53 | } 54 | 55 | //write node and set up address-index map 56 | index = 0; 57 | for(Nodes::const_iterator i = cmplx.nodes.begin(); i != cmplx.nodes.end(); ++i) { 58 | Node& n = **i; 59 | if(n.status == Node::Dead) continue; 60 | node_index_map[&n] = index; 61 | Edge* e = n.entry(); 62 | nodes.push_back(File::Node(n.cp.x, n.cp.y, n.pp.x, n.pp.y, (uint8_t)n.type, trigon_index_map[(n.entry())->t], (uint8_t)e->t->label(e), n.color.to32(), n.w_, n.contrast)); 63 | ++index; 64 | } 65 | 66 | index = 0; 67 | for(Trigons::const_iterator i = cmplx.trigons.begin(); i != cmplx.trigons.end(); ++i) { 68 | Tri& t = **i; 69 | if(t.status == Tri::Dead) continue; 70 | 71 | uint32_t aji, bji, cji; 72 | Tri::Label ajl, bjl, cjl; 73 | 74 | aji = bji = cji = -1; //default 75 | ajl = bjl = cjl = Tri::None; //default 76 | 77 | if(t.a.j) { 78 | aji = trigon_index_map[t.a.j->t]; 79 | ajl = t.a.j->t->label(t.a.j); 80 | 81 | } 82 | if(t.b.j) { 83 | bji = trigon_index_map[t.b.j->t]; 84 | bjl = t.b.j->t->label(t.b.j); 85 | } 86 | if(t.c.j) { 87 | cji = trigon_index_map[t.c.j->t]; 88 | cjl = t.c.j->t->label(t.c.j); 89 | } 90 | 91 | trigons.push_back(File::Tri(index, t.type, t.color.to32(), 92 | node_index_map[t.a.n], node_index_map[t.b.n], node_index_map[t.c.n], 93 | aji, bji, cji, 94 | ajl, bjl, cjl, 95 | t.a.w, t.b.w, t.c.w)); 96 | ++index; 97 | } 98 | 99 | header = File::Header(3, (uint32_t)nodes.size(), (uint32_t)trigons.size(), cmplx._canvas); 100 | 101 | ready_to_load = true; 102 | } 103 | 104 | Complex* State::load() { 105 | 106 | if(!ready_to_load) return 0; 107 | 108 | Complex* cmplx = new Complex(); 109 | 110 | cmplx->_canvas = header.canvas; 111 | 112 | //associate each node's index with the node's memory address in the list 113 | std::vector index_node_map(header.num_nodes); 114 | std::vector index_trigon_map(header.num_trigons); 115 | 116 | for(uint32_t i = 0; i < header.num_nodes; ++i) { 117 | File::Node const& fn = nodes[i]; 118 | Node* n = new Node(Vec2i(fn.x, fn.y), (Node::Type)fn.type, Col(fn.color)); 119 | n->pp = Vec2i(fn.px, fn.py); 120 | n->w_ = fn.w; 121 | n->contrast = fn.ctrst; 122 | cmplx->nodes.push_back(n); 123 | index_node_map[i] = n; 124 | } 125 | 126 | for(uint32_t i = 0; i < header.num_trigons; ++i) { 127 | File::Tri const& ft = trigons[i]; 128 | Tri* t = new Tri(index_node_map[ft.node_a], index_node_map[ft.node_b], index_node_map[ft.node_c], (Tri::Type)ft.type, Col(ft.color)); 129 | cmplx->trigons.push_back(t); 130 | index_trigon_map[i] = t; 131 | } 132 | 133 | //link trigons with its adjacent trigons 134 | for(uint32_t i = 0; i < header.num_trigons; ++i) { 135 | Tri& t = *index_trigon_map[i]; 136 | File::Tri& ft = trigons[i]; 137 | t.a.j = ft.aj_index == (uint32_t)-1? 0 : index_trigon_map[ft.aj_index]->edge((Tri::Label)ft.aj_label); 138 | t.b.j = ft.bj_index == (uint32_t)-1? 0 : index_trigon_map[ft.bj_index]->edge((Tri::Label)ft.bj_label); 139 | t.c.j = ft.cj_index == (uint32_t)-1? 0 : index_trigon_map[ft.cj_index]->edge((Tri::Label)ft.cj_label); 140 | 141 | t.a.w = ft.aw; 142 | t.b.w = ft.bw; 143 | t.c.w = ft.cw; 144 | } 145 | 146 | //link the nodes' entry edges 147 | for(uint32_t i = 0; i < header.num_nodes; ++i) { 148 | Node& n = *index_node_map[i]; 149 | File::Node filenode = nodes[i]; 150 | n.setentry(index_trigon_map[filenode.entry_ti]->edge((Tri::Label)filenode.entry_label)); 151 | } 152 | 153 | /*Very temporary!*/ 154 | std::vector ts; 155 | for(auto t : cmplx->ts) 156 | ts.push_back(t); 157 | cmplx->cola = ts[0]->color; 158 | cmplx->colb = ts[1]->color; 159 | cmplx->colc = ts[3]->color; 160 | 161 | return cmplx; 162 | } 163 | 164 | bool State::export_to(std::string const& filename) { 165 | 166 | if(!ready_to_load) return false; 167 | 168 | std::ofstream outfile(filename, std::ofstream::binary); 169 | if(!outfile.is_open()) { 170 | std::cout << "Could not open file \"" << filename << "\"" << std::endl; 171 | return false; 172 | } 173 | 174 | outfile.write((char*)&header, sizeof(header)); 175 | outfile.write((char*)&nodes[0], sizeof(File::Node)*nodes.size()); 176 | outfile.write((char*)&trigons[0], sizeof(File::Tri)*trigons.size()); 177 | 178 | return true; 179 | } 180 | 181 | bool State::import_from(std::string const& filename) { 182 | 183 | std::ifstream infile(filename, std::ifstream::binary); 184 | infile.read((char*)&header, sizeof(header)); 185 | if(!infile.is_open()) return false; 186 | 187 | nodes.resize(header.num_nodes); 188 | trigons.resize(header.num_trigons); 189 | 190 | //This data is read into a buffer as it will be used multiple times in different iterations. 191 | infile.read((char*)&nodes[0], sizeof(File::Node)*header.num_nodes); 192 | infile.read((char*)&trigons[0], sizeof(File::Tri)*header.num_trigons); 193 | 194 | return ready_to_load = true; 195 | } 196 | -------------------------------------------------------------------------------- /src/state.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "common/color.h" 3 | #include "complex/complex.h" 4 | #include "camera.h" 5 | #include 6 | 7 | #pragma pack(push, 1) 8 | 9 | namespace File { 10 | 11 | struct Header { 12 | Header() : version(3), num_nodes(0), num_trigons(0) {} 13 | Header(uint32_t version, uint32_t num_nodes, uint32_t num_trigons, Vec2i const& canvas) : 14 | version(version), num_nodes(num_nodes), num_trigons(num_trigons), canvas(canvas){} 15 | 16 | uint32_t version; 17 | uint32_t num_nodes; 18 | uint32_t num_trigons; 19 | Vec2i canvas; 20 | }; 21 | 22 | struct Node { 23 | Node() : x(0), y(0), type(0), entry_ti(0), entry_label(0), color(0) {} 24 | Node(int64_t x, int64_t y, int64_t px, int64_t py, uint8_t t, uint32_t eti, uint8_t el, uint32_t c, double w, double ctrst) : 25 | x(x), y(y), px(px), py(py), type(t), entry_ti(eti), entry_label(el), color(c), w(w), ctrst(ctrst) {} 26 | 27 | int64_t x, y; 28 | int64_t px, py; 29 | double z; 30 | uint8_t type; 31 | uint32_t entry_ti; //entry trigon index 32 | uint8_t entry_label; //entry label 33 | uint32_t color; 34 | Vec2 n; 35 | double w; 36 | double ctrst; 37 | }; 38 | 39 | struct Tri { 40 | Tri() : index(0), type(0), color(0), node_a(0), node_b(0), node_c(0), aj_index(0), bj_index(0), cj_index(0), aj_label(0), bj_label(0), cj_label(0) {} 41 | Tri(uint32_t i, uint8_t t, uint32_t color, uint32_t na, uint32_t bn, uint32_t nc, uint32_t aj, uint32_t bj, uint32_t cj, uint8_t al, uint8_t bl, uint8_t cl, 42 | double aw, double bw, double cw) : 43 | index(i), type(t), color(color), node_a(na), node_b(bn), node_c(nc), aj_index(aj), bj_index(bj), cj_index(cj), aj_label(al), bj_label(bl), cj_label(cl), 44 | aw(aw), bw(bw), cw(cw) {} 45 | 46 | uint32_t index; 47 | uint8_t type; 48 | uint32_t color; 49 | uint32_t node_a, node_b, node_c; 50 | uint32_t aj_index, bj_index, cj_index; //The index of the adjacent trigon. -1 means no adjacent trigon. 51 | uint8_t aj_label, bj_label, cj_label; //The label of the adjacent trigon edge 52 | double aw, bw, cw; 53 | }; 54 | } 55 | 56 | #pragma pack(pop) 57 | 58 | struct State { 59 | //somewhat unintuitively we have here that: 60 | //export == load (to file) 61 | //import == save (from file) 62 | 63 | State() : ready_to_load(false) {} 64 | State(std::string const& filename); 65 | State(Complex const& cmplx); 66 | Complex* load(); 67 | 68 | bool export_to(std::string const& filename); 69 | static bool export_to(Complex const& cmplx, std::string file); 70 | static Complex* load_from(std::string file); 71 | 72 | private: 73 | bool import_from(std::string const& filename); 74 | void save(Complex const& cmplx); 75 | 76 | File::Header header; 77 | std::vector nodes; 78 | std::vector trigons; 79 | bool ready_to_load; 80 | }; 81 | -------------------------------------------------------------------------------- /src/tool/tools.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "common/entity.h" 3 | #include "camera.h" 4 | #include "complex/node.h" 5 | 6 | struct Tool { 7 | Tool() { radius = 0.008; } 8 | virtual void reset() {} 9 | virtual void timer_update() {} 10 | virtual void right_down(Vec2) {} 11 | virtual void motion(Vec2) {} 12 | virtual void left_down(Vec2) {} 13 | virtual void left_up(Vec2) {} 14 | virtual void right_up(Vec2) {} 15 | virtual void wheel_rot(double) {} 16 | 17 | public: 18 | static bool left; 19 | static bool right; 20 | double radius; 21 | }; 22 | 23 | struct Brush : Tool { 24 | static constexpr double default_brush_radius = 0.15; 25 | static constexpr double min_split_len_factor = 3; 26 | double blend_dist_th = 1; 27 | 28 | enum Actions { 29 | Drop = 1<<1, 30 | Split_line = 1<<2, 31 | Push = 1<<3, 32 | Rub = 1<<4, 33 | Contrast = 1<<5, 34 | Blur = 1<<6, 35 | Repelpinch = 1<<7, 36 | Smooth = 1<<8, 37 | Blend = 1<<9, 38 | Timer = 1<<10 39 | }; 40 | 41 | Brush() : actions(0) { radius = default_brush_radius; } 42 | Brush(int64_t actions) : actions(actions) { radius = default_brush_radius; } 43 | virtual void timer_update(); 44 | virtual void right_down(Vec2) { action(); } 45 | virtual void motion(Vec2); 46 | virtual void left_down(Vec2); 47 | virtual void left_up(Vec2) {} 48 | virtual void right_up(Vec2) {} 49 | virtual void wheel_rot(double); 50 | virtual void action(Vec2 const* scr_v = nullptr); 51 | void toggle(Actions a) { actions ^= (unsigned int)a; } 52 | 53 | void split_radius(); 54 | void split_line(Vec2 rel); 55 | void rub(Vec2 rel); 56 | void blend(); 57 | void change_contrast(); 58 | void change_blur(); 59 | void push(); 60 | void smooth(); 61 | 62 | void treat_canvas(); 63 | 64 | private: 65 | Node* split_intersection(Edge* e); 66 | int64_t actions; 67 | bool perturb; 68 | }; 69 | 70 | struct Paintbrush : Brush { Paintbrush() : Brush(Brush::Drop| Brush::Split_line | Brush::Push) {} }; 71 | struct Rubbrush : Brush { Rubbrush() : Brush(Brush::Rub | Brush::Blend | Brush::Split_line) {} }; 72 | struct Contrastbrush : Brush { Contrastbrush() : Brush(Brush::Contrast | Brush::Timer) {} }; 73 | struct Blurbrush : Brush { Blurbrush() : Brush(Brush::Blur | Brush::Timer) {} }; 74 | struct Repelpinchbrush : Brush { Repelpinchbrush() : Brush(Brush::Repelpinch | Brush::Split_line | Brush::Timer) {} }; 75 | struct Smoothbrush : Brush { Smoothbrush() : Brush(Brush::Smooth | Brush::Split_line | Brush::Timer) {} }; 76 | 77 | struct Cameratool : Tool { 78 | Cameratool() {} 79 | void motion(Vec2 rel); 80 | void left_down(Vec2 p); 81 | void left_up(Vec2 p); 82 | void right_down(Vec2 p); 83 | void right_up(Vec2 p); 84 | void wheel_rot(double delta); 85 | Vec2 o_mouse; 86 | Vec2 mouse; 87 | Vec2 o_zrotz; 88 | }; 89 | 90 | struct Selecttool : Tool { 91 | Selecttool() : selected(0) {} 92 | void motion(Vec2 rel); 93 | void left_down(Vec2 p); 94 | void right_down(Vec2 p); 95 | void wheel_rot(double delta); 96 | int id() { return selected? selected->id : 0; } 97 | Class* selected_() { return selected? selected : 0; } 98 | void reset() { selected = 0; } 99 | private: 100 | Class* selected; 101 | }; 102 | 103 | struct Colorpicker : Tool { 104 | Colorpicker() {} 105 | void left_down(Vec2 p_scr); 106 | void right_down(Vec2 p_scr); 107 | void motion(Vec2 v_scr); 108 | void pick(Vec2i p_scr); 109 | Col o_color; 110 | }; 111 | -------------------------------------------------------------------------------- /src/util.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | std::string get_file_contents(const char *filename) 9 | { 10 | std::ifstream in(filename, std::ios::in | std::ios::binary); 11 | if (in) 12 | { 13 | std::ostringstream contents; 14 | contents << in.rdbuf(); 15 | in.close(); 16 | return(contents.str()); 17 | } 18 | std::cout << "Could not read file: \"" << filename << "\"" << std::endl; 19 | return std::string(); 20 | } 21 | 22 | std::string new_filename(char const* path, char const* ext) 23 | { 24 | std::string filename; 25 | time_t t = time(0); 26 | tm& ts = *(localtime(&t)); 27 | 28 | std::stringstream f; 29 | f.fill('0'); 30 | f << path << std::setw(2) << ts.tm_mon+1 31 | << "-" << std::setw(2) << ts.tm_mday 32 | << "-" << std::setw(2) << ts.tm_hour 33 | << "-" << std::setw(2) << ts.tm_min 34 | << "-" << std::setw(2) << ts.tm_sec; 35 | 36 | bool valid_filename_found = false; 37 | for(int count = 1; !valid_filename_found; ++count) { 38 | std::stringstream out(f.str()); 39 | out.seekp(0, std::ios_base::end); 40 | if(count > 1) out << "-" << count; 41 | filename = out.str() + ext; 42 | std::ifstream file(filename); 43 | valid_filename_found = !file.is_open(); 44 | } 45 | 46 | return filename; 47 | } 48 | -------------------------------------------------------------------------------- /src/util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common/vector.h" 4 | #include 5 | 6 | #define GET_A(X) ((X & 0xff000000) >> 24) 7 | #define GET_R(X) ((X & 0x00ff0000) >> 16) 8 | #define GET_G(X) ((X & 0x0000ff00) >> 8) 9 | #define GET_B(X) (X & 0x000000ff) 10 | 11 | #define WGET_R(X) ((Uint32)((X & 0x00ff0000) >> 16)) 12 | #define WGET_G(X) ((Uint32)((X & 0x0000ff00) >> 8)) 13 | #define WGET_B(X) ((Uint32)(X & 0x000000ff)) 14 | 15 | #define PUT_A(X) ((X) << 24) 16 | #define PUT_R(X) ((X) << 16) 17 | #define PUT_G(X) ((X) << 8) 18 | #define PUT_B(X) (X) 19 | 20 | #define PUT_RGB(X, Y, Z) ((((Uint8)(X)) << 16) | (((Uint8)(Y)) << 8) | (Uint8)(Z)) 21 | #define PUT_RGBA(X, Y, Z, W) ((((Uint8)(W)) << 24) | (((Uint8)(X)) << 16) | (((Uint8)(Y)) << 8) | (Uint8)(Z)) 22 | 23 | #define SWAP(A, B, T) T = A; A = B; B = T 24 | 25 | template S area(Vector2 a, Vector2 b, Vector2 c) { 26 | Vector2 ab = b - a; 27 | Vector2 ac = c - a; 28 | return ab.x*ac.y - ab.y*ac.x; 29 | } 30 | 31 | template Vector2 rot90(Vector2 const& a) { 32 | return Vector2(-a.y, a.x); 33 | } 34 | 35 | std::string new_filename(char const* path, char const* ext); 36 | std::string get_file_contents(const char *filename); 37 | -------------------------------------------------------------------------------- /src/window.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "graphics/graphics.h" 9 | #include "common/entity.h" 10 | #include "tool/tools.h" 11 | #include "globals.h" 12 | 13 | const double NormalPitchSpeed = 0.05; 14 | const double NormalYawSpeed = 1.; 15 | 16 | QT_BEGIN_NAMESPACE 17 | class QSlider; 18 | class QPushButton; 19 | QT_END_NAMESPACE 20 | 21 | class GLWidget; 22 | class MainWindow; 23 | 24 | class Window : public QWidget { 25 | Q_OBJECT 26 | 27 | public: 28 | Window(); 29 | 30 | void dump_canvas2(std::string name = ""); 31 | 32 | public slots: 33 | void set_brush_color(); 34 | 35 | void new_canvas(); 36 | void reset_view(); 37 | void dump_canvas(); 38 | void connect_toggle_buttons(); 39 | 40 | void set_surface(bool b); 41 | void set_control_net(bool b); 42 | void set_edges(bool b); 43 | void set_nodes(bool b); 44 | void set_contours(bool b); 45 | void set_gaussian(bool b); 46 | 47 | signals: 48 | void surface_changed(bool b); 49 | void control_net_changed(bool b); 50 | void edges_changed(bool b); 51 | void nodes_changed(bool b); 52 | void contours_changed(bool b); 53 | void gaussian_changed(bool b); 54 | 55 | protected: 56 | void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE; 57 | void keyReleaseEvent(QKeyEvent *event) Q_DECL_OVERRIDE; 58 | void timerEvent(QTimerEvent *event) Q_DECL_OVERRIDE; 59 | 60 | public: 61 | bool space_down; 62 | 63 | void set_colorpicker_button_color(); 64 | 65 | private: 66 | void wasd_press(int key); 67 | std::string get_QLineEdit_string(QLineEdit* le); 68 | 69 | QMainWindow *main_window; 70 | QLineEdit* save_name; 71 | 72 | QCheckBox *surface_button, *gaussian_button, *control_net_button, *edges_button, *nodes_button, *contours_button; 73 | QCheckBox *drop_button, *blend_button, *split_button, *rub_button, *push_button, *contrast_button, *blur_button, *smooth_button, *timer_button; 74 | 75 | const int timer_interval = 10; //ms 76 | unsigned int timer_modulo = 1; 77 | unsigned int timer_counter = 0; 78 | }; 79 | --------------------------------------------------------------------------------