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 06712f0f78..4702096b09 100644 --- a/DesktopEditor/agg-2.4/include/test_grads/custom_gradients.h +++ b/DesktopEditor/agg-2.4/include/test_grads/custom_gradients.h @@ -5,10 +5,13 @@ #define M_1_PI 0.318309886183790671538 #endif +#ifndef NAN_FLOAT +#define NAN_FLOAT 0.0f/0.0f +#endif + #ifndef SHADING_PDF #define SHADING_PDF - namespace agg { /** @@ -21,10 +24,16 @@ namespace agg * * */ + + /** + * Абстрактный класс для параметризации. + * + * Чтобы показать что данный пиксель не надо закрашивать используется nan + */ class calcBase { public: - virtual float eval(float , float ) = 0; + virtual float eval(float, float) = 0; virtual ~calcBase() {} void set_rotation(float angle) { @@ -51,12 +60,15 @@ namespace agg { srand(time(NULL)); } - virtual float eval(float , float ) override + virtual float eval(float, float) override { - return rand() / (float )RAND_MAX; + return rand() / (float)RAND_MAX; } }; + /** + * Параметр радисального градиента. + */ class calcRadial : public calcBase { public: @@ -87,6 +99,9 @@ namespace agg float invXsize, invYsize; }; + /** + * Параметр конусного градиента. Не используется в пдф. + */ class calcConical : public calcBase { public: @@ -115,7 +130,10 @@ namespace agg float invXsize, invYsize; float m1pi; }; - + + /** + * Параметр квадратного градиента. Не используется в пдф. + */ class calcDiamond : public calcBase { public: @@ -146,6 +164,9 @@ namespace agg float invXsize, invYsize; }; + /** + * Параметр линейного градиента. + */ class calcNewLinear : public calcBase { public: @@ -177,6 +198,9 @@ namespace agg NSStructures::GradientInfo ginfo; }; + /** + * Треугольный шейдинг, закрашивает всю область. + */ class calcTriangle : public calcBase { public: @@ -200,26 +224,30 @@ namespace agg baricentric_weights(const NSStructures::Point &P, const std::vector &t) { std::vector r(3); - r[0] = ( (t[1].y - t[2].y) * (P.x - t[2].x) + (t[2].x - t[1].x) * (P.y - t[2].y) ) / - ((t[1].y - t[2].y) * (t[0].x - t[2].x) + (t[2].x - t[1].x) * (t[0].y - t[2].y)); - r[1] = ( (t[2].y - t[0].y) * (P.x - t[2].x) + (t[0].x - t[2].x) * (P.y - t[2].y) ) / - ((t[1].y - t[2].y) * (t[0].x - t[2].x) + (t[2].x - t[1].x) * (t[0].y - t[2].y)); + r[0] = ((t[1].y - t[2].y) * (P.x - t[2].x) + (t[2].x - t[1].x) * (P.y - t[2].y)) / + ((t[1].y - t[2].y) * (t[0].x - t[2].x) + (t[2].x - t[1].x) * (t[0].y - t[2].y)); + r[1] = ((t[2].y - t[0].y) * (P.x - t[2].x) + (t[0].x - t[2].x) * (P.y - t[2].y)) / + ((t[1].y - t[2].y) * (t[0].x - t[2].x) + (t[2].x - t[1].x) * (t[0].y - t[2].y)); r[2] = 1 - r[0] - r[1]; return r; } NSStructures::GradientInfo ginfo; }; + /** + * Шейдинг гладкой поверхности, закрашивает только саму поверхность. + * + * Алгоритм работы примерно следующий. + * Проходимся по плоскости значений параметра, и для каждой точки закрашиваем квадрат с границой. + * + * P(u,v), P(u + du, u + dv) - углы. + * + * Это позволяет изьежать вычисления обратной функции, которую можно в общем случаем почтитать только методом Ньютона. + */ class calcCurve : public calcBase { - /** - * Проходим по всем значениям параметра и рисуем, т.к. иначе придется решать систему кубических уравнений. - * - * Судя по всему чтото сильно эффективней для кривых не написать, разве что - * Можно пытаться отрисовывать как можно меньше, например делать шаг больше не на границе, - * но у этого свои минусы. В любом случае, такой объект будет очень плохо постоянно перерисовывать. - */ public: + // В конструкторе происходит весь прекалк, т.е. экзепляр класса полностью готов к работе. calcCurve(const NSStructures::GradientInfo &_g, bool calculate_tensor_coefs = true) : tensor_size(4) { ginfo = _g; @@ -231,8 +259,10 @@ namespace agg auto start_p = get_p(u, v); xmax = xmin = start_p.x; ymax = ymin = start_p.y; - for (;u <= 1; u += delta) { - for (v = 0;v <= 1; v+= delta) { + for (; u <= 1; u += 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); @@ -240,72 +270,74 @@ namespace agg ymin = std::min(p.y, ymin); } } - + RES = (int)std::max(ymax - ymin, xmax - xmin); - precalc = std::vector>(RES, std::vector(RES, 0.0f/0.0f)); // nan + precalc = std::vector>(RES, std::vector(RES, NAN_FLOAT)); delta = 1.0f / RES; std::pair prev_i; - /** - * В худшем случае, константа на которую надо делить это 3 - значит будет рабоать в 9 раз медленнее - * - * Я думаю над некоторыми оптимизациями, главная проблема в том что шаг идет по двум измерениям. - * - * - */ - for (u = 0.0; u <= 1; u += delta / 1.4) { - bool start = true; - for (v = 0.0; v <= 1; v+= delta / 1.4) { + for (u = 0; u <=1; u+=delta) + { + for (v = 0; v <= 1; v+=delta) + { NSStructures::Point p = get_p(u, v); - std::pair i = get_index(p.x, p.y); - - if (i.first > RES -1 || i.second > RES - 1 || i.first < 0 || i.second < 0) - { - continue; - } + std::pair index1 = get_index(p.x, p.y); + p = get_p(u + delta, v + delta); + std::pair index2 = get_index(p.x, p.y); float t = - 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; - - precalc[i.first][i.second] = t; - - start = false; - prev_i = i; + 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; + + fill_square(index1, index2, t); } } } + + // Заполняем квадрат в один цвет, чтобы небыло пропусков. + void fill_square(std::pair index1, std::pair index2, float t) + { + for (int i = std::min(index1.first, index2.first); i <= std::max(index1.first, index2.first); i++) + { + for (int j = std::min(index1.second, index2.second); j <= std::max(index1.second, index2.second); j++) + { + if (i < RES && j < RES) + { + precalc[i][j] = t; + } + } + } + } + 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 + if (i.first > RES - 1 || i.second > RES - 1 || i.first < 0 || i.second < 0) + return NAN_FLOAT; // Не закрашиваем return precalc[i.first][i.second]; } - /** - * Через полинамы такого вида определяется нужная нам поверхность. - */ - static float berstein_polynomial(float t, int i) + + // Через полинамы такого вида определяется нужная нам поверхность. + static float berstein_polynomial(float t, int i) { switch (i) { case 0: - return (1 - t) * (1 - t) * (1- t); + return (1 - t) * (1 - t) * (1 - t); case 1: - return 3 * t * (1 - t) * (1- t); + return 3 * t * (1 - t) * (1 - t); case 2: - return 3 * t * t * (1- t); + return 3 * t * t * (1 - t); case 3: return t * t * t; - + default: printf("!!!!!!"); } } - private: NSStructures::Point get_p(float u, float v) @@ -313,44 +345,50 @@ namespace agg 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); + 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. + } + + /** + * т.к. шестой тип шейдинга по сути является частным случаем седьмого, только с пересчетом некоторый точек. + * Этот метод позволяет вычислить нужные параметры, подробнее в стандарте пдф 208с. + */ void calculate_tensor() { auto p = ginfo.shading.patch; //----------------------------------------------------------------------------- - p[1][1] = (1.0 / 9) * ( -4.0 * p[0][0] + 6 * ( p[0][1] + p[1][0] ) + 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] ); + - 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] ) + 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] ); + - 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] ) + 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] ); + - 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] ) + 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] ); + - 2 * (p[3][0] + p[0][3]) + 3 * (p[0][2] + p[2][0]) - p[0][0]); //----------------------------------------------------------------------------- ginfo.shading.patch = p; } - + std::pair get_index(float x, float y) { size_t x_index = (int)(RES - 1) * (x - xmin) / (xmax - xmin); size_t y_index = (int)(RES - 1) * (y - ymin) / (ymax - ymin); - + return {x_index, y_index}; } + NSStructures::GradientInfo ginfo; std::vector> precalc; const size_t tensor_size; @@ -358,12 +396,17 @@ namespace agg size_t RES; }; + + /** + * Основной класс отвечающий за градиенты. + */ template class gradient_base { public: typedef ColorT color_type; - protected: + + private: enum { StateInit = 0, @@ -372,7 +415,7 @@ namespace agg MaxColorIndex = 512 }; - protected: + private: int m_state; NSStructures::GradientInfo m_oGradientInfo; @@ -383,7 +426,7 @@ namespace agg agg::trans_affine m_trans; - protected: + private: const color_type *m_pSubColors; const float *m_pPosSubColors; int m_nCountSubColors; @@ -392,32 +435,20 @@ namespace agg color_type m_color_table[MaxColorIndex + 1]; bool m_valid_table[MaxColorIndex + 1]; - protected: - + private: + + // Параметризация, с некторыми обертками. inline float calculate_param(const float &x, const float &y) { float t = calculate->eval(x, y); + if(isnanf(t)) + return t; + + if (t < 0 && !m_oGradientInfo.continue_shading) + return NAN_FLOAT; + if (t > 1 && !m_oGradientInfo.continue_shading) + return NAN_FLOAT; - if (m_oGradientInfo.discrete_step > FLT_EPSILON) - { - if (t >= 1) - t -= FLT_EPSILON; - t = m_oGradientInfo.discrete_step * floor(t * invStep) + 0.5 * m_oGradientInfo.discrete_step; - } - - if (m_oGradientInfo.periodic) - { - t = triagle_saw(m_oGradientInfo.periods * t); - } - - if (m_oGradientInfo.reflected) - { - t *= 2; - if (t > 1 + FLT_EPSILON) - { - t = 2. - t; - } - } if (t > m_oGradientInfo.largeRadius) return 1; if (t < m_oGradientInfo.littleRadius) @@ -426,10 +457,6 @@ namespace agg return t; t = (t - m_oGradientInfo.littleRadius) / (m_oGradientInfo.largeRadius - m_oGradientInfo.littleRadius); // TODO optimize - if (t < 0) - return 0; - if (t > 1) - return 1; return t; } @@ -455,10 +482,10 @@ namespace agg invStep = 1.0f / m_oGradientInfo.discrete_step; if (m_oGradientInfo.shading.shading_type == NSStructures::ShadingInfo::TensorCurveInterpolation) - initialise_curve(false); + initialise_curve(false); if (m_oGradientInfo.shading.shading_type == NSStructures::ShadingInfo::CurveInterpolation) - initialise_curve(); + initialise_curve(); switch (bType) { @@ -487,7 +514,7 @@ namespace agg break; case Aggplus::BrushTypeTensorCurveGradient: - calculate = new calcCurve(m_oGradientInfo, false); + calculate = new calcCurve(m_oGradientInfo, false); break; default: @@ -526,7 +553,7 @@ namespace agg { for (unsigned count = 0; count < len; ++count, ++x) { - if (m_oGradientInfo.shading.shading_type == NSStructures::ShadingInfo::FunctionOnly) + if (m_oGradientInfo.shading.shading_type == NSStructures::ShadingInfo::FunctionOnly) { float _x = x; float _y = y; @@ -540,18 +567,18 @@ namespace agg } else if (m_oGradientInfo.shading.shading_type == NSStructures::ShadingInfo::CurveInterpolation) { - *span++ = this->curve_eval(x,y); // todo + *span++ = this->curve_eval(x, y); } else if (m_oGradientInfo.shading.shading_type == NSStructures::ShadingInfo::TensorCurveInterpolation) { - *span++ = this->curve_eval(x,y); // todo + *span++ = this->curve_eval(x, y); } else if (m_oGradientInfo.shading.shading_type == NSStructures::ShadingInfo::Parametric) { - float t = calculate_param(x,y); - if (isnan(t)) + float t = calculate_param(x, y); + if (isnan(t)) { - *span++ = {0,0,0,0}; + *span++ = {0, 0, 0, 0}; } else if (m_oGradientInfo.shading.f_type == NSStructures::ShadingInfo::UseNew) { @@ -567,7 +594,7 @@ namespace agg } } } - + /** * Выставляем всякую инфу про наш градиент. */ @@ -636,26 +663,28 @@ namespace agg return fabs(2 * asinf(sinf(x * pi)) * M_1_PI); } - int limit8bit(int a) { + + // Нужно для безопасного сложения цветов. + int limit8bit(int a) + { if (a >= 0x100) return 0xFF; return a; } - /** - * Умножение цвета на число (теплейт поэтому не перегрузка *) - */ + + + // Умножение цвета на число (теплейт поэтому не перегрузка *) ColorT mul(ColorT c1, float t) { return ColorT(limit8bit(c1.r * t), limit8bit(c1.g * t), limit8bit(c1.b * t), limit8bit(c1.a * t)); } - /** - * Сумма двух цветов - */ - ColorT sum(ColorT c1, ColorT c2) + // Сумма двух цветов + ColorT sum(ColorT c1, ColorT c2) { - return ColorT(limit8bit(c1.r + c2.r), limit8bit(c1.g + c2.g), - limit8bit(c1.b + c2.b), limit8bit(c1.a + c2.a)); + return ColorT(limit8bit(c1.r + c2.r), limit8bit(c1.g + c2.g), + limit8bit(c1.b + c2.b), limit8bit(c1.a + c2.a)); } + /** * Треугольная интерполяция на цветовой функции. * Вычисляется по барицентрическим координатам. @@ -666,7 +695,7 @@ namespace agg ColorT c1 = mul(m_oGradientInfo.shading.triangle_colors[0], fabs(w[0])); ColorT c2 = mul(m_oGradientInfo.shading.triangle_colors[1], fabs(w[1])); ColorT c3 = mul(m_oGradientInfo.shading.triangle_colors[2], fabs(w[2])); - return sum(c1, sum(c2,c3)); + return sum(c1, sum(c2, c3)); } @@ -675,6 +704,10 @@ namespace agg * И логика чуть менее запутанная. * Основной алгоритм - разбить поверхность на множество квадратиков. И забить туда значения сразу. Чтобы обратную фнкцию не считать. * + * Основня цель повтора - сделать единый интерфейс параметризации и все остальное. + * Т.к. просто добавляя разные параметризации, можно добавить большое количесво нужных градиентов. + * + * Все с кривыми работает так же как и параметры, только интерполируется не парамет, а цвет. */ std::vector> precalc; @@ -693,9 +726,11 @@ namespace agg 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) { + 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); @@ -704,22 +739,22 @@ namespace agg } } RES = (int)std::max(ymax - ymin, xmax - xmin); - precalc = std::vector>(RES, std::vector(RES, {0,0,0,0})); + precalc = std::vector>(RES, std::vector(RES, {0, 0, 0, 0})); delta = 1.0f / RES; - for (u = 0.0; u <= 1; u += delta / 2) { - for (v = 0.0; v <= 1; v+= delta / 2) { - 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; - } + for (u = 0.0; u <= 1; u += delta) + { + for (v = 0.0; v <= 1; v += delta) + { + NSStructures::Point p = get_p_curve(u, v); + std::pair index1 = get_index_curve(p.x, p.y); + p = get_p_curve(u + delta, v + delta); + std::pair index2 = get_index_curve(p.x, p.y); 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))); + fill_square(index1, index2, sum(c00, sum(c01, sum(c10, c11)))); } } } @@ -727,9 +762,9 @@ namespace agg 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}; - + 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]; } @@ -738,9 +773,10 @@ namespace agg 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); + 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; @@ -751,93 +787,47 @@ namespace agg { auto p = m_oGradientInfo.shading.patch; //----------------------------------------------------------------------------- - p[1][1] = (1.0 / 9) * ( -4.0 * p[0][0] + 6 * ( p[0][1] + p[1][0] ) + 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] ); + - 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] ) + 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] ); + - 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] ) + 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] ); + - 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] ) + 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] ); + - 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}; } - }; + + void fill_square(const std::pair &index1, const std::pair &index2, const ColorT &c) + { + for (int i = std::min(index1.first, index2.first); i <= std::max(index1.first, index2.first); i++) + { + for (int j = std::min(index1.second, index2.second); j <= std::max(index1.second, index2.second); j++) + { + if (i < RES && j < RES) + { + precalc[i][j] = c; + } + } + } + } + }; } -/* -Одна из возможных оптимизаций, пока не получилось, мб еще к ней вернусь. -if (!start && std::max(abs(p_i.first - i.first), abs(p_i.second - i.second)) >= 1) - { - std::pair start = {std::min(p_i.first, i.first), std::min(p_i.second, i.second)}; - std::pair finish = {std::max(p_i.first, i.first), std::max(p_i.second, i.second)}; - - // Т.к вероятне всего "скачки" будут не больше пары пикселей я не вижу смысла счиать прямую. - - int right = finish.first - start.first + 1; - int down = finish.second - start.second + 1; - - if (right >= down) - { - int step = right / down; - int add = right % down; - for (int i = 0; i < down; i++) - { - int cs = step; - if (add) - { - cs++; - add--; - } - for (int j = 0; j < cs; j++) - { - precalc[start.first][start.second] = t; - start.first++; - } - start.second++; - } - } - else - { - int step = down / right; - int add = down % right; - for (int i = 0; i < down; i++) - { - int cs = step; - if (add) - { - cs++; - add--; - } - for (int j = 0; j < cs; j++) - { - precalc[start.first][start.second] = t; - start.second++; - } - start.first++; - } - } - } - else - { - precalc[i.first][i.second] = t; - } - start = false; - p_i = i; -*/ #endif \ No newline at end of file diff --git a/DesktopEditor/graphics/shading_info.h b/DesktopEditor/graphics/shading_info.h index b9593a28cc..b45ad0b1c5 100644 --- a/DesktopEditor/graphics/shading_info.h +++ b/DesktopEditor/graphics/shading_info.h @@ -11,18 +11,8 @@ namespace NSStructures { /** - * PDF Gradients is not so comparable with this graphics lib - * so my realisation of gradients use quite different interface. - * - * First of all we have to be able to use different (x, y) -> color / (x, y) -> t -> color - * functions in runtime. I think the most natural way is to use vector. - * - * - * Потом приведу комменты в порядок, после ревью. - * * * */ - // TODO div optimise template class ColorFunction /** @@ -264,8 +254,6 @@ namespace NSStructures - - // Contains PDF render info /** * Тут хранится информация спецефичная для рендера ПДФ. * @@ -278,8 +266,6 @@ namespace NSStructures * Так же шейдер будет получать, в качетве параметров, границы, тут я пока не решил, вообще * можно оставить соблюдение границ, на откуп пользователю, т.к. все равно заполенение в конечном итоге будет * выполняться с помощью рисования замкнутого пути и команды Fill - * - * * */ struct ShadingInfo { @@ -299,6 +285,7 @@ namespace NSStructures }f_type; // if UseOld old function is called, look for IGraphicsRender.put_BrushGradientColors; ColorFunction function; + bool default_mapping; // boundaries to domain of color function @@ -307,11 +294,8 @@ namespace NSStructures std::vector triangle_colors; std::vector triangle_parameters; - // non linear (NOT ready) пока не написал, как кривую переводить в нормальные координаты - bool parametrised_curve_shading; - /** - * матрица 4 на 4 заполняется как в документации к пдф 7 тип + * Матрица 4 на 4 заполняется как в документации к пдф 7 тип * Если выбран тип 6 то значения (1,2) (2,1) (1,1) (2,2) * В массиве игнормруется и заполняются автоматически, следите за переданным типом градинта * (Нумерация от нуля) @@ -333,7 +317,8 @@ namespace NSStructures reflected(false), periods(0.5f), periodic(false), xsize(1.0f), ysize(1.0f), - linstretch(1.0f), linoffset(0.0f) + linstretch(1.0f), linoffset(0.0f), + continue_shading(true) { } @@ -360,15 +345,47 @@ namespace NSStructures 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 + float continue_shading; ShadingInfo shading; }; /** * Создает объект класса GradientInfo по заданным параметрам. + * + * Цветовую функцию надо заполнять вручную */ class GInfoConstructor { - + static GradientInfo get_functional() + { + + } + static GradientInfo get_linear() + { + + } + static GradientInfo get_radial() + { + + } + static GradientInfo get_triangle() + { + + } + static GradientInfo get_curve(const std::vector &curve_points, + const std::vector &curve_parametrs, + const std::vector &curve_colors) + { + GradientInfo ginfo; + + return ginfo; + } + static GradientInfo get_tensor_curve(const std::vector> &curve_poits, + const std::vector &curve_parametrs, + const std::vector &curve_colors) + { + + } }; } diff --git a/Test/Applications/gradient/Gradient/mainwindow.cpp b/Test/Applications/gradient/Gradient/mainwindow.cpp index caa28842c1..6a14dbb50a 100644 --- a/Test/Applications/gradient/Gradient/mainwindow.cpp +++ b/Test/Applications/gradient/Gradient/mainwindow.cpp @@ -77,7 +77,7 @@ void GenerateImg(QImage &img, std::vector &points, Info &info) { if (points.size() > 0) { pRasterRenderer->PathCommandMoveTo(points[0].x, points[0].y); for (uint i = 1; i < points.size(); i++) { - pRasterRenderer->PathCommandLineTo(points[i].x, points[i].y); + pRasterRenderer->PathCommandLineTo(points[i].x, points[i].y) ; } } pRasterRenderer->Fill(); @@ -177,20 +177,20 @@ void MainWindow::on_PathType_itemClicked(QListWidgetItem *item) } else if (item->text() == "Patch") { points = {{0, 0}, {105, 0}, {105, 105}, {0, 105}}; - info.gradient_type = c_BrushTypeCurveGradient; - info.ginfo.shading.shading_type = NSStructures::ShadingInfo::Parametric; + info.gradient_type = c_BrushTypeTensorCurveGradient ; + info.ginfo.shading.shading_type = NSStructures::ShadingInfo::CurveInterpolation; info.ginfo.shading.patch = { {{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,10}} + {{80,80}, {40, 40}, {130, 70}, {80,10}} }; info.ginfo.shading.patch_parameters = { {0 , 1}, {1, 0.5} }; info.ginfo.shading.patch_colors = { - {{255, 0, 0}, {0, 255, 255}}, + {{255, 0, 0}, {150, 255, 255}}, {{0, 255, 0}, {0, 0, 255}} }; float mult = 4.0; @@ -313,12 +313,7 @@ void MainWindow::on_ColorSpaces_itemDoubleClicked(QListWidgetItem *item) void MainWindow::on_Reflected_CheckBox_clicked(bool checked) { - info.ginfo.reflected = checked; + info.ginfo.continue_shading = checked; on_RenderPic_clicked(); } -void MainWindow::on_PeriodicCheckBox_clicked(bool checked) -{ - info.ginfo.periodic = checked; - on_RenderPic_clicked(); -} diff --git a/Test/Applications/gradient/Gradient/mainwindow.h b/Test/Applications/gradient/Gradient/mainwindow.h index cd813d0002..f560a9bae0 100644 --- a/Test/Applications/gradient/Gradient/mainwindow.h +++ b/Test/Applications/gradient/Gradient/mainwindow.h @@ -96,8 +96,6 @@ private slots: void on_Reflected_CheckBox_clicked(bool checked); - void on_PeriodicCheckBox_clicked(bool checked); - private: Ui::MainWindow *ui; }; diff --git a/Test/Applications/gradient/Gradient/mainwindow.ui b/Test/Applications/gradient/Gradient/mainwindow.ui index da005f63a1..f86eabdb61 100644 --- a/Test/Applications/gradient/Gradient/mainwindow.ui +++ b/Test/Applications/gradient/Gradient/mainwindow.ui @@ -403,19 +403,6 @@ - - - - 470 - 80 - 81 - 22 - - - - Periodic - - @@ -649,6 +636,9 @@ + + true + 600 @@ -658,7 +648,10 @@ - Reflected + Continue + + + true