d3d8/tests: Add helpers to avoid multiple readbacks of the render target surface.
[wine.git] / dlls / d2d1 / brush.c
blobf450f24e9a80f953e0eb1e164908e41ef06e383d
1 /*
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
19 #include "config.h"
20 #include "wine/port.h"
22 #include "d2d1_private.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(d2d);
26 static inline struct d2d_gradient *impl_from_ID2D1GradientStopCollection(ID2D1GradientStopCollection *iface)
28 return CONTAINING_RECORD(iface, struct d2d_gradient, ID2D1GradientStopCollection_iface);
31 static HRESULT STDMETHODCALLTYPE d2d_gradient_QueryInterface(ID2D1GradientStopCollection *iface,
32 REFIID iid, void **out)
34 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
36 if (IsEqualGUID(iid, &IID_ID2D1GradientStopCollection)
37 || IsEqualGUID(iid, &IID_ID2D1Resource)
38 || IsEqualGUID(iid, &IID_IUnknown))
40 ID2D1GradientStopCollection_AddRef(iface);
41 *out = iface;
42 return S_OK;
45 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
47 *out = NULL;
48 return E_NOINTERFACE;
51 static ULONG STDMETHODCALLTYPE d2d_gradient_AddRef(ID2D1GradientStopCollection *iface)
53 struct d2d_gradient *gradient = impl_from_ID2D1GradientStopCollection(iface);
54 ULONG refcount = InterlockedIncrement(&gradient->refcount);
56 TRACE("%p increasing refcount to %u.\n", iface, refcount);
58 return refcount;
61 static ULONG STDMETHODCALLTYPE d2d_gradient_Release(ID2D1GradientStopCollection *iface)
63 struct d2d_gradient *gradient = impl_from_ID2D1GradientStopCollection(iface);
64 ULONG refcount = InterlockedDecrement(&gradient->refcount);
66 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
68 if (!refcount)
70 HeapFree(GetProcessHeap(), 0, gradient->stops);
71 ID2D1Factory_Release(gradient->factory);
72 HeapFree(GetProcessHeap(), 0, gradient);
75 return refcount;
78 static void STDMETHODCALLTYPE d2d_gradient_GetFactory(ID2D1GradientStopCollection *iface, ID2D1Factory **factory)
80 struct d2d_gradient *gradient = impl_from_ID2D1GradientStopCollection(iface);
82 TRACE("iface %p, factory %p.\n", iface, factory);
84 ID2D1Factory_AddRef(*factory = gradient->factory);
87 static UINT32 STDMETHODCALLTYPE d2d_gradient_GetGradientStopCount(ID2D1GradientStopCollection *iface)
89 struct d2d_gradient *gradient = impl_from_ID2D1GradientStopCollection(iface);
91 TRACE("iface %p.\n", iface);
93 return gradient->stop_count;
96 static void STDMETHODCALLTYPE d2d_gradient_GetGradientStops(ID2D1GradientStopCollection *iface,
97 D2D1_GRADIENT_STOP *stops, UINT32 stop_count)
99 struct d2d_gradient *gradient = impl_from_ID2D1GradientStopCollection(iface);
101 TRACE("iface %p, stops %p, stop_count %u.\n", iface, stops, stop_count);
103 memcpy(stops, gradient->stops, min(gradient->stop_count, stop_count) * sizeof(*stops));
104 if (stop_count > gradient->stop_count)
105 memset(stops, 0, (stop_count - gradient->stop_count) * sizeof(*stops));
108 static D2D1_GAMMA STDMETHODCALLTYPE d2d_gradient_GetColorInterpolationGamma(ID2D1GradientStopCollection *iface)
110 FIXME("iface %p stub!\n", iface);
112 return D2D1_GAMMA_1_0;
115 static D2D1_EXTEND_MODE STDMETHODCALLTYPE d2d_gradient_GetExtendMode(ID2D1GradientStopCollection *iface)
117 FIXME("iface %p stub!\n", iface);
119 return D2D1_EXTEND_MODE_CLAMP;
122 static const struct ID2D1GradientStopCollectionVtbl d2d_gradient_vtbl =
124 d2d_gradient_QueryInterface,
125 d2d_gradient_AddRef,
126 d2d_gradient_Release,
127 d2d_gradient_GetFactory,
128 d2d_gradient_GetGradientStopCount,
129 d2d_gradient_GetGradientStops,
130 d2d_gradient_GetColorInterpolationGamma,
131 d2d_gradient_GetExtendMode,
134 HRESULT d2d_gradient_init(struct d2d_gradient *gradient, ID2D1Factory *factory,
135 const D2D1_GRADIENT_STOP *stops, UINT32 stop_count, D2D1_GAMMA gamma, D2D1_EXTEND_MODE extend_mode)
137 FIXME("Ignoring gradient properties.\n");
139 gradient->ID2D1GradientStopCollection_iface.lpVtbl = &d2d_gradient_vtbl;
140 gradient->refcount = 1;
141 ID2D1Factory_AddRef(gradient->factory = factory);
143 gradient->stop_count = stop_count;
144 if (!(gradient->stops = HeapAlloc(GetProcessHeap(), 0, stop_count * sizeof(*stops))))
145 return E_OUTOFMEMORY;
146 memcpy(gradient->stops, stops, stop_count * sizeof(*stops));
148 return S_OK;
151 static void d2d_brush_destroy(struct d2d_brush *brush)
153 ID2D1Factory_Release(brush->factory);
154 HeapFree(GetProcessHeap(), 0, brush);
157 static void d2d_brush_init(struct d2d_brush *brush, ID2D1Factory *factory,
158 enum d2d_brush_type type, const D2D1_BRUSH_PROPERTIES *desc, const struct ID2D1BrushVtbl *vtbl)
160 static const D2D1_MATRIX_3X2_F identity =
162 1.0f, 0.0f,
163 0.0f, 1.0f,
164 0.0f, 0.0f,
167 brush->ID2D1Brush_iface.lpVtbl = vtbl;
168 brush->refcount = 1;
169 ID2D1Factory_AddRef(brush->factory = factory);
170 brush->opacity = desc ? desc->opacity : 1.0f;
171 brush->transform = desc ? desc->transform : identity;
172 brush->type = type;
175 static inline struct d2d_brush *impl_from_ID2D1SolidColorBrush(ID2D1SolidColorBrush *iface)
177 return CONTAINING_RECORD(iface, struct d2d_brush, ID2D1Brush_iface);
180 static HRESULT STDMETHODCALLTYPE d2d_solid_color_brush_QueryInterface(ID2D1SolidColorBrush *iface,
181 REFIID iid, void **out)
183 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
185 if (IsEqualGUID(iid, &IID_ID2D1SolidColorBrush)
186 || IsEqualGUID(iid, &IID_ID2D1Brush)
187 || IsEqualGUID(iid, &IID_ID2D1Resource)
188 || IsEqualGUID(iid, &IID_IUnknown))
190 ID2D1SolidColorBrush_AddRef(iface);
191 *out = iface;
192 return S_OK;
195 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
197 *out = NULL;
198 return E_NOINTERFACE;
201 static ULONG STDMETHODCALLTYPE d2d_solid_color_brush_AddRef(ID2D1SolidColorBrush *iface)
203 struct d2d_brush *brush = impl_from_ID2D1SolidColorBrush(iface);
204 ULONG refcount = InterlockedIncrement(&brush->refcount);
206 TRACE("%p increasing refcount to %u.\n", iface, refcount);
208 return refcount;
211 static ULONG STDMETHODCALLTYPE d2d_solid_color_brush_Release(ID2D1SolidColorBrush *iface)
213 struct d2d_brush *brush = impl_from_ID2D1SolidColorBrush(iface);
214 ULONG refcount = InterlockedDecrement(&brush->refcount);
216 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
218 if (!refcount)
219 d2d_brush_destroy(brush);
221 return refcount;
224 static void STDMETHODCALLTYPE d2d_solid_color_brush_GetFactory(ID2D1SolidColorBrush *iface, ID2D1Factory **factory)
226 struct d2d_brush *brush = impl_from_ID2D1SolidColorBrush(iface);
228 TRACE("iface %p, factory %p.\n", iface, factory);
230 ID2D1Factory_AddRef(*factory = brush->factory);
233 static void STDMETHODCALLTYPE d2d_solid_color_brush_SetOpacity(ID2D1SolidColorBrush *iface, float opacity)
235 struct d2d_brush *brush = impl_from_ID2D1SolidColorBrush(iface);
237 TRACE("iface %p, opacity %.8e.\n", iface, opacity);
239 brush->opacity = opacity;
242 static void STDMETHODCALLTYPE d2d_solid_color_brush_SetTransform(ID2D1SolidColorBrush *iface,
243 const D2D1_MATRIX_3X2_F *transform)
245 struct d2d_brush *brush = impl_from_ID2D1SolidColorBrush(iface);
247 TRACE("iface %p, transform %p.\n", iface, transform);
249 brush->transform = *transform;
252 static float STDMETHODCALLTYPE d2d_solid_color_brush_GetOpacity(ID2D1SolidColorBrush *iface)
254 struct d2d_brush *brush = impl_from_ID2D1SolidColorBrush(iface);
256 TRACE("iface %p.\n", iface);
258 return brush->opacity;
261 static void STDMETHODCALLTYPE d2d_solid_color_brush_GetTransform(ID2D1SolidColorBrush *iface,
262 D2D1_MATRIX_3X2_F *transform)
264 struct d2d_brush *brush = impl_from_ID2D1SolidColorBrush(iface);
266 TRACE("iface %p, transform %p.\n", iface, transform);
268 *transform = brush->transform;
271 static void STDMETHODCALLTYPE d2d_solid_color_brush_SetColor(ID2D1SolidColorBrush *iface, const D2D1_COLOR_F *color)
273 struct d2d_brush *brush = impl_from_ID2D1SolidColorBrush(iface);
275 TRACE("iface %p, color %p.\n", iface, color);
277 brush->u.solid.color = *color;
280 static D2D1_COLOR_F * STDMETHODCALLTYPE d2d_solid_color_brush_GetColor(ID2D1SolidColorBrush *iface, D2D1_COLOR_F *color)
282 struct d2d_brush *brush = impl_from_ID2D1SolidColorBrush(iface);
284 TRACE("iface %p, color %p.\n", iface, color);
286 *color = brush->u.solid.color;
287 return color;
290 static const struct ID2D1SolidColorBrushVtbl d2d_solid_color_brush_vtbl =
292 d2d_solid_color_brush_QueryInterface,
293 d2d_solid_color_brush_AddRef,
294 d2d_solid_color_brush_Release,
295 d2d_solid_color_brush_GetFactory,
296 d2d_solid_color_brush_SetOpacity,
297 d2d_solid_color_brush_SetTransform,
298 d2d_solid_color_brush_GetOpacity,
299 d2d_solid_color_brush_GetTransform,
300 d2d_solid_color_brush_SetColor,
301 d2d_solid_color_brush_GetColor,
304 void d2d_solid_color_brush_init(struct d2d_brush *brush, ID2D1Factory *factory,
305 const D2D1_COLOR_F *color, const D2D1_BRUSH_PROPERTIES *desc)
307 d2d_brush_init(brush, factory, D2D_BRUSH_TYPE_SOLID, desc,
308 (ID2D1BrushVtbl *)&d2d_solid_color_brush_vtbl);
309 brush->u.solid.color = *color;
312 static inline struct d2d_brush *impl_from_ID2D1LinearGradientBrush(ID2D1LinearGradientBrush *iface)
314 return CONTAINING_RECORD(iface, struct d2d_brush, ID2D1Brush_iface);
317 static HRESULT STDMETHODCALLTYPE d2d_linear_gradient_brush_QueryInterface(ID2D1LinearGradientBrush *iface,
318 REFIID iid, void **out)
320 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
322 if (IsEqualGUID(iid, &IID_ID2D1LinearGradientBrush)
323 || IsEqualGUID(iid, &IID_ID2D1Brush)
324 || IsEqualGUID(iid, &IID_ID2D1Resource)
325 || IsEqualGUID(iid, &IID_IUnknown))
327 ID2D1LinearGradientBrush_AddRef(iface);
328 *out = iface;
329 return S_OK;
332 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
334 *out = NULL;
335 return E_NOINTERFACE;
338 static ULONG STDMETHODCALLTYPE d2d_linear_gradient_brush_AddRef(ID2D1LinearGradientBrush *iface)
340 struct d2d_brush *brush = impl_from_ID2D1LinearGradientBrush(iface);
341 ULONG refcount = InterlockedIncrement(&brush->refcount);
343 TRACE("%p increasing refcount to %u.\n", iface, refcount);
345 return refcount;
348 static ULONG STDMETHODCALLTYPE d2d_linear_gradient_brush_Release(ID2D1LinearGradientBrush *iface)
350 struct d2d_brush *brush = impl_from_ID2D1LinearGradientBrush(iface);
351 ULONG refcount = InterlockedDecrement(&brush->refcount);
353 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
355 if (!refcount)
356 d2d_brush_destroy(brush);
358 return refcount;
361 static void STDMETHODCALLTYPE d2d_linear_gradient_brush_GetFactory(ID2D1LinearGradientBrush *iface,
362 ID2D1Factory **factory)
364 struct d2d_brush *brush = impl_from_ID2D1LinearGradientBrush(iface);
366 TRACE("iface %p, factory %p.\n", iface, factory);
368 ID2D1Factory_AddRef(*factory = brush->factory);
371 static void STDMETHODCALLTYPE d2d_linear_gradient_brush_SetOpacity(ID2D1LinearGradientBrush *iface, float opacity)
373 FIXME("iface %p, opacity %.8e stub!\n", iface, opacity);
376 static void STDMETHODCALLTYPE d2d_linear_gradient_brush_SetTransform(ID2D1LinearGradientBrush *iface,
377 const D2D1_MATRIX_3X2_F *transform)
379 struct d2d_brush *brush = impl_from_ID2D1LinearGradientBrush(iface);
381 TRACE("iface %p, transform %p.\n", iface, transform);
383 brush->transform = *transform;
386 static float STDMETHODCALLTYPE d2d_linear_gradient_brush_GetOpacity(ID2D1LinearGradientBrush *iface)
388 FIXME("iface %p stub!\n", iface);
390 return 0.0f;
393 static void STDMETHODCALLTYPE d2d_linear_gradient_brush_GetTransform(ID2D1LinearGradientBrush *iface,
394 D2D1_MATRIX_3X2_F *transform)
396 struct d2d_brush *brush = impl_from_ID2D1LinearGradientBrush(iface);
398 TRACE("iface %p, transform %p.\n", iface, transform);
400 *transform = brush->transform;
403 static void STDMETHODCALLTYPE d2d_linear_gradient_brush_SetStartPoint(ID2D1LinearGradientBrush *iface,
404 D2D1_POINT_2F start_point)
406 FIXME("iface %p, start_point {%.8e, %.8e} stub!\n", iface, start_point.x, start_point.y);
409 static void STDMETHODCALLTYPE d2d_linear_gradient_brush_SetEndPoint(ID2D1LinearGradientBrush *iface,
410 D2D1_POINT_2F end_point)
412 FIXME("iface %p, end_point {%.8e, %.8e} stub!\n", iface, end_point.x, end_point.y);
415 static D2D1_POINT_2F * STDMETHODCALLTYPE d2d_linear_gradient_brush_GetStartPoint(ID2D1LinearGradientBrush *iface,
416 D2D1_POINT_2F *point)
418 FIXME("iface %p, point %p stub!\n", iface, point);
420 point->x = 0.0f;
421 point->y = 0.0f;
422 return point;
425 static D2D1_POINT_2F * STDMETHODCALLTYPE d2d_linear_gradient_brush_GetEndPoint(ID2D1LinearGradientBrush *iface,
426 D2D1_POINT_2F *point)
428 FIXME("iface %p, point %p stub!\n", iface, point);
430 point->x = 0.0f;
431 point->y = 0.0f;
432 return point;
435 static void STDMETHODCALLTYPE d2d_linear_gradient_brush_GetGradientStopCollection(ID2D1LinearGradientBrush *iface,
436 ID2D1GradientStopCollection **gradient)
438 FIXME("iface %p, gradient %p stub!\n", iface, gradient);
440 *gradient = NULL;
443 static const struct ID2D1LinearGradientBrushVtbl d2d_linear_gradient_brush_vtbl =
445 d2d_linear_gradient_brush_QueryInterface,
446 d2d_linear_gradient_brush_AddRef,
447 d2d_linear_gradient_brush_Release,
448 d2d_linear_gradient_brush_GetFactory,
449 d2d_linear_gradient_brush_SetOpacity,
450 d2d_linear_gradient_brush_SetTransform,
451 d2d_linear_gradient_brush_GetOpacity,
452 d2d_linear_gradient_brush_GetTransform,
453 d2d_linear_gradient_brush_SetStartPoint,
454 d2d_linear_gradient_brush_SetEndPoint,
455 d2d_linear_gradient_brush_GetStartPoint,
456 d2d_linear_gradient_brush_GetEndPoint,
457 d2d_linear_gradient_brush_GetGradientStopCollection,
460 void d2d_linear_gradient_brush_init(struct d2d_brush *brush, ID2D1Factory *factory,
461 const D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES *gradient_brush_desc, const D2D1_BRUSH_PROPERTIES *brush_desc,
462 ID2D1GradientStopCollection *gradient)
464 FIXME("Ignoring brush properties.\n");
466 d2d_brush_init(brush, factory, D2D_BRUSH_TYPE_LINEAR, brush_desc,
467 (ID2D1BrushVtbl *)&d2d_linear_gradient_brush_vtbl);
470 static inline struct d2d_brush *impl_from_ID2D1BitmapBrush(ID2D1BitmapBrush *iface)
472 return CONTAINING_RECORD(iface, struct d2d_brush, ID2D1Brush_iface);
475 static HRESULT STDMETHODCALLTYPE d2d_bitmap_brush_QueryInterface(ID2D1BitmapBrush *iface,
476 REFIID iid, void **out)
478 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
480 if (IsEqualGUID(iid, &IID_ID2D1BitmapBrush)
481 || IsEqualGUID(iid, &IID_ID2D1Brush)
482 || IsEqualGUID(iid, &IID_ID2D1Resource)
483 || IsEqualGUID(iid, &IID_IUnknown))
485 ID2D1BitmapBrush_AddRef(iface);
486 *out = iface;
487 return S_OK;
490 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
492 *out = NULL;
493 return E_NOINTERFACE;
496 static ULONG STDMETHODCALLTYPE d2d_bitmap_brush_AddRef(ID2D1BitmapBrush *iface)
498 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
499 ULONG refcount = InterlockedIncrement(&brush->refcount);
501 TRACE("%p increasing refcount to %u.\n", iface, refcount);
503 return refcount;
506 static ULONG STDMETHODCALLTYPE d2d_bitmap_brush_Release(ID2D1BitmapBrush *iface)
508 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
509 ULONG refcount = InterlockedDecrement(&brush->refcount);
511 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
513 if (!refcount)
515 if (brush->u.bitmap.sampler_state)
516 ID3D10SamplerState_Release(brush->u.bitmap.sampler_state);
517 if (brush->u.bitmap.bitmap)
518 ID2D1Bitmap_Release(&brush->u.bitmap.bitmap->ID2D1Bitmap_iface);
519 d2d_brush_destroy(brush);
522 return refcount;
525 static void STDMETHODCALLTYPE d2d_bitmap_brush_GetFactory(ID2D1BitmapBrush *iface,
526 ID2D1Factory **factory)
528 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
530 TRACE("iface %p, factory %p.\n", iface, factory);
532 ID2D1Factory_AddRef(*factory = brush->factory);
535 static void STDMETHODCALLTYPE d2d_bitmap_brush_SetOpacity(ID2D1BitmapBrush *iface, float opacity)
537 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
539 TRACE("iface %p, opacity %.8e.\n", iface, opacity);
541 brush->opacity = opacity;
544 static void STDMETHODCALLTYPE d2d_bitmap_brush_SetTransform(ID2D1BitmapBrush *iface,
545 const D2D1_MATRIX_3X2_F *transform)
547 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
549 TRACE("iface %p, transform %p.\n", iface, transform);
551 brush->transform = *transform;
554 static float STDMETHODCALLTYPE d2d_bitmap_brush_GetOpacity(ID2D1BitmapBrush *iface)
556 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
558 TRACE("iface %p.\n", iface);
560 return brush->opacity;
563 static void STDMETHODCALLTYPE d2d_bitmap_brush_GetTransform(ID2D1BitmapBrush *iface,
564 D2D1_MATRIX_3X2_F *transform)
566 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
568 TRACE("iface %p, transform %p.\n", iface, transform);
570 *transform = brush->transform;
573 static void STDMETHODCALLTYPE d2d_bitmap_brush_SetExtendModeX(ID2D1BitmapBrush *iface, D2D1_EXTEND_MODE mode)
575 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
577 TRACE("iface %p, mode %#x.\n", iface, mode);
579 brush->u.bitmap.extend_mode_x = mode;
580 if (brush->u.bitmap.sampler_state)
582 ID3D10SamplerState_Release(brush->u.bitmap.sampler_state);
583 brush->u.bitmap.sampler_state = NULL;
587 static void STDMETHODCALLTYPE d2d_bitmap_brush_SetExtendModeY(ID2D1BitmapBrush *iface, D2D1_EXTEND_MODE mode)
589 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
591 TRACE("iface %p, mode %#x.\n", iface, mode);
593 brush->u.bitmap.extend_mode_y = mode;
594 if (brush->u.bitmap.sampler_state)
596 ID3D10SamplerState_Release(brush->u.bitmap.sampler_state);
597 brush->u.bitmap.sampler_state = NULL;
601 static void STDMETHODCALLTYPE d2d_bitmap_brush_SetInterpolationMode(ID2D1BitmapBrush *iface,
602 D2D1_BITMAP_INTERPOLATION_MODE mode)
604 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
606 TRACE("iface %p, mode %#x.\n", iface, mode);
608 brush->u.bitmap.interpolation_mode = mode;
609 if (brush->u.bitmap.sampler_state)
611 ID3D10SamplerState_Release(brush->u.bitmap.sampler_state);
612 brush->u.bitmap.sampler_state = NULL;
616 static void STDMETHODCALLTYPE d2d_bitmap_brush_SetBitmap(ID2D1BitmapBrush *iface, ID2D1Bitmap *bitmap)
618 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
620 TRACE("iface %p, bitmap %p.\n", iface, bitmap);
622 if (bitmap)
623 ID2D1Bitmap_AddRef(bitmap);
624 if (brush->u.bitmap.bitmap)
625 ID2D1Bitmap_Release(&brush->u.bitmap.bitmap->ID2D1Bitmap_iface);
626 brush->u.bitmap.bitmap = unsafe_impl_from_ID2D1Bitmap(bitmap);
629 static D2D1_EXTEND_MODE STDMETHODCALLTYPE d2d_bitmap_brush_GetExtendModeX(ID2D1BitmapBrush *iface)
631 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
633 TRACE("iface %p.\n", iface);
635 return brush->u.bitmap.extend_mode_x;
638 static D2D1_EXTEND_MODE STDMETHODCALLTYPE d2d_bitmap_brush_GetExtendModeY(ID2D1BitmapBrush *iface)
640 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
642 TRACE("iface %p.\n", iface);
644 return brush->u.bitmap.extend_mode_y;
647 static D2D1_BITMAP_INTERPOLATION_MODE STDMETHODCALLTYPE d2d_bitmap_brush_GetInterpolationMode(ID2D1BitmapBrush *iface)
649 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
651 TRACE("iface %p.\n", iface);
653 return brush->u.bitmap.interpolation_mode;
656 static void STDMETHODCALLTYPE d2d_bitmap_brush_GetBitmap(ID2D1BitmapBrush *iface, ID2D1Bitmap **bitmap)
658 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
660 TRACE("iface %p, bitmap %p.\n", iface, bitmap);
662 if ((*bitmap = &brush->u.bitmap.bitmap->ID2D1Bitmap_iface))
663 ID2D1Bitmap_AddRef(*bitmap);
666 static const struct ID2D1BitmapBrushVtbl d2d_bitmap_brush_vtbl =
668 d2d_bitmap_brush_QueryInterface,
669 d2d_bitmap_brush_AddRef,
670 d2d_bitmap_brush_Release,
671 d2d_bitmap_brush_GetFactory,
672 d2d_bitmap_brush_SetOpacity,
673 d2d_bitmap_brush_SetTransform,
674 d2d_bitmap_brush_GetOpacity,
675 d2d_bitmap_brush_GetTransform,
676 d2d_bitmap_brush_SetExtendModeX,
677 d2d_bitmap_brush_SetExtendModeY,
678 d2d_bitmap_brush_SetInterpolationMode,
679 d2d_bitmap_brush_SetBitmap,
680 d2d_bitmap_brush_GetExtendModeX,
681 d2d_bitmap_brush_GetExtendModeY,
682 d2d_bitmap_brush_GetInterpolationMode,
683 d2d_bitmap_brush_GetBitmap,
686 void d2d_bitmap_brush_init(struct d2d_brush *brush, ID2D1Factory *factory, ID2D1Bitmap *bitmap,
687 const D2D1_BITMAP_BRUSH_PROPERTIES *bitmap_brush_desc, const D2D1_BRUSH_PROPERTIES *brush_desc)
689 d2d_brush_init(brush, factory, D2D_BRUSH_TYPE_BITMAP,
690 brush_desc, (ID2D1BrushVtbl *)&d2d_bitmap_brush_vtbl);
691 if ((brush->u.bitmap.bitmap = unsafe_impl_from_ID2D1Bitmap(bitmap)))
692 ID2D1Bitmap_AddRef(&brush->u.bitmap.bitmap->ID2D1Bitmap_iface);
693 if (bitmap_brush_desc)
695 brush->u.bitmap.extend_mode_x = bitmap_brush_desc->extendModeX;
696 brush->u.bitmap.extend_mode_y = bitmap_brush_desc->extendModeY;
697 brush->u.bitmap.interpolation_mode = bitmap_brush_desc->interpolationMode;
699 else
701 brush->u.bitmap.extend_mode_x = D2D1_EXTEND_MODE_CLAMP;
702 brush->u.bitmap.extend_mode_y = D2D1_EXTEND_MODE_CLAMP;
703 brush->u.bitmap.interpolation_mode = D2D1_BITMAP_INTERPOLATION_MODE_LINEAR;
707 struct d2d_brush *unsafe_impl_from_ID2D1Brush(ID2D1Brush *iface)
709 if (!iface)
710 return NULL;
711 assert(iface->lpVtbl == (const ID2D1BrushVtbl *)&d2d_solid_color_brush_vtbl
712 || iface->lpVtbl == (const ID2D1BrushVtbl *)&d2d_linear_gradient_brush_vtbl
713 || iface->lpVtbl == (const ID2D1BrushVtbl *)&d2d_bitmap_brush_vtbl);
714 return CONTAINING_RECORD(iface, struct d2d_brush, ID2D1Brush_iface);
717 static D3D10_TEXTURE_ADDRESS_MODE texture_address_mode_from_extend_mode(D2D1_EXTEND_MODE mode)
719 switch (mode)
721 case D2D1_EXTEND_MODE_CLAMP:
722 return D3D10_TEXTURE_ADDRESS_CLAMP;
723 case D2D1_EXTEND_MODE_WRAP:
724 return D3D10_TEXTURE_ADDRESS_WRAP;
725 case D2D1_EXTEND_MODE_MIRROR:
726 return D3D10_TEXTURE_ADDRESS_MIRROR;
727 default:
728 FIXME("Unhandled extend mode %#x.\n", mode);
729 return D3D10_TEXTURE_ADDRESS_CLAMP;
733 HRESULT d2d_brush_get_ps_cb(struct d2d_brush *brush, struct d2d_d3d_render_target *render_target,
734 ID3D10Buffer **ps_cb)
736 D3D10_SUBRESOURCE_DATA buffer_data;
737 D3D10_BUFFER_DESC buffer_desc;
738 struct
740 float _11, _21, _31, pad0;
741 float _12, _22, _32, opacity;
742 BOOL ignore_alpha;
743 } bitmap_brush_cb;
744 D2D1_COLOR_F color;
745 HRESULT hr;
747 buffer_desc.Usage = D3D10_USAGE_DEFAULT;
748 buffer_desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
749 buffer_desc.CPUAccessFlags = 0;
750 buffer_desc.MiscFlags = 0;
752 buffer_data.SysMemPitch = 0;
753 buffer_data.SysMemSlicePitch = 0;
755 if (brush->type == D2D_BRUSH_TYPE_SOLID)
757 color = brush->u.solid.color;
758 color.a *= brush->opacity;
759 color.r *= color.a;
760 color.g *= color.a;
761 color.b *= color.a;
763 buffer_desc.ByteWidth = sizeof(color);
764 buffer_data.pSysMem = &color;
766 else if (brush->type == D2D_BRUSH_TYPE_BITMAP)
768 struct d2d_bitmap *bitmap = brush->u.bitmap.bitmap;
769 D2D_MATRIX_3X2_F w, b;
770 float dpi_scale, d;
772 /* Scale for dpi. */
773 w = render_target->drawing_state.transform;
774 dpi_scale = render_target->dpi_x / 96.0f;
775 w._11 *= dpi_scale;
776 w._21 *= dpi_scale;
777 w._31 *= dpi_scale;
778 dpi_scale = render_target->dpi_y / 96.0f;
779 w._12 *= dpi_scale;
780 w._22 *= dpi_scale;
781 w._32 *= dpi_scale;
783 /* Scale for bitmap size and dpi. */
784 b = brush->transform;
785 dpi_scale = bitmap->pixel_size.width * (96.0f / bitmap->dpi_x);
786 b._11 *= dpi_scale;
787 b._21 *= dpi_scale;
788 dpi_scale = bitmap->pixel_size.height * (96.0f / bitmap->dpi_y);
789 b._12 *= dpi_scale;
790 b._22 *= dpi_scale;
792 d2d_matrix_multiply(&b, &w);
794 /* Invert the matrix. (Because the matrix is applied to the sampling
795 * coordinates. I.e., to scale the bitmap by 2 we need to divide the
796 * coordinates by 2.) */
797 d = b._11 * b._22 - b._21 * b._12;
798 if (d != 0.0f)
800 bitmap_brush_cb._11 = b._22 / d;
801 bitmap_brush_cb._21 = -b._21 / d;
802 bitmap_brush_cb._31 = (b._21 * b._32 - b._31 * b._22) / d;
803 bitmap_brush_cb._12 = -b._12 / d;
804 bitmap_brush_cb._22 = b._11 / d;
805 bitmap_brush_cb._32 = -(b._11 * b._32 - b._31 * b._12) / d;
807 bitmap_brush_cb.opacity = brush->opacity;
808 bitmap_brush_cb.ignore_alpha = bitmap->format.alphaMode == D2D1_ALPHA_MODE_IGNORE;
810 buffer_desc.ByteWidth = sizeof(bitmap_brush_cb);
811 buffer_data.pSysMem = &bitmap_brush_cb;
813 else
815 FIXME("Unhandled brush type %#x.\n", brush->type);
816 return E_NOTIMPL;
819 if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device, &buffer_desc, &buffer_data, ps_cb)))
820 ERR("Failed to create constant buffer, hr %#x.\n", hr);
822 return hr;
825 void d2d_brush_bind_resources(struct d2d_brush *brush, struct d2d_d3d_render_target *render_target,
826 enum d2d_shape_type shape_type)
828 static const float blend_factor[] = {1.0f, 1.0f, 1.0f, 1.0f};
829 ID3D10Device *device = render_target->device;
830 ID3D10PixelShader *ps;
831 HRESULT hr;
833 ID3D10Device_OMSetBlendState(device, render_target->bs, blend_factor, D3D10_DEFAULT_SAMPLE_MASK);
834 if (!(ps = render_target->shape_resources[shape_type].ps[brush->type]))
835 FIXME("No pixel shader for shape type %#x and brush type %#x.\n", shape_type, brush->type);
836 ID3D10Device_PSSetShader(device, ps);
838 if (brush->type == D2D_BRUSH_TYPE_BITMAP)
840 ID3D10Device_PSSetShaderResources(device, 0, 1, &brush->u.bitmap.bitmap->view);
841 if (!brush->u.bitmap.sampler_state)
843 D3D10_SAMPLER_DESC sampler_desc;
845 if (brush->u.bitmap.interpolation_mode == D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR)
846 sampler_desc.Filter = D3D10_FILTER_MIN_MAG_MIP_POINT;
847 else
848 sampler_desc.Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR;
849 sampler_desc.AddressU = texture_address_mode_from_extend_mode(brush->u.bitmap.extend_mode_x);
850 sampler_desc.AddressV = texture_address_mode_from_extend_mode(brush->u.bitmap.extend_mode_y);
851 sampler_desc.AddressW = D3D10_TEXTURE_ADDRESS_CLAMP;
852 sampler_desc.MipLODBias = 0.0f;
853 sampler_desc.MaxAnisotropy = 0;
854 sampler_desc.ComparisonFunc = D3D10_COMPARISON_NEVER;
855 sampler_desc.BorderColor[0] = 0.0f;
856 sampler_desc.BorderColor[1] = 0.0f;
857 sampler_desc.BorderColor[2] = 0.0f;
858 sampler_desc.BorderColor[3] = 0.0f;
859 sampler_desc.MinLOD = 0.0f;
860 sampler_desc.MaxLOD = 0.0f;
862 if (FAILED(hr = ID3D10Device_CreateSamplerState(device,
863 &sampler_desc, &brush->u.bitmap.sampler_state)))
864 ERR("Failed to create sampler state, hr %#x.\n", hr);
866 ID3D10Device_PSSetSamplers(device, 0, 1, &brush->u.bitmap.sampler_state);
868 else if (brush->type != D2D_BRUSH_TYPE_SOLID)
870 FIXME("Unhandled brush type %#x.\n", brush->type);