1 module directx.d2d1_1helper;
2 /*=========================================================================*\
3 
4     Copyright (c) Microsoft Corporation.  All rights reserved.
5 
6     File: D2D1_1Helper.h
7 
8     Module Name: D2D
9 
10     Description: Helper files over the D2D interfaces and APIs.
11 
12 \*=========================================================================*/
13 
14 public import directx.d2d1_1;
15 import directx.d2d1helper;
16 
17 template TypeTraits(T : INT32)
18 {
19     alias Point =  D2D1_POINT_2L;
20     alias Rect = D2D1_RECT_L;
21 }
22 
23 template TypeTraits(T : LONG)
24 {
25     alias Point = D2D1_POINT_2L;
26     alias Rect = D2D1_RECT_L;
27 }
28 
29 struct Matrix4x3F // : D2D1_MATRIX_4X3_F
30 {
31     D2D1_MATRIX_4X3_F matrix;
32     alias matrix this;
33 
34     nothrow this(D2D1_MATRIX_4X3_F m) { matrix = m; }
35     nothrow this(
36         FLOAT m11, FLOAT m12, FLOAT m13,
37         FLOAT m21, FLOAT m22, FLOAT m23,
38         FLOAT m31, FLOAT m32, FLOAT m33,
39         FLOAT m41, FLOAT m42, FLOAT m43
40         )
41     {
42         _11 = m11;
43         _12 = m12;
44         _13 = m13;
45 
46         _21 = m21;
47         _22 = m22;
48         _23 = m23;
49 
50         _31 = m31;
51         _32 = m32;
52         _33 = m33;
53 
54         _41 = m41;
55         _42 = m42;
56         _43 = m43;
57     }
58 
59     // this()
60     /// Use this instead of default constructor
61     static @property nothrow Identity()
62     {
63         return Matrix4x3F(
64             1, 0, 0,
65             0, 1, 0,
66             0, 0, 1,
67             0, 0, 0
68         );
69     }
70 }
71 
72 struct Matrix4x4F // : public D2D1_MATRIX_4X4_F
73 {
74     D2D1_MATRIX_4X4_F matrix;
75     alias matrix this;
76 
77     nothrow this(D2D1_MATRIX_4X4_F m) { matrix = m; }
78     nothrow this(
79         FLOAT m11, FLOAT m12, FLOAT m13, FLOAT m14,
80         FLOAT m21, FLOAT m22, FLOAT m23, FLOAT m24,
81         FLOAT m31, FLOAT m32, FLOAT m33, FLOAT m34,
82         FLOAT m41, FLOAT m42, FLOAT m43, FLOAT m44
83         )
84     {
85         _11 = m11;
86         _12 = m12;
87         _13 = m13;
88         _14 = m14;
89 
90         _21 = m21;
91         _22 = m22;
92         _23 = m23;
93         _24 = m24;
94 
95         _31 = m31;
96         _32 = m32;
97         _33 = m33;
98         _34 = m34;
99 
100         _41 = m41;
101         _42 = m42;
102         _43 = m43;
103         _44 = m44;
104     }
105 
106     // this()
107     /// Use this instead of default constructor
108     static nothrow @property Identity()
109     {
110         return Matrix4x4F(
111             1, 0, 0, 0,
112             0, 1, 0, 0,
113             0, 0, 1, 0,
114             0, 0, 0, 1
115         );
116     }
117 
118     bool opEquals(
119         const Matrix4x4F r
120         ) const
121     {
122         return _11 == r._11 && _12 == r._12 && _13 == r._13 && _14 == r._14 &&
123                 _21 == r._21 && _22 == r._22 && _23 == r._23 && _24 == r._24 &&
124                 _31 == r._31 && _32 == r._32 && _33 == r._33 && _34 == r._34 &&
125                 _41 == r._41 && _42 == r._42 && _43 == r._43 && _44 == r._44;
126     }
127 
128     static
129     Matrix4x4F
130     Translation(FLOAT x, FLOAT y, FLOAT z)
131     {
132         Matrix4x4F translation;
133 
134         translation._11 = 1.0; translation._12 = 0.0; translation._13 = 0.0; translation._14 = 0.0;
135         translation._21 = 0.0; translation._22 = 1.0; translation._23 = 0.0; translation._24 = 0.0;
136         translation._31 = 0.0; translation._32 = 0.0; translation._33 = 1.0; translation._34 = 0.0;
137         translation._41 = x;   translation._42 = y;   translation._43 = z;   translation._44 = 1.0;
138 
139         return translation;
140     }
141 
142     static
143     Matrix4x4F
144     Scale(FLOAT x, FLOAT y, FLOAT z)
145     {
146         Matrix4x4F scale;
147 
148         scale._11 = x;   scale._12 = 0.0; scale._13 = 0.0; scale._14 = 0.0;
149         scale._21 = 0.0; scale._22 = y;   scale._23 = 0.0; scale._24 = 0.0;
150         scale._31 = 0.0; scale._32 = 0.0; scale._33 = z;   scale._34 = 0.0;
151         scale._41 = 0.0; scale._42 = 0.0; scale._43 = 0.0; scale._44 = 1.0;
152 
153         return scale;
154     }
155 
156     static
157     Matrix4x4F
158     RotationX(FLOAT degreeX)
159     {
160         FLOAT angleInRadian = degreeX * (3.141592654f / 180.0f);
161 
162         FLOAT sinAngle = 0.0;
163         FLOAT cosAngle = 0.0;
164         D2D1SinCos(angleInRadian, &sinAngle, &cosAngle);
165 
166         return Matrix4x4F(
167             1, 0,         0,        0,
168             0, cosAngle,  sinAngle, 0,
169             0, -sinAngle, cosAngle, 0,
170             0, 0,         0,        1
171             );
172     }
173 
174     static
175     Matrix4x4F
176     RotationY(FLOAT degreeY)
177     {
178         FLOAT angleInRadian = degreeY * (3.141592654f / 180.0f);
179 
180         FLOAT sinAngle = 0.0;
181         FLOAT cosAngle = 0.0;
182         D2D1SinCos(angleInRadian, &sinAngle, &cosAngle);
183 
184         return Matrix4x4F(
185             cosAngle, 0, -sinAngle, 0,
186             0,        1, 0,         0,
187             sinAngle, 0, cosAngle,  0,
188             0,        0, 0,         1
189             );
190     }
191 
192     static
193     Matrix4x4F
194     RotationZ(FLOAT degreeZ)
195     {
196         FLOAT angleInRadian = degreeZ * (3.141592654f / 180.0f);
197 
198         FLOAT sinAngle = 0.0;
199         FLOAT cosAngle = 0.0;
200         D2D1SinCos(angleInRadian, &sinAngle, &cosAngle);
201 
202         return Matrix4x4F(
203             cosAngle,  sinAngle, 0, 0,
204             -sinAngle, cosAngle, 0, 0,
205             0,         0,        1, 0,
206             0,         0,        0, 1
207             );
208     }
209 
210     //
211     // 3D Rotation matrix for an arbitrary axis specified by x, y and z
212     //
213     static
214     Matrix4x4F
215     RotationArbitraryAxis(FLOAT x, FLOAT y, FLOAT z, FLOAT degree)
216     {
217         // Normalize the vector represented by x, y, and z
218         FLOAT magnitude = D2D1Vec3Length(x, y, z);
219         x /= magnitude;
220         y /= magnitude;
221         z /= magnitude;
222 
223         FLOAT angleInRadian = degree * (3.141592654f / 180.0f);
224 
225         FLOAT sinAngle = 0.0;
226         FLOAT cosAngle = 0.0;
227         D2D1SinCos(angleInRadian, &sinAngle, &cosAngle);
228 
229         FLOAT oneMinusCosAngle = 1 - cosAngle;
230 
231         return Matrix4x4F(
232             1             + oneMinusCosAngle * (x * x - 1),
233             z  * sinAngle + oneMinusCosAngle *  x * y,
234             -y * sinAngle + oneMinusCosAngle *  x * z,
235             0,
236 
237             -z * sinAngle + oneMinusCosAngle *  y * x,
238             1             + oneMinusCosAngle * (y * y - 1),
239             x  * sinAngle + oneMinusCosAngle *  y * z,
240             0,
241 
242             y  * sinAngle + oneMinusCosAngle *  z * x,
243             -x * sinAngle + oneMinusCosAngle *  z * y,
244             1             + oneMinusCosAngle * (z * z - 1) ,
245             0,
246 
247             0, 0, 0, 1
248             );
249     }
250 
251     static
252     Matrix4x4F
253     SkewX(FLOAT degreeX)
254     {
255         FLOAT angleInRadian = degreeX * (3.141592654f / 180.0f);
256 
257         FLOAT tanAngle = D2D1Tan(angleInRadian);
258 
259         return Matrix4x4F(
260             1,          0,  0, 0,
261             tanAngle,   1,  0, 0,
262             0,          0,  1, 0,
263             0,          0,  0, 1
264             );
265     }
266 
267     static
268     Matrix4x4F
269     SkewY(FLOAT degreeY)
270     {
271         FLOAT angleInRadian = degreeY * (3.141592654f / 180.0f);
272 
273         FLOAT tanAngle = D2D1Tan(angleInRadian);
274 
275         return Matrix4x4F(
276             1,  tanAngle,   0, 0,
277             0,  1,          0, 0,
278             0,  0,          1, 0,
279             0,  0,          0, 1
280             );
281     }
282 
283 
284     static
285     Matrix4x4F
286     PerspectiveProjection(FLOAT depth)
287     {
288         float proj = 0;
289 
290         if (depth > 0)
291         {
292             proj = -1/depth;
293         }
294 
295         return Matrix4x4F(
296             1, 0, 0, 0,
297             0, 1, 0, 0,
298             0, 0, 1, proj,
299             0, 0, 0, 1
300             );
301     }
302 
303     //
304     // Functions for convertion from the base D2D1_MATRIX_4X4_f to
305     // this type without making a copy
306     //
307     static
308     const(Matrix4x4F)*
309     ReinterpretBaseType(const(D2D1_MATRIX_4X4_F)* pMatrix)
310     {
311         return cast(const(Matrix4x4F)*)pMatrix;
312     }
313 
314     static
315     nothrow
316     Matrix4x4F*
317     ReinterpretBaseType(D2D1_MATRIX_4X4_F *pMatrix)
318     {
319         return cast(Matrix4x4F*)(pMatrix);
320     }
321 
322     nothrow
323     FLOAT
324     Determinant() const
325     {
326         FLOAT minor1 = _41 * (_12 * (_23 * _34 - _33 * _24) - _13 * (_22 * _34 - _24 * _32) + _14 * (_22 * _33 - _23 * _32));
327         FLOAT minor2 = _42 * (_11 * (_21 * _34 - _31 * _24) - _13 * (_21 * _34 - _24 * _31) + _14 * (_21 * _33 - _23 * _31));
328         FLOAT minor3 = _43 * (_11 * (_22 * _34 - _32 * _24) - _12 * (_21 * _34 - _24 * _31) + _14 * (_21 * _32 - _22 * _31));
329         FLOAT minor4 = _44 * (_11 * (_22 * _33 - _32 * _23) - _12 * (_21 * _33 - _23 * _31) + _13 * (_21 * _32 - _22 * _31));
330 
331         return minor1 - minor2 + minor3 - minor4;
332     }
333 
334     nothrow
335     bool
336     IsIdentity() const
337     {
338         return _11 == 1.0f && _12 == 0.0f && _13 == 0.0f && _14 == 0.0f
339             && _21 == 0.0f && _22 == 1.0f && _23 == 0.0f && _24 == 0.0f
340             && _31 == 0.0f && _32 == 0.0f && _33 == 1.0f && _34 == 0.0f
341             && _41 == 0.0f && _42 == 0.0f && _43 == 0.0f && _44 == 1.0f;
342     }
343 
344     nothrow
345     void
346     SetProduct(const Matrix4x4F a, const Matrix4x4F b)
347     {
348         _11 = a._11 * b._11 + a._12 * b._21 + a._13 * b._31 + a._14 * b._41;
349         _12 = a._11 * b._12 + a._12 * b._22 + a._13 * b._32 + a._14 * b._42;
350         _13 = a._11 * b._13 + a._12 * b._23 + a._13 * b._33 + a._14 * b._43;
351         _14 = a._11 * b._14 + a._12 * b._24 + a._13 * b._34 + a._14 * b._44;
352 
353         _21 = a._21 * b._11 + a._22 * b._21 + a._23 * b._31 + a._24 * b._41;
354         _22 = a._21 * b._12 + a._22 * b._22 + a._23 * b._32 + a._24 * b._42;
355         _23 = a._21 * b._13 + a._22 * b._23 + a._23 * b._33 + a._24 * b._43;
356         _24 = a._21 * b._14 + a._22 * b._24 + a._23 * b._34 + a._24 * b._44;
357 
358         _31 = a._31 * b._11 + a._32 * b._21 + a._33 * b._31 + a._34 * b._41;
359         _32 = a._31 * b._12 + a._32 * b._22 + a._33 * b._32 + a._34 * b._42;
360         _33 = a._31 * b._13 + a._32 * b._23 + a._33 * b._33 + a._34 * b._43;
361         _34 = a._31 * b._14 + a._32 * b._24 + a._33 * b._34 + a._34 * b._44;
362 
363         _41 = a._41 * b._11 + a._42 * b._21 + a._43 * b._31 + a._44 * b._41;
364         _42 = a._41 * b._12 + a._42 * b._22 + a._43 * b._32 + a._44 * b._42;
365         _43 = a._41 * b._13 + a._42 * b._23 + a._43 * b._33 + a._44 * b._43;
366         _44 = a._41 * b._14 + a._42 * b._24 + a._43 * b._34 + a._44 * b._44;
367     }
368 
369     nothrow
370     Matrix4x4F
371     opBinary(string op)(const Matrix4x4F matrix) const if(op == "*")
372     {
373         Matrix4x4F result;
374 
375         result.SetProduct(*this, matrix);
376 
377         return result;
378     }
379 }
380 
381 
382 struct Matrix5x4F // : D2D1_MATRIX_5X4_F
383 {
384     D2D1_MATRIX_5X4_F matrix;
385     alias matrix this;
386 
387     nothrow this(D2D1_MATRIX_5X4_F m) { matrix = m; }
388     nothrow this(
389         FLOAT m11, FLOAT m12, FLOAT m13, FLOAT m14,
390         FLOAT m21, FLOAT m22, FLOAT m23, FLOAT m24,
391         FLOAT m31, FLOAT m32, FLOAT m33, FLOAT m34,
392         FLOAT m41, FLOAT m42, FLOAT m43, FLOAT m44,
393         FLOAT m51, FLOAT m52, FLOAT m53, FLOAT m54
394         )
395     {
396         _11 = m11;
397         _12 = m12;
398         _13 = m13;
399         _14 = m14;
400 
401         _21 = m21;
402         _22 = m22;
403         _23 = m23;
404         _24 = m24;
405 
406         _31 = m31;
407         _32 = m32;
408         _33 = m33;
409         _34 = m34;
410 
411         _41 = m41;
412         _42 = m42;
413         _43 = m43;
414         _44 = m44;
415 
416         _51 = m51;
417         _52 = m52;
418         _53 = m53;
419         _54 = m54;
420     }
421 
422     // this()
423     /// Use this instead of default constructor
424     static nothrow @property Identity()
425     {
426         return Matrix5x4F(
427             1, 0, 0, 0,
428             0, 1, 0, 0,
429             0, 0, 1, 0,
430             0, 0, 0, 1,
431             0, 0, 0, 0
432         );
433     }
434 }
435 
436 D2D1_COLOR_F
437 ConvertColorSpace(
438     D2D1_COLOR_SPACE sourceColorSpace,
439     D2D1_COLOR_SPACE destinationColorSpace,
440     const D2D1_COLOR_F color
441     )
442 {
443     return D2D1ConvertColorSpace(
444         sourceColorSpace,
445         destinationColorSpace,
446         &color
447         );
448 }
449 
450 D2D1_DRAWING_STATE_DESCRIPTION1
451 DrawingStateDescription1(
452     D2D1_ANTIALIAS_MODE antialiasMode = D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
453     D2D1_TEXT_ANTIALIAS_MODE textAntialiasMode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT,
454     D2D1_TAG tag1 = 0,
455     D2D1_TAG tag2 = 0,
456     const D2D1_MATRIX_3X2_F transform = D2D1.IdentityMatrix(),
457     D2D1_PRIMITIVE_BLEND primitiveBlend = D2D1_PRIMITIVE_BLEND_SOURCE_OVER,
458     D2D1_UNIT_MODE unitMode = D2D1_UNIT_MODE_DIPS
459     )
460 {
461     D2D1_DRAWING_STATE_DESCRIPTION1 drawingStateDescription1;
462 
463     drawingStateDescription1.antialiasMode = antialiasMode;
464     drawingStateDescription1.textAntialiasMode = textAntialiasMode;
465     drawingStateDescription1.tag1 = tag1;
466     drawingStateDescription1.tag2 = tag2;
467     drawingStateDescription1.transform = transform;
468     drawingStateDescription1.primitiveBlend = primitiveBlend;
469     drawingStateDescription1.unitMode = unitMode;
470 
471     return drawingStateDescription1;
472 }
473 
474 D2D1_DRAWING_STATE_DESCRIPTION1
475 DrawingStateDescription1(
476     const D2D1_DRAWING_STATE_DESCRIPTION desc,
477     D2D1_PRIMITIVE_BLEND primitiveBlend = D2D1_PRIMITIVE_BLEND_SOURCE_OVER,
478     D2D1_UNIT_MODE unitMode = D2D1_UNIT_MODE_DIPS
479     )
480 {
481     D2D1_DRAWING_STATE_DESCRIPTION1 drawingStateDescription1;
482 
483     drawingStateDescription1.antialiasMode = desc.antialiasMode;
484     drawingStateDescription1.textAntialiasMode = desc.textAntialiasMode;
485     drawingStateDescription1.tag1 = desc.tag1;
486     drawingStateDescription1.tag2 = desc.tag2;
487     drawingStateDescription1.transform = desc.transform;
488     drawingStateDescription1.primitiveBlend = primitiveBlend;
489     drawingStateDescription1.unitMode = unitMode;
490 
491     return drawingStateDescription1;
492 }
493 
494 D2D1_BITMAP_PROPERTIES1
495 BitmapProperties1(
496     D2D1_BITMAP_OPTIONS bitmapOptions = D2D1_BITMAP_OPTIONS_NONE,
497     const D2D1_PIXEL_FORMAT pixelFormat = D2D1.PixelFormat(),
498     FLOAT dpiX = 96.0f,
499     FLOAT dpiY = 96.0f,
500     ID2D1ColorContext colorContext = null
501     )
502 {
503     D2D1_BITMAP_PROPERTIES1 bitmapProperties =
504     {
505         pixelFormat,
506         dpiX, dpiY,
507         bitmapOptions,
508         colorContext
509     };
510 
511     return bitmapProperties;
512 }    
513 
514 D2D1_LAYER_PARAMETERS1
515 LayerParameters1(
516     const D2D1_RECT_F contentBounds = D2D1.InfiniteRect(),
517     ID2D1Geometry geometricMask = NULL,
518     D2D1_ANTIALIAS_MODE maskAntialiasMode = D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
519     D2D1_MATRIX_3X2_F maskTransform = D2D1.IdentityMatrix(),
520     FLOAT opacity = 1.0,
521     ID2D1Brush opacityBrush = NULL,
522     D2D1_LAYER_OPTIONS1 layerOptions = D2D1_LAYER_OPTIONS1_NONE
523     )
524 {
525     D2D1_LAYER_PARAMETERS1 layerParameters;
526 
527     layerParameters.contentBounds = contentBounds;
528     layerParameters.geometricMask = geometricMask;
529     layerParameters.maskAntialiasMode = maskAntialiasMode;
530     layerParameters.maskTransform = maskTransform;
531     layerParameters.opacity = opacity;
532     layerParameters.opacityBrush = opacityBrush;
533     layerParameters.layerOptions = layerOptions;
534 
535     return layerParameters;
536 }
537 
538 D2D1_STROKE_STYLE_PROPERTIES1
539 StrokeStyleProperties1(
540     D2D1_CAP_STYLE startCap = D2D1_CAP_STYLE_FLAT,
541     D2D1_CAP_STYLE endCap = D2D1_CAP_STYLE_FLAT,
542     D2D1_CAP_STYLE dashCap = D2D1_CAP_STYLE_FLAT,
543     D2D1_LINE_JOIN lineJoin = D2D1_LINE_JOIN_MITER,
544     FLOAT miterLimit = 10.0f,
545     D2D1_DASH_STYLE dashStyle = D2D1_DASH_STYLE_SOLID,
546     FLOAT dashOffset = 0.0f,
547     D2D1_STROKE_TRANSFORM_TYPE transformType = D2D1_STROKE_TRANSFORM_TYPE_NORMAL
548     )
549 {
550     D2D1_STROKE_STYLE_PROPERTIES1 strokeStyleProperties;
551 
552     strokeStyleProperties.startCap = startCap;
553     strokeStyleProperties.endCap = endCap;
554     strokeStyleProperties.dashCap = dashCap;
555     strokeStyleProperties.lineJoin = lineJoin;
556     strokeStyleProperties.miterLimit = miterLimit;
557     strokeStyleProperties.dashStyle = dashStyle;
558     strokeStyleProperties.dashOffset = dashOffset;
559     strokeStyleProperties.transformType = transformType;
560 
561     return strokeStyleProperties;
562 }
563 
564 D2D1_IMAGE_BRUSH_PROPERTIES
565 ImageBrushProperties(
566     D2D1_RECT_F sourceRectangle,
567     D2D1_EXTEND_MODE extendModeX = D2D1_EXTEND_MODE_CLAMP,
568     D2D1_EXTEND_MODE extendModeY = D2D1_EXTEND_MODE_CLAMP,
569     D2D1_INTERPOLATION_MODE interpolationMode = D2D1_INTERPOLATION_MODE_LINEAR
570     )
571 {
572     D2D1_IMAGE_BRUSH_PROPERTIES imageBrushProperties;
573 
574     imageBrushProperties.extendModeX = extendModeX;
575     imageBrushProperties.extendModeY = extendModeY;
576     imageBrushProperties.interpolationMode = interpolationMode;
577     imageBrushProperties.sourceRectangle = sourceRectangle;
578 
579     return imageBrushProperties;
580 }
581 
582 D2D1_BITMAP_BRUSH_PROPERTIES1
583 BitmapBrushProperties1(
584     D2D1_EXTEND_MODE extendModeX = D2D1_EXTEND_MODE_CLAMP,
585     D2D1_EXTEND_MODE extendModeY = D2D1_EXTEND_MODE_CLAMP,
586     D2D1_INTERPOLATION_MODE interpolationMode = D2D1_INTERPOLATION_MODE_LINEAR
587     )
588 {
589     D2D1_BITMAP_BRUSH_PROPERTIES1 bitmapBrush1Properties;
590 
591     bitmapBrush1Properties.extendModeX = extendModeX;
592     bitmapBrush1Properties.extendModeY = extendModeY;
593     bitmapBrush1Properties.interpolationMode = interpolationMode;
594 
595     return bitmapBrush1Properties;
596 }
597 
598 D2D1_PRINT_CONTROL_PROPERTIES
599 PrintControlProperties(
600     D2D1_PRINT_FONT_SUBSET_MODE fontSubsetMode = D2D1_PRINT_FONT_SUBSET_MODE_DEFAULT,
601     FLOAT rasterDpi = 150.0f,
602     D2D1_COLOR_SPACE colorSpace = D2D1_COLOR_SPACE_SRGB
603     )
604 {
605     D2D1_PRINT_CONTROL_PROPERTIES printControlProps;
606 
607     printControlProps.fontSubset = fontSubsetMode;
608     printControlProps.rasterDPI = rasterDpi;
609     printControlProps.colorSpace = colorSpace;
610 
611     return printControlProps;
612 }
613 
614 D2D1_RENDERING_CONTROLS
615 RenderingControls(
616     D2D1_BUFFER_PRECISION bufferPrecision,
617     D2D1_SIZE_U tileSize
618     )
619 {
620     D2D1_RENDERING_CONTROLS renderingControls;
621 
622     renderingControls.bufferPrecision = bufferPrecision;
623     renderingControls.tileSize = tileSize;
624 
625     return renderingControls;
626 }
627 
628 D2D1_EFFECT_INPUT_DESCRIPTION
629 EffectInputDescription(
630     ID2D1Effect effect,
631     UINT32 inputIndex,
632     D2D1_RECT_F inputRectangle
633     )
634 {
635     D2D1_EFFECT_INPUT_DESCRIPTION description;
636 
637     description.effect = effect;
638     description.inputIndex = inputIndex;
639     description.inputRectangle = inputRectangle;
640 
641     return description;
642 }
643 
644 D2D1_CREATION_PROPERTIES
645 CreationProperties(
646     D2D1_THREADING_MODE threadingMode,
647     D2D1_DEBUG_LEVEL debugLevel,
648     D2D1_DEVICE_CONTEXT_OPTIONS options
649     )
650 {
651     D2D1_CREATION_PROPERTIES creationProperties;
652 
653     creationProperties.threadingMode = threadingMode;
654     creationProperties.debugLevel = debugLevel;
655     creationProperties.options = options;
656 
657     return creationProperties;
658 }
659 
660 D2D1_VECTOR_2F
661 Vector2F(
662     FLOAT x = 0.0f,
663     FLOAT y = 0.0f
664     )
665 {
666     D2D1_VECTOR_2F vec2 = {x, y};
667     return vec2;
668 }
669 
670 D2D1_VECTOR_3F
671 Vector3F(
672     FLOAT x = 0.0f,
673     FLOAT y = 0.0f,
674     FLOAT z = 0.0f
675     )
676 {
677     D2D1_VECTOR_3F vec3 = {x, y, z};
678     return vec3;
679 }
680 
681 D2D1_VECTOR_4F
682 Vector4F(
683     FLOAT x = 0.0f,
684     FLOAT y = 0.0f,
685     FLOAT z = 0.0f,
686     FLOAT w = 0.0f
687     )
688 {
689     D2D1_VECTOR_4F vec4 = {x, y, z, w};
690     return vec4;
691 }
692 
693 D2D1_POINT_2L
694 Point2L(
695     INT32 x = 0,
696     INT32 y = 0
697     )
698 {
699     return D2D1_POINT_2L(x, y);
700 }
701 
702 D2D1_RECT_L
703 RectL(
704     INT32 left = 0,
705     INT32 top = 0,
706     INT32 right = 0,
707     INT32 bottom = 0
708     )
709 {
710     return D2D1_RECT_L(left, top, right, bottom);
711 }
712 
713 ///
714 /// Sets a bitmap as an effect input, while inserting a DPI compensation effect
715 /// to preserve visual appearance as the device context's DPI changes.
716 /// 
717 HRESULT
718 SetDpiCompensatedEffectInput(
719     ID2D1DeviceContext deviceContext,
720     ID2D1Effect effect,
721     UINT32 inputIndex,
722     ID2D1Bitmap inputBitmap,
723     D2D1_INTERPOLATION_MODE interpolationMode = D2D1_INTERPOLATION_MODE_LINEAR,
724     D2D1_BORDER_MODE borderMode = D2D1_BORDER_MODE_HARD
725     )
726 {
727     HRESULT hr = S_OK;
728     ID2D1Effect dpiCompensationEffect = null;
729 
730     if (inputBitmap is null)
731     {
732         effect.SetInput(inputIndex, null);
733         return hr;
734     }
735 
736     hr = deviceContext.CreateEffect(&CLSID_D2D1DpiCompensation, &dpiCompensationEffect);
737 
738     if (SUCCEEDED(hr))
739     {
740             if (SUCCEEDED(hr))
741             {
742                 dpiCompensationEffect.SetInput(0, inputBitmap);
743 
744                 D2D1_POINT_2F bitmapDpi;
745                 inputBitmap.GetDpi(bitmapDpi.x, bitmapDpi.y);
746                 hr = dpiCompensationEffect.SetValue(D2D1_DPICOMPENSATION_PROP_INPUT_DPI, bitmapDpi);
747             }
748 
749             if (SUCCEEDED(hr))
750             {
751                 hr = dpiCompensationEffect.SetValue(D2D1_DPICOMPENSATION_PROP_INTERPOLATION_MODE, interpolationMode);
752             }
753 
754             if (SUCCEEDED(hr))
755             {
756                 hr = dpiCompensationEffect.SetValue(D2D1_DPICOMPENSATION_PROP_BORDER_MODE, borderMode);
757             }
758 
759             if (SUCCEEDED(hr))
760             {
761                 effect.SetInputEffect(inputIndex, dpiCompensationEffect);
762             }
763 
764             if (dpiCompensationEffect !is null)
765             {
766                 dpiCompensationEffect.Release();
767             }
768     }
769 
770     return hr;
771 }