2 * Copyright 2014 Henri Verbeet for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "wine/port.h"
22 #include "d2d1_private.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(d2d
);
26 struct d2d_bitmap_brush_cb
28 float _11
, _21
, _31
, pad0
;
29 float _12
, _22
, _32
, opacity
;
30 BOOL ignore_alpha
, pad1
, pad2
, pad3
;
33 static inline struct d2d_gradient
*impl_from_ID2D1GradientStopCollection(ID2D1GradientStopCollection
*iface
)
35 return CONTAINING_RECORD(iface
, struct d2d_gradient
, ID2D1GradientStopCollection_iface
);
38 static HRESULT STDMETHODCALLTYPE
d2d_gradient_QueryInterface(ID2D1GradientStopCollection
*iface
,
39 REFIID iid
, void **out
)
41 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
43 if (IsEqualGUID(iid
, &IID_ID2D1GradientStopCollection
)
44 || IsEqualGUID(iid
, &IID_ID2D1Resource
)
45 || IsEqualGUID(iid
, &IID_IUnknown
))
47 ID2D1GradientStopCollection_AddRef(iface
);
52 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
58 static ULONG STDMETHODCALLTYPE
d2d_gradient_AddRef(ID2D1GradientStopCollection
*iface
)
60 struct d2d_gradient
*gradient
= impl_from_ID2D1GradientStopCollection(iface
);
61 ULONG refcount
= InterlockedIncrement(&gradient
->refcount
);
63 TRACE("%p increasing refcount to %u.\n", iface
, refcount
);
68 static ULONG STDMETHODCALLTYPE
d2d_gradient_Release(ID2D1GradientStopCollection
*iface
)
70 struct d2d_gradient
*gradient
= impl_from_ID2D1GradientStopCollection(iface
);
71 ULONG refcount
= InterlockedDecrement(&gradient
->refcount
);
73 TRACE("%p decreasing refcount to %u.\n", iface
, refcount
);
77 HeapFree(GetProcessHeap(), 0, gradient
->stops
);
78 ID2D1Factory_Release(gradient
->factory
);
79 HeapFree(GetProcessHeap(), 0, gradient
);
85 static void STDMETHODCALLTYPE
d2d_gradient_GetFactory(ID2D1GradientStopCollection
*iface
, ID2D1Factory
**factory
)
87 struct d2d_gradient
*gradient
= impl_from_ID2D1GradientStopCollection(iface
);
89 TRACE("iface %p, factory %p.\n", iface
, factory
);
91 ID2D1Factory_AddRef(*factory
= gradient
->factory
);
94 static UINT32 STDMETHODCALLTYPE
d2d_gradient_GetGradientStopCount(ID2D1GradientStopCollection
*iface
)
96 struct d2d_gradient
*gradient
= impl_from_ID2D1GradientStopCollection(iface
);
98 TRACE("iface %p.\n", iface
);
100 return gradient
->stop_count
;
103 static void STDMETHODCALLTYPE
d2d_gradient_GetGradientStops(ID2D1GradientStopCollection
*iface
,
104 D2D1_GRADIENT_STOP
*stops
, UINT32 stop_count
)
106 struct d2d_gradient
*gradient
= impl_from_ID2D1GradientStopCollection(iface
);
108 TRACE("iface %p, stops %p, stop_count %u.\n", iface
, stops
, stop_count
);
110 memcpy(stops
, gradient
->stops
, min(gradient
->stop_count
, stop_count
) * sizeof(*stops
));
111 if (stop_count
> gradient
->stop_count
)
112 memset(stops
, 0, (stop_count
- gradient
->stop_count
) * sizeof(*stops
));
115 static D2D1_GAMMA STDMETHODCALLTYPE
d2d_gradient_GetColorInterpolationGamma(ID2D1GradientStopCollection
*iface
)
117 FIXME("iface %p stub!\n", iface
);
119 return D2D1_GAMMA_1_0
;
122 static D2D1_EXTEND_MODE STDMETHODCALLTYPE
d2d_gradient_GetExtendMode(ID2D1GradientStopCollection
*iface
)
124 FIXME("iface %p stub!\n", iface
);
126 return D2D1_EXTEND_MODE_CLAMP
;
129 static const struct ID2D1GradientStopCollectionVtbl d2d_gradient_vtbl
=
131 d2d_gradient_QueryInterface
,
133 d2d_gradient_Release
,
134 d2d_gradient_GetFactory
,
135 d2d_gradient_GetGradientStopCount
,
136 d2d_gradient_GetGradientStops
,
137 d2d_gradient_GetColorInterpolationGamma
,
138 d2d_gradient_GetExtendMode
,
141 HRESULT
d2d_gradient_create(ID2D1Factory
*factory
, const D2D1_GRADIENT_STOP
*stops
,
142 UINT32 stop_count
, D2D1_GAMMA gamma
, D2D1_EXTEND_MODE extend_mode
, struct d2d_gradient
**gradient
)
144 if (!(*gradient
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(**gradient
))))
145 return E_OUTOFMEMORY
;
147 FIXME("Ignoring gradient properties.\n");
149 (*gradient
)->ID2D1GradientStopCollection_iface
.lpVtbl
= &d2d_gradient_vtbl
;
150 (*gradient
)->refcount
= 1;
151 ID2D1Factory_AddRef((*gradient
)->factory
= factory
);
153 (*gradient
)->stop_count
= stop_count
;
154 if (!((*gradient
)->stops
= HeapAlloc(GetProcessHeap(), 0, stop_count
* sizeof(*stops
))))
156 HeapFree(GetProcessHeap(), 0, *gradient
);
157 return E_OUTOFMEMORY
;
159 memcpy((*gradient
)->stops
, stops
, stop_count
* sizeof(*stops
));
161 TRACE("Created gradient %p.\n", *gradient
);
165 static void d2d_brush_destroy(struct d2d_brush
*brush
)
167 ID2D1Factory_Release(brush
->factory
);
168 HeapFree(GetProcessHeap(), 0, brush
);
171 static void d2d_brush_init(struct d2d_brush
*brush
, ID2D1Factory
*factory
,
172 enum d2d_brush_type type
, const D2D1_BRUSH_PROPERTIES
*desc
, const struct ID2D1BrushVtbl
*vtbl
)
174 static const D2D1_MATRIX_3X2_F identity
=
181 brush
->ID2D1Brush_iface
.lpVtbl
= vtbl
;
183 ID2D1Factory_AddRef(brush
->factory
= factory
);
184 brush
->opacity
= desc
? desc
->opacity
: 1.0f
;
185 brush
->transform
= desc
? desc
->transform
: identity
;
189 static inline struct d2d_brush
*impl_from_ID2D1SolidColorBrush(ID2D1SolidColorBrush
*iface
)
191 return CONTAINING_RECORD(iface
, struct d2d_brush
, ID2D1Brush_iface
);
194 static HRESULT STDMETHODCALLTYPE
d2d_solid_color_brush_QueryInterface(ID2D1SolidColorBrush
*iface
,
195 REFIID iid
, void **out
)
197 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
199 if (IsEqualGUID(iid
, &IID_ID2D1SolidColorBrush
)
200 || IsEqualGUID(iid
, &IID_ID2D1Brush
)
201 || IsEqualGUID(iid
, &IID_ID2D1Resource
)
202 || IsEqualGUID(iid
, &IID_IUnknown
))
204 ID2D1SolidColorBrush_AddRef(iface
);
209 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
212 return E_NOINTERFACE
;
215 static ULONG STDMETHODCALLTYPE
d2d_solid_color_brush_AddRef(ID2D1SolidColorBrush
*iface
)
217 struct d2d_brush
*brush
= impl_from_ID2D1SolidColorBrush(iface
);
218 ULONG refcount
= InterlockedIncrement(&brush
->refcount
);
220 TRACE("%p increasing refcount to %u.\n", iface
, refcount
);
225 static ULONG STDMETHODCALLTYPE
d2d_solid_color_brush_Release(ID2D1SolidColorBrush
*iface
)
227 struct d2d_brush
*brush
= impl_from_ID2D1SolidColorBrush(iface
);
228 ULONG refcount
= InterlockedDecrement(&brush
->refcount
);
230 TRACE("%p decreasing refcount to %u.\n", iface
, refcount
);
233 d2d_brush_destroy(brush
);
238 static void STDMETHODCALLTYPE
d2d_solid_color_brush_GetFactory(ID2D1SolidColorBrush
*iface
, ID2D1Factory
**factory
)
240 struct d2d_brush
*brush
= impl_from_ID2D1SolidColorBrush(iface
);
242 TRACE("iface %p, factory %p.\n", iface
, factory
);
244 ID2D1Factory_AddRef(*factory
= brush
->factory
);
247 static void STDMETHODCALLTYPE
d2d_solid_color_brush_SetOpacity(ID2D1SolidColorBrush
*iface
, float opacity
)
249 struct d2d_brush
*brush
= impl_from_ID2D1SolidColorBrush(iface
);
251 TRACE("iface %p, opacity %.8e.\n", iface
, opacity
);
253 brush
->opacity
= opacity
;
256 static void STDMETHODCALLTYPE
d2d_solid_color_brush_SetTransform(ID2D1SolidColorBrush
*iface
,
257 const D2D1_MATRIX_3X2_F
*transform
)
259 struct d2d_brush
*brush
= impl_from_ID2D1SolidColorBrush(iface
);
261 TRACE("iface %p, transform %p.\n", iface
, transform
);
263 brush
->transform
= *transform
;
266 static float STDMETHODCALLTYPE
d2d_solid_color_brush_GetOpacity(ID2D1SolidColorBrush
*iface
)
268 struct d2d_brush
*brush
= impl_from_ID2D1SolidColorBrush(iface
);
270 TRACE("iface %p.\n", iface
);
272 return brush
->opacity
;
275 static void STDMETHODCALLTYPE
d2d_solid_color_brush_GetTransform(ID2D1SolidColorBrush
*iface
,
276 D2D1_MATRIX_3X2_F
*transform
)
278 struct d2d_brush
*brush
= impl_from_ID2D1SolidColorBrush(iface
);
280 TRACE("iface %p, transform %p.\n", iface
, transform
);
282 *transform
= brush
->transform
;
285 static void STDMETHODCALLTYPE
d2d_solid_color_brush_SetColor(ID2D1SolidColorBrush
*iface
, const D2D1_COLOR_F
*color
)
287 struct d2d_brush
*brush
= impl_from_ID2D1SolidColorBrush(iface
);
289 TRACE("iface %p, color %p.\n", iface
, color
);
291 brush
->u
.solid
.color
= *color
;
294 static D2D1_COLOR_F
* STDMETHODCALLTYPE
d2d_solid_color_brush_GetColor(ID2D1SolidColorBrush
*iface
, D2D1_COLOR_F
*color
)
296 struct d2d_brush
*brush
= impl_from_ID2D1SolidColorBrush(iface
);
298 TRACE("iface %p, color %p.\n", iface
, color
);
300 *color
= brush
->u
.solid
.color
;
304 static const struct ID2D1SolidColorBrushVtbl d2d_solid_color_brush_vtbl
=
306 d2d_solid_color_brush_QueryInterface
,
307 d2d_solid_color_brush_AddRef
,
308 d2d_solid_color_brush_Release
,
309 d2d_solid_color_brush_GetFactory
,
310 d2d_solid_color_brush_SetOpacity
,
311 d2d_solid_color_brush_SetTransform
,
312 d2d_solid_color_brush_GetOpacity
,
313 d2d_solid_color_brush_GetTransform
,
314 d2d_solid_color_brush_SetColor
,
315 d2d_solid_color_brush_GetColor
,
318 HRESULT
d2d_solid_color_brush_create(ID2D1Factory
*factory
, const D2D1_COLOR_F
*color
,
319 const D2D1_BRUSH_PROPERTIES
*desc
, struct d2d_brush
**brush
)
321 if (!(*brush
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(**brush
))))
322 return E_OUTOFMEMORY
;
324 d2d_brush_init(*brush
, factory
, D2D_BRUSH_TYPE_SOLID
, desc
,
325 (ID2D1BrushVtbl
*)&d2d_solid_color_brush_vtbl
);
326 (*brush
)->u
.solid
.color
= *color
;
328 TRACE("Created brush %p.\n", *brush
);
332 static inline struct d2d_brush
*impl_from_ID2D1LinearGradientBrush(ID2D1LinearGradientBrush
*iface
)
334 return CONTAINING_RECORD(iface
, struct d2d_brush
, ID2D1Brush_iface
);
337 static HRESULT STDMETHODCALLTYPE
d2d_linear_gradient_brush_QueryInterface(ID2D1LinearGradientBrush
*iface
,
338 REFIID iid
, void **out
)
340 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
342 if (IsEqualGUID(iid
, &IID_ID2D1LinearGradientBrush
)
343 || IsEqualGUID(iid
, &IID_ID2D1Brush
)
344 || IsEqualGUID(iid
, &IID_ID2D1Resource
)
345 || IsEqualGUID(iid
, &IID_IUnknown
))
347 ID2D1LinearGradientBrush_AddRef(iface
);
352 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
355 return E_NOINTERFACE
;
358 static ULONG STDMETHODCALLTYPE
d2d_linear_gradient_brush_AddRef(ID2D1LinearGradientBrush
*iface
)
360 struct d2d_brush
*brush
= impl_from_ID2D1LinearGradientBrush(iface
);
361 ULONG refcount
= InterlockedIncrement(&brush
->refcount
);
363 TRACE("%p increasing refcount to %u.\n", iface
, refcount
);
368 static ULONG STDMETHODCALLTYPE
d2d_linear_gradient_brush_Release(ID2D1LinearGradientBrush
*iface
)
370 struct d2d_brush
*brush
= impl_from_ID2D1LinearGradientBrush(iface
);
371 ULONG refcount
= InterlockedDecrement(&brush
->refcount
);
373 TRACE("%p decreasing refcount to %u.\n", iface
, refcount
);
377 ID2D1GradientStopCollection_Release(brush
->u
.linear
.gradient
);
378 d2d_brush_destroy(brush
);
384 static void STDMETHODCALLTYPE
d2d_linear_gradient_brush_GetFactory(ID2D1LinearGradientBrush
*iface
,
385 ID2D1Factory
**factory
)
387 struct d2d_brush
*brush
= impl_from_ID2D1LinearGradientBrush(iface
);
389 TRACE("iface %p, factory %p.\n", iface
, factory
);
391 ID2D1Factory_AddRef(*factory
= brush
->factory
);
394 static void STDMETHODCALLTYPE
d2d_linear_gradient_brush_SetOpacity(ID2D1LinearGradientBrush
*iface
, float opacity
)
396 FIXME("iface %p, opacity %.8e stub!\n", iface
, opacity
);
399 static void STDMETHODCALLTYPE
d2d_linear_gradient_brush_SetTransform(ID2D1LinearGradientBrush
*iface
,
400 const D2D1_MATRIX_3X2_F
*transform
)
402 struct d2d_brush
*brush
= impl_from_ID2D1LinearGradientBrush(iface
);
404 TRACE("iface %p, transform %p.\n", iface
, transform
);
406 brush
->transform
= *transform
;
409 static float STDMETHODCALLTYPE
d2d_linear_gradient_brush_GetOpacity(ID2D1LinearGradientBrush
*iface
)
411 FIXME("iface %p stub!\n", iface
);
416 static void STDMETHODCALLTYPE
d2d_linear_gradient_brush_GetTransform(ID2D1LinearGradientBrush
*iface
,
417 D2D1_MATRIX_3X2_F
*transform
)
419 struct d2d_brush
*brush
= impl_from_ID2D1LinearGradientBrush(iface
);
421 TRACE("iface %p, transform %p.\n", iface
, transform
);
423 *transform
= brush
->transform
;
426 static void STDMETHODCALLTYPE
d2d_linear_gradient_brush_SetStartPoint(ID2D1LinearGradientBrush
*iface
,
427 D2D1_POINT_2F start_point
)
429 struct d2d_brush
*brush
= impl_from_ID2D1LinearGradientBrush(iface
);
431 TRACE("iface %p, start_point {%.8e, %.8e}.\n", iface
, start_point
.x
, start_point
.y
);
433 brush
->u
.linear
.desc
.startPoint
= start_point
;
436 static void STDMETHODCALLTYPE
d2d_linear_gradient_brush_SetEndPoint(ID2D1LinearGradientBrush
*iface
,
437 D2D1_POINT_2F end_point
)
439 struct d2d_brush
*brush
= impl_from_ID2D1LinearGradientBrush(iface
);
441 TRACE("iface %p, end_point {%.8e, %.8e}.\n", iface
, end_point
.x
, end_point
.y
);
443 brush
->u
.linear
.desc
.endPoint
= end_point
;
446 static D2D1_POINT_2F
* STDMETHODCALLTYPE
d2d_linear_gradient_brush_GetStartPoint(ID2D1LinearGradientBrush
*iface
,
447 D2D1_POINT_2F
*point
)
449 struct d2d_brush
*brush
= impl_from_ID2D1LinearGradientBrush(iface
);
451 TRACE("iface %p, point %p.\n", iface
, point
);
453 *point
= brush
->u
.linear
.desc
.startPoint
;
457 static D2D1_POINT_2F
* STDMETHODCALLTYPE
d2d_linear_gradient_brush_GetEndPoint(ID2D1LinearGradientBrush
*iface
,
458 D2D1_POINT_2F
*point
)
460 struct d2d_brush
*brush
= impl_from_ID2D1LinearGradientBrush(iface
);
462 TRACE("iface %p, point %p.\n", iface
, point
);
464 *point
= brush
->u
.linear
.desc
.endPoint
;
468 static void STDMETHODCALLTYPE
d2d_linear_gradient_brush_GetGradientStopCollection(ID2D1LinearGradientBrush
*iface
,
469 ID2D1GradientStopCollection
**gradient
)
471 struct d2d_brush
*brush
= impl_from_ID2D1LinearGradientBrush(iface
);
473 TRACE("iface %p, gradient %p.\n", iface
, gradient
);
475 ID2D1GradientStopCollection_AddRef(*gradient
= brush
->u
.linear
.gradient
);
478 static const struct ID2D1LinearGradientBrushVtbl d2d_linear_gradient_brush_vtbl
=
480 d2d_linear_gradient_brush_QueryInterface
,
481 d2d_linear_gradient_brush_AddRef
,
482 d2d_linear_gradient_brush_Release
,
483 d2d_linear_gradient_brush_GetFactory
,
484 d2d_linear_gradient_brush_SetOpacity
,
485 d2d_linear_gradient_brush_SetTransform
,
486 d2d_linear_gradient_brush_GetOpacity
,
487 d2d_linear_gradient_brush_GetTransform
,
488 d2d_linear_gradient_brush_SetStartPoint
,
489 d2d_linear_gradient_brush_SetEndPoint
,
490 d2d_linear_gradient_brush_GetStartPoint
,
491 d2d_linear_gradient_brush_GetEndPoint
,
492 d2d_linear_gradient_brush_GetGradientStopCollection
,
495 HRESULT
d2d_linear_gradient_brush_create(ID2D1Factory
*factory
, const D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES
*gradient_brush_desc
,
496 const D2D1_BRUSH_PROPERTIES
*brush_desc
, ID2D1GradientStopCollection
*gradient
, struct d2d_brush
**brush
)
498 if (!(*brush
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(**brush
))))
499 return E_OUTOFMEMORY
;
501 d2d_brush_init(*brush
, factory
, D2D_BRUSH_TYPE_LINEAR
, brush_desc
,
502 (ID2D1BrushVtbl
*)&d2d_linear_gradient_brush_vtbl
);
503 (*brush
)->u
.linear
.desc
= *gradient_brush_desc
;
504 ID2D1GradientStopCollection_AddRef((*brush
)->u
.linear
.gradient
= gradient
);
506 TRACE("Created brush %p.\n", *brush
);
510 static inline struct d2d_brush
*impl_from_ID2D1BitmapBrush(ID2D1BitmapBrush
*iface
)
512 return CONTAINING_RECORD(iface
, struct d2d_brush
, ID2D1Brush_iface
);
515 static HRESULT STDMETHODCALLTYPE
d2d_bitmap_brush_QueryInterface(ID2D1BitmapBrush
*iface
,
516 REFIID iid
, void **out
)
518 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
520 if (IsEqualGUID(iid
, &IID_ID2D1BitmapBrush
)
521 || IsEqualGUID(iid
, &IID_ID2D1Brush
)
522 || IsEqualGUID(iid
, &IID_ID2D1Resource
)
523 || IsEqualGUID(iid
, &IID_IUnknown
))
525 ID2D1BitmapBrush_AddRef(iface
);
530 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
533 return E_NOINTERFACE
;
536 static ULONG STDMETHODCALLTYPE
d2d_bitmap_brush_AddRef(ID2D1BitmapBrush
*iface
)
538 struct d2d_brush
*brush
= impl_from_ID2D1BitmapBrush(iface
);
539 ULONG refcount
= InterlockedIncrement(&brush
->refcount
);
541 TRACE("%p increasing refcount to %u.\n", iface
, refcount
);
546 static ULONG STDMETHODCALLTYPE
d2d_bitmap_brush_Release(ID2D1BitmapBrush
*iface
)
548 struct d2d_brush
*brush
= impl_from_ID2D1BitmapBrush(iface
);
549 ULONG refcount
= InterlockedDecrement(&brush
->refcount
);
551 TRACE("%p decreasing refcount to %u.\n", iface
, refcount
);
555 if (brush
->u
.bitmap
.sampler_state
)
556 ID3D10SamplerState_Release(brush
->u
.bitmap
.sampler_state
);
557 if (brush
->u
.bitmap
.bitmap
)
558 ID2D1Bitmap_Release(&brush
->u
.bitmap
.bitmap
->ID2D1Bitmap_iface
);
559 d2d_brush_destroy(brush
);
565 static void STDMETHODCALLTYPE
d2d_bitmap_brush_GetFactory(ID2D1BitmapBrush
*iface
,
566 ID2D1Factory
**factory
)
568 struct d2d_brush
*brush
= impl_from_ID2D1BitmapBrush(iface
);
570 TRACE("iface %p, factory %p.\n", iface
, factory
);
572 ID2D1Factory_AddRef(*factory
= brush
->factory
);
575 static void STDMETHODCALLTYPE
d2d_bitmap_brush_SetOpacity(ID2D1BitmapBrush
*iface
, float opacity
)
577 struct d2d_brush
*brush
= impl_from_ID2D1BitmapBrush(iface
);
579 TRACE("iface %p, opacity %.8e.\n", iface
, opacity
);
581 brush
->opacity
= opacity
;
584 static void STDMETHODCALLTYPE
d2d_bitmap_brush_SetTransform(ID2D1BitmapBrush
*iface
,
585 const D2D1_MATRIX_3X2_F
*transform
)
587 struct d2d_brush
*brush
= impl_from_ID2D1BitmapBrush(iface
);
589 TRACE("iface %p, transform %p.\n", iface
, transform
);
591 brush
->transform
= *transform
;
594 static float STDMETHODCALLTYPE
d2d_bitmap_brush_GetOpacity(ID2D1BitmapBrush
*iface
)
596 struct d2d_brush
*brush
= impl_from_ID2D1BitmapBrush(iface
);
598 TRACE("iface %p.\n", iface
);
600 return brush
->opacity
;
603 static void STDMETHODCALLTYPE
d2d_bitmap_brush_GetTransform(ID2D1BitmapBrush
*iface
,
604 D2D1_MATRIX_3X2_F
*transform
)
606 struct d2d_brush
*brush
= impl_from_ID2D1BitmapBrush(iface
);
608 TRACE("iface %p, transform %p.\n", iface
, transform
);
610 *transform
= brush
->transform
;
613 static void STDMETHODCALLTYPE
d2d_bitmap_brush_SetExtendModeX(ID2D1BitmapBrush
*iface
, D2D1_EXTEND_MODE mode
)
615 struct d2d_brush
*brush
= impl_from_ID2D1BitmapBrush(iface
);
617 TRACE("iface %p, mode %#x.\n", iface
, mode
);
619 brush
->u
.bitmap
.extend_mode_x
= mode
;
620 if (brush
->u
.bitmap
.sampler_state
)
622 ID3D10SamplerState_Release(brush
->u
.bitmap
.sampler_state
);
623 brush
->u
.bitmap
.sampler_state
= NULL
;
627 static void STDMETHODCALLTYPE
d2d_bitmap_brush_SetExtendModeY(ID2D1BitmapBrush
*iface
, D2D1_EXTEND_MODE mode
)
629 struct d2d_brush
*brush
= impl_from_ID2D1BitmapBrush(iface
);
631 TRACE("iface %p, mode %#x.\n", iface
, mode
);
633 brush
->u
.bitmap
.extend_mode_y
= mode
;
634 if (brush
->u
.bitmap
.sampler_state
)
636 ID3D10SamplerState_Release(brush
->u
.bitmap
.sampler_state
);
637 brush
->u
.bitmap
.sampler_state
= NULL
;
641 static void STDMETHODCALLTYPE
d2d_bitmap_brush_SetInterpolationMode(ID2D1BitmapBrush
*iface
,
642 D2D1_BITMAP_INTERPOLATION_MODE mode
)
644 struct d2d_brush
*brush
= impl_from_ID2D1BitmapBrush(iface
);
646 TRACE("iface %p, mode %#x.\n", iface
, mode
);
648 brush
->u
.bitmap
.interpolation_mode
= mode
;
649 if (brush
->u
.bitmap
.sampler_state
)
651 ID3D10SamplerState_Release(brush
->u
.bitmap
.sampler_state
);
652 brush
->u
.bitmap
.sampler_state
= NULL
;
656 static void STDMETHODCALLTYPE
d2d_bitmap_brush_SetBitmap(ID2D1BitmapBrush
*iface
, ID2D1Bitmap
*bitmap
)
658 struct d2d_brush
*brush
= impl_from_ID2D1BitmapBrush(iface
);
660 TRACE("iface %p, bitmap %p.\n", iface
, bitmap
);
663 ID2D1Bitmap_AddRef(bitmap
);
664 if (brush
->u
.bitmap
.bitmap
)
665 ID2D1Bitmap_Release(&brush
->u
.bitmap
.bitmap
->ID2D1Bitmap_iface
);
666 brush
->u
.bitmap
.bitmap
= unsafe_impl_from_ID2D1Bitmap(bitmap
);
669 static D2D1_EXTEND_MODE STDMETHODCALLTYPE
d2d_bitmap_brush_GetExtendModeX(ID2D1BitmapBrush
*iface
)
671 struct d2d_brush
*brush
= impl_from_ID2D1BitmapBrush(iface
);
673 TRACE("iface %p.\n", iface
);
675 return brush
->u
.bitmap
.extend_mode_x
;
678 static D2D1_EXTEND_MODE STDMETHODCALLTYPE
d2d_bitmap_brush_GetExtendModeY(ID2D1BitmapBrush
*iface
)
680 struct d2d_brush
*brush
= impl_from_ID2D1BitmapBrush(iface
);
682 TRACE("iface %p.\n", iface
);
684 return brush
->u
.bitmap
.extend_mode_y
;
687 static D2D1_BITMAP_INTERPOLATION_MODE STDMETHODCALLTYPE
d2d_bitmap_brush_GetInterpolationMode(ID2D1BitmapBrush
*iface
)
689 struct d2d_brush
*brush
= impl_from_ID2D1BitmapBrush(iface
);
691 TRACE("iface %p.\n", iface
);
693 return brush
->u
.bitmap
.interpolation_mode
;
696 static void STDMETHODCALLTYPE
d2d_bitmap_brush_GetBitmap(ID2D1BitmapBrush
*iface
, ID2D1Bitmap
**bitmap
)
698 struct d2d_brush
*brush
= impl_from_ID2D1BitmapBrush(iface
);
700 TRACE("iface %p, bitmap %p.\n", iface
, bitmap
);
702 if ((*bitmap
= &brush
->u
.bitmap
.bitmap
->ID2D1Bitmap_iface
))
703 ID2D1Bitmap_AddRef(*bitmap
);
706 static const struct ID2D1BitmapBrushVtbl d2d_bitmap_brush_vtbl
=
708 d2d_bitmap_brush_QueryInterface
,
709 d2d_bitmap_brush_AddRef
,
710 d2d_bitmap_brush_Release
,
711 d2d_bitmap_brush_GetFactory
,
712 d2d_bitmap_brush_SetOpacity
,
713 d2d_bitmap_brush_SetTransform
,
714 d2d_bitmap_brush_GetOpacity
,
715 d2d_bitmap_brush_GetTransform
,
716 d2d_bitmap_brush_SetExtendModeX
,
717 d2d_bitmap_brush_SetExtendModeY
,
718 d2d_bitmap_brush_SetInterpolationMode
,
719 d2d_bitmap_brush_SetBitmap
,
720 d2d_bitmap_brush_GetExtendModeX
,
721 d2d_bitmap_brush_GetExtendModeY
,
722 d2d_bitmap_brush_GetInterpolationMode
,
723 d2d_bitmap_brush_GetBitmap
,
726 HRESULT
d2d_bitmap_brush_create(ID2D1Factory
*factory
, ID2D1Bitmap
*bitmap
, const D2D1_BITMAP_BRUSH_PROPERTIES
*bitmap_brush_desc
,
727 const D2D1_BRUSH_PROPERTIES
*brush_desc
, struct d2d_brush
**brush
)
729 if (!(*brush
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(**brush
))))
730 return E_OUTOFMEMORY
;
732 d2d_brush_init(*brush
, factory
, D2D_BRUSH_TYPE_BITMAP
,
733 brush_desc
, (ID2D1BrushVtbl
*)&d2d_bitmap_brush_vtbl
);
734 if (((*brush
)->u
.bitmap
.bitmap
= unsafe_impl_from_ID2D1Bitmap(bitmap
)))
735 ID2D1Bitmap_AddRef(&(*brush
)->u
.bitmap
.bitmap
->ID2D1Bitmap_iface
);
736 if (bitmap_brush_desc
)
738 (*brush
)->u
.bitmap
.extend_mode_x
= bitmap_brush_desc
->extendModeX
;
739 (*brush
)->u
.bitmap
.extend_mode_y
= bitmap_brush_desc
->extendModeY
;
740 (*brush
)->u
.bitmap
.interpolation_mode
= bitmap_brush_desc
->interpolationMode
;
744 (*brush
)->u
.bitmap
.extend_mode_x
= D2D1_EXTEND_MODE_CLAMP
;
745 (*brush
)->u
.bitmap
.extend_mode_y
= D2D1_EXTEND_MODE_CLAMP
;
746 (*brush
)->u
.bitmap
.interpolation_mode
= D2D1_BITMAP_INTERPOLATION_MODE_LINEAR
;
749 TRACE("Created brush %p.\n", *brush
);
753 struct d2d_brush
*unsafe_impl_from_ID2D1Brush(ID2D1Brush
*iface
)
757 assert(iface
->lpVtbl
== (const ID2D1BrushVtbl
*)&d2d_solid_color_brush_vtbl
758 || iface
->lpVtbl
== (const ID2D1BrushVtbl
*)&d2d_linear_gradient_brush_vtbl
759 || iface
->lpVtbl
== (const ID2D1BrushVtbl
*)&d2d_bitmap_brush_vtbl
);
760 return CONTAINING_RECORD(iface
, struct d2d_brush
, ID2D1Brush_iface
);
763 static D3D10_TEXTURE_ADDRESS_MODE
texture_address_mode_from_extend_mode(D2D1_EXTEND_MODE mode
)
767 case D2D1_EXTEND_MODE_CLAMP
:
768 return D3D10_TEXTURE_ADDRESS_CLAMP
;
769 case D2D1_EXTEND_MODE_WRAP
:
770 return D3D10_TEXTURE_ADDRESS_WRAP
;
771 case D2D1_EXTEND_MODE_MIRROR
:
772 return D3D10_TEXTURE_ADDRESS_MIRROR
;
774 FIXME("Unhandled extend mode %#x.\n", mode
);
775 return D3D10_TEXTURE_ADDRESS_CLAMP
;
779 static BOOL
d2d_brush_fill_cb(struct d2d_brush
*brush
, struct d2d_d3d_render_target
*render_target
, void *cb
)
781 struct d2d_bitmap_brush_cb
*bitmap_brush_cb
;
784 if (brush
->type
== D2D_BRUSH_TYPE_SOLID
)
788 *color
= brush
->u
.solid
.color
;
789 color
->a
*= brush
->opacity
;
790 color
->r
*= color
->a
;
791 color
->g
*= color
->a
;
792 color
->b
*= color
->a
;
797 if (brush
->type
== D2D_BRUSH_TYPE_BITMAP
)
799 struct d2d_bitmap
*bitmap
= brush
->u
.bitmap
.bitmap
;
800 D2D_MATRIX_3X2_F w
, b
;
803 bitmap_brush_cb
= cb
;
806 w
= render_target
->drawing_state
.transform
;
807 dpi_scale
= render_target
->desc
.dpiX
/ 96.0f
;
811 dpi_scale
= render_target
->desc
.dpiY
/ 96.0f
;
816 /* Scale for bitmap size and dpi. */
817 b
= brush
->transform
;
818 dpi_scale
= bitmap
->pixel_size
.width
* (96.0f
/ bitmap
->dpi_x
);
821 dpi_scale
= bitmap
->pixel_size
.height
* (96.0f
/ bitmap
->dpi_y
);
825 d2d_matrix_multiply(&b
, &w
);
827 /* Invert the matrix. (Because the matrix is applied to the sampling
828 * coordinates. I.e., to scale the bitmap by 2 we need to divide the
829 * coordinates by 2.) */
830 d
= b
._11
* b
._22
- b
._21
* b
._12
;
833 bitmap_brush_cb
->_11
= b
._22
/ d
;
834 bitmap_brush_cb
->_21
= -b
._21
/ d
;
835 bitmap_brush_cb
->_31
= (b
._21
* b
._32
- b
._31
* b
._22
) / d
;
836 bitmap_brush_cb
->_12
= -b
._12
/ d
;
837 bitmap_brush_cb
->_22
= b
._11
/ d
;
838 bitmap_brush_cb
->_32
= -(b
._11
* b
._32
- b
._31
* b
._12
) / d
;
840 bitmap_brush_cb
->opacity
= brush
->opacity
;
841 bitmap_brush_cb
->ignore_alpha
= bitmap
->format
.alphaMode
== D2D1_ALPHA_MODE_IGNORE
;
846 FIXME("Unhandled brush type %#x.\n", brush
->type
);
850 HRESULT
d2d_brush_get_ps_cb(struct d2d_brush
*brush
, struct d2d_brush
*opacity_brush
,
851 struct d2d_d3d_render_target
*render_target
, ID3D10Buffer
**ps_cb
)
853 D3D10_SUBRESOURCE_DATA buffer_data
;
854 D3D10_BUFFER_DESC buffer_desc
;
858 static const size_t brush_sizes
[] =
860 /* D2D_BRUSH_TYPE_SOLID */ sizeof(D2D1_COLOR_F
),
861 /* D2D_BRUSH_TYPE_LINEAR */ 0,
862 /* D2D_BRUSH_TYPE_BITMAP */ sizeof(struct d2d_bitmap_brush_cb
),
865 buffer_desc
.Usage
= D3D10_USAGE_DEFAULT
;
866 buffer_desc
.BindFlags
= D3D10_BIND_CONSTANT_BUFFER
;
867 buffer_desc
.CPUAccessFlags
= 0;
868 buffer_desc
.MiscFlags
= 0;
870 buffer_data
.SysMemPitch
= 0;
871 buffer_data
.SysMemSlicePitch
= 0;
873 if (brush
->type
>= sizeof(brush_sizes
) / sizeof(*brush_sizes
))
875 ERR("Unhandled brush type %#x.\n", brush
->type
);
879 buffer_desc
.ByteWidth
= brush_sizes
[brush
->type
];
882 if (opacity_brush
->type
>= sizeof(brush_sizes
) / sizeof(*brush_sizes
))
884 ERR("Unhandled opacity brush type %#x.\n", opacity_brush
->type
);
887 buffer_desc
.ByteWidth
+= brush_sizes
[opacity_brush
->type
];
890 if (!(cb_data
= HeapAlloc(GetProcessHeap(), 0, buffer_desc
.ByteWidth
)))
892 ERR("Failed to allocate constant buffer data.\n");
893 return E_OUTOFMEMORY
;
895 buffer_data
.pSysMem
= cb_data
;
897 if (!d2d_brush_fill_cb(brush
, render_target
, cb_data
))
899 HeapFree(GetProcessHeap(), 0, cb_data
);
902 if (opacity_brush
&& !d2d_brush_fill_cb(opacity_brush
, render_target
, cb_data
+ brush_sizes
[brush
->type
]))
904 HeapFree(GetProcessHeap(), 0, cb_data
);
908 if (FAILED(hr
= ID3D10Device_CreateBuffer(render_target
->device
, &buffer_desc
, &buffer_data
, ps_cb
)))
909 ERR("Failed to create constant buffer, hr %#x.\n", hr
);
910 HeapFree(GetProcessHeap(), 0, cb_data
);
915 static void d2d_brush_bind_bitmap(struct d2d_brush
*brush
, ID3D10Device
*device
,
916 unsigned int resource_idx
, unsigned int sampler_idx
)
920 ID3D10Device_PSSetShaderResources(device
, resource_idx
, 1, &brush
->u
.bitmap
.bitmap
->view
);
921 if (!brush
->u
.bitmap
.sampler_state
)
923 D3D10_SAMPLER_DESC sampler_desc
;
925 if (brush
->u
.bitmap
.interpolation_mode
== D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR
)
926 sampler_desc
.Filter
= D3D10_FILTER_MIN_MAG_MIP_POINT
;
928 sampler_desc
.Filter
= D3D10_FILTER_MIN_MAG_MIP_LINEAR
;
929 sampler_desc
.AddressU
= texture_address_mode_from_extend_mode(brush
->u
.bitmap
.extend_mode_x
);
930 sampler_desc
.AddressV
= texture_address_mode_from_extend_mode(brush
->u
.bitmap
.extend_mode_y
);
931 sampler_desc
.AddressW
= D3D10_TEXTURE_ADDRESS_CLAMP
;
932 sampler_desc
.MipLODBias
= 0.0f
;
933 sampler_desc
.MaxAnisotropy
= 0;
934 sampler_desc
.ComparisonFunc
= D3D10_COMPARISON_NEVER
;
935 sampler_desc
.BorderColor
[0] = 0.0f
;
936 sampler_desc
.BorderColor
[1] = 0.0f
;
937 sampler_desc
.BorderColor
[2] = 0.0f
;
938 sampler_desc
.BorderColor
[3] = 0.0f
;
939 sampler_desc
.MinLOD
= 0.0f
;
940 sampler_desc
.MaxLOD
= 0.0f
;
942 if (FAILED(hr
= ID3D10Device_CreateSamplerState(device
,
943 &sampler_desc
, &brush
->u
.bitmap
.sampler_state
)))
944 ERR("Failed to create sampler state, hr %#x.\n", hr
);
946 ID3D10Device_PSSetSamplers(device
, sampler_idx
, 1, &brush
->u
.bitmap
.sampler_state
);
949 void d2d_brush_bind_resources(struct d2d_brush
*brush
, struct d2d_brush
*opacity_brush
,
950 struct d2d_d3d_render_target
*render_target
, enum d2d_shape_type shape_type
)
952 static const float blend_factor
[] = {1.0f
, 1.0f
, 1.0f
, 1.0f
};
953 unsigned int resource_idx
= 0, sampler_idx
= 0;
954 ID3D10Device
*device
= render_target
->device
;
955 enum d2d_brush_type opacity_brush_type
;
956 ID3D10PixelShader
*ps
;
958 ID3D10Device_OMSetBlendState(device
, render_target
->bs
, blend_factor
, D3D10_DEFAULT_SAMPLE_MASK
);
959 opacity_brush_type
= opacity_brush
? opacity_brush
->type
: D2D_BRUSH_TYPE_COUNT
;
960 if (!(ps
= render_target
->shape_resources
[shape_type
].ps
[brush
->type
][opacity_brush_type
]))
961 FIXME("No pixel shader for shape type %#x and brush types %#x/%#x.\n",
962 shape_type
, brush
->type
, opacity_brush_type
);
963 ID3D10Device_PSSetShader(device
, ps
);
965 if (brush
->type
== D2D_BRUSH_TYPE_BITMAP
)
966 d2d_brush_bind_bitmap(brush
, device
, resource_idx
++, sampler_idx
++);
967 else if (brush
->type
!= D2D_BRUSH_TYPE_SOLID
)
968 FIXME("Unhandled brush type %#x.\n", brush
->type
);
972 if (opacity_brush
->type
== D2D_BRUSH_TYPE_BITMAP
)
973 d2d_brush_bind_bitmap(opacity_brush
, device
, resource_idx
++, sampler_idx
++);
974 else if (opacity_brush
->type
!= D2D_BRUSH_TYPE_SOLID
)
975 FIXME("Unhandled opacity brush type %#x.\n", opacity_brush
->type
);