Modified wxGraphicsPath concatenation (with AddPath) for Direct2D renderer.
Because wxGraphicsPath comprises current ID2D1PathGeometry object and the collection of transformed (sub-)geometries (ID2D1TransformedGeometry objects) so to concatenate two paths we need to concatenate their current geometries as well as to combine the collections of transformed geometries.
This commit is contained in:
@@ -98,6 +98,8 @@ public:
|
|||||||
/**
|
/**
|
||||||
Adds another path onto the current path. After this call the current
|
Adds another path onto the current path. After this call the current
|
||||||
point will be at the added path's current point.
|
point will be at the added path's current point.
|
||||||
|
For Direct2D the path being appended shouldn't contain
|
||||||
|
a started non-empty subpath when this function is called.
|
||||||
*/
|
*/
|
||||||
virtual void AddPath(const wxGraphicsPath& path);
|
virtual void AddPath(const wxGraphicsPath& path);
|
||||||
|
|
||||||
|
@@ -1059,6 +1059,7 @@ private:
|
|||||||
|
|
||||||
ID2D1Geometry* GetFullGeometry() const;
|
ID2D1Geometry* GetFullGeometry() const;
|
||||||
|
|
||||||
|
bool IsEmpty() const;
|
||||||
bool IsStateSafeForFlush() const;
|
bool IsStateSafeForFlush() const;
|
||||||
|
|
||||||
struct GeometryStateData
|
struct GeometryStateData
|
||||||
@@ -1284,6 +1285,12 @@ ID2D1Geometry* wxD2DPathData::GetFullGeometry() const
|
|||||||
return m_combinedGeometry;
|
return m_combinedGeometry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool wxD2DPathData::IsEmpty() const
|
||||||
|
{
|
||||||
|
return !m_currentPointSet && !m_figureOpened &&
|
||||||
|
m_pTransformedGeometries.size() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool wxD2DPathData::IsStateSafeForFlush() const
|
bool wxD2DPathData::IsStateSafeForFlush() const
|
||||||
{
|
{
|
||||||
// Only geometry with not yet started figure
|
// Only geometry with not yet started figure
|
||||||
@@ -1493,61 +1500,87 @@ void wxD2DPathData::GetCurrentPoint(wxDouble* x, wxDouble* y) const
|
|||||||
// adds another path
|
// adds another path
|
||||||
void wxD2DPathData::AddPath(const wxGraphicsPathData* path)
|
void wxD2DPathData::AddPath(const wxGraphicsPathData* path)
|
||||||
{
|
{
|
||||||
wxD2DPathData* d2dPath =
|
wxD2DPathData* pathSrc =
|
||||||
const_cast<wxD2DPathData*>(static_cast<const wxD2DPathData*>(path));
|
const_cast<wxD2DPathData*>(static_cast<const wxD2DPathData*>(path));
|
||||||
|
|
||||||
// Nothing to do if geometry of appended path is not initialized.
|
// Nothing to do if geometry of appended path is not initialized.
|
||||||
if ( d2dPath->m_pathGeometry == NULL || d2dPath->m_geometrySink == NULL )
|
if ( pathSrc->m_pathGeometry == NULL || pathSrc->m_geometrySink == NULL )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Close current sub-path (leaving the figure as is).
|
// Because only closed geometry (with closed sink)
|
||||||
EndFigure(D2D1_FIGURE_END_OPEN);
|
|
||||||
|
|
||||||
// Because only geometry with closed sink (immutable)
|
|
||||||
// can be transferred to another geometry object with
|
// can be transferred to another geometry object with
|
||||||
// ID2D1PathGeometry::Stream() so we have to make
|
// ID2D1PathGeometry::Stream() so we have to close it
|
||||||
// a writable copy of the appended geometry
|
// before any operation and to re-open afterwards.
|
||||||
// and re-assign it to the source path after actual appending.
|
// Unfortunately, to close the sink it is also necessary
|
||||||
|
// to end the figure it contains, if it was open.
|
||||||
|
// After re-opening the geometry we should also re-start
|
||||||
|
// the figure (if it was open) and restore its state but
|
||||||
|
// it seems there is no straightforward way to do so
|
||||||
|
// if the figure is not empty.
|
||||||
|
//
|
||||||
|
// So, only if appended path has a sub-path closed or
|
||||||
|
// has an empty sub-path open there is possible to restore
|
||||||
|
// its state after appending it to the current path and only
|
||||||
|
// in this case the operation doesn't introduce side effects.
|
||||||
|
|
||||||
|
// Nothing to do if appended path is empty.
|
||||||
|
if ( pathSrc->IsEmpty() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Save positional and auxiliary data
|
||||||
|
// of the appended path and its geometry.
|
||||||
|
GeometryStateData curStateSrc;
|
||||||
|
pathSrc->SaveGeometryState(curStateSrc);
|
||||||
|
|
||||||
|
// Raise warning if appended path has an open non-empty sub-path.
|
||||||
|
wxASSERT_MSG( pathSrc->IsStateSafeForFlush(),
|
||||||
|
wxS("Sub-path in appended path should be closed prior to this operation") );
|
||||||
|
// Close appended geometry.
|
||||||
|
pathSrc->Flush();
|
||||||
|
|
||||||
|
// Close current geometry (leaving the figure as is).
|
||||||
|
Flush();
|
||||||
|
|
||||||
// Close appended geometry sink.
|
|
||||||
d2dPath->EndFigure(D2D1_FIGURE_END_OPEN);
|
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
hr = d2dPath->m_geometrySink->Close();
|
ID2D1TransformedGeometry* pTransformedGeometry = NULL;
|
||||||
wxFAILED_HRESULT_MSG(hr);
|
// Add current geometry to the collection transformed geometries.
|
||||||
|
hr = m_direct2dfactory->CreateTransformedGeometry(m_pathGeometry,
|
||||||
|
D2D1::Matrix3x2F::Identity(), &pTransformedGeometry);
|
||||||
|
wxCHECK_HRESULT_RET(hr);
|
||||||
|
m_pTransformedGeometries.push_back(pTransformedGeometry);
|
||||||
|
|
||||||
// Transfer appended geometry to the current geometry sink.
|
// Add to the collection transformed geometries from the appended path.
|
||||||
hr = d2dPath->m_pathGeometry->Stream(m_geometrySink);
|
for ( size_t i = 0; i < pathSrc->m_pTransformedGeometries.size(); i++ )
|
||||||
wxFAILED_HRESULT_MSG(hr);
|
|
||||||
// Copy auxiliary data if appended path is non-empty.
|
|
||||||
UINT32 segCount = 0;
|
|
||||||
UINT32 figCount = 0;
|
|
||||||
hr = d2dPath->m_pathGeometry->GetSegmentCount(&segCount);
|
|
||||||
wxFAILED_HRESULT_MSG(hr);
|
|
||||||
hr = d2dPath->m_pathGeometry->GetFigureCount(&figCount);
|
|
||||||
wxFAILED_HRESULT_MSG(hr);
|
|
||||||
if( segCount > 0 || figCount > 0 || d2dPath->m_currentPointSet || d2dPath->m_figureOpened )
|
|
||||||
{
|
{
|
||||||
m_currentPointSet = d2dPath->m_currentPointSet;
|
pTransformedGeometry = NULL;
|
||||||
m_currentPoint = d2dPath->m_currentPoint;
|
hr = m_direct2dfactory->CreateTransformedGeometry(
|
||||||
m_figureOpened = d2dPath->m_figureOpened;
|
pathSrc->m_pTransformedGeometries[i],
|
||||||
m_figureStart = d2dPath->m_figureStart;
|
D2D1::Matrix3x2F::Identity(), &pTransformedGeometry);
|
||||||
|
wxCHECK_HRESULT_RET(hr);
|
||||||
|
m_pTransformedGeometries.push_back(pTransformedGeometry);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a writable copy of the appended geometry.
|
// Clear and reopen current geometry.
|
||||||
wxCOMPtr<ID2D1PathGeometry> srcPathGeometry;
|
m_pathGeometry.reset();
|
||||||
wxCOMPtr<ID2D1GeometrySink> srcGeometrySink;
|
EnsureGeometryOpen();
|
||||||
hr = m_direct2dfactory->CreatePathGeometry(&srcPathGeometry);
|
|
||||||
wxFAILED_HRESULT_MSG(hr);
|
|
||||||
hr = srcPathGeometry->Open(&srcGeometrySink);
|
|
||||||
wxFAILED_HRESULT_MSG(hr);
|
|
||||||
// Transfer appended geometry.
|
|
||||||
hr = d2dPath->m_pathGeometry->Stream(srcGeometrySink);
|
|
||||||
wxFAILED_HRESULT_MSG(hr);
|
|
||||||
|
|
||||||
// Assign a writable copy of the appendeed
|
// Transfer appended geometry to the current geometry sink.
|
||||||
// geometry back to the source path.
|
hr = pathSrc->m_pathGeometry->Stream(m_geometrySink);
|
||||||
d2dPath->m_pathGeometry = srcPathGeometry;
|
wxCHECK_HRESULT_RET(hr);
|
||||||
d2dPath->m_geometrySink = srcGeometrySink;
|
|
||||||
|
// Apply to the current path positional data from the appended path.
|
||||||
|
// This operation fully sets geometry to the required state
|
||||||
|
// only if it represents geometry without started figure
|
||||||
|
// or with started but empty figure.
|
||||||
|
RestoreGeometryState(curStateSrc);
|
||||||
|
|
||||||
|
// Reopen appended geometry.
|
||||||
|
pathSrc->EnsureGeometryOpen();
|
||||||
|
// Restore its positional data.
|
||||||
|
// This operation fully restores geometry to the required state
|
||||||
|
// only if it represents geometry without started figure
|
||||||
|
// or with started but empty figure.
|
||||||
|
pathSrc->RestoreGeometryState(curStateSrc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// closes the current sub-path
|
// closes the current sub-path
|
||||||
|
Reference in New Issue
Block a user