Files
DocumentServer-v-9.2.0/core/DesktopEditor/graphics/Graphics.cpp
Yajbir Singh f1b860b25c
Some checks failed
check / markdownlint (push) Has been cancelled
check / spellchecker (push) Has been cancelled
updated
2025-12-11 19:03:17 +05:30

2562 lines
68 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* (c) Copyright Ascensio System SIA 2010-2023
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation. In accordance with
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
* that Ascensio System SIA expressly excludes the warranty of non-infringement
* of any third-party rights.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish
* street, Riga, Latvia, EU, LV-1050.
*
* The interactive user interfaces in modified source and object code versions
* of the Program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU AGPL version 3.
*
* Pursuant to Section 7(b) of the License you must retain the original Product
* logo when distributing the program. Pursuant to Section 7(e) we decline to
* grant you any rights under trademark law for use of our trademarks.
*
* All the Product's GUI elements, including illustrations and icon sets, as
* well as technical writing content are licensed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
*
*/
#include "Graphics.h"
#include <algorithm>
#include "../fontengine/FontFile.h"
namespace Aggplus
{
CGraphics::CGraphics()
{
m_pPixels = NULL;
m_pDib = NULL;
m_dWidthPix = 0;
m_dHeightPix = 0;
m_dDpiX = 72.0;
m_dDpiY = 72.0;
m_ePageUnits = UnitPixel;
m_bIntegerGrid = false;
#ifdef _WINDOWS_GDIPLUS_USE_
m_pBitmap = NULL;
m_pGraphics = NULL;
m_oInitGdiplus.Init();
#endif
m_dGlobalAlpha = 1.0;
m_bSwapRGB = false;
m_bIsDarkMode = false;
#if defined (_LINUX) || defined (_QT)
m_bSwapRGB = true;
#endif
m_dDpiTile = -1;
m_pAlphaMask = NULL;
m_pSoftMask = NULL;
m_nTextRenderMode = FT_RENDER_MODE_NORMAL;
m_nBlendMode = agg::comp_op_src_over;
m_bIs0PenWidthAs1px = false;
}
CGraphics::CGraphics(int dwWidth, int dwHeight, int stride, BYTE* pBuffer) : m_dwConfigFlags(0)
{
m_dWidthPix = 0;
m_dHeightPix = 0;
m_dDpiX = 72.0;
m_dDpiY = 72.0;
m_ePageUnits = UnitPixel;
m_pPixels = NULL;
m_bIntegerGrid = false;
Create(pBuffer, dwWidth, dwHeight, stride, 0);
m_dGlobalAlpha = 1.0;
#ifdef _WINDOW_GDIPLUS_USE_
m_pBitmap = NULL;
m_pGraphics = NULL;
#endif
m_bSwapRGB = false;
#if defined (_LINUX) || defined (_QT)
m_bSwapRGB = true;
#endif
m_dDpiTile = -1;
m_pAlphaMask = NULL;
m_pSoftMask = NULL;
m_nTextRenderMode = FT_RENDER_MODE_NORMAL;
m_nBlendMode = agg::comp_op_src_over;
m_bIs0PenWidthAs1px = false;
}
CGraphics::CGraphics(CImage* pImage) : m_dwConfigFlags(0)
{
m_dGlobalAlpha = 1.0;
if (!pImage)
{
return;
}
m_dWidthPix = 0;
m_dHeightPix = 0;
m_dDpiX = 72.0;
m_dDpiY = 72.0;
m_ePageUnits = UnitPixel;
m_pPixels = NULL;
m_bIntegerGrid = false;
Create(pImage->m_pImgData, pImage->GetWidth(), pImage->GetHeight(), pImage->m_nStride, 0);
#ifdef _WINDOW_GDIPLUS_USE_
m_pBitmap = NULL;
m_pGraphics = NULL;
#endif
m_bSwapRGB = false;
#if defined (_LINUX) || defined (_QT)
m_bSwapRGB = true;
#endif
m_dDpiTile = -1;
m_pAlphaMask = NULL;
m_pSoftMask = NULL;
m_nTextRenderMode = FT_RENDER_MODE_NORMAL;
m_nBlendMode = agg::comp_op_src_over;
m_bIs0PenWidthAs1px = false;
}
CGraphics::~CGraphics()
{
#ifdef _WINDOW_GDIPLUS_USE_
RELEASEOBJECT(m_pGraphics);
RELEASEOBJECT(m_pBitmap);
#endif
RELEASEINTERFACE(m_pAlphaMask);
RELEASEINTERFACE(m_pSoftMask);
while (!m_arLayers.empty())
{
RELEASEINTERFACE(m_arLayers.top());
m_arLayers.pop();
}
}
INT CGraphics::IsDib()
{
return (NULL != m_pDib);
}
Status CGraphics::Create(BYTE* pPixels, int lWidth, int lHeight, int lStride, LONG lPitch)
{
if (lStride < 0)
{
//BYTE* pBuffer = pPixels + (lHeight - 1) * lStride;
//m_frame_buffer.create(lWidth, lHeight, false, lStride, pBuffer);
m_frame_buffer.create(lWidth, lHeight, false, lStride, pPixels);
}
else
{
m_frame_buffer.create(lWidth, lHeight, false, lStride, pPixels);
}
m_dWidthPix = (double)lWidth;
m_dHeightPix = (double)lHeight;
m_rasterizer.get_rasterizer().clip_box(0, 0, m_dWidthPix, m_dHeightPix);
m_rasterizer.get_rasterizer().gamma(agg::gamma_none());
m_dClipLeft = 0;
m_dClipTop = 0;
m_dClipWidth = m_dWidthPix;
m_dClipHeight = m_dHeightPix;
m_oClip.Create(lWidth, lHeight);
UpdateUnits();
return Ok;
}
Status CGraphics::Create2(BYTE* pPixels, int lWidth, int lHeight, int lStride, LONG lPitch, LONG x, LONG y, LONG w, LONG h, double dW, double dH, CDIB* pDib)
{
if (lStride < 0)
{
m_frame_buffer.create(lWidth, lHeight, false, lStride, pPixels);
}
else
{
m_frame_buffer.create(lWidth, lHeight, false, lStride, pPixels);
}
m_dWidthPix = (double)dW;
m_dHeightPix = (double)dH;
m_rasterizer.get_rasterizer().clip_box(x, y, w + x, h + y);
m_rasterizer.get_rasterizer().gamma(agg::gamma_none());
m_dClipLeft = x;
m_dClipTop = y;
m_dClipWidth = w;
m_dClipHeight = h;
m_oClip.Create(lWidth, lHeight);
UpdateUnits();
#ifdef _WINDOW_GDIPLUS_USE_
RELEASEOBJECT(m_pGraphics);
RELEASEOBJECT(m_pBitmap);
#endif
BYTE* pBuffer = pPixels;
if (0 > lStride)
{
// переворачиваем изображение для GDI+
pBuffer += 4 * lWidth * (lHeight - 1);
}
#ifdef _WINDOW_GDIPLUS_USE_
m_pBitmap = new Gdiplus::Bitmap(lWidth, lHeight, lStride, PixelFormat32bppARGB, pBuffer);
m_pGraphics = new Gdiplus::Graphics(m_pBitmap);
m_pGraphics->SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAlias);
m_pGraphics->SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
#endif
m_pPixels = pPixels;
m_pDib = pDib;
return Ok;
}
Status CGraphics::CreatePart(LONG lLeft, LONG lTop, LONG lWidth, LONG lHeight, CGraphics** ppPart)
{
// здесь минимум кода. Просто сделать дубликат - и выставить ему правильные границы.
// а потом уже и dpi и все настройки.
return Ok;
}
double CGraphics::GetDpiX()
{
return m_dDpiX;
}
double CGraphics::GetDpiY()
{
return m_dDpiY;
}
Status CGraphics::SetDpiX(double dDpiX)
{
if (dDpiX != m_dDpiX)
{
m_dDpiX = dDpiX;
}
return Ok;
}
Status CGraphics::SetDpiY(double dDpiY)
{
if (dDpiY != m_dDpiY)
{
m_dDpiY = dDpiY;
}
return Ok;
}
Status CGraphics::SetPageWidth(double lWidth, LONG lUnit)
{
// вычисилить dpi и выставить его
switch (lUnit)
{
case UnitPoint:
{
lWidth /= c_ag_Inch_to_Point;
SetDpiX(m_dWidthPix / lWidth);
break;
}
case UnitMillimeter:
{
lWidth /= c_ag_Inch_to_MM;
SetDpiX(m_dWidthPix / lWidth);
break;
}
case UnitInch:
{
SetDpiX(m_dWidthPix / lWidth);
break;
}
default:
break;
};
return Ok;
}
Status CGraphics::SetPageHeight(double lHeight, LONG lUnit)
{
// вычисилить dpi и выставить его
switch (lUnit)
{
case UnitPoint:
{
lHeight /= c_ag_Inch_to_Point;
SetDpiY(m_dHeightPix / lHeight);
break;
}
case UnitMillimeter:
{
lHeight /= c_ag_Inch_to_MM;
SetDpiY(m_dHeightPix / lHeight);
break;
}
case UnitInch:
{
SetDpiY(m_dHeightPix / lHeight);
break;
}
default:
break;
};
return Ok;
}
Unit CGraphics::GetPageUnit()
{
return m_ePageUnits;
}
Status CGraphics::SetPageUnit(Unit lUnits)
{
m_ePageUnits = lUnits;
UpdateUnits();
return Ok;
}
CMatrix* CGraphics::GetTransform()
{
return &m_oTransform;
}
Status CGraphics::SetTransform(CMatrix* pTransform)
{
m_oTransform = *pTransform;
return Ok;
}
CMatrix* CGraphics::GetBaseTransform()
{
return &m_oBaseTransform;
}
Status CGraphics::SetBaseTransform(CMatrix* pTransform)
{
m_oBaseTransform = *pTransform;
return Ok;
}
Status CGraphics::TranslateTransform(double x, double y, MatrixOrder order)
{
m_oTransform.Translate(x, y, order);
return Ok;
}
Status CGraphics::RotateTransform(double dAngle, MatrixOrder order)
{
m_oTransform.Rotate(dAngle, order);
return Ok;
}
Status CGraphics::ScaleTransform(double dScaleX, double dScaleY, MatrixOrder order)
{
m_oTransform.Scale(dScaleX, dScaleY, order);
return Ok;
}
Status CGraphics::ShearTransform(double shearX, double shearY, MatrixOrder order)
{
m_oTransform.Shear(shearX, shearY, order);
return Ok;
}
Status CGraphics::MultiplyTransform(CMatrix* pMatrix, MatrixOrder order)
{
m_oTransform.Multiply(pMatrix, order);
return Ok;
}
// функции отсечения
Status CGraphics::SetClipRect(double dLeft, double dTop, double dWidth, double dHeight)
{
double dx1 = dLeft;
double dy1 = dTop;
double dx2 = dLeft + dWidth;
double dy2 = dTop + dHeight;
m_oFullTransform.TransformPoint(dx1, dy1);
m_oFullTransform.TransformPoint(dx2, dy2);
m_dClipLeft = std::max(0.0, dx1);
m_dClipTop = std::max(0.0, dy1);
m_dClipWidth = std::min(dx2, m_dWidthPix - 1) - m_dClipLeft;
m_dClipHeight = std::min(dy2, m_dHeightPix - 1) - m_dClipTop;
m_oClip.Reset();
return Ok;
}
Status CGraphics::SetClipRect2(double dLeft, double dTop, double dWidth, double dHeight)
{
m_dClipLeft = std::max(0.0, dLeft);
m_dClipTop = std::max(0.0, dTop);
m_dClipWidth = std::min(dWidth, m_dWidthPix - 1 - m_dClipLeft);
m_dClipHeight = std::min(dHeight, m_dHeightPix - 1 - m_dClipTop);
m_rasterizer.get_rasterizer().clip_box(m_dClipLeft, m_dClipTop, m_dClipWidth + m_dClipLeft, m_dClipHeight + m_dClipTop);
m_oClip.Reset();
return Ok;
}
Status CGraphics::SetClipRect3(double dLeft, double dTop, double dWidth, double dHeight)
{
double dRight = dLeft + dWidth;
double dBottom = dTop + dHeight;
m_oFullTransform.TransformPoint(dLeft, dTop);
m_oFullTransform.TransformPoint(dRight, dBottom);
dWidth = dRight - dLeft;
dHeight = dBottom - dTop;
m_dClipLeft = dLeft;
m_dClipTop = dTop;
m_dClipWidth = dWidth;
m_dClipHeight = dHeight;
m_rasterizer.get_rasterizer().reset_clipping();
m_rasterizer.get_rasterizer().clip_box(m_dClipLeft, m_dClipTop, m_dClipWidth + m_dClipLeft, m_dClipHeight + m_dClipTop);
m_frame_buffer.ren_base().clip_box((int)m_dClipLeft, (int)m_dClipTop, (int)(m_dClipWidth + m_dClipLeft), (int)(m_dClipHeight + m_dClipTop));
m_oClip.Reset();
return Ok;
}
Status CGraphics::SetClip(CGraphicsPath* pPath)
{
if (NULL == pPath)
return InvalidParameter;
m_oClip.GenerateClip(pPath, &m_oFullTransform);
return Ok;
}
Status CGraphics::ResetClip()
{
m_oClip.Reset();
m_oClipState.Clear();
return Ok;
}
Status CGraphics::ExclugeClip(CGraphicsPath* pPath)
{
if (NULL == pPath)
return InvalidParameter;
CGraphicsPath oMemory;
oMemory.AddRectangle(0, 0, m_dWidthPix, m_dHeightPix);
oMemory.AddPath(*pPath);
m_oClip.GenerateClip(&oMemory, &m_oFullTransform);
return Ok;
}
Status CGraphics::CombineClip(CGraphicsPath* pPath, agg::sbool_op_e op, NSStructures::CPen* pPen)
{
Aggplus::CMatrix m;
return InternalClip(pPath, (m_bIntegerGrid || pPath->m_internal->m_pTransform != NULL) ? &m : &m_oFullTransform, op, pPen);
}
Status CGraphics::InternalClip(CGraphicsPath* pPath, CMatrix* pTransform, agg::sbool_op_e op, NSStructures::CPen* pPen)
{
if (NULL == pPath)
return InvalidParameter;
bool bTempRasterizer = false;
CClipMulti::clip_rasterizer* pRasterizer = m_oClip.GetRasterizer();
if (!pRasterizer)
{
pRasterizer = new CClipMulti::clip_rasterizer();
pRasterizer->clip_box(0, 0, m_oClip.m_lWidth, m_oClip.m_lHeight);
bTempRasterizer = true;
}
agg::trans_affine* pAffine = NULL;
if (pPen)
pAffine = DoStrokePath(pPen, pPath, pRasterizer);
else
{
typedef agg::conv_transform<agg::path_storage> trans_type;
trans_type trans(pPath->m_internal->m_agg_ps, pTransform->m_internal->m_agg_mtx);
typedef agg::conv_curve<trans_type> conv_crv_type;
conv_crv_type c_c_path(trans);
pRasterizer->add_path(c_c_path);
}
m_oClip.Combine(pPath->m_internal->m_bEvenOdd, op, pRasterizer);
// write to clips history
CGraphics_ClipStateRecord* pRecord = new CGraphics_ClipStateRecord();
pRecord->Path = (NULL != pPath) ? pPath->Clone() : NULL;
pRecord->Transform = (NULL != pTransform) ? new CMatrix(*pTransform) : new CMatrix();
pRecord->Operation = op;
m_oClipState.AddRecord(pRecord);
if (pAffine)
delete pAffine;
if (bTempRasterizer)
delete pRasterizer;
return Ok;
}
INT CGraphics::MeasureString(const std::wstring& strText, CFontManager* pManager, double* lWidth, double* lHeight)
{
if (NULL == pManager || NULL == lWidth || NULL == lHeight)
return FALSE;
pManager->LoadString1(strText, 0, 0);
TBBox oBox = pManager->MeasureString();
*lWidth = (double)oBox.fMaxX - oBox.fMinX;
*lHeight = (double)oBox.fMaxY - oBox.fMinY;
return TRUE;
}
Status CGraphics::Clear(CColor oColor)
{
CBrushSolid oBrush(oColor);
return FillRectangle(&oBrush, 0, 0, m_dWidthPix, m_dHeightPix);
}
Status CGraphics::DrawArc(NSStructures::CPen* pPen, double x, double y, double width, double height, double startAngle, double sweepAngle)
{
CGraphicsPath oPath;
oPath.AddArc(x, y, width, height, startAngle, sweepAngle);
return DrawPath(pPen, &oPath);
}
Status CGraphics::DrawBezier(NSStructures::CPen* pPen, double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
{
CGraphicsPath oPath;
oPath.AddBezier(x1, y1, x2, y2, x3, y3, x4, y4);
return DrawPath(pPen, &oPath);
}
Status CGraphics::DrawBeziers(NSStructures::CPen* pPen, double* pPoints, LONG lCount)
{
CGraphicsPath oPath;
oPath.AddBeziers(pPoints, lCount);
return DrawPath(pPen, &oPath);
}
Status CGraphics::DrawCurve(NSStructures::CPen* pPen, double* pPoints, LONG lCount)
{
CGraphicsPath oPath;
oPath.AddBeziers(pPoints, lCount);
return DrawPath(pPen, &oPath);
}
Status CGraphics::DrawLine(NSStructures::CPen* pPen, double x1, double y1, double x2, double y2)
{
CGraphicsPath oPath;
oPath.AddLine(x1, y1, x2, y2);
return DrawPath(pPen, &oPath);
}
Status CGraphics::DrawLines(NSStructures::CPen* pPen, double* pPoints, LONG lCount)
{
CGraphicsPath oPath;
oPath.AddLines(pPoints, lCount);
return DrawPath(pPen, &oPath);
}
Status CGraphics::DrawRectangle(NSStructures::CPen* pPen, double x, double y, double width, double height)
{
CGraphicsPath oPath;
oPath.AddRectangle(x, y, width, height);
return DrawPath(pPen, &oPath);
}
Status CGraphics::DrawEllipse(NSStructures::CPen* pPen, double x, double y, double width, double height)
{
CGraphicsPath oPath;
oPath.AddEllipse(x, y, width, height);
return DrawPath(pPen, &oPath);
}
Status CGraphics::DrawPath(NSStructures::CPen* pPen, CGraphicsPath* pPath, const double& gamma)
{
if (NULL == pPen || NULL == pPath)
return InvalidParameter;
m_rasterizer.get_rasterizer().reset();
agg::trans_affine* pAffine = DoStrokePath(pPen, pPath, &m_rasterizer.get_rasterizer());
CColor oColor((BYTE)(pPen->Alpha * m_dGlobalAlpha), pPen->Color, m_bSwapRGB);
CBrushSolid oBrush(oColor);
m_rasterizer.get_rasterizer().filling_rule(agg::fill_non_zero);
if (gamma >= 0)
m_rasterizer.get_rasterizer().gamma(agg::gamma_threshold(gamma));
DoFillPath(&oBrush);
if (gamma >= 0)
m_rasterizer.gamma(1.0);
RELEASEOBJECT(pAffine);
return Ok;
}
Status CGraphics::DrawPathNoTransform(NSStructures::CPen* pPen, CGraphicsPath* pPath)
{
if (NULL == pPen || NULL == pPath)
return InvalidParameter;
m_rasterizer.get_rasterizer().reset();
//butt_cap, square_cap, round_cap
//pg.line_cap(agg::vcgen_stroke::round_cap);
agg::line_join_e LineJoin;
switch(pPen->LineJoin)
{
case LineJoinMiter : LineJoin = agg::miter_join; break;
case LineJoinBevel : LineJoin = agg::bevel_join; break;
default:
case LineJoinRound : LineJoin = agg::round_join; break;
case LineJoinMiterClipped: LineJoin = agg::miter_join_revert; break;
}
double dWidth = pPen->Size;
double dblMiterLimit = 0.5;
agg::path_storage path_copy(pPath->m_internal->m_agg_ps);
typedef agg::conv_curve<agg::path_storage> conv_crv_type;
conv_crv_type c_c_path(path_copy);
c_c_path.approximation_scale(25.0);
c_c_path.approximation_method(agg::curve_inc);
DashStyle eStyle = (DashStyle)pPen->DashStyle;
if (DashStyleSolid == eStyle || DashStyleCustom == eStyle)
{
typedef agg::conv_stroke<conv_crv_type> Path_Conv_StrokeN;
Path_Conv_StrokeN pgN(c_c_path);
//typedef agg::conv_stroke<agg::path_storage> Path_Conv_StrokeN;
//Path_Conv_StrokeN pgN(pPath->m_agg_ps);
pgN.line_join(agg::round_join);
pgN.miter_limit(dblMiterLimit);
//pgN.approximation_scale(25.0);
pgN.width(dWidth);
typedef agg::conv_transform<Path_Conv_StrokeN> transStroke;
CMatrix oM;
transStroke trans(pgN, oM.m_internal->m_agg_mtx);
m_rasterizer.get_rasterizer().add_path(trans);
}
else
{
typedef agg::conv_dash<conv_crv_type> Path_Conv_Dash;
Path_Conv_Dash poly2_dash(c_c_path);
typedef agg::conv_stroke<Path_Conv_Dash> Path_Conv_StrokeD;
Path_Conv_StrokeD pgD(poly2_dash);
switch (eStyle)
{
case DashStyleDash:
poly2_dash.add_dash(3.00*dWidth, dWidth);
break;
case DashStyleDot:
poly2_dash.add_dash(dWidth, dWidth);
break;
case DashStyleDashDot:
poly2_dash.add_dash(3.00*dWidth, dWidth);
poly2_dash.add_dash(dWidth, dWidth);
break;
case DashStyleDashDotDot:
poly2_dash.add_dash(3.00*dWidth, dWidth);
poly2_dash.add_dash(dWidth, dWidth);
poly2_dash.add_dash(dWidth, dWidth);
break;
default:
case DashStyleCustom:break;
}
pgD.line_join(LineJoin);
pgD.miter_limit(dblMiterLimit);
pgD.width(dWidth);
agg::conv_transform<Path_Conv_StrokeD> trans(pgD, m_oFullTransform.m_internal->m_agg_mtx);
m_rasterizer.get_rasterizer().add_path(trans);
}
CColor oColor((BYTE)pPen->Alpha, pPen->Color, m_bSwapRGB);
CBrushSolid oBrush(oColor);
m_rasterizer.get_rasterizer().filling_rule(agg::fill_non_zero);
DoFillPath(&oBrush);
return Ok;
}
Status CGraphics::FillEllipse(CBrush* pBrush, double x, double y, double width, double height)
{
CGraphicsPath oPath;
oPath.AddEllipse(x, y, width, height);
return FillPath(pBrush, &oPath);
}
Status CGraphics::FillRectangle(CBrush* pBrush, double x, double y, double width, double height)
{
CGraphicsPath oPath;
oPath.AddRectangle(x, y, width, height);
return FillPath(pBrush, &oPath);
}
Status CGraphics::FillPolygon(CBrush* pBrush, double* pPoints, LONG lCount)
{
CGraphicsPath oPath;
oPath.AddPolygon(pPoints, lCount);
return FillPath(pBrush, &oPath);
}
Status CGraphics::FillPath(CBrush* pBrush, CGraphicsPath* pPath)
{
if (NULL == pBrush)
return InvalidParameter;
m_rasterizer.get_rasterizer().reset();
agg::path_storage p2(pPath->m_internal->m_agg_ps);
typedef agg::conv_transform<agg::path_storage> trans_type;
trans_type* ptrans = NULL;
agg::trans_affine* paffine = NULL;
if (!m_bIntegerGrid)
ptrans = new trans_type(p2, m_oFullTransform.m_internal->m_agg_mtx);
else
{
paffine = new agg::trans_affine();
ptrans = new trans_type(p2, *paffine);
}
typedef agg::conv_curve<trans_type> conv_crv_type;
conv_crv_type c_c_path(*ptrans);
m_rasterizer.get_rasterizer().add_path(c_c_path);
m_rasterizer.get_rasterizer().filling_rule(pPath->m_internal->m_bEvenOdd ? agg::fill_even_odd : agg::fill_non_zero);
if (pBrush->GetType() == Aggplus::BrushTypeTextureFill)
{
CBrushTexture *ptxBrush= (CBrushTexture *)pBrush;
DWORD dwPatternWidth = ptxBrush->PatternGetWidth();
DWORD dwPatternHeight = ptxBrush->PatternGetHeight();
if( !dwPatternWidth || !dwPatternHeight )
return Ok;
double x = 0;
double y = 0;
double r = 0;
double b = 0;
if (!ptxBrush->m_bUseBounds)
{
pPath->GetBounds(x, y, r, b);
r += x;
b += y;
}
else
{
x = ptxBrush->m_oBounds.left;
y = ptxBrush->m_oBounds.top;
r = ptxBrush->m_oBounds.right;
b = ptxBrush->m_oBounds.bottom;
}
CMatrix brushMatrix(ptxBrush->m_mtx);
if (ptxBrush->GetWrapMode() == Aggplus::WrapModeClamp)
{
double dScaleX = (r - x) / dwPatternWidth;
double dScaleY = (b - y) / dwPatternHeight;
brushMatrix.Scale(dScaleX, dScaleY, Aggplus::MatrixOrderAppend);
}
if (ptxBrush->GetWrapMode() != Aggplus::WrapModeClamp && m_dDpiTile > 1)
{
double dScaleX = m_dDpiX / m_dDpiTile;
double dScaleY = m_dDpiY / m_dDpiTile;
brushMatrix.Scale(dScaleX, dScaleY, Aggplus::MatrixOrderAppend);
}
brushMatrix.Translate(x, y, Aggplus::MatrixOrderAppend);
brushMatrix.Multiply(&m_oFullTransform, MatrixOrderAppend);
ptxBrush->SetTransform(&brushMatrix);
}
DoFillPath(pBrush);
RELEASEOBJECT(ptrans);
RELEASEOBJECT(paffine);
return Ok;
}
// отрисовка картинки
Status CGraphics::DrawImage(CImage* pImage, double x, double y, double width, double height)
{
if (!pImage || pImage->GetLastStatus() != Ok)
return UnknownImageFormat;
if(width == 0.00 || height == 0.00)
return InvalidParameter;
CGraphicsPath oPath;
oPath.MoveTo(x, y);
oPath.LineTo(x+width, y);
oPath.LineTo(x+width, y+height);
oPath.LineTo(x, y+height);
oPath.CloseFigure();
CBrushTexture oBrush(pImage, Aggplus::WrapModeClamp);
FillPath(&oBrush, &oPath);
return Ok;
}
Status CGraphics::DrawMeta(const std::wstring& strFile, double x, double y, double width, double height)
{
return Ok;
}
#ifdef _WINDOW_GDIPLUS_USE_
Status CGraphics::DrawGdiplusImage(Gdiplus::Bitmap* pImage, double x, double y, double width, double height)
{
if (!pImage || pImage->GetLastStatus() != Gdiplus::Ok)
return UnknownImageFormat;
if(width == 0.00 || height == 0.00)
return InvalidParameter;
m_pGraphics->SetPageUnit(Gdiplus::UnitPixel);
double x1 = x;
double y1 = y;
m_oFullTransform.TransformPoint(x1, y1);
double x2 = x + width;
double y2 = y;
m_oFullTransform.TransformPoint(x2, y2);
double x3 = x;
double y3 = y + height;
m_oFullTransform.TransformPoint(x3, y3);
Gdiplus::PointF points[3];
points[0].X = (float)(x1 - 1.0);
points[0].Y = (float)(y1 - 1.0);
points[1].X = (float)(x2 + 1.0);
points[1].Y = (float)(y2 - 1.0);
points[2].X = (float)(x3 - 1.0);
points[2].Y = (float)(y3 + 1.0);
m_pGraphics->DrawImage(pImage, points, 3);
return Ok;
}
#endif
INT CGraphics::DrawImageUnscaled(CImage* pImage, double x, double y)
{
return TRUE;
}
INT CGraphics::DrawString(const std::wstring& strText, CFontManager* pFont, CBrush* pBrush, double x, double y)
{
if (pBrush->GetType() != BrushTypeSolidColor)
return TRUE;
CMatrix oMatrix = m_oBaseTransform;
oMatrix.Multiply(&m_oTransform, MatrixOrderPrepend);
double mass[6];
oMatrix.GetElements(mass);
double _x = x;
double _y = y;
CMatrix oM1 = oMatrix;
oM1.Invert();
oM1.Multiply(&m_oFullTransform, MatrixOrderPrepend);
oM1.TransformPoint(_x, _y);
pFont->SetTextMatrix((float)mass[0], (float)mass[1], (float)mass[2], (float)mass[3], (float)mass[4], (float)mass[5]);
m_nTextRenderMode = pFont->m_nRENDER_MODE;
pFont->LoadString2(strText, (float)_x, (float)_y);
float fX = 0;
float fY = 0;
INT bRes = FALSE;
while (TRUE)
{
TGlyph* pGlyph = NULL;
bRes = pFont->GetNextChar2(pGlyph, fX, fY);
if (FALSE == bRes)
break;
if (NULL != pGlyph)
{
FillGlyph2((int)fX, (int)fY, pGlyph, pBrush);
}
}
return TRUE;
}
INT CGraphics::DrawString(const unsigned int* pGids, const unsigned int nGidsCount, CFontManager* pFont, CBrush* pBrush, double x, double y)
{
if (pBrush->GetType() != BrushTypeSolidColor)
return TRUE;
CMatrix oMatrix = m_oBaseTransform;
oMatrix.Multiply(&m_oTransform, MatrixOrderPrepend);
double mass[6];
oMatrix.GetElements(mass);
double _x = x;
double _y = y;
CMatrix oM1 = oMatrix;
oM1.Invert();
oM1.Multiply(&m_oFullTransform, MatrixOrderPrepend);
oM1.TransformPoint(_x, _y);
pFont->SetTextMatrix((float)mass[0], (float)mass[1], (float)mass[2], (float)mass[3], (float)mass[4], (float)mass[5]);
m_nTextRenderMode = pFont->m_nRENDER_MODE;
pFont->LoadString2(pGids, nGidsCount, (float)_x, (float)_y);
float fX = 0;
float fY = 0;
INT bRes = FALSE;
while (TRUE)
{
TGlyph* pGlyph = NULL;
bRes = pFont->GetNextChar2(pGlyph, fX, fY);
if (FALSE == bRes)
break;
if (NULL != pGlyph)
{
FillGlyph2((int)fX, (int)fY, pGlyph, pBrush);
}
}
return TRUE;
}
INT CGraphics::DrawStringC(const LONG& lText, CFontManager* pFont, CBrush* pBrush, double x, double y)
{
if (pBrush->GetType() != BrushTypeSolidColor)
return TRUE;
CMatrix oMatrix = m_oBaseTransform;
oMatrix.Multiply(&m_oTransform, MatrixOrderPrepend);
double mass[6];
oMatrix.GetElements(mass);
double _x = x;
double _y = y;
CMatrix oM1 = oMatrix;
oM1.Invert();
oM1.Multiply(&m_oFullTransform, MatrixOrderPrepend);
oM1.TransformPoint(_x, _y);
pFont->SetTextMatrix((float)mass[0], (float)mass[1], (float)mass[2], (float)mass[3], (float)mass[4], (float)mass[5]);
m_nTextRenderMode = pFont->m_nRENDER_MODE;
pFont->LoadString2C(lText, (float)_x, (float)_y);
float fX = 0;
float fY = 0;
INT bRes = FALSE;
while (TRUE)
{
TGlyph* pGlyph = NULL;
bRes = pFont->GetNextChar2(pGlyph, fX, fY);
if (FALSE == bRes)
break;
if (NULL != pGlyph)
{
FillGlyph2((int)fX, (int)fY, pGlyph, pBrush);
}
}
return TRUE;
}
INT CGraphics::DrawStringPath(const std::wstring& strText, CFontManager* pFont, CBrush* pBrush, double x, double y)
{
if (pBrush->GetType() != BrushTypeSolidColor)
return TRUE;
Aggplus::CGraphicsPath oPath;
oPath.AddString(strText, pFont, x, y);
FillPath(pBrush, &oPath);
return TRUE;
}
INT CGraphics::DrawStringPathC(const LONG& lText, CFontManager* pFont, CBrush* pBrush, double x, double y)
{
if (pBrush->GetType() != BrushTypeSolidColor)
return TRUE;
Aggplus::CGraphicsPath oPath;
oPath.AddStringC(lText, pFont, x, y);
FillPath(pBrush, &oPath);
return TRUE;
}
Status CGraphics::SetAlphaMask(CAlphaMask *pAlphaMask)
{
RELEASEINTERFACE(m_pAlphaMask);
m_pAlphaMask = pAlphaMask;
if (m_pAlphaMask)
m_pAlphaMask->AddRef();
return CreateLayer();
}
Status CGraphics::StartCreatingAlphaMask()
{
return CreateLayer();
}
Status CGraphics::EndCreatingAlphaMask()
{
if (m_arLayers.empty())
return WrongState;
CGraphicsLayer *pCurrentGraphicsLayer = m_arLayers.top();
m_arLayers.pop();
if (pCurrentGraphicsLayer->Empty())
return GenericError;
BYTE* pBuffer = pCurrentGraphicsLayer->GetBuffer();
pCurrentGraphicsLayer->ClearBuffer(false);
RELEASEINTERFACE(pCurrentGraphicsLayer);
RELEASEINTERFACE(m_pAlphaMask);
m_pAlphaMask = new CAlphaMask(pBuffer, EMaskDataType::ImageBuffer, false);
return CreateLayer();
}
Status CGraphics::ResetAlphaMask()
{
BlendLayer();
RELEASEINTERFACE(m_pAlphaMask);
return Ok;
}
CSoftMask* CGraphics::CreateSoftMask(bool bAlpha)
{
if (m_arLayers.empty())
return NULL;
CGraphicsLayer *pCurrentGraphicsLayer = m_arLayers.top();
m_arLayers.pop();
if (pCurrentGraphicsLayer->Empty())
{
RELEASEINTERFACE(pCurrentGraphicsLayer);
return NULL;
}
BYTE* pBuffer = pCurrentGraphicsLayer->GetBuffer();
pCurrentGraphicsLayer->ClearBuffer(false);
RELEASEINTERFACE(pCurrentGraphicsLayer);
RELEASEINTERFACE(m_pSoftMask);
unsigned int unWidth = m_frame_buffer.ren_buf().width(), unHeight = m_frame_buffer.ren_buf().height();
bool bFlip = m_frame_buffer.ren_buf().stride() < 0;
m_pSoftMask = new CSoftMask(pBuffer, unWidth, unHeight, bFlip, m_bSwapRGB, bAlpha);
pBuffer = m_arLayers.empty() ? m_pPixels : m_arLayers.top()->GetBuffer();
if (!pBuffer)
{
RELEASEINTERFACE(pCurrentGraphicsLayer);
return NULL;
}
m_frame_buffer.ren_buf().attach(pBuffer, unWidth, unHeight, m_frame_buffer.ren_buf().stride());
return m_pSoftMask;
}
Status CGraphics::SetSoftMask(CSoftMask* pSoftMask)
{
if (m_pSoftMask == pSoftMask)
return Ok;
RELEASEINTERFACE(m_pSoftMask);
m_pSoftMask = pSoftMask;
if (m_pSoftMask)
m_pSoftMask->AddRef();
return Ok;
}
Status CGraphics::AddLayer(CGraphicsLayer *pGraphicsLayer)
{
if (NULL == pGraphicsLayer || pGraphicsLayer->Empty())
return InvalidParameter;
m_arLayers.push(pGraphicsLayer);
pGraphicsLayer->AddRef();
int nStride = m_frame_buffer.ren_buf().stride();
const unsigned int unWidth = m_frame_buffer.ren_buf().width();
const unsigned int unHeight = m_frame_buffer.ren_buf().height();
m_frame_buffer.create(unWidth, unHeight, nStride < 0, nStride, pGraphicsLayer->GetBuffer());
return Ok;
}
Status CGraphics::CreateLayer()
{
int nStride = m_frame_buffer.ren_buf().stride();
const unsigned int unWidth = m_frame_buffer.ren_buf().width();
const unsigned int unHeight = m_frame_buffer.ren_buf().height();
UINT unSize = unWidth * unHeight * m_frame_buffer.pix_size;
BYTE *pBuffer = new BYTE[unSize];
memset(pBuffer, 0x00, unSize);
m_frame_buffer.create(unWidth, unHeight, nStride < 0, nStride, pBuffer);
m_arLayers.push(new CGraphicsLayer(pBuffer, false));
return Ok;
}
Status CGraphics::BlendLayer()
{
if (m_arLayers.empty())
return WrongState;
CGraphicsLayer *pCurrentGraphicsLayer = m_arLayers.top();
m_arLayers.pop();
BYTE* pBuffer = NULL;
if (!m_arLayers.empty())
pBuffer = m_arLayers.top()->GetBuffer();
else
pBuffer = m_pPixels;
if (NULL == pBuffer)
{
RELEASEINTERFACE(pCurrentGraphicsLayer);
return WrongState;
}
m_frame_buffer.ren_buf().attach(pBuffer, m_frame_buffer.ren_buf().width(), m_frame_buffer.ren_buf().height(), m_frame_buffer.ren_buf().stride());
if (m_pAlphaMask)
{
switch(m_pAlphaMask->GetDataType())
{
case EMaskDataType::ImageBuffer:
{
Aggplus::BlendTo<agg::rgb_to_gray_mask_u8<2, 1, 0>>(pCurrentGraphicsLayer, m_frame_buffer.pixfmt(), m_pAlphaMask->GetBuffer(), m_pAlphaMask->GetStep());
break;
}
case EMaskDataType::AlphaBuffer:
{
Aggplus::BlendTo<agg::one_component_mask_u8>(pCurrentGraphicsLayer, m_frame_buffer.pixfmt(), m_pAlphaMask->GetBuffer(), m_pAlphaMask->GetStep());
break;
}
}
}
else if (m_pSoftMask)
{
ESoftMaskType nType = m_pSoftMask->GetDataType();
if (nType == ESoftMaskType::RGBGrayBuffer)
Aggplus::BlendTo<agg::rgb_to_gray_mask_u8<0, 1, 2>>(pCurrentGraphicsLayer, m_frame_buffer.pixfmt(), m_pSoftMask->GetBuffer(), m_pSoftMask->GetStep());
else if (nType == ESoftMaskType::BGRGrayBuffer)
Aggplus::BlendTo<agg::rgb_to_gray_mask_u8<2, 1, 0>>(pCurrentGraphicsLayer, m_frame_buffer.pixfmt(), m_pSoftMask->GetBuffer(), m_pSoftMask->GetStep());
else if (nType == ESoftMaskType::Alpha4Buffer)
Aggplus::BlendTo<agg::one_component_mask_u8>(pCurrentGraphicsLayer, m_frame_buffer.pixfmt(), m_pSoftMask->GetBuffer() + 3, m_pSoftMask->GetStep());
}
else
{
if (m_nBlendMode != agg::comp_op_src_over)
{
pixfmt_type_comp pixfmt(m_frame_buffer.ren_buf(), m_nBlendMode);
Aggplus::BlendTo(pCurrentGraphicsLayer, pixfmt, m_nBlendMode);
}
else
Aggplus::BlendTo(pCurrentGraphicsLayer, m_frame_buffer.pixfmt());
}
RELEASEINTERFACE(pCurrentGraphicsLayer);
return Ok;
}
Status CGraphics::RemoveLayer()
{
if (m_arLayers.empty())
return WrongState;
CGraphicsLayer *pCurrentGraphicsLayer = m_arLayers.top();
m_arLayers.pop();
BYTE* pBuffer = NULL;
if (!m_arLayers.empty())
pBuffer = m_arLayers.top()->GetBuffer();
else
pBuffer = m_pPixels;
if (NULL == pBuffer)
{
RELEASEINTERFACE(pCurrentGraphicsLayer);
return WrongState;
}
m_frame_buffer.ren_buf().attach(pBuffer, m_frame_buffer.ren_buf().width(), m_frame_buffer.ren_buf().height(), m_frame_buffer.ren_buf().stride());
RELEASEINTERFACE(pCurrentGraphicsLayer);
return Ok;
}
Status CGraphics::SetLayerSettings(const TGraphicsLayerSettings &oSettings)
{
if (m_arLayers.empty())
return WrongState;
m_arLayers.top()->SetSettings(oSettings);
return Ok;
}
Status CGraphics::SetLayerOpacity(double dOpacity)
{
if (dOpacity < 0. || dOpacity > 1.)
return InvalidParameter;
if (m_arLayers.empty())
return WrongState;
m_arLayers.top()->SetOpacity(dOpacity);
return Ok;
}
void CGraphics::CalculateFullTransform()
{
m_oFullTransform = m_oCoordTransform;
m_oFullTransform.Multiply(&m_oBaseTransform, MatrixOrderAppend);
m_oFullTransform.Multiply(&m_oTransform, MatrixOrderPrepend);
}
bool CGraphics::IsClip()
{
return m_oClip.IsClip();
}
template<class Rasterizer, class Renderer, class Scanline>
void CGraphics::render_scanlines_3(Rasterizer& ras, Renderer& ren, Scanline& sl)
{
if (!m_oClip.IsClip())
{
agg::render_scanlines(ras, sl, ren);
}
else
{
if (!m_oClip.IsClip2())
{
typedef agg::scanline_p8 sbool_scanline_type;
sbool_scanline_type sl1;
sbool_scanline_type sl2;
agg::sbool_combine_shapes_aa(agg::sbool_and, ras, m_oClip.m_rasterizer, sl1, sl2, sl, ren);
}
else
{
typedef agg::scanline_p8 sbool_scanline_type;
sbool_scanline_type sl1;
sbool_scanline_type sl2;
agg::sbool_combine_shapes_aa(agg::sbool_and, ras, (1 == m_oClip.m_lCurStorage) ? m_oClip.m_storage1 : m_oClip.m_storage2, sl1, sl2, sl, ren);
}
}
}
template<class Renderer>
void CGraphics::render_scanlines(Renderer& ren)
{
render_scanlines_2(m_rasterizer.get_rasterizer(), ren);
}
template<class Renderer>
void CGraphics::render_scanlines_alpha(Renderer& ren, BYTE Alpha)
{
double dAlpha = m_dGlobalAlpha * Alpha / 255.0;
if (fabs(dAlpha - 1.0) < FLT_EPSILON)
{
render_scanlines(ren);
}
else
{
m_rasterizer.gamma_multi(dAlpha);
render_scanlines(ren);
m_rasterizer.gamma(1.0);
}
}
template<class Rasterizer, class Renderer>
void CGraphics::render_scanlines_2(Rasterizer& ras, Renderer& ren)
{
if (m_pSoftMask)
{
ESoftMaskType nType = m_pSoftMask->GetDataType();
if (nType == ESoftMaskType::RGBGrayBuffer)
return render_scanlines_3(ras, ren, ((CSoftMaskRGBAgray*)m_pSoftMask->m_pInternal)->GetScanline());
if (nType == ESoftMaskType::BGRGrayBuffer)
return render_scanlines_3(ras, ren, ((CSoftMaskBGRAgray*)m_pSoftMask->m_pInternal)->GetScanline());
if (nType == ESoftMaskType::Alpha4Buffer)
return render_scanlines_3(ras, ren, ((CSoftMaskAlpha*)m_pSoftMask->m_pInternal)->GetScanline());
}
render_scanlines_3(ras, ren, m_rasterizer.get_scanline());
}
void CGraphics::DoFillPathSolid(CColor dwColor)
{
if (m_nBlendMode != agg::comp_op_src_over)
{
typedef agg::renderer_scanline_aa_solid<comp_renderer_type> solid_comp_renderer_type;
solid_comp_renderer_type ren_solid;
comp_renderer_type ren_base;
pixfmt_type_comp pixfmt(m_frame_buffer.ren_buf(), m_nBlendMode);
ren_base.attach(pixfmt);
ren_solid.attach(ren_base);
ren_solid.color(dwColor.GetAggColor());
render_scanlines(ren_solid);
}
else
{
typedef agg::renderer_scanline_aa_solid<base_renderer_type> solid_renderer_type;
solid_renderer_type ren_fine(m_frame_buffer.ren_base());
ren_fine.color(dwColor.GetAggColor());
render_scanlines(ren_fine);
}
}
void CGraphics::DoFillPathGradient(CBrushLinearGradient *pBrush)
{
CDoubleRect& oBounds = pBrush->GetBounds();
CMatrix oMatrix;
agg::rect_d rect;
if (oBounds.GetWidth() > FLT_EPSILON || oBounds.GetHeight() > FLT_EPSILON)
{
rect.x1 = oBounds.left;
rect.y1 = oBounds.top;
rect.x2 = oBounds.right;
rect.y2 = oBounds.bottom;
oMatrix = m_oFullTransform;
oMatrix.Invert();
}
else
{
int x = m_rasterizer.get_rasterizer().min_x();
int y = m_rasterizer.get_rasterizer().min_y();
int r = m_rasterizer.get_rasterizer().max_x();
int b = m_rasterizer.get_rasterizer().max_y();
if (r < x || b < y)
return;
rect.x1 = x;
rect.x2 = r;
rect.y1 = y;
rect.y2 = b;
}
typedef agg::my_span_gradient<agg::rgba8> gradient_span_gen;
gradient_span_gen span_gen;
span_gen.SetDirection(rect, (double)pBrush->GetAngle(), oMatrix.m_internal->m_agg_mtx);
agg::rgba8* pSubColors = NULL;
float* pSubBlends = NULL;
int nCountSubColors = pBrush->GetInterpolationColorsCount();
if( nCountSubColors > 0 )
{
pSubColors = new agg::rgba8[nCountSubColors];
pSubBlends = new float[nCountSubColors];
if( pSubColors && pSubBlends )
{
for( int i = 0; i < nCountSubColors; i++ )
{
CColor c;
pBrush->GetSubColor( i, &c, &pSubBlends[i] );
pSubColors[i] = agg::rgba8(c.GetB(), c.GetG(), c.GetR(), c.GetA());
}
span_gen.SetSubColors( pSubColors, pSubBlends, nCountSubColors );
}
}
typedef agg::span_allocator<gradient_span_gen::color_type> gradient_span_alloc;
gradient_span_alloc span_alloc;
typedef agg::renderer_scanline_aa<base_renderer_type, gradient_span_alloc, gradient_span_gen> renderer_gradient_type;
renderer_gradient_type ren_gradient( m_frame_buffer.ren_base(), span_alloc, span_gen );
if (fabs(m_dGlobalAlpha - 1.0) < FLT_EPSILON)
{
render_scanlines(ren_gradient);
}
else
{
m_rasterizer.gamma_multi(m_dGlobalAlpha);
render_scanlines(ren_gradient);
m_rasterizer.gamma(1.0);
}
if( pSubColors ) delete [] pSubColors;
if( pSubBlends ) delete [] pSubBlends;
}
void CGraphics::DoFillPathGradient2(CBrushLinearGradient *pBrush)
{
CDoubleRect& oBounds = pBrush->GetBounds();
CMatrix oMatrix;
agg::rect_d rect;
if (oBounds.GetWidth() > FLT_EPSILON || oBounds.GetHeight() > FLT_EPSILON)
{
rect.x1 = oBounds.left;
rect.y1 = oBounds.top;
rect.x2 = oBounds.right;
rect.y2 = oBounds.bottom;
oMatrix = m_oFullTransform;
oMatrix.Invert();
}
else
{
int x = m_rasterizer.get_rasterizer().min_x();
int y = m_rasterizer.get_rasterizer().min_y();
int r = m_rasterizer.get_rasterizer().max_x();
int b = m_rasterizer.get_rasterizer().max_y();
if (r < x || b < y)
return;
rect.x1 = x;
rect.x2 = r;
rect.y1 = y;
rect.y2 = b;
}
typedef agg::my_span_path_gradient<agg::rgba8> gradient_span_gen;
gradient_span_gen span_gen;
span_gen.SetDirection(rect, oMatrix.m_internal->m_agg_mtx);
agg::rgba8* pSubColors = NULL;
float* pSubBlends = NULL;
int nCountSubColors = pBrush->GetInterpolationColorsCount();
if( nCountSubColors > 0 )
{
pSubColors = new agg::rgba8[nCountSubColors];
pSubBlends = new float[nCountSubColors];
if( pSubColors && pSubBlends )
{
for( int i = 0; i < nCountSubColors; i++ )
{
CColor c;
pBrush->GetSubColor( i, &c, &pSubBlends[i] );
pSubColors[i] = agg::rgba8(c.GetB(), c.GetG(), c.GetR(), c.GetA());
}
span_gen.SetSubColors( pSubColors, pSubBlends, nCountSubColors );
}
}
typedef agg::span_allocator<gradient_span_gen::color_type> gradient_span_alloc;
gradient_span_alloc span_alloc;
typedef agg::renderer_scanline_aa<base_renderer_type, gradient_span_alloc, gradient_span_gen> renderer_gradient_type;
renderer_gradient_type ren_gradient( m_frame_buffer.ren_base(), span_alloc, span_gen );
if (fabs(m_dGlobalAlpha - 1.0) < FLT_EPSILON)
{
render_scanlines(ren_gradient);
}
else
{
m_rasterizer.gamma_multi(m_dGlobalAlpha);
render_scanlines(ren_gradient);
m_rasterizer.gamma(1.0);
}
if( pSubColors ) delete [] pSubColors;
if( pSubBlends ) delete [] pSubBlends;
}
void CGraphics::DoFillPathHatch(CBrushHatch *pBrush)
{
#if 0
CDoubleRect& oBounds = pBrush->GetBounds();
CMatrix oMatrix;
agg::rect_d rect;
if (oBounds.GetWidth() > FLT_EPSILON || oBounds.GetHeight() > FLT_EPSILON)
{
rect.x1 = oBounds.left;
rect.y1 = oBounds.top;
rect.x2 = oBounds.right;
rect.y2 = oBounds.bottom;
oMatrix = m_oFullTransform;
}
else
{
int x = m_rasterizer.get_rasterizer().min_x();
int y = m_rasterizer.get_rasterizer().min_y();
int width = m_rasterizer.get_rasterizer().max_x() - m_rasterizer.get_rasterizer().min_x();
int height = m_rasterizer.get_rasterizer().max_y() - m_rasterizer.get_rasterizer().min_y();
rect.x1 = x;
rect.x2 = x + width;
rect.y1 = y;
rect.y2 = y + height;
}
typedef agg::agg_span_hatch<agg::rgba8> hatch_span_gen;
hatch_span_gen span_gen;
agg::rgba8 c1 = agg::rgba8(pBrush->m_dwColor1.GetB(), pBrush->m_dwColor1.GetG(), pBrush->m_dwColor1.GetR(), pBrush->m_dwColor1.GetA());
agg::rgba8 c2 = agg::rgba8(pBrush->m_dwColor2.GetB(), pBrush->m_dwColor2.GetG(), pBrush->m_dwColor2.GetR(), pBrush->m_dwColor2.GetA());
span_gen.SetDirection(pBrush->m_name, rect, oMatrix.m_agg_mtx, c1, c2);
typedef agg::span_allocator<hatch_span_gen::color_type> hatch_span_alloc;
hatch_span_alloc span_alloc;
typedef agg::renderer_scanline_aa<base_renderer_type, hatch_span_alloc, hatch_span_gen> renderer_hatch_type;
renderer_hatch_type ren_hatch( m_frame_buffer.ren_base(), span_alloc, span_gen );
if (fabs(m_dGlobalAlpha - 1.0) < FLT_EPSILON)
{
render_scanlines(ren_hatch);
}
else
{
m_rasterizer.gamma_multi(m_dGlobalAlpha);
render_scanlines(ren_hatch);
m_rasterizer.gamma(1.0);
}
#else
agg::rgba8 c1 = agg::rgba8(pBrush->m_dwColor1.GetR(), pBrush->m_dwColor1.GetG(), pBrush->m_dwColor1.GetB(), pBrush->m_dwColor1.GetA());
agg::rgba8 c2 = agg::rgba8(pBrush->m_dwColor2.GetR(), pBrush->m_dwColor2.GetG(), pBrush->m_dwColor2.GetB(), pBrush->m_dwColor2.GetA());
BYTE* pPattern = new BYTE[HATCH_TX_SIZE * HATCH_TX_SIZE * 4];
agg::GetHatchPattern(pBrush->m_name, (agg::rgba8*)pPattern, c1, c2);
agg::trans_affine mtx_Work(m_oTransform.m_internal->m_agg_mtx);
if (m_dDpiTile > 1)
mtx_Work.scale(m_dDpiX / m_dDpiTile, m_dDpiY / m_dDpiTile);
mtx_Work.invert();
span_alloc_type span_allocator;
interpolator_type_linear interpolator(mtx_Work);
agg::rendering_buffer PatRendBuff;
PatRendBuff.attach(pPattern, HATCH_TX_SIZE, HATCH_TX_SIZE, HATCH_TX_SIZE << 2);
typedef agg::pixfmt_bgra32 pixfmt;
//image_accessor_wrap
typedef agg::wrap_mode_repeat wrap_x_type;
typedef agg::wrap_mode_repeat wrap_y_type;
typedef agg::image_accessor_wrap<pixfmt, wrap_x_type, wrap_y_type> img_source_type;
typedef agg::span_image_filter_rgba_bilinear<img_source_type, interpolator_type_linear> span_gen_type;
typedef agg::renderer_scanline_aa<base_renderer_type, span_alloc_type, span_gen_type> renderer_type;
pixfmt img_pixf(PatRendBuff);
img_source_type img_src(img_pixf);
span_gen_type sg(img_src, interpolator);
renderer_type ri(m_frame_buffer.ren_base(), span_allocator, sg);
if (fabs(m_dGlobalAlpha - 1.0) < FLT_EPSILON)
{
render_scanlines(ri);
}
else
{
m_rasterizer.gamma_multi(m_dGlobalAlpha);
render_scanlines(ri);
m_rasterizer.gamma(1.0);
}
RELEASEARRAYOBJECTS(pPattern);
#endif
}
void CGraphics::DoFillPathTextureClampSz(const CMatrix &mImgMtx, const void *pImgBuff, DWORD dwImgWidth, DWORD dwImgHeight, int nImgStride)
{
span_alloc_type span_allocator; // Span Allocator
typedef agg::pixfmt_rgba32 pixfmt;
typedef agg::image_accessor_clip<pixfmt> img_source_type;
typedef agg::span_image_filter_rgba_bilinear<img_source_type, interpolator_type_linear> span_gen_type;
typedef agg::renderer_scanline_aa<base_renderer_type, span_alloc_type, span_gen_type> renderer_type;
agg::trans_affine mtx_Work(mImgMtx.m_internal->m_agg_mtx);
mtx_Work.multiply(m_oFullTransform.m_internal->m_agg_mtx);
mtx_Work.invert();
interpolator_type_linear interpolator(mtx_Work);
{
//agg::rendering_buffer PatRendBuff((BYTE *)pImgBuff, dwImgWidth, dwImgHeight, nImgStride);
agg::rendering_buffer PatRendBuff;
PatRendBuff.attach((BYTE*)pImgBuff, dwImgWidth, dwImgHeight, nImgStride);
pixfmt img_pixf(PatRendBuff);
img_source_type img_src(img_pixf, agg::rgba(0, 0, 0, 0));
span_gen_type sg(img_src, interpolator);
renderer_type ri(m_frame_buffer.ren_base(), span_allocator, sg);
//agg::render_scanlines(m_rasterizer.get_rasterizer(), m_rasterizer.get_scanline(), ri);
render_scanlines(ri);
}
}
void CGraphics::DoFillPathTextureClampSz2(const CMatrix &mImgMtx, const void *pImgBuff, DWORD dwImgWidth, DWORD dwImgHeight, int nImgStride, BYTE Alpha)
{
span_alloc_type span_allocator;
agg::trans_affine mtx_Work(mImgMtx.m_internal->m_agg_mtx);
mtx_Work.invert();
interpolator_type_linear interpolator(mtx_Work);
agg::rendering_buffer PatRendBuff;
PatRendBuff.attach((BYTE*)pImgBuff, dwImgWidth, dwImgHeight, nImgStride);
int nCurrentMode = 255;
if (!m_bSwapRGB)
{
typedef agg::pixfmt_bgra32 pixfmt;
typedef agg::image_accessor_clone<pixfmt> img_source_type;
pixfmt img_pixf(PatRendBuff);
img_source_type img_src(img_pixf);
switch (nCurrentMode)
{
case 0:
{
typedef agg::span_image_filter_rgba_nn<img_source_type, interpolator_type_linear> span_gen_type;
typedef agg::renderer_scanline_aa<base_renderer_type, span_alloc_type, span_gen_type> renderer_type;
span_gen_type sg(img_src, interpolator);
renderer_type ri(m_frame_buffer.ren_base(), span_allocator, sg);
render_scanlines_alpha(ri, Alpha);
break;
}
case 1:
{
typedef agg::span_image_filter_rgba_bilinear<img_source_type, interpolator_type_linear> span_gen_type;
typedef agg::renderer_scanline_aa<base_renderer_type, span_alloc_type, span_gen_type> renderer_type;
span_gen_type sg(img_src, interpolator);
renderer_type ri(m_frame_buffer.ren_base(), span_allocator, sg);
render_scanlines_alpha(ri, Alpha);
break;
}
case 2:
{
typedef agg::span_image_filter_rgba_2x2<img_source_type, interpolator_type_linear> span_gen_type;
typedef agg::renderer_scanline_aa<base_renderer_type, span_alloc_type, span_gen_type> renderer_type;
agg::image_filter_lut filter;
filter.calculate(agg::image_filter_bicubic(), false);
span_gen_type sg(img_src, interpolator, filter);
renderer_type ri(m_frame_buffer.ren_base(), span_allocator, sg);
render_scanlines_alpha(ri, Alpha);
break;
}
case 3:
{
typedef agg::span_image_filter_rgba_2x2<img_source_type, interpolator_type_linear> span_gen_type;
typedef agg::renderer_scanline_aa<base_renderer_type, span_alloc_type, span_gen_type> renderer_type;
agg::image_filter_lut filter;
filter.calculate(agg::image_filter_spline16(), false);
span_gen_type sg(img_src, interpolator, filter);
renderer_type ri(m_frame_buffer.ren_base(), span_allocator, sg);
render_scanlines_alpha(ri, Alpha);
break;
}
case 4:
{
typedef agg::span_image_filter_rgba_2x2<img_source_type, interpolator_type_linear> span_gen_type;
typedef agg::renderer_scanline_aa<base_renderer_type, span_alloc_type, span_gen_type> renderer_type;
agg::image_filter_lut filter;
filter.calculate(agg::image_filter_blackman256(), false);
span_gen_type sg(img_src, interpolator, filter);
renderer_type ri(m_frame_buffer.ren_base(), span_allocator, sg);
render_scanlines_alpha(ri, Alpha);
break;
}
case 255:
{
typedef agg::span_image_resample_rgba_affine_for_draw<img_source_type> span_gen_type;
typedef agg::renderer_scanline_aa<base_renderer_type, span_alloc_type, span_gen_type> renderer_type;
agg::image_filter_lut filter;
filter.calculate(agg::image_filter_bilinear(), false);
span_gen_type sg(img_src, interpolator, filter);
renderer_type ri(m_frame_buffer.ren_base(), span_allocator, sg);
render_scanlines_alpha(ri, Alpha);
break;
}
default:
break;
}
}
else
{
typedef agg::pixfmt_rgba32 pixfmt;
typedef agg::image_accessor_clone<pixfmt> img_source_type;
pixfmt img_pixf(PatRendBuff);
img_source_type img_src(img_pixf);
switch (nCurrentMode)
{
case 0:
{
typedef agg::span_image_filter_rgba_nn<img_source_type, interpolator_type_linear> span_gen_type;
typedef agg::renderer_scanline_aa<base_renderer_type, span_alloc_type, span_gen_type> renderer_type;
span_gen_type sg(img_src, interpolator);
renderer_type ri(m_frame_buffer.ren_base(), span_allocator, sg);
render_scanlines_alpha(ri, Alpha);
break;
}
case 1:
{
typedef agg::span_image_filter_rgba_bilinear<img_source_type, interpolator_type_linear> span_gen_type;
typedef agg::renderer_scanline_aa<base_renderer_type, span_alloc_type, span_gen_type> renderer_type;
span_gen_type sg(img_src, interpolator);
renderer_type ri(m_frame_buffer.ren_base(), span_allocator, sg);
render_scanlines_alpha(ri, Alpha);
break;
}
case 2:
{
typedef agg::span_image_filter_rgba_2x2<img_source_type, interpolator_type_linear> span_gen_type;
typedef agg::renderer_scanline_aa<base_renderer_type, span_alloc_type, span_gen_type> renderer_type;
agg::image_filter_lut filter;
filter.calculate(agg::image_filter_bicubic(), false);
span_gen_type sg(img_src, interpolator, filter);
renderer_type ri(m_frame_buffer.ren_base(), span_allocator, sg);
render_scanlines_alpha(ri, Alpha);
break;
}
case 3:
{
typedef agg::span_image_filter_rgba_2x2<img_source_type, interpolator_type_linear> span_gen_type;
typedef agg::renderer_scanline_aa<base_renderer_type, span_alloc_type, span_gen_type> renderer_type;
agg::image_filter_lut filter;
filter.calculate(agg::image_filter_spline16(), false);
span_gen_type sg(img_src, interpolator, filter);
renderer_type ri(m_frame_buffer.ren_base(), span_allocator, sg);
render_scanlines_alpha(ri, Alpha);
break;
}
case 4:
{
typedef agg::span_image_filter_rgba_2x2<img_source_type, interpolator_type_linear> span_gen_type;
typedef agg::renderer_scanline_aa<base_renderer_type, span_alloc_type, span_gen_type> renderer_type;
agg::image_filter_lut filter;
filter.calculate(agg::image_filter_blackman256(), false);
span_gen_type sg(img_src, interpolator, filter);
renderer_type ri(m_frame_buffer.ren_base(), span_allocator, sg);
render_scanlines_alpha(ri, Alpha);
break;
}
case 255:
{
typedef agg::span_image_resample_rgba_affine_for_draw<img_source_type> span_gen_type;
typedef agg::renderer_scanline_aa<base_renderer_type, span_alloc_type, span_gen_type> renderer_type;
agg::image_filter_lut filter;
filter.calculate(agg::image_filter_bilinear(), false);
span_gen_type sg(img_src, interpolator, filter);
renderer_type ri(m_frame_buffer.ren_base(), span_allocator, sg);
render_scanlines_alpha(ri, Alpha);
break;
}
default:
break;
}
}
}
template<class ColorSpacePix>
void CGraphics::DoFillPathTextureClampSz3(const CMatrix &matrix, const void *pImgBuff, DWORD dwImgWidth, DWORD dwImgHeight, int nImgStride, Aggplus::WrapMode wrapmode, BYTE Alpha)
{
agg::trans_affine mtx_Work( matrix.m_internal->m_agg_mtx );
agg::trans_affine coords = m_oCoordTransform.m_internal->m_agg_mtx;
coords.invert();
mtx_Work.premultiply(coords);
//mtx_Work.multiply(m_oFullTransform.m_agg_mtx);
mtx_Work.invert();
span_alloc_type span_allocator; // Span Allocator
interpolator_type_linear interpolator(mtx_Work);
//agg::rendering_buffer PatRendBuff((BYTE *)pImgBuff, dwImgWidth, dwImgHeight, nImgStride);
agg::rendering_buffer PatRendBuff;
PatRendBuff.attach((BYTE*)pImgBuff, dwImgWidth, dwImgHeight, nImgStride);
typedef ColorSpacePix pixfmt;
if(wrapmode == WrapModeTileFlipX)
{
//image_accessor_wrap
typedef agg::wrap_mode_reflect wrap_x_type;
typedef agg::wrap_mode_repeat wrap_y_type;
typedef agg::image_accessor_wrap<pixfmt, wrap_x_type, wrap_y_type> img_source_type;
typedef agg::span_image_filter_rgba_bilinear<img_source_type, interpolator_type_linear> span_gen_type;
typedef agg::renderer_scanline_aa<base_renderer_type, span_alloc_type, span_gen_type> renderer_type;
pixfmt img_pixf(PatRendBuff);
img_source_type img_src(img_pixf);
span_gen_type sg(img_src, interpolator);
renderer_type ri(m_frame_buffer.ren_base(), span_allocator, sg);
double dAlpha = m_dGlobalAlpha * Alpha / 255.0;
if (fabs(dAlpha - 1.0) < FLT_EPSILON)
{
render_scanlines(ri);
}
else
{
m_rasterizer.gamma_multi(dAlpha);
render_scanlines(ri);
m_rasterizer.gamma(1.0);
}
}
else if(wrapmode == WrapModeTileFlipY)
{
//image_accessor_wrap
typedef agg::wrap_mode_repeat wrap_x_type;
typedef agg::wrap_mode_reflect wrap_y_type;
typedef agg::image_accessor_wrap<pixfmt, wrap_x_type, wrap_y_type> img_source_type;
typedef agg::span_image_filter_rgba_bilinear<img_source_type, interpolator_type_linear> span_gen_type;
typedef agg::renderer_scanline_aa<base_renderer_type, span_alloc_type, span_gen_type> renderer_type;
pixfmt img_pixf(PatRendBuff);
img_source_type img_src(img_pixf);
span_gen_type sg(img_src, interpolator);
renderer_type ri(m_frame_buffer.ren_base(), span_allocator, sg);
double dAlpha = m_dGlobalAlpha * Alpha / 255.0;
if (fabs(dAlpha - 1.0) < FLT_EPSILON)
{
render_scanlines(ri);
}
else
{
m_rasterizer.gamma_multi(dAlpha);
render_scanlines(ri);
m_rasterizer.gamma(1.0);
}
}
else if(wrapmode == WrapModeTileFlipXY)
{
//image_accessor_wrap
typedef agg::wrap_mode_reflect wrap_x_type;
typedef agg::wrap_mode_reflect wrap_y_type;
typedef agg::image_accessor_wrap<pixfmt, wrap_x_type, wrap_y_type> img_source_type;
typedef agg::span_image_filter_rgba_bilinear<img_source_type, interpolator_type_linear> span_gen_type;
typedef agg::renderer_scanline_aa<base_renderer_type, span_alloc_type, span_gen_type> renderer_type;
pixfmt img_pixf(PatRendBuff);
img_source_type img_src(img_pixf);
span_gen_type sg(img_src, interpolator);
renderer_type ri(m_frame_buffer.ren_base(), span_allocator, sg);
double dAlpha = m_dGlobalAlpha * Alpha / 255.0;
if (fabs(dAlpha - 1.0) < FLT_EPSILON)
{
render_scanlines(ri);
}
else
{
m_rasterizer.gamma_multi(dAlpha);
render_scanlines(ri);
m_rasterizer.gamma(1.0);
}
}
else //Repeat
{
//image_accessor_wrap
typedef agg::wrap_mode_repeat wrap_x_type;
typedef agg::wrap_mode_repeat wrap_y_type;
typedef agg::image_accessor_wrap<pixfmt, wrap_x_type, wrap_y_type> img_source_type;
typedef agg::span_image_filter_rgba_bilinear<img_source_type, interpolator_type_linear> span_gen_type;
typedef agg::renderer_scanline_aa<base_renderer_type, span_alloc_type, span_gen_type> renderer_type;
pixfmt img_pixf(PatRendBuff);
img_source_type img_src(img_pixf);
span_gen_type sg(img_src, interpolator);
renderer_type ri(m_frame_buffer.ren_base(), span_allocator, sg);
double dAlpha = m_dGlobalAlpha * Alpha / 255.0;
if (fabs(dAlpha - 1.0) < FLT_EPSILON)
{
render_scanlines(ri);
}
else
{
m_rasterizer.gamma_multi(dAlpha);
render_scanlines(ri);
m_rasterizer.gamma(1.0);
}
}
}
void CGraphics::DoFillPath(const CBrush* Brush)
{
if (NULL == Brush)
return;
Aggplus::BrushType eBrushType = Brush->GetType();
switch (eBrushType)
{
case BrushTypeSolidColor:
{
CColor clr;
((CBrushSolid*)Brush)->GetColor(&clr);
DoFillPathSolid(clr);
break;
}
case BrushTypeHatchFill:
{
DoFillPathHatch((Aggplus::CBrushHatch*)Brush);
break;
}
case BrushTypeTextureFill:
{
CBrushTexture *ptxBrush = (CBrushTexture *)Brush;
LPVOID pImgBuff = ptxBrush->GetData();
if (pImgBuff)
{
DWORD dwImgWidth = ptxBrush->PatternGetWidth();
DWORD dwImgHeight = ptxBrush->PatternGetHeight();
int nImgStride = ptxBrush->PatternGetStride();
if(pImgBuff && dwImgWidth && dwImgHeight)
{
Aggplus::WrapMode wrapmode = ptxBrush->m_wrapMode;
Aggplus::CMatrix matrix = ptxBrush->m_mtx;
if(wrapmode == WrapModeClamp)
{
DoFillPathTextureClampSz2( matrix, pImgBuff, dwImgWidth, dwImgHeight, nImgStride, ptxBrush->Alpha);
}
else
{
if (!m_bSwapRGB)
{
DoFillPathTextureClampSz3<agg::pixfmt_bgra32>(matrix, pImgBuff, dwImgWidth, dwImgHeight, nImgStride, wrapmode, ptxBrush->Alpha);
}
else
{
DoFillPathTextureClampSz3<agg::pixfmt_rgba32>(matrix, pImgBuff, dwImgWidth, dwImgHeight, nImgStride, wrapmode, ptxBrush->Alpha);
}
}
}
}
break;
}
case BrushTypeLinearGradient:
{
DoFillPathGradient((CBrushLinearGradient*)Brush);
break;
}
case BrushTypePathGradient:
{
DoFillPathGradient2((CBrushLinearGradient*)Brush);
break;
}
case BrushTypeMyTestGradient:
case BrushTypeNewLinearGradient:
case BrushTypeConicalGradient:
case BrushTypeRadialGradient:
case BrushTypeDiamondGradient:
case BrushTypeTriagnleMeshGradient:
case BrushTypeCurveGradient:
case BrushTypeTensorCurveGradient:
{
DoFillPathGradientType((CBrushLinearGradient*)Brush);
break;
}
default:
break;
}
}
template<class Rasterizer>
agg::trans_affine* CGraphics::DoStrokePath(NSStructures::CPen* pPen, CGraphicsPath* pPath, Rasterizer* pRasterizer)
{
agg::line_join_e LineJoin = agg::round_join;
switch(pPen->LineJoin)
{
case LineJoinMiter : LineJoin = agg::miter_join_revert; break;
case LineJoinBevel : LineJoin = agg::bevel_join; break;
case LineJoinRound : LineJoin = agg::round_join; break;
case LineJoinMiterClipped : LineJoin = agg::miter_join_revert; break;
default: break;
}
agg::line_cap_e LineCap = agg::round_cap;
switch(pPen->LineStartCap)
{
case LineCapFlat : LineCap = agg::butt_cap; break;
case LineCapRound : LineCap = agg::round_cap; break;
case LineCapSquare : LineCap = agg::square_cap; break;
default: break;
}
double dWidth = pPen->Size;
if (!m_bIntegerGrid && m_bIs0PenWidthAs1px)
{
double dWidthMinSize, dSqrtDet = sqrt(abs(m_oFullTransform.m_internal->m_agg_mtx.determinant()));
if (0 == dWidth)
{
double dX = 0.72, dY = 0.72;
agg::trans_affine invert = ~m_oFullTransform.m_internal->m_agg_mtx;
invert.transform_2x2(&dX, &dY);
dWidth = std::min(abs(dX), abs(dY));
}
else if (0 != dSqrtDet && dWidth < (dWidthMinSize = 1.0 / dSqrtDet))
dWidth = dWidthMinSize;
}
double dblMiterLimit = pPen->MiterLimit;
agg::path_storage path_copy(pPath->m_internal->m_agg_ps);
bool bIsUseIdentity = m_bIntegerGrid;
if (!bIsUseIdentity)
{
agg::trans_affine* full_trans = &m_oFullTransform.m_internal->m_agg_mtx;
double dDet = full_trans->determinant();
if (fabs(dDet) < 0.0001)
{
path_copy.transform_all_paths(m_oFullTransform.m_internal->m_agg_mtx);
dWidth *= sqrt(fabs(dDet));
bIsUseIdentity = true;
}
}
typedef agg::conv_curve<agg::path_storage> conv_crv_type;
conv_crv_type c_c_path(path_copy);
c_c_path.approximation_scale(25.0);
c_c_path.approximation_method(agg::curve_inc);
DashStyle eStyle = (DashStyle)pPen->DashStyle;
if (DashStyleCustom == eStyle)
{
if (0 == pPen->Count || NULL == pPen->DashPattern)
{
eStyle = DashStyleSolid;
}
else
{
bool bFoundNormal = false;
for (int i = 0; i < pPen->Count; i++)
{
if (fabs(pPen->DashPattern[i]) > 0.0001)
{
bFoundNormal = true;
break;
}
}
if (!bFoundNormal)
eStyle = DashStyleSolid;
}
}
agg::trans_affine* pAffine = &m_oFullTransform.m_internal->m_agg_mtx;
if (bIsUseIdentity)
pAffine = new agg::trans_affine();
if (DashStyleSolid == eStyle)
{
typedef agg::conv_stroke<conv_crv_type> Path_Conv_StrokeN;
Path_Conv_StrokeN pgN(c_c_path);
//pgN.line_join(agg::miter_join_revert);
pgN.line_cap(LineCap);
pgN.line_join(LineJoin);
pgN.inner_join(agg::inner_round);
pgN.miter_limit(dblMiterLimit);
pgN.width(dWidth);
pgN.approximation_scale(25.0);
typedef agg::conv_transform<Path_Conv_StrokeN> transStroke;
transStroke trans(pgN, *pAffine);
pRasterizer->add_path(trans);
}
else
{
typedef agg::conv_dash<conv_crv_type> Path_Conv_Dash;
Path_Conv_Dash poly2_dash(c_c_path);
typedef agg::conv_stroke<Path_Conv_Dash> Path_Conv_StrokeD;
Path_Conv_StrokeD pgD(poly2_dash);
switch (eStyle)
{
case DashStyleDash:
poly2_dash.add_dash(3.00*dWidth, dWidth);
break;
case DashStyleDot:
poly2_dash.add_dash(dWidth, dWidth);
break;
case DashStyleDashDot:
poly2_dash.add_dash(3.00*dWidth, dWidth);
poly2_dash.add_dash(dWidth, dWidth);
break;
case DashStyleDashDotDot:
poly2_dash.add_dash(3.00*dWidth, dWidth);
poly2_dash.add_dash(dWidth, dWidth);
poly2_dash.add_dash(dWidth, dWidth);
break;
default:
case DashStyleCustom:
{
double offset = pPen->DashOffset;
double* params = pPen->DashPattern;
LONG lCount = pPen->Count;
LONG lCount2 = lCount / 2;
double dKoef = 1.0;
for (LONG i = 0; i < lCount2; ++i)
{
if (0 == i)
{
poly2_dash.add_dash((params[i * 2]) * dKoef, params[i * 2 + 1] * dKoef);
}
else
{
poly2_dash.add_dash(params[i * 2] * dKoef, params[i * 2 + 1] * dKoef);
}
}
if (1 == (lCount % 2))
{
poly2_dash.add_dash(params[lCount - 1] * dKoef, 0);
}
poly2_dash.dash_start(offset * dKoef);
break;
}
}
double dWidthMinSize = 1.0 / sqrt(abs(m_oCoordTransform.m_internal->m_agg_mtx.determinant()));
if ((0 == dWidth && !m_bIntegerGrid) || dWidth < dWidthMinSize)
dWidth = dWidthMinSize;
pgD.line_cap(LineCap);
pgD.line_join(LineJoin);
pgD.miter_limit(dblMiterLimit);
pgD.width(dWidth);
agg::conv_transform<Path_Conv_StrokeD> trans(pgD, *pAffine);
pRasterizer->add_path(trans);
}
return bIsUseIdentity ? pAffine : NULL;
}
// text methods
int CGraphics::FillGlyph2(int nX, int nY, TGlyph* pGlyph, Aggplus::CBrush* pBrush)
{
int lWidth = pGlyph->oBitmap.nWidth;
int lHeight = pGlyph->oBitmap.nHeight;
BYTE* pData = pGlyph->oBitmap.pData;
int nFrameW = (int)m_frame_buffer.width();
int nFrameH = (int)m_frame_buffer.height();
if (NULL == pData)
return 0;
if (NULL == pData || (nX + lWidth < 0) || (nX >= nFrameW) || (nY + lHeight < 0))
return 0;
if (!m_oClip.IsClip() && (0 <= nX) && (0 <= nY) && ((nX + lWidth) < nFrameW) && ((nY + lHeight) < nFrameH))
{
return FillGlyphSimple(nX, nY, lWidth, lHeight, pData, pBrush);
}
typedef agg::scanline_u8_am<agg::alpha_mask_gray8> scanline_type;
agg::scanline_storage_aa8 storage;
//PrepareScanlineStorage(&storage, nX, nY, pGlyph);
for (int j = 0; j < lHeight; ++j)
{
agg::scanline_p8 sl;
sl.reset(nX, nX + lWidth);
sl.add_cells(nX, lWidth, pData + j * lWidth);
sl.finalize(nY + j);
storage.render(sl);
}
if (pBrush->GetType() == Aggplus::BrushTypeSolidColor)
{
CColor clr;
((CBrushSolid*)pBrush)->GetColor(&clr);
typedef agg::renderer_scanline_aa_solid<base_renderer_type> solid_renderer_type;
solid_renderer_type ren_fine(m_frame_buffer.ren_base());
ren_fine.color(clr.GetAggColor());
//agg::render_scanlines(storage, m_rasterizer.get_scanline(), ren_fine);
render_scanlines_2(storage, ren_fine);
}
return 0;
}
int CGraphics::FillGlyphSimple(int nX, int nY, LONG lWidth, LONG lHeight, BYTE* pData, Aggplus::CBrush* pBrush)
{
CColor clr;
((CBrushSolid*)pBrush)->GetColor(&clr);
typedef agg::renderer_scanline_aa_solid<base_renderer_type> solid_renderer_type;
solid_renderer_type ren_fine(m_frame_buffer.ren_base());
ren_fine.color(clr.GetAggColor());
if (m_nTextRenderMode == FT_RENDER_MODE_LCD)
{
ren_fine.render_subpix(lWidth / 3, lHeight, pData, nX, nY);
}
else
{
ren_fine.render(lWidth, lHeight, pData, nX, nY);
}
return 0;
}
void CGraphics::PrepareScanlineStorage(agg::scanline_storage_aa8* storage, int x, int y, TGlyphBitmap *pGlyph)
{
//agg::scanline_p8 sl;
int width = pGlyph->nWidth;
m_rasterizer.get_scanline().reset(x, x + width);
for (int j = 0; j < pGlyph->nHeight; ++j)
{
m_rasterizer.get_scanline().add_cells(x + j * width, width, pGlyph->pData + j * width);
}
m_rasterizer.get_scanline().finalize(y);
storage->render(m_rasterizer.get_scanline());
}
void CGraphics::UpdateUnits()
{
// здесь - пересчет координат
m_oCoordTransform.Reset();
double dScaleX = 1.0;
double dScaleY = 1.0;
switch (m_ePageUnits)
{
case UnitPoint:
{
dScaleX = m_dDpiX / c_ag_Inch_to_Point;
dScaleY = m_dDpiY / c_ag_Inch_to_Point;
break;
}
case UnitMillimeter:
{
dScaleX = m_dDpiX / c_ag_Inch_to_MM;
dScaleY = m_dDpiY / c_ag_Inch_to_MM;
break;
}
case UnitInch:
{
dScaleX = m_dDpiX;
dScaleY = m_dDpiY;
break;
}
default:
break;
};
m_oCoordTransform.Scale(dScaleX, dScaleY, MatrixOrderAppend);
CalculateFullTransform();
}
// Testing
void CGraphics::DoFillPathGradientType(CBrushLinearGradient *pBrush)
{
CDoubleRect& oBounds = pBrush->GetBounds();
CMatrix oMatrix;
agg::rect_d rect;
if (oBounds.GetWidth() > FLT_EPSILON || oBounds.GetHeight() > FLT_EPSILON)
{
rect.x1 = oBounds.left;
rect.y1 = oBounds.top;
rect.x2 = oBounds.right;
rect.y2 = oBounds.bottom;
oMatrix = m_oFullTransform;
oMatrix.Invert();
}
else
{
int x = m_rasterizer.get_rasterizer().min_x();
int y = m_rasterizer.get_rasterizer().min_y();
int r = m_rasterizer.get_rasterizer().max_x();
int b = m_rasterizer.get_rasterizer().max_y();
if (r < x || b < y)
return;
rect.x1 = x;
rect.x2 = r;
rect.y1 = y;
rect.y2 = b;
}
ScaleGranientInfo(pBrush->GetType(), pBrush->m_oGradientInfo);
typedef agg::gradient_base<agg::rgba8> gradient_span_gen;
gradient_span_gen span_gen;
span_gen.SetDirection(rect, oMatrix.m_internal->m_agg_mtx, m_bSwapRGB);
span_gen.SetGradientInfo(pBrush->m_oGradientInfo, pBrush->GetType());
agg::rgba8* pSubColors = NULL;
float* pSubBlends = NULL;
int nCountSubColors = pBrush->GetInterpolationColorsCount();
if( nCountSubColors > 0 )
{
pSubColors = new agg::rgba8[nCountSubColors];
pSubBlends = new float[nCountSubColors];
if( pSubColors && pSubBlends )
{
for( int i = 0; i < nCountSubColors; i++ )
{
CColor c;
pBrush->GetSubColor( i, &c, &pSubBlends[i] );
pSubColors[i] = agg::rgba8(c.GetB(), c.GetG(), c.GetR(), c.GetA());
}
span_gen.SetSubColors( pSubColors, pSubBlends, nCountSubColors );
}
}
typedef agg::span_allocator<gradient_span_gen::color_type> gradient_span_alloc;
gradient_span_alloc span_alloc;
typedef agg::renderer_scanline_aa<base_renderer_type, gradient_span_alloc, gradient_span_gen> renderer_gradient_type;
renderer_gradient_type ren_gradient( m_frame_buffer.ren_base(), span_alloc, span_gen );
if (fabs(m_dGlobalAlpha - 1.0) < FLT_EPSILON)
{
render_scanlines(ren_gradient);
}
else
{
m_rasterizer.gamma_multi(m_dGlobalAlpha);
render_scanlines(ren_gradient);
m_rasterizer.gamma(1.0);
}
if( pSubColors ) delete [] pSubColors;
if( pSubBlends ) delete [] pSubBlends;
}
void CGraphics::ScaleGranientInfo(long type, NSStructures::GradientInfo &ginfo)
{
if (type == BrushTypeMyTestGradient)
{
std::vector<float> new_map(6);
float M[6];
std::vector<float> G = ginfo.shading.mapping;
m_oFullTransform.GetElements(M);
new_map[0] = M[0] * G[0] + M[2] * G[1];
new_map[1] = M[1] * G[0] + M[3] * G[1];
new_map[2] = M[0] * G[2] + M[2] * G[3];
new_map[3] = M[1] * G[2] + M[3] * G[3];
new_map[4] = M[0] * G[4] + M[2] * G[5] + M[4];
new_map[5] = M[1] * G[4] + M[3] * G[5] + M[5];
ginfo.shading.mapping = new_map;
float D = new_map[0] * new_map[3] - new_map[1] * new_map[2];
ginfo.shading.inv_map[0] = new_map[3] / D;
ginfo.shading.inv_map[1] = -new_map[1] / D;
ginfo.shading.inv_map[2] = -new_map[2] / D;
ginfo.shading.inv_map[3] = new_map[0] / D;
ginfo.shading.inv_map[4] = -new_map[4];
ginfo.shading.inv_map[5] = -new_map[5];
return;
}
if (type == BrushTypeNewLinearGradient)
{
ScaleCoords(ginfo.shading.point1.x, ginfo.shading.point1.y);
ScaleCoords(ginfo.shading.point2.x, ginfo.shading.point2.y);
return;
}
if (type == BrushTypeRadialGradient)
{
ginfo.r0 = ginfo.r0 * sqrt(fabs(m_oFullTransform.Determinant()));
ginfo.r1 = ginfo.r1 * sqrt(fabs(m_oFullTransform.Determinant()));
ScaleCoords(ginfo.p0.x, ginfo.p0.y);
ScaleCoords(ginfo.p1.x, ginfo.p1.y);
return;
}
if (type == BrushTypeTriagnleMeshGradient)
{
for (int i = 0; i < 3; i++)
{
ScaleCoords(ginfo.shading.triangle[i].x, ginfo.shading.triangle[i].y);
}
return;
}
if (type == BrushTypeCurveGradient || type == BrushTypeTensorCurveGradient)
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
ScaleCoords(ginfo.shading.patch[i][j].x, ginfo.shading.patch[i][j].y);
}
}
return;
}
}
void CGraphics::ScaleCoords(float &x, float &y)
{
double newx = x;
double newy = y;
m_oFullTransform.TransformPoint(newx, newy);
x = newx;
y = newy;
return;
}
}