bool
BPolygon::_AddPoints(const BPoint* points, int32 count, bool computeBounds)
{
	if (points == NULL || count <= 0)
		return false;
	if (count > MAX_POINT_COUNT || (fCount + count) > MAX_POINT_COUNT) {
		fprintf(stderr, "BPolygon::_AddPoints(%" B_PRId32 ") - too many points"
			"\n", count);
		return false;
	}

	BPoint* newPoints = (BPoint*)realloc(fPoints, (fCount + count)
		* sizeof(BPoint));
	if (newPoints == NULL) {
		fprintf(stderr, "BPolygon::_AddPoints(%" B_PRId32 ") out of memory\n",
			count);
		return false;
	}

	fPoints = newPoints;
	memcpy(fPoints + fCount, points, count * sizeof(BPoint));
	fCount += count;

	if (computeBounds)
		_ComputeBounds();

	return true;
}
void VGraphicPath::SetPosBy(GReal inHoriz, GReal inVert)
{
#if !GRAPHIC_MIXED_GDIPLUS_D2D
	if (!VWinD2DGraphicContext::IsAvailable())
	{
#endif
		Gdiplus::Matrix matrix;
		matrix.Translate(inHoriz, inVert);
		fPath->Transform(&matrix);
#if !GRAPHIC_MIXED_GDIPLUS_D2D
	}
#endif

#if ENABLE_D2D
	if (VWinD2DGraphicContext::IsAvailable() && fPathD2D)
	{
		End();
		
		VAffineTransform mat;
		mat.SetTranslation( inHoriz, inVert);
		D2D1_MATRIX_3X2_F matNative;
		mat.ToNativeMatrix((D2D_MATRIX_REF)&matNative);

		ID2D1Geometry *sourcePath = fPathD2D;
		
		ID2D1TransformedGeometry *thisPath = NULL;
		VWinD2DGraphicContext::GetMutexFactory().Lock();
		bool ok = SUCCEEDED(VWinD2DGraphicContext::GetFactory()->CreateTransformedGeometry( sourcePath, &matNative, &thisPath));
		VWinD2DGraphicContext::GetMutexFactory().Unlock();
		xbox_assert(ok);
		if (ok)
		{
			fPathD2D = thisPath;
			sourcePath->Release();
		}
		else 
			return;
	}
#endif

	fPolygon.SetPosBy(inHoriz, inVert);

	if (fComputeBoundsAccurate)
	{
		VPoint translate( (SmallReal)inHoriz, (SmallReal)inVert);

		if (fPathMin != GP_BOUNDS_MIN_DEFAULT)
			fPathMin += translate;
		if (fPathMax != GP_BOUNDS_MAX_DEFAULT)
			fPathMax += translate;
	}
	_ComputeBounds();

	if (fCreateStorageForCrispEdges)
	{
		fDrawCmds.push_back( VGraphicPathDrawCmd( GPDCT_SET_POS_BY, inHoriz, inVert));
		fCurTransform.Translate( inHoriz, inVert, VAffineTransform::MatrixOrderAppend);
	}
}
void VGraphicPath::AddOval(const VRect& inBounds)
{
#if !GRAPHIC_MIXED_GDIPLUS_D2D
	if (!VWinD2DGraphicContext::IsAvailable())
	{
#endif
		Gdiplus::RectF rect(inBounds.GetLeft(), inBounds.GetTop(), inBounds.GetWidth(), inBounds.GetHeight());
		fPath->AddEllipse(rect);
#if !GRAPHIC_MIXED_GDIPLUS_D2D
	}
#endif

#if ENABLE_D2D
	if (VWinD2DGraphicContext::IsAvailable())
	{
		if (!fGeomSink)
		{
			Begin();
			if (!fGeomSink)
				return;
		}

		if (!fFigureIsClosed)
			fGeomSink->EndFigure( D2D1_FIGURE_END_OPEN);
		fFigureIsClosed = true;

		GReal radiusX = inBounds.GetWidth()*0.5f;
		GReal radiusY = inBounds.GetHeight()*0.5f;
		D2D1_POINT_2F center = D2D1::Point2F( inBounds.GetLeft()+radiusX, inBounds.GetTop()+radiusY);
		D2D1_POINT_2F s = D2D1::Point2F(center.x-radiusX, center.y);
		D2D1_POINT_2F d = D2D1::Point2F(center.x+radiusX, center.y);

		fGeomSink->BeginFigure( s, D2D1_FIGURE_BEGIN_FILLED);
		fGeomSink->AddArc( D2D1::ArcSegment( d, D2D1::SizeF(radiusX, radiusY), 0.0f, D2D1_SWEEP_DIRECTION_CLOCKWISE, D2D1_ARC_SIZE_SMALL));
		fGeomSink->AddArc( D2D1::ArcSegment( s, D2D1::SizeF(radiusX, radiusY), 0.0f, D2D1_SWEEP_DIRECTION_CLOCKWISE, D2D1_ARC_SIZE_SMALL));
		fGeomSink->EndFigure( D2D1_FIGURE_END_OPEN);
	}
#endif

	fPolygon.AddPoint(inBounds.GetTopLeft());
	fPolygon.AddPoint(inBounds.GetTopRight());
	fPolygon.AddPoint(inBounds.GetBotRight());
	fPolygon.AddPoint(inBounds.GetBotLeft());

	if (fComputeBoundsAccurate)
		_addRectToBounds( inBounds);
	_ComputeBounds();

	if (fCreateStorageForCrispEdges)
		fDrawCmds.push_back( VGraphicPathDrawCmd( GPDCT_ADD_OVAL, inBounds));
}
void VGraphicPath::End()
{
#if ENABLE_D2D
	if (fGeomSink)
	{
		if (!fFigureIsClosed)
			fGeomSink->EndFigure( D2D1_FIGURE_END_OPEN);
		fFigureIsClosed = true;
		fGeomSink->Close();
		fGeomSink->Release();
		fGeomSink = NULL;
		_ComputeBounds();
	}
#endif
}
void VGraphicPath::AddBezierTo(const VPoint& inStartControl, const VPoint& inDestPoint, const VPoint& inDestControl)
{
#if !GRAPHIC_MIXED_GDIPLUS_D2D
	if (!VWinD2DGraphicContext::IsAvailable())
	{
#endif
		Gdiplus::PointF d = Gdiplus::PointF(inDestPoint.GetX(), inDestPoint.GetY());
		Gdiplus::PointF c1 = Gdiplus::PointF(inStartControl.GetX(), inStartControl.GetY());
		Gdiplus::PointF c2 = Gdiplus::PointF(inDestControl.GetX(), inDestControl.GetY());
		
		fPath->AddBezier(Gdiplus::PointF(fLastPoint.x,fLastPoint.y), c1, c2, d);
		fLastPoint.x = d.X;
		fLastPoint.y = d.Y;
#if !GRAPHIC_MIXED_GDIPLUS_D2D
	}
#endif

#if ENABLE_D2D
	if (VWinD2DGraphicContext::IsAvailable())
	{
		if (!fGeomSink)
		{
			Begin();
			if (!fGeomSink)
				return;
		}

		D2D1_POINT_2F c1 = D2D1::Point2F(inStartControl.GetX(), inStartControl.GetY());
		D2D1_POINT_2F c2 = D2D1::Point2F(inDestControl.GetX(), inDestControl.GetY());
		D2D1_POINT_2F d = D2D1::Point2F(inDestPoint.GetX(), inDestPoint.GetY());

		fGeomSink->AddBezier( D2D1::BezierSegment(c1, c2, d));
	}
#endif

	fPolygon.AddPoint(inDestPoint);

	if (fComputeBoundsAccurate)
		_addBezierToBounds( inStartControl, inDestControl, inDestPoint);
	_ComputeBounds();

	fHasBezier = true;
	if (fCreateStorageForCrispEdges)
		fDrawCmds.push_back( VGraphicPathDrawCmd( GPDCT_ADD_BEZIER_TO, inStartControl, inDestPoint, inDestControl));
}
void VGraphicPath::BeginSubPathAt(const VPoint& inLocalPoint)
{
#if !GRAPHIC_MIXED_GDIPLUS_D2D
	if (!VWinD2DGraphicContext::IsAvailable())
	{
#endif
		fLastPoint = VPoint((GReal)inLocalPoint.GetX(), (GReal)inLocalPoint.GetY());
		fPath->StartFigure();
#if !GRAPHIC_MIXED_GDIPLUS_D2D
	}
#endif

#if ENABLE_D2D
	if (VWinD2DGraphicContext::IsAvailable())
	{
		if (!fGeomSink)
		{
			Begin();
			if (!fGeomSink)
				return;
		}

		if (!fFigureIsClosed)
			//do not forget to close current figure before opening new figure to prevent really nasty artifacts...
			fGeomSink->EndFigure( D2D1_FIGURE_END_OPEN);
		fGeomSink->BeginFigure( D2D1::Point2F( inLocalPoint.GetX(), inLocalPoint.GetY()),
								   D2D1_FIGURE_BEGIN_FILLED);
		fFigureIsClosed = false;
	}
#endif

	fPolygon.AddPoint(inLocalPoint);

	if (fComputeBoundsAccurate)
		_addPointToBounds( inLocalPoint);
	_ComputeBounds();

	if (fCreateStorageForCrispEdges)
		fDrawCmds.push_back( VGraphicPathDrawCmd( GPDCT_BEGIN_SUBPATH_AT, inLocalPoint));
}
void VGraphicPath::AddLineTo(const VPoint& inDestPoint)
{
#if !GRAPHIC_MIXED_GDIPLUS_D2D
	if (!VWinD2DGraphicContext::IsAvailable())
	{
#endif
		Gdiplus::PointF d = Gdiplus::PointF(inDestPoint.GetX(), inDestPoint.GetY());
		fPath->AddLine(Gdiplus::PointF(fLastPoint.x,fLastPoint.y), d);
		fLastPoint.x = d.X;
		fLastPoint.y = d.Y;
#if !GRAPHIC_MIXED_GDIPLUS_D2D
	}
#endif

#if ENABLE_D2D
	if (VWinD2DGraphicContext::IsAvailable())
	{
		if (!fGeomSink)
		{
			Begin();
			if (!fGeomSink)
				return;
		}

		fGeomSink->AddLine( D2D1::Point2F( inDestPoint.GetX(), inDestPoint.GetY()));
	}
#endif

	fPolygon.AddPoint(inDestPoint);

	if (fComputeBoundsAccurate)
		_addPointToBounds( inDestPoint);
	_ComputeBounds();

	if (fCreateStorageForCrispEdges)
		fDrawCmds.push_back( VGraphicPathDrawCmd( GPDCT_ADD_LINE_TO, inDestPoint));
}