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 6675e05aad..0e965117fe 100644 --- a/DesktopEditor/agg-2.4/include/test_grads/custom_gradients.h +++ b/DesktopEditor/agg-2.4/include/test_grads/custom_gradients.h @@ -5,6 +5,8 @@ #define M_1_PI 0.318309886183790671538 #endif + + namespace agg { /** @@ -20,7 +22,7 @@ namespace agg class calcBase { public: - virtual float eval(float, float) = 0; + virtual float eval(float , float ) = 0; virtual ~calcBase() {} void set_rotation(float angle) { @@ -47,9 +49,9 @@ 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; } }; @@ -87,7 +89,7 @@ namespace agg { public: calcConical(const NSStructures::GradientInfo &_gi, float _cx, float _cy, float _factor) : ginfo(_gi), cx(_cx), cy(_cy), factor(_factor), inverseFactor(1.0f / _factor), - invXsize(1.0f / _gi.xsize), invYsize(1.0f / _gi.ysize), m1pi((float)agg::pi) + invXsize(1.0f / _gi.xsize), invYsize(1.0f / _gi.ysize) { cx += ginfo.centerX * inverseFactor; cy += ginfo.centerY * inverseFactor; @@ -100,7 +102,7 @@ namespace agg rotate(x, y); x *= invXsize; y *= invYsize; - float t = fabs(atan2(x, y)) * m1pi; + float t = fabs(atan2(x, y)) * M_1_PI; return t; } @@ -182,33 +184,159 @@ namespace agg } virtual float eval(float x, float y) override { - // тут можно любую интерполяцию сделать, там не написано какая должна быть - // пока просто по проекциям берет среднее todo refactor - float t1 = relative_project_len(x, y, ginfo.shading.triangle[0], ginfo.shading.triangle[1]); - float t2 = relative_project_len(x, y, ginfo.shading.triangle[1], ginfo.shading.triangle[2]); - float t3 = relative_project_len(x, y, ginfo.shading.triangle[2], ginfo.shading.triangle[0]); - return 0.333333333 * (ginfo.shading.triangle_parametrs[0] * (t2 + 1 - t1) + - ginfo.shading.triangle_parametrs[1] * (t3 + 1 - t2) + - ginfo.shading.triangle_parametrs[2] * (t1 + 1 - t3)); + 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]; } - // x first, наверное это стоит немного отрефакторить пока просто пробую чтобы работало - //todo - static float relative_project_len(float x, float y, std::pair start, std::pair finish) + + /** + * Вычисляем веса по барицетрическим координатам + * https://codeplea.com/triangular-interpolation + */ + static std::vector + baricentric_weights(const NSStructures::Point &P, const std::vector &t) { - return ((x - start.first) * (finish.first - start.first) + (y - start.second) * (finish.second - start.second)) - / ((finish.first - start.first) * (finish.first - start.first) + - (finish.second - start.second) * (finish.second - start.second)); //(a, b) / b^2 + 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[2] = 1 - r[0] - r[1]; + return r; } NSStructures::GradientInfo ginfo; }; + class calcCurve : public calcBase + { + /** + * Пока наивный метод, из недостатков - долгая инициализация, из плюсов если рендерить несколько раз + * то будет быстро, достаточно будет преобразование старых координат в новые. И как то сохранить результат инициализации. + * Пока не буду ничего этого делать, тк. наверное все равно придется поменять. + */ + public: + calcCurve(const NSStructures::GradientInfo &_g, bool calculate_tensor_coefs = true) : tensor_size(4) + { + ginfo = _g; + if (calculate_tensor_coefs) + calculate_tensor(); + RES = 10; //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)); + for (;u <= 1; u += delta) { + for (;v <= 1; v+= delta) { + auto p = get_p(u, v); + xmax = std::max(p.x, xmax); + ymax = std::max(p.y, ymax); + xmin = std::min(p.x, xmin); + ymin = std::min(p.y, ymin); + } + } + for (u = 0.0; u <= 1; u += delta) { + 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; + } + } + } + virtual float eval(float x, float y) override + { + auto i = get_index(x, y); + 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) + { + switch (i) + { + case 0: + return (1 - t) * (1 - t) * (1- t); + case 1: + return 3 * t * (1 - t) * (1- t); + case 2: + return 3 * t * t * (1- t); + case 3: + return t * t * t; + + default: + printf("!!!!!!"); + } + } + + // pdf 208p. + 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] ) + + - 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] ); + //----------------------------------------------------------------------------- + ginfo.shading.patch = p; + } + + 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}; + } + + NSStructures::GradientInfo ginfo; + std::vector> precalc; + const size_t tensor_size; + float xmin, xmax, ymin, ymax; + size_t RES; + }; + template class gradient_base { public: typedef ColorT color_type; - typedef NSStructures::GradientInfo ginfo; - protected: enum { @@ -221,7 +349,7 @@ namespace agg protected: int m_state; - ginfo m_oGradientInfo; + NSStructures::GradientInfo m_oGradientInfo; float invStep; agg::point_d m_center; float m_factor; @@ -239,6 +367,7 @@ namespace agg bool m_valid_table[MaxColorIndex + 1]; protected: + inline float calculate_param(const float &x, const float &y) { float t = calculate->eval(x, y); @@ -290,7 +419,11 @@ namespace agg { } virtual ~gradient_base() {} - void SetGradientInfo(ginfo _g, Aggplus::BrushType bType) + + /** + * Выбор варианта параметризации. И получение основной инфы о градиенте. + */ + void SetGradientInfo(const NSStructures::GradientInfo &_g, Aggplus::BrushType bType) { m_oGradientInfo = _g; invStep = 1.0f / m_oGradientInfo.discrete_step; @@ -311,9 +444,19 @@ namespace agg case Aggplus::BrushTypeNewLinearGradient: calculate = new calcNewLinear(m_oGradientInfo, xmin, ymin, xmax, ymax); break; - case Aggplus::BrushTypeMyTestGradient: + + case Aggplus::BrushTypeTriagnleMeshGradient: calculate = new calcTriangle(m_oGradientInfo); break; + + case Aggplus::BrushTypeCurveGradient: + calculate = new calcCurve(m_oGradientInfo); + break; + + case Aggplus::BrushTypeTensorCurveGradient: + calculate = new calcCurve(m_oGradientInfo, false); + break; + default: fprintf(stderr, "WRONG BRUSH TYPE"); calculate = new calcRandom(); @@ -321,6 +464,9 @@ namespace agg } } + /** + * Для старой цветовой функции. + */ void SetSubColors(const color_type *colors, const float *positions, int count) { m_pSubColors = colors; @@ -328,6 +474,9 @@ namespace agg m_nCountSubColors = count; } + /** + * Нужно для функции отрисовки. + */ void prepare() { if (m_state != StateReady) @@ -337,56 +486,54 @@ namespace agg } } + /** + * Генерирует цвет пикселя для рендерной функции. + */ void generate(color_type *span, int x, int y, unsigned len) { for (unsigned count = 0; count < len; ++count, ++x) { - double _x = x; - double _y = y; - m_trans.transform(&_x, &_y); - float t = calculate_param((float)_x, (float)_y); - if (m_oGradientInfo.shading.parametrised_triangle_shading) { - *span++ = this->triangle(x, y); - } - else if (m_oGradientInfo.shading.f_type == NSStructures::ShadingInfo::UseXY2Color) + if (m_oGradientInfo.shading.shading_type == NSStructures::ShadingInfo::FunctionOnly) { + float _x = x; + float _y = y; _x = (_x - xmin) / (xmax - xmin); _y = (_y - ymin) / (ymax - xmin); *span++ = m_oGradientInfo.shading.function.get_color(_x, _y); //m_color_table[index]; } - else if (m_oGradientInfo.shading.f_type == NSStructures::ShadingInfo::UseT2Color) + else if (m_oGradientInfo.shading.shading_type == NSStructures::ShadingInfo::TriangleInterpolation) { - *span++ = m_oGradientInfo.shading.function.get_color(t); + *span++ = this->triangle(x, y); } - else + else if (m_oGradientInfo.shading.shading_type == NSStructures::ShadingInfo::CurveInterpolation) { - int index = int(t * MaxColorIndex + 0.5); - if (!m_valid_table[index]) - CalcColor(index); - *span++ = m_color_table[index]; + *span++ = this->triangle(x,y); // todo + } + else if (m_oGradientInfo.shading.shading_type == NSStructures::ShadingInfo::TesorCurveInterpolation) + { + *span++ = this->triangle(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) + { + *span++ = m_oGradientInfo.shading.function.get_color(t); + } + if (m_oGradientInfo.shading.f_type == NSStructures::ShadingInfo::UseOld) + { + int index = int(t * MaxColorIndex + 0.5); + if (!m_valid_table[index]) + CalcColor(index); + *span++ = m_color_table[index]; + } } } } - //todo refactor - ColorT mul(ColorT c1, float t) - { - return ColorT(c1.r * t, c1.g * t, c1.b * t, c1.a * t); - } - ColorT sum(ColorT c1, ColorT c2) - { - return ColorT(c1.r + c2.r, c1.g + c2.g, c1.b + c2.b, c1.a + c2.a); - } - ColorT triangle(float x, float y) - { - float t1 = calcTriangle::relative_project_len(x, y, m_oGradientInfo.shading.triangle[0], m_oGradientInfo.shading.triangle[1]); - float t2 = calcTriangle::relative_project_len(x, y, m_oGradientInfo.shading.triangle[1], m_oGradientInfo.shading.triangle[2]); - float t3 = calcTriangle::relative_project_len(x, y, m_oGradientInfo.shading.triangle[2], m_oGradientInfo.shading.triangle[0]); - - ColorT c1 = mul(m_oGradientInfo.shading.triangle_colors[0], (t2 + 1 - t1)/3); - ColorT c2 = mul(m_oGradientInfo.shading.triangle_colors[1], (t3 + 1 - t2)/3); - ColorT c3 = mul(m_oGradientInfo.shading.triangle_colors[2], (t2 + 1 - t1)/3); - return sum(c1, sum(c2,c3)); - } + + /** + * Выставляем всякую инфу про наш градиент. + */ void SetDirection(const agg::rect_d &bounds, const agg::trans_affine &trans) { m_trans = trans; @@ -408,6 +555,9 @@ namespace agg } protected: + /** + * Для старой цветовой функции + */ void CalcColor(int index) { float t = index * (1.0 / MaxColorIndex); @@ -441,9 +591,47 @@ namespace agg m_valid_table[index] = true; } + /** + * Треугольная пила, нужна для периодических градиентов. + */ inline float triagle_saw(float x) { return fabs(2 * asinf(sinf(x * pi)) * M_1_PI); } + + 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) + { + return ColorT(limit8bit(c1.r + c2.r), limit8bit(c1.g + c2.g), + limit8bit(c1.b + c2.b), limit8bit(c1.a + c2.a)); + } + /** + * Треугольная интерполяция на цветовой функции. + * Вычисляется по барицентрическим координатам. + */ + ColorT triangle(float x, float y) + { + auto w = calcTriangle::baricentric_weights({x, y}, m_oGradientInfo.shading.triangle); + 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)); + } + + }; } diff --git a/DesktopEditor/graphics/AggPlusEnums.h b/DesktopEditor/graphics/AggPlusEnums.h index 1a8c08f318..a4f387c948 100644 --- a/DesktopEditor/graphics/AggPlusEnums.h +++ b/DesktopEditor/graphics/AggPlusEnums.h @@ -148,6 +148,10 @@ enum BrushType BrushTypeConicalGradient = 6, BrushTypeDiamondGradient = 7, BrushTypeNewLinearGradient = 8, + BrushTypeTriagnleMeshGradient = 9, + BrushTypeCurveGradient = 10, + BrushTypeTensorCurveGradient = 11, + BrushTypeMyTestGradient = 100 }; diff --git a/DesktopEditor/graphics/Graphics.cpp b/DesktopEditor/graphics/Graphics.cpp index 835f43250e..9245b0460a 100644 --- a/DesktopEditor/graphics/Graphics.cpp +++ b/DesktopEditor/graphics/Graphics.cpp @@ -1901,7 +1901,10 @@ namespace Aggplus (BrushTypeNewLinearGradient == Type) || (BrushTypeConicalGradient == Type) || (BrushTypeRadialGradient == Type) || - (BrushTypeDiamondGradient == Type)) + (BrushTypeDiamondGradient == Type) || + (BrushTypeTriagnleMeshGradient == Type) || + (BrushTypeCurveGradient == Type) || + (BrushTypeTensorCurveGradient == Type) ) { DoFillPathGradientType((CBrushLinearGradient*)Brush); } diff --git a/DesktopEditor/graphics/GraphicsRenderer.cpp b/DesktopEditor/graphics/GraphicsRenderer.cpp index cd475b4c77..df5ffea536 100644 --- a/DesktopEditor/graphics/GraphicsRenderer.cpp +++ b/DesktopEditor/graphics/GraphicsRenderer.cpp @@ -67,20 +67,23 @@ Aggplus::CBrush* CGraphicsRenderer::CreateBrush(NSStructures::CBrush* pBrush) return pNew; } - else if ((c_BrushTypeHorizontal == Type) || - (c_BrushTypeVertical == Type) || - (c_BrushTypeDiagonal1 == Type) || - (c_BrushTypeDiagonal2 == Type) || - (c_BrushTypeCenter == Type) || - (c_BrushTypePathGradient1 == Type) || - (c_BrushTypePathGradient2 == Type) || - (c_BrushTypeCylinderHor == Type) || - (c_BrushTypeCylinderVer == Type) || - (c_BrushTypePathRadialGradient == Type) || - (c_BrushTypePathNewLinearGradient == Type) || - (c_BrushTypePathConicalGradient == Type) || - (c_BrushTypePathDiamondGradient == Type) || - (c_BrushTypeMyTestGradient == Type)) + else if ((c_BrushTypeHorizontal == Type) || + (c_BrushTypeVertical == Type) || + (c_BrushTypeDiagonal1 == Type) || + (c_BrushTypeDiagonal2 == Type) || + (c_BrushTypeCenter == Type) || + (c_BrushTypePathGradient1 == Type) || + (c_BrushTypePathGradient2 == Type) || + (c_BrushTypeCylinderHor == Type) || + (c_BrushTypeCylinderVer == Type) || + (c_BrushTypePathRadialGradient == Type) || + (c_BrushTypePathNewLinearGradient == Type) || + (c_BrushTypePathConicalGradient == Type) || + (c_BrushTypePathDiamondGradient == Type) || + (c_BrushTypeMyTestGradient == Type) || + (c_BrushTypeTriagnleMeshGradient == Type) || + (c_BrushTypeCurveGradient == Type) || + (c_BrushTypeTensorCurveGradient == Type)) { Aggplus::CColor o1((BYTE)(pBrush->Alpha1 * m_dGlobalAlpha), pBrush->Color1, bIsSwappedRGB); Aggplus::CColor o2((BYTE)(pBrush->Alpha2 * m_dGlobalAlpha), pBrush->Color2, bIsSwappedRGB); @@ -148,6 +151,15 @@ Aggplus::CBrush* CGraphicsRenderer::CreateBrush(NSStructures::CBrush* pBrush) break; case c_BrushTypePathDiamondGradient: pNew->m_bType = Aggplus::BrushTypeDiamondGradient; + break; + case c_BrushTypeTensorCurveGradient: + pNew->m_bType = Aggplus::BrushTypeTensorCurveGradient; + break; + case c_BrushTypeCurveGradient: + pNew->m_bType = Aggplus::BrushTypeCurveGradient; + break; + case c_BrushTypeTriagnleMeshGradient: + pNew->m_bType = Aggplus::BrushTypeTriagnleMeshGradient; break; default: diff --git a/DesktopEditor/graphics/GraphicsRenderer.h b/DesktopEditor/graphics/GraphicsRenderer.h index cb05e090ad..a7ddf99374 100644 --- a/DesktopEditor/graphics/GraphicsRenderer.h +++ b/DesktopEditor/graphics/GraphicsRenderer.h @@ -163,7 +163,7 @@ public: virtual HRESULT PenDashPattern(double* pPattern, LONG lCount); // brush ------------------------------------------------------------------------------------ - virtual void put_BrushGradInfo(const NSStructures::GradientInfo _ginfo) override { + virtual void put_BrushGradInfo(const NSStructures::GradientInfo &_ginfo) override { m_oBrush.m_oGradientInfo = _ginfo; } diff --git a/DesktopEditor/graphics/pro/Graphics.h b/DesktopEditor/graphics/pro/Graphics.h index 5d3f4d85ab..76e879b148 100644 --- a/DesktopEditor/graphics/pro/Graphics.h +++ b/DesktopEditor/graphics/pro/Graphics.h @@ -125,7 +125,7 @@ namespace NSGraphics // test - virtual void put_BrushGradInfo(const NSStructures::GradientInfo _ginfo) = 0; + virtual void put_BrushGradInfo(const NSStructures::GradientInfo &_ginfo) = 0; }; GRAPHICS_DECL IGraphicsRenderer* Create(); diff --git a/DesktopEditor/graphics/shading_info.h b/DesktopEditor/graphics/shading_info.h index 2d63b37a25..03c5798d60 100644 --- a/DesktopEditor/graphics/shading_info.h +++ b/DesktopEditor/graphics/shading_info.h @@ -5,13 +5,16 @@ #define M_PI 3.14159265358979323846 #endif +#ifndef SHADING_INFO +#define SHADING_INFO + 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 / t -> color + * 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. * * @@ -46,9 +49,9 @@ namespace NSStructures { public: // Default constructor works only with one parameter functions - ColorFuction() : RESOLUTION(512), x_domain_min(0.0f), x_domain_max(1.0f), - values(std::vector>(1, std::vector(RESOLUTION))) + ColorFuction() : 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++) { unsigned int value = 255 - (255 * ((float)i / RESOLUTION)); @@ -56,9 +59,10 @@ namespace NSStructures } } - ColorFuction(size_t res, float xmin, float xmax) : RESOLUTION(res), x_domain_min(xmin), x_domain_max(xmax), - values(std::vector>(1, std::vector(RESOLUTION))) + ColorFuction(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++) { unsigned int value = 255 - (255 * ((float)i / RESOLUTION)); @@ -66,10 +70,9 @@ 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), - values(std::vector>(RESOLUTION, std::vector(RESOLUTION))) + 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) { - + values = std::vector>(RESOLUTION, std::vector(RESOLUTION)); for (int i = 0; i < RESOLUTION; i++) { for (int j = 0; j < RESOLUTION; j++) @@ -187,8 +190,10 @@ namespace NSStructures return RESOLUTION - 1; return y_index; } - - int interpolate_indexes(size_t first, size_t second, size_t line = 0) + /** + * Линейная интерполяция для построения цветовой функции. + */ + int interpolate_indexes(size_t first, size_t second, size_t line = 0) { size_t len = second - first; ColorT f = values[line][first]; @@ -204,23 +209,63 @@ namespace NSStructures unsigned int hex2a(uint32_t c) { - return (c / 256 / 256 / 256) % 256; + unsigned int a = (c >> 24) % 0x100; + std::cout << a << "sdfsd\n"; + return a; } unsigned int hex2r(uint32_t c) { - return (c / 256 / 256) % 256; + return (c >> 16) % 0x100; } unsigned int hex2g(uint32_t c) { - return (c / 256) % 256; + return (c >> 8) % 0x100; } unsigned int hex2b(uint32_t c) { - return c % 256; + return c % 0x100; } }; + struct Point + { + Point():x(0),y(0){} + Point(float _x, float _y):x(_x),y(_y){} + float x, y; + + Point& operator+=(const Point &a) + { + x += a.x; + y += a.y; + return *this; + } + + + /** + * Костыль от ошибок линковки. Чтобы время не терять пока что. + */ + friend Point operator*(const Point &a, float t) + { + return Point(a.x * t, a.y * t); + } + friend Point operator*(float t, const Point &a) + { + return Point(a.x * t, a.y * t); + } + friend Point operator+(const Point &a, const Point &b) + { + return Point(a.x + b.x, a.y + b.y); + } + friend Point operator-(const Point &a, const Point &b) + { + return Point(a.x - b.x, a.y - b.y); + } + }; + + + + // Contains PDF render info /** * Тут хранится информация спецефичная для рендера ПДФ. @@ -237,51 +282,47 @@ namespace NSStructures * * * */ - - struct float_affine { - float sx, shy, shx, sy, tx, ty; - void transform(float &x, float &y) - { - double tmp = x; - x = tmp * sx + y * shx + tx; - y = tmp * shy + y * sy + ty; - } - }; - struct ShadingInfo { public: - ShadingInfo() : function(), - f_type(UseT2Color) + ShadingInfo() : shading_type(Parametric), f_type(UseNew){} + enum ShadingType { - } - enum ShadingType { - Triangle, SimpleCubic, TensorCubic - }; + FunctionOnly, + Parametric, + TriangleInterpolation, + CurveInterpolation, + TesorCurveInterpolation + } shading_type; enum ColorFunctionType { - UseOld, - UseT2Color, - UseXY2Color - }; // if UseOld old function is called, look for IChaphicsRender.put_BrushGradientColors - ColorFunctionType f_type; + UseOld, UseNew + }f_type; // if UseOld old function is called, look for IChaphicsRender.put_BrushGradientColors; ColorFuction function; bool default_mapping; // boundaries to domain of color function - float_affine mapping; // пока не готово, если дефолтный то выстввляется специальным методом, если нет то пользователь сам выставляет. - // triangle shading bool parametrised_triangle_shading; - std::vector> triangle; + std::vector triangle; std::vector triangle_colors; std::vector triangle_parametrs; // non linear (NOT ready) пока не написал, как кривую переводить в нормальные координаты bool parametrised_curve_shading; - std::vector> patch; // 12 точкек характеризующих фигуру + + /** + * матрица 4 на 4 заполняется как в документации к пдф 7 тип + * Если выбран тип 6 то значения (1,2) (2,1) (1,1) (2,2) + * В массиве игнормруется и заполняются автоматически, следите за переданным типом градинта + * (Нумерация от нуля) + * + * Наверное напишу адаптор который переводит порядок точек из 6 типа в общий. + */ + std::vector> patch; std::vector patch_colors; // 4 цвета по углам + std::vector patch_patamerts; // 4 параметра }; // Containing additional info about gradient @@ -324,3 +365,5 @@ namespace NSStructures ShadingInfo shading; }; } + +#endif \ No newline at end of file diff --git a/DesktopEditor/graphics/structures.h b/DesktopEditor/graphics/structures.h index 2bdb9c442a..18a0163192 100644 --- a/DesktopEditor/graphics/structures.h +++ b/DesktopEditor/graphics/structures.h @@ -107,6 +107,9 @@ const long c_BrushTypePathRadialGradient = 6001; const long c_BrushTypePathConicalGradient = 6002; const long c_BrushTypePathDiamondGradient = 6003; const long c_BrushTypePathNewLinearGradient = 6004; +const long c_BrushTypeTriagnleMeshGradient = 6005; +const long c_BrushTypeCurveGradient = 6006; +const long c_BrushTypeTensorCurveGradient = 6007; const long c_BrushTypeShading = 7000; diff --git a/Test/Applications/gradient/Gradient/mainwindow.cpp b/Test/Applications/gradient/Gradient/mainwindow.cpp index d94f977a5d..a05e8ec5c0 100644 --- a/Test/Applications/gradient/Gradient/mainwindow.cpp +++ b/Test/Applications/gradient/Gradient/mainwindow.cpp @@ -42,7 +42,7 @@ void GenerateImg(QImage &img, std::vector &points, Info &info) { unsigned int back = 0xffffff; unsigned int* pData32 = (unsigned int*)pData; - unsigned int* pData32End = pData32 + nRasterW * nRasterH; + unsigned int* pData32End = pData32 + nRasterW * nRasterH ; //дефолтный тон должен быть прозрачным, а не белым while (pData32 < pData32End) *pData32++ = back; @@ -64,7 +64,7 @@ void GenerateImg(QImage &img, std::vector &points, Info &info) { NSStructures::GradientInfo ginfo = info.ginfo; //ginfo.reflected = true; - ginfo.shading.f_type = NSStructures::ShadingInfo::UseT2Color; + ginfo.shading.f_type = NSStructures::ShadingInfo::UseNew; pRasterRenderer->put_BrushGradInfo(ginfo); auto a = info.c; auto b = info.p; @@ -162,11 +162,25 @@ void MainWindow::on_PathType_itemClicked(QListWidgetItem *item) } else if (item->text() == "Triangle") { points = {{5, 10}, {40, 100}, {100, 1}}; - info.gradient_type = c_BrushTypeMyTestGradient; + /* + * Пока чтобы тестить прямую интерполяцию цвета, нужно редактировать код + * И вычтавить info.ginfo.shading.shading_type как NSStructures::ShadingInfo::TriangleInterpolation + * Чтобы тестить параметрическую нужно выставить NSStructures::ShadingInfo::Parametric + * С опцией Parametric можно тестить другие градиенты. + * + */ + info.gradient_type = c_BrushTypeTriagnleMeshGradient; + info.ginfo.shading.shading_type = NSStructures::ShadingInfo::TriangleInterpolation; 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.1f, 1.0f}; - info.ginfo.shading.parametrised_triangle_shading = false; - info.ginfo.shading.triangle_colors = {{255,0,0, 255}, {0,255,0,255 }, {0,0,255,255}}; + info.ginfo.shading.triangle_parametrs = {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}} + }; } } @@ -251,7 +265,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 white") { + else if (item->text() == "Black and wh200ite") { 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 dafa57c725..3138e5df63 100644 --- a/Test/Applications/gradient/Gradient/mainwindow.h +++ b/Test/Applications/gradient/Gradient/mainwindow.h @@ -39,6 +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; }; ~Info() { }