From 290b677dbe0d3308afe00ffaa39806038d2665bc Mon Sep 17 00:00:00 2001 From: danya Date: Mon, 22 Mar 2021 14:03:00 +0300 Subject: [PATCH] coons patch and tensor shading made somewhat working realisation of coons patch gradient and tensor shading still need debugging and optimisations --- .../include/test_grads/custom_gradients.h | 195 ++++++++++++++---- DesktopEditor/graphics/shading_info.h | 30 ++- DesktopEditor/graphics/structures.h | 1 - .../gradient/Gradient/mainwindow.cpp | 32 ++- .../gradient/Gradient/mainwindow.h | 2 +- 5 files changed, 194 insertions(+), 66 deletions(-) diff --git a/DesktopEditor/agg-2.4/include/test_grads/custom_gradients.h b/DesktopEditor/agg-2.4/include/test_grads/custom_gradients.h index 0e965117fe..a0573dd077 100644 --- a/DesktopEditor/agg-2.4/include/test_grads/custom_gradients.h +++ b/DesktopEditor/agg-2.4/include/test_grads/custom_gradients.h @@ -1,6 +1,6 @@ #include #include - +#include "../../../graphics/AggPlusEnums.h" #ifndef M_1_PI #define M_1_PI 0.318309886183790671538 #endif @@ -185,9 +185,9 @@ namespace agg virtual float eval(float x, float y) override { auto w = baricentric_weights({x, y}, ginfo.shading.triangle); - return w[0] * ginfo.shading.triangle_parametrs[0] + - w[1] * ginfo.shading.triangle_parametrs[1] + - w[2] * ginfo.shading.triangle_parametrs[2]; + return w[0] * ginfo.shading.triangle_parameters[0] + + w[1] * ginfo.shading.triangle_parameters[1] + + w[2] * ginfo.shading.triangle_parameters[2]; } /** @@ -221,15 +221,15 @@ namespace agg ginfo = _g; if (calculate_tensor_coefs) calculate_tensor(); - RES = 10; //ginfo.shading.function.get_resolution(); + RES = ginfo.shading.function.get_resolution(); float delta = 1.0 / RES; float u = 0, v = 0; auto start_p = get_p(u, v); xmax = xmin = start_p.x; ymax = ymin = start_p.y; - precalc = std::vector>(RES, std::vector(RES, 0.0f)); + precalc = std::vector>(RES, std::vector(RES, 0.0f/0.0f)); // nan for (;u <= 1; u += delta) { - for (;v <= 1; v+= delta) { + for (v = 0;v <= 1; v+= delta) { auto p = get_p(u, v); xmax = std::max(p.x, xmax); ymax = std::max(p.y, ymax); @@ -241,32 +241,28 @@ namespace agg for (v = 0.0; v <= 1; v+= delta) { auto p = get_p(u, v); auto i = get_index(p.x, p.y); - if (i.first == 0 || i.first == RES - 1 || i.second == 0 || i.second == RES - 1) - precalc[i.first][i.second] = 0; - else - precalc[i.first][i.second] = 1; + if (i.first > RES -1 || i.second > RES - 1 || i.first < 0 || i.second < 0) + { + continue; + } + precalc[i.first][i.second] = + ginfo.shading.patch_parameters[0][0] * (1 - v) * (1 - u) + + ginfo.shading.patch_parameters[0][1] * (1 - v) * u + + ginfo.shading.patch_parameters[1][0] * v * (1 - u) + + ginfo.shading.patch_parameters[1][1] * v * u; } } } virtual float eval(float x, float y) override { auto i = get_index(x, y); + if (i.first > RES -1 || i.second > RES - 1 || i.first < 0 || i.second < 0) + return 0.0f/0.0f; // nan intentionaly + return precalc[i.first][i.second]; } - private: - NSStructures::Point get_p(float u, float v) - { - NSStructures::Point p; - for (int i = 0; i < tensor_size; i++) - { - for (int j = 0; j < tensor_size; j++) { - p+= ginfo.shading.patch[i][j] * berstein_polynomial(u, i) * berstein_polynomial(v, j); - } - } - return p; - } - float berstein_polynomial(float t, int i) + static float berstein_polynomial(float t, int i) { switch (i) { @@ -284,6 +280,19 @@ namespace agg } } + + private: + NSStructures::Point get_p(float u, float v) + { + NSStructures::Point p; + for (int i = 0; i < tensor_size; i++) + { + for (int j = 0; j < tensor_size; j++) { + p+= ginfo.shading.patch[i][j] * berstein_polynomial(u, i) * berstein_polynomial(v, j); + } + } + return p; + } // pdf 208p. void calculate_tensor() { @@ -311,16 +320,7 @@ namespace agg std::pair get_index(float x, float y) { size_t x_index = (size_t)(RES - 1) * (x - xmin) / (xmax - xmin); - if (x_index < 0) - x_index = 0; - if (x_index > RES - 1) - x_index = RES - 1; - size_t y_index = (size_t)(RES - 1) * (y - ymin) / (ymax - ymin); - if (y_index < 0) - y_index = 0; - if (y_index > RES - 1) - y_index = RES - 1; return {x_index, y_index}; } @@ -427,6 +427,13 @@ namespace agg { m_oGradientInfo = _g; invStep = 1.0f / m_oGradientInfo.discrete_step; + + if (m_oGradientInfo.shading.shading_type == NSStructures::ShadingInfo::TensorCurveInterpolation) + initialise_curve(false); + + if (m_oGradientInfo.shading.shading_type == NSStructures::ShadingInfo::CurveInterpolation) + initialise_curve(); + switch (bType) { case Aggplus::BrushTypeRadialGradient: @@ -454,7 +461,7 @@ namespace agg break; case Aggplus::BrushTypeTensorCurveGradient: - calculate = new calcCurve(m_oGradientInfo, false); + calculate = new calcCurve(m_oGradientInfo, false); break; default: @@ -507,20 +514,24 @@ namespace agg } else if (m_oGradientInfo.shading.shading_type == NSStructures::ShadingInfo::CurveInterpolation) { - *span++ = this->triangle(x,y); // todo + *span++ = this->curve_eval(x,y); // todo } - else if (m_oGradientInfo.shading.shading_type == NSStructures::ShadingInfo::TesorCurveInterpolation) + else if (m_oGradientInfo.shading.shading_type == NSStructures::ShadingInfo::TensorCurveInterpolation) { - *span++ = this->triangle(x,y); // todo + *span++ = this->curve_eval(x,y); // todo } else if (m_oGradientInfo.shading.shading_type == NSStructures::ShadingInfo::Parametric) { float t = calculate_param(x,y); - if (m_oGradientInfo.shading.f_type == NSStructures::ShadingInfo::UseNew) + if (isnan(t)) + { + *span++ = {0,0,0,0}; + } + else if (m_oGradientInfo.shading.f_type == NSStructures::ShadingInfo::UseNew) { *span++ = m_oGradientInfo.shading.function.get_color(t); } - if (m_oGradientInfo.shading.f_type == NSStructures::ShadingInfo::UseOld) + else if (m_oGradientInfo.shading.f_type == NSStructures::ShadingInfo::UseOld) { int index = int(t * MaxColorIndex + 0.5); if (!m_valid_table[index]) @@ -633,5 +644,109 @@ namespace agg } - }; + /** + * Здесь все относящееся к кривой поверхности, будет дублирование кода, зато потом в теории будет проще работать. + * И логика чуть менее запутанная. + * Основной алгоритм - разбить поверхность на множество квадратиков. И забить туда значения сразу. Чтобы обратную фнкцию не считать. + * + */ + + std::vector> precalc; + size_t tensor_size; + float xmin_curve, xmax_curve, ymin_curve, ymax_curve; + size_t RES; + + void initialise_curve(bool calculate_tensor_coefs = true) + { + tensor_size = 4; + if (calculate_tensor_coefs) + calculate_tensor(); + RES = m_oGradientInfo.shading.function.get_resolution(); + float delta = 1.0 / RES; + float u = 0, v = 0; + auto start_p = get_p_curve(u, v); + xmax_curve = xmin_curve = start_p.x; + ymax_curve = ymin_curve = start_p.y; + precalc = std::vector>(RES, std::vector(RES, {0,0,0,0})); + for (;u <= 1; u += delta) { + for (v = 0;v <= 1; v+= delta) { + auto p = get_p_curve(u, v); + xmax_curve = std::max(p.x, xmax_curve); + ymax_curve = std::max(p.y, ymax_curve); + xmin_curve = std::min(p.x, xmin_curve); + ymin_curve = std::min(p.y, ymin_curve); + } + } + for (u = 0.0; u <= 1; u += delta) { + for (v = 0.0; v <= 1; v+= delta) { + auto p = get_p_curve(u, v); + auto i = get_index_curve(p.x, p.y); + if (i.first > RES -1 || i.second > RES - 1 || i.first < 0 || i.second < 0) + { + continue; + } + + ColorT c00 = mul(m_oGradientInfo.shading.patch_colors[0][0], (1 - u) * (1 - v)); + ColorT c01 = mul(m_oGradientInfo.shading.patch_colors[0][1], u * (1 - v)); + ColorT c10 = mul(m_oGradientInfo.shading.patch_colors[1][0], (1 - u) * v); + ColorT c11 = mul(m_oGradientInfo.shading.patch_colors[1][1], u * v); + precalc[i.first][i.second] = sum(c00, sum(c01, sum(c10, c11))); + } + } + } + + ColorT curve_eval(float x, float y) + { + auto i = get_index_curve(x, y); + if (i.first > RES -1 || i.second > RES - 1 || i.first < 0 || i.second < 0) + return {0,0,0,0}; + + return precalc[i.first][i.second]; + } + + NSStructures::Point get_p_curve(float u, float v) + { + NSStructures::Point p; + for (int i = 0; i < tensor_size; i++) + { + for (int j = 0; j < tensor_size; j++) { + p+= m_oGradientInfo.shading.patch[i][j] * + calcCurve::berstein_polynomial(u, i) * calcCurve::berstein_polynomial(v, j); + } + } + return p; + } + + // pdf 208p. + void calculate_tensor() + { + auto p = m_oGradientInfo.shading.patch; + //----------------------------------------------------------------------------- + p[1][1] = (1.0 / 9) * ( -4.0 * p[0][0] + 6 * ( p[0][1] + p[1][0] ) + + - 2 * ( p[0][3] + p[3][0] ) + 3 * ( p[3][1] + p[1][3] ) - p[3][3] ); + //----------------------------------------------------------------------------- + p[1][2] = (1.0 / 9) * ( -4.0 * p[0][3] + 6 * ( p[0][2] + p[1][3] ) + + - 2 * ( p[0][0] + p[3][3] ) + 3 * ( p[3][2] + p[1][0] ) - p[3][0] ); + //----------------------------------------------------------------------------- + p[2][1] = (1.0 / 9) * ( -4.0 * p[3][0] + 6 * ( p[3][1] + p[2][0] ) + + - 2 * ( p[3][3] + p[0][0] ) + 3 * ( p[0][1] + p[2][3] ) - p[0][3] ); + //----------------------------------------------------------------------------- + p[2][2] = (1.0 / 9) * ( -4.0 * p[3][3] + 6 * ( p[3][2] + p[2][3] ) + + - 2 * ( p[3][0] + p[0][3] ) + 3 * ( p[0][2] + p[2][0] ) - p[0][0] ); + //----------------------------------------------------------------------------- + m_oGradientInfo.shading.patch = p; + } + + std::pair get_index_curve(float x, float y) + { + size_t x_index = (size_t)(RES - 1) * (x - xmin_curve) / (xmax_curve - xmin_curve); + size_t y_index = (size_t)(RES - 1) * (y - ymin_curve) / (ymax_curve - ymin_curve); + + return {x_index, y_index}; + } + }; } diff --git a/DesktopEditor/graphics/shading_info.h b/DesktopEditor/graphics/shading_info.h index 03c5798d60..2a5f8aecd7 100644 --- a/DesktopEditor/graphics/shading_info.h +++ b/DesktopEditor/graphics/shading_info.h @@ -24,7 +24,7 @@ namespace NSStructures * */ // TODO div optimise template - class ColorFuction + class ColorFunction /** * Реализацию произвольной функции в рантайме я решил сделать как массив, тк так проще всего * я еще не совсем понял как точно передается в пдфе функция, но такая реализация, позволяет пользователю @@ -49,7 +49,7 @@ namespace NSStructures { public: // Default constructor works only with one parameter functions - ColorFuction() : RESOLUTION(512), x_domain_min(0.0f), x_domain_max(1.0f) + ColorFunction() : RESOLUTION(512), x_domain_min(0.0f), x_domain_max(1.0f) { values = std::vector>(1, std::vector(RESOLUTION)); for (int i = 0; i < RESOLUTION; i++) @@ -59,8 +59,8 @@ namespace NSStructures } } - ColorFuction(size_t res, float xmin, float xmax) : RESOLUTION(res), x_domain_min(xmin), x_domain_max(xmax) - + ColorFunction(size_t res, float xmin, float xmax) : RESOLUTION(res), x_domain_min(xmin), x_domain_max(xmax) + { values = std::vector>(1, std::vector(RESOLUTION)); for (int i = 0; i < RESOLUTION; i++) @@ -70,7 +70,7 @@ namespace NSStructures } } - ColorFuction(size_t res, float xmin, float xmax, float ymin, float ymax) : RESOLUTION(res), x_domain_min(xmin), x_domain_max(xmax), y_domain_min(ymin), y_domain_max(ymax) + ColorFunction(size_t res, float xmin, float xmax, float ymin, float ymax) : RESOLUTION(res), x_domain_min(xmin), x_domain_max(xmax), y_domain_min(ymin), y_domain_max(ymax) { values = std::vector>(RESOLUTION, std::vector(RESOLUTION)); for (int i = 0; i < RESOLUTION; i++) @@ -210,7 +210,6 @@ namespace NSStructures unsigned int hex2a(uint32_t c) { unsigned int a = (c >> 24) % 0x100; - std::cout << a << "sdfsd\n"; return a; } @@ -292,22 +291,21 @@ namespace NSStructures Parametric, TriangleInterpolation, CurveInterpolation, - TesorCurveInterpolation + TensorCurveInterpolation } shading_type; enum ColorFunctionType { UseOld, UseNew - }f_type; // if UseOld old function is called, look for IChaphicsRender.put_BrushGradientColors; - ColorFuction function; + }f_type; // if UseOld old function is called, look for IGraphicsRender.put_BrushGradientColors; + ColorFunction function; bool default_mapping; // boundaries to domain of color function // triangle shading - bool parametrised_triangle_shading; std::vector triangle; std::vector triangle_colors; - std::vector triangle_parametrs; + std::vector triangle_parameters; // non linear (NOT ready) пока не написал, как кривую переводить в нормальные координаты bool parametrised_curve_shading; @@ -321,8 +319,8 @@ namespace NSStructures * Наверное напишу адаптор который переводит порядок точек из 6 типа в общий. */ std::vector> patch; - std::vector patch_colors; // 4 цвета по углам - std::vector patch_patamerts; // 4 параметра + std::vector> patch_colors; // 2 на 2 цвета по углам + std::vector> patch_parameters; // 2 на 2 параметра }; // Containing additional info about gradient @@ -347,7 +345,7 @@ namespace NSStructures { return angle / (float)M_PI * 180.f; } - void setStepByNum(int n) // recomended to use + void setStepByNum(int n) // recommended to use { discrete_step = 1.0f / n; } @@ -355,11 +353,11 @@ namespace NSStructures float littleRadius, largeRadius; // used in radial gradient - [0, 1] float centerX, centerY; // used in radial, diamond and conical gradient - offset relative to figure center float angle; // used in linear and conical gradient (rad) - float discrete_step; // used to make discrete gradient. <= 0 to make continious + float discrete_step; // used to make discrete gradient. <= 0 to make continuous float xsize, ysize; // stretch image; can be negative to reflect relative to other axis; cannot be zero bool reflected; // 1234567 -> 1357531 works kind of like this bool periodic; - float periods; // number of perionds (best with to colours, works as saw fuction in color space) + float periods; // number of periods (best with to colours, works as saw function in color space) float linstretch; // stretch linear gradient, can be negative (eq angle = 180) can not be zero float linoffset; // offset relative to image size ShadingInfo shading; diff --git a/DesktopEditor/graphics/structures.h b/DesktopEditor/graphics/structures.h index 18a0163192..27dbcb33f7 100644 --- a/DesktopEditor/graphics/structures.h +++ b/DesktopEditor/graphics/structures.h @@ -111,7 +111,6 @@ const long c_BrushTypeTriagnleMeshGradient = 6005; const long c_BrushTypeCurveGradient = 6006; const long c_BrushTypeTensorCurveGradient = 6007; -const long c_BrushTypeShading = 7000; const long c_BrushTextureModeStretch = 0; const long c_BrushTextureModeTile = 1; diff --git a/Test/Applications/gradient/Gradient/mainwindow.cpp b/Test/Applications/gradient/Gradient/mainwindow.cpp index a05e8ec5c0..6b56bbc0fa 100644 --- a/Test/Applications/gradient/Gradient/mainwindow.cpp +++ b/Test/Applications/gradient/Gradient/mainwindow.cpp @@ -169,18 +169,34 @@ void MainWindow::on_PathType_itemClicked(QListWidgetItem *item) * С опцией Parametric можно тестить другие градиенты. * */ - info.gradient_type = c_BrushTypeTriagnleMeshGradient; - info.ginfo.shading.shading_type = NSStructures::ShadingInfo::TriangleInterpolation; + info.gradient_type = c_BrushTypeTensorCurveGradient; + info.ginfo.shading.shading_type = NSStructures::ShadingInfo::Parametric; info.ginfo.shading.triangle = {{5 * 3.84, 10 * 3.84}, {40 * 3.84, 100 * 3.84}, {100 * 3.84, 1 * 3.84}}; - info.ginfo.shading.triangle_parametrs = {0.0f, 0.5f, 1.0f} ; + info.ginfo.shading.triangle_parameters = {0.0f, 0.5f, 1.0f} ; info.ginfo.shading.triangle_colors = {{255,0,0, 255}, {255,255,0,255 }, {0,255,0,255}}; info.ginfo.shading.patch = { - {{10, 40}, {}, {}, {10,10}}, - {{}, {}, {}, {}}, - {{}, {}, {}, {}}, - {{40,40}, {}, {}, {40,10}} + {{10, 80}, {20, 70}, {0, 20}, {10,10}}, + {{25, 75}, {40, 60}, {40, 40}, {20, 0}}, + {{90, 70}, {60,60}, {60, 40}, {70, 20}}, + {{80,80}, {70, 70}, {90, 20}, {80,80}} }; + info.ginfo.shading.patch_parameters = { + {0 , 1}, + {1, 0.5} + }; + info.ginfo.shading.patch_colors = { + {{255, 0, 0}, {0, 255, 255}}, + {{0, 255, 0}, {0, 0, 255}} + }; + float mult = 4.0; + for (int i = 0; i < info.ginfo.shading.patch.size(); i++) + { + for (int j = 0; j < info.ginfo.shading.patch[0].size(); j++) + { + info.ginfo.shading.patch[i][j] = info.ginfo.shading.patch[i][j] * mult; + } + } } } @@ -265,7 +281,7 @@ void MainWindow::on_ColorSpaces_itemClicked(QListWidgetItem *item) info.ginfo.shading.function.set_linear_interpolation({0xFFff0000, 0xFFffa500, 0xFFffff00, 0xFF008000, 0xFF0000ff, 0xFFFF00FF} , {0.0f,0.2f,0.4f,0.6f,0.8f,1.0f}); } - else if (item->text() == "Black and wh200ite") { + else if (item->text() == "Black and white") { info.c = {(LONG)0xFFFFFFFF, (LONG)0xFF000000}; info.p = {0.0, 1}; info.n_colors = 2; diff --git a/Test/Applications/gradient/Gradient/mainwindow.h b/Test/Applications/gradient/Gradient/mainwindow.h index 3138e5df63..cd813d0002 100644 --- a/Test/Applications/gradient/Gradient/mainwindow.h +++ b/Test/Applications/gradient/Gradient/mainwindow.h @@ -39,7 +39,7 @@ struct Info { c = {(LONG)0xFFff0000, (LONG)0xFFffa500, (LONG)0xFFffff00, (LONG)0xFF008000, (LONG)0xFF0000ff, (LONG)0xFFFF00FF}; p = {0.0,0.2,0.4,0.6,0.8,1}; n_colors = 6; - ginfo.shading.parametrised_triangle_shading = false; + ginfo.shading.shading_type = NSStructures::ShadingInfo::Parametric; }; ~Info() { }