2015-09-16 22:15:42 -05:00
// 7 september 2015
2015-10-09 10:17:58 -05:00
# include "uipriv_windows.h"
2015-09-16 22:15:42 -05:00
static ID2D1Factory * d2dfactory = NULL ;
HRESULT initDraw ( void )
{
D2D1_FACTORY_OPTIONS opts ;
ZeroMemory ( & opts , sizeof ( D2D1_FACTORY_OPTIONS ) ) ;
// TODO make this an option
opts . debugLevel = D2D1_DEBUG_LEVEL_NONE ;
return D2D1CreateFactory ( D2D1_FACTORY_TYPE_SINGLE_THREADED ,
& IID_ID2D1Factory ,
& opts ,
2015-09-17 09:31:22 -05:00
( void * * ) ( & d2dfactory ) ) ;
2015-09-16 22:15:42 -05:00
}
void uninitDraw ( void )
{
ID2D1Factory_Release ( d2dfactory ) ;
}
2015-09-16 22:42:24 -05:00
ID2D1HwndRenderTarget * makeHWNDRenderTarget ( HWND hwnd )
{
D2D1_RENDER_TARGET_PROPERTIES props ;
D2D1_HWND_RENDER_TARGET_PROPERTIES hprops ;
HDC dc ;
RECT r ;
ID2D1HwndRenderTarget * rt ;
2015-09-17 09:31:22 -05:00
HRESULT hr ;
2015-09-16 22:42:24 -05:00
// we need a DC for the DPI
// we *could* just use the screen DPI but why when we have a window handle and its DC has a DPI
dc = GetDC ( hwnd ) ;
if ( dc = = NULL )
logLastError ( " error getting DC to find DPI in makeHWNDRenderTarget() " ) ;
ZeroMemory ( & props , sizeof ( D2D1_RENDER_TARGET_PROPERTIES ) ) ;
props . type = D2D1_RENDER_TARGET_TYPE_DEFAULT ;
props . pixelFormat . format = DXGI_FORMAT_UNKNOWN ;
props . pixelFormat . alphaMode = D2D1_ALPHA_MODE_UNKNOWN ;
props . dpiX = GetDeviceCaps ( dc , LOGPIXELSX ) ;
props . dpiY = GetDeviceCaps ( dc , LOGPIXELSY ) ;
props . usage = D2D1_RENDER_TARGET_USAGE_NONE ;
props . minLevel = D2D1_FEATURE_LEVEL_DEFAULT ;
if ( ReleaseDC ( hwnd , dc ) = = 0 )
logLastError ( " error releasing DC for finding DPI in makeHWNDRenderTarget() " ) ;
if ( GetClientRect ( hwnd , & r ) = = 0 )
logLastError ( " error getting current size of window in makeHWNDRenderTarget() " ) ;
ZeroMemory ( & hprops , sizeof ( D2D1_HWND_RENDER_TARGET_PROPERTIES ) ) ;
hprops . hwnd = hwnd ;
hprops . pixelSize . width = r . right - r . left ;
hprops . pixelSize . height = r . bottom - r . top ;
hprops . presentOptions = D2D1_PRESENT_OPTIONS_NONE ;
2015-09-17 09:31:22 -05:00
hr = ID2D1Factory_CreateHwndRenderTarget ( d2dfactory ,
2015-09-16 22:42:24 -05:00
& props ,
& hprops ,
& rt ) ;
if ( hr ! = S_OK )
logHRESULT ( " error creating area HWND render target in makeHWNDRenderTarget() " , hr ) ;
return rt ;
}
2015-10-06 18:56:38 -05:00
struct uiDrawPath {
ID2D1PathGeometry * path ;
ID2D1GeometrySink * sink ;
BOOL inFigure ;
} ;
uiDrawPath * uiDrawNewPath ( uiDrawFillMode fillmode )
{
uiDrawPath * p ;
HRESULT hr ;
2015-10-09 10:49:57 -05:00
p = uiNew ( uiDrawPath ) ;
2015-10-06 18:56:38 -05:00
hr = ID2D1Factory_CreatePathGeometry ( d2dfactory ,
& ( p - > path ) ) ;
if ( hr ! = S_OK )
logHRESULT ( " error creating path in uiDrawNewPath() " , hr ) ;
hr = ID2D1PathGeometry_Open ( p - > path ,
& ( p - > sink ) ) ;
if ( hr ! = S_OK )
logHRESULT ( " error opening path in uiDrawNewPath() " , hr ) ;
switch ( fillmode ) {
2015-10-07 10:12:18 -05:00
case uiDrawFillModeWinding :
ID2D1GeometrySink_SetFillMode ( p - > sink ,
2015-10-06 18:56:38 -05:00
D2D1_FILL_MODE_WINDING ) ;
break ;
case uiDrawFillModeAlternate :
2015-10-07 10:12:18 -05:00
ID2D1GeometrySink_SetFillMode ( p - > sink ,
2015-10-06 18:56:38 -05:00
D2D1_FILL_MODE_ALTERNATE ) ;
break ;
}
p - > inFigure = FALSE ;
return p ;
}
void uiDrawFreePath ( uiDrawPath * p )
{
if ( p - > inFigure )
ID2D1GeometrySink_EndFigure ( p - > sink ,
D2D1_FIGURE_END_OPEN ) ;
if ( p - > sink ! = NULL )
// TODO close sink first?
ID2D1GeometrySink_Release ( p - > sink ) ;
ID2D1PathGeometry_Release ( p - > path ) ;
2015-10-09 10:49:57 -05:00
uiFree ( p ) ;
2015-10-06 18:56:38 -05:00
}
void uiDrawPathNewFigure ( uiDrawPath * p , double x , double y )
2015-09-16 22:15:42 -05:00
{
2015-10-06 18:56:38 -05:00
D2D1_POINT_2F pt ;
2015-09-17 12:10:38 -05:00
2015-10-06 18:56:38 -05:00
if ( p - > inFigure )
2015-10-07 10:12:18 -05:00
ID2D1GeometrySink_EndFigure ( p - > sink ,
2015-09-17 12:10:38 -05:00
D2D1_FIGURE_END_OPEN ) ;
2015-10-07 10:12:18 -05:00
pt . x = x ;
pt . y = y ;
2015-10-06 18:56:38 -05:00
ID2D1GeometrySink_BeginFigure ( p - > sink ,
pt ,
2015-09-17 12:10:38 -05:00
D2D1_FIGURE_BEGIN_FILLED ) ;
2015-10-06 18:56:38 -05:00
p - > inFigure = TRUE ;
2015-09-16 22:15:42 -05:00
}
2015-10-10 09:48:10 -05:00
// Direct2D arcs require a little explanation.
// An arc in Direct2D is defined by the chord between the endpoints.
// There are four possible arcs with the same two endpoints that you can draw this way.
// See https://www.youtube.com/watch?v=ATS0ANW1UxQ for a demonstration.
// There is a property rotationAngle which deals with the rotation /of the entire ellipse that forms an ellpitical arc/ - it's effectively a transformation on the arc.
// That is to say, it's NOT THE SWEEP.
// The sweep is defined by the start and end points and whether the arc is "large".
// As a result, this design does not allow for full circles or ellipses with a single arc; they have to be simulated with two.
struct arc {
double xCenter ;
double yCenter ;
double radius ;
double startAngle ;
double sweep ;
} ;
2015-10-11 06:51:14 -05:00
// this is used for the comparison below
// if it falls apart it can be changed later
# define aerMax 6 * DBL_EPSILON
2015-10-10 09:48:10 -05:00
static void drawArc ( uiDrawPath * p , struct arc * a , void ( * startFunction ) ( uiDrawPath * , double , double ) )
2015-10-07 07:07:07 -05:00
{
2015-10-10 09:48:10 -05:00
double sinx , cosx ;
double startX , startY ;
double endX , endY ;
D2D1_ARC_SEGMENT as ;
2015-10-11 06:51:14 -05:00
BOOL fullCircle ;
2015-10-07 07:07:07 -05:00
2015-10-10 09:48:10 -05:00
// as above, we can't do a full circle with one arc
// simulate it with two half-circles
2015-10-11 06:51:14 -05:00
// of course, we have a dragon: equality on floating-point values!
// I've chosen to do the AlmostEqualRelative() technique in https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
fullCircle = FALSE ;
if ( a - > sweep > ( 2 * M_PI ) ) // this part is easy
fullCircle = TRUE ;
else {
double aerDiff ;
aerDiff = fabs ( a - > sweep - ( 2 * M_PI ) ) ;
// if we got here then we know a->sweep is larger (or the same!)
fullCircle = aerDiff < = a - > sweep * aerMax ;
}
if ( fullCircle ) {
2015-10-10 09:48:10 -05:00
a - > sweep = M_PI ;
drawArc ( p , a , startFunction ) ;
a - > startAngle + = M_PI ;
drawArc ( p , a , NULL ) ;
return ;
}
// first, figure out the arc's endpoints
2015-10-07 10:12:18 -05:00
// unfortunately D2D1SinCos() is only defined on Windows 8 and newer
// the MSDN page doesn't say this, but says it requires d2d1_1.h, which is listed as only supported on Windows 8 and newer elsewhere on MSDN
// so we must use sin() and cos() and hope it's right...
2015-10-10 09:48:10 -05:00
sinx = sin ( a - > startAngle ) ;
cosx = cos ( a - > startAngle ) ;
startX = a - > xCenter + a - > radius * cosx ;
startY = a - > yCenter - a - > radius * sinx ;
sinx = sin ( a - > startAngle + a - > sweep ) ;
cosx = cos ( a - > startAngle + a - > sweep ) ;
endX = a - > xCenter + a - > radius * cosx ;
endY = a - > yCenter - a - > radius * sinx ;
// now do the initial step to get the current point to be the start point
// this is either creating a new figure, drawing a line, or (in the case of our full circle code above) doing nothing
if ( startFunction ! = NULL )
( * startFunction ) ( p , startX , startY ) ;
// now we can draw the arc
2015-10-07 07:07:07 -05:00
as . point . x = endX ;
as . point . y = endY ;
2015-10-10 09:48:10 -05:00
as . size . width = a - > radius ;
as . size . height = a - > radius ;
as . rotationAngle = 0 ; // as above, not relevant for circles
2015-10-10 08:23:44 -05:00
as . sweepDirection = D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE ;
2015-10-10 09:48:10 -05:00
if ( a - > sweep > M_PI )
2015-10-07 10:43:51 -05:00
as . arcSize = D2D1_ARC_SIZE_LARGE ;
2015-10-07 11:19:20 -05:00
else
as . arcSize = D2D1_ARC_SIZE_SMALL ;
2015-10-10 09:48:10 -05:00
ID2D1GeometrySink_AddArc ( p - > sink , & as ) ;
2015-10-07 07:07:07 -05:00
}
2015-10-09 20:51:43 -05:00
void uiDrawPathNewFigureWithArc ( uiDrawPath * p , double xCenter , double yCenter , double radius , double startAngle , double sweep )
2015-10-07 07:07:07 -05:00
{
2015-10-10 09:48:10 -05:00
struct arc a ;
a . xCenter = xCenter ;
a . yCenter = yCenter ;
a . radius = radius ;
a . startAngle = startAngle ;
a . sweep = sweep ;
drawArc ( p , & a , uiDrawPathNewFigure ) ;
2015-10-07 07:07:07 -05:00
}
2015-10-06 18:56:38 -05:00
void uiDrawPathLineTo ( uiDrawPath * p , double x , double y )
2015-09-16 22:15:42 -05:00
{
2015-10-06 18:56:38 -05:00
D2D1_POINT_2F pt ;
2015-09-17 12:10:38 -05:00
2015-10-06 18:56:38 -05:00
pt . x = x ;
pt . y = y ;
ID2D1GeometrySink_AddLine ( p - > sink , pt ) ;
2015-09-16 22:15:42 -05:00
}
2015-10-09 20:51:43 -05:00
void uiDrawPathArcTo ( uiDrawPath * p , double xCenter , double yCenter , double radius , double startAngle , double sweep )
2015-09-16 22:15:42 -05:00
{
2015-10-10 09:48:10 -05:00
struct arc a ;
a . xCenter = xCenter ;
a . yCenter = yCenter ;
a . radius = radius ;
a . startAngle = startAngle ;
a . sweep = sweep ;
drawArc ( p , & a , uiDrawPathLineTo ) ;
2015-09-16 22:15:42 -05:00
}
2015-10-06 18:56:38 -05:00
void uiDrawPathBezierTo ( uiDrawPath * p , double c1x , double c1y , double c2x , double c2y , double endX , double endY )
2015-09-16 22:15:42 -05:00
{
2015-10-06 18:56:38 -05:00
D2D1_BEZIER_SEGMENT s ;
s . point1 . x = c1x ;
s . point1 . y = c1y ;
s . point2 . x = c2x ;
s . point2 . y = c2y ;
s . point3 . x = endX ;
s . point3 . y = endY ;
ID2D1GeometrySink_AddBezier ( p - > sink , & s ) ;
2015-09-16 22:15:42 -05:00
}
2015-10-06 18:56:38 -05:00
void uiDrawPathCloseFigure ( uiDrawPath * p )
2015-09-16 22:15:42 -05:00
{
2015-10-06 18:56:38 -05:00
ID2D1GeometrySink_EndFigure ( p - > sink ,
2015-09-17 12:10:38 -05:00
D2D1_FIGURE_END_CLOSED ) ;
2015-10-06 18:56:38 -05:00
p - > inFigure = FALSE ;
}
2015-10-07 11:34:53 -05:00
void uiDrawPathAddRectangle ( uiDrawPath * p , double x , double y , double width , double height )
2015-10-06 18:56:38 -05:00
{
2015-10-07 11:34:53 -05:00
// this is the same algorithm used by cairo and Core Graphics, according to their documentations
uiDrawPathNewFigure ( p , x , y ) ;
uiDrawPathLineTo ( p , x + width , y ) ;
uiDrawPathLineTo ( p , x + width , y + height ) ;
uiDrawPathLineTo ( p , x , y + height ) ;
uiDrawPathCloseFigure ( p ) ;
2015-10-06 18:56:38 -05:00
}
void uiDrawPathEnd ( uiDrawPath * p )
{
HRESULT hr ;
2015-10-07 10:12:18 -05:00
if ( p - > inFigure ) {
ID2D1GeometrySink_EndFigure ( p - > sink ,
2015-10-06 18:56:38 -05:00
D2D1_FIGURE_END_OPEN ) ;
2015-10-07 10:12:18 -05:00
// needed for uiDrawFreePath()
p - > inFigure = FALSE ;
}
2015-10-06 18:56:38 -05:00
hr = ID2D1GeometrySink_Close ( p - > sink ) ;
if ( hr ! = S_OK )
logHRESULT ( " error closing path in uiDrawPathEnd() " , hr ) ;
ID2D1GeometrySink_Release ( p - > sink ) ;
p - > sink = NULL ;
2015-09-16 22:15:42 -05:00
}
2015-10-07 09:47:38 -05:00
struct uiDrawContext {
ID2D1RenderTarget * rt ;
} ;
uiDrawContext * newContext ( ID2D1RenderTarget * rt )
{
uiDrawContext * c ;
2015-10-09 10:49:57 -05:00
c = uiNew ( uiDrawContext ) ;
2015-10-07 09:47:38 -05:00
c - > rt = rt ;
return c ;
}
2015-10-09 11:41:01 -05:00
void freeContext ( uiDrawContext * c )
{
uiFree ( c ) ;
}
2015-10-07 09:47:38 -05:00
static ID2D1Brush * makeSolidBrush ( uiDrawBrush * b , ID2D1RenderTarget * rt , D2D1_BRUSH_PROPERTIES * props )
2015-09-16 22:15:42 -05:00
{
2015-09-17 12:10:38 -05:00
D2D1_COLOR_F color ;
ID2D1SolidColorBrush * brush ;
HRESULT hr ;
2015-09-16 22:15:42 -05:00
2015-10-07 09:47:38 -05:00
color . r = b - > R ;
color . g = b - > G ;
color . b = b - > B ;
color . a = b - > A ;
hr = ID2D1RenderTarget_CreateSolidColorBrush ( rt ,
& color ,
2015-10-07 10:12:18 -05:00
props ,
2015-10-07 09:47:38 -05:00
& brush ) ;
if ( hr ! = S_OK )
logHRESULT ( " error creating solid brush in makeSolidBrush() " , hr ) ;
return ( ID2D1Brush * ) brush ;
}
2015-10-07 15:54:56 -05:00
static ID2D1GradientStopCollection * mkstops ( uiDrawBrush * b , ID2D1RenderTarget * rt )
{
ID2D1GradientStopCollection * s ;
D2D1_GRADIENT_STOP * stops ;
size_t i ;
HRESULT hr ;
2015-10-09 10:49:57 -05:00
stops = uiAlloc ( b - > NumStops * sizeof ( D2D1_GRADIENT_STOP ) , " D2D1_GRADIENT_STOP[] " ) ;
2015-10-07 15:54:56 -05:00
for ( i = 0 ; i < b - > NumStops ; i + + ) {
stops [ i ] . position = b - > Stops [ i ] . Pos ;
stops [ i ] . color . r = b - > Stops [ i ] . R ;
stops [ i ] . color . g = b - > Stops [ i ] . G ;
stops [ i ] . color . b = b - > Stops [ i ] . B ;
stops [ i ] . color . a = b - > Stops [ i ] . A ;
}
// TODO BUG IN MINGW
// the Microsoft headers give this all 6 parameters
// the MinGW headers use the 4-parameter version
hr = ( * ( rt - > lpVtbl - > CreateGradientStopCollection ) ) ( rt ,
stops ,
b - > NumStops ,
D2D1_GAMMA_2_2 , // this is the default for the C++-only overload of ID2D1RenderTarget::GradientStopCollection()
D2D1_EXTEND_MODE_CLAMP ,
& s ) ;
if ( hr ! = S_OK )
logHRESULT ( " error creating stop collection in mkstops() " , hr ) ;
2015-10-09 10:49:57 -05:00
uiFree ( stops ) ;
2015-10-07 15:54:56 -05:00
return s ;
}
2015-10-07 09:47:38 -05:00
static ID2D1Brush * makeLinearBrush ( uiDrawBrush * b , ID2D1RenderTarget * rt , D2D1_BRUSH_PROPERTIES * props )
{
2015-10-07 15:54:56 -05:00
ID2D1LinearGradientBrush * brush ;
D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES gprops ;
ID2D1GradientStopCollection * stops ;
HRESULT hr ;
ZeroMemory ( & gprops , sizeof ( D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES ) ) ;
gprops . startPoint . x = b - > X0 ;
gprops . startPoint . y = b - > Y0 ;
gprops . endPoint . x = b - > X1 ;
gprops . endPoint . y = b - > Y1 ;
stops = mkstops ( b , rt ) ;
hr = ID2D1RenderTarget_CreateLinearGradientBrush ( rt ,
& gprops ,
props ,
stops ,
& brush ) ;
if ( hr ! = S_OK )
logHRESULT ( " error creating gradient brush in makeLinearBrush() " , hr ) ;
// the example at https://msdn.microsoft.com/en-us/library/windows/desktop/dd756682%28v=vs.85%29.aspx says this is safe to do now
ID2D1GradientStopCollection_Release ( stops ) ;
return ( ID2D1Brush * ) brush ;
2015-10-07 09:47:38 -05:00
}
static ID2D1Brush * makeRadialBrush ( uiDrawBrush * b , ID2D1RenderTarget * rt , D2D1_BRUSH_PROPERTIES * props )
{
2015-10-07 17:32:55 -05:00
ID2D1RadialGradientBrush * brush ;
D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES gprops ;
ID2D1GradientStopCollection * stops ;
HRESULT hr ;
ZeroMemory ( & gprops , sizeof ( D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES ) ) ;
gprops . gradientOriginOffset . x = b - > X0 - b - > X1 ;
gprops . gradientOriginOffset . y = b - > Y0 - b - > Y1 ;
gprops . center . x = b - > X1 ;
gprops . center . y = b - > Y1 ;
gprops . radiusX = b - > OuterRadius ;
gprops . radiusY = b - > OuterRadius ;
stops = mkstops ( b , rt ) ;
hr = ID2D1RenderTarget_CreateRadialGradientBrush ( rt ,
& gprops ,
props ,
stops ,
& brush ) ;
if ( hr ! = S_OK )
logHRESULT ( " error creating gradient brush in makeRadialBrush() " , hr ) ;
ID2D1GradientStopCollection_Release ( stops ) ;
return ( ID2D1Brush * ) brush ;
2015-10-07 09:47:38 -05:00
}
static ID2D1Brush * makeBrush ( uiDrawBrush * b , ID2D1RenderTarget * rt )
{
D2D1_BRUSH_PROPERTIES props ;
2015-09-16 22:15:42 -05:00
2015-09-17 12:10:38 -05:00
ZeroMemory ( & props , sizeof ( D2D1_BRUSH_PROPERTIES ) ) ;
props . opacity = 1.0 ;
// identity matrix
props . transform . _11 = 1 ;
props . transform . _22 = 1 ;
2015-09-16 22:15:42 -05:00
2015-10-07 09:47:38 -05:00
switch ( b - > Type ) {
case uiDrawBrushTypeSolid :
return makeSolidBrush ( b , rt , & props ) ;
2015-10-07 15:54:56 -05:00
case uiDrawBrushTypeLinearGradient :
return makeLinearBrush ( b , rt , & props ) ;
2015-10-07 17:32:55 -05:00
case uiDrawBrushTypeRadialGradient :
return makeRadialBrush ( b , rt , & props ) ;
2015-10-07 09:47:38 -05:00
// case uiDrawBrushTypeImage:
// TODO
}
2015-10-09 10:49:57 -05:00
complain ( " invalid brush type %d in makeBrush() " , b - > Type ) ;
2015-10-07 09:47:38 -05:00
return NULL ; // make compiler happy
2015-09-16 22:15:42 -05:00
}
2015-10-07 09:47:38 -05:00
void uiDrawStroke ( uiDrawContext * c , uiDrawPath * p , uiDrawBrush * b , uiDrawStrokeParams * sp )
2015-09-16 22:15:42 -05:00
{
2015-10-07 09:47:38 -05:00
ID2D1Brush * brush ;
2015-10-07 12:05:48 -05:00
ID2D1StrokeStyle * style ;
D2D1_STROKE_STYLE_PROPERTIES dsp ;
HRESULT hr ;
2015-09-16 22:15:42 -05:00
2015-10-07 09:47:38 -05:00
brush = makeBrush ( b , c - > rt ) ;
2015-10-07 12:05:48 -05:00
ZeroMemory ( & dsp , sizeof ( D2D1_STROKE_STYLE_PROPERTIES ) ) ;
switch ( sp - > Cap ) {
case uiDrawLineCapFlat :
dsp . startCap = D2D1_CAP_STYLE_FLAT ;
dsp . endCap = D2D1_CAP_STYLE_FLAT ;
dsp . dashCap = D2D1_CAP_STYLE_FLAT ;
break ;
case uiDrawLineCapRound :
dsp . startCap = D2D1_CAP_STYLE_ROUND ;
dsp . endCap = D2D1_CAP_STYLE_ROUND ;
dsp . dashCap = D2D1_CAP_STYLE_ROUND ;
break ;
case uiDrawLineCapSquare :
dsp . startCap = D2D1_CAP_STYLE_SQUARE ;
dsp . endCap = D2D1_CAP_STYLE_SQUARE ;
dsp . dashCap = D2D1_CAP_STYLE_SQUARE ;
break ;
}
switch ( sp - > Join ) {
case uiDrawLineJoinMiter :
dsp . lineJoin = D2D1_LINE_JOIN_MITER_OR_BEVEL ;
dsp . miterLimit = sp - > MiterLimit ;
break ;
case uiDrawLineJoinRound :
dsp . lineJoin = D2D1_LINE_JOIN_ROUND ;
break ;
case uiDrawLineJoinBevel :
dsp . lineJoin = D2D1_LINE_JOIN_BEVEL ;
break ;
}
dsp . dashStyle = D2D1_DASH_STYLE_SOLID ;
dsp . dashOffset = 0 ;
hr = ID2D1Factory_CreateStrokeStyle ( d2dfactory ,
& dsp ,
NULL ,
0 ,
& style ) ;
if ( hr ! = S_OK )
logHRESULT ( " error creating stroke style in uiDrawStroke() " , hr ) ;
2015-09-17 12:10:38 -05:00
ID2D1RenderTarget_DrawGeometry ( c - > rt ,
2015-10-07 09:47:38 -05:00
( ID2D1Geometry * ) ( p - > path ) ,
brush ,
sp - > Thickness ,
2015-10-07 12:05:48 -05:00
style ) ;
ID2D1StrokeStyle_Release ( style ) ;
2015-10-07 09:47:38 -05:00
ID2D1Brush_Release ( brush ) ;
2015-09-16 22:15:42 -05:00
}
2015-10-07 09:47:38 -05:00
void uiDrawFill ( uiDrawContext * c , uiDrawPath * p , uiDrawBrush * b )
2015-09-16 22:15:42 -05:00
{
2015-10-07 09:47:38 -05:00
ID2D1Brush * brush ;
2015-09-17 12:10:38 -05:00
2015-10-07 09:47:38 -05:00
brush = makeBrush ( b , c - > rt ) ;
2015-09-17 12:10:38 -05:00
ID2D1RenderTarget_FillGeometry ( c - > rt ,
2015-10-07 09:47:38 -05:00
( ID2D1Geometry * ) ( p - > path ) ,
brush ,
2015-09-17 12:10:38 -05:00
NULL ) ;
2015-10-07 09:47:38 -05:00
ID2D1Brush_Release ( brush ) ;
2015-09-16 22:15:42 -05:00
}