| /* |
| * Copyright 2014 Henri Verbeet for CodeWeavers |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include "config.h" |
| #include "wine/port.h" |
| |
| #include "d2d1_private.h" |
| #include "wincodec.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(d2d); |
| |
| #define INITIAL_CLIP_STACK_SIZE 4 |
| |
| struct d2d_draw_text_layout_ctx |
| { |
| ID2D1Brush *brush; |
| D2D1_DRAW_TEXT_OPTIONS options; |
| }; |
| |
| static void d2d_matrix_multiply(D2D_MATRIX_3X2_F *a, const D2D_MATRIX_3X2_F *b) |
| { |
| D2D_MATRIX_3X2_F tmp = *a; |
| |
| a->_11 = tmp._11 * b->_11 + tmp._12 * b->_21; |
| a->_12 = tmp._11 * b->_12 + tmp._12 * b->_22; |
| a->_21 = tmp._21 * b->_11 + tmp._22 * b->_21; |
| a->_22 = tmp._21 * b->_12 + tmp._22 * b->_22; |
| a->_31 = tmp._31 * b->_11 + tmp._32 * b->_21 + b->_31; |
| a->_32 = tmp._31 * b->_12 + tmp._32 * b->_22 + b->_32; |
| } |
| |
| static void d2d_point_set(D2D1_POINT_2F *dst, float x, float y) |
| { |
| dst->x = x; |
| dst->y = y; |
| } |
| |
| static void d2d_point_transform(D2D1_POINT_2F *dst, const D2D1_MATRIX_3X2_F *matrix, float x, float y) |
| { |
| dst->x = x * matrix->_11 + y * matrix->_21 + matrix->_31; |
| dst->y = x * matrix->_12 + y * matrix->_22 + matrix->_32; |
| } |
| |
| static void d2d_rect_expand(D2D1_RECT_F *dst, const D2D1_POINT_2F *point) |
| { |
| if (point->x < dst->left) |
| dst->left = point->x; |
| if (point->y < dst->top) |
| dst->top = point->y; |
| if (point->x > dst->right) |
| dst->right = point->x; |
| if (point->y > dst->bottom) |
| dst->bottom = point->y; |
| } |
| |
| static void d2d_rect_intersect(D2D1_RECT_F *dst, const D2D1_RECT_F *src) |
| { |
| if (src->left > dst->left) |
| dst->left = src->left; |
| if (src->top > dst->top) |
| dst->top = src->top; |
| if (src->right < dst->right) |
| dst->right = src->right; |
| if (src->bottom < dst->bottom) |
| dst->bottom = src->bottom; |
| } |
| |
| static void d2d_rect_set(D2D1_RECT_F *dst, float left, float top, float right, float bottom) |
| { |
| dst->left = left; |
| dst->top = top; |
| dst->right = right; |
| dst->bottom = bottom; |
| } |
| |
| static BOOL d2d_clip_stack_init(struct d2d_clip_stack *stack) |
| { |
| if (!(stack->stack = HeapAlloc(GetProcessHeap(), 0, INITIAL_CLIP_STACK_SIZE * sizeof(*stack->stack)))) |
| return FALSE; |
| |
| stack->size = INITIAL_CLIP_STACK_SIZE; |
| stack->count = 0; |
| |
| return TRUE; |
| } |
| |
| static void d2d_clip_stack_cleanup(struct d2d_clip_stack *stack) |
| { |
| HeapFree(GetProcessHeap(), 0, stack->stack); |
| } |
| |
| static BOOL d2d_clip_stack_push(struct d2d_clip_stack *stack, const D2D1_RECT_F *rect) |
| { |
| D2D1_RECT_F r; |
| |
| if (stack->count == stack->size) |
| { |
| D2D1_RECT_F *new_stack; |
| unsigned int new_size; |
| |
| if (stack->size > UINT_MAX / 2) |
| return FALSE; |
| |
| new_size = stack->size * 2; |
| if (!(new_stack = HeapReAlloc(GetProcessHeap(), 0, stack->stack, new_size * sizeof(*stack->stack)))) |
| return FALSE; |
| |
| stack->stack = new_stack; |
| stack->size = new_size; |
| } |
| |
| r = *rect; |
| if (stack->count) |
| d2d_rect_intersect(&r, &stack->stack[stack->count - 1]); |
| stack->stack[stack->count++] = r; |
| |
| return TRUE; |
| } |
| |
| static void d2d_clip_stack_pop(struct d2d_clip_stack *stack) |
| { |
| if (!stack->count) |
| return; |
| --stack->count; |
| } |
| |
| static void d2d_draw(struct d2d_d3d_render_target *render_target, ID3D10Buffer *vs_cb, |
| ID3D10PixelShader *ps, ID3D10Buffer *ps_cb, struct d2d_brush *brush) |
| { |
| ID3D10Device *device = render_target->device; |
| unsigned int offset; |
| D3D10_VIEWPORT vp; |
| HRESULT hr; |
| static const float blend_factor[] = {1.0f, 1.0f, 1.0f, 1.0f}; |
| |
| vp.TopLeftX = 0; |
| vp.TopLeftY = 0; |
| vp.Width = render_target->pixel_size.width; |
| vp.Height = render_target->pixel_size.height; |
| vp.MinDepth = 0.0f; |
| vp.MaxDepth = 1.0f; |
| |
| if (FAILED(hr = render_target->stateblock->lpVtbl->Capture(render_target->stateblock))) |
| { |
| WARN("Failed to capture stateblock, hr %#x.\n", hr); |
| return; |
| } |
| |
| ID3D10Device_ClearState(device); |
| |
| ID3D10Device_IASetInputLayout(device, render_target->il); |
| ID3D10Device_IASetPrimitiveTopology(device, D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); |
| offset = 0; |
| ID3D10Device_IASetVertexBuffers(device, 0, 1, &render_target->vb, |
| &render_target->vb_stride, &offset); |
| ID3D10Device_VSSetConstantBuffers(device, 0, 1, &vs_cb); |
| ID3D10Device_VSSetShader(device, render_target->vs); |
| ID3D10Device_PSSetConstantBuffers(device, 0, 1, &ps_cb); |
| ID3D10Device_PSSetShader(device, ps); |
| ID3D10Device_RSSetViewports(device, 1, &vp); |
| if (render_target->clip_stack.count) |
| { |
| const D2D1_RECT_F *clip_rect; |
| D3D10_RECT scissor_rect; |
| |
| clip_rect = &render_target->clip_stack.stack[render_target->clip_stack.count - 1]; |
| scissor_rect.left = clip_rect->left + 0.5f; |
| scissor_rect.top = clip_rect->top + 0.5f; |
| scissor_rect.right = clip_rect->right + 0.5f; |
| scissor_rect.bottom = clip_rect->bottom + 0.5f; |
| ID3D10Device_RSSetScissorRects(device, 1, &scissor_rect); |
| ID3D10Device_RSSetState(device, render_target->rs); |
| } |
| ID3D10Device_OMSetRenderTargets(device, 1, &render_target->view, NULL); |
| if (brush) |
| { |
| ID3D10Device_OMSetBlendState(device, render_target->bs, blend_factor, D3D10_DEFAULT_SAMPLE_MASK); |
| d2d_brush_bind_resources(brush, device); |
| } |
| |
| ID3D10Device_Draw(device, 4, 0); |
| |
| if (FAILED(hr = render_target->stateblock->lpVtbl->Apply(render_target->stateblock))) |
| WARN("Failed to apply stateblock, hr %#x.\n", hr); |
| } |
| |
| static inline struct d2d_d3d_render_target *impl_from_ID2D1RenderTarget(ID2D1RenderTarget *iface) |
| { |
| return CONTAINING_RECORD(iface, struct d2d_d3d_render_target, ID2D1RenderTarget_iface); |
| } |
| |
| static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_QueryInterface(ID2D1RenderTarget *iface, REFIID iid, void **out) |
| { |
| TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); |
| |
| if (IsEqualGUID(iid, &IID_ID2D1RenderTarget) |
| || IsEqualGUID(iid, &IID_ID2D1Resource) |
| || IsEqualGUID(iid, &IID_IUnknown)) |
| { |
| ID2D1RenderTarget_AddRef(iface); |
| *out = iface; |
| return S_OK; |
| } |
| |
| WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); |
| |
| *out = NULL; |
| return E_NOINTERFACE; |
| } |
| |
| static ULONG STDMETHODCALLTYPE d2d_d3d_render_target_AddRef(ID2D1RenderTarget *iface) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface); |
| ULONG refcount = InterlockedIncrement(&render_target->refcount); |
| |
| TRACE("%p increasing refcount to %u.\n", iface, refcount); |
| |
| return refcount; |
| } |
| |
| static ULONG STDMETHODCALLTYPE d2d_d3d_render_target_Release(ID2D1RenderTarget *iface) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface); |
| ULONG refcount = InterlockedDecrement(&render_target->refcount); |
| |
| TRACE("%p decreasing refcount to %u.\n", iface, refcount); |
| |
| if (!refcount) |
| { |
| d2d_clip_stack_cleanup(&render_target->clip_stack); |
| if (render_target->text_rendering_params) |
| IDWriteRenderingParams_Release(render_target->text_rendering_params); |
| ID3D10PixelShader_Release(render_target->rect_bitmap_ps); |
| ID3D10PixelShader_Release(render_target->rect_solid_ps); |
| ID3D10BlendState_Release(render_target->bs); |
| ID3D10RasterizerState_Release(render_target->rs); |
| ID3D10VertexShader_Release(render_target->vs); |
| ID3D10Buffer_Release(render_target->vb); |
| ID3D10InputLayout_Release(render_target->il); |
| render_target->stateblock->lpVtbl->Release(render_target->stateblock); |
| ID3D10RenderTargetView_Release(render_target->view); |
| ID3D10Device_Release(render_target->device); |
| ID2D1Factory_Release(render_target->factory); |
| HeapFree(GetProcessHeap(), 0, render_target); |
| } |
| |
| return refcount; |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_GetFactory(ID2D1RenderTarget *iface, ID2D1Factory **factory) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface); |
| |
| TRACE("iface %p, factory %p.\n", iface, factory); |
| |
| *factory = render_target->factory; |
| ID2D1Factory_AddRef(*factory); |
| } |
| |
| static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateBitmap(ID2D1RenderTarget *iface, |
| D2D1_SIZE_U size, const void *src_data, UINT32 pitch, const D2D1_BITMAP_PROPERTIES *desc, ID2D1Bitmap **bitmap) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface); |
| struct d2d_bitmap *object; |
| HRESULT hr; |
| |
| TRACE("iface %p, size {%u, %u}, src_data %p, pitch %u, desc %p, bitmap %p.\n", |
| iface, size.width, size.height, src_data, pitch, desc, bitmap); |
| |
| if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)))) |
| return E_OUTOFMEMORY; |
| |
| if (FAILED(hr = d2d_bitmap_init(object, render_target, size, src_data, pitch, desc))) |
| { |
| WARN("Failed to initialize bitmap, hr %#x.\n", hr); |
| HeapFree(GetProcessHeap(), 0, object); |
| return hr; |
| } |
| |
| TRACE("Created bitmap %p.\n", object); |
| *bitmap = &object->ID2D1Bitmap_iface; |
| |
| return S_OK; |
| } |
| |
| static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateBitmapFromWicBitmap(ID2D1RenderTarget *iface, |
| IWICBitmapSource *bitmap_source, const D2D1_BITMAP_PROPERTIES *desc, ID2D1Bitmap **bitmap) |
| { |
| D2D1_BITMAP_PROPERTIES bitmap_desc; |
| unsigned int bpp, data_size; |
| D2D1_SIZE_U size; |
| WICRect rect; |
| UINT32 pitch; |
| HRESULT hr; |
| void *data; |
| |
| TRACE("iface %p, bitmap_source %p, desc %p, bitmap %p.\n", |
| iface, bitmap_source, desc, bitmap); |
| |
| if (FAILED(hr = IWICBitmapSource_GetSize(bitmap_source, &size.width, &size.height))) |
| { |
| WARN("Failed to get bitmap size, hr %#x.\n", hr); |
| return hr; |
| } |
| |
| if (!desc) |
| { |
| bitmap_desc.pixelFormat.format = DXGI_FORMAT_UNKNOWN; |
| bitmap_desc.pixelFormat.alphaMode = D2D1_ALPHA_MODE_UNKNOWN; |
| bitmap_desc.dpiX = 0.0f; |
| bitmap_desc.dpiY = 0.0f; |
| } |
| else |
| { |
| bitmap_desc = *desc; |
| } |
| |
| if (bitmap_desc.pixelFormat.format == DXGI_FORMAT_UNKNOWN) |
| { |
| WICPixelFormatGUID wic_format; |
| |
| if (FAILED(hr = IWICBitmapSource_GetPixelFormat(bitmap_source, &wic_format))) |
| { |
| WARN("Failed to get bitmap format, hr %#x.\n", hr); |
| return hr; |
| } |
| |
| if (IsEqualGUID(&wic_format, &GUID_WICPixelFormat32bppPBGRA) |
| || IsEqualGUID(&wic_format, &GUID_WICPixelFormat32bppBGR)) |
| { |
| bitmap_desc.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM; |
| } |
| else |
| { |
| WARN("Unsupported WIC bitmap format %s.\n", debugstr_guid(&wic_format)); |
| return D2DERR_UNSUPPORTED_PIXEL_FORMAT; |
| } |
| } |
| |
| switch (bitmap_desc.pixelFormat.format) |
| { |
| case DXGI_FORMAT_B8G8R8A8_UNORM: |
| bpp = 4; |
| break; |
| |
| default: |
| FIXME("Unhandled format %#x.\n", bitmap_desc.pixelFormat.format); |
| return D2DERR_UNSUPPORTED_PIXEL_FORMAT; |
| } |
| |
| pitch = ((bpp * size.width) + 15) & ~15; |
| data_size = pitch * size.height; |
| if (!(data = HeapAlloc(GetProcessHeap(), 0, data_size))) |
| return E_OUTOFMEMORY; |
| |
| rect.X = 0; |
| rect.Y = 0; |
| rect.Width = size.width; |
| rect.Height = size.height; |
| if (FAILED(hr = IWICBitmapSource_CopyPixels(bitmap_source, &rect, pitch, data_size, data))) |
| { |
| WARN("Failed to copy bitmap pixels, hr %#x.\n", hr); |
| HeapFree(GetProcessHeap(), 0, data); |
| return hr; |
| } |
| |
| hr = d2d_d3d_render_target_CreateBitmap(iface, size, data, pitch, &bitmap_desc, bitmap); |
| |
| HeapFree(GetProcessHeap(), 0, data); |
| |
| return hr; |
| } |
| |
| static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateSharedBitmap(ID2D1RenderTarget *iface, |
| REFIID iid, void *data, const D2D1_BITMAP_PROPERTIES *desc, ID2D1Bitmap **bitmap) |
| { |
| FIXME("iface %p, iid %s, data %p, desc %p, bitmap %p stub!\n", |
| iface, debugstr_guid(iid), data, desc, bitmap); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateBitmapBrush(ID2D1RenderTarget *iface, |
| ID2D1Bitmap *bitmap, const D2D1_BITMAP_BRUSH_PROPERTIES *bitmap_brush_desc, |
| const D2D1_BRUSH_PROPERTIES *brush_desc, ID2D1BitmapBrush **brush) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface); |
| struct d2d_brush *object; |
| HRESULT hr; |
| |
| TRACE("iface %p, bitmap %p, bitmap_brush_desc %p, brush_desc %p, brush %p.\n", |
| iface, bitmap, bitmap_brush_desc, brush_desc, brush); |
| |
| if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)))) |
| return E_OUTOFMEMORY; |
| |
| if (FAILED(hr = d2d_bitmap_brush_init(object, render_target, bitmap, bitmap_brush_desc, brush_desc))) |
| { |
| WARN("Failed to initialize brush, hr %#x.\n", hr); |
| HeapFree(GetProcessHeap(), 0, object); |
| return hr; |
| } |
| |
| TRACE("Created brush %p.\n", object); |
| *brush = (ID2D1BitmapBrush *)&object->ID2D1Brush_iface; |
| |
| return S_OK; |
| } |
| |
| static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateSolidColorBrush(ID2D1RenderTarget *iface, |
| const D2D1_COLOR_F *color, const D2D1_BRUSH_PROPERTIES *desc, ID2D1SolidColorBrush **brush) |
| { |
| struct d2d_brush *object; |
| |
| TRACE("iface %p, color %p, desc %p, brush %p.\n", iface, color, desc, brush); |
| |
| if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)))) |
| return E_OUTOFMEMORY; |
| |
| d2d_solid_color_brush_init(object, iface, color, desc); |
| |
| TRACE("Created brush %p.\n", object); |
| *brush = (ID2D1SolidColorBrush *)&object->ID2D1Brush_iface; |
| |
| return S_OK; |
| } |
| |
| static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateGradientStopCollection(ID2D1RenderTarget *iface, |
| const D2D1_GRADIENT_STOP *stops, UINT32 stop_count, D2D1_GAMMA gamma, D2D1_EXTEND_MODE extend_mode, |
| ID2D1GradientStopCollection **gradient) |
| { |
| struct d2d_gradient *object; |
| HRESULT hr; |
| |
| TRACE("iface %p, stops %p, stop_count %u, gamma %#x, extend_mode %#x, gradient %p.\n", |
| iface, stops, stop_count, gamma, extend_mode, gradient); |
| |
| if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)))) |
| return E_OUTOFMEMORY; |
| |
| if (FAILED(hr = d2d_gradient_init(object, iface, stops, stop_count, gamma, extend_mode))) |
| { |
| WARN("Failed to initialize gradient, hr %#x.\n", hr); |
| HeapFree(GetProcessHeap(), 0, object); |
| return hr; |
| } |
| |
| TRACE("Created gradient %p.\n", object); |
| *gradient = &object->ID2D1GradientStopCollection_iface; |
| |
| return S_OK; |
| } |
| |
| static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateLinearGradientBrush(ID2D1RenderTarget *iface, |
| const D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES *gradient_brush_desc, const D2D1_BRUSH_PROPERTIES *brush_desc, |
| ID2D1GradientStopCollection *gradient, ID2D1LinearGradientBrush **brush) |
| { |
| struct d2d_brush *object; |
| |
| TRACE("iface %p, gradient_brush_desc %p, brush_desc %p, gradient %p, brush %p.\n", |
| iface, gradient_brush_desc, brush_desc, gradient, brush); |
| |
| if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)))) |
| return E_OUTOFMEMORY; |
| |
| d2d_linear_gradient_brush_init(object, iface, gradient_brush_desc, brush_desc, gradient); |
| |
| TRACE("Created brush %p.\n", object); |
| *brush = (ID2D1LinearGradientBrush *)&object->ID2D1Brush_iface; |
| |
| return S_OK; |
| } |
| |
| static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateRadialGradientBrush(ID2D1RenderTarget *iface, |
| const D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES *gradient_brush_desc, const D2D1_BRUSH_PROPERTIES *brush_desc, |
| ID2D1GradientStopCollection *gradient, ID2D1RadialGradientBrush **brush) |
| { |
| FIXME("iface %p, gradient_brush_desc %p, brush_desc %p, gradient %p, brush %p stub!\n", |
| iface, gradient_brush_desc, brush_desc, gradient, brush); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateCompatibleRenderTarget(ID2D1RenderTarget *iface, |
| const D2D1_SIZE_F *size, const D2D1_SIZE_U *pixel_size, const D2D1_PIXEL_FORMAT *format, |
| D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS options, ID2D1BitmapRenderTarget **render_target) |
| { |
| FIXME("iface %p, size %p, pixel_size %p, format %p, options %#x, render_target %p stub!\n", |
| iface, size, pixel_size, format, options, render_target); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateLayer(ID2D1RenderTarget *iface, |
| const D2D1_SIZE_F *size, ID2D1Layer **layer) |
| { |
| FIXME("iface %p, size %p, layer %p stub!\n", iface, size, layer); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateMesh(ID2D1RenderTarget *iface, ID2D1Mesh **mesh) |
| { |
| struct d2d_mesh *object; |
| |
| TRACE("iface %p, mesh %p.\n", iface, mesh); |
| |
| if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)))) |
| return E_OUTOFMEMORY; |
| |
| d2d_mesh_init(object); |
| |
| TRACE("Created mesh %p.\n", object); |
| *mesh = &object->ID2D1Mesh_iface; |
| |
| return S_OK; |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawLine(ID2D1RenderTarget *iface, |
| D2D1_POINT_2F p0, D2D1_POINT_2F p1, ID2D1Brush *brush, float stroke_width, ID2D1StrokeStyle *stroke_style) |
| { |
| FIXME("iface %p, p0 {%.8e, %.8e}, p1 {%.8e, %.8e}, brush %p, stroke_width %.8e, stroke_style %p stub!\n", |
| iface, p0.x, p0.y, p1.x, p1.y, brush, stroke_width, stroke_style); |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawRectangle(ID2D1RenderTarget *iface, |
| const D2D1_RECT_F *rect, ID2D1Brush *brush, float stroke_width, ID2D1StrokeStyle *stroke_style) |
| { |
| FIXME("iface %p, rect %p, brush %p, stroke_width %.8e, stroke_style %p stub!\n", |
| iface, rect, brush, stroke_width, stroke_style); |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_FillRectangle(ID2D1RenderTarget *iface, |
| const D2D1_RECT_F *rect, ID2D1Brush *brush) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface); |
| struct d2d_brush *brush_impl = unsafe_impl_from_ID2D1Brush(brush); |
| D3D10_SUBRESOURCE_DATA buffer_data; |
| D3D10_BUFFER_DESC buffer_desc; |
| ID3D10Buffer *vs_cb, *ps_cb; |
| ID3D10PixelShader *ps; |
| D2D1_COLOR_F color; |
| float tmp_x, tmp_y; |
| HRESULT hr; |
| struct |
| { |
| float _11, _21, _31, pad0; |
| float _12, _22, _32, pad1; |
| } transform; |
| |
| TRACE("iface %p, rect %p, brush %p.\n", iface, rect, brush); |
| |
| if (brush_impl->type != D2D_BRUSH_TYPE_SOLID |
| && brush_impl->type != D2D_BRUSH_TYPE_BITMAP) |
| { |
| FIXME("Unhandled brush type %#x.\n", brush_impl->type); |
| return; |
| } |
| |
| /* Translate from clip space to world (D2D rendertarget) space, taking the |
| * dpi and rendertarget transform into account. */ |
| tmp_x = (2.0f * render_target->dpi_x) / (96.0f * render_target->pixel_size.width); |
| tmp_y = -(2.0f * render_target->dpi_y) / (96.0f * render_target->pixel_size.height); |
| transform._11 = render_target->drawing_state.transform._11 * tmp_x; |
| transform._21 = render_target->drawing_state.transform._21 * tmp_x; |
| transform._31 = render_target->drawing_state.transform._31 * tmp_x - 1.0f; |
| transform.pad0 = 0.0f; |
| transform._12 = render_target->drawing_state.transform._12 * tmp_y; |
| transform._22 = render_target->drawing_state.transform._22 * tmp_y; |
| transform._32 = render_target->drawing_state.transform._32 * tmp_y + 1.0f; |
| transform.pad1 = 0.0f; |
| |
| /* Translate from world space to object space. */ |
| tmp_x = min(rect->left, rect->right) + fabsf(rect->right - rect->left) / 2.0f; |
| tmp_y = min(rect->top, rect->bottom) + fabsf(rect->bottom - rect->top) / 2.0f; |
| transform._31 += tmp_x * transform._11 + tmp_y * transform._21; |
| transform._32 += tmp_x * transform._12 + tmp_y * transform._22; |
| tmp_x = fabsf(rect->right - rect->left) / 2.0f; |
| tmp_y = fabsf(rect->bottom - rect->top) / 2.0f; |
| transform._11 *= tmp_x; |
| transform._12 *= tmp_x; |
| transform._21 *= tmp_y; |
| transform._22 *= tmp_y; |
| |
| buffer_desc.ByteWidth = sizeof(transform); |
| buffer_desc.Usage = D3D10_USAGE_DEFAULT; |
| buffer_desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER; |
| buffer_desc.CPUAccessFlags = 0; |
| buffer_desc.MiscFlags = 0; |
| |
| buffer_data.pSysMem = &transform; |
| buffer_data.SysMemPitch = 0; |
| buffer_data.SysMemSlicePitch = 0; |
| |
| if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device, &buffer_desc, &buffer_data, &vs_cb))) |
| { |
| WARN("Failed to create constant buffer, hr %#x.\n", hr); |
| return; |
| } |
| |
| if (brush_impl->type == D2D_BRUSH_TYPE_BITMAP) |
| { |
| struct d2d_bitmap *bitmap = brush_impl->u.bitmap.bitmap; |
| D2D_MATRIX_3X2_F w, b; |
| float dpi_scale, d; |
| |
| ps = render_target->rect_bitmap_ps; |
| |
| /* Scale for dpi. */ |
| w = render_target->drawing_state.transform; |
| dpi_scale = render_target->dpi_x / 96.0f; |
| w._11 *= dpi_scale; |
| w._21 *= dpi_scale; |
| w._31 *= dpi_scale; |
| dpi_scale = render_target->dpi_y / 96.0f; |
| w._12 *= dpi_scale; |
| w._22 *= dpi_scale; |
| w._32 *= dpi_scale; |
| |
| /* Scale for bitmap size and dpi. */ |
| b = brush_impl->transform; |
| dpi_scale = bitmap->pixel_size.width * (bitmap->dpi_x / 96.0f); |
| b._11 *= dpi_scale; |
| b._21 *= dpi_scale; |
| dpi_scale = bitmap->pixel_size.height * (bitmap->dpi_y / 96.0f); |
| b._12 *= dpi_scale; |
| b._22 *= dpi_scale; |
| |
| d2d_matrix_multiply(&b, &w); |
| |
| /* Invert the matrix. (Because the matrix is applied to the sampling |
| * coordinates. I.e., to scale the bitmap by 2 we need to divide the |
| * coordinates by 2.) */ |
| d = b._11 * b._22 - b._21 * b._12; |
| if (d != 0.0f) |
| { |
| transform._11 = b._22 / d; |
| transform._21 = -b._21 / d; |
| transform._31 = (b._21 * b._32 - b._31 * b._22) / d; |
| transform._12 = -b._12 / d; |
| transform._22 = b._11 / d; |
| transform._32 = -(b._11 * b._32 - b._31 * b._12) / d; |
| } |
| transform.pad1 = brush_impl->opacity; |
| |
| buffer_desc.ByteWidth = sizeof(transform); |
| buffer_data.pSysMem = &transform; |
| } |
| else |
| { |
| ps = render_target->rect_solid_ps; |
| |
| color = brush_impl->u.solid.color; |
| color.a *= brush_impl->opacity; |
| |
| buffer_desc.ByteWidth = sizeof(color); |
| buffer_data.pSysMem = &color; |
| } |
| |
| if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device, &buffer_desc, &buffer_data, &ps_cb))) |
| { |
| WARN("Failed to create constant buffer, hr %#x.\n", hr); |
| ID3D10Buffer_Release(vs_cb); |
| return; |
| } |
| |
| d2d_draw(render_target, vs_cb, ps, ps_cb, brush_impl); |
| |
| ID3D10Buffer_Release(ps_cb); |
| ID3D10Buffer_Release(vs_cb); |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawRoundedRectangle(ID2D1RenderTarget *iface, |
| const D2D1_ROUNDED_RECT *rect, ID2D1Brush *brush, float stroke_width, ID2D1StrokeStyle *stroke_style) |
| { |
| FIXME("iface %p, rect %p, brush %p, stroke_width %.8e, stroke_style %p stub!\n", |
| iface, rect, brush, stroke_width, stroke_style); |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_FillRoundedRectangle(ID2D1RenderTarget *iface, |
| const D2D1_ROUNDED_RECT *rect, ID2D1Brush *brush) |
| { |
| FIXME("iface %p, rect %p, brush %p stub!\n", iface, rect, brush); |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawEllipse(ID2D1RenderTarget *iface, |
| const D2D1_ELLIPSE *ellipse, ID2D1Brush *brush, float stroke_width, ID2D1StrokeStyle *stroke_style) |
| { |
| FIXME("iface %p, ellipse %p, brush %p, stroke_width %.8e, stroke_style %p stub!\n", |
| iface, ellipse, brush, stroke_width, stroke_style); |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_FillEllipse(ID2D1RenderTarget *iface, |
| const D2D1_ELLIPSE *ellipse, ID2D1Brush *brush) |
| { |
| FIXME("iface %p, ellipse %p, brush %p stub!\n", iface, ellipse, brush); |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawGeometry(ID2D1RenderTarget *iface, |
| ID2D1Geometry *geometry, ID2D1Brush *brush, float stroke_width, ID2D1StrokeStyle *stroke_style) |
| { |
| FIXME("iface %p, geometry %p, brush %p, stroke_width %.8e, stroke_style %p stub!\n", |
| iface, geometry, brush, stroke_width, stroke_style); |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_FillGeometry(ID2D1RenderTarget *iface, |
| ID2D1Geometry *geometry, ID2D1Brush *brush, ID2D1Brush *opacity_brush) |
| { |
| FIXME("iface %p, geometry %p, brush %p, opacity_brush %p stub!\n", iface, geometry, brush, opacity_brush); |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_FillMesh(ID2D1RenderTarget *iface, |
| ID2D1Mesh *mesh, ID2D1Brush *brush) |
| { |
| FIXME("iface %p, mesh %p, brush %p stub!\n", iface, mesh, brush); |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_FillOpacityMask(ID2D1RenderTarget *iface, |
| ID2D1Bitmap *mask, ID2D1Brush *brush, D2D1_OPACITY_MASK_CONTENT content, |
| const D2D1_RECT_F *dst_rect, const D2D1_RECT_F *src_rect) |
| { |
| FIXME("iface %p, mask %p, brush %p, content %#x, dst_rect %p, src_rect %p stub!\n", |
| iface, mask, brush, content, dst_rect, src_rect); |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawBitmap(ID2D1RenderTarget *iface, |
| ID2D1Bitmap *bitmap, const D2D1_RECT_F *dst_rect, float opacity, |
| D2D1_BITMAP_INTERPOLATION_MODE interpolation_mode, const D2D1_RECT_F *src_rect) |
| { |
| D2D1_BITMAP_BRUSH_PROPERTIES bitmap_brush_desc; |
| D2D1_BRUSH_PROPERTIES brush_desc; |
| ID2D1BitmapBrush *brush; |
| D2D1_RECT_F s, d; |
| HRESULT hr; |
| |
| TRACE("iface %p, bitmap %p, dst_rect %p, opacity %.8e, interpolation_mode %#x, src_rect %p.\n", |
| iface, bitmap, dst_rect, opacity, interpolation_mode, src_rect); |
| |
| if (src_rect) |
| { |
| s = *src_rect; |
| } |
| else |
| { |
| D2D1_SIZE_F size; |
| |
| size = ID2D1Bitmap_GetSize(bitmap); |
| s.left = 0.0f; |
| s.top = 0.0f; |
| s.right = size.width; |
| s.bottom = size.height; |
| } |
| |
| if (dst_rect) |
| { |
| d = *dst_rect; |
| } |
| else |
| { |
| d.left = 0.0f; |
| d.top = 0.0f; |
| d.right = s.right - s.left; |
| d.bottom = s.bottom - s.top; |
| } |
| |
| bitmap_brush_desc.extendModeX = D2D1_EXTEND_MODE_CLAMP; |
| bitmap_brush_desc.extendModeY = D2D1_EXTEND_MODE_CLAMP; |
| bitmap_brush_desc.interpolationMode = interpolation_mode; |
| |
| brush_desc.opacity = opacity; |
| brush_desc.transform._11 = fabsf((d.right - d.left) / (s.right - s.left)); |
| brush_desc.transform._21 = 0.0f; |
| brush_desc.transform._31 = min(d.left, d.right) - min(s.left, s.right) * brush_desc.transform._11; |
| brush_desc.transform._12 = 0.0f; |
| brush_desc.transform._22 = fabsf((d.bottom - d.top) / (s.bottom - s.top)); |
| brush_desc.transform._32 = min(d.top, d.bottom) - min(s.top, s.bottom) * brush_desc.transform._22; |
| |
| if (FAILED(hr = ID2D1RenderTarget_CreateBitmapBrush(iface, bitmap, &bitmap_brush_desc, &brush_desc, &brush))) |
| { |
| ERR("Failed to create bitmap brush, hr %#x.\n", hr); |
| return; |
| } |
| |
| ID2D1RenderTarget_FillRectangle(iface, &d, (ID2D1Brush *)brush); |
| ID2D1BitmapBrush_Release(brush); |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawText(ID2D1RenderTarget *iface, |
| const WCHAR *string, UINT32 string_len, IDWriteTextFormat *text_format, const D2D1_RECT_F *layout_rect, |
| ID2D1Brush *brush, D2D1_DRAW_TEXT_OPTIONS options, DWRITE_MEASURING_MODE measuring_mode) |
| { |
| IDWriteTextLayout *text_layout; |
| IDWriteFactory *dwrite_factory; |
| D2D1_POINT_2F origin; |
| HRESULT hr; |
| |
| TRACE("iface %p, string %s, string_len %u, text_format %p, layout_rect %p, " |
| "brush %p, options %#x, measuring_mode %#x.\n", |
| iface, debugstr_wn(string, string_len), string_len, text_format, layout_rect, |
| brush, options, measuring_mode); |
| |
| if (measuring_mode != DWRITE_MEASURING_MODE_NATURAL) |
| FIXME("Ignoring measuring mode %#x.\n", measuring_mode); |
| |
| if (FAILED(hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, |
| &IID_IDWriteFactory, (IUnknown **)&dwrite_factory))) |
| { |
| ERR("Failed to create dwrite factory, hr %#x.\n", hr); |
| return; |
| } |
| |
| hr = IDWriteFactory_CreateTextLayout(dwrite_factory, string, string_len, text_format, |
| layout_rect->right - layout_rect->left, layout_rect->bottom - layout_rect->top, &text_layout); |
| IDWriteFactory_Release(dwrite_factory); |
| if (FAILED(hr)) |
| { |
| ERR("Failed to create text layout, hr %#x.\n", hr); |
| return; |
| } |
| |
| d2d_point_set(&origin, layout_rect->left, layout_rect->top); |
| ID2D1RenderTarget_DrawTextLayout(iface, origin, text_layout, brush, options); |
| IDWriteTextLayout_Release(text_layout); |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawTextLayout(ID2D1RenderTarget *iface, |
| D2D1_POINT_2F origin, IDWriteTextLayout *layout, ID2D1Brush *brush, D2D1_DRAW_TEXT_OPTIONS options) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface); |
| struct d2d_draw_text_layout_ctx ctx; |
| HRESULT hr; |
| |
| TRACE("iface %p, origin {%.8e, %.8e}, layout %p, brush %p, options %#x.\n", |
| iface, origin.x, origin.y, layout, brush, options); |
| |
| ctx.brush = brush; |
| ctx.options = options; |
| |
| if (FAILED(hr = IDWriteTextLayout_Draw(layout, |
| &ctx, &render_target->IDWriteTextRenderer_iface, origin.x, origin.y))) |
| FIXME("Failed to draw text layout, hr %#x.\n", hr); |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawGlyphRun(ID2D1RenderTarget *iface, |
| D2D1_POINT_2F baseline_origin, const DWRITE_GLYPH_RUN *glyph_run, ID2D1Brush *brush, |
| DWRITE_MEASURING_MODE measuring_mode) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface); |
| D2D1_MATRIX_3X2_F *transform, prev_transform; |
| ID2D1PathGeometry *geometry; |
| ID2D1GeometrySink *sink; |
| HRESULT hr; |
| |
| TRACE("iface %p, baseline_origin {%.8e, %.8e}, glyph_run %p, brush %p, measuring_mode %#x.\n", |
| iface, baseline_origin.x, baseline_origin.y, glyph_run, brush, measuring_mode); |
| |
| if (measuring_mode) |
| FIXME("Ignoring measuring mode %#x.\n", measuring_mode); |
| |
| if (FAILED(hr = ID2D1Factory_CreatePathGeometry(render_target->factory, &geometry))) |
| { |
| ERR("Failed to create geometry, hr %#x.\n", hr); |
| return; |
| } |
| |
| if (FAILED(hr = ID2D1PathGeometry_Open(geometry, &sink))) |
| { |
| ERR("Failed to open geometry sink, hr %#x.\n", hr); |
| ID2D1PathGeometry_Release(geometry); |
| return; |
| } |
| |
| if (FAILED(hr = IDWriteFontFace_GetGlyphRunOutline(glyph_run->fontFace, glyph_run->fontEmSize, |
| glyph_run->glyphIndices, glyph_run->glyphAdvances, glyph_run->glyphOffsets, glyph_run->glyphCount, |
| glyph_run->isSideways, glyph_run->bidiLevel & 1, (IDWriteGeometrySink *)sink))) |
| { |
| ERR("Failed to get glyph run outline, hr %#x.\n", hr); |
| ID2D1GeometrySink_Release(sink); |
| ID2D1PathGeometry_Release(geometry); |
| return; |
| } |
| |
| if (FAILED(hr = ID2D1GeometrySink_Close(sink))) |
| ERR("Failed to close geometry sink, hr %#x.\n", hr); |
| ID2D1GeometrySink_Release(sink); |
| |
| transform = &render_target->drawing_state.transform; |
| prev_transform = *transform; |
| transform->_31 += baseline_origin.x * transform->_11 + baseline_origin.y * transform->_21; |
| transform->_32 += baseline_origin.x * transform->_12 + baseline_origin.y * transform->_22; |
| ID2D1RenderTarget_FillGeometry(iface, (ID2D1Geometry *)geometry, brush, NULL); |
| *transform = prev_transform; |
| |
| ID2D1PathGeometry_Release(geometry); |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_SetTransform(ID2D1RenderTarget *iface, |
| const D2D1_MATRIX_3X2_F *transform) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface); |
| |
| TRACE("iface %p, transform %p.\n", iface, transform); |
| |
| render_target->drawing_state.transform = *transform; |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_GetTransform(ID2D1RenderTarget *iface, |
| D2D1_MATRIX_3X2_F *transform) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface); |
| |
| TRACE("iface %p, transform %p.\n", iface, transform); |
| |
| *transform = render_target->drawing_state.transform; |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_SetAntialiasMode(ID2D1RenderTarget *iface, |
| D2D1_ANTIALIAS_MODE antialias_mode) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface); |
| |
| TRACE("iface %p, antialias_mode %#x stub!\n", iface, antialias_mode); |
| |
| render_target->drawing_state.antialiasMode = antialias_mode; |
| } |
| |
| static D2D1_ANTIALIAS_MODE STDMETHODCALLTYPE d2d_d3d_render_target_GetAntialiasMode(ID2D1RenderTarget *iface) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface); |
| |
| TRACE("iface %p.\n", iface); |
| |
| return render_target->drawing_state.antialiasMode; |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_SetTextAntialiasMode(ID2D1RenderTarget *iface, |
| D2D1_TEXT_ANTIALIAS_MODE antialias_mode) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface); |
| |
| TRACE("iface %p, antialias_mode %#x.\n", iface, antialias_mode); |
| |
| render_target->drawing_state.textAntialiasMode = antialias_mode; |
| } |
| |
| static D2D1_TEXT_ANTIALIAS_MODE STDMETHODCALLTYPE d2d_d3d_render_target_GetTextAntialiasMode(ID2D1RenderTarget *iface) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface); |
| |
| TRACE("iface %p.\n", iface); |
| |
| return render_target->drawing_state.textAntialiasMode; |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_SetTextRenderingParams(ID2D1RenderTarget *iface, |
| IDWriteRenderingParams *text_rendering_params) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface); |
| |
| TRACE("iface %p, text_rendering_params %p.\n", iface, text_rendering_params); |
| |
| if (text_rendering_params) |
| IDWriteRenderingParams_AddRef(text_rendering_params); |
| if (render_target->text_rendering_params) |
| IDWriteRenderingParams_Release(render_target->text_rendering_params); |
| render_target->text_rendering_params = text_rendering_params; |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_GetTextRenderingParams(ID2D1RenderTarget *iface, |
| IDWriteRenderingParams **text_rendering_params) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface); |
| |
| TRACE("iface %p, text_rendering_params %p.\n", iface, text_rendering_params); |
| |
| if ((*text_rendering_params = render_target->text_rendering_params)) |
| IDWriteRenderingParams_AddRef(*text_rendering_params); |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_SetTags(ID2D1RenderTarget *iface, D2D1_TAG tag1, D2D1_TAG tag2) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface); |
| |
| TRACE("iface %p, tag1 %s, tag2 %s.\n", iface, wine_dbgstr_longlong(tag1), wine_dbgstr_longlong(tag2)); |
| |
| render_target->drawing_state.tag1 = tag1; |
| render_target->drawing_state.tag2 = tag2; |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_GetTags(ID2D1RenderTarget *iface, D2D1_TAG *tag1, D2D1_TAG *tag2) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface); |
| |
| TRACE("iface %p, tag1 %p, tag2 %p.\n", iface, tag1, tag2); |
| |
| *tag1 = render_target->drawing_state.tag1; |
| *tag2 = render_target->drawing_state.tag2; |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_PushLayer(ID2D1RenderTarget *iface, |
| const D2D1_LAYER_PARAMETERS *layer_parameters, ID2D1Layer *layer) |
| { |
| FIXME("iface %p, layer_parameters %p, layer %p stub!\n", iface, layer_parameters, layer); |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_PopLayer(ID2D1RenderTarget *iface) |
| { |
| FIXME("iface %p stub!\n", iface); |
| } |
| |
| static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_Flush(ID2D1RenderTarget *iface, D2D1_TAG *tag1, D2D1_TAG *tag2) |
| { |
| FIXME("iface %p, tag1 %p, tag2 %p stub!\n", iface, tag1, tag2); |
| |
| return E_NOTIMPL; |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_SaveDrawingState(ID2D1RenderTarget *iface, |
| ID2D1DrawingStateBlock *state_block) |
| { |
| struct d2d_state_block *state_block_impl = unsafe_impl_from_ID2D1DrawingStateBlock(state_block); |
| struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface); |
| |
| TRACE("iface %p, state_block %p.\n", iface, state_block); |
| |
| state_block_impl->drawing_state = render_target->drawing_state; |
| if (render_target->text_rendering_params) |
| IDWriteRenderingParams_AddRef(render_target->text_rendering_params); |
| if (state_block_impl->text_rendering_params) |
| IDWriteRenderingParams_Release(state_block_impl->text_rendering_params); |
| state_block_impl->text_rendering_params = render_target->text_rendering_params; |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_RestoreDrawingState(ID2D1RenderTarget *iface, |
| ID2D1DrawingStateBlock *state_block) |
| { |
| struct d2d_state_block *state_block_impl = unsafe_impl_from_ID2D1DrawingStateBlock(state_block); |
| struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface); |
| |
| TRACE("iface %p, state_block %p.\n", iface, state_block); |
| |
| render_target->drawing_state = state_block_impl->drawing_state; |
| if (state_block_impl->text_rendering_params) |
| IDWriteRenderingParams_AddRef(state_block_impl->text_rendering_params); |
| if (render_target->text_rendering_params) |
| IDWriteRenderingParams_Release(render_target->text_rendering_params); |
| render_target->text_rendering_params = state_block_impl->text_rendering_params; |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_PushAxisAlignedClip(ID2D1RenderTarget *iface, |
| const D2D1_RECT_F *clip_rect, D2D1_ANTIALIAS_MODE antialias_mode) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface); |
| D2D1_RECT_F transformed_rect; |
| float x_scale, y_scale; |
| D2D1_POINT_2F point; |
| |
| TRACE("iface %p, clip_rect %p, antialias_mode %#x.\n", iface, clip_rect, antialias_mode); |
| |
| if (antialias_mode != D2D1_ANTIALIAS_MODE_ALIASED) |
| FIXME("Ignoring antialias_mode %#x.\n", antialias_mode); |
| |
| x_scale = render_target->dpi_x / 96.0f; |
| y_scale = render_target->dpi_y / 96.0f; |
| d2d_point_transform(&point, &render_target->drawing_state.transform, |
| clip_rect->left * x_scale, clip_rect->top * y_scale); |
| d2d_rect_set(&transformed_rect, point.x, point.y, point.x, point.y); |
| d2d_point_transform(&point, &render_target->drawing_state.transform, |
| clip_rect->left * x_scale, clip_rect->bottom * y_scale); |
| d2d_rect_expand(&transformed_rect, &point); |
| d2d_point_transform(&point, &render_target->drawing_state.transform, |
| clip_rect->right * x_scale, clip_rect->top * y_scale); |
| d2d_rect_expand(&transformed_rect, &point); |
| d2d_point_transform(&point, &render_target->drawing_state.transform, |
| clip_rect->right * x_scale, clip_rect->bottom * y_scale); |
| d2d_rect_expand(&transformed_rect, &point); |
| |
| if (!d2d_clip_stack_push(&render_target->clip_stack, &transformed_rect)) |
| WARN("Failed to push clip rect.\n"); |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_PopAxisAlignedClip(ID2D1RenderTarget *iface) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface); |
| |
| TRACE("iface %p.\n", iface); |
| |
| d2d_clip_stack_pop(&render_target->clip_stack); |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_Clear(ID2D1RenderTarget *iface, const D2D1_COLOR_F *color) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface); |
| D3D10_SUBRESOURCE_DATA buffer_data; |
| D3D10_BUFFER_DESC buffer_desc; |
| ID3D10Buffer *vs_cb, *ps_cb; |
| HRESULT hr; |
| |
| static const float transform[] = |
| { |
| 1.0f, 0.0f, 0.0f, 0.0f, |
| 0.0f, -1.0f, 0.0f, 0.0f, |
| }; |
| |
| TRACE("iface %p, color %p.\n", iface, color); |
| |
| buffer_desc.ByteWidth = sizeof(transform); |
| buffer_desc.Usage = D3D10_USAGE_DEFAULT; |
| buffer_desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER; |
| buffer_desc.CPUAccessFlags = 0; |
| buffer_desc.MiscFlags = 0; |
| |
| buffer_data.pSysMem = transform; |
| buffer_data.SysMemPitch = 0; |
| buffer_data.SysMemSlicePitch = 0; |
| |
| if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device, &buffer_desc, &buffer_data, &vs_cb))) |
| { |
| WARN("Failed to create constant buffer, hr %#x.\n", hr); |
| return; |
| } |
| |
| buffer_desc.ByteWidth = sizeof(*color); |
| buffer_data.pSysMem = color; |
| |
| if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device, &buffer_desc, &buffer_data, &ps_cb))) |
| { |
| WARN("Failed to create constant buffer, hr %#x.\n", hr); |
| ID3D10Buffer_Release(vs_cb); |
| return; |
| } |
| |
| d2d_draw(render_target, vs_cb, render_target->rect_solid_ps, ps_cb, NULL); |
| |
| ID3D10Buffer_Release(ps_cb); |
| ID3D10Buffer_Release(vs_cb); |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_BeginDraw(ID2D1RenderTarget *iface) |
| { |
| TRACE("iface %p.\n", iface); |
| } |
| |
| static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_EndDraw(ID2D1RenderTarget *iface, |
| D2D1_TAG *tag1, D2D1_TAG *tag2) |
| { |
| TRACE("iface %p, tag1 %p, tag2 %p.\n", iface, tag1, tag2); |
| |
| if (tag1) |
| *tag1 = 0; |
| if (tag2) |
| *tag2 = 0; |
| |
| return S_OK; |
| } |
| |
| static D2D1_PIXEL_FORMAT * STDMETHODCALLTYPE d2d_d3d_render_target_GetPixelFormat(ID2D1RenderTarget *iface, |
| D2D1_PIXEL_FORMAT *format) |
| { |
| FIXME("iface %p, format %p stub!\n", iface, format); |
| |
| format->format = DXGI_FORMAT_UNKNOWN; |
| format->alphaMode = D2D1_ALPHA_MODE_UNKNOWN; |
| return format; |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_SetDpi(ID2D1RenderTarget *iface, float dpi_x, float dpi_y) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface); |
| |
| TRACE("iface %p, dpi_x %.8e, dpi_y %.8e.\n", iface, dpi_x, dpi_y); |
| |
| if (dpi_x == 0.0f && dpi_y == 0.0f) |
| { |
| dpi_x = 96.0f; |
| dpi_y = 96.0f; |
| } |
| |
| render_target->dpi_x = dpi_x; |
| render_target->dpi_y = dpi_y; |
| } |
| |
| static void STDMETHODCALLTYPE d2d_d3d_render_target_GetDpi(ID2D1RenderTarget *iface, float *dpi_x, float *dpi_y) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface); |
| |
| TRACE("iface %p, dpi_x %p, dpi_y %p.\n", iface, dpi_x, dpi_y); |
| |
| *dpi_x = render_target->dpi_x; |
| *dpi_y = render_target->dpi_y; |
| } |
| |
| static D2D1_SIZE_F * STDMETHODCALLTYPE d2d_d3d_render_target_GetSize(ID2D1RenderTarget *iface, D2D1_SIZE_F *size) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface); |
| |
| TRACE("iface %p, size %p.\n", iface, size); |
| |
| size->width = render_target->pixel_size.width / (render_target->dpi_x / 96.0f); |
| size->height = render_target->pixel_size.height / (render_target->dpi_y / 96.0f); |
| return size; |
| } |
| |
| static D2D1_SIZE_U * STDMETHODCALLTYPE d2d_d3d_render_target_GetPixelSize(ID2D1RenderTarget *iface, |
| D2D1_SIZE_U *pixel_size) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface); |
| |
| TRACE("iface %p, pixel_size %p.\n", iface, pixel_size); |
| |
| *pixel_size = render_target->pixel_size; |
| return pixel_size; |
| } |
| |
| static UINT32 STDMETHODCALLTYPE d2d_d3d_render_target_GetMaximumBitmapSize(ID2D1RenderTarget *iface) |
| { |
| FIXME("iface %p stub!\n", iface); |
| |
| return 0; |
| } |
| |
| static BOOL STDMETHODCALLTYPE d2d_d3d_render_target_IsSupported(ID2D1RenderTarget *iface, |
| const D2D1_RENDER_TARGET_PROPERTIES *desc) |
| { |
| FIXME("iface %p, desc %p stub!\n", iface, desc); |
| |
| return FALSE; |
| } |
| |
| static const struct ID2D1RenderTargetVtbl d2d_d3d_render_target_vtbl = |
| { |
| d2d_d3d_render_target_QueryInterface, |
| d2d_d3d_render_target_AddRef, |
| d2d_d3d_render_target_Release, |
| d2d_d3d_render_target_GetFactory, |
| d2d_d3d_render_target_CreateBitmap, |
| d2d_d3d_render_target_CreateBitmapFromWicBitmap, |
| d2d_d3d_render_target_CreateSharedBitmap, |
| d2d_d3d_render_target_CreateBitmapBrush, |
| d2d_d3d_render_target_CreateSolidColorBrush, |
| d2d_d3d_render_target_CreateGradientStopCollection, |
| d2d_d3d_render_target_CreateLinearGradientBrush, |
| d2d_d3d_render_target_CreateRadialGradientBrush, |
| d2d_d3d_render_target_CreateCompatibleRenderTarget, |
| d2d_d3d_render_target_CreateLayer, |
| d2d_d3d_render_target_CreateMesh, |
| d2d_d3d_render_target_DrawLine, |
| d2d_d3d_render_target_DrawRectangle, |
| d2d_d3d_render_target_FillRectangle, |
| d2d_d3d_render_target_DrawRoundedRectangle, |
| d2d_d3d_render_target_FillRoundedRectangle, |
| d2d_d3d_render_target_DrawEllipse, |
| d2d_d3d_render_target_FillEllipse, |
| d2d_d3d_render_target_DrawGeometry, |
| d2d_d3d_render_target_FillGeometry, |
| d2d_d3d_render_target_FillMesh, |
| d2d_d3d_render_target_FillOpacityMask, |
| d2d_d3d_render_target_DrawBitmap, |
| d2d_d3d_render_target_DrawText, |
| d2d_d3d_render_target_DrawTextLayout, |
| d2d_d3d_render_target_DrawGlyphRun, |
| d2d_d3d_render_target_SetTransform, |
| d2d_d3d_render_target_GetTransform, |
| d2d_d3d_render_target_SetAntialiasMode, |
| d2d_d3d_render_target_GetAntialiasMode, |
| d2d_d3d_render_target_SetTextAntialiasMode, |
| d2d_d3d_render_target_GetTextAntialiasMode, |
| d2d_d3d_render_target_SetTextRenderingParams, |
| d2d_d3d_render_target_GetTextRenderingParams, |
| d2d_d3d_render_target_SetTags, |
| d2d_d3d_render_target_GetTags, |
| d2d_d3d_render_target_PushLayer, |
| d2d_d3d_render_target_PopLayer, |
| d2d_d3d_render_target_Flush, |
| d2d_d3d_render_target_SaveDrawingState, |
| d2d_d3d_render_target_RestoreDrawingState, |
| d2d_d3d_render_target_PushAxisAlignedClip, |
| d2d_d3d_render_target_PopAxisAlignedClip, |
| d2d_d3d_render_target_Clear, |
| d2d_d3d_render_target_BeginDraw, |
| d2d_d3d_render_target_EndDraw, |
| d2d_d3d_render_target_GetPixelFormat, |
| d2d_d3d_render_target_SetDpi, |
| d2d_d3d_render_target_GetDpi, |
| d2d_d3d_render_target_GetSize, |
| d2d_d3d_render_target_GetPixelSize, |
| d2d_d3d_render_target_GetMaximumBitmapSize, |
| d2d_d3d_render_target_IsSupported, |
| }; |
| |
| static inline struct d2d_d3d_render_target *impl_from_IDWriteTextRenderer(IDWriteTextRenderer *iface) |
| { |
| return CONTAINING_RECORD(iface, struct d2d_d3d_render_target, IDWriteTextRenderer_iface); |
| } |
| |
| static HRESULT STDMETHODCALLTYPE d2d_text_renderer_QueryInterface(IDWriteTextRenderer *iface, REFIID iid, void **out) |
| { |
| TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); |
| |
| if (IsEqualGUID(iid, &IID_IDWriteTextRenderer) |
| || IsEqualGUID(iid, &IID_IDWritePixelSnapping) |
| || IsEqualGUID(iid, &IID_IUnknown)) |
| { |
| IDWriteTextRenderer_AddRef(iface); |
| *out = iface; |
| return S_OK; |
| } |
| |
| WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); |
| |
| *out = NULL; |
| return E_NOINTERFACE; |
| } |
| |
| static ULONG STDMETHODCALLTYPE d2d_text_renderer_AddRef(IDWriteTextRenderer *iface) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_IDWriteTextRenderer(iface); |
| |
| TRACE("iface %p.\n", iface); |
| |
| return d2d_d3d_render_target_AddRef(&render_target->ID2D1RenderTarget_iface); |
| } |
| |
| static ULONG STDMETHODCALLTYPE d2d_text_renderer_Release(IDWriteTextRenderer *iface) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_IDWriteTextRenderer(iface); |
| |
| TRACE("iface %p.\n", iface); |
| |
| return d2d_d3d_render_target_Release(&render_target->ID2D1RenderTarget_iface); |
| } |
| |
| static HRESULT STDMETHODCALLTYPE d2d_text_renderer_IsPixelSnappingDisabled(IDWriteTextRenderer *iface, |
| void *ctx, BOOL *disabled) |
| { |
| struct d2d_draw_text_layout_ctx *context = ctx; |
| |
| TRACE("iface %p, ctx %p, disabled %p.\n", iface, ctx, disabled); |
| |
| *disabled = context->options & D2D1_DRAW_TEXT_OPTIONS_NO_SNAP; |
| |
| return S_OK; |
| } |
| |
| static HRESULT STDMETHODCALLTYPE d2d_text_renderer_GetCurrentTransform(IDWriteTextRenderer *iface, |
| void *ctx, DWRITE_MATRIX *transform) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_IDWriteTextRenderer(iface); |
| |
| TRACE("iface %p, ctx %p, transform %p.\n", iface, ctx, transform); |
| |
| ID2D1RenderTarget_GetTransform(&render_target->ID2D1RenderTarget_iface, (D2D1_MATRIX_3X2_F *)transform); |
| |
| return S_OK; |
| } |
| |
| static HRESULT STDMETHODCALLTYPE d2d_text_renderer_GetPixelsPerDip(IDWriteTextRenderer *iface, void *ctx, float *ppd) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_IDWriteTextRenderer(iface); |
| |
| TRACE("iface %p, ctx %p, ppd %p.\n", iface, ctx, ppd); |
| |
| *ppd = render_target->dpi_y / 96.0f; |
| |
| return S_OK; |
| } |
| |
| static HRESULT STDMETHODCALLTYPE d2d_text_renderer_DrawGlyphRun(IDWriteTextRenderer *iface, void *ctx, |
| float baseline_origin_x, float baseline_origin_y, DWRITE_MEASURING_MODE measuring_mode, |
| const DWRITE_GLYPH_RUN *glyph_run, const DWRITE_GLYPH_RUN_DESCRIPTION *desc, IUnknown *effect) |
| { |
| struct d2d_d3d_render_target *render_target = impl_from_IDWriteTextRenderer(iface); |
| D2D1_POINT_2F baseline_origin = {baseline_origin_x, baseline_origin_y}; |
| struct d2d_draw_text_layout_ctx *context = ctx; |
| |
| TRACE("iface %p, ctx %p, baseline_origin_x %.8e, baseline_origin_y %.8e, " |
| "measuring_mode %#x, glyph_run %p, desc %p, effect %p.\n", |
| iface, ctx, baseline_origin_x, baseline_origin_y, |
| measuring_mode, glyph_run, desc, effect); |
| |
| if (desc) |
| FIXME("Ignoring glyph run description %p.\n", desc); |
| if (effect) |
| FIXME("Ignoring effect %p.\n", effect); |
| if (context->options & ~D2D1_DRAW_TEXT_OPTIONS_NO_SNAP) |
| FIXME("Ignoring options %#x.\n", context->options); |
| |
| TRACE("%s\n", debugstr_wn(desc->string, desc->stringLength)); |
| ID2D1RenderTarget_DrawGlyphRun(&render_target->ID2D1RenderTarget_iface, |
| baseline_origin, glyph_run, context->brush, measuring_mode); |
| |
| return S_OK; |
| } |
| |
| static HRESULT STDMETHODCALLTYPE d2d_text_renderer_DrawUnderline(IDWriteTextRenderer *iface, void *ctx, |
| float baseline_origin_x, float baseline_origin_y, const DWRITE_UNDERLINE *underline, IUnknown *effect) |
| { |
| FIXME("iface %p, ctx %p, baseline_origin_x %.8e, baseline_origin_y %.8e, underline %p, effect %p stub!\n", |
| iface, ctx, baseline_origin_x, baseline_origin_y, underline, effect); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT STDMETHODCALLTYPE d2d_text_renderer_DrawStrikethrough(IDWriteTextRenderer *iface, void *ctx, |
| float baseline_origin_x, float baseline_origin_y, const DWRITE_STRIKETHROUGH *strikethrough, IUnknown *effect) |
| { |
| FIXME("iface %p, ctx %p, baseline_origin_x %.8e, baseline_origin_y %.8e, strikethrough %p, effect %p stub!\n", |
| iface, ctx, baseline_origin_x, baseline_origin_y, strikethrough, effect); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT STDMETHODCALLTYPE d2d_text_renderer_DrawInlineObject(IDWriteTextRenderer *iface, void *ctx, |
| float origin_x, float origin_y, IDWriteInlineObject *object, BOOL is_sideways, BOOL is_rtl, IUnknown *effect) |
| { |
| FIXME("iface %p, ctx %p, origin_x %.8e, origin_y %.8e, object %p, is_sideways %#x, is_rtl %#x, effect %p stub!\n", |
| iface, ctx, origin_x, origin_y, object, is_sideways, is_rtl, effect); |
| |
| return E_NOTIMPL; |
| } |
| |
| static const struct IDWriteTextRendererVtbl d2d_text_renderer_vtbl = |
| { |
| d2d_text_renderer_QueryInterface, |
| d2d_text_renderer_AddRef, |
| d2d_text_renderer_Release, |
| d2d_text_renderer_IsPixelSnappingDisabled, |
| d2d_text_renderer_GetCurrentTransform, |
| d2d_text_renderer_GetPixelsPerDip, |
| d2d_text_renderer_DrawGlyphRun, |
| d2d_text_renderer_DrawUnderline, |
| d2d_text_renderer_DrawStrikethrough, |
| d2d_text_renderer_DrawInlineObject, |
| }; |
| |
| HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_target, ID2D1Factory *factory, |
| IDXGISurface *surface, const D2D1_RENDER_TARGET_PROPERTIES *desc) |
| { |
| D3D10_SUBRESOURCE_DATA buffer_data; |
| D3D10_STATE_BLOCK_MASK state_mask; |
| DXGI_SURFACE_DESC surface_desc; |
| D3D10_RASTERIZER_DESC rs_desc; |
| D3D10_BUFFER_DESC buffer_desc; |
| D3D10_BLEND_DESC blend_desc; |
| ID3D10Resource *resource; |
| HRESULT hr; |
| |
| static const D3D10_INPUT_ELEMENT_DESC il_desc[] = |
| { |
| {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0}, |
| }; |
| static const DWORD vs_code[] = |
| { |
| /* float3x2 transform; |
| * |
| * float4 main(float4 position : POSITION) : SV_POSITION |
| * { |
| * return float4(mul(position.xyw, transform), position.zw); |
| * } */ |
| 0x43425844, 0x0add3194, 0x205f74ec, 0xab527fe7, 0xbe6ad704, 0x00000001, 0x00000128, 0x00000003, |
| 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, |
| 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000f0f, 0x49534f50, 0x4e4f4954, 0xababab00, |
| 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000001, 0x00000003, |
| 0x00000000, 0x0000000f, 0x505f5653, 0x5449534f, 0x004e4f49, 0x52444853, 0x0000008c, 0x00010040, |
| 0x00000023, 0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0300005f, 0x001010f2, 0x00000000, |
| 0x04000067, 0x001020f2, 0x00000000, 0x00000001, 0x08000010, 0x00102012, 0x00000000, 0x00101346, |
| 0x00000000, 0x00208246, 0x00000000, 0x00000000, 0x08000010, 0x00102022, 0x00000000, 0x00101346, |
| 0x00000000, 0x00208246, 0x00000000, 0x00000001, 0x05000036, 0x001020c2, 0x00000000, 0x00101ea6, |
| 0x00000000, 0x0100003e, |
| }; |
| static const DWORD rect_solid_ps_code[] = |
| { |
| /* float4 color; |
| * |
| * float4 main(float4 position : SV_POSITION) : SV_Target |
| * { |
| * return color; |
| * } */ |
| 0x43425844, 0x88eefcfd, 0x93d6fd47, 0x173c242f, 0x0106d07a, 0x00000001, 0x000000dc, 0x00000003, |
| 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, |
| 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000000f, 0x505f5653, 0x5449534f, 0x004e4f49, |
| 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003, |
| 0x00000000, 0x0000000f, 0x545f5653, 0x65677261, 0xabab0074, 0x52444853, 0x00000040, 0x00000040, |
| 0x00000010, 0x04000059, 0x00208e46, 0x00000000, 0x00000001, 0x03000065, 0x001020f2, 0x00000000, |
| 0x06000036, 0x001020f2, 0x00000000, 0x00208e46, 0x00000000, 0x00000000, 0x0100003e, |
| }; |
| static const DWORD rect_bitmap_ps_code[] = |
| { |
| #if 0 |
| float3x2 transform; |
| float opacity; |
| |
| SamplerState s; |
| Texture2D t; |
| |
| float4 main(float4 position : SV_POSITION) : SV_Target |
| { |
| float2 texcoord; |
| float4 ret; |
| |
| texcoord.x = position.x * transform._11 + position.y * transform._21 + transform._31; |
| texcoord.y = position.x * transform._12 + position.y * transform._22 + transform._32; |
| ret = t.Sample(s, texcoord); |
| ret.a *= opacity; |
| |
| return ret; |
| } |
| #endif |
| 0x43425844, 0x9a5f9280, 0xa5351c23, 0x15d6e760, 0xce35bcc3, 0x00000001, 0x000001d0, 0x00000003, |
| 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, |
| 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000030f, 0x505f5653, 0x5449534f, 0x004e4f49, |
| 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003, |
| 0x00000000, 0x0000000f, 0x545f5653, 0x65677261, 0xabab0074, 0x52444853, 0x00000134, 0x00000040, |
| 0x0000004d, 0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0300005a, 0x00106000, 0x00000000, |
| 0x04001858, 0x00107000, 0x00000000, 0x00005555, 0x04002064, 0x00101032, 0x00000000, 0x00000001, |
| 0x03000065, 0x001020f2, 0x00000000, 0x02000068, 0x00000001, 0x0800000f, 0x00100012, 0x00000000, |
| 0x00101046, 0x00000000, 0x00208046, 0x00000000, 0x00000000, 0x08000000, 0x00100012, 0x00000000, |
| 0x0010000a, 0x00000000, 0x0020802a, 0x00000000, 0x00000000, 0x0800000f, 0x00100042, 0x00000000, |
| 0x00101046, 0x00000000, 0x00208046, 0x00000000, 0x00000001, 0x08000000, 0x00100022, 0x00000000, |
| 0x0010002a, 0x00000000, 0x0020802a, 0x00000000, 0x00000001, 0x09000045, 0x001000f2, 0x00000000, |
| 0x00100046, 0x00000000, 0x00107e46, 0x00000000, 0x00106000, 0x00000000, 0x08000038, 0x00102082, |
| 0x00000000, 0x0010003a, 0x00000000, 0x0020803a, 0x00000000, 0x00000001, 0x05000036, 0x00102072, |
| 0x00000000, 0x00100246, 0x00000000, 0x0100003e, |
| }; |
| static const struct |
| { |
| float x, y; |
| } |
| quad[] = |
| { |
| {-1.0f, 1.0f}, |
| {-1.0f, -1.0f}, |
| { 1.0f, 1.0f}, |
| { 1.0f, -1.0f}, |
| }; |
| static const D2D1_MATRIX_3X2_F identity = |
| { |
| 1.0f, 0.0f, |
| 0.0f, 1.0f, |
| 0.0f, 0.0f, |
| }; |
| |
| FIXME("Ignoring render target properties.\n"); |
| |
| render_target->ID2D1RenderTarget_iface.lpVtbl = &d2d_d3d_render_target_vtbl; |
| render_target->IDWriteTextRenderer_iface.lpVtbl = &d2d_text_renderer_vtbl; |
| render_target->refcount = 1; |
| render_target->factory = factory; |
| ID2D1Factory_AddRef(render_target->factory); |
| |
| if (FAILED(hr = IDXGISurface_GetDevice(surface, &IID_ID3D10Device, (void **)&render_target->device))) |
| { |
| WARN("Failed to get device interface, hr %#x.\n", hr); |
| ID2D1Factory_Release(render_target->factory); |
| return hr; |
| } |
| |
| if (FAILED(hr = IDXGISurface_QueryInterface(surface, &IID_ID3D10Resource, (void **)&resource))) |
| { |
| WARN("Failed to get ID3D10Resource interface, hr %#x.\n", hr); |
| goto err; |
| } |
| |
| hr = ID3D10Device_CreateRenderTargetView(render_target->device, resource, NULL, &render_target->view); |
| ID3D10Resource_Release(resource); |
| if (FAILED(hr)) |
| { |
| WARN("Failed to create rendertarget view, hr %#x.\n", hr); |
| goto err; |
| } |
| |
| if (FAILED(hr = D3D10StateBlockMaskEnableAll(&state_mask))) |
| { |
| WARN("Failed to create stateblock mask, hr %#x.\n", hr); |
| goto err; |
| } |
| |
| if (FAILED(hr = D3D10CreateStateBlock(render_target->device, &state_mask, &render_target->stateblock))) |
| { |
| WARN("Failed to create stateblock, hr %#x.\n", hr); |
| goto err; |
| } |
| |
| if (FAILED(hr = ID3D10Device_CreateInputLayout(render_target->device, il_desc, |
| sizeof(il_desc) / sizeof(*il_desc), vs_code, sizeof(vs_code), |
| &render_target->il))) |
| { |
| WARN("Failed to create clear input layout, hr %#x.\n", hr); |
| goto err; |
| } |
| |
| buffer_desc.ByteWidth = sizeof(quad); |
| buffer_desc.Usage = D3D10_USAGE_DEFAULT; |
| buffer_desc.BindFlags = D3D10_BIND_VERTEX_BUFFER; |
| buffer_desc.CPUAccessFlags = 0; |
| buffer_desc.MiscFlags = 0; |
| |
| buffer_data.pSysMem = quad; |
| buffer_data.SysMemPitch = 0; |
| buffer_data.SysMemSlicePitch = 0; |
| |
| render_target->vb_stride = sizeof(*quad); |
| if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device, |
| &buffer_desc, &buffer_data, &render_target->vb))) |
| { |
| WARN("Failed to create clear vertex buffer, hr %#x.\n", hr); |
| goto err; |
| } |
| |
| if (FAILED(hr = ID3D10Device_CreateVertexShader(render_target->device, |
| vs_code, sizeof(vs_code), &render_target->vs))) |
| { |
| WARN("Failed to create clear vertex shader, hr %#x.\n", hr); |
| goto err; |
| } |
| |
| rs_desc.FillMode = D3D10_FILL_SOLID; |
| rs_desc.CullMode = D3D10_CULL_BACK; |
| rs_desc.FrontCounterClockwise = FALSE; |
| rs_desc.DepthBias = 0; |
| rs_desc.DepthBiasClamp = 0.0f; |
| rs_desc.SlopeScaledDepthBias = 0.0f; |
| rs_desc.DepthClipEnable = TRUE; |
| rs_desc.ScissorEnable = TRUE; |
| rs_desc.MultisampleEnable = FALSE; |
| rs_desc.AntialiasedLineEnable = FALSE; |
| if (FAILED(hr = ID3D10Device_CreateRasterizerState(render_target->device, &rs_desc, &render_target->rs))) |
| { |
| WARN("Failed to create clear rasterizer state, hr %#x.\n", hr); |
| goto err; |
| } |
| |
| memset(&blend_desc, 0, sizeof(blend_desc)); |
| blend_desc.BlendEnable[0] = TRUE; |
| blend_desc.SrcBlend = D3D10_BLEND_SRC_ALPHA; |
| blend_desc.DestBlend = D3D10_BLEND_INV_SRC_ALPHA; |
| blend_desc.BlendOp = D3D10_BLEND_OP_ADD; |
| blend_desc.SrcBlendAlpha = D3D10_BLEND_ZERO; |
| blend_desc.DestBlendAlpha = D3D10_BLEND_ONE; |
| blend_desc.BlendOpAlpha = D3D10_BLEND_OP_ADD; |
| blend_desc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL; |
| if (FAILED(hr = ID3D10Device_CreateBlendState(render_target->device, &blend_desc, &render_target->bs))) |
| { |
| WARN("Failed to create blend state, hr %#x.\n", hr); |
| goto err; |
| } |
| |
| if (FAILED(hr = ID3D10Device_CreatePixelShader(render_target->device, |
| rect_solid_ps_code, sizeof(rect_solid_ps_code), &render_target->rect_solid_ps))) |
| { |
| WARN("Failed to create pixel shader, hr %#x.\n", hr); |
| goto err; |
| } |
| |
| if (FAILED(hr = ID3D10Device_CreatePixelShader(render_target->device, |
| rect_bitmap_ps_code, sizeof(rect_bitmap_ps_code), &render_target->rect_bitmap_ps))) |
| { |
| WARN("Failed to create pixel shader, hr %#x.\n", hr); |
| goto err; |
| } |
| |
| if (FAILED(hr = IDXGISurface_GetDesc(surface, &surface_desc))) |
| { |
| WARN("Failed to get surface desc, hr %#x.\n", hr); |
| goto err; |
| } |
| |
| render_target->pixel_size.width = surface_desc.Width; |
| render_target->pixel_size.height = surface_desc.Height; |
| render_target->drawing_state.transform = identity; |
| |
| if (!d2d_clip_stack_init(&render_target->clip_stack)) |
| { |
| WARN("Failed to initialize clip stack.\n"); |
| hr = E_FAIL; |
| goto err; |
| } |
| |
| render_target->dpi_x = desc->dpiX; |
| render_target->dpi_y = desc->dpiY; |
| |
| if (render_target->dpi_x == 0.0f && render_target->dpi_y == 0.0f) |
| { |
| render_target->dpi_x = 96.0f; |
| render_target->dpi_y = 96.0f; |
| } |
| |
| return S_OK; |
| |
| err: |
| if (render_target->rect_bitmap_ps) |
| ID3D10PixelShader_Release(render_target->rect_bitmap_ps); |
| if (render_target->rect_solid_ps) |
| ID3D10PixelShader_Release(render_target->rect_solid_ps); |
| if (render_target->bs) |
| ID3D10BlendState_Release(render_target->bs); |
| if (render_target->rs) |
| ID3D10RasterizerState_Release(render_target->rs); |
| if (render_target->vs) |
| ID3D10VertexShader_Release(render_target->vs); |
| if (render_target->vb) |
| ID3D10Buffer_Release(render_target->vb); |
| if (render_target->il) |
| ID3D10InputLayout_Release(render_target->il); |
| if (render_target->stateblock) |
| render_target->stateblock->lpVtbl->Release(render_target->stateblock); |
| if (render_target->view) |
| ID3D10RenderTargetView_Release(render_target->view); |
| if (render_target->device) |
| ID3D10Device_Release(render_target->device); |
| ID2D1Factory_Release(render_target->factory); |
| return hr; |
| } |