2 * Copyright (C) 2008 Tony Wasserka
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "d3dx9_36_private.h"
24 ID3DXFont ID3DXFont_iface
;
27 IDirect3DDevice9
*device
;
35 IDirect3DTexture9
*texture
;
40 /* Returns the smallest power of 2 which is greater than or equal to num */
41 static UINT
make_pow2(UINT num
)
45 /* In the unlikely event somebody passes a large value, make sure we don't enter an infinite loop */
46 if (num
>= 0x80000000)
55 static inline struct d3dx_font
*impl_from_ID3DXFont(ID3DXFont
*iface
)
57 return CONTAINING_RECORD(iface
, struct d3dx_font
, ID3DXFont_iface
);
60 static HRESULT WINAPI
ID3DXFontImpl_QueryInterface(ID3DXFont
*iface
, REFIID riid
, void **out
)
62 TRACE("iface %p, riid %s, out %p.\n", iface
, debugstr_guid(riid
), out
);
64 if (IsEqualGUID(riid
, &IID_ID3DXFont
)
65 || IsEqualGUID(riid
, &IID_IUnknown
))
67 IUnknown_AddRef(iface
);
72 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid
));
78 static ULONG WINAPI
ID3DXFontImpl_AddRef(ID3DXFont
*iface
)
80 struct d3dx_font
*This
= impl_from_ID3DXFont(iface
);
81 ULONG ref
= InterlockedIncrement(&This
->ref
);
83 TRACE("%p increasing refcount to %u\n", iface
, ref
);
88 static ULONG WINAPI
ID3DXFontImpl_Release(ID3DXFont
*iface
)
90 struct d3dx_font
*This
= impl_from_ID3DXFont(iface
);
91 ULONG ref
= InterlockedDecrement(&This
->ref
);
93 TRACE("%p decreasing refcount to %u\n", iface
, ref
);
99 IDirect3DTexture9_Release(This
->texture
);
100 DeleteObject(This
->bitmap
);
102 DeleteObject(This
->hfont
);
104 IDirect3DDevice9_Release(This
->device
);
105 HeapFree(GetProcessHeap(), 0, This
);
110 static HRESULT WINAPI
ID3DXFontImpl_GetDevice(ID3DXFont
*iface
, IDirect3DDevice9
**device
)
112 struct d3dx_font
*This
= impl_from_ID3DXFont(iface
);
114 TRACE("iface %p, device %p\n", iface
, device
);
116 if( !device
) return D3DERR_INVALIDCALL
;
117 *device
= This
->device
;
118 IDirect3DDevice9_AddRef(This
->device
);
123 static HRESULT WINAPI
ID3DXFontImpl_GetDescA(ID3DXFont
*iface
, D3DXFONT_DESCA
*desc
)
125 struct d3dx_font
*This
= impl_from_ID3DXFont(iface
);
127 TRACE("iface %p, desc %p\n", iface
, desc
);
129 if( !desc
) return D3DERR_INVALIDCALL
;
130 memcpy(desc
, &This
->desc
, FIELD_OFFSET(D3DXFONT_DESCA
, FaceName
));
131 WideCharToMultiByte(CP_ACP
, 0, This
->desc
.FaceName
, -1, desc
->FaceName
, sizeof(desc
->FaceName
) / sizeof(CHAR
), NULL
, NULL
);
136 static HRESULT WINAPI
ID3DXFontImpl_GetDescW(ID3DXFont
*iface
, D3DXFONT_DESCW
*desc
)
138 struct d3dx_font
*This
= impl_from_ID3DXFont(iface
);
140 TRACE("iface %p, desc %p\n", iface
, desc
);
142 if( !desc
) return D3DERR_INVALIDCALL
;
148 static BOOL WINAPI
ID3DXFontImpl_GetTextMetricsA(ID3DXFont
*iface
, TEXTMETRICA
*metrics
)
150 struct d3dx_font
*This
= impl_from_ID3DXFont(iface
);
151 TRACE("iface %p, metrics %p\n", iface
, metrics
);
152 return GetTextMetricsA(This
->hdc
, metrics
);
155 static BOOL WINAPI
ID3DXFontImpl_GetTextMetricsW(ID3DXFont
*iface
, TEXTMETRICW
*metrics
)
157 struct d3dx_font
*This
= impl_from_ID3DXFont(iface
);
158 TRACE("iface %p, metrics %p\n", iface
, metrics
);
159 return GetTextMetricsW(This
->hdc
, metrics
);
162 static HDC WINAPI
ID3DXFontImpl_GetDC(ID3DXFont
*iface
)
164 struct d3dx_font
*This
= impl_from_ID3DXFont(iface
);
165 TRACE("iface %p\n", iface
);
169 static HRESULT WINAPI
ID3DXFontImpl_GetGlyphData(ID3DXFont
*iface
, UINT glyph
,
170 IDirect3DTexture9
**texture
, RECT
*blackbox
, POINT
*cellinc
)
172 FIXME("iface %p, glyph %#x, texture %p, blackbox %p, cellinc %p stub!\n",
173 iface
, glyph
, texture
, blackbox
, cellinc
);
177 static HRESULT WINAPI
ID3DXFontImpl_PreloadCharacters(ID3DXFont
*iface
, UINT first
, UINT last
)
179 FIXME("iface %p, first %u, last %u stub!\n", iface
, first
, last
);
183 static HRESULT WINAPI
ID3DXFontImpl_PreloadGlyphs(ID3DXFont
*iface
, UINT first
, UINT last
)
185 FIXME("iface %p, first %u, last %u stub!\n", iface
, first
, last
);
189 static HRESULT WINAPI
ID3DXFontImpl_PreloadTextA(ID3DXFont
*iface
, const char *string
, INT count
)
191 FIXME("iface %p, string %s, count %d stub!\n", iface
, debugstr_a(string
), count
);
195 static HRESULT WINAPI
ID3DXFontImpl_PreloadTextW(ID3DXFont
*iface
, const WCHAR
*string
, INT count
)
197 FIXME("iface %p, string %s, count %d stub!\n", iface
, debugstr_w(string
), count
);
201 static INT WINAPI
ID3DXFontImpl_DrawTextA(ID3DXFont
*iface
, ID3DXSprite
*sprite
,
202 const char *string
, INT count
, RECT
*rect
, DWORD format
, D3DCOLOR color
)
207 TRACE("iface %p, sprite %p, string %s, count %d, rect %s, format %#x, color 0x%08x\n",
208 iface
, sprite
, debugstr_a(string
), count
, wine_dbgstr_rect(rect
), format
, color
);
210 if (!string
|| count
== 0)
216 countW
= MultiByteToWideChar(CP_ACP
, 0, string
, count
, NULL
, 0);
217 stringW
= HeapAlloc(GetProcessHeap(), 0, countW
* sizeof(WCHAR
));
220 MultiByteToWideChar(CP_ACP
, 0, string
, count
, stringW
, countW
);
221 ret
= ID3DXFont_DrawTextW(iface
, sprite
, stringW
, countW
, rect
, format
, color
);
222 HeapFree(GetProcessHeap(), 0, stringW
);
228 static INT WINAPI
ID3DXFontImpl_DrawTextW(ID3DXFont
*iface
, ID3DXSprite
*sprite
,
229 const WCHAR
*string
, INT count
, RECT
*rect
, DWORD format
, D3DCOLOR color
)
231 struct d3dx_font
*This
= impl_from_ID3DXFont(iface
);
235 TRACE("iface %p, sprite %p, string %s, count %d, rect %s, format %#x, color 0x%08x\n",
236 iface
, sprite
, debugstr_w(string
), count
, wine_dbgstr_rect(rect
), format
, color
);
238 if (!string
|| count
== 0)
242 count
= lstrlenW(string
);
244 /* Strip terminating NULL characters */
245 while (count
> 0 && !string
[count
-1])
251 height
= DrawTextW(This
->hdc
, string
, count
, &calc_rect
, format
| DT_CALCRECT
);
253 if (format
& DT_CALCRECT
)
260 if (format
& DT_CENTER
)
262 UINT new_width
= calc_rect
.right
- calc_rect
.left
;
263 calc_rect
.left
= (rect
->right
+ rect
->left
- new_width
) / 2;
264 calc_rect
.right
= calc_rect
.left
+ new_width
;
267 if (height
&& (calc_rect
.left
< calc_rect
.right
))
269 D3DLOCKED_RECT locked_rect
;
270 D3DXVECTOR3 position
;
271 UINT text_width
, text_height
;
273 ID3DXSprite
*target
= sprite
;
277 /* Get rect position and dimensions */
278 position
.x
= calc_rect
.left
;
279 position
.y
= calc_rect
.top
;
281 text_width
= calc_rect
.right
- calc_rect
.left
;
282 text_height
= calc_rect
.bottom
- calc_rect
.top
;
285 text_rect
.right
= text_width
;
286 text_rect
.bottom
= text_height
;
288 /* We need to flush as it seems all draws in the begin/end sequence use only the latest updated texture */
290 ID3DXSprite_Flush(sprite
);
292 /* Extend texture and DIB section to contain text */
293 if ((text_width
> This
->tex_width
) || (text_height
> This
->tex_height
))
295 BITMAPINFOHEADER header
;
297 if (text_width
> This
->tex_width
)
298 This
->tex_width
= make_pow2(text_width
);
299 if (text_height
> This
->tex_height
)
300 This
->tex_height
= make_pow2(text_height
);
304 IDirect3DTexture9_Release(This
->texture
);
305 DeleteObject(This
->bitmap
);
308 hr
= D3DXCreateTexture(This
->device
, This
->tex_width
, This
->tex_height
, 1, 0,
309 D3DFMT_A8R8G8B8
, D3DPOOL_DEFAULT
, &This
->texture
);
312 This
->texture
= NULL
;
316 header
.biSize
= sizeof(header
);
317 header
.biWidth
= This
->tex_width
;
318 header
.biHeight
= -This
->tex_height
;
320 header
.biBitCount
= 32;
321 header
.biCompression
= BI_RGB
;
322 header
.biSizeImage
= sizeof(DWORD
) * This
->tex_width
* This
->tex_height
;
323 header
.biXPelsPerMeter
= 0;
324 header
.biYPelsPerMeter
= 0;
325 header
.biClrUsed
= 0;
326 header
.biClrImportant
= 0;
328 This
->bitmap
= CreateDIBSection(This
->hdc
, (const BITMAPINFO
*)&header
,
329 DIB_RGB_COLORS
, (void**)&This
->bits
, NULL
, 0);
332 IDirect3DTexture9_Release(This
->texture
);
333 This
->texture
= NULL
;
337 SelectObject(This
->hdc
, This
->bitmap
);
340 if (FAILED(IDirect3DTexture9_LockRect(This
->texture
, 0, &locked_rect
, &text_rect
, D3DLOCK_DISCARD
)))
344 for (i
= 0; i
< text_height
; i
++)
345 memset(This
->bits
+ i
* This
->tex_width
* sizeof(DWORD
), 0,
346 text_width
* sizeof(DWORD
));
348 DrawTextW(This
->hdc
, string
, count
, &text_rect
, format
);
350 /* All RGB components are equal so take one as alpha and set RGB
351 * color to white, so it can be modulated with color parameter */
352 for (i
= 0; i
< text_height
; i
++)
354 DWORD
*src
= (DWORD
*)This
->bits
+ i
* This
->tex_width
;
355 DWORD
*dst
= (DWORD
*)((BYTE
*)locked_rect
.pBits
+ i
* locked_rect
.Pitch
);
356 for (j
= 0; j
< text_width
; j
++)
358 *dst
++ = (*src
++ << 24) | 0xFFFFFF;
362 IDirect3DTexture9_UnlockRect(This
->texture
, 0);
366 hr
= D3DXCreateSprite(This
->device
, &target
);
369 ID3DXSprite_Begin(target
, 0);
372 hr
= target
->lpVtbl
->Draw(target
, This
->texture
, &text_rect
, NULL
, &position
, color
);
376 ID3DXSprite_End(target
);
377 ID3DXSprite_Release(target
);
387 static HRESULT WINAPI
ID3DXFontImpl_OnLostDevice(ID3DXFont
*iface
)
389 FIXME("iface %p stub!\n", iface
);
393 static HRESULT WINAPI
ID3DXFontImpl_OnResetDevice(ID3DXFont
*iface
)
395 FIXME("iface %p stub\n", iface
);
399 static const ID3DXFontVtbl D3DXFont_Vtbl
=
401 /*** IUnknown methods ***/
402 ID3DXFontImpl_QueryInterface
,
403 ID3DXFontImpl_AddRef
,
404 ID3DXFontImpl_Release
,
405 /*** ID3DXFont methods ***/
406 ID3DXFontImpl_GetDevice
,
407 ID3DXFontImpl_GetDescA
,
408 ID3DXFontImpl_GetDescW
,
409 ID3DXFontImpl_GetTextMetricsA
,
410 ID3DXFontImpl_GetTextMetricsW
,
412 ID3DXFontImpl_GetGlyphData
,
413 ID3DXFontImpl_PreloadCharacters
,
414 ID3DXFontImpl_PreloadGlyphs
,
415 ID3DXFontImpl_PreloadTextA
,
416 ID3DXFontImpl_PreloadTextW
,
417 ID3DXFontImpl_DrawTextA
,
418 ID3DXFontImpl_DrawTextW
,
419 ID3DXFontImpl_OnLostDevice
,
420 ID3DXFontImpl_OnResetDevice
423 HRESULT WINAPI
D3DXCreateFontA(struct IDirect3DDevice9
*device
, INT height
, UINT width
,
424 UINT weight
, UINT miplevels
, BOOL italic
, DWORD charset
, DWORD precision
, DWORD quality
,
425 DWORD pitchandfamily
, const char *facename
, struct ID3DXFont
**font
)
429 if( !device
|| !font
) return D3DERR_INVALIDCALL
;
434 desc
.MipLevels
=miplevels
;
436 desc
.CharSet
=charset
;
437 desc
.OutputPrecision
=precision
;
438 desc
.Quality
=quality
;
439 desc
.PitchAndFamily
=pitchandfamily
;
440 if(facename
!= NULL
) lstrcpyA(desc
.FaceName
, facename
);
441 else desc
.FaceName
[0] = '\0';
443 return D3DXCreateFontIndirectA(device
, &desc
, font
);
446 HRESULT WINAPI
D3DXCreateFontW(IDirect3DDevice9
*device
, INT height
, UINT width
, UINT weight
, UINT miplevels
, BOOL italic
, DWORD charset
,
447 DWORD precision
, DWORD quality
, DWORD pitchandfamily
, const WCHAR
*facename
, ID3DXFont
**font
)
451 if( !device
|| !font
) return D3DERR_INVALIDCALL
;
456 desc
.MipLevels
=miplevels
;
458 desc
.CharSet
=charset
;
459 desc
.OutputPrecision
=precision
;
460 desc
.Quality
=quality
;
461 desc
.PitchAndFamily
=pitchandfamily
;
462 if(facename
!= NULL
) strcpyW(desc
.FaceName
, facename
);
463 else desc
.FaceName
[0] = '\0';
465 return D3DXCreateFontIndirectW(device
, &desc
, font
);
468 /***********************************************************************
469 * D3DXCreateFontIndirectA (D3DX9_36.@)
471 HRESULT WINAPI
D3DXCreateFontIndirectA(IDirect3DDevice9
*device
, const D3DXFONT_DESCA
*desc
, ID3DXFont
**font
)
473 D3DXFONT_DESCW widedesc
;
475 if( !device
|| !desc
|| !font
) return D3DERR_INVALIDCALL
;
477 /* Copy everything but the last structure member. This requires the
478 two D3DXFONT_DESC structures to be equal until the FaceName member */
479 memcpy(&widedesc
, desc
, FIELD_OFFSET(D3DXFONT_DESCA
, FaceName
));
480 MultiByteToWideChar(CP_ACP
, 0, desc
->FaceName
, -1,
481 widedesc
.FaceName
, sizeof(widedesc
.FaceName
)/sizeof(WCHAR
));
482 return D3DXCreateFontIndirectW(device
, &widedesc
, font
);
485 /***********************************************************************
486 * D3DXCreateFontIndirectW (D3DX9_36.@)
488 HRESULT WINAPI
D3DXCreateFontIndirectW(IDirect3DDevice9
*device
, const D3DXFONT_DESCW
*desc
, ID3DXFont
**font
)
490 D3DDEVICE_CREATION_PARAMETERS cpars
;
492 struct d3dx_font
*object
;
496 TRACE("(%p, %p, %p)\n", device
, desc
, font
);
498 if (!device
|| !desc
|| !font
) return D3DERR_INVALIDCALL
;
500 TRACE("desc: %d %d %d %d %d %d %d %d %d %s\n", desc
->Height
, desc
->Width
, desc
->Weight
, desc
->MipLevels
, desc
->Italic
,
501 desc
->CharSet
, desc
->OutputPrecision
, desc
->Quality
, desc
->PitchAndFamily
, debugstr_w(desc
->FaceName
));
503 /* The device MUST support D3DFMT_A8R8G8B8 */
504 IDirect3DDevice9_GetDirect3D(device
, &d3d
);
505 IDirect3DDevice9_GetCreationParameters(device
, &cpars
);
506 IDirect3DDevice9_GetDisplayMode(device
, 0, &mode
);
507 hr
= IDirect3D9_CheckDeviceFormat(d3d
, cpars
.AdapterOrdinal
, cpars
.DeviceType
, mode
.Format
, 0, D3DRTYPE_TEXTURE
, D3DFMT_A8R8G8B8
);
510 IDirect3D9_Release(d3d
);
511 return D3DXERR_INVALIDDATA
;
513 IDirect3D9_Release(d3d
);
515 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(struct d3dx_font
));
519 return E_OUTOFMEMORY
;
521 object
->ID3DXFont_iface
.lpVtbl
= &D3DXFont_Vtbl
;
523 object
->device
= device
;
524 object
->desc
= *desc
;
526 object
->hdc
= CreateCompatibleDC(NULL
);
529 HeapFree(GetProcessHeap(), 0, object
);
530 return D3DXERR_INVALIDDATA
;
533 object
->hfont
= CreateFontW(desc
->Height
, desc
->Width
, 0, 0, desc
->Weight
, desc
->Italic
, FALSE
, FALSE
, desc
->CharSet
,
534 desc
->OutputPrecision
, CLIP_DEFAULT_PRECIS
, desc
->Quality
, desc
->PitchAndFamily
, desc
->FaceName
);
537 DeleteDC(object
->hdc
);
538 HeapFree(GetProcessHeap(), 0, object
);
539 return D3DXERR_INVALIDDATA
;
541 SelectObject(object
->hdc
, object
->hfont
);
542 SetTextColor(object
->hdc
, 0x00ffffff);
543 SetBkColor(object
->hdc
, 0x00000000);
545 IDirect3DDevice9_AddRef(device
);
546 *font
= &object
->ID3DXFont_iface
;