winebus.sys: Add stub driver.
[wine.git] / dlls / d2d1 / brush.c
blob1454faf66682912b89c61f4586bc9d712eaaab7e
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)
376 d2d_brush_destroy(brush);
378 return refcount;
381 static void STDMETHODCALLTYPE d2d_linear_gradient_brush_GetFactory(ID2D1LinearGradientBrush *iface,
382 ID2D1Factory **factory)
384 struct d2d_brush *brush = impl_from_ID2D1LinearGradientBrush(iface);
386 TRACE("iface %p, factory %p.\n", iface, factory);
388 ID2D1Factory_AddRef(*factory = brush->factory);
391 static void STDMETHODCALLTYPE d2d_linear_gradient_brush_SetOpacity(ID2D1LinearGradientBrush *iface, float opacity)
393 FIXME("iface %p, opacity %.8e stub!\n", iface, opacity);
396 static void STDMETHODCALLTYPE d2d_linear_gradient_brush_SetTransform(ID2D1LinearGradientBrush *iface,
397 const D2D1_MATRIX_3X2_F *transform)
399 struct d2d_brush *brush = impl_from_ID2D1LinearGradientBrush(iface);
401 TRACE("iface %p, transform %p.\n", iface, transform);
403 brush->transform = *transform;
406 static float STDMETHODCALLTYPE d2d_linear_gradient_brush_GetOpacity(ID2D1LinearGradientBrush *iface)
408 FIXME("iface %p stub!\n", iface);
410 return 0.0f;
413 static void STDMETHODCALLTYPE d2d_linear_gradient_brush_GetTransform(ID2D1LinearGradientBrush *iface,
414 D2D1_MATRIX_3X2_F *transform)
416 struct d2d_brush *brush = impl_from_ID2D1LinearGradientBrush(iface);
418 TRACE("iface %p, transform %p.\n", iface, transform);
420 *transform = brush->transform;
423 static void STDMETHODCALLTYPE d2d_linear_gradient_brush_SetStartPoint(ID2D1LinearGradientBrush *iface,
424 D2D1_POINT_2F start_point)
426 FIXME("iface %p, start_point {%.8e, %.8e} stub!\n", iface, start_point.x, start_point.y);
429 static void STDMETHODCALLTYPE d2d_linear_gradient_brush_SetEndPoint(ID2D1LinearGradientBrush *iface,
430 D2D1_POINT_2F end_point)
432 FIXME("iface %p, end_point {%.8e, %.8e} stub!\n", iface, end_point.x, end_point.y);
435 static D2D1_POINT_2F * STDMETHODCALLTYPE d2d_linear_gradient_brush_GetStartPoint(ID2D1LinearGradientBrush *iface,
436 D2D1_POINT_2F *point)
438 FIXME("iface %p, point %p stub!\n", iface, point);
440 point->x = 0.0f;
441 point->y = 0.0f;
442 return point;
445 static D2D1_POINT_2F * STDMETHODCALLTYPE d2d_linear_gradient_brush_GetEndPoint(ID2D1LinearGradientBrush *iface,
446 D2D1_POINT_2F *point)
448 FIXME("iface %p, point %p stub!\n", iface, point);
450 point->x = 0.0f;
451 point->y = 0.0f;
452 return point;
455 static void STDMETHODCALLTYPE d2d_linear_gradient_brush_GetGradientStopCollection(ID2D1LinearGradientBrush *iface,
456 ID2D1GradientStopCollection **gradient)
458 FIXME("iface %p, gradient %p stub!\n", iface, gradient);
460 *gradient = NULL;
463 static const struct ID2D1LinearGradientBrushVtbl d2d_linear_gradient_brush_vtbl =
465 d2d_linear_gradient_brush_QueryInterface,
466 d2d_linear_gradient_brush_AddRef,
467 d2d_linear_gradient_brush_Release,
468 d2d_linear_gradient_brush_GetFactory,
469 d2d_linear_gradient_brush_SetOpacity,
470 d2d_linear_gradient_brush_SetTransform,
471 d2d_linear_gradient_brush_GetOpacity,
472 d2d_linear_gradient_brush_GetTransform,
473 d2d_linear_gradient_brush_SetStartPoint,
474 d2d_linear_gradient_brush_SetEndPoint,
475 d2d_linear_gradient_brush_GetStartPoint,
476 d2d_linear_gradient_brush_GetEndPoint,
477 d2d_linear_gradient_brush_GetGradientStopCollection,
480 HRESULT d2d_linear_gradient_brush_create(ID2D1Factory *factory, const D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES *gradient_brush_desc,
481 const D2D1_BRUSH_PROPERTIES *brush_desc, ID2D1GradientStopCollection *gradient, struct d2d_brush **brush)
483 if (!(*brush = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(**brush))))
484 return E_OUTOFMEMORY;
486 FIXME("Ignoring brush properties.\n");
488 d2d_brush_init(*brush, factory, D2D_BRUSH_TYPE_LINEAR, brush_desc,
489 (ID2D1BrushVtbl *)&d2d_linear_gradient_brush_vtbl);
491 TRACE("Created brush %p.\n", *brush);
492 return S_OK;
495 static inline struct d2d_brush *impl_from_ID2D1BitmapBrush(ID2D1BitmapBrush *iface)
497 return CONTAINING_RECORD(iface, struct d2d_brush, ID2D1Brush_iface);
500 static HRESULT STDMETHODCALLTYPE d2d_bitmap_brush_QueryInterface(ID2D1BitmapBrush *iface,
501 REFIID iid, void **out)
503 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
505 if (IsEqualGUID(iid, &IID_ID2D1BitmapBrush)
506 || IsEqualGUID(iid, &IID_ID2D1Brush)
507 || IsEqualGUID(iid, &IID_ID2D1Resource)
508 || IsEqualGUID(iid, &IID_IUnknown))
510 ID2D1BitmapBrush_AddRef(iface);
511 *out = iface;
512 return S_OK;
515 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
517 *out = NULL;
518 return E_NOINTERFACE;
521 static ULONG STDMETHODCALLTYPE d2d_bitmap_brush_AddRef(ID2D1BitmapBrush *iface)
523 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
524 ULONG refcount = InterlockedIncrement(&brush->refcount);
526 TRACE("%p increasing refcount to %u.\n", iface, refcount);
528 return refcount;
531 static ULONG STDMETHODCALLTYPE d2d_bitmap_brush_Release(ID2D1BitmapBrush *iface)
533 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
534 ULONG refcount = InterlockedDecrement(&brush->refcount);
536 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
538 if (!refcount)
540 if (brush->u.bitmap.sampler_state)
541 ID3D10SamplerState_Release(brush->u.bitmap.sampler_state);
542 if (brush->u.bitmap.bitmap)
543 ID2D1Bitmap_Release(&brush->u.bitmap.bitmap->ID2D1Bitmap_iface);
544 d2d_brush_destroy(brush);
547 return refcount;
550 static void STDMETHODCALLTYPE d2d_bitmap_brush_GetFactory(ID2D1BitmapBrush *iface,
551 ID2D1Factory **factory)
553 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
555 TRACE("iface %p, factory %p.\n", iface, factory);
557 ID2D1Factory_AddRef(*factory = brush->factory);
560 static void STDMETHODCALLTYPE d2d_bitmap_brush_SetOpacity(ID2D1BitmapBrush *iface, float opacity)
562 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
564 TRACE("iface %p, opacity %.8e.\n", iface, opacity);
566 brush->opacity = opacity;
569 static void STDMETHODCALLTYPE d2d_bitmap_brush_SetTransform(ID2D1BitmapBrush *iface,
570 const D2D1_MATRIX_3X2_F *transform)
572 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
574 TRACE("iface %p, transform %p.\n", iface, transform);
576 brush->transform = *transform;
579 static float STDMETHODCALLTYPE d2d_bitmap_brush_GetOpacity(ID2D1BitmapBrush *iface)
581 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
583 TRACE("iface %p.\n", iface);
585 return brush->opacity;
588 static void STDMETHODCALLTYPE d2d_bitmap_brush_GetTransform(ID2D1BitmapBrush *iface,
589 D2D1_MATRIX_3X2_F *transform)
591 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
593 TRACE("iface %p, transform %p.\n", iface, transform);
595 *transform = brush->transform;
598 static void STDMETHODCALLTYPE d2d_bitmap_brush_SetExtendModeX(ID2D1BitmapBrush *iface, D2D1_EXTEND_MODE mode)
600 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
602 TRACE("iface %p, mode %#x.\n", iface, mode);
604 brush->u.bitmap.extend_mode_x = mode;
605 if (brush->u.bitmap.sampler_state)
607 ID3D10SamplerState_Release(brush->u.bitmap.sampler_state);
608 brush->u.bitmap.sampler_state = NULL;
612 static void STDMETHODCALLTYPE d2d_bitmap_brush_SetExtendModeY(ID2D1BitmapBrush *iface, D2D1_EXTEND_MODE mode)
614 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
616 TRACE("iface %p, mode %#x.\n", iface, mode);
618 brush->u.bitmap.extend_mode_y = mode;
619 if (brush->u.bitmap.sampler_state)
621 ID3D10SamplerState_Release(brush->u.bitmap.sampler_state);
622 brush->u.bitmap.sampler_state = NULL;
626 static void STDMETHODCALLTYPE d2d_bitmap_brush_SetInterpolationMode(ID2D1BitmapBrush *iface,
627 D2D1_BITMAP_INTERPOLATION_MODE mode)
629 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
631 TRACE("iface %p, mode %#x.\n", iface, mode);
633 brush->u.bitmap.interpolation_mode = 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_SetBitmap(ID2D1BitmapBrush *iface, ID2D1Bitmap *bitmap)
643 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
645 TRACE("iface %p, bitmap %p.\n", iface, bitmap);
647 if (bitmap)
648 ID2D1Bitmap_AddRef(bitmap);
649 if (brush->u.bitmap.bitmap)
650 ID2D1Bitmap_Release(&brush->u.bitmap.bitmap->ID2D1Bitmap_iface);
651 brush->u.bitmap.bitmap = unsafe_impl_from_ID2D1Bitmap(bitmap);
654 static D2D1_EXTEND_MODE STDMETHODCALLTYPE d2d_bitmap_brush_GetExtendModeX(ID2D1BitmapBrush *iface)
656 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
658 TRACE("iface %p.\n", iface);
660 return brush->u.bitmap.extend_mode_x;
663 static D2D1_EXTEND_MODE STDMETHODCALLTYPE d2d_bitmap_brush_GetExtendModeY(ID2D1BitmapBrush *iface)
665 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
667 TRACE("iface %p.\n", iface);
669 return brush->u.bitmap.extend_mode_y;
672 static D2D1_BITMAP_INTERPOLATION_MODE STDMETHODCALLTYPE d2d_bitmap_brush_GetInterpolationMode(ID2D1BitmapBrush *iface)
674 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
676 TRACE("iface %p.\n", iface);
678 return brush->u.bitmap.interpolation_mode;
681 static void STDMETHODCALLTYPE d2d_bitmap_brush_GetBitmap(ID2D1BitmapBrush *iface, ID2D1Bitmap **bitmap)
683 struct d2d_brush *brush = impl_from_ID2D1BitmapBrush(iface);
685 TRACE("iface %p, bitmap %p.\n", iface, bitmap);
687 if ((*bitmap = &brush->u.bitmap.bitmap->ID2D1Bitmap_iface))
688 ID2D1Bitmap_AddRef(*bitmap);
691 static const struct ID2D1BitmapBrushVtbl d2d_bitmap_brush_vtbl =
693 d2d_bitmap_brush_QueryInterface,
694 d2d_bitmap_brush_AddRef,
695 d2d_bitmap_brush_Release,
696 d2d_bitmap_brush_GetFactory,
697 d2d_bitmap_brush_SetOpacity,
698 d2d_bitmap_brush_SetTransform,
699 d2d_bitmap_brush_GetOpacity,
700 d2d_bitmap_brush_GetTransform,
701 d2d_bitmap_brush_SetExtendModeX,
702 d2d_bitmap_brush_SetExtendModeY,
703 d2d_bitmap_brush_SetInterpolationMode,
704 d2d_bitmap_brush_SetBitmap,
705 d2d_bitmap_brush_GetExtendModeX,
706 d2d_bitmap_brush_GetExtendModeY,
707 d2d_bitmap_brush_GetInterpolationMode,
708 d2d_bitmap_brush_GetBitmap,
711 HRESULT d2d_bitmap_brush_create(ID2D1Factory *factory, ID2D1Bitmap *bitmap, const D2D1_BITMAP_BRUSH_PROPERTIES *bitmap_brush_desc,
712 const D2D1_BRUSH_PROPERTIES *brush_desc, struct d2d_brush **brush)
714 if (!(*brush = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(**brush))))
715 return E_OUTOFMEMORY;
717 d2d_brush_init(*brush, factory, D2D_BRUSH_TYPE_BITMAP,
718 brush_desc, (ID2D1BrushVtbl *)&d2d_bitmap_brush_vtbl);
719 if (((*brush)->u.bitmap.bitmap = unsafe_impl_from_ID2D1Bitmap(bitmap)))
720 ID2D1Bitmap_AddRef(&(*brush)->u.bitmap.bitmap->ID2D1Bitmap_iface);
721 if (bitmap_brush_desc)
723 (*brush)->u.bitmap.extend_mode_x = bitmap_brush_desc->extendModeX;
724 (*brush)->u.bitmap.extend_mode_y = bitmap_brush_desc->extendModeY;
725 (*brush)->u.bitmap.interpolation_mode = bitmap_brush_desc->interpolationMode;
727 else
729 (*brush)->u.bitmap.extend_mode_x = D2D1_EXTEND_MODE_CLAMP;
730 (*brush)->u.bitmap.extend_mode_y = D2D1_EXTEND_MODE_CLAMP;
731 (*brush)->u.bitmap.interpolation_mode = D2D1_BITMAP_INTERPOLATION_MODE_LINEAR;
734 TRACE("Created brush %p.\n", *brush);
735 return S_OK;
738 struct d2d_brush *unsafe_impl_from_ID2D1Brush(ID2D1Brush *iface)
740 if (!iface)
741 return NULL;
742 assert(iface->lpVtbl == (const ID2D1BrushVtbl *)&d2d_solid_color_brush_vtbl
743 || iface->lpVtbl == (const ID2D1BrushVtbl *)&d2d_linear_gradient_brush_vtbl
744 || iface->lpVtbl == (const ID2D1BrushVtbl *)&d2d_bitmap_brush_vtbl);
745 return CONTAINING_RECORD(iface, struct d2d_brush, ID2D1Brush_iface);
748 static D3D10_TEXTURE_ADDRESS_MODE texture_address_mode_from_extend_mode(D2D1_EXTEND_MODE mode)
750 switch (mode)
752 case D2D1_EXTEND_MODE_CLAMP:
753 return D3D10_TEXTURE_ADDRESS_CLAMP;
754 case D2D1_EXTEND_MODE_WRAP:
755 return D3D10_TEXTURE_ADDRESS_WRAP;
756 case D2D1_EXTEND_MODE_MIRROR:
757 return D3D10_TEXTURE_ADDRESS_MIRROR;
758 default:
759 FIXME("Unhandled extend mode %#x.\n", mode);
760 return D3D10_TEXTURE_ADDRESS_CLAMP;
764 static BOOL d2d_brush_fill_cb(struct d2d_brush *brush, struct d2d_d3d_render_target *render_target, void *cb)
766 struct d2d_bitmap_brush_cb *bitmap_brush_cb;
767 D2D1_COLOR_F *color;
769 if (brush->type == D2D_BRUSH_TYPE_SOLID)
771 color = cb;
773 *color = brush->u.solid.color;
774 color->a *= brush->opacity;
775 color->r *= color->a;
776 color->g *= color->a;
777 color->b *= color->a;
779 return TRUE;
782 if (brush->type == D2D_BRUSH_TYPE_BITMAP)
784 struct d2d_bitmap *bitmap = brush->u.bitmap.bitmap;
785 D2D_MATRIX_3X2_F w, b;
786 float dpi_scale, d;
788 bitmap_brush_cb = cb;
790 /* Scale for dpi. */
791 w = render_target->drawing_state.transform;
792 dpi_scale = render_target->dpi_x / 96.0f;
793 w._11 *= dpi_scale;
794 w._21 *= dpi_scale;
795 w._31 *= dpi_scale;
796 dpi_scale = render_target->dpi_y / 96.0f;
797 w._12 *= dpi_scale;
798 w._22 *= dpi_scale;
799 w._32 *= dpi_scale;
801 /* Scale for bitmap size and dpi. */
802 b = brush->transform;
803 dpi_scale = bitmap->pixel_size.width * (96.0f / bitmap->dpi_x);
804 b._11 *= dpi_scale;
805 b._21 *= dpi_scale;
806 dpi_scale = bitmap->pixel_size.height * (96.0f / bitmap->dpi_y);
807 b._12 *= dpi_scale;
808 b._22 *= dpi_scale;
810 d2d_matrix_multiply(&b, &w);
812 /* Invert the matrix. (Because the matrix is applied to the sampling
813 * coordinates. I.e., to scale the bitmap by 2 we need to divide the
814 * coordinates by 2.) */
815 d = b._11 * b._22 - b._21 * b._12;
816 if (d != 0.0f)
818 bitmap_brush_cb->_11 = b._22 / d;
819 bitmap_brush_cb->_21 = -b._21 / d;
820 bitmap_brush_cb->_31 = (b._21 * b._32 - b._31 * b._22) / d;
821 bitmap_brush_cb->_12 = -b._12 / d;
822 bitmap_brush_cb->_22 = b._11 / d;
823 bitmap_brush_cb->_32 = -(b._11 * b._32 - b._31 * b._12) / d;
825 bitmap_brush_cb->opacity = brush->opacity;
826 bitmap_brush_cb->ignore_alpha = bitmap->format.alphaMode == D2D1_ALPHA_MODE_IGNORE;
828 return TRUE;
831 FIXME("Unhandled brush type %#x.\n", brush->type);
832 return FALSE;
835 HRESULT d2d_brush_get_ps_cb(struct d2d_brush *brush, struct d2d_brush *opacity_brush,
836 struct d2d_d3d_render_target *render_target, ID3D10Buffer **ps_cb)
838 D3D10_SUBRESOURCE_DATA buffer_data;
839 D3D10_BUFFER_DESC buffer_desc;
840 BYTE *cb_data;
841 HRESULT hr;
843 static const size_t brush_sizes[] =
845 /* D2D_BRUSH_TYPE_SOLID */ sizeof(D2D1_COLOR_F),
846 /* D2D_BRUSH_TYPE_LINEAR */ 0,
847 /* D2D_BRUSH_TYPE_BITMAP */ sizeof(struct d2d_bitmap_brush_cb),
850 buffer_desc.Usage = D3D10_USAGE_DEFAULT;
851 buffer_desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
852 buffer_desc.CPUAccessFlags = 0;
853 buffer_desc.MiscFlags = 0;
855 buffer_data.SysMemPitch = 0;
856 buffer_data.SysMemSlicePitch = 0;
858 if (brush->type >= sizeof(brush_sizes) / sizeof(*brush_sizes))
860 ERR("Unhandled brush type %#x.\n", brush->type);
861 return E_NOTIMPL;
864 buffer_desc.ByteWidth = brush_sizes[brush->type];
865 if (opacity_brush)
867 if (opacity_brush->type >= sizeof(brush_sizes) / sizeof(*brush_sizes))
869 ERR("Unhandled opacity brush type %#x.\n", brush->type);
870 return E_NOTIMPL;
872 buffer_desc.ByteWidth += brush_sizes[opacity_brush->type];
875 if (!(cb_data = HeapAlloc(GetProcessHeap(), 0, buffer_desc.ByteWidth)))
877 ERR("Failed to allocate constant buffer data.\n");
878 return E_OUTOFMEMORY;
880 buffer_data.pSysMem = cb_data;
882 if (!d2d_brush_fill_cb(brush, render_target, cb_data))
884 HeapFree(GetProcessHeap(), 0, cb_data);
885 return E_NOTIMPL;
887 if (opacity_brush && !d2d_brush_fill_cb(opacity_brush, render_target, cb_data + brush_sizes[brush->type]))
889 HeapFree(GetProcessHeap(), 0, cb_data);
890 return E_NOTIMPL;
893 if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device, &buffer_desc, &buffer_data, ps_cb)))
894 ERR("Failed to create constant buffer, hr %#x.\n", hr);
895 HeapFree(GetProcessHeap(), 0, cb_data);
897 return hr;
900 static void d2d_brush_bind_bitmap(struct d2d_brush *brush, ID3D10Device *device,
901 unsigned int resource_idx, unsigned int sampler_idx)
903 HRESULT hr;
905 ID3D10Device_PSSetShaderResources(device, resource_idx, 1, &brush->u.bitmap.bitmap->view);
906 if (!brush->u.bitmap.sampler_state)
908 D3D10_SAMPLER_DESC sampler_desc;
910 if (brush->u.bitmap.interpolation_mode == D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR)
911 sampler_desc.Filter = D3D10_FILTER_MIN_MAG_MIP_POINT;
912 else
913 sampler_desc.Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR;
914 sampler_desc.AddressU = texture_address_mode_from_extend_mode(brush->u.bitmap.extend_mode_x);
915 sampler_desc.AddressV = texture_address_mode_from_extend_mode(brush->u.bitmap.extend_mode_y);
916 sampler_desc.AddressW = D3D10_TEXTURE_ADDRESS_CLAMP;
917 sampler_desc.MipLODBias = 0.0f;
918 sampler_desc.MaxAnisotropy = 0;
919 sampler_desc.ComparisonFunc = D3D10_COMPARISON_NEVER;
920 sampler_desc.BorderColor[0] = 0.0f;
921 sampler_desc.BorderColor[1] = 0.0f;
922 sampler_desc.BorderColor[2] = 0.0f;
923 sampler_desc.BorderColor[3] = 0.0f;
924 sampler_desc.MinLOD = 0.0f;
925 sampler_desc.MaxLOD = 0.0f;
927 if (FAILED(hr = ID3D10Device_CreateSamplerState(device,
928 &sampler_desc, &brush->u.bitmap.sampler_state)))
929 ERR("Failed to create sampler state, hr %#x.\n", hr);
931 ID3D10Device_PSSetSamplers(device, sampler_idx, 1, &brush->u.bitmap.sampler_state);
934 void d2d_brush_bind_resources(struct d2d_brush *brush, struct d2d_brush *opacity_brush,
935 struct d2d_d3d_render_target *render_target, enum d2d_shape_type shape_type)
937 static const float blend_factor[] = {1.0f, 1.0f, 1.0f, 1.0f};
938 unsigned int resource_idx = 0, sampler_idx = 0;
939 ID3D10Device *device = render_target->device;
940 enum d2d_brush_type opacity_brush_type;
941 ID3D10PixelShader *ps;
943 ID3D10Device_OMSetBlendState(device, render_target->bs, blend_factor, D3D10_DEFAULT_SAMPLE_MASK);
944 opacity_brush_type = opacity_brush ? opacity_brush->type : D2D_BRUSH_TYPE_COUNT;
945 if (!(ps = render_target->shape_resources[shape_type].ps[brush->type][opacity_brush_type]))
946 FIXME("No pixel shader for shape type %#x and brush types %#x/%#x.\n",
947 shape_type, brush->type, opacity_brush_type);
948 ID3D10Device_PSSetShader(device, ps);
950 if (brush->type == D2D_BRUSH_TYPE_BITMAP)
951 d2d_brush_bind_bitmap(brush, device, resource_idx++, sampler_idx++);
952 else if (brush->type != D2D_BRUSH_TYPE_SOLID)
953 FIXME("Unhandled brush type %#x.\n", brush->type);
955 if (opacity_brush)
957 if (opacity_brush->type == D2D_BRUSH_TYPE_BITMAP)
958 d2d_brush_bind_bitmap(opacity_brush, device, resource_idx++, sampler_idx++);
959 else if (opacity_brush->type != D2D_BRUSH_TYPE_SOLID)
960 FIXME("Unhandled opacity brush type %#x.\n", opacity_brush->type);