1272 lines
38 KiB
C++
1272 lines
38 KiB
C++
#include "Direct2DRender.h"
|
||
#include <Shlwapi.h>
|
||
|
||
#include <GdiPlus.h>
|
||
#pragma comment(lib, "gdiplus.lib")
|
||
|
||
#if USED_DIRECT2D
|
||
#define _NOREND_IMAGE_
|
||
//#define _NOREND_IMAGE_ return;
|
||
#pragma comment(lib,"dwrite.lib")
|
||
#pragma comment(lib,"d2d1.lib")
|
||
#pragma comment(lib,"Windowscodecs.lib")
|
||
#undef min
|
||
#undef max
|
||
namespace ezui {
|
||
ULONG_PTR g_GdiplusToken = NULL;
|
||
namespace D2D {
|
||
ID2D1Factory* g_Direct2dFactory = NULL;
|
||
IDWriteFactory* g_WriteFactory = NULL;
|
||
IWICImagingFactory* g_ImageFactory = NULL;
|
||
}
|
||
#define __COLOR_SCALE 0.003921569f
|
||
#define __To_D2D_COLOR_F(color) D2D_COLOR_F{FLOAT(color.GetR() * __COLOR_SCALE), FLOAT(color.GetG() * __COLOR_SCALE), FLOAT(color.GetB() * __COLOR_SCALE),FLOAT(color.GetA() * __COLOR_SCALE)}
|
||
#define __To_D2D_RectF(rect) D2D_RECT_F{(FLOAT)rect.X,(FLOAT)rect.Y,(FLOAT)rect.GetRight(),(FLOAT)rect.GetBottom() }
|
||
#define __To_D2D_PointF(pt) D2D1_POINT_2F{(FLOAT)pt.X,(FLOAT)pt.Y}
|
||
|
||
template<typename Interface>
|
||
inline void SafeRelease(
|
||
Interface** ppInterfaceToRelease)
|
||
{
|
||
if (*ppInterfaceToRelease != NULL)
|
||
{
|
||
(*ppInterfaceToRelease)->Release();
|
||
(*ppInterfaceToRelease) = NULL;
|
||
}
|
||
}
|
||
|
||
//TextFormat
|
||
Font::Font(const std::wstring& fontFamily, float fontSize) {
|
||
ASSERT(!(fontSize == 0));
|
||
this->m_fontFamily = fontFamily;
|
||
this->m_fontSize = fontSize;
|
||
D2D::g_WriteFactory->CreateTextFormat(fontFamily.c_str(), NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, m_fontSize, L"", &m_value);
|
||
}
|
||
Font::~Font() {
|
||
if (m_value && !m_ref) {
|
||
SafeRelease(&m_value);
|
||
}
|
||
}
|
||
float Font::GetFontSize()const {
|
||
return m_fontSize;
|
||
}
|
||
const std::wstring& Font::GetFontFamily()const {
|
||
return m_fontFamily;
|
||
}
|
||
void Font::Copy(const Font& _copy) {
|
||
((Font&)(_copy)).m_ref = true;
|
||
this->m_value = _copy.Get();
|
||
this->m_fontFamily = _copy.GetFontFamily();
|
||
this->m_fontSize = _copy.GetFontSize();
|
||
}
|
||
IDWriteTextFormat* Font::Get() const {
|
||
return m_value;
|
||
}
|
||
Font::Font(const Font& rightValue) {
|
||
Copy(rightValue);
|
||
}
|
||
bool Font::operator==(const Font& _right) {
|
||
if (_right.GetFontFamily() == this->GetFontFamily() && (std::fabs(_right.GetFontSize() - this->GetFontSize()) < EZUI_FLOAT_EPSILON)) {
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
void TextLayout::GetMetrics()
|
||
{
|
||
if (m_textLayout) {
|
||
m_textLayout->GetMetrics(&m_textMetrics);
|
||
}
|
||
}
|
||
//TextLayout
|
||
TextLayout::TextLayout(const std::wstring& text, const Font& font, const SizeF& maxSize, TextAlign textAlign) {
|
||
this->m_unicodeSize = text.size();
|
||
this->m_fontSize = font.GetFontSize();
|
||
this->m_fontFamily = font.GetFontFamily();
|
||
D2D::g_WriteFactory->CreateTextLayout(text.c_str(), text.size(), font.Get(), maxSize.Width, maxSize.Height, &m_textLayout);
|
||
if (m_textLayout == NULL)return;
|
||
SetTextAlign(textAlign);
|
||
}
|
||
IDWriteTextLayout* TextLayout::Get() const {
|
||
return m_textLayout;
|
||
}
|
||
Point TextLayout::HitTestPoint(const Point& pt, int* _textPos, BOOL* _isTrailingHit, int* fontHeight) {
|
||
int& textPos = *_textPos;
|
||
BOOL& isTrailingHit = *_isTrailingHit;
|
||
DWRITE_HIT_TEST_METRICS hitTestMetrics;
|
||
BOOL isInside;
|
||
{
|
||
FLOAT x = (FLOAT)pt.X, y = (FLOAT)pt.Y;
|
||
m_textLayout->HitTestPoint(
|
||
(FLOAT)x,
|
||
(FLOAT)y,
|
||
&isTrailingHit,
|
||
&isInside,
|
||
&hitTestMetrics
|
||
);
|
||
}
|
||
int posX = (int)(hitTestMetrics.left + 0.5);
|
||
if (isTrailingHit) {//判断前侧还是尾侧
|
||
posX += (int)(hitTestMetrics.width + 0.5);
|
||
}
|
||
*fontHeight = (int)(hitTestMetrics.height + 0.5);
|
||
textPos = hitTestMetrics.textPosition;
|
||
return Point{ posX,(int)(hitTestMetrics.top + 0.5) };//返回光标所在的位置
|
||
}
|
||
|
||
void TextLayout::HitTestPoint(const Point& pt, HitTestMetrics* outHitTestMetrics) {
|
||
BOOL isTrailingHit;
|
||
DWRITE_HIT_TEST_METRICS hitTestMetrics;
|
||
BOOL isInside;
|
||
{
|
||
FLOAT x = (FLOAT)pt.X, y = (FLOAT)pt.Y;
|
||
m_textLayout->HitTestPoint(
|
||
(FLOAT)x,
|
||
(FLOAT)y,
|
||
&isTrailingHit,
|
||
&isInside,
|
||
&hitTestMetrics
|
||
);
|
||
}
|
||
outHitTestMetrics->Length = hitTestMetrics.length;
|
||
outHitTestMetrics->TextPos = hitTestMetrics.textPosition;
|
||
outHitTestMetrics->IsTrailingHit = isTrailingHit;
|
||
outHitTestMetrics->FontBox.X = hitTestMetrics.left;
|
||
outHitTestMetrics->FontBox.Y = hitTestMetrics.top;
|
||
outHitTestMetrics->FontBox.Width = hitTestMetrics.width;
|
||
outHitTestMetrics->FontBox.Height = hitTestMetrics.height;
|
||
}
|
||
|
||
Point TextLayout::HitTestTextPosition(int textPos, BOOL isTrailingHit) {
|
||
if (m_textLayout == NULL)return Point{ 0,0 };
|
||
DWRITE_HIT_TEST_METRICS hitTestMetrics;
|
||
FLOAT X, Y;
|
||
m_textLayout->HitTestTextPosition(textPos, isTrailingHit, &X, &Y, &hitTestMetrics);
|
||
return Point((int)(X + 0.5), (int)(Y + 0.5));
|
||
}
|
||
const std::wstring& TextLayout::GetFontFamily()
|
||
{
|
||
return this->m_fontFamily;
|
||
}
|
||
Size TextLayout::GetFontBox() {
|
||
this->GetMetrics();
|
||
FLOAT width = m_textMetrics.widthIncludingTrailingWhitespace;
|
||
FLOAT height = m_textMetrics.height;
|
||
return Size{ (int)(width + 1) ,(int)(height + 1) };//加1是为了向上取整
|
||
}
|
||
float TextLayout::GetFontSize()
|
||
{
|
||
return this->m_fontSize;
|
||
}
|
||
int TextLayout::Width() {
|
||
this->GetMetrics();
|
||
FLOAT width = m_textMetrics.widthIncludingTrailingWhitespace;
|
||
return (int)(width + 1);
|
||
}
|
||
int TextLayout::Height() {
|
||
this->GetMetrics();
|
||
FLOAT width = m_textMetrics.height;
|
||
return (width + 1);
|
||
}
|
||
int TextLayout::GetFontHeight() {
|
||
this->GetMetrics();
|
||
FLOAT height = m_textMetrics.height;
|
||
return ((height / m_textMetrics.lineCount) + 0.5);
|
||
}
|
||
int TextLayout::GetLineCount() {
|
||
this->GetMetrics();
|
||
return m_textMetrics.lineCount;
|
||
}
|
||
|
||
#undef min
|
||
#undef max
|
||
const std::vector<RectF>& TextLayout::GetLineRects() {
|
||
//如果unicode个数为0 且获取过m_lineRects 则直接返回不执行获取操作
|
||
if (!m_textLayout || m_unicodeSize == 0 || !m_lineRects.empty()) {
|
||
return m_lineRects;
|
||
}
|
||
UINT lineCount = GetLineCount();
|
||
//获取每行 metrics
|
||
std::vector<DWRITE_LINE_METRICS> lineMetrics(lineCount);
|
||
auto hr = m_textLayout->GetLineMetrics(lineMetrics.data(), lineCount, &lineCount);
|
||
if (FAILED(hr)) {
|
||
return m_lineRects;
|
||
}
|
||
//遍历每一行,计算对应矩形
|
||
UINT32 textPos = 0;
|
||
for (UINT32 i = 0; i < lineCount; i++) {
|
||
auto& lm = lineMetrics[i];
|
||
if (lm.length == 0) { // 空行
|
||
textPos += lm.length;
|
||
continue;
|
||
}
|
||
//给一个足够大的 buffer,存放 hit test 的矩形
|
||
std::vector<DWRITE_HIT_TEST_METRICS> metrics(lm.length);
|
||
UINT32 actualCount = 0;
|
||
|
||
hr = m_textLayout->HitTestTextRange(
|
||
textPos, lm.length, // 这一行的字符范围
|
||
0.0f, 0.0f, // offsetX, offsetY
|
||
metrics.data(), (UINT32)metrics.size(),
|
||
&actualCount
|
||
);
|
||
|
||
if (SUCCEEDED(hr) && actualCount > 0) {
|
||
float minX = metrics[0].left;
|
||
float maxX = metrics[0].left + metrics[0].width;
|
||
float top = metrics[0].top;
|
||
float bottom = top + metrics[0].height;
|
||
|
||
for (UINT32 j = 1; j < actualCount; j++) {
|
||
auto& m = metrics[j];
|
||
minX = std::min(minX, m.left);
|
||
maxX = std::max(maxX, m.left + m.width);
|
||
top = std::min(top, m.top);
|
||
bottom = std::max(bottom, m.top + m.height);
|
||
}
|
||
m_lineRects.push_back(RectF(minX, top, maxX - minX, bottom - top));
|
||
}
|
||
textPos += lm.length; //下一行的起始字符
|
||
}
|
||
return m_lineRects;
|
||
}
|
||
|
||
void TextLayout::SetTextAlign(TextAlign textAlign) {
|
||
#define __Top DWRITE_PARAGRAPH_ALIGNMENT_NEAR
|
||
#define __Bottom DWRITE_PARAGRAPH_ALIGNMENT_FAR
|
||
#define __Left DWRITE_TEXT_ALIGNMENT_LEADING
|
||
#define __Right DWRITE_TEXT_ALIGNMENT_TRAILING
|
||
#define __Middle DWRITE_PARAGRAPH_ALIGNMENT_CENTER
|
||
#define __Center DWRITE_TEXT_ALIGNMENT_CENTER
|
||
if (m_textLayout == NULL)return;
|
||
//垂直对其方式
|
||
if (((int)textAlign & (int)VAlign::Top) == (int)VAlign::Top) {
|
||
m_textLayout->SetParagraphAlignment(__Top);
|
||
}
|
||
if (((int)textAlign & (int)VAlign::Mid) == (int)VAlign::Mid) {
|
||
m_textLayout->SetParagraphAlignment(__Middle);
|
||
}
|
||
if (((int)textAlign & (int)VAlign::Bottom) == (int)VAlign::Bottom) {
|
||
m_textLayout->SetParagraphAlignment(__Bottom);
|
||
}
|
||
//水平对其方式
|
||
if (((int)textAlign & (int)HAlign::Left) == (int)HAlign::Left) {
|
||
m_textLayout->SetTextAlignment(__Left);
|
||
}
|
||
if (((int)textAlign & (int)HAlign::Center) == (int)HAlign::Center) {
|
||
m_textLayout->SetTextAlignment(__Center);
|
||
}
|
||
if (((int)textAlign & (int)HAlign::Right) == (int)HAlign::Right) {
|
||
m_textLayout->SetTextAlignment(__Right);
|
||
}
|
||
#undef __Top
|
||
#undef __Bottom
|
||
#undef __Left
|
||
#undef __Right
|
||
#undef __Middle
|
||
#undef __Center
|
||
}
|
||
void TextLayout::SetUnderline(int pos, int count)
|
||
{
|
||
if (count > 0) {
|
||
m_textLayout->SetUnderline(TRUE, { (UINT32)pos,(UINT32)count });
|
||
}
|
||
}
|
||
TextLayout::~TextLayout() {
|
||
if (m_textLayout) {
|
||
SafeRelease(&m_textLayout);
|
||
}
|
||
}
|
||
//DXImage
|
||
void DXImage::DecodeOfRender(ID2D1RenderTarget* render) {
|
||
HRESULT hr = 0;
|
||
if (m_d2dBitmap != NULL) {
|
||
if (m_d2dBitmap) {
|
||
SafeRelease(&m_d2dBitmap);
|
||
}
|
||
}
|
||
if (m_fmtcovter) {
|
||
hr = render->CreateBitmapFromWicBitmap(m_fmtcovter, 0, &m_d2dBitmap);
|
||
}
|
||
if (m_bitMap) {
|
||
hr = render->CreateBitmapFromWicBitmap(m_bitMap, &m_d2dBitmap);
|
||
}
|
||
}
|
||
int DXImage::Width() {
|
||
return m_width;
|
||
}
|
||
int DXImage::Height() {
|
||
return m_height;
|
||
}
|
||
void DXImage::CreateFormStream(IStream* istram) {
|
||
HRESULT imgCreate = S_OK;
|
||
if (D2D::g_ImageFactory) {
|
||
imgCreate = D2D::g_ImageFactory->CreateDecoderFromStream(istram, NULL, WICDecodeMetadataCacheOnDemand, &m_bitmapdecoder);//
|
||
}
|
||
if (m_bitmapdecoder) {
|
||
D2D::g_ImageFactory->CreateFormatConverter(&m_fmtcovter);
|
||
m_bitmapdecoder->GetFrame(0, &m_pframe);
|
||
m_fmtcovter->Initialize(m_pframe, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, NULL, 0.0f, WICBitmapPaletteTypeCustom);
|
||
UINT width, height;
|
||
m_pframe->GetSize(&width, &height);
|
||
this->m_width = width;
|
||
this->m_height = height;
|
||
Init();
|
||
}
|
||
}
|
||
void DXImage::CreateFromFile(const std::wstring& filew)
|
||
{
|
||
HRESULT ret = S_OK;
|
||
if (D2D::g_ImageFactory) {
|
||
ret = D2D::g_ImageFactory->CreateDecoderFromFilename(filew.c_str(), NULL, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &m_bitmapdecoder);//
|
||
}
|
||
if (m_bitmapdecoder) {
|
||
ret = D2D::g_ImageFactory->CreateFormatConverter(&m_fmtcovter);
|
||
ret = m_bitmapdecoder->GetFrame(0, &m_pframe);
|
||
ret = m_fmtcovter->Initialize(m_pframe, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, NULL, 0.0f, WICBitmapPaletteTypeCustom);
|
||
UINT width, height;
|
||
ret = m_pframe->GetSize(&width, &height);
|
||
this->m_width = width;
|
||
this->m_height = height;
|
||
Init();
|
||
}
|
||
}
|
||
|
||
// 获取 GIF 帧位置
|
||
WICRect GetFrameRect(IWICMetadataQueryReader* metaReader) {
|
||
WICRect rect = { 0,0,0,0 };
|
||
PROPVARIANT pv;
|
||
PropVariantInit(&pv);
|
||
|
||
if (SUCCEEDED(metaReader->GetMetadataByName(L"/imgdesc/Left", &pv))) {
|
||
rect.X = pv.uiVal;
|
||
}
|
||
PropVariantClear(&pv);
|
||
|
||
if (SUCCEEDED(metaReader->GetMetadataByName(L"/imgdesc/Top", &pv)))
|
||
{
|
||
rect.Y = pv.uiVal;
|
||
}
|
||
PropVariantClear(&pv);
|
||
|
||
if (SUCCEEDED(metaReader->GetMetadataByName(L"/imgdesc/Width", &pv)))
|
||
{
|
||
rect.Width = pv.uiVal;
|
||
}
|
||
PropVariantClear(&pv);
|
||
|
||
if (SUCCEEDED(metaReader->GetMetadataByName(L"/imgdesc/Height", &pv)))
|
||
{
|
||
rect.Height = pv.uiVal;
|
||
}
|
||
PropVariantClear(&pv);
|
||
|
||
return rect;
|
||
}
|
||
|
||
// 拷贝整个位图
|
||
void CopyBitmap(IWICBitmap* src, IWICBitmap* dst) {
|
||
if (!src || !dst) return;
|
||
|
||
UINT w = 0, h = 0;
|
||
src->GetSize(&w, &h);
|
||
WICRect rect = { 0,0,(INT)w,(INT)h };
|
||
|
||
IWICBitmapLock* lockSrc = NULL;
|
||
IWICBitmapLock* lockDst = NULL;
|
||
|
||
if (SUCCEEDED(src->Lock(&rect, WICBitmapLockRead, &lockSrc)) &&
|
||
SUCCEEDED(dst->Lock(&rect, WICBitmapLockWrite, &lockDst)))
|
||
{
|
||
UINT cbBufferSrc = 0, cbBufferDst = 0;
|
||
BYTE* pSrc = NULL;
|
||
BYTE* pDst = NULL;
|
||
lockSrc->GetDataPointer(&cbBufferSrc, &pSrc);
|
||
lockDst->GetDataPointer(&cbBufferDst, &pDst);
|
||
|
||
memcpy(pDst, pSrc, cbBufferSrc);
|
||
}
|
||
|
||
if (lockSrc) SafeRelease(&lockSrc);
|
||
if (lockDst) SafeRelease(&lockDst);
|
||
}
|
||
|
||
// 清除矩形区域(透明)
|
||
void ClearRegion(IWICBitmap* bmp, const WICRect& rect) {
|
||
if (!bmp) return;
|
||
|
||
IWICBitmapLock* lock = NULL;
|
||
if (SUCCEEDED(bmp->Lock(&rect, WICBitmapLockWrite, &lock)))
|
||
{
|
||
UINT cbBuffer = 0;
|
||
BYTE* pData = NULL;
|
||
lock->GetDataPointer(&cbBuffer, &pData);
|
||
memset(pData, 0, cbBuffer); // 全部置 0(透明)
|
||
}
|
||
SafeRelease(&lock);
|
||
}
|
||
void CopyFrameToCanvas(IWICBitmapSource* frame, IWICBitmap* canvas, UINT CanvasWidth, UINT CanvasHeight, const WICRect& frameRect)
|
||
{
|
||
if (!frame || !canvas) return;
|
||
|
||
// 锁定整个画布
|
||
WICRect fullRect{ 0, 0, (INT)CanvasWidth, (INT)CanvasHeight };
|
||
IWICBitmapLock* lock = NULL;
|
||
if (FAILED(canvas->Lock(&fullRect, WICBitmapLockWrite, &lock))) return;
|
||
|
||
UINT cbBuffer = 0;
|
||
BYTE* pDst = NULL;
|
||
lock->GetDataPointer(&cbBuffer, &pDst);
|
||
|
||
UINT canvasStride = CanvasWidth * 4;
|
||
UINT frameStride = frameRect.Width * 4;
|
||
UINT frameBufferSize = frameStride * frameRect.Height;
|
||
BYTE* tempBuffer = new BYTE[frameBufferSize];
|
||
|
||
WICRect copyRect = { 0, 0, frameRect.Width, frameRect.Height };
|
||
HRESULT hr = frame->CopyPixels(©Rect, frameStride, frameBufferSize, tempBuffer);
|
||
if (FAILED(hr)) {
|
||
delete[] tempBuffer;
|
||
SafeRelease(&lock);
|
||
return;
|
||
}
|
||
|
||
// 复制像素到画布的对应偏移位置
|
||
for (UINT y = 0; y < frameRect.Height; y++) {
|
||
BYTE* srcLine = tempBuffer + y * frameStride;
|
||
BYTE* dstLine = pDst + (frameRect.Y + y) * canvasStride + frameRect.X * 4;
|
||
|
||
for (UINT x = 0; x < frameRect.Width; x++) {
|
||
BYTE* srcPx = srcLine + x * 4;
|
||
BYTE* dstPx = dstLine + x * 4;
|
||
|
||
BYTE srcA = srcPx[3];
|
||
if (srcA != 0) {
|
||
dstPx[0] = srcPx[0];
|
||
dstPx[1] = srcPx[1];
|
||
dstPx[2] = srcPx[2];
|
||
dstPx[3] = srcPx[3];
|
||
}
|
||
}
|
||
}
|
||
|
||
//释放
|
||
delete[] tempBuffer;
|
||
SafeRelease(&lock);
|
||
}
|
||
|
||
void DXImage::Init()
|
||
{
|
||
m_framePos = 0;
|
||
m_frames.clear();
|
||
|
||
if (!m_bitmapdecoder) return;
|
||
|
||
UINT fCount = 0;
|
||
m_bitmapdecoder->GetFrameCount(&fCount);
|
||
m_frameCount = fCount;
|
||
|
||
if (fCount <= 1) {
|
||
return;
|
||
}
|
||
if (m_fmtcovter) {
|
||
//如果是gif那就不需要m_fmtcovter 因为会把解析完毕的每一帧存储起来直接用
|
||
SafeRelease(&m_fmtcovter);
|
||
}
|
||
|
||
UINT width = Width();
|
||
UINT height = Height();
|
||
|
||
// 创建全尺寸画布
|
||
IWICBitmap* canvas = NULL;
|
||
D2D::g_ImageFactory->CreateBitmap(
|
||
width, height,
|
||
GUID_WICPixelFormat32bppPBGRA,
|
||
WICBitmapCacheOnLoad,
|
||
&canvas);
|
||
|
||
// 备份画布(用于 disposal=3)
|
||
IWICBitmap* prevCanvas = NULL;
|
||
D2D::g_ImageFactory->CreateBitmap(
|
||
width, height,
|
||
GUID_WICPixelFormat32bppPBGRA,
|
||
WICBitmapCacheOnLoad,
|
||
&prevCanvas);
|
||
|
||
for (UINT i = 0; i < fCount; i++)
|
||
{
|
||
IWICBitmapFrameDecode* srcFrame = NULL;
|
||
m_bitmapdecoder->GetFrame(i, &srcFrame);
|
||
|
||
// 元数据读取器
|
||
IWICMetadataQueryReader* metaReader = NULL;
|
||
srcFrame->GetMetadataQueryReader(&metaReader);
|
||
|
||
// 延时
|
||
UINT delayMs = 100;
|
||
PROPVARIANT pv;
|
||
PropVariantInit(&pv);
|
||
if (SUCCEEDED(metaReader->GetMetadataByName(L"/grctlext/Delay", &pv)))
|
||
{
|
||
delayMs = pv.uiVal * 10; // 单位 1/100 秒
|
||
}
|
||
PropVariantClear(&pv);
|
||
|
||
// Disposal
|
||
UINT disposal = 0;
|
||
if (SUCCEEDED(metaReader->GetMetadataByName(L"/grctlext/Disposal", &pv)))
|
||
{
|
||
disposal = pv.uiVal;
|
||
}
|
||
PropVariantClear(&pv);
|
||
|
||
// Disposal=3 保存备份
|
||
if (disposal == 3) {
|
||
CopyBitmap(canvas, prevCanvas);
|
||
}
|
||
|
||
// Disposal=2 清区域
|
||
if (disposal == 2 && i > 0)
|
||
{
|
||
WICRect rect = GetFrameRect(metaReader);
|
||
ClearRegion(canvas, rect);
|
||
}
|
||
else if (disposal == 3 && i > 0)
|
||
{
|
||
CopyBitmap(prevCanvas, canvas);
|
||
}
|
||
|
||
// 转换帧格式
|
||
IWICFormatConverter* converter = NULL;
|
||
D2D::g_ImageFactory->CreateFormatConverter(&converter);
|
||
converter->Initialize(srcFrame, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, NULL, 0.f, WICBitmapPaletteTypeCustom);
|
||
|
||
// 帧矩形
|
||
WICRect rect = GetFrameRect(metaReader);
|
||
|
||
// 绘制到 canvas
|
||
CopyFrameToCanvas(converter, canvas, width, height, rect);
|
||
|
||
// 存一份当前画布的完整副本
|
||
IWICBitmap* frameCopy = NULL;
|
||
D2D::g_ImageFactory->CreateBitmapFromSource(canvas, WICBitmapCacheOnLoad, &frameCopy);
|
||
GifFrame gf = { frameCopy, delayMs };
|
||
m_frames.push_back(gf);
|
||
|
||
// 释放临时对象
|
||
SafeRelease(&converter);
|
||
SafeRelease(&metaReader);
|
||
SafeRelease(&srcFrame);
|
||
|
||
}
|
||
// 释放画布
|
||
SafeRelease(&canvas);
|
||
SafeRelease(&prevCanvas);
|
||
//读取第一帧
|
||
this->NextFrame();
|
||
}
|
||
|
||
WORD DXImage::NextFrame() {
|
||
if (m_frames.empty()) {
|
||
return 0; // 没有帧
|
||
}
|
||
if (m_framePos >= m_frames.size()) {
|
||
m_framePos = 0;
|
||
}
|
||
this->m_bitMap = m_frames[m_framePos].wicBitmap;
|
||
UINT delayMs = m_frames[m_framePos].delay;
|
||
// 这里不需要释放和创建格式转换器了,播放时再转 D2D 位图
|
||
// 只移动索引
|
||
m_framePos++;
|
||
return (WORD)delayMs;
|
||
}
|
||
DXImage* DXImage::Clone()
|
||
{
|
||
UINT width, height;
|
||
m_fmtcovter->GetSize(&width, &height); // 获取位图源的宽度和高度
|
||
//暂时不做clone函数
|
||
return NULL;
|
||
}
|
||
DXImage::DXImage(HBITMAP hBitmap) {
|
||
if (D2D::g_ImageFactory) {
|
||
//WICBitmapUsePremultipliedAlpha:传入的图像颜色值已经与 Alpha 通道预乘
|
||
D2D::g_ImageFactory->CreateBitmapFromHBITMAP(hBitmap, NULL, WICBitmapUsePremultipliedAlpha, &m_bitMap);
|
||
UINT width, height;
|
||
m_bitMap->GetSize(&width, &height);
|
||
this->m_width = width;
|
||
this->m_height = height;
|
||
Init();
|
||
}
|
||
}
|
||
DXImage::DXImage(const std::wstring& file) {
|
||
CreateFromFile(file);
|
||
}
|
||
DXImage::DXImage(int width, int height)
|
||
{
|
||
this->m_width = width;
|
||
this->m_height = height;
|
||
ASSERT(!(width <= 0 || height <= 0));
|
||
HRESULT hr = D2D::g_ImageFactory->CreateBitmap((UINT)width, (UINT)height, GUID_WICPixelFormat32bppPBGRA, WICBitmapCacheOnDemand, &m_bitMap);
|
||
}
|
||
DXImage::DXImage(const void* data, size_t imgSize)
|
||
{
|
||
ASSERT(data);
|
||
ASSERT(imgSize);
|
||
IStream* stream = SHCreateMemStream((BYTE*)data, imgSize);
|
||
if (stream) {
|
||
this->CreateFormStream(stream);
|
||
SafeRelease(&stream);
|
||
}
|
||
}
|
||
ID2D1Bitmap* DXImage::Get()
|
||
{
|
||
return m_d2dBitmap;
|
||
}
|
||
IWICBitmap* DXImage::GetIWICBitmap()
|
||
{
|
||
return m_bitMap;
|
||
}
|
||
DXImage::DXImage(IStream* istram) {
|
||
CreateFormStream(istram);
|
||
}
|
||
DXImage::~DXImage()
|
||
{
|
||
if (m_d2dBitmap) {
|
||
SafeRelease(&m_d2dBitmap);
|
||
}
|
||
if (m_bitmapdecoder) {
|
||
SafeRelease(&m_bitmapdecoder);
|
||
}
|
||
if (m_pframe) {
|
||
SafeRelease(&m_pframe);
|
||
}
|
||
if (m_fmtcovter) {
|
||
SafeRelease(&m_fmtcovter);
|
||
}
|
||
if (m_bitMap) {
|
||
SafeRelease(&m_bitMap);
|
||
}
|
||
for (auto& it : m_frames) {
|
||
SafeRelease(&it.wicBitmap);
|
||
}
|
||
}
|
||
|
||
void Geometry::Combine(Geometry& out, const Geometry& a, const Geometry& b, D2D1_COMBINE_MODE COMBINE_MODE)
|
||
{
|
||
ID2D1PathGeometry* outPathGeometry = NULL;
|
||
D2D::g_Direct2dFactory->CreatePathGeometry(&outPathGeometry);
|
||
ID2D1GeometrySink* geometrySink = NULL;
|
||
outPathGeometry->Open(&geometrySink);
|
||
HRESULT ret = a.m_rgn->CombineWithGeometry(b.m_rgn, COMBINE_MODE, NULL, geometrySink);
|
||
geometrySink->Close();
|
||
if (out.m_rgn) {
|
||
SafeRelease(&out.m_rgn);
|
||
}
|
||
out.m_rgn = outPathGeometry;
|
||
SafeRelease(&geometrySink);
|
||
}
|
||
|
||
void RectangleGeometry::Create(float x, float y, float width, float height, float _radius)
|
||
{
|
||
if (_radius > 0) {
|
||
float radius = GetMaxRadius(width, height, _radius);
|
||
D2D1_ROUNDED_RECT rectF{ x,y,(x + width),(y + height) ,radius ,radius };
|
||
D2D::g_Direct2dFactory->CreateRoundedRectangleGeometry(rectF, (ID2D1RoundedRectangleGeometry**)&m_rgn);
|
||
}
|
||
else {
|
||
D2D_RECT_F rectF{ x,y,(x + width),(y + height) };
|
||
D2D::g_Direct2dFactory->CreateRectangleGeometry(rectF, (ID2D1RectangleGeometry**)&m_rgn);
|
||
}
|
||
}
|
||
RectangleGeometry::RectangleGeometry(float x, float y, float width, float height, float _radius) {
|
||
Create(x, y, width, height, _radius);
|
||
}
|
||
RectangleGeometry::RectangleGeometry(const RectF& _rect, float _radius)
|
||
{
|
||
float x = _rect.X, y = _rect.Y, width = _rect.Width, height = _rect.Height;
|
||
Create(x, y, width, height, _radius);
|
||
}
|
||
RectangleGeometry::RectangleGeometry(const RectF& _rect, float topLeftRadius, float topRightRadius, float bottomRightRadius, float bottomLeftRadius)
|
||
{
|
||
ID2D1PathGeometry* pPathGeometry = NULL;
|
||
D2D1_RECT_F rect = __To_D2D_RectF(_rect);
|
||
D2D::g_Direct2dFactory->CreatePathGeometry(&pPathGeometry);
|
||
topLeftRadius = GetMaxRadius(_rect.Width, _rect.Height, topLeftRadius);
|
||
topRightRadius = GetMaxRadius(_rect.Width, _rect.Height, topRightRadius);
|
||
bottomRightRadius = GetMaxRadius(_rect.Width, _rect.Height, bottomRightRadius);
|
||
bottomLeftRadius = GetMaxRadius(_rect.Width, _rect.Height, bottomLeftRadius);
|
||
// 打开路径几何图形的几何接口
|
||
ID2D1GeometrySink* pSink;
|
||
pPathGeometry->Open(&pSink);
|
||
// 开始绘制路径
|
||
pSink->BeginFigure(D2D1::Point2F(rect.left, rect.top + topLeftRadius), D2D1_FIGURE_BEGIN_FILLED);
|
||
// 添加弧线段到左上角
|
||
pSink->AddArc(
|
||
D2D1::ArcSegment(
|
||
D2D1::Point2F(rect.left + topLeftRadius, rect.top),
|
||
D2D1::SizeF(topLeftRadius, topLeftRadius),
|
||
0.0f,
|
||
D2D1_SWEEP_DIRECTION_CLOCKWISE,
|
||
D2D1_ARC_SIZE_SMALL
|
||
)
|
||
);
|
||
// 添加弧线段到右上角
|
||
pSink->AddLine(D2D1::Point2F(rect.right - topRightRadius, rect.top));
|
||
pSink->AddArc(
|
||
D2D1::ArcSegment(
|
||
D2D1::Point2F(rect.right, rect.top + topRightRadius),
|
||
D2D1::SizeF(topRightRadius, topRightRadius),
|
||
0.0f,
|
||
D2D1_SWEEP_DIRECTION_CLOCKWISE,
|
||
D2D1_ARC_SIZE_SMALL
|
||
)
|
||
);
|
||
// 添加弧线段到右下角
|
||
pSink->AddLine(D2D1::Point2F(rect.right, rect.bottom - bottomRightRadius));
|
||
pSink->AddArc(
|
||
D2D1::ArcSegment(
|
||
D2D1::Point2F(rect.right - bottomRightRadius, rect.bottom),
|
||
D2D1::SizeF(bottomRightRadius, bottomRightRadius),
|
||
0.0f,
|
||
D2D1_SWEEP_DIRECTION_CLOCKWISE,
|
||
D2D1_ARC_SIZE_SMALL
|
||
)
|
||
);
|
||
// 添加弧线段到左下角
|
||
pSink->AddLine(D2D1::Point2F(rect.left + bottomLeftRadius, rect.bottom));
|
||
pSink->AddArc(
|
||
D2D1::ArcSegment(
|
||
D2D1::Point2F(rect.left, rect.bottom - bottomLeftRadius),
|
||
D2D1::SizeF(bottomLeftRadius, bottomLeftRadius),
|
||
0.0f,
|
||
D2D1_SWEEP_DIRECTION_CLOCKWISE,
|
||
D2D1_ARC_SIZE_SMALL
|
||
)
|
||
);
|
||
// 结束路径
|
||
pSink->EndFigure(D2D1_FIGURE_END_CLOSED);
|
||
pSink->Close();
|
||
SafeRelease(&pSink);
|
||
this->m_rgn = pPathGeometry;
|
||
}
|
||
|
||
Geometry::Geometry() {
|
||
}
|
||
|
||
void Geometry::AddArc(const PointF& endPoint, float radius) {
|
||
m_pSink->AddArc(
|
||
D2D1::ArcSegment(
|
||
D2D1::Point2F(endPoint.X, endPoint.Y),
|
||
D2D1::SizeF(radius, radius),
|
||
0.0f,
|
||
D2D1_SWEEP_DIRECTION_CLOCKWISE,
|
||
D2D1_ARC_SIZE_SMALL
|
||
)
|
||
);
|
||
}
|
||
|
||
void Geometry::AddAcr(const D2D1_ARC_SEGMENT& arc)
|
||
{
|
||
m_pSink->AddArc(arc);
|
||
}
|
||
|
||
void Geometry::AddLine(const PointF& endPoint) {
|
||
D2D1_POINT_2F p{ endPoint.X, endPoint.Y };
|
||
m_pSink->AddLine(p);
|
||
}
|
||
void Geometry::BeginFigure(const PointF& startPoint, D2D1_FIGURE_BEGIN figureBegin) {
|
||
ID2D1PathGeometry* path;
|
||
D2D::g_Direct2dFactory->CreatePathGeometry(&path);
|
||
path->Open(&m_pSink);
|
||
m_pSink->BeginFigure(__To_D2D_PointF(startPoint), figureBegin);
|
||
m_rgn = path;
|
||
}
|
||
void Geometry::CloseFigure(D2D1_FIGURE_END figureEnd) {
|
||
m_pSink->EndFigure(figureEnd);
|
||
m_pSink->Close(); // 完成 Path 定义
|
||
}
|
||
|
||
Geometry::~Geometry() {
|
||
if (m_pSink) {
|
||
SafeRelease(&m_pSink);
|
||
}
|
||
if (m_rgn) {
|
||
SafeRelease(&m_rgn);
|
||
|
||
}
|
||
}
|
||
ID2D1Geometry* Geometry::Get() const {
|
||
return m_rgn;
|
||
}
|
||
|
||
|
||
PieGeometry::PieGeometry(const RectF& rectF, float startAngle, float endAngle)
|
||
{
|
||
auto rect = __To_D2D_RectF(rectF);
|
||
// 1. 计算圆心和半径
|
||
D2D1_POINT_2F center = {
|
||
(rect.left + rect.right) / 2.0f,
|
||
(rect.top + rect.bottom) / 2.0f
|
||
};
|
||
|
||
float radiusX = (rect.right - rect.left) / 2.0f;
|
||
float radiusY = (rect.bottom - rect.top) / 2.0f;
|
||
|
||
bool isFullCircle = fabsf(endAngle - startAngle) >= 359.999f;
|
||
if (isFullCircle) {
|
||
// 方法2:直接使用椭圆几何(更高效)
|
||
ID2D1EllipseGeometry* pEllipse = NULL;
|
||
D2D1_ELLIPSE ellipse{ center, radiusX, radiusY };
|
||
D2D::g_Direct2dFactory->CreateEllipseGeometry(&ellipse, &pEllipse);
|
||
//赋值
|
||
this->m_rgn = (ID2D1Geometry*)pEllipse;
|
||
}
|
||
else {
|
||
|
||
// 2. 角度处理(转换为弧度)
|
||
float startRad = startAngle * (3.1415926f / 180.0f);
|
||
float endRad = endAngle * (3.1415926f / 180.0f);
|
||
|
||
// 3. 创建路径几何
|
||
ID2D1PathGeometry* pGeometry = NULL;
|
||
D2D::g_Direct2dFactory->CreatePathGeometry(&pGeometry);
|
||
|
||
ID2D1GeometrySink* pSink = NULL;
|
||
pGeometry->Open(&pSink);
|
||
// 4. 计算弧线起点和终点
|
||
D2D1_POINT_2F startPoint = {
|
||
center.x + radiusX * cosf(startRad),
|
||
center.y + radiusY * sinf(startRad)
|
||
};
|
||
D2D1_POINT_2F endPoint = {
|
||
center.x + radiusX * cosf(endRad),
|
||
center.y + radiusY * sinf(endRad)
|
||
};
|
||
|
||
// 5. 构造扇形路径
|
||
pSink->BeginFigure(center, D2D1_FIGURE_BEGIN_FILLED);
|
||
pSink->AddLine(startPoint);
|
||
|
||
D2D1_ARC_SEGMENT arc{
|
||
endPoint,
|
||
D2D1::SizeF(radiusX, radiusY),
|
||
0.0f,
|
||
(endRad > startRad) ? D2D1_SWEEP_DIRECTION_CLOCKWISE : D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE,
|
||
(fabsf(endRad - startRad) <= 3.1415926f) ? D2D1_ARC_SIZE_SMALL : D2D1_ARC_SIZE_LARGE
|
||
};
|
||
pSink->AddArc(arc);
|
||
pSink->AddLine(center);
|
||
pSink->EndFigure(D2D1_FIGURE_END_CLOSED);
|
||
//释放
|
||
pSink->Close();
|
||
SafeRelease(&pSink);
|
||
//赋值
|
||
this->m_rgn = pGeometry;
|
||
}
|
||
}
|
||
};
|
||
|
||
namespace ezui {
|
||
void RenderInitialize()
|
||
{
|
||
HRESULT hr = S_OK;
|
||
// Create a Direct2D factory.
|
||
if (D2D::g_Direct2dFactory == NULL) {
|
||
hr = ::D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, &D2D::g_Direct2dFactory);
|
||
if (!D2D::g_Direct2dFactory) {
|
||
::MessageBoxW(NULL, L"Failed to create ID2D1Factory", L"Error", MB_ICONSTOP);
|
||
}
|
||
else {
|
||
D2D1_RENDER_TARGET_PROPERTIES defaultOption = D2D1::RenderTargetProperties(
|
||
D2D1_RENDER_TARGET_TYPE_DEFAULT,
|
||
D2D1::PixelFormat(
|
||
DXGI_FORMAT_B8G8R8A8_UNORM,
|
||
D2D1_ALPHA_MODE_PREMULTIPLIED),
|
||
0,
|
||
0,
|
||
D2D1_RENDER_TARGET_USAGE_NONE,
|
||
D2D1_FEATURE_LEVEL_DEFAULT
|
||
);
|
||
//初始化一下d2d让第一次启动窗口快一点
|
||
ID2D1DCRenderTarget* initRender = NULL;
|
||
hr = D2D::g_Direct2dFactory->CreateDCRenderTarget(&defaultOption, (ID2D1DCRenderTarget**)&initRender);
|
||
SafeRelease(&initRender);
|
||
}
|
||
}
|
||
if (D2D::g_WriteFactory == NULL) {
|
||
hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown**>(&D2D::g_WriteFactory));
|
||
if (!D2D::g_WriteFactory) {
|
||
::MessageBoxW(NULL, L"Failed to create IDWriteFactory", L"Error", MB_ICONSTOP);
|
||
}
|
||
}
|
||
if (D2D::g_ImageFactory == NULL) {
|
||
_GUID imageFactoryOld{ 0xcacaf262, 0x9370, 0x4615, 0xa1, 0x3b, 0x9f, 0x55, 0x39, 0xda, 0x4c, 0xa };//xp win7 旧版
|
||
_GUID WICImagingFactoryId = CLSID_WICImagingFactory;//当前平台
|
||
ImagingFactoryInit:
|
||
hr = CoCreateInstance(WICImagingFactoryId, NULL, CLSCTX_INPROC_SERVER, __uuidof(IWICImagingFactory), (LPVOID*)&D2D::g_ImageFactory);
|
||
if (hr != S_OK) {
|
||
//if (hr == 0x800401F0) {//未初始化com 自己在全局初始化一下就好了 (自己控制初始化时机)
|
||
// ::CoInitialize(NULL);
|
||
// goto ImagingFactory;
|
||
//}
|
||
if (hr == 0x80040154) {//没有注册类 不用win7的sdk生成的程序在下win7系统上运行会出现此错误
|
||
WICImagingFactoryId = imageFactoryOld;
|
||
goto ImagingFactoryInit;
|
||
}
|
||
CHAR buf[256]{ 0 };
|
||
sprintf_s(buf, "Code 0x%08X", hr);
|
||
::MessageBoxA(NULL, buf, "Failed to create IWICImagingFactory", MB_ICONSTOP);
|
||
}
|
||
}
|
||
|
||
if (g_GdiplusToken == NULL) {
|
||
//初始化GDI+
|
||
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
|
||
Gdiplus::GdiplusStartup(&g_GdiplusToken, &gdiplusStartupInput, NULL);
|
||
}
|
||
}
|
||
void RenderUnInitialize()
|
||
{
|
||
if (D2D::g_Direct2dFactory) {
|
||
SafeRelease(&D2D::g_Direct2dFactory);
|
||
}
|
||
if (D2D::g_WriteFactory) {
|
||
SafeRelease(&D2D::g_WriteFactory);
|
||
}
|
||
if (D2D::g_ImageFactory) {
|
||
SafeRelease(&D2D::g_ImageFactory);
|
||
}
|
||
//释放GDI+
|
||
if (g_GdiplusToken) {
|
||
Gdiplus::GdiplusShutdown(g_GdiplusToken);
|
||
g_GdiplusToken = NULL;
|
||
}
|
||
}
|
||
float GetMaxRadius(float width, float height, float _radius)
|
||
{
|
||
float radius = _radius;//半径
|
||
float diameter = radius * 2;//直径
|
||
if (width > height || (std::fabs(width - height) < EZUI_FLOAT_EPSILON)) {
|
||
if (diameter > height) {
|
||
radius = height / 2.0f;
|
||
}
|
||
}
|
||
else if (height > width) {
|
||
if (diameter > width) {
|
||
radius = width / 2.0f;
|
||
}
|
||
}
|
||
return radius;
|
||
}
|
||
DXRender::DXRender(HDC dc, int x, int y, int width, int height) {
|
||
D2D1_RENDER_TARGET_PROPERTIES defaultOption = D2D1::RenderTargetProperties(
|
||
D2D1_RENDER_TARGET_TYPE_DEFAULT,
|
||
D2D1::PixelFormat(
|
||
DXGI_FORMAT_B8G8R8A8_UNORM,
|
||
D2D1_ALPHA_MODE_PREMULTIPLIED),//表示三通道的值已经是预乘了a通之后的数值
|
||
0,
|
||
0,
|
||
D2D1_RENDER_TARGET_USAGE_NONE,
|
||
D2D1_FEATURE_LEVEL_DEFAULT
|
||
);
|
||
HRESULT hr = D2D::g_Direct2dFactory->CreateDCRenderTarget(&defaultOption, (ID2D1DCRenderTarget**)&m_render);
|
||
RECT rc{ x,y,x + width ,y + height };
|
||
((ID2D1DCRenderTarget*)m_render)->BindDC(dc, &rc);
|
||
m_render->BeginDraw();
|
||
}
|
||
|
||
DXRender::DXRender(DXImage* dxImage) {
|
||
D2D1_RENDER_TARGET_PROPERTIES defaultOption = D2D1::RenderTargetProperties(
|
||
D2D1_RENDER_TARGET_TYPE_DEFAULT,
|
||
D2D1::PixelFormat(),
|
||
0,
|
||
0,
|
||
D2D1_RENDER_TARGET_USAGE_NONE,
|
||
D2D1_FEATURE_LEVEL_DEFAULT
|
||
);
|
||
HRESULT hr = D2D::g_Direct2dFactory->CreateWicBitmapRenderTarget(dxImage->GetIWICBitmap(), defaultOption, (ID2D1RenderTarget**)&m_render);
|
||
m_render->BeginDraw();
|
||
}
|
||
|
||
|
||
DXRender::~DXRender() {
|
||
if (m_render) {
|
||
m_render->EndDraw();
|
||
}
|
||
if (m_font) {
|
||
delete m_font;
|
||
}
|
||
SafeRelease(&m_render);
|
||
SafeRelease(&m_brush);
|
||
SafeRelease(&m_pStrokeStyle);
|
||
}
|
||
ID2D1SolidColorBrush* DXRender::GetBrush()
|
||
{
|
||
if (m_brush == NULL) {
|
||
m_render->CreateSolidColorBrush(D2D_COLOR_F{ 0,0,0,1 }, &m_brush);
|
||
}
|
||
return m_brush;
|
||
}
|
||
ID2D1StrokeStyle* DXRender::GetStrokeStyle() {
|
||
return m_pStrokeStyle;
|
||
}
|
||
void DXRender::SetFont(const std::wstring& fontFamily, float fontSize) {
|
||
if (m_font != NULL) {
|
||
if (m_font->GetFontFamily() == fontFamily && (std::fabs(m_font->GetFontSize() - fontSize) < EZUI_FLOAT_EPSILON)) {
|
||
return;
|
||
}
|
||
delete m_font;
|
||
}
|
||
m_font = new Font(fontFamily, fontSize);
|
||
}
|
||
void DXRender::SetFont(const Font& _copy_font) {
|
||
if (m_font != NULL) {
|
||
if (*m_font == _copy_font) {
|
||
return;
|
||
}
|
||
delete m_font;
|
||
}
|
||
m_font = new Font(_copy_font);
|
||
}
|
||
void DXRender::SetColor(const __EzUI__Color& color) {
|
||
if (m_brush == NULL) {
|
||
m_render->CreateSolidColorBrush(__To_D2D_COLOR_F(color), &m_brush);
|
||
}
|
||
else {
|
||
m_brush->SetColor(__To_D2D_COLOR_F(color));
|
||
}
|
||
}
|
||
void DXRender::SetStrokeStyle(StrokeStyle strokeStyle)
|
||
{
|
||
if (m_pStrokeStyle != NULL) {
|
||
SafeRelease(&m_pStrokeStyle);
|
||
}
|
||
if (strokeStyle == StrokeStyle::Dash) {
|
||
// 使用系统默认的虚线样式
|
||
D2D1_DASH_STYLE dashStyle = D2D1_DASH_STYLE_DASH; // 常规虚线样式
|
||
// 创建虚线样式
|
||
D2D::g_Direct2dFactory->CreateStrokeStyle(
|
||
D2D1::StrokeStyleProperties(
|
||
D2D1_CAP_STYLE_FLAT, // 线帽样式
|
||
D2D1_CAP_STYLE_FLAT, // 结束线帽样式
|
||
D2D1_CAP_STYLE_ROUND, // 虚线部分的线帽样式
|
||
D2D1_LINE_JOIN_ROUND, // 线段连接样式
|
||
10.0f, // 斜接限制
|
||
dashStyle, // 设置虚线样式为常规虚线
|
||
0.0f // 自定义虚线的间隔(不需要)
|
||
),
|
||
NULL, 0, &m_pStrokeStyle);
|
||
}
|
||
}
|
||
void DXRender::DrawTextLayout(const TextLayout& textLayout, const PointF& startLacation) {
|
||
m_render->DrawTextLayout(D2D1_POINT_2F{ startLacation.X ,startLacation.Y }, textLayout.Get(), GetBrush());
|
||
}
|
||
void DXRender::DrawString(const std::wstring& text, const RectF& rect, ezui::TextAlign textAlign) {
|
||
TextLayout textLayout(text, *m_font, { rect.Width, rect.Height }, textAlign);
|
||
this->DrawTextLayout(textLayout, { rect.X,rect.Y });
|
||
}
|
||
void DXRender::DrawLine(const PointF& A, const PointF& B, float width) {
|
||
m_render->DrawLine(D2D1_POINT_2F{ A.X,A.Y }, D2D1_POINT_2F{ B.X,B.Y }, GetBrush(), width, GetStrokeStyle());
|
||
}
|
||
|
||
void DXRender::DrawRectangle(const RectF& rect, float _radius, float width)
|
||
{
|
||
if (_radius > 0) {
|
||
float radius = GetMaxRadius(rect.Width, rect.Height, _radius);
|
||
D2D1_ROUNDED_RECT roundRect{ __To_D2D_RectF(rect), radius, radius };
|
||
m_render->DrawRoundedRectangle(roundRect, GetBrush(), width, GetStrokeStyle());
|
||
}
|
||
else {
|
||
m_render->DrawRectangle(__To_D2D_RectF(rect), GetBrush(), width, GetStrokeStyle());
|
||
}
|
||
}
|
||
|
||
|
||
void DXRender::FillRectangle(const RectF& rect, float _radius) {
|
||
if (_radius > 0) {
|
||
float radius = GetMaxRadius(rect.Width, rect.Height, _radius);
|
||
D2D1_ROUNDED_RECT roundRect{ __To_D2D_RectF(rect), radius, radius };
|
||
m_render->FillRoundedRectangle(roundRect, GetBrush());
|
||
}
|
||
else {
|
||
m_render->FillRectangle(__To_D2D_RectF(rect), GetBrush());
|
||
}
|
||
}
|
||
|
||
void DXRender::SetTransform(float offsetX, float offsetY)
|
||
{
|
||
this->m_offset.X = offsetX;
|
||
this->m_offset.Y = offsetY;
|
||
this->SetTransform(this->m_offset.X, this->m_offset.Y, this->m_rotatePoint.X, this->m_rotatePoint.Y, this->m_angle);
|
||
}
|
||
|
||
void DXRender::SetTransform(float startX, float startY, float angle) {
|
||
this->m_rotatePoint.X = startX;
|
||
this->m_rotatePoint.Y = startY;
|
||
this->m_angle = angle;
|
||
this->SetTransform(this->m_offset.X, this->m_offset.Y, this->m_rotatePoint.X, this->m_rotatePoint.Y, this->m_angle);
|
||
}
|
||
|
||
void DXRender::SetTransform(float offsetX, float offsetY, float startX, float startY, float angle)
|
||
{
|
||
// 创建D2D矩阵转换对象 平移变换
|
||
D2D1::Matrix3x2F transformMatrix = D2D1::Matrix3x2F::Translation(offsetX, offsetY);
|
||
// 判断是否需要进行旋转变换
|
||
if (angle != 0)
|
||
{
|
||
// 旋转变换
|
||
transformMatrix = transformMatrix * D2D1::Matrix3x2F::Rotation(angle, D2D1_POINT_2F{ startX, startY });
|
||
}
|
||
// 将转换矩阵应用于绘制对象
|
||
m_render->SetTransform(transformMatrix);
|
||
}
|
||
|
||
void DXRender::DrawBezier(const PointF& startPoint, const Bezier& points, float width) {
|
||
ID2D1GeometrySink* pSink = NULL;
|
||
ID2D1PathGeometry* pathGeometry = NULL;
|
||
D2D::g_Direct2dFactory->CreatePathGeometry(&pathGeometry);
|
||
pathGeometry->Open(&pSink);
|
||
pSink->BeginFigure(__To_D2D_PointF(startPoint), D2D1_FIGURE_BEGIN_FILLED);
|
||
D2D1_BEZIER_SEGMENT bzr{ __To_D2D_PointF(points.point1) ,__To_D2D_PointF(points.point2) ,__To_D2D_PointF(points.point3) };
|
||
pSink->AddBezier(bzr);
|
||
pSink->EndFigure(D2D1_FIGURE_END_OPEN);
|
||
pSink->Close();
|
||
m_render->DrawGeometry(pathGeometry, GetBrush(), width, GetStrokeStyle());
|
||
SafeRelease(&pathGeometry);
|
||
SafeRelease(&pSink);
|
||
}
|
||
void DXRender::DrawBezier(const PointF& startPoint, std::list<Bezier>& beziers, float width)
|
||
{
|
||
ID2D1GeometrySink* pSink = NULL;
|
||
ID2D1PathGeometry* pathGeometry = NULL;
|
||
D2D::g_Direct2dFactory->CreatePathGeometry(&pathGeometry);
|
||
pathGeometry->Open(&pSink);
|
||
pSink->BeginFigure(__To_D2D_PointF(startPoint), D2D1_FIGURE_BEGIN_FILLED);
|
||
for (auto& it : beziers) {
|
||
D2D1_BEZIER_SEGMENT bzr{ __To_D2D_PointF(it.point1) ,__To_D2D_PointF(it.point2) ,__To_D2D_PointF(it.point3) };
|
||
pSink->AddBezier(bzr);
|
||
}
|
||
pSink->EndFigure(D2D1_FIGURE_END_OPEN);
|
||
pSink->Close();
|
||
m_render->DrawGeometry(pathGeometry, GetBrush(), width, GetStrokeStyle());
|
||
SafeRelease(&pathGeometry);
|
||
SafeRelease(&pSink);
|
||
}
|
||
|
||
void DXRender::PushLayer(const Geometry& dxGeometry) {
|
||
ID2D1Layer* layer = NULL;
|
||
m_render->CreateLayer(&layer);
|
||
m_render->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(), dxGeometry.Get()), layer);//放入layer
|
||
SafeRelease(&layer);
|
||
}
|
||
void DXRender::PopLayer() {
|
||
m_render->PopLayer();
|
||
}
|
||
void DXRender::PushAxisAlignedClip(const RectF& rectBounds) {
|
||
m_render->PushAxisAlignedClip(__To_D2D_RectF(rectBounds), D2D1_ANTIALIAS_MODE::D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
|
||
}
|
||
void DXRender::PopAxisAlignedClip() {
|
||
m_render->PopAxisAlignedClip();
|
||
}
|
||
|
||
void DXRender::DrawImage(DXImage* image, const RectF& tagRect, float opacity) {
|
||
_NOREND_IMAGE_
|
||
if (image->Visible == false) return;
|
||
//解码
|
||
image->DecodeOfRender(m_render);
|
||
ID2D1Bitmap* bitmap = image->Get();
|
||
if (!bitmap) {
|
||
//解码失败
|
||
return;
|
||
}
|
||
ImageSizeMode imageSizeMode = image->SizeMode;
|
||
const Rect& sourceRect = image->Clip;
|
||
//计算坐标
|
||
RectF rect(tagRect.X, tagRect.Y, tagRect.Width, tagRect.Height);
|
||
//转换坐标,缩放
|
||
Size imgSize(image->Width(), image->Height());
|
||
if (!sourceRect.IsEmptyArea()) {
|
||
imgSize.Width = sourceRect.Width;
|
||
imgSize.Height = sourceRect.Height;
|
||
}
|
||
|
||
//加上在Owner区域的偏移
|
||
rect.X += image->DrawPosition.X;
|
||
rect.Y += image->DrawPosition.Y;
|
||
|
||
RectF realRendRect;//最终渲染的矩形位置
|
||
if (!image->DrawSize.Empty()) {
|
||
//限制在Owner中的绘制区域
|
||
realRendRect = RectF(rect.X, rect.Y, image->DrawSize.Width, image->DrawSize.Height);
|
||
}
|
||
else {
|
||
//不限制绘制区域 根据imageSizeMode属性进行坐标转换
|
||
realRendRect = RectF::Transformation(imageSizeMode, rect, SizeF(imgSize.Width, imgSize.Height));
|
||
}
|
||
//开始绘制
|
||
D2D_RECT_F drawRectF = __To_D2D_RectF(realRendRect);
|
||
if (!sourceRect.IsEmptyArea()) {
|
||
//裁剪图片部分内容进行绘制
|
||
D2D_RECT_F imageClipRectF = __To_D2D_RectF(sourceRect);
|
||
m_render->DrawBitmap(bitmap, drawRectF, opacity, D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, imageClipRectF);
|
||
}
|
||
else {
|
||
//不裁剪图片的方式进行绘制
|
||
m_render->DrawBitmap(bitmap, drawRectF, opacity);
|
||
}
|
||
}
|
||
void DXRender::DrawEllipse(const RectF& rectF, float strokeWidth)
|
||
{
|
||
PieGeometry pie(rectF, 0, 360);
|
||
DrawGeometry(pie.Get(), strokeWidth);
|
||
}
|
||
void DXRender::FillEllipse(const RectF& rectF)
|
||
{
|
||
PieGeometry pie(rectF, 0, 360);
|
||
FillGeometry(pie.Get());
|
||
}
|
||
|
||
void DXRender::DrawPie(const RectF& rectF, float startAngle, float endAngle, float strokeWidth)
|
||
{
|
||
PieGeometry pie(rectF, startAngle, endAngle);
|
||
DrawGeometry(pie.Get(), strokeWidth);
|
||
}
|
||
void DXRender::FillPie(const RectF& rectF, float startAngle, float endAngle)
|
||
{
|
||
PieGeometry pie(rectF, startAngle, endAngle);
|
||
FillGeometry(pie.Get());
|
||
}
|
||
void DXRender::DrawPoint(const PointF& pt) {
|
||
D2D1_ELLIPSE ellipse = D2D1::Ellipse(__To_D2D_PointF(pt), 0.5, 0.5);
|
||
m_render->FillEllipse(ellipse, GetBrush());
|
||
}
|
||
void DXRender::DrawArc(const RectF& rect, float startAngle, float sweepAngle, float width) {
|
||
}
|
||
void DXRender::DrawArc(const PointF& point1, const PointF& point2, const PointF& point3, float width)
|
||
{
|
||
}
|
||
void DXRender::DrawGeometry(ID2D1Geometry* geometry, float width)
|
||
{
|
||
m_render->DrawGeometry(geometry, GetBrush(), width, this->GetStrokeStyle());
|
||
}
|
||
void DXRender::FillGeometry(ID2D1Geometry* geometry)
|
||
{
|
||
m_render->FillGeometry(geometry, GetBrush());
|
||
}
|
||
void DXRender::DrawGeometry(Geometry* path, float width)
|
||
{
|
||
DrawGeometry(path->Get(), width);
|
||
}
|
||
void DXRender::FillGeometry(Geometry* path)
|
||
{
|
||
FillGeometry(path->Get());
|
||
}
|
||
void DXRender::Flush()
|
||
{
|
||
m_render->Flush();
|
||
}
|
||
ID2D1DCRenderTarget* DXRender::Get() {
|
||
return m_render;
|
||
}
|
||
};
|
||
|
||
#endif |