/// <summary> /// Initializes a new instance of the <see cref="Polyline"/> class. /// </summary> /// <param name="">The .</param> RubyGM::Drawable::Polyline::Polyline(const PolylineStatus& ps) noexcept : Super(ps) { assert(m_pGiGeometry == nullptr); assert(ps.points && ps.count >= 2); this->filled_color.a = 0.f; // 初始化 ID2D1PathGeometry* path = nullptr; ID2D1GeometrySink* sink = nullptr; // 创建路径几何 auto hr = Bridge::CreatePathGeometry(path); // 打开路径记录 if (SUCCEEDED(hr)) { hr = path->Open(&sink); } // 填充路径 if (SUCCEEDED(hr)) { auto points = impl::d2d(ps.points); sink->BeginFigure(*points, D2D1_FIGURE_BEGIN_HOLLOW); sink->AddLines(points + 1, ps.count - 1); sink->EndFigure(D2D1_FIGURE_END_CLOSED); hr = sink->Close(); } // 错误代码 if (FAILED(hr)) Game::SetLastErrorCode(hr); RubyGM::SafeRelease(sink); // 数据转换 auto gi = static_cast<ID2D1Geometry*>(path); m_pGiGeometry = static_cast<IGMGeometry*>(gi); }
ID2D1PathGeometry* Direct2DLowLevelGraphicsContext::pathToPathGeometry (const Path& path, const AffineTransform& transform) { ID2D1PathGeometry* p = nullptr; Direct2DFactories::getInstance().d2dFactory->CreatePathGeometry (&p); ComSmartPtr <ID2D1GeometrySink> sink; HRESULT hr = p->Open (sink.resetAndGetPointerAddress()); sink->SetFillMode (D2D1_FILL_MODE_WINDING); // xxx need to check Path::isUsingNonZeroWinding() pathToGeometrySink (path, sink, transform); hr = sink->Close(); return p; }
void Renderer::FillPolygon(Vector2D * points, int size, bool close) { if (size < 3) return; HRESULT hr; ID2D1PathGeometry* pGeometry = nullptr; hr = GRAPHICSDEVICEMANAGER->GetGraphics()->GetD2DFactory()->CreatePathGeometry(&pGeometry); if (FAILED(hr)) { SafeRelease(pGeometry); //Logger::Log(_T("Failed to create path geometry"), LOGTYPE_WARNING, false); return; } //Write to the path geometry using the geometry sink ID2D1GeometrySink* pGeometrySink = nullptr; hr = pGeometry->Open(&pGeometrySink); if (FAILED(hr)) { SafeRelease(pGeometrySink); SafeRelease(pGeometry); //Logger::Log(_T("Failed to create geometry sink"), LOGTYPE_WARNING, false); return; } if (SUCCEEDED(hr)) { pGeometrySink->BeginFigure(D2D1::Point2((FLOAT)points[0].x, (FLOAT)points[0].y), D2D1_FIGURE_BEGIN_FILLED); for (int i = 1; i < size; ++i) pGeometrySink->AddLine(D2D1::Point2F((FLOAT)points[i].x, (FLOAT)points[i].y)); pGeometrySink->EndFigure(D2D1_FIGURE_END_CLOSED); hr = pGeometrySink->Close(); SafeRelease(pGeometrySink); } if (SUCCEEDED(hr)) { GRAPHICSDEVICEMANAGER->GetGraphics()->GetRenderTarget()->FillGeometry(pGeometry, GRAPHICSDEVICEMANAGER->GetGraphics()->GetColorBrush()); SafeRelease(pGeometry); return; } SafeRelease(pGeometry); }
ID2D1PathGeometry* Direct2DLowLevelGraphicsContext::rectListToPathGeometry (const RectangleList& clipRegion) { ID2D1PathGeometry* p = nullptr; Direct2DFactories::getInstance().d2dFactory->CreatePathGeometry (&p); ComSmartPtr <ID2D1GeometrySink> sink; HRESULT hr = p->Open (sink.resetAndGetPointerAddress()); // xxx handle error sink->SetFillMode (D2D1_FILL_MODE_WINDING); for (int i = clipRegion.getNumRectangles(); --i >= 0;) rectToGeometrySink (clipRegion.getRectangle(i), sink); hr = sink->Close(); return p; }
~D2DPathRendererState() { if (path) { path->Release(); path = NULL; } }
void VGraphicPath::Widen(const GReal inStrokeWidth, ID2D1StrokeStyle* inStrokeStyle) { xbox_assert(inStrokeStyle); End(); if (fPathD2D != NULL) { CComPtr<ID2D1StrokeStyle> strokeStyle = (ID2D1StrokeStyle *)inStrokeStyle; ID2D1Geometry *oldPath = fPathD2D; //create new path ID2D1PathGeometry *newPath = NULL; VWinD2DGraphicContext::GetMutexFactory().Lock(); HRESULT hr = VWinD2DGraphicContext::GetFactory()->CreatePathGeometry( &newPath); xbox_assert(SUCCEEDED(hr)); VWinD2DGraphicContext::GetMutexFactory().Unlock(); //widen current path CComPtr<ID2D1GeometrySink> thisGeomSink; if (SUCCEEDED(newPath->Open(&thisGeomSink))) { thisGeomSink->SetFillMode( fFillMode == FILLRULE_EVENODD ? D2D1_FILL_MODE_ALTERNATE : D2D1_FILL_MODE_WINDING); if (!SUCCEEDED(oldPath->Widen( inStrokeWidth, strokeStyle, NULL, 0.0f, thisGeomSink))) { newPath->Release(); return; } thisGeomSink->Close(); } fPathD2D = newPath; oldPath->Release(); fCreateStorageForCrispEdges = false; fHasBezier = false; fDrawCmds.clear(); fCurTransform.MakeIdentity(); } }
void VGraphicPath::Begin() { #if ENABLE_D2D //start to populate geometry if (fGeomSink) return; if (fPathD2D == NULL) return; ID2D1PathGeometry *thisPath = NULL; if (FAILED(fPathD2D->QueryInterface( __uuidof(ID2D1PathGeometry), (void **)&thisPath))) return; //no more a ID2D1PathGeometry so skip ID2D1GeometrySink *thisGeomSink; if (SUCCEEDED(thisPath->Open(&thisGeomSink))) { fGeomSink = thisGeomSink; thisGeomSink->SetFillMode( fFillMode == FILLRULE_EVENODD ? D2D1_FILL_MODE_ALTERNATE : D2D1_FILL_MODE_WINDING); fFigureIsClosed = true; } thisPath->Release(); #endif }
void GraphData(PlotData **data, ID2D1Factory *d2dFactory, ID2D1RenderTarget *target, ID2D1SolidColorBrush *brush, float xScale, float yScale) { int c = 0; while(*data) { brush->SetColor(Colors[c++]); ID2D1PathGeometry *path = NULL; if(SUCCEEDED(d2dFactory->CreatePathGeometry(&path))) { ID2D1GeometrySink *sink = NULL; if (SUCCEEDED(path->Open(&sink))) { PlotGraph(**data, sink, xScale, yScale); SUCCEEDED(sink->Close()); target->DrawGeometry(path, brush); SafeRelease(&sink); } SafeRelease(&path); } data++; } }
HRESULT SaveToImageFile() { HRESULT hr = S_OK; // // Create Factories // IWICImagingFactory *pWICFactory = NULL; ID2D1Factory *pD2DFactory = NULL; IDWriteFactory *pDWriteFactory = NULL; IWICBitmap *pWICBitmap = NULL; ID2D1RenderTarget *pRT = NULL; IDWriteTextFormat *pTextFormat = NULL; ID2D1PathGeometry *pPathGeometry = NULL; ID2D1GeometrySink *pSink = NULL; ID2D1GradientStopCollection *pGradientStops = NULL; ID2D1LinearGradientBrush *pLGBrush = NULL; ID2D1SolidColorBrush *pBlackBrush = NULL; IWICBitmapEncoder *pEncoder = NULL; IWICBitmapFrameEncode *pFrameEncode = NULL; IWICStream *pStream = NULL; hr = CoCreateInstance( CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IWICImagingFactory, reinterpret_cast<void **>(&pWICFactory) ); if (SUCCEEDED(hr)) { hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2DFactory); } if (SUCCEEDED(hr)) { hr = DWriteCreateFactory( DWRITE_FACTORY_TYPE_SHARED, __uuidof(pDWriteFactory), reinterpret_cast<IUnknown **>(&pDWriteFactory) ); } // // Create IWICBitmap and RT // static const UINT sc_bitmapWidth = 640; static const UINT sc_bitmapHeight = 480; if (SUCCEEDED(hr)) { hr = pWICFactory->CreateBitmap( sc_bitmapWidth, sc_bitmapHeight, GUID_WICPixelFormat32bppBGR, WICBitmapCacheOnLoad, &pWICBitmap ); } if (SUCCEEDED(hr)) { hr = pD2DFactory->CreateWicBitmapRenderTarget( pWICBitmap, D2D1::RenderTargetProperties(), &pRT ); } if (SUCCEEDED(hr)) { // // Create text format // static const WCHAR sc_fontName[] = L"Calibri"; static const FLOAT sc_fontSize = 50; hr = pDWriteFactory->CreateTextFormat( sc_fontName, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, sc_fontSize, L"", //locale &pTextFormat ); } if (SUCCEEDED(hr)) { pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER); pTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER); // // Create a path geometry representing an hour glass // hr = pD2DFactory->CreatePathGeometry(&pPathGeometry); } if (SUCCEEDED(hr)) { hr = pPathGeometry->Open(&pSink); } if (SUCCEEDED(hr)) { pSink->SetFillMode(D2D1_FILL_MODE_ALTERNATE); pSink->BeginFigure( D2D1::Point2F(0, 0), D2D1_FIGURE_BEGIN_FILLED ); pSink->AddLine(D2D1::Point2F(200, 0)); pSink->AddBezier( D2D1::BezierSegment( D2D1::Point2F(150, 50), D2D1::Point2F(150, 150), D2D1::Point2F(200, 200)) ); pSink->AddLine(D2D1::Point2F(0, 200)); pSink->AddBezier( D2D1::BezierSegment( D2D1::Point2F(50, 150), D2D1::Point2F(50, 50), D2D1::Point2F(0, 0)) ); pSink->EndFigure(D2D1_FIGURE_END_CLOSED); hr = pSink->Close(); } if (SUCCEEDED(hr)) { // // Create a linear-gradient brush // static const D2D1_GRADIENT_STOP stops[] = { { 0.f, { 0.f, 1.f, 1.f, 1.f } }, { 1.f, { 0.f, 0.f, 1.f, 1.f } }, }; hr = pRT->CreateGradientStopCollection( stops, ARRAYSIZE(stops), &pGradientStops ); } if (SUCCEEDED(hr)) { hr = pRT->CreateLinearGradientBrush( D2D1::LinearGradientBrushProperties( D2D1::Point2F(100, 0), D2D1::Point2F(100, 200)), D2D1::BrushProperties(), pGradientStops, &pLGBrush ); } if (SUCCEEDED(hr)) { hr = pRT->CreateSolidColorBrush( D2D1::ColorF(D2D1::ColorF::Black), &pBlackBrush ); } if (SUCCEEDED(hr)) { // // Render into the bitmap // pRT->BeginDraw(); pRT->Clear(D2D1::ColorF(D2D1::ColorF::White)); D2D1_SIZE_F rtSize = pRT->GetSize(); // Set the world transform to a 45 degree rotation at the center of the render target // and write "Hello, World". pRT->SetTransform( D2D1::Matrix3x2F::Rotation( 45, D2D1::Point2F( rtSize.width / 2, rtSize.height / 2)) ); static const WCHAR sc_helloWorld[] = L"Hello, World!"; pRT->DrawText( sc_helloWorld, ARRAYSIZE(sc_helloWorld) - 1, pTextFormat, D2D1::RectF(0, 0, rtSize.width, rtSize.height), pBlackBrush); // // Reset back to the identity transform // pRT->SetTransform(D2D1::Matrix3x2F::Translation(0, rtSize.height - 200)); pRT->FillGeometry(pPathGeometry, pLGBrush); pRT->SetTransform(D2D1::Matrix3x2F::Translation(rtSize.width - 200, 0)); pRT->FillGeometry(pPathGeometry, pLGBrush); hr = pRT->EndDraw(); } if (SUCCEEDED(hr)) { // // Save image to file // hr = pWICFactory->CreateStream(&pStream); } WICPixelFormatGUID format = GUID_WICPixelFormatDontCare; if (SUCCEEDED(hr)) { static const WCHAR filename[] = L"output.png"; hr = pStream->InitializeFromFilename(filename, GENERIC_WRITE); } if (SUCCEEDED(hr)) { hr = pWICFactory->CreateEncoder(GUID_ContainerFormatPng, NULL, &pEncoder); } if (SUCCEEDED(hr)) { hr = pEncoder->Initialize(pStream, WICBitmapEncoderNoCache); } if (SUCCEEDED(hr)) { hr = pEncoder->CreateNewFrame(&pFrameEncode, NULL); } if (SUCCEEDED(hr)) { hr = pFrameEncode->Initialize(NULL); } if (SUCCEEDED(hr)) { hr = pFrameEncode->SetSize(sc_bitmapWidth, sc_bitmapHeight); } if (SUCCEEDED(hr)) { hr = pFrameEncode->SetPixelFormat(&format); } if (SUCCEEDED(hr)) { hr = pFrameEncode->WriteSource(pWICBitmap, NULL); } if (SUCCEEDED(hr)) { hr = pFrameEncode->Commit(); } if (SUCCEEDED(hr)) { hr = pEncoder->Commit(); } SafeRelease(&pWICFactory); SafeRelease(&pD2DFactory); SafeRelease(&pDWriteFactory); SafeRelease(&pWICBitmap); SafeRelease(&pRT); SafeRelease(&pTextFormat); SafeRelease(&pPathGeometry); SafeRelease(&pSink); SafeRelease(&pGradientStops); SafeRelease(&pLGBrush); SafeRelease(&pBlackBrush); SafeRelease(&pEncoder); SafeRelease(&pFrameEncode); SafeRelease(&pStream); return hr; }
/** combine current path with the specified path @remarks does not update internal polygon used only by D2D impl for path clipping implementation */ void VGraphicPath::_Combine( const VGraphicPath& inPath, bool inIntersect) { End(); //ensure proper combination if current path or input path is empty if (inPath.GetBounds().GetWidth() == 0.0f || inPath.GetBounds().GetHeight() == 0.0f) { //input path is empty if (inIntersect) Clear(); return; } if (GetBounds().GetWidth() == 0.0f || GetBounds().GetHeight() == 0.0f) { //current path is empty if (inIntersect) return; else *this = inPath; return; } //combine D2D path if appropriate //TODO: make it work for Gdiplus::GraphicPath too ? if (fPathD2D != NULL && inPath.GetImplPathD2D()) { ID2D1Geometry *oldPath = fPathD2D; //create new path ID2D1PathGeometry *newPath = NULL; VWinD2DGraphicContext::GetMutexFactory().Lock(); HRESULT hr = VWinD2DGraphicContext::GetFactory()->CreatePathGeometry( &newPath); xbox_assert(SUCCEEDED(hr)); VWinD2DGraphicContext::GetMutexFactory().Unlock(); //combine current path with input path CComPtr<ID2D1GeometrySink> thisGeomSink; if (SUCCEEDED(newPath->Open(&thisGeomSink))) { thisGeomSink->SetFillMode( fFillMode == FILLRULE_EVENODD ? D2D1_FILL_MODE_ALTERNATE : D2D1_FILL_MODE_WINDING); if (!SUCCEEDED(oldPath->CombineWithGeometry( inPath.GetImplPathD2D(), inIntersect ? D2D1_COMBINE_MODE_INTERSECT : D2D1_COMBINE_MODE_UNION, NULL, 0.0f, thisGeomSink ))) { newPath->Release(); return; } thisGeomSink->Close(); } fPathD2D = newPath; oldPath->Release(); if (inIntersect) fBounds.Intersect( inPath.GetBounds()); else fBounds.Union( inPath.GetBounds()); fCreateStorageForCrispEdges = false; fHasBezier = false; fDrawCmds.clear(); fCurTransform.MakeIdentity(); } }
// // Generates new graph geometry, which may change every frame. // HRESULT D3D12MemoryManagement::GenerateMemoryGraphGeometry(const RectF& Bounds, UINT GraphSizeMB, ID2D1PathGeometry** ppPathGeometry) { HRESULT hr; ID2D1PathGeometry* pPathGeometry = nullptr; ID2D1GeometrySink* pGeometrySink = nullptr; hr = m_pD2DFactory->CreatePathGeometry(&pPathGeometry); if (FAILED(hr)) { LOG_WARNING("Failed to create path geometry, hr=0x%.8x"); goto cleanup; } hr = pPathGeometry->Open(&pGeometrySink); if (FAILED(hr)) { LOG_WARNING("Failed to open path geometry sink, hr=0x%.8x"); goto cleanup; } { float GraphHeightPadded = GRAPH_HEIGHT * GRAPH_HEIGHT_RATIO / 100; float XStep = GRAPH_WIDTH / GRAPH_SEGMENTS; D2D1_POINT_2F Point; Point.x = Bounds.Left; Point.y = Bounds.Bottom; pGeometrySink->BeginFigure(Point, D2D1_FIGURE_BEGIN_FILLED); for (UINT i = 0; i < NUM_GRAPH_POINTS; ++i) { UINT32 GraphPoint = (i + m_CurrentGraphPoint) % NUM_GRAPH_POINTS; Point.y = Bounds.Bottom - (m_GraphPoints[GraphPoint] / 1024 / 1024) / (float)GraphSizeMB * GraphHeightPadded; pGeometrySink->AddLine(Point); Point.x += XStep; } Point.x = Bounds.Right; Point.y = Bounds.Bottom; pGeometrySink->AddLine(Point); pGeometrySink->EndFigure(D2D1_FIGURE_END_CLOSED); } hr = pGeometrySink->Close(); if (FAILED(hr)) { LOG_ERROR("Failed to close path geometry sink, hr=0x%.8x", hr); goto cleanup; } pGeometrySink->Release(); *ppPathGeometry = pPathGeometry; return S_OK; cleanup: SafeRelease(pGeometrySink); SafeRelease(pPathGeometry); return hr; }
/// <summary> /// IDWriteTextRenderer::DrawGlyphRun /// Draws glyphs /// </summary> HRESULT StateTextRender::DrawGlyphRun( LPVOID clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, DWRITE_MEASURING_MODE measuringMode, const DWRITE_GLYPH_RUN * glyphRun, const DWRITE_GLYPH_RUN_DESCRIPTION * glyphRunDescription, LPUNKNOWN clientDrawingEffect) { UNREFERENCED_PARAMETER(glyphRunDescription); UNREFERENCED_PARAMETER(clientDrawingEffect); HRESULT hr = S_OK; auto renderTarget = ((ID2D1RenderTarget*) clientDrawingContext); // Since the fill looks horrid anyways, only do this if we are // going to stroke, and fill using D2D's DrawGlyphRun if (mState->mStateSettings.fontStrokeWidth > 0.0f) { // Get our D2D factory ID2D1Factory *d2dFactory; renderTarget->GetFactory(&d2dFactory); // Create the path geometry. ID2D1PathGeometry *pPathGeometry = nullptr; hr = d2dFactory->CreatePathGeometry(&pPathGeometry); // Write to the path geometry using the geometry sink. ID2D1GeometrySink* sink = nullptr; if (SUCCEEDED(hr)) { hr = pPathGeometry->Open(&sink); } // Get the glyph run outline geometries back from DirectWrite and place them within the geometry sink. if (SUCCEEDED(hr)) { hr = glyphRun->fontFace->GetGlyphRunOutline( glyphRun->fontEmSize, glyphRun->glyphIndices, glyphRun->glyphAdvances, glyphRun->glyphOffsets, glyphRun->glyphCount, glyphRun->isSideways, glyphRun->bidiLevel % 2, sink ); } // Close the geometry sink if (SUCCEEDED(hr)) { hr = sink->Close(); } // Initialize a matrix to translate the origin of the glyph run. D2D1::Matrix3x2F const matrix = D2D1::Matrix3x2F( 1.0f, 0.0f, 0.0f, 1.0f, baselineOriginX, baselineOriginY ); // Create the transformed geometry ID2D1TransformedGeometry* pTransformedGeometry = nullptr; if (SUCCEEDED(hr)) { hr = d2dFactory->CreateTransformedGeometry( pPathGeometry, &matrix, &pTransformedGeometry ); } ID2D1StrokeStyle* strokeStyle = nullptr; if (SUCCEEDED(hr)) { d2dFactory->CreateStrokeStyle( D2D1::StrokeStyleProperties( D2D1_CAP_STYLE_FLAT, D2D1_CAP_STYLE_FLAT, D2D1_CAP_STYLE_SQUARE, D2D1_LINE_JOIN_BEVEL, 5.0f, D2D1_DASH_STYLE_SOLID, 0.0f ), nullptr, 0, &strokeStyle); } if (SUCCEEDED(hr)) { float strokeWidth = mState->mStateSettings.fontStrokeWidth; if (strokeWidth != 0.0f) { // Draw the outline of the glyph run renderTarget->DrawGeometry( pTransformedGeometry, mState->mBrushes[State::BrushType::TextStroke].brush, strokeWidth, strokeStyle ); } // Fill in the glyph run // This is so ugly... /*renderTarget->FillGeometry( pTransformedGeometry, mState->mBrushes[State::BrushType::Text].brush );*/ } SAFERELEASE(strokeStyle); SAFERELEASE(pPathGeometry); SAFERELEASE(sink); SAFERELEASE(pTransformedGeometry); d2dFactory->Release(); } // TODO::Figure out how to replicate the quality of D2Ds DrawGlyphRun! renderTarget->DrawGlyphRun(D2D1::Point2F(baselineOriginX, baselineOriginY), glyphRun, mState->mBrushes[State::BrushType::Text].brush, measuringMode); return hr; }
int _tmain(int argc, _TCHAR* argv[]) { HRESULT hr = S_OK; // Create a Direct2D factory. CHECKHR(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &g_pD2DFactory)); // Create a DirectWrite factory. CHECKHR(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown**>(&g_pDWriteFactory))); // Create a WIC factory IWICImagingFactory* pWICFactory = NULL; CHECKHR(CoInitialize(nullptr)); CHECKHR(CoCreateInstance(CLSID_WICImagingFactory1, nullptr, CLSCTX_INPROC_SERVER, IID_IWICImagingFactory, (LPVOID*)&pWICFactory)); // Create an IWICBitmap and RT IWICBitmap* pWICBitmap = NULL; static const UINT sc_bitmapWidth = 640; static const UINT sc_bitmapHeight = 480; CHECKHR(pWICFactory->CreateBitmap(sc_bitmapWidth, sc_bitmapHeight, GUID_WICPixelFormat32bppBGR, WICBitmapCacheOnLoad, &pWICBitmap)); // Set the render target type to D2D1_RENDER_TARGET_TYPE_DEFAULT to use software rendering. CHECKHR(g_pD2DFactory->CreateWicBitmapRenderTarget( pWICBitmap, D2D1::RenderTargetProperties(), &g_pRenderTarget)); // Create text format and a path geometry representing an hour glass. IDWriteTextFormat* pTextFormat = NULL; static const WCHAR sc_fontName[] = L"Calibri"; static const FLOAT sc_fontSize = 50; CHECKHR(g_pDWriteFactory->CreateTextFormat( sc_fontName, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, sc_fontSize, L"", //locale &pTextFormat )); CHECKHR(pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER)); CHECKHR(pTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER)); // Create a path geometry ID2D1PathGeometry* pPathGeometry = NULL; ID2D1GeometrySink* pSink = NULL; CHECKHR(g_pD2DFactory->CreatePathGeometry(&pPathGeometry)); CHECKHR(pPathGeometry->Open(&pSink)); pSink->SetFillMode(D2D1_FILL_MODE_ALTERNATE); pSink->BeginFigure( D2D1::Point2F(0, 0), D2D1_FIGURE_BEGIN_FILLED ); pSink->AddLine(D2D1::Point2F(200, 0)); pSink->AddBezier( D2D1::BezierSegment( D2D1::Point2F(150, 50), D2D1::Point2F(150, 150), D2D1::Point2F(200, 200)) ); pSink->AddLine(D2D1::Point2F(0, 200)); pSink->AddBezier( D2D1::BezierSegment( D2D1::Point2F(50, 150), D2D1::Point2F(50, 50), D2D1::Point2F(0, 0)) ); pSink->EndFigure(D2D1_FIGURE_END_CLOSED); CHECKHR(pSink->Close()); // Create GradientStopCollection ID2D1GradientStopCollection *pGradientStops = NULL; static const D2D1_GRADIENT_STOP stops[] = { { 0.f, { 0.f, 1.f, 1.f, 1.f } }, { 1.f, { 0.f, 0.f, 1.f, 1.f } }, }; CHECKHR(g_pRenderTarget->CreateGradientStopCollection( stops, ARRAYSIZE(stops), &pGradientStops )); ID2D1LinearGradientBrush* pLGBrush = NULL; ID2D1SolidColorBrush* pBlackBrush = NULL; CHECKHR(g_pRenderTarget->CreateLinearGradientBrush( D2D1::LinearGradientBrushProperties( D2D1::Point2F(100, 0), D2D1::Point2F(100, 200)), D2D1::BrushProperties(), pGradientStops, &pLGBrush )); CHECKHR(g_pRenderTarget->CreateSolidColorBrush( D2D1::ColorF(D2D1::ColorF::Black), &pBlackBrush )); // Render into the bitmap. g_pRenderTarget->BeginDraw(); g_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White)); D2D1_SIZE_F rtSize = g_pRenderTarget->GetSize(); // Set the world transform to a 45 degree rotation at the center of the render target // and write "Hello, World". g_pRenderTarget->SetTransform( D2D1::Matrix3x2F::Rotation( 45, D2D1::Point2F( rtSize.width / 2, rtSize.height / 2)) ); static const WCHAR sc_helloWorld[] = L"Hello, World!"; g_pRenderTarget->DrawText( sc_helloWorld, ARRAYSIZE(sc_helloWorld) - 1, pTextFormat, D2D1::RectF(0, 0, rtSize.width, rtSize.height), pBlackBrush); // Reset back to the identity transform. g_pRenderTarget->SetTransform(D2D1::Matrix3x2F::Translation(0, rtSize.height - 200)); g_pRenderTarget->FillGeometry(pPathGeometry, pLGBrush); g_pRenderTarget->SetTransform(D2D1::Matrix3x2F::Translation(rtSize.width - 200, 0)); g_pRenderTarget->FillGeometry(pPathGeometry, pLGBrush); CHECKHR(g_pRenderTarget->EndDraw()); // Save the image to a file. IWICStream* pStream = NULL; CHECKHR(pWICFactory->CreateStream(&pStream)); // Use InitializeFromFilename to write to a file. If there is need to write inside the memory, use InitializeFromMemory. static const WCHAR filename[] = L"output.png"; CHECKHR(pStream->InitializeFromFilename(filename, GENERIC_WRITE)); IWICBitmapEncoder* pEncoder = NULL; CHECKHR(pWICFactory->CreateEncoder(GUID_ContainerFormatPng, NULL, &pEncoder)); CHECKHR(pEncoder->Initialize(pStream, WICBitmapEncoderNoCache)); IWICBitmapFrameEncode* pFrameEncode = NULL; CHECKHR(pEncoder->CreateNewFrame(&pFrameEncode, NULL)); // Use IWICBitmapFrameEncode to encode the bitmap into the picture format you want. CHECKHR(pFrameEncode->Initialize(NULL)); CHECKHR(pFrameEncode->SetSize(sc_bitmapWidth, sc_bitmapHeight)); WICPixelFormatGUID format = GUID_WICPixelFormatDontCare; CHECKHR(pFrameEncode->SetPixelFormat(&format)); CHECKHR(pFrameEncode->WriteSource(pWICBitmap, NULL)); CHECKHR(pFrameEncode->Commit()); CHECKHR(pEncoder->Commit()); return 0; }
HRESULT DemoApp::CreateGeometries() { HRESULT hr = S_OK; if (!m_pGeometry) { IGeometryRealizationFactory *pRealizationFactory = NULL; IGeometryRealization *pRealization = NULL; ID2D1TransformedGeometry *pGeometry = NULL; ID2D1PathGeometry *pPathGeometry = NULL; ID2D1GeometrySink *pSink = NULL; float squareWidth = 0.9f * sc_boardWidth / m_numSquares; // Create the path geometry. hr = m_pD2DFactory->CreatePathGeometry(&pPathGeometry); if (SUCCEEDED(hr)) { // Write to the path geometry using the geometry sink to // create an hour glass shape. hr = pPathGeometry->Open(&pSink); } if (SUCCEEDED(hr)) { pSink->SetFillMode(D2D1_FILL_MODE_ALTERNATE); pSink->BeginFigure( D2D1::Point2F(0, 0), D2D1_FIGURE_BEGIN_FILLED ); pSink->AddLine(D2D1::Point2F(1.0f, 0)); pSink->AddBezier( D2D1::BezierSegment( D2D1::Point2F(0.75f, 0.25f), D2D1::Point2F(0.75f, 0.75f), D2D1::Point2F(1.0f, 1.0f)) ); pSink->AddLine(D2D1::Point2F(0, 1.0f)); pSink->AddBezier( D2D1::BezierSegment( D2D1::Point2F(0.25f, 0.75f), D2D1::Point2F(0.25f, 0.25f), D2D1::Point2F(0, 0)) ); pSink->EndFigure(D2D1_FIGURE_END_CLOSED); hr = pSink->Close(); } if (SUCCEEDED(hr)) { D2D1_MATRIX_3X2_F scale = D2D1::Matrix3x2F::Scale(squareWidth, squareWidth); D2D1_MATRIX_3X2_F translation = D2D1::Matrix3x2F::Translation(-squareWidth / 2, -squareWidth / 2); hr = m_pD2DFactory->CreateTransformedGeometry( pPathGeometry, scale * translation, &pGeometry ); } if (SUCCEEDED(hr)) { // Transfer the reference. m_pGeometry = pGeometry; pGeometry = NULL; } SafeRelease(&pRealizationFactory); SafeRelease(&pRealization); SafeRelease(&pGeometry); SafeRelease(&pPathGeometry); SafeRelease(&pSink); } return hr; }