d2d1: Fix a typo in traced error message parameter.
[wine.git] / dlls / d2d1 / brush.c
blobd51f53ff53557f5fd992e9b2e4d3c3ce114b2497
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 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);
48 *out = iface;
49 return S_OK;
52 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
54 *out = NULL;
55 return E_NOINTERFACE;
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);
65 return 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);
75 if (!refcount)
77 HeapFree(GetProcessHeap(), 0, gradient->stops);
78 ID2D1Factory_Release(gradient->factory);
79 HeapFree(GetProcessHeap(), 0, gradient);
82 return refcount;
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,
132 d2d_gradient_AddRef,
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);
162 return S_OK;
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 =
176 1.0f, 0.0f,
177 0.0f, 1.0f,
178 0.0f, 0.0f,
181 brush->ID2D1Brush_iface.lpVtbl = vtbl;
182 brush->refcount = 1;
183 ID2D1Factory_AddRef(brush->factory = factory);
184 brush->opacity = desc ? desc->opacity : 1.0f;
185 brush->transform = desc ? desc->transform : identity;
186 brush->type = type;
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);
205 *out = iface;
206 return S_OK;
209 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
211 *out = NULL;
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);
222 return 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);
232 if (!refcount)
233 d2d_brush_destroy(brush);
235 return refcount;
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;
301 return 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);
329 return S_OK;
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);
348 *out = iface;
349 return S_OK;
352 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
354 *out = NULL;
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);
365 return 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);
375 if (!refcount)
377 ID2D1GradientStopCollection_Release(brush->u.linear.gradient);
378 d2d_brush_destroy(brush);
381 return refcount;
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);
413 return 0.0f;
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;
454 return point;
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;
465 return point;
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);
507 return S_OK;
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);
526 *out = iface;
527 return S_OK;
530 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
532 *out = NULL;
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);
543 return 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);
553 if (!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);
562 return refcount;
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);
662 if (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;
742 else
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);
750 return S_OK;
753 struct d2d_brush *unsafe_impl_from_ID2D1Brush(ID2D1Brush *iface)
755 if (!iface)
756 return NULL;
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)
765 switch (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;
773 default:
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;
782 D2D1_COLOR_F *color;
784 if (brush->type == D2D_BRUSH_TYPE_SOLID)
786 color = cb;
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;
794 return TRUE;
797 if (brush->type == D2D_BRUSH_TYPE_BITMAP)
799 struct d2d_bitmap *bitmap = brush->u.bitmap.bitmap;
800 D2D_MATRIX_3X2_F w, b;
801 float dpi_scale, d;
803 bitmap_brush_cb = cb;
805 /* Scale for dpi. */
806 w = render_target->drawing_state.transform;
807 dpi_scale = render_target->desc.dpiX / 96.0f;
808 w._11 *= dpi_scale;
809 w._21 *= dpi_scale;
810 w._31 *= dpi_scale;
811 dpi_scale = render_target->desc.dpiY / 96.0f;
812 w._12 *= dpi_scale;
813 w._22 *= dpi_scale;
814 w._32 *= dpi_scale;
816 /* Scale for bitmap size and dpi. */
817 b = brush->transform;
818 dpi_scale = bitmap->pixel_size.width * (96.0f / bitmap->dpi_x);
819 b._11 *= dpi_scale;
820 b._21 *= dpi_scale;
821 dpi_scale = bitmap->pixel_size.height * (96.0f / bitmap->dpi_y);
822 b._12 *= dpi_scale;
823 b._22 *= dpi_scale;
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;
831 if (d != 0.0f)
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;
843 return TRUE;
846 FIXME("Unhandled brush type %#x.\n", brush->type);
847 return FALSE;
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;
855 BYTE *cb_data;
856 HRESULT hr;
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);
876 return E_NOTIMPL;
879 buffer_desc.ByteWidth = brush_sizes[brush->type];
880 if (opacity_brush)
882 if (opacity_brush->type >= sizeof(brush_sizes) / sizeof(*brush_sizes))
884 ERR("Unhandled opacity brush type %#x.\n", opacity_brush->type);
885 return E_NOTIMPL;
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);
900 return E_NOTIMPL;
902 if (opacity_brush && !d2d_brush_fill_cb(opacity_brush, render_target, cb_data + brush_sizes[brush->type]))
904 HeapFree(GetProcessHeap(), 0, cb_data);
905 return E_NOTIMPL;
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);
912 return hr;
915 static void d2d_brush_bind_bitmap(struct d2d_brush *brush, ID3D10Device *device,
916 unsigned int resource_idx, unsigned int sampler_idx)
918 HRESULT hr;
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;
927 else
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);
970 if (opacity_brush)
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);