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
21 #include "d3dx9_private.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(d3dx
);
32 IDirect3DTexture9
*texture
;
34 struct wine_rb_entry entry
;
39 ID3DXFont ID3DXFont_iface
;
42 IDirect3DDevice9
*device
;
49 struct wine_rb_tree glyph_tree
;
51 IDirect3DTexture9
**textures
;
52 unsigned int texture_count
, texture_pos
;
54 unsigned int texture_size
, glyph_size
, glyphs_per_texture
;
57 static int glyph_rb_compare(const void *key
, const struct wine_rb_entry
*entry
)
59 struct d3dx_glyph
*glyph
= WINE_RB_ENTRY_VALUE(entry
, struct d3dx_glyph
, entry
);
60 unsigned int id
= (UINT_PTR
)key
;
62 return id
- glyph
->id
;
65 static void glyph_rb_free(struct wine_rb_entry
*entry
, void *context
)
67 struct d3dx_glyph
*glyph
= WINE_RB_ENTRY_VALUE(entry
, struct d3dx_glyph
, entry
);
72 static inline struct d3dx_font
*impl_from_ID3DXFont(ID3DXFont
*iface
)
74 return CONTAINING_RECORD(iface
, struct d3dx_font
, ID3DXFont_iface
);
77 static HRESULT WINAPI
ID3DXFontImpl_QueryInterface(ID3DXFont
*iface
, REFIID riid
, void **out
)
79 TRACE("iface %p, riid %s, out %p.\n", iface
, debugstr_guid(riid
), out
);
81 if (IsEqualGUID(riid
, &IID_ID3DXFont
)
82 || IsEqualGUID(riid
, &IID_IUnknown
))
84 IUnknown_AddRef(iface
);
89 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid
));
95 static ULONG WINAPI
ID3DXFontImpl_AddRef(ID3DXFont
*iface
)
97 struct d3dx_font
*font
= impl_from_ID3DXFont(iface
);
98 ULONG ref
= InterlockedIncrement(&font
->ref
);
100 TRACE("%p increasing refcount to %u\n", iface
, ref
);
104 static ULONG WINAPI
ID3DXFontImpl_Release(ID3DXFont
*iface
)
106 struct d3dx_font
*font
= impl_from_ID3DXFont(iface
);
107 ULONG ref
= InterlockedDecrement(&font
->ref
);
110 TRACE("%p decreasing refcount to %u\n", iface
, ref
);
114 for (i
= 0; i
< font
->texture_count
; ++i
)
115 IDirect3DTexture9_Release(font
->textures
[i
]);
117 heap_free(font
->textures
);
119 wine_rb_destroy(&font
->glyph_tree
, glyph_rb_free
, NULL
);
121 DeleteObject(font
->hfont
);
123 IDirect3DDevice9_Release(font
->device
);
129 static HRESULT WINAPI
ID3DXFontImpl_GetDevice(ID3DXFont
*iface
, IDirect3DDevice9
**device
)
131 struct d3dx_font
*font
= impl_from_ID3DXFont(iface
);
133 TRACE("iface %p, device %p\n", iface
, device
);
135 if( !device
) return D3DERR_INVALIDCALL
;
136 *device
= font
->device
;
137 IDirect3DDevice9_AddRef(font
->device
);
142 static HRESULT WINAPI
ID3DXFontImpl_GetDescA(ID3DXFont
*iface
, D3DXFONT_DESCA
*desc
)
144 struct d3dx_font
*font
= impl_from_ID3DXFont(iface
);
146 TRACE("iface %p, desc %p\n", iface
, desc
);
148 if( !desc
) return D3DERR_INVALIDCALL
;
149 memcpy(desc
, &font
->desc
, FIELD_OFFSET(D3DXFONT_DESCA
, FaceName
));
150 WideCharToMultiByte(CP_ACP
, 0, font
->desc
.FaceName
, -1, desc
->FaceName
, ARRAY_SIZE(desc
->FaceName
), NULL
, NULL
);
155 static HRESULT WINAPI
ID3DXFontImpl_GetDescW(ID3DXFont
*iface
, D3DXFONT_DESCW
*desc
)
157 struct d3dx_font
*font
= impl_from_ID3DXFont(iface
);
159 TRACE("iface %p, desc %p\n", iface
, desc
);
161 if( !desc
) return D3DERR_INVALIDCALL
;
167 static BOOL WINAPI
ID3DXFontImpl_GetTextMetricsA(ID3DXFont
*iface
, TEXTMETRICA
*metrics
)
169 struct d3dx_font
*font
= impl_from_ID3DXFont(iface
);
170 TRACE("iface %p, metrics %p\n", iface
, metrics
);
171 return GetTextMetricsA(font
->hdc
, metrics
);
174 static BOOL WINAPI
ID3DXFontImpl_GetTextMetricsW(ID3DXFont
*iface
, TEXTMETRICW
*metrics
)
176 struct d3dx_font
*font
= impl_from_ID3DXFont(iface
);
177 TRACE("iface %p, metrics %p\n", iface
, metrics
);
178 return GetTextMetricsW(font
->hdc
, metrics
);
181 static HDC WINAPI
ID3DXFontImpl_GetDC(ID3DXFont
*iface
)
183 struct d3dx_font
*font
= impl_from_ID3DXFont(iface
);
184 TRACE("iface %p\n", iface
);
188 static HRESULT WINAPI
ID3DXFontImpl_GetGlyphData(ID3DXFont
*iface
, UINT glyph
,
189 IDirect3DTexture9
**texture
, RECT
*black_box
, POINT
*cell_inc
)
191 struct d3dx_font
*font
= impl_from_ID3DXFont(iface
);
192 struct wine_rb_entry
*entry
;
195 TRACE("iface %p, glyph %#x, texture %p, black_box %p, cell_inc %p.\n",
196 iface
, glyph
, texture
, black_box
, cell_inc
);
198 hr
= ID3DXFont_PreloadGlyphs(iface
, glyph
, glyph
);
202 entry
= wine_rb_get(&font
->glyph_tree
, ULongToPtr(glyph
));
205 struct d3dx_glyph
*current_glyph
= WINE_RB_ENTRY_VALUE(entry
, struct d3dx_glyph
, entry
);
208 *cell_inc
= current_glyph
->cell_inc
;
210 *black_box
= current_glyph
->black_box
;
213 *texture
= current_glyph
->texture
;
215 IDirect3DTexture9_AddRef(current_glyph
->texture
);
220 return D3DXERR_INVALIDDATA
;
223 static HRESULT WINAPI
ID3DXFontImpl_PreloadCharacters(ID3DXFont
*iface
, UINT first
, UINT last
)
225 struct d3dx_font
*font
= impl_from_ID3DXFont(iface
);
226 unsigned int i
, count
, start
, end
;
230 TRACE("iface %p, first %u, last %u.\n", iface
, first
, last
);
235 count
= last
- first
+ 1;
236 indices
= heap_alloc(count
* sizeof(*indices
));
238 return E_OUTOFMEMORY
;
240 chars
= heap_alloc(count
* sizeof(*chars
));
244 return E_OUTOFMEMORY
;
247 for (i
= 0; i
< count
; ++i
)
248 chars
[i
] = first
+ i
;
250 GetGlyphIndicesW(font
->hdc
, chars
, count
, indices
, 0);
252 start
= end
= indices
[0];
253 for (i
= 1; i
< count
; ++i
)
255 if (indices
[i
] == end
+ 1)
260 ID3DXFont_PreloadGlyphs(iface
, start
, end
);
261 start
= end
= indices
[i
];
263 ID3DXFont_PreloadGlyphs(iface
, start
, end
);
271 static uint32_t morton_decode(uint32_t x
)
274 x
= (x
^ (x
>> 1)) & 0x33333333;
275 x
= (x
^ (x
>> 2)) & 0x0f0f0f0f;
276 x
= (x
^ (x
>> 4)) & 0x00ff00ff;
277 x
= (x
^ (x
>> 8)) & 0x0000ffff;
281 /* The glyphs are stored in a grid. Cell sizes vary between different font
284 * The grid is filled in Morton order:
285 * 1 2 5 6 17 18 21 22
286 * 3 4 7 8 19 20 23 24
287 * 9 10 13 14 25 26 29 30
288 * 11 12 15 16 27 28 31 32
292 * i.e. we try to fill one small square, then three equal-sized squares so
293 * that we get one big square, etc.
295 * The glyphs are positioned around their baseline, which is located at y
296 * position glyph_size * i + tmAscent. Concerning the x position, the glyphs
297 * are centered around glyph_size * (i + 0.5). */
298 static HRESULT WINAPI
ID3DXFontImpl_PreloadGlyphs(ID3DXFont
*iface
, UINT first
, UINT last
)
300 static const MAT2 mat
= { {0,1}, {0,0}, {0,0}, {0,1} };
301 struct d3dx_font
*font
= impl_from_ID3DXFont(iface
);
302 IDirect3DTexture9
*current_texture
= NULL
;
303 unsigned int size
, stride
, glyph
, x
, y
;
304 struct d3dx_glyph
*current_glyph
;
305 D3DLOCKED_RECT lockrect
;
306 GLYPHMETRICS metrics
;
312 TRACE("iface %p, first %u, last %u.\n", iface
, first
, last
);
317 if (font
->texture_count
)
318 current_texture
= font
->textures
[font
->texture_count
- 1];
320 for (glyph
= first
; glyph
<= last
; ++glyph
)
322 if (wine_rb_get(&font
->glyph_tree
, ULongToPtr(glyph
)))
325 current_glyph
= heap_alloc(sizeof(*current_glyph
));
329 IDirect3DTexture9_UnlockRect(current_texture
, 0);
330 return E_OUTOFMEMORY
;
333 current_glyph
->id
= glyph
;
334 current_glyph
->texture
= NULL
;
335 wine_rb_put(&font
->glyph_tree
, ULongToPtr(current_glyph
->id
), ¤t_glyph
->entry
);
337 size
= GetGlyphOutlineW(font
->hdc
, glyph
, GGO_GLYPH_INDEX
| GGO_GRAY8_BITMAP
, &metrics
, 0, NULL
, &mat
);
338 if (size
== GDI_ERROR
)
340 WARN("GetGlyphOutlineW failed.\n");
346 buffer
= heap_alloc(size
);
350 IDirect3DTexture9_UnlockRect(current_texture
, 0);
351 return E_OUTOFMEMORY
;
354 GetGlyphOutlineW(font
->hdc
, glyph
, GGO_GLYPH_INDEX
| GGO_GRAY8_BITMAP
, &metrics
, size
, buffer
, &mat
);
356 if (font
->texture_pos
== font
->glyphs_per_texture
)
358 unsigned int new_texture_count
= font
->texture_count
+ 1;
359 IDirect3DTexture9
**new_textures
;
362 IDirect3DTexture9_UnlockRect(current_texture
, 0);
364 new_textures
= heap_realloc(font
->textures
, new_texture_count
* sizeof(*new_textures
));
368 return E_OUTOFMEMORY
;
370 font
->textures
= new_textures
;
372 if (FAILED(hr
= IDirect3DDevice9_CreateTexture(font
->device
, font
->texture_size
,
373 font
->texture_size
, 0, 0, D3DFMT_A8R8G8B8
, D3DPOOL_MANAGED
,
374 &font
->textures
[font
->texture_count
], NULL
)))
380 current_texture
= font
->textures
[font
->texture_count
++];
381 font
->texture_pos
= 0;
386 if (FAILED(hr
= IDirect3DTexture9_LockRect(current_texture
, 0, &lockrect
, NULL
, 0)))
394 x
= morton_decode(font
->texture_pos
) * font
->glyph_size
;
395 y
= morton_decode(font
->texture_pos
>> 1) * font
->glyph_size
;
397 current_glyph
->black_box
.left
= x
- metrics
.gmptGlyphOrigin
.x
+ font
->glyph_size
/ 2
398 - metrics
.gmBlackBoxX
/ 2;
399 current_glyph
->black_box
.top
= y
- metrics
.gmptGlyphOrigin
.y
+ font
->metrics
.tmAscent
+ 1;
400 current_glyph
->black_box
.right
= current_glyph
->black_box
.left
+ metrics
.gmBlackBoxX
;
401 current_glyph
->black_box
.bottom
= current_glyph
->black_box
.top
+ metrics
.gmBlackBoxY
;
402 current_glyph
->cell_inc
.x
= metrics
.gmptGlyphOrigin
.x
- 1;
403 current_glyph
->cell_inc
.y
= font
->metrics
.tmAscent
- metrics
.gmptGlyphOrigin
.y
- 1;
404 current_glyph
->texture
= current_texture
;
406 pixel_data
= lockrect
.pBits
;
407 stride
= (metrics
.gmBlackBoxX
+ 3) & ~3;
408 for (y
= 0; y
< metrics
.gmBlackBoxY
; ++y
)
409 for (x
= 0; x
< metrics
.gmBlackBoxX
; ++x
)
410 pixel_data
[(current_glyph
->black_box
.top
+ y
) * lockrect
.Pitch
/ 4
411 + current_glyph
->black_box
.left
+ x
] =
412 (buffer
[y
* stride
+ x
] * 255 / 64 << 24) | 0x00ffffffu
;
418 IDirect3DTexture9_UnlockRect(current_texture
, 0);
423 static HRESULT WINAPI
ID3DXFontImpl_PreloadTextA(ID3DXFont
*iface
, const char *string
, INT count
)
429 TRACE("iface %p, string %s, count %d.\n", iface
, debugstr_an(string
, count
), count
);
431 if (!string
&& !count
)
435 return D3DERR_INVALIDCALL
;
437 countW
= MultiByteToWideChar(CP_ACP
, 0, string
, count
< 0 ? -1 : count
, NULL
, 0);
439 wstr
= heap_alloc(countW
* sizeof(*wstr
));
441 return E_OUTOFMEMORY
;
443 MultiByteToWideChar(CP_ACP
, 0, string
, count
< 0 ? -1 : count
, wstr
, countW
);
445 hr
= ID3DXFont_PreloadTextW(iface
, wstr
, count
< 0 ? countW
- 1 : countW
);
452 static HRESULT WINAPI
ID3DXFontImpl_PreloadTextW(ID3DXFont
*iface
, const WCHAR
*string
, INT count
)
454 struct d3dx_font
*font
= impl_from_ID3DXFont(iface
);
458 TRACE("iface %p, string %s, count %d.\n", iface
, debugstr_wn(string
, count
), count
);
460 if (!string
&& !count
)
464 return D3DERR_INVALIDCALL
;
467 count
= lstrlenW(string
);
469 indices
= heap_alloc(count
* sizeof(*indices
));
471 return E_OUTOFMEMORY
;
473 GetGlyphIndicesW(font
->hdc
, string
, count
, indices
, 0);
475 for (i
= 0; i
< count
; ++i
)
476 ID3DXFont_PreloadGlyphs(iface
, indices
[i
], indices
[i
]);
483 static INT WINAPI
ID3DXFontImpl_DrawTextA(ID3DXFont
*iface
, ID3DXSprite
*sprite
,
484 const char *string
, INT count
, RECT
*rect
, DWORD format
, D3DCOLOR color
)
489 TRACE("iface %p, sprite %p, string %s, count %d, rect %s, format %#x, color 0x%08x.\n",
490 iface
, sprite
, debugstr_an(string
, count
), count
, wine_dbgstr_rect(rect
), format
, color
);
492 if (!string
|| !count
)
495 countW
= MultiByteToWideChar(CP_ACP
, 0, string
, count
< 0 ? -1 : count
, NULL
, 0);
500 wstr
= heap_alloc_zero(countW
* sizeof(*wstr
));
504 MultiByteToWideChar(CP_ACP
, 0, string
, count
< 0 ? -1 : count
, wstr
, countW
);
506 ret
= ID3DXFont_DrawTextW(iface
, sprite
, wstr
, count
< 0 ? countW
- 1 : countW
,
507 rect
, format
, color
);
514 static void word_break(HDC hdc
, const WCHAR
*str
, unsigned int *str_len
,
515 unsigned int chars_fit
, unsigned int *chars_used
, SIZE
*size
)
523 sla
= heap_alloc(*str_len
* sizeof(*sla
));
527 memset(&sa
, 0, sizeof(sa
));
528 sa
.eScript
= SCRIPT_UNDEFINED
;
530 ScriptBreak(str
, *str_len
, &sa
, sla
);
532 /* Work back from the last character that did fit to a place where we can break */
534 while (i
> 0 && !sla
[i
].fSoftBreak
) /* chars_fit < *str_len so this is valid */
537 /* If the there is no word that fits put in all characters that do fit */
538 if (!sla
[i
].fSoftBreak
)
542 if (sla
[i
].fWhiteSpace
)
545 /* Remove extra spaces */
546 while (i
> 0 && sla
[i
-1].fWhiteSpace
)
550 /* Remeasure the string */
551 GetTextExtentExPointW(hdc
, str
, *str_len
, 0, NULL
, NULL
, size
);
555 static const WCHAR
*read_line(HDC hdc
, const WCHAR
*str
, unsigned int *count
,
556 WCHAR
*dest
, unsigned int *dest_len
, int width
, DWORD format
, SIZE
*size
)
558 unsigned int orig_count
= *count
;
563 while (*count
&& (str
[i
] != '\n' || (format
& DT_SINGLELINE
)))
566 if (str
[i
] != '\r' && str
[i
] != '\n')
567 dest
[(*dest_len
)++] = str
[i
];
572 GetTextExtentExPointW(hdc
, dest
, *dest_len
, width
, &num_fit
, NULL
, size
);
574 if (num_fit
< *dest_len
&& (format
& DT_WORDBREAK
))
576 unsigned int chars_used
;
578 word_break(hdc
, dest
, dest_len
, num_fit
, &chars_used
, size
);
579 *count
= orig_count
- chars_used
;
583 if (*count
&& str
[i
] == '\n')
594 static int compute_rect(struct d3dx_font
*font
, const WCHAR
*string
, unsigned int count
,
595 WCHAR
*line
, RECT
*rect
, DWORD format
)
597 int y
, lh
, width
, top
= rect
->top
;
602 lh
= font
->metrics
.tmHeight
;
603 width
= rect
->right
- rect
->left
;
607 unsigned int line_len
;
609 string
= read_line(font
->hdc
, string
, &count
, line
, &line_len
, width
, format
, &size
);
611 if (size
.cx
> max_width
)
615 if (!(format
& DT_NOCLIP
) && (y
> rect
->bottom
))
619 if (format
& DT_CENTER
)
621 rect
->left
+= (rect
->right
- rect
->left
- max_width
) / 2;
622 rect
->right
= rect
->left
+ max_width
;
624 else if (format
& DT_RIGHT
)
626 rect
->left
= rect
->right
- max_width
;
630 rect
->right
= rect
->left
+ max_width
;
633 if (format
& DT_VCENTER
)
635 rect
->top
+= (rect
->bottom
- y
) / 2;
636 rect
->bottom
= rect
->top
+ y
- top
;
638 else if (format
& DT_BOTTOM
)
640 rect
->top
+= rect
->bottom
- y
;
647 return rect
->bottom
- top
;
650 static INT WINAPI
ID3DXFontImpl_DrawTextW(ID3DXFont
*iface
, ID3DXSprite
*sprite
,
651 const WCHAR
*string
, INT in_count
, RECT
*rect
, DWORD format
, D3DCOLOR color
)
653 struct d3dx_font
*font
= impl_from_ID3DXFont(iface
);
654 int lh
, x
, y
, width
, top
, ret
= 0;
655 ID3DXSprite
*target
= sprite
;
661 TRACE("iface %p, sprite %p, string %s, in_count %d, rect %s, format %#x, color 0x%08x.\n",
662 iface
, sprite
, debugstr_wn(string
, in_count
), in_count
, wine_dbgstr_rect(rect
), format
, color
);
667 count
= in_count
< 0 ? lstrlenW(string
) : in_count
;
672 if (format
& DT_CALCRECT
)
675 if (format
& DT_SINGLELINE
)
676 format
&= ~DT_WORDBREAK
;
678 line
= heap_alloc(count
* sizeof(*line
));
682 if (!rect
|| format
& (DT_CALCRECT
| DT_VCENTER
| DT_BOTTOM
))
689 else if (!(format
& DT_CALCRECT
))
697 ret
= compute_rect(font
, string
, count
, line
, rect
, format
);
699 if (format
& DT_CALCRECT
)
708 lh
= font
->metrics
.tmHeight
;
709 width
= rect
->right
- rect
->left
;
713 D3DXCreateSprite(font
->device
, &target
);
714 ID3DXSprite_Begin(target
, 0);
719 unsigned int line_len
, i
;
720 GCP_RESULTSW results
;
722 string
= read_line(font
->hdc
, string
, &count
, line
, &line_len
, width
, format
, &size
);
724 if (format
& DT_CENTER
)
725 x
= (rect
->left
+ rect
->right
- size
.cx
) / 2;
726 else if (format
& DT_RIGHT
)
727 x
= rect
->right
- size
.cx
;
731 memset(&results
, 0, sizeof(results
));
732 results
.nGlyphs
= line_len
;
734 results
.lpCaretPos
= heap_alloc(line_len
* sizeof(*results
.lpCaretPos
));
735 if (!results
.lpCaretPos
)
738 results
.lpGlyphs
= heap_alloc(line_len
* sizeof(*results
.lpGlyphs
));
739 if (!results
.lpGlyphs
)
741 heap_free(results
.lpCaretPos
);
745 GetCharacterPlacementW(font
->hdc
, line
, line_len
, 0, &results
, 0);
747 for (i
= 0; i
< results
.nGlyphs
; ++i
)
749 IDirect3DTexture9
*texture
;
754 ID3DXFont_GetGlyphData(iface
, results
.lpGlyphs
[i
], &texture
, &black_box
, &cell_inc
);
759 pos
.x
= cell_inc
.x
+ x
+ results
.lpCaretPos
[i
];
760 pos
.y
= cell_inc
.y
+ y
;
763 if (!(format
& DT_NOCLIP
))
765 if (pos
.x
> rect
->right
)
767 IDirect3DTexture9_Release(texture
);
771 if (pos
.x
+ black_box
.right
- black_box
.left
> rect
->right
)
772 black_box
.right
= black_box
.left
+ rect
->right
- pos
.x
;
774 if (pos
.y
+ black_box
.bottom
- black_box
.top
> rect
->bottom
)
775 black_box
.bottom
= black_box
.top
+ rect
->bottom
- pos
.y
;
778 ID3DXSprite_Draw(target
, texture
, &black_box
, NULL
, &pos
, color
);
779 IDirect3DTexture9_Release(texture
);
782 heap_free(results
.lpCaretPos
);
783 heap_free(results
.lpGlyphs
);
786 if (!(DT_NOCLIP
& format
) && (y
> rect
->bottom
))
793 if (target
!= sprite
)
795 ID3DXSprite_End(target
);
796 ID3DXSprite_Release(target
);
804 static HRESULT WINAPI
ID3DXFontImpl_OnLostDevice(ID3DXFont
*iface
)
806 FIXME("iface %p stub!\n", iface
);
810 static HRESULT WINAPI
ID3DXFontImpl_OnResetDevice(ID3DXFont
*iface
)
812 FIXME("iface %p stub\n", iface
);
816 static const ID3DXFontVtbl D3DXFont_Vtbl
=
818 /*** IUnknown methods ***/
819 ID3DXFontImpl_QueryInterface
,
820 ID3DXFontImpl_AddRef
,
821 ID3DXFontImpl_Release
,
822 /*** ID3DXFont methods ***/
823 ID3DXFontImpl_GetDevice
,
824 ID3DXFontImpl_GetDescA
,
825 ID3DXFontImpl_GetDescW
,
826 ID3DXFontImpl_GetTextMetricsA
,
827 ID3DXFontImpl_GetTextMetricsW
,
829 ID3DXFontImpl_GetGlyphData
,
830 ID3DXFontImpl_PreloadCharacters
,
831 ID3DXFontImpl_PreloadGlyphs
,
832 ID3DXFontImpl_PreloadTextA
,
833 ID3DXFontImpl_PreloadTextW
,
834 ID3DXFontImpl_DrawTextA
,
835 ID3DXFontImpl_DrawTextW
,
836 ID3DXFontImpl_OnLostDevice
,
837 ID3DXFontImpl_OnResetDevice
840 HRESULT WINAPI
D3DXCreateFontA(struct IDirect3DDevice9
*device
, INT height
, UINT width
,
841 UINT weight
, UINT miplevels
, BOOL italic
, DWORD charset
, DWORD precision
, DWORD quality
,
842 DWORD pitchandfamily
, const char *facename
, struct ID3DXFont
**font
)
846 if( !device
|| !font
) return D3DERR_INVALIDCALL
;
851 desc
.MipLevels
=miplevels
;
853 desc
.CharSet
=charset
;
854 desc
.OutputPrecision
=precision
;
855 desc
.Quality
=quality
;
856 desc
.PitchAndFamily
=pitchandfamily
;
857 if(facename
!= NULL
) lstrcpyA(desc
.FaceName
, facename
);
858 else desc
.FaceName
[0] = '\0';
860 return D3DXCreateFontIndirectA(device
, &desc
, font
);
863 HRESULT WINAPI
D3DXCreateFontW(IDirect3DDevice9
*device
, INT height
, UINT width
, UINT weight
, UINT miplevels
, BOOL italic
, DWORD charset
,
864 DWORD precision
, DWORD quality
, DWORD pitchandfamily
, const WCHAR
*facename
, ID3DXFont
**font
)
868 if( !device
|| !font
) return D3DERR_INVALIDCALL
;
873 desc
.MipLevels
=miplevels
;
875 desc
.CharSet
=charset
;
876 desc
.OutputPrecision
=precision
;
877 desc
.Quality
=quality
;
878 desc
.PitchAndFamily
=pitchandfamily
;
879 if(facename
!= NULL
) lstrcpyW(desc
.FaceName
, facename
);
880 else desc
.FaceName
[0] = '\0';
882 return D3DXCreateFontIndirectW(device
, &desc
, font
);
885 /***********************************************************************
886 * D3DXCreateFontIndirectA (D3DX9_36.@)
888 HRESULT WINAPI
D3DXCreateFontIndirectA(IDirect3DDevice9
*device
, const D3DXFONT_DESCA
*desc
, ID3DXFont
**font
)
890 D3DXFONT_DESCW widedesc
;
892 if( !device
|| !desc
|| !font
) return D3DERR_INVALIDCALL
;
894 /* Copy everything but the last structure member. This requires the
895 two D3DXFONT_DESC structures to be equal until the FaceName member */
896 memcpy(&widedesc
, desc
, FIELD_OFFSET(D3DXFONT_DESCA
, FaceName
));
897 MultiByteToWideChar(CP_ACP
, 0, desc
->FaceName
, -1, widedesc
.FaceName
, ARRAY_SIZE(widedesc
.FaceName
));
898 return D3DXCreateFontIndirectW(device
, &widedesc
, font
);
901 /***********************************************************************
902 * D3DXCreateFontIndirectW (D3DX9_36.@)
904 HRESULT WINAPI
D3DXCreateFontIndirectW(IDirect3DDevice9
*device
, const D3DXFONT_DESCW
*desc
, ID3DXFont
**font
)
906 D3DDEVICE_CREATION_PARAMETERS cpars
;
907 struct d3dx_font
*object
;
912 TRACE("(%p, %p, %p)\n", device
, desc
, font
);
914 if( !device
|| !desc
|| !font
) return D3DERR_INVALIDCALL
;
916 /* the device MUST support D3DFMT_A8R8G8B8 */
917 IDirect3DDevice9_GetDirect3D(device
, &d3d
);
918 IDirect3DDevice9_GetCreationParameters(device
, &cpars
);
919 IDirect3DDevice9_GetDisplayMode(device
, 0, &mode
);
920 hr
= IDirect3D9_CheckDeviceFormat(d3d
, cpars
.AdapterOrdinal
, cpars
.DeviceType
, mode
.Format
, 0, D3DRTYPE_TEXTURE
, D3DFMT_A8R8G8B8
);
923 IDirect3D9_Release(d3d
);
924 return D3DXERR_INVALIDDATA
;
926 IDirect3D9_Release(d3d
);
928 object
= heap_alloc_zero(sizeof(*object
));
932 return E_OUTOFMEMORY
;
934 object
->ID3DXFont_iface
.lpVtbl
= &D3DXFont_Vtbl
;
936 object
->device
= device
;
937 object
->desc
= *desc
;
939 object
->hdc
= CreateCompatibleDC(NULL
);
943 return D3DXERR_INVALIDDATA
;
946 object
->hfont
= CreateFontW(desc
->Height
, desc
->Width
, 0, 0, desc
->Weight
, desc
->Italic
, FALSE
, FALSE
, desc
->CharSet
,
947 desc
->OutputPrecision
, CLIP_DEFAULT_PRECIS
, desc
->Quality
, desc
->PitchAndFamily
, desc
->FaceName
);
950 DeleteDC(object
->hdc
);
952 return D3DXERR_INVALIDDATA
;
954 SelectObject(object
->hdc
, object
->hfont
);
956 wine_rb_init(&object
->glyph_tree
, glyph_rb_compare
);
958 if (!GetTextMetricsW(object
->hdc
, &object
->metrics
))
960 DeleteObject(object
->hfont
);
961 DeleteDC(object
->hdc
);
963 return D3DXERR_INVALIDDATA
;
966 object
->glyph_size
= make_pow2(object
->metrics
.tmHeight
);
968 object
->texture_size
= object
->glyph_size
;
969 if (object
->glyph_size
< 256)
970 object
->texture_size
= min(256, object
->texture_size
* 16);
972 object
->glyphs_per_texture
= object
->texture_size
* object
->texture_size
973 / (object
->glyph_size
* object
->glyph_size
);
974 object
->texture_pos
= object
->glyphs_per_texture
;
976 IDirect3DDevice9_AddRef(device
);
977 *font
= &object
->ID3DXFont_iface
;