Mostly migrated draw.c.
This commit is contained in:
parent
a8b6cab2ab
commit
2c097f5587
|
@ -1,5 +1,5 @@
|
||||||
// 7 september 2015
|
// 7 september 2015
|
||||||
#include "uipriv_windows.h"
|
#include "uipriv_windows.hpp"
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
// - write a test for transform followed by clip and clip followed by transform to make sure they work the same as on gtk+ and cocoa
|
// - write a test for transform followed by clip and clip followed by transform to make sure they work the same as on gtk+ and cocoa
|
||||||
|
@ -21,7 +21,7 @@ HRESULT initDraw(void)
|
||||||
|
|
||||||
void uninitDraw(void)
|
void uninitDraw(void)
|
||||||
{
|
{
|
||||||
ID2D1Factory_Release(d2dfactory);
|
d2dfactory->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
ID2D1HwndRenderTarget *makeHWNDRenderTarget(HWND hwnd)
|
ID2D1HwndRenderTarget *makeHWNDRenderTarget(HWND hwnd)
|
||||||
|
@ -37,7 +37,7 @@ ID2D1HwndRenderTarget *makeHWNDRenderTarget(HWND hwnd)
|
||||||
// we *could* just use the screen DPI but why when we have a window handle and its DC has a 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);
|
dc = GetDC(hwnd);
|
||||||
if (dc == NULL)
|
if (dc == NULL)
|
||||||
logLastError("error getting DC to find DPI in makeHWNDRenderTarget()");
|
logLastError(L"error getting DC to find DPI");
|
||||||
|
|
||||||
ZeroMemory(&props, sizeof (D2D1_RENDER_TARGET_PROPERTIES));
|
ZeroMemory(&props, sizeof (D2D1_RENDER_TARGET_PROPERTIES));
|
||||||
props.type = D2D1_RENDER_TARGET_TYPE_DEFAULT;
|
props.type = D2D1_RENDER_TARGET_TYPE_DEFAULT;
|
||||||
|
@ -49,10 +49,10 @@ ID2D1HwndRenderTarget *makeHWNDRenderTarget(HWND hwnd)
|
||||||
props.minLevel = D2D1_FEATURE_LEVEL_DEFAULT;
|
props.minLevel = D2D1_FEATURE_LEVEL_DEFAULT;
|
||||||
|
|
||||||
if (ReleaseDC(hwnd, dc) == 0)
|
if (ReleaseDC(hwnd, dc) == 0)
|
||||||
logLastError("error releasing DC for finding DPI in makeHWNDRenderTarget()");
|
logLastError(L"error releasing DC for finding DPI");
|
||||||
|
|
||||||
if (GetClientRect(hwnd, &r) == 0)
|
if (GetClientRect(hwnd, &r) == 0)
|
||||||
logLastError("error getting current size of window in makeHWNDRenderTarget()");
|
logLastError(L"error getting current size of window");
|
||||||
|
|
||||||
ZeroMemory(&hprops, sizeof (D2D1_HWND_RENDER_TARGET_PROPERTIES));
|
ZeroMemory(&hprops, sizeof (D2D1_HWND_RENDER_TARGET_PROPERTIES));
|
||||||
hprops.hwnd = hwnd;
|
hprops.hwnd = hwnd;
|
||||||
|
@ -61,12 +61,12 @@ ID2D1HwndRenderTarget *makeHWNDRenderTarget(HWND hwnd)
|
||||||
// according to Rick Brewster, some drivers will misbehave if we don't specify this (see http://stackoverflow.com/a/33222983/3408572)
|
// according to Rick Brewster, some drivers will misbehave if we don't specify this (see http://stackoverflow.com/a/33222983/3408572)
|
||||||
hprops.presentOptions = D2D1_PRESENT_OPTIONS_RETAIN_CONTENTS;
|
hprops.presentOptions = D2D1_PRESENT_OPTIONS_RETAIN_CONTENTS;
|
||||||
|
|
||||||
hr = ID2D1Factory_CreateHwndRenderTarget(d2dfactory,
|
hr = d2dfactory->CreateHwndRenderTarget(
|
||||||
&props,
|
&props,
|
||||||
&hprops,
|
&hprops,
|
||||||
&rt);
|
&rt);
|
||||||
if (hr != S_OK)
|
if (hr != S_OK)
|
||||||
logHRESULT("error creating area HWND render target in makeHWNDRenderTarget()", hr);
|
logHRESULT(L"error creating area HWND render target", hr);
|
||||||
return rt;
|
return rt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,22 +82,18 @@ uiDrawPath *uiDrawNewPath(uiDrawFillMode fillmode)
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
p = uiNew(uiDrawPath);
|
p = uiNew(uiDrawPath);
|
||||||
hr = ID2D1Factory_CreatePathGeometry(d2dfactory,
|
hr = d2dfactory->CreatePathGeometry(&(p->path));
|
||||||
&(p->path));
|
|
||||||
if (hr != S_OK)
|
if (hr != S_OK)
|
||||||
logHRESULT("error creating path in uiDrawNewPath()", hr);
|
logHRESULT(L"error creating path", hr);
|
||||||
hr = ID2D1PathGeometry_Open(p->path,
|
hr = p->path->Open(&(p->sink));
|
||||||
&(p->sink));
|
|
||||||
if (hr != S_OK)
|
if (hr != S_OK)
|
||||||
logHRESULT("error opening path in uiDrawNewPath()", hr);
|
logHRESULT(L"error opening path", hr);
|
||||||
switch (fillmode) {
|
switch (fillmode) {
|
||||||
case uiDrawFillModeWinding:
|
case uiDrawFillModeWinding:
|
||||||
ID2D1GeometrySink_SetFillMode(p->sink,
|
p->sink->SetFillMode(D2D1_FILL_MODE_WINDING);
|
||||||
D2D1_FILL_MODE_WINDING);
|
|
||||||
break;
|
break;
|
||||||
case uiDrawFillModeAlternate:
|
case uiDrawFillModeAlternate:
|
||||||
ID2D1GeometrySink_SetFillMode(p->sink,
|
p->sink->SetFillMode(D2D1_FILL_MODE_ALTERNATE);
|
||||||
D2D1_FILL_MODE_ALTERNATE);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
|
@ -106,12 +102,11 @@ uiDrawPath *uiDrawNewPath(uiDrawFillMode fillmode)
|
||||||
void uiDrawFreePath(uiDrawPath *p)
|
void uiDrawFreePath(uiDrawPath *p)
|
||||||
{
|
{
|
||||||
if (p->inFigure)
|
if (p->inFigure)
|
||||||
ID2D1GeometrySink_EndFigure(p->sink,
|
p->sink->EndFigure(D2D1_FIGURE_END_OPEN);
|
||||||
D2D1_FIGURE_END_OPEN);
|
|
||||||
if (p->sink != NULL)
|
if (p->sink != NULL)
|
||||||
// TODO close sink first?
|
// TODO close sink first?
|
||||||
ID2D1GeometrySink_Release(p->sink);
|
p->sink->Release();
|
||||||
ID2D1PathGeometry_Release(p->path);
|
p->path->Release();
|
||||||
uiFree(p);
|
uiFree(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,13 +115,10 @@ void uiDrawPathNewFigure(uiDrawPath *p, double x, double y)
|
||||||
D2D1_POINT_2F pt;
|
D2D1_POINT_2F pt;
|
||||||
|
|
||||||
if (p->inFigure)
|
if (p->inFigure)
|
||||||
ID2D1GeometrySink_EndFigure(p->sink,
|
p-sink->EndFigure(D2D1_FIGURE_END_OPEN);
|
||||||
D2D1_FIGURE_END_OPEN);
|
|
||||||
pt.x = x;
|
pt.x = x;
|
||||||
pt.y = y;
|
pt.y = y;
|
||||||
ID2D1GeometrySink_BeginFigure(p->sink,
|
p->sink->BeginFigure(pt, D2D1_FIGURE_BEGIN_FILLED);
|
||||||
pt,
|
|
||||||
D2D1_FIGURE_BEGIN_FILLED);
|
|
||||||
p->inFigure = TRUE;
|
p->inFigure = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,7 +218,7 @@ static void drawArc(uiDrawPath *p, struct arc *a, void (*startFunction)(uiDrawPa
|
||||||
as.arcSize = D2D1_ARC_SIZE_SMALL;
|
as.arcSize = D2D1_ARC_SIZE_SMALL;
|
||||||
else
|
else
|
||||||
as.arcSize = D2D1_ARC_SIZE_LARGE;
|
as.arcSize = D2D1_ARC_SIZE_LARGE;
|
||||||
ID2D1GeometrySink_AddArc(p->sink, &as);
|
p->sink->AddArc(&as);
|
||||||
}
|
}
|
||||||
|
|
||||||
void uiDrawPathNewFigureWithArc(uiDrawPath *p, double xCenter, double yCenter, double radius, double startAngle, double sweep, int negative)
|
void uiDrawPathNewFigureWithArc(uiDrawPath *p, double xCenter, double yCenter, double radius, double startAngle, double sweep, int negative)
|
||||||
|
@ -248,7 +240,7 @@ void uiDrawPathLineTo(uiDrawPath *p, double x, double y)
|
||||||
|
|
||||||
pt.x = x;
|
pt.x = x;
|
||||||
pt.y = y;
|
pt.y = y;
|
||||||
ID2D1GeometrySink_AddLine(p->sink, pt);
|
p->sink->AddLine(pt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void uiDrawPathArcTo(uiDrawPath *p, double xCenter, double yCenter, double radius, double startAngle, double sweep, int negative)
|
void uiDrawPathArcTo(uiDrawPath *p, double xCenter, double yCenter, double radius, double startAngle, double sweep, int negative)
|
||||||
|
@ -274,13 +266,12 @@ void uiDrawPathBezierTo(uiDrawPath *p, double c1x, double c1y, double c2x, doubl
|
||||||
s.point2.y = c2y;
|
s.point2.y = c2y;
|
||||||
s.point3.x = endX;
|
s.point3.x = endX;
|
||||||
s.point3.y = endY;
|
s.point3.y = endY;
|
||||||
ID2D1GeometrySink_AddBezier(p->sink, &s);
|
p->sink->AddBezier(&s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void uiDrawPathCloseFigure(uiDrawPath *p)
|
void uiDrawPathCloseFigure(uiDrawPath *p)
|
||||||
{
|
{
|
||||||
ID2D1GeometrySink_EndFigure(p->sink,
|
p->sink->EndFigure(D2D1_FIGURE_END_CLOSED);
|
||||||
D2D1_FIGURE_END_CLOSED);
|
|
||||||
p->inFigure = FALSE;
|
p->inFigure = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,20 +290,21 @@ void uiDrawPathEnd(uiDrawPath *p)
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
if (p->inFigure) {
|
if (p->inFigure) {
|
||||||
ID2D1GeometrySink_EndFigure(p->sink,
|
p->sink->EndFigure(D2D1_FIGURE_END_OPEN);
|
||||||
D2D1_FIGURE_END_OPEN);
|
|
||||||
// needed for uiDrawFreePath()
|
// needed for uiDrawFreePath()
|
||||||
p->inFigure = FALSE;
|
p->inFigure = FALSE;
|
||||||
}
|
}
|
||||||
hr = ID2D1GeometrySink_Close(p->sink);
|
hr = p->sink->Close();
|
||||||
if (hr != S_OK)
|
if (hr != S_OK)
|
||||||
logHRESULT("error closing path in uiDrawPathEnd()", hr);
|
logHRESULT(L"error closing path", hr);
|
||||||
ID2D1GeometrySink_Release(p->sink);
|
p->sink->Release();
|
||||||
|
// also needed for uiDrawFreePath()
|
||||||
p->sink = NULL;
|
p->sink = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct uiDrawContext {
|
struct uiDrawContext {
|
||||||
ID2D1RenderTarget *rt;
|
ID2D1RenderTarget *rt;
|
||||||
|
// TODO move to std::vector
|
||||||
struct ptrArray *states;
|
struct ptrArray *states;
|
||||||
ID2D1PathGeometry *currentClip;
|
ID2D1PathGeometry *currentClip;
|
||||||
};
|
};
|
||||||
|
@ -330,7 +322,7 @@ static void resetTarget(ID2D1RenderTarget *rt)
|
||||||
ZeroMemory(&dm, sizeof (D2D1_MATRIX_3X2_F));
|
ZeroMemory(&dm, sizeof (D2D1_MATRIX_3X2_F));
|
||||||
dm._11 = 1;
|
dm._11 = 1;
|
||||||
dm._22 = 1;
|
dm._22 = 1;
|
||||||
ID2D1RenderTarget_SetTransform(rt, &dm);
|
rt->SetTransform(&dm);
|
||||||
}
|
}
|
||||||
|
|
||||||
uiDrawContext *newContext(ID2D1RenderTarget *rt)
|
uiDrawContext *newContext(ID2D1RenderTarget *rt)
|
||||||
|
@ -347,7 +339,7 @@ uiDrawContext *newContext(ID2D1RenderTarget *rt)
|
||||||
void freeContext(uiDrawContext *c)
|
void freeContext(uiDrawContext *c)
|
||||||
{
|
{
|
||||||
if (c->currentClip != NULL)
|
if (c->currentClip != NULL)
|
||||||
ID2D1PathGeometry_Release(c->currentClip);
|
c->currentClip->Release();
|
||||||
uninitStates(c);
|
uninitStates(c);
|
||||||
uiFree(c);
|
uiFree(c);
|
||||||
}
|
}
|
||||||
|
@ -363,13 +355,13 @@ static ID2D1Brush *makeSolidBrush(uiDrawBrush *b, ID2D1RenderTarget *rt, D2D1_BR
|
||||||
color.b = b->B;
|
color.b = b->B;
|
||||||
color.a = b->A;
|
color.a = b->A;
|
||||||
|
|
||||||
hr = ID2D1RenderTarget_CreateSolidColorBrush(rt,
|
hr = rt->CreateSolidColorBrush(
|
||||||
&color,
|
&color,
|
||||||
props,
|
props,
|
||||||
&brush);
|
&brush);
|
||||||
if (hr != S_OK)
|
if (hr != S_OK)
|
||||||
logHRESULT("error creating solid brush in makeSolidBrush()", hr);
|
logHRESULT(L"error creating solid brush", hr);
|
||||||
return (ID2D1Brush *) brush;
|
return brush;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ID2D1GradientStopCollection *mkstops(uiDrawBrush *b, ID2D1RenderTarget *rt)
|
static ID2D1GradientStopCollection *mkstops(uiDrawBrush *b, ID2D1RenderTarget *rt)
|
||||||
|
@ -388,17 +380,14 @@ static ID2D1GradientStopCollection *mkstops(uiDrawBrush *b, ID2D1RenderTarget *r
|
||||||
stops[i].color.a = b->Stops[i].A;
|
stops[i].color.a = b->Stops[i].A;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO BUG IN MINGW
|
hr = rt->CreateGradientStopCollection(
|
||||||
// the Microsoft headers give this all 6 parameters
|
|
||||||
// the MinGW headers use the 4-parameter version
|
|
||||||
hr = (*(rt->lpVtbl->CreateGradientStopCollection))(rt,
|
|
||||||
stops,
|
stops,
|
||||||
b->NumStops,
|
b->NumStops,
|
||||||
D2D1_GAMMA_2_2, // this is the default for the C++-only overload of ID2D1RenderTarget::GradientStopCollection()
|
D2D1_GAMMA_2_2, // this is the default for the C++-only overload of ID2D1RenderTarget::GradientStopCollection()
|
||||||
D2D1_EXTEND_MODE_CLAMP,
|
D2D1_EXTEND_MODE_CLAMP,
|
||||||
&s);
|
&s);
|
||||||
if (hr != S_OK)
|
if (hr != S_OK)
|
||||||
logHRESULT("error creating stop collection in mkstops()", hr);
|
logHRESULT(L"error creating stop collection", hr);
|
||||||
|
|
||||||
uiFree(stops);
|
uiFree(stops);
|
||||||
return s;
|
return s;
|
||||||
|
@ -419,17 +408,17 @@ static ID2D1Brush *makeLinearBrush(uiDrawBrush *b, ID2D1RenderTarget *rt, D2D1_B
|
||||||
|
|
||||||
stops = mkstops(b, rt);
|
stops = mkstops(b, rt);
|
||||||
|
|
||||||
hr = ID2D1RenderTarget_CreateLinearGradientBrush(rt,
|
hr = rt->CreateLinearGradientBrush(
|
||||||
&gprops,
|
&gprops,
|
||||||
props,
|
props,
|
||||||
stops,
|
stops,
|
||||||
&brush);
|
&brush);
|
||||||
if (hr != S_OK)
|
if (hr != S_OK)
|
||||||
logHRESULT("error creating gradient brush in makeLinearBrush()", hr);
|
logHRESULT(L"error creating gradient brush", 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
|
// 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);
|
stops->Release();
|
||||||
return (ID2D1Brush *) brush;
|
return brush;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ID2D1Brush *makeRadialBrush(uiDrawBrush *b, ID2D1RenderTarget *rt, D2D1_BRUSH_PROPERTIES *props)
|
static ID2D1Brush *makeRadialBrush(uiDrawBrush *b, ID2D1RenderTarget *rt, D2D1_BRUSH_PROPERTIES *props)
|
||||||
|
@ -449,16 +438,16 @@ static ID2D1Brush *makeRadialBrush(uiDrawBrush *b, ID2D1RenderTarget *rt, D2D1_B
|
||||||
|
|
||||||
stops = mkstops(b, rt);
|
stops = mkstops(b, rt);
|
||||||
|
|
||||||
hr = ID2D1RenderTarget_CreateRadialGradientBrush(rt,
|
hr = rt->CreateRadialGradientBrush(
|
||||||
&gprops,
|
&gprops,
|
||||||
props,
|
props,
|
||||||
stops,
|
stops,
|
||||||
&brush);
|
&brush);
|
||||||
if (hr != S_OK)
|
if (hr != S_OK)
|
||||||
logHRESULT("error creating gradient brush in makeRadialBrush()", hr);
|
logHRESULT(L"error creating gradient brush", hr);
|
||||||
|
|
||||||
ID2D1GradientStopCollection_Release(stops);
|
stops->Release();
|
||||||
return (ID2D1Brush *) brush;
|
return brush;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ID2D1Brush *makeBrush(uiDrawBrush *b, ID2D1RenderTarget *rt)
|
static ID2D1Brush *makeBrush(uiDrawBrush *b, ID2D1RenderTarget *rt)
|
||||||
|
@ -508,13 +497,9 @@ static ID2D1Layer *applyClip(uiDrawContext *c)
|
||||||
|
|
||||||
// create a layer for clipping
|
// create a layer for clipping
|
||||||
// we have to explicitly make the layer because we're still targeting Windows 7
|
// we have to explicitly make the layer because we're still targeting Windows 7
|
||||||
// TODO MINGW BUG
|
hr = c->rt->CreateLayer(NULL, &layer);
|
||||||
// this macro is supposed to take three parameters
|
|
||||||
hr = (*(c->rt->lpVtbl->CreateLayer))(c->rt,
|
|
||||||
NULL,
|
|
||||||
&layer);
|
|
||||||
if (hr != S_OK)
|
if (hr != S_OK)
|
||||||
logHRESULT("error creating clip layer in applyClip()", hr);
|
logHRESULT(L"error creating clip layer", hr);
|
||||||
|
|
||||||
// apply it as the clip
|
// apply it as the clip
|
||||||
ZeroMemory(¶ms, sizeof (D2D1_LAYER_PARAMETERS));
|
ZeroMemory(¶ms, sizeof (D2D1_LAYER_PARAMETERS));
|
||||||
|
@ -533,11 +518,9 @@ static ID2D1Layer *applyClip(uiDrawContext *c)
|
||||||
params.opacityBrush = NULL;
|
params.opacityBrush = NULL;
|
||||||
params.layerOptions = D2D1_LAYER_OPTIONS_NONE;
|
params.layerOptions = D2D1_LAYER_OPTIONS_NONE;
|
||||||
// TODO is this correct?
|
// TODO is this correct?
|
||||||
if (ID2D1RenderTarget_GetTextAntialiasMode(c->rt) == D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE)
|
if (c->rt->GetTextAntialiasMode() == D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE)
|
||||||
params.layerOptions = D2D1_LAYER_OPTIONS_INITIALIZE_FOR_CLEARTYPE;
|
params.layerOptions = D2D1_LAYER_OPTIONS_INITIALIZE_FOR_CLEARTYPE;
|
||||||
ID2D1RenderTarget_PushLayer(c->rt,
|
c->rt->PushLayer(¶ms, layer);
|
||||||
¶ms,
|
|
||||||
layer);
|
|
||||||
|
|
||||||
// return the layer so it can be freed later
|
// return the layer so it can be freed later
|
||||||
return layer;
|
return layer;
|
||||||
|
@ -547,8 +530,8 @@ static void unapplyClip(uiDrawContext *c, ID2D1Layer *layer)
|
||||||
{
|
{
|
||||||
if (layer == NULL)
|
if (layer == NULL)
|
||||||
return;
|
return;
|
||||||
ID2D1RenderTarget_PopLayer(c->rt);
|
c->rt->PopLayer();
|
||||||
ID2D1Layer_Release(layer);
|
layer->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
void uiDrawStroke(uiDrawContext *c, uiDrawPath *p, uiDrawBrush *b, uiDrawStrokeParams *sp)
|
void uiDrawStroke(uiDrawContext *c, uiDrawPath *p, uiDrawBrush *b, uiDrawStrokeParams *sp)
|
||||||
|
@ -604,26 +587,26 @@ void uiDrawStroke(uiDrawContext *c, uiDrawPath *p, uiDrawBrush *b, uiDrawStrokeP
|
||||||
dashes[i] = sp->Dashes[i] / sp->Thickness;
|
dashes[i] = sp->Dashes[i] / sp->Thickness;
|
||||||
}
|
}
|
||||||
dsp.dashOffset = sp->DashPhase / sp->Thickness;
|
dsp.dashOffset = sp->DashPhase / sp->Thickness;
|
||||||
hr = ID2D1Factory_CreateStrokeStyle(d2dfactory,
|
hr = d2dfactory->CreateStrokeStyle(
|
||||||
&dsp,
|
&dsp,
|
||||||
dashes,
|
dashes,
|
||||||
sp->NumDashes,
|
sp->NumDashes,
|
||||||
&style);
|
&style);
|
||||||
if (hr != S_OK)
|
if (hr != S_OK)
|
||||||
logHRESULT("error creating stroke style in uiDrawStroke()", hr);
|
logHRESULT(L"error creating stroke style", hr);
|
||||||
if (sp->NumDashes != 0)
|
if (sp->NumDashes != 0)
|
||||||
uiFree(dashes);
|
uiFree(dashes);
|
||||||
|
|
||||||
cliplayer = applyClip(c);
|
cliplayer = applyClip(c);
|
||||||
ID2D1RenderTarget_DrawGeometry(c->rt,
|
c->rt->DrawGeometry(
|
||||||
(ID2D1Geometry *) (p->path),
|
(ID2D1Geometry *) (p->path),
|
||||||
brush,
|
brush,
|
||||||
sp->Thickness,
|
sp->Thickness,
|
||||||
style);
|
style);
|
||||||
unapplyClip(c, cliplayer);
|
unapplyClip(c, cliplayer);
|
||||||
|
|
||||||
ID2D1StrokeStyle_Release(style);
|
style->Release();
|
||||||
ID2D1Brush_Release(brush);
|
brush->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
void uiDrawFill(uiDrawContext *c, uiDrawPath *p, uiDrawBrush *b)
|
void uiDrawFill(uiDrawContext *c, uiDrawPath *p, uiDrawBrush *b)
|
||||||
|
@ -633,12 +616,12 @@ void uiDrawFill(uiDrawContext *c, uiDrawPath *p, uiDrawBrush *b)
|
||||||
|
|
||||||
brush = makeBrush(b, c->rt);
|
brush = makeBrush(b, c->rt);
|
||||||
cliplayer = applyClip(c);
|
cliplayer = applyClip(c);
|
||||||
ID2D1RenderTarget_FillGeometry(c->rt,
|
c->rt->FillGeometry(
|
||||||
(ID2D1Geometry *) (p->path),
|
(ID2D1Geometry *) (p->path),
|
||||||
brush,
|
brush,
|
||||||
NULL);
|
NULL);
|
||||||
unapplyClip(c, cliplayer);
|
unapplyClip(c, cliplayer);
|
||||||
ID2D1Brush_Release(brush);
|
brush->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void m2d(uiDrawMatrix *m, D2D1_MATRIX_3X2_F *d)
|
static void m2d(uiDrawMatrix *m, D2D1_MATRIX_3X2_F *d)
|
||||||
|
@ -669,6 +652,7 @@ void uiDrawMatrixSetIdentity(uiDrawMatrix *m)
|
||||||
// frustratingly all of the operations on a matrix except rotation and skeweing are provided by the C++-only d2d1helper.h
|
// frustratingly all of the operations on a matrix except rotation and skeweing are provided by the C++-only d2d1helper.h
|
||||||
// we'll have to recreate their functionalities here
|
// we'll have to recreate their functionalities here
|
||||||
// the implementations are all in the main matrix.c file
|
// the implementations are all in the main matrix.c file
|
||||||
|
// TODO switch to these instead actually
|
||||||
|
|
||||||
void uiDrawMatrixTranslate(uiDrawMatrix *m, double x, double y)
|
void uiDrawMatrixTranslate(uiDrawMatrix *m, double x, double y)
|
||||||
{
|
{
|
||||||
|
@ -743,13 +727,14 @@ void uiDrawMatrixTransformSize(uiDrawMatrix *m, double *x, double *y)
|
||||||
fallbackTransformSize(m, x, y);
|
fallbackTransformSize(m, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO move to using d2d matrices exclusively
|
||||||
void uiDrawTransform(uiDrawContext *c, uiDrawMatrix *m)
|
void uiDrawTransform(uiDrawContext *c, uiDrawMatrix *m)
|
||||||
{
|
{
|
||||||
D2D1_MATRIX_3X2_F dm;
|
D2D1_MATRIX_3X2_F dm;
|
||||||
uiDrawMatrix already;
|
uiDrawMatrix already;
|
||||||
uiDrawMatrix temp;
|
uiDrawMatrix temp;
|
||||||
|
|
||||||
ID2D1RenderTarget_GetTransform(c->rt, &dm);
|
c->rt->GetTransform(&dm);
|
||||||
d2m(&dm, &already);
|
d2m(&dm, &already);
|
||||||
temp = *m; // don't modify m
|
temp = *m; // don't modify m
|
||||||
// you would think we have to do already * m, right?
|
// you would think we have to do already * m, right?
|
||||||
|
@ -761,10 +746,10 @@ void uiDrawTransform(uiDrawContext *c, uiDrawMatrix *m)
|
||||||
// TODO see if Microsoft says to do this
|
// TODO see if Microsoft says to do this
|
||||||
uiDrawMatrixMultiply(&temp, &already);
|
uiDrawMatrixMultiply(&temp, &already);
|
||||||
m2d(&temp, &dm);
|
m2d(&temp, &dm);
|
||||||
ID2D1RenderTarget_SetTransform(c->rt, &dm);
|
c->rt->SetTransform(&dm);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO for this, stroke, and fill, make sure that an open path causes error state
|
// TODO for this, stroke, and fill, make sure that a non-ended uiDrawPath causes error state
|
||||||
void uiDrawClip(uiDrawContext *c, uiDrawPath *path)
|
void uiDrawClip(uiDrawContext *c, uiDrawPath *path)
|
||||||
{
|
{
|
||||||
ID2D1PathGeometry *newPath;
|
ID2D1PathGeometry *newPath;
|
||||||
|
@ -775,39 +760,34 @@ void uiDrawClip(uiDrawContext *c, uiDrawPath *path)
|
||||||
if (c->currentClip == NULL) {
|
if (c->currentClip == NULL) {
|
||||||
c->currentClip = path->path;
|
c->currentClip = path->path;
|
||||||
// we have to take our own reference to that clip
|
// we have to take our own reference to that clip
|
||||||
ID2D1PathGeometry_AddRef(c->currentClip);
|
c->currentClip->AddRef();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// otherwise we have to intersect the current path with the new one
|
// otherwise we have to intersect the current path with the new one
|
||||||
// we do that into a new path, and then replace c->currentClip with that new path
|
// we do that into a new path, and then replace c->currentClip with that new path
|
||||||
hr = ID2D1Factory_CreatePathGeometry(d2dfactory,
|
hr = d2dfactoryCreatePathGeometry(&newPath);
|
||||||
&newPath);
|
|
||||||
if (hr != S_OK)
|
if (hr != S_OK)
|
||||||
logHRESULT("error creating new path in uiDrawClip()", hr);
|
logHRESULT(L"error creating new path", hr);
|
||||||
hr = ID2D1PathGeometry_Open(newPath,
|
hr = newPath->Open(&newSink);
|
||||||
&newSink);
|
|
||||||
if (hr != S_OK)
|
if (hr != S_OK)
|
||||||
logHRESULT("error opening new path in uiDrawClip()", hr);
|
logHRESULT(L"error opening new path", hr);
|
||||||
// TODO BUG IN MINGW
|
hr = c->currentClip->CombineWithGeometry(
|
||||||
// the macro is supposed to take 6 parameters
|
path->path,
|
||||||
hr = (*(c->currentClip->lpVtbl->Base.CombineWithGeometry))(
|
|
||||||
(ID2D1Geometry *) (c->currentClip),
|
|
||||||
(ID2D1Geometry *) (path->path),
|
|
||||||
D2D1_COMBINE_MODE_INTERSECT,
|
D2D1_COMBINE_MODE_INTERSECT,
|
||||||
NULL,
|
NULL,
|
||||||
// TODO is this correct or can this be set per target?
|
// TODO is this correct or can this be set per target?
|
||||||
D2D1_DEFAULT_FLATTENING_TOLERANCE,
|
D2D1_DEFAULT_FLATTENING_TOLERANCE,
|
||||||
(ID2D1SimplifiedGeometrySink *) newSink);
|
newSink);
|
||||||
if (hr != S_OK)
|
if (hr != S_OK)
|
||||||
logHRESULT("error intersecting old path with new path in uiDrawClip()", hr);
|
logHRESULT(L"error intersecting old path with new path", hr);
|
||||||
hr = ID2D1GeometrySink_Close(newSink);
|
hr = newSink->Close();
|
||||||
if (hr != S_OK)
|
if (hr != S_OK)
|
||||||
logHRESULT("error closing new path in uiDrawClip()", hr);
|
logHRESULT(L"error closing new path", hr);
|
||||||
ID2D1GeometrySink_Release(newSink);
|
newSink->Release();
|
||||||
|
|
||||||
// okay we have the new clip; we just need to replace the old one with it
|
// okay we have the new clip; we just need to replace the old one with it
|
||||||
ID2D1PathGeometry_Release(c->currentClip);
|
c->currentClip->Release();
|
||||||
c->currentClip = newPath;
|
c->currentClip = newPath;
|
||||||
// we have a reference already; no need for another
|
// we have a reference already; no need for another
|
||||||
}
|
}
|
||||||
|
@ -836,18 +816,18 @@ void uiDrawSave(uiDrawContext *c)
|
||||||
ID2D1DrawingStateBlock *dsb;
|
ID2D1DrawingStateBlock *dsb;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
hr = ID2D1Factory_CreateDrawingStateBlock(d2dfactory,
|
hr = d2dfactory->CreateDrawingStateBlock(
|
||||||
// TODO verify that these are correct
|
// TODO verify that these are correct
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
&dsb);
|
&dsb);
|
||||||
if (hr != S_OK)
|
if (hr != S_OK)
|
||||||
logHRESULT("error creating drawing state block in uiDrawSave()", hr);
|
logHRESULT(L"error creating drawing state block", hr);
|
||||||
ID2D1RenderTarget_SaveDrawingState(c->rt, dsb);
|
c->rt->SaveDrawingState(dsb);
|
||||||
|
|
||||||
// if we have a clip, we need to hold another reference to it
|
// if we have a clip, we need to hold another reference to it
|
||||||
if (c->currentClip != NULL)
|
if (c->currentClip != NULL)
|
||||||
ID2D1PathGeometry_AddRef(c->currentClip);
|
c->currentClip->AddRef();
|
||||||
|
|
||||||
state = uiNew(struct state);
|
state = uiNew(struct state);
|
||||||
state->dsb = dsb;
|
state->dsb = dsb;
|
||||||
|
@ -861,12 +841,12 @@ void uiDrawRestore(uiDrawContext *c)
|
||||||
|
|
||||||
state = ptrArrayIndex(c->states, struct state *, c->states->len - 1);
|
state = ptrArrayIndex(c->states, struct state *, c->states->len - 1);
|
||||||
|
|
||||||
ID2D1RenderTarget_RestoreDrawingState(c->rt, state->dsb);
|
c->rt->RestoreDrawingState(state->dsb);
|
||||||
ID2D1DrawingStateBlock_Release(state->dsb);
|
state->dsb->Release();
|
||||||
|
|
||||||
// if we have a current clip, we need to drop it
|
// if we have a current clip, we need to drop it
|
||||||
if (c->currentClip != NULL)
|
if (c->currentClip != NULL)
|
||||||
ID2D1PathGeometry_Release(c->currentClip);
|
c->currentClip->Release();
|
||||||
// no need to explicitly addref or release; just transfer the ref
|
// no need to explicitly addref or release; just transfer the ref
|
||||||
c->currentClip = state->clip;
|
c->currentClip = state->clip;
|
||||||
|
|
||||||
|
@ -874,6 +854,8 @@ void uiDrawRestore(uiDrawContext *c)
|
||||||
ptrArrayDelete(c->states, c->states->len - 1);
|
ptrArrayDelete(c->states, c->states->len - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO C++-ize the rest of the file
|
||||||
|
|
||||||
// TODO document that fully opaque black is the default text color; figure out whether this is upheld in various scenarios on other platforms
|
// TODO document that fully opaque black is the default text color; figure out whether this is upheld in various scenarios on other platforms
|
||||||
void uiDrawText(uiDrawContext *c, double x, double y, uiDrawTextLayout *layout)
|
void uiDrawText(uiDrawContext *c, double x, double y, uiDrawTextLayout *layout)
|
||||||
{
|
{
|
||||||
|
@ -888,7 +870,7 @@ void uiDrawText(uiDrawContext *c, double x, double y, uiDrawTextLayout *layout)
|
||||||
brush.A = 1.0;
|
brush.A = 1.0;
|
||||||
black = makeBrush(&brush, c->rt);
|
black = makeBrush(&brush, c->rt);
|
||||||
doDrawText(c->rt, black, x, y, layout);
|
doDrawText(c->rt, black, x, y, layout);
|
||||||
ID2D1Brush_Release(black);
|
black->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO this is a mess
|
// TODO this is a mess
|
Loading…
Reference in New Issue