2 * Copyright (C) 2008 - 2009 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 "wine/port.h"
23 #include "wine/debug.h"
24 #include "wine/unicode.h"
25 #include "d3dx9_36_private.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(d3dx
);
29 static HRESULT WINAPI
ID3DXFontImpl_QueryInterface(LPD3DXFONT iface
, REFIID riid
, LPVOID
*object
)
31 ID3DXFontImpl
*This
=(ID3DXFontImpl
*)iface
;
33 TRACE("(%p): QueryInterface from %s\n", This
, debugstr_guid(riid
));
34 if(IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_ID3DXFont
)) {
35 IUnknown_AddRef(iface
);
39 WARN("(%p)->(%s, %p): not found\n", iface
, debugstr_guid(riid
), *object
);
43 static ULONG WINAPI
ID3DXFontImpl_AddRef(LPD3DXFONT iface
)
45 ID3DXFontImpl
*This
=(ID3DXFontImpl
*)iface
;
46 ULONG ref
=InterlockedIncrement(&This
->ref
);
47 TRACE("(%p): AddRef from %d\n", This
, ref
-1);
51 static ULONG WINAPI
ID3DXFontImpl_Release(LPD3DXFONT iface
)
53 ID3DXFontImpl
*This
=(ID3DXFontImpl
*)iface
;
54 ULONG ref
=InterlockedDecrement(&This
->ref
);
55 TRACE("(%p): ReleaseRef to %d\n", This
, ref
);
60 for(i
= 0;i
< This
->TotalGlyphs
;i
++)
61 IDirect3DTexture9_Release(This
->pGlyphs
[i
].tex
);
63 if(This
->pTexture
) IDirect3DTexture9_Release(This
->pTexture
);
65 HeapFree(GetProcessHeap(), 0, This
->pBuf1
);
66 HeapFree(GetProcessHeap(), 0, This
->pBuf2
);
67 HeapFree(GetProcessHeap(), 0, This
->pGlyphs
);
68 DeleteObject(This
->hfont
);
70 IDirect3DDevice9_Release(This
->device
);
71 HeapFree(GetProcessHeap(), 0, This
);
76 static HRESULT WINAPI
ID3DXFontImpl_GetDevice(LPD3DXFONT iface
, LPDIRECT3DDEVICE9
*device
)
78 ID3DXFontImpl
*This
=(ID3DXFontImpl
*)iface
;
79 TRACE("(%p)\n", This
);
81 if( !device
) return D3DERR_INVALIDCALL
;
82 *device
= This
->device
;
83 IDirect3DDevice9_AddRef(This
->device
);
88 static HRESULT WINAPI
ID3DXFontImpl_GetDescA(LPD3DXFONT iface
, D3DXFONT_DESCA
*desc
)
90 ID3DXFontImpl
*This
=(ID3DXFontImpl
*)iface
;
91 TRACE("(%p)\n", This
);
93 if( !desc
) return D3DERR_INVALIDCALL
;
94 memcpy(desc
, &This
->desc
, FIELD_OFFSET(D3DXFONT_DESCA
, FaceName
));
95 WideCharToMultiByte(CP_ACP
, 0, This
->desc
.FaceName
, -1, desc
->FaceName
, sizeof(desc
->FaceName
) / sizeof(CHAR
), NULL
, NULL
);
100 static HRESULT WINAPI
ID3DXFontImpl_GetDescW(LPD3DXFONT iface
, D3DXFONT_DESCW
*desc
)
102 ID3DXFontImpl
*This
=(ID3DXFontImpl
*)iface
;
103 TRACE("(%p)\n", This
);
105 if( !desc
) return D3DERR_INVALIDCALL
;
111 static BOOL WINAPI
ID3DXFontImpl_GetTextMetricsA(LPD3DXFONT iface
, TEXTMETRICA
*metrics
)
113 ID3DXFontImpl
*This
=(ID3DXFontImpl
*)iface
;
114 TRACE("(%p)\n", This
);
115 return GetTextMetricsA(This
->hdc
, metrics
);
118 static BOOL WINAPI
ID3DXFontImpl_GetTextMetricsW(LPD3DXFONT iface
, TEXTMETRICW
*metrics
)
120 ID3DXFontImpl
*This
=(ID3DXFontImpl
*)iface
;
121 TRACE("(%p)\n", This
);
122 return GetTextMetricsW(This
->hdc
, metrics
);
125 static HDC WINAPI
ID3DXFontImpl_GetDC(LPD3DXFONT iface
)
127 ID3DXFontImpl
*This
=(ID3DXFontImpl
*)iface
;
128 TRACE("(%p)\n", This
);
132 /************************************************************
133 * ID3DXFont_GetGlyphData
135 * Returns the internally stored texture and some info about
136 * the position of the requested glyph on that texture
140 * texture [O] length of the string
141 * blackbox [O] smallest rectangle that completely encloses the glyph on the texture
142 * cellinc [O] offset from the baseline to the bottom of the glyph
146 * Failure: D3DERR_INVALIDCALL
147 * D3DXERR_INVALIDDATA
150 * Glyphs which are passed to this function get preloaded, too
153 static HRESULT WINAPI
ID3DXFontImpl_GetGlyphData(LPD3DXFONT iface
, UINT glyph
, LPDIRECT3DTEXTURE9
*texture
, RECT
*blackbox
, POINT
*cellinc
)
155 ID3DXFontImpl
*This
=(ID3DXFontImpl
*)iface
;
158 TRACE("(%p)\n", This
);
160 if( !texture
|| !blackbox
|| !cellinc
) return D3DERR_INVALIDCALL
;
162 for(i
= 0;i
< This
->TotalGlyphs
;i
++)
163 if(This
->pGlyphs
[i
].id
== glyph
) {
164 *cellinc
= This
->pGlyphs
[i
].cellinc
;
165 *blackbox
= This
->pGlyphs
[i
].blackbox
;
166 *texture
= This
->pGlyphs
[i
].tex
;
167 IDirect3DTexture9_AddRef(This
->pGlyphs
[i
].tex
);
171 hr
= ID3DXFont_PreloadGlyphs(iface
, glyph
, glyph
);
172 if(FAILED(hr
)) return hr
;
175 for(i
= 0;i
< This
->TotalGlyphs
;i
++)
176 if(This
->pGlyphs
[i
].id
== glyph
) {
177 *cellinc
= This
->pGlyphs
[i
].cellinc
;
178 *blackbox
= This
->pGlyphs
[i
].blackbox
;
179 *texture
= This
->pGlyphs
[i
].tex
;
180 IDirect3DTexture9_AddRef(This
->pGlyphs
[i
].tex
);
184 return D3DXERR_INVALIDDATA
;
187 /************************************************************
188 * ID3DXFont_PreloadCharacters
190 * Preloads the specified character series into the internal texture
193 * first [I] first character to be preloaded
194 * last [I] last character to be preloaded
198 * Failure: D3DERR_INVALIDCALL
201 * We just split each character into its glyphs and call PreloadGlyphs here.
204 static HRESULT WINAPI
ID3DXFontImpl_PreloadCharacters(LPD3DXFONT iface
, UINT first
, UINT last
)
206 ID3DXFontImpl
*This
=(ID3DXFontImpl
*)iface
;
207 GCP_RESULTSW results
;
210 TRACE("(%p)\n", This
);
211 if(last
< first
) return D3D_OK
;
213 if(This
->BufSize1
< sizeof(WCHAR
) * (last
- first
+ 1)) {
214 This
->BufSize1
= (sizeof(WCHAR
) * (last
- first
+ 1) + 63) & ~63;
215 This
->pBuf1
= HeapReAlloc(GetProcessHeap(), 0, This
->pBuf1
, This
->BufSize1
);
217 for(i
= 0; i
< last
- first
+ 1; i
++)
218 ((LPWSTR
)This
->pBuf1
)[i
] = (WCHAR
)(first
+ i
);
220 if(This
->BufSize2
< sizeof(WORD
) * (last
- first
+ 1)) {
221 This
->BufSize2
= (sizeof(WORD
) * (last
- first
+ 1) + 63) & ~63;
222 This
->pBuf2
= HeapReAlloc(GetProcessHeap(), 0, This
->pBuf2
, This
->BufSize2
);
225 ZeroMemory(&results
, sizeof(GCP_RESULTSW
));
226 results
.lpGlyphs
= (LPWORD
)This
->pBuf2
;
227 results
.nGlyphs
= last
- first
+ 1;
229 GetCharacterPlacementW(This
->hdc
, (LPWSTR
)This
->pBuf1
, last
- first
+ 1, 0, &results
, 0);
231 for(i
= 0;i
< last
- first
+ 1;i
++)
232 ID3DXFont_PreloadGlyphs(iface
, (UINT
)(((LPWORD
)This
->pBuf2
)[i
]), (UINT
)(((LPWORD
)This
->pBuf2
)[i
]));
237 /************************************************************
238 * ID3DXFont_PreloadGlyphs
240 * Preloads the specified glyph series into the internal texture
243 * first [I] first glyph to be preloaded
244 * last [I] last glyph to be preloaded
250 * The glyphs are stored in a grid.
251 * Cell sizes vary between different font sizes.
252 * The grid is filled in this order:
253 * 1 2 5 6 17 18 21 22
254 * 3 4 7 8 19 20 23 24
255 * 9 10 13 14 25 26 29 30
256 * 11 12 15 16 27 28 31 32
259 * i.e. we try to fill one small square, then three equal-sized squares so that we get one big square, etc...
261 * The glyphs are positioned around their baseline, which is located at y position GridSize * (i + 0.75).
262 * Concerning the x position, the glyphs are centered around GridSize * (i + 0.5).
265 static HRESULT WINAPI
ID3DXFontImpl_PreloadGlyphs(LPD3DXFONT iface
, UINT first
, UINT last
)
267 ID3DXFontImpl
*This
=(ID3DXFontImpl
*)iface
;
269 UINT glyph
, i
, x
, y
, OutlinePitch
;
271 TRACE("(%p)\n", This
);
273 if(last
< first
) return D3D_OK
;
275 for(glyph
= first
; glyph
<= last
; glyph
++) {
276 GLYPHMETRICS metrics
;
277 D3DLOCKED_RECT lockrect
;
278 MAT2 mat
= { {0,1}, {0,0}, {0,0}, {0,1} };
279 UINT offx
= This
->GridSize
/ 2, offy
= This
->GridSize
* 3 / 4;
281 /* Check whether the glyph is already preloaded */
282 for(i
= 0;i
< This
->TotalGlyphs
;i
++)
283 if(This
->pGlyphs
[i
].id
== glyph
)
285 if(i
< This
->TotalGlyphs
) continue;
287 /* calculate glyph position */
288 for(i
= 0;i
< 16; i
++) {
289 if((This
->CurGlyph
% This
->GlyphsPerTex
) & (1 << (2*i
))) offx
+= This
->GridSize
* (1 << i
);
290 if(i
< 15) if((This
->CurGlyph
% This
->GlyphsPerTex
) & (1 << (2*i
+ 1))) offy
+= This
->GridSize
* (1 << i
);
293 /* make sure we have enough memory */
294 if(This
->TotalGlyphs
+ 1 > This
->AllocatedGlyphs
) {
295 This
->AllocatedGlyphs
<<= 1;
296 This
->pGlyphs
= HeapReAlloc(GetProcessHeap(), 0, This
->pGlyphs
, sizeof(GLYPH
) * This
->AllocatedGlyphs
);
299 /* get the glyph data */
300 newsize
= GetGlyphOutlineW(This
->hdc
, glyph
, GGO_GLYPH_INDEX
| GGO_GRAY8_BITMAP
, &metrics
, 0, NULL
, &mat
);
301 if(newsize
== GDI_ERROR
) continue;
302 if(This
->BufSize1
< newsize
) {
303 This
->pBuf1
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->pBuf1
, (newsize
+ 63) & ~63);
304 This
->BufSize1
= (newsize
+ 63) & ~63;
306 GetGlyphOutlineW(This
->hdc
, glyph
, GGO_GLYPH_INDEX
| GGO_GRAY8_BITMAP
, &metrics
, newsize
, This
->pBuf1
, &mat
);
308 /* create a new texture if necessary */
309 if( (This
->CurGlyph
% This
->GlyphsPerTex
) == 0) {
310 if(This
->pTexture
) IDirect3DTexture9_Release(This
->pTexture
);
311 IDirect3DDevice9_CreateTexture(This
->device
, This
->TexSize
, This
->TexSize
, 0, 0, D3DFMT_A8R8G8B8
, D3DPOOL_MANAGED
, &This
->pTexture
, NULL
);
312 offx
= This
->GridSize
/ 2;
313 offy
= This
->GridSize
* 3 / 4;
316 /* fill in glyph data */
317 This
->pGlyphs
[This
->CurGlyph
].id
= glyph
;
318 This
->pGlyphs
[This
->CurGlyph
].blackbox
.left
= offx
- metrics
.gmptGlyphOrigin
.x
- metrics
.gmBlackBoxX
/ 2;
319 This
->pGlyphs
[This
->CurGlyph
].blackbox
.top
= offy
- metrics
.gmptGlyphOrigin
.y
;
320 This
->pGlyphs
[This
->CurGlyph
].blackbox
.right
= offx
- metrics
.gmptGlyphOrigin
.x
+ metrics
.gmBlackBoxX
/ 2;
321 if(metrics
.gmBlackBoxX
% 2) This
->pGlyphs
[This
->CurGlyph
].blackbox
.right
++;
322 This
->pGlyphs
[This
->CurGlyph
].blackbox
.bottom
= offy
- metrics
.gmptGlyphOrigin
.y
+ metrics
.gmBlackBoxY
;
323 This
->pGlyphs
[This
->CurGlyph
].cellinc
.x
= metrics
.gmptGlyphOrigin
.x
- 1;
324 This
->pGlyphs
[This
->CurGlyph
].cellinc
.y
= This
->FontAscent
- metrics
.gmptGlyphOrigin
.y
- 1;
325 This
->pGlyphs
[This
->CurGlyph
].tex
= This
->pTexture
;
326 IDirect3DTexture9_AddRef(This
->pTexture
);
328 /* copy glyph data to texture */
329 IDirect3DTexture9_LockRect(This
->pTexture
, 0, &lockrect
, &This
->pGlyphs
[This
->CurGlyph
].blackbox
, 0);
330 OutlinePitch
= (metrics
.gmBlackBoxX
+ 3) & ~3;
332 for(x
= 0;x
< This
->pGlyphs
[This
->CurGlyph
].blackbox
.right
- This
->pGlyphs
[This
->CurGlyph
].blackbox
.left
;x
++)
333 for(y
= 0;y
< This
->pGlyphs
[This
->CurGlyph
].blackbox
.bottom
- This
->pGlyphs
[This
->CurGlyph
].blackbox
.top
;y
++) {
334 ((BYTE
*)lockrect
.pBits
)[4 * x
+ y
* lockrect
.Pitch
] = 255;
335 ((BYTE
*)lockrect
.pBits
)[4 * x
+ y
* lockrect
.Pitch
+ 1] = 255;
336 ((BYTE
*)lockrect
.pBits
)[4 * x
+ y
* lockrect
.Pitch
+ 2] = 255;
337 ((BYTE
*)lockrect
.pBits
)[4 * x
+ y
* lockrect
.Pitch
+ 3] = ((BYTE
*)This
->pBuf1
)[x
+ y
* OutlinePitch
] * 255 / 64;
340 IDirect3DTexture9_UnlockRect(This
->pTexture
, 0);
345 D3DXFilterTexture((IDirect3DBaseTexture9
*)This
->pTexture
, NULL
, 0, D3DX_DEFAULT
);
350 /************************************************************
351 * ID3DXFont_PreloadText
353 * Preloads a string into the internal texture
356 * string [I] string to be preloaded
357 * count [I] length of the string
360 * Success: D3D_OK, if we successfully preload the text or
361 * if string and count are NULL
362 * Failure: D3DERR_INVALIDCALL, if string is NULL and count is not 0
365 static HRESULT WINAPI
ID3DXFontImpl_PreloadTextA(LPD3DXFONT iface
, LPCSTR string
, INT count
)
369 TRACE("(%p): relay\n", iface
);
371 if(string
== NULL
&& count
== 0) return D3D_OK
;
372 if(string
== NULL
) return D3DERR_INVALIDCALL
;
374 if(count
== -1) count
= MultiByteToWideChar(CP_ACP
, 0, string
, -1, NULL
, 0);
375 widestr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, count
* sizeof(WCHAR
));
376 MultiByteToWideChar(CP_ACP
, 0, string
, -1, widestr
, count
);
378 hr
= ID3DXFont_PreloadTextW(iface
, widestr
, count
);
379 HeapFree(GetProcessHeap(), 0, widestr
);
384 static HRESULT WINAPI
ID3DXFontImpl_PreloadTextW(LPD3DXFONT iface
, LPCWSTR string
, INT count
)
386 ID3DXFontImpl
*This
=(ID3DXFontImpl
*)iface
;
387 GCP_RESULTSW results
;
390 TRACE("(%p)\n", This
);
392 if(string
== NULL
&& count
== 0) return D3D_OK
;
393 if(string
== NULL
) return D3DERR_INVALIDCALL
;
394 if(count
== -1) count
= strlenW(string
);
396 if(This
->BufSize1
< sizeof(WORD
) * count
) {
397 This
->BufSize1
= (sizeof(WORD
) * count
+ 63) & ~63;
398 This
->pBuf1
= HeapReAlloc(GetProcessHeap(), 0, This
->pBuf1
, This
->BufSize1
);
401 ZeroMemory(&results
, sizeof(GCP_RESULTSW
));
402 results
.lpGlyphs
= (LPWORD
)This
->pBuf1
;
403 results
.nGlyphs
= count
;
405 GetCharacterPlacementW(This
->hdc
, string
, count
, 0, &results
, 0);
407 for(i
= 0;i
< count
;i
++)
408 ID3DXFont_PreloadGlyphs(iface
, (UINT
)((WORD
*)This
->pBuf1
)[i
], (UINT
)((WORD
*)This
->pBuf1
)[i
]);
413 /************************************************************
416 * Renders the specified string to the screen
419 * sprite [I] sprite object used to draw the text
420 * string [I] string to be drawn
421 * count [I] length of the string
422 * rect [I] rect which tells us where to draw the string
423 * format [I] format of the string
424 * color [I] text color
427 * The height of the drawn text
430 static INT WINAPI
ID3DXFontImpl_DrawTextA(LPD3DXFONT iface
, LPD3DXSPRITE sprite
, LPCSTR string
, INT count
, LPRECT rect
, DWORD format
, D3DCOLOR color
)
434 TRACE("(%p): relay\n", iface
);
436 if(string
== NULL
&& count
== 0) return D3D_OK
;
437 if(string
== NULL
) return D3DERR_INVALIDCALL
;
439 if(count
== -1) count
= MultiByteToWideChar(CP_ACP
, 0, string
, -1, NULL
, 0);
440 widestr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, count
* sizeof(WCHAR
));
441 MultiByteToWideChar(CP_ACP
, 0, string
, -1, widestr
, count
);
443 ret
= ID3DXFont_DrawTextW(iface
, sprite
, widestr
, count
- 1, rect
, format
, color
);
444 HeapFree(GetProcessHeap(), 0, widestr
);
454 #define MAX_BUFFER 1024
455 static void TEXT_WordBreak (HDC hdc
, WCHAR
*str
, unsigned int max_str
,
456 unsigned int *len_str
,
457 int width
, int format
, unsigned int chars_fit
,
458 unsigned int *chars_used
, SIZE
*size
)
467 else if (*p
== SPACE
) p
--;
469 while (p
> str
&& *(--p
) != SPACE
);
471 word_fits
= (p
!= str
|| *p
== SPACE
);
477 if (!(format
& (DT_RIGHT
| DT_CENTER
)) || *p
!= SPACE
) p
++;
479 next_is_space
= (p
- str
) < *len_str
&& *p
== SPACE
;
482 *chars_used
= *len_str
;
483 if (next_is_space
) (*chars_used
)++;
485 const WCHAR
*e
= str
+ *len_str
;
487 while (p
< e
&& *p
!= SPACE
) p
++;
488 *chars_used
= p
- str
;
489 if (p
< e
) (*chars_used
)++;
493 GetTextExtentExPointW (hdc
, str
, *len_str
, 0, NULL
, NULL
, size
);
496 static void TEXT_SkipChars (int *new_count
, const WCHAR
**new_str
,
497 int start_count
, const WCHAR
*start_str
,
500 const WCHAR
*str_on_entry
= start_str
;
504 if (*start_str
++ == PREFIX
&& max
--)
507 start_count
-= (start_str
- str_on_entry
);
509 *new_str
= start_str
;
510 *new_count
= start_count
;
513 static const WCHAR
*TEXT_NextLineW(HDC hdc
, const WCHAR
*str
, int *count
,
514 WCHAR
*dest
, int *len
, int width
, DWORD format
,
515 SIZE
*retsize
, int last_line
, int tabwidth
)
521 int seg_i
, seg_count
, seg_j
;
526 unsigned int j_in_seg
;
531 if (str
[i
] == TAB
&& (format
& DT_EXPANDTABS
)) {
532 plen
= ((plen
/tabwidth
)+1)*tabwidth
;
534 if (j
< maxl
) dest
[j
++] = str
[i
++];
537 while (*count
&& str
[i
] == TAB
) {
540 if (j
< maxl
) dest
[j
++] = str
[i
++];
549 while (*count
&& (str
[i
] != TAB
|| !(format
& DT_EXPANDTABS
)) && ((str
[i
] != CR
&& str
[i
] != LF
) || (format
& DT_SINGLELINE
))) {
550 if (str
[i
] == PREFIX
&& *count
> 1) {
553 if (str
[i
] == PREFIX
) {
555 if (j
< maxl
) dest
[j
++] = str
[i
];
560 if (j
< maxl
) dest
[j
++] = str
[i
];
565 j_in_seg
= j
- seg_j
;
566 max_seg_width
= width
- plen
;
567 GetTextExtentExPointW (hdc
, dest
+ seg_j
, j_in_seg
, max_seg_width
, &num_fit
, NULL
, &size
);
571 line_fits
= (num_fit
>= j_in_seg
);
572 if (!line_fits
&& (format
& DT_WORDBREAK
))
575 unsigned int chars_used
;
576 TEXT_WordBreak (hdc
, dest
+seg_j
, maxl
-seg_j
, &j_in_seg
,
577 max_seg_width
, format
, num_fit
, &chars_used
, &size
);
578 line_fits
= (size
.cx
<= max_seg_width
);
580 TEXT_SkipChars (count
, &s
, seg_count
, str
+seg_i
, i
-seg_i
, chars_used
);
585 j
= seg_j
+ j_in_seg
;
587 if (size
.cy
> retsize
->cy
)
588 retsize
->cy
= size
.cy
;
590 if (word_broken
) break;
591 else if (!*count
) break;
592 else if (str
[i
] == CR
|| str
[i
] == LF
) {
595 if (*count
&& (str
[i
] == CR
|| str
[i
] == LF
) && str
[i
] != str
[i
-1]) {
605 if (*count
) return (&str
[i
]);
609 static INT WINAPI
ID3DXFontImpl_DrawTextW(LPD3DXFONT iface
, LPD3DXSPRITE sprite
, LPCWSTR string
, INT count
, LPRECT rect
, DWORD format
, D3DCOLOR color
)
611 ID3DXFontImpl
*This
=(ID3DXFontImpl
*)iface
;
616 WCHAR line
[MAX_BUFFER
];
627 TRACE("(%p)\n", This
);
629 if( !string
|| !count
|| *string
== '\0') return 0;
630 if(count
== -1) count
= strlenW(string
);
632 if (format
& DT_SINGLELINE
) format
&= ~DT_WORDBREAK
;
633 if (format
& DT_CALCRECT
) format
|= DT_NOCLIP
;
640 y
= ID3DXFont_DrawTextW(iface
, sprite
, string
, count
, &bufrect
, DT_CALCRECT
, 0);
641 if(format
& DT_CALCRECT
) return y
;
644 textrect
= bufrect
= *rect
;
645 if(rect
->left
>= rect
->right
|| rect
->top
> rect
->bottom
) format
|= DT_CALCRECT
| DT_NOCLIP
;
648 if(format
& (DT_CENTER
| DT_RIGHT
| DT_VCENTER
| DT_BOTTOM
)) {
649 if( rect
) y
= ID3DXFont_DrawTextW(iface
, NULL
, string
, count
, &bufrect
, DT_CALCRECT
| (format
& DT_WORDBREAK
), 0);
651 if(format
& DT_CENTER
) {
652 textrect
.left
= (textrect
.right
+ textrect
.left
- (bufrect
.right
- bufrect
.left
)) / 2;
653 textrect
.right
= textrect
.left
+ (bufrect
.right
- bufrect
.left
);
654 } else if(format
& DT_RIGHT
) {
655 textrect
.left
= textrect
.right
- (bufrect
.right
- bufrect
.left
);
656 textrect
.right
= textrect
.right
;
659 if(format
& DT_VCENTER
) {
660 textrect
.top
= (textrect
.bottom
+ textrect
.top
- (bufrect
.bottom
- bufrect
.top
)) / 2;
661 textrect
.bottom
= textrect
.top
+ (bufrect
.bottom
- bufrect
.top
);
662 } else if(format
& DT_BOTTOM
) textrect
.top
= textrect
.bottom
- (bufrect
.bottom
- bufrect
.top
);
665 x
= textrect
.left
, y
= textrect
.top
;
666 width
= textrect
.right
- textrect
.left
;
669 GetTextMetricsW(This
->hdc
, &tm
);
672 if (count
== -1) count
= strlenW(string
);
673 if (format
& DT_EXPANDTABS
) tabwidth
= tm
.tmAveCharWidth
* 8;
675 if( !(format
& DT_CALCRECT
) ) {
676 if(sprite
) target
= sprite
;
678 D3DXCreateSprite(This
->device
, &target
);
679 ID3DXSprite_Begin(target
, 0);
684 len
= sizeof(line
)/sizeof(line
[0]);
685 last_line
= !(format
& DT_NOCLIP
) && (y
+ lh
> textrect
.bottom
);
686 strPtr
= TEXT_NextLineW(This
->hdc
, strPtr
, &count
, line
, &len
, width
, format
, &size
, last_line
, tabwidth
);
688 if (!(format
& DT_CALCRECT
)) {
689 const WCHAR
*str
= line
;
695 if ((format
& DT_EXPANDTABS
)) {
697 p
= str
; while (p
< str
+len
&& *p
!= TAB
) p
++;
699 if (len_seg
!= len
&& !GetTextExtentPointW(This
->hdc
, str
, len_seg
, &size
)) return 0;
700 } else len_seg
= len
;
703 GCP_RESULTSW results
;
709 if(This
->BufSize1
< sizeof(INT
) * len_seg
) { /* carets */
710 This
->BufSize1
= (sizeof(INT
) * len_seg
+ 63) & ~63;
711 This
->pBuf1
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->pBuf1
, This
->BufSize1
);
713 if(This
->BufSize2
< sizeof(WORD
) * len_seg
) { /* glyphs */
714 This
->BufSize2
= (sizeof(WORD
) * len_seg
+ 63) & ~63;
715 This
->pBuf2
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->pBuf2
, This
->BufSize2
);
717 ZeroMemory(&results
, sizeof(GCP_RESULTSW
));
718 results
.lpCaretPos
= (INT
*)This
->pBuf1
;
719 results
.lpGlyphs
= (LPWORD
)This
->pBuf2
;
720 results
.nGlyphs
= len_seg
;
722 stringlength
= GetCharacterPlacementW(This
->hdc
, str
, len_seg
, 0, &results
, 0);
723 stringlength
&= 0xFFFF;
725 ID3DXFont_GetTextMetricsW(iface
, &metrics
);
727 for(i
= 0;i
< results
.nGlyphs
;i
++) {
728 LPDIRECT3DTEXTURE9 tex
;
732 /* TODO: Implement format flags DT_NOCLIP and DT_RTLREADING */
734 ID3DXFont_GetGlyphData(iface
, ((LPWORD
)This
->pBuf2
)[i
], &tex
, &bbox
, &cinc
);
736 pos
.x
= ((INT
*)This
->pBuf1
)[i
] + cinc
.x
+ xseg
;
739 ID3DXSprite_Draw(target
, tex
, &bbox
, NULL
, &pos
, color
);
740 IDirect3DTexture9_Release(tex
);
748 xseg
+= ((size
.cx
/tabwidth
)+1)*tabwidth
;
751 } else if (size
.cx
> max_width
) max_width
= size
.cx
;
754 } while (strPtr
&& !last_line
);
756 textrect
.right
= textrect
.left
+ max_width
;
758 if ((format
& DT_CALCRECT
) && rect
) *rect
= textrect
;
760 if( !(format
& DT_CALCRECT
) && target
!= sprite
) {
761 ID3DXSprite_End(target
);
762 ID3DXSprite_Release(target
);
765 return y
- textrect
.top
;
768 static HRESULT WINAPI
ID3DXFontImpl_OnLostDevice(LPD3DXFONT iface
)
770 ID3DXFontImpl
*This
=(ID3DXFontImpl
*)iface
;
771 FIXME("(%p): stub\n", This
);
775 static HRESULT WINAPI
ID3DXFontImpl_OnResetDevice(LPD3DXFONT iface
)
777 ID3DXFontImpl
*This
=(ID3DXFontImpl
*)iface
;
778 FIXME("(%p): stub\n", This
);
782 static const ID3DXFontVtbl D3DXFont_Vtbl
=
784 /*** IUnknown methods ***/
785 ID3DXFontImpl_QueryInterface
,
786 ID3DXFontImpl_AddRef
,
787 ID3DXFontImpl_Release
,
788 /*** ID3DXFont methods ***/
789 ID3DXFontImpl_GetDevice
,
790 ID3DXFontImpl_GetDescA
,
791 ID3DXFontImpl_GetDescW
,
792 ID3DXFontImpl_GetTextMetricsA
,
793 ID3DXFontImpl_GetTextMetricsW
,
795 ID3DXFontImpl_GetGlyphData
,
796 ID3DXFontImpl_PreloadCharacters
,
797 ID3DXFontImpl_PreloadGlyphs
,
798 ID3DXFontImpl_PreloadTextA
,
799 ID3DXFontImpl_PreloadTextW
,
800 ID3DXFontImpl_DrawTextA
,
801 ID3DXFontImpl_DrawTextW
,
802 ID3DXFontImpl_OnLostDevice
,
803 ID3DXFontImpl_OnResetDevice
806 HRESULT WINAPI
D3DXCreateFontA(LPDIRECT3DDEVICE9 device
, INT height
, UINT width
, UINT weight
, UINT miplevels
, BOOL italic
, DWORD charset
,
807 DWORD precision
, DWORD quality
, DWORD pitchandfamily
, LPCSTR facename
, LPD3DXFONT
*font
)
811 if( !device
|| !font
) return D3DERR_INVALIDCALL
;
816 desc
.MipLevels
=miplevels
;
818 desc
.CharSet
=charset
;
819 desc
.OutputPrecision
=precision
;
820 desc
.Quality
=quality
;
821 desc
.PitchAndFamily
=pitchandfamily
;
822 if(facename
!= NULL
) lstrcpyA(desc
.FaceName
, facename
);
823 else desc
.FaceName
[0] = '\0';
825 return D3DXCreateFontIndirectA(device
, &desc
, font
);
828 HRESULT WINAPI
D3DXCreateFontW(LPDIRECT3DDEVICE9 device
, INT height
, UINT width
, UINT weight
, UINT miplevels
, BOOL italic
, DWORD charset
,
829 DWORD precision
, DWORD quality
, DWORD pitchandfamily
, LPCWSTR facename
, LPD3DXFONT
*font
)
833 if( !device
|| !font
) return D3DERR_INVALIDCALL
;
838 desc
.MipLevels
=miplevels
;
840 desc
.CharSet
=charset
;
841 desc
.OutputPrecision
=precision
;
842 desc
.Quality
=quality
;
843 desc
.PitchAndFamily
=pitchandfamily
;
844 if(facename
!= NULL
) strcpyW(desc
.FaceName
, facename
);
845 else desc
.FaceName
[0] = '\0';
847 return D3DXCreateFontIndirectW(device
, &desc
, font
);
850 /***********************************************************************
851 * D3DXCreateFontIndirectA (D3DX9_36.@)
853 HRESULT WINAPI
D3DXCreateFontIndirectA(LPDIRECT3DDEVICE9 device
, CONST D3DXFONT_DESCA
*desc
, LPD3DXFONT
*font
)
855 D3DXFONT_DESCW widedesc
;
857 if( !device
|| !desc
|| !font
) return D3DERR_INVALIDCALL
;
859 /* Copy everything but the last structure member. This requires the
860 two D3DXFONT_DESC structures to be equal until the FaceName member */
861 memcpy(&widedesc
, desc
, FIELD_OFFSET(D3DXFONT_DESCA
, FaceName
));
862 MultiByteToWideChar(CP_ACP
, 0, desc
->FaceName
, -1,
863 widedesc
.FaceName
, sizeof(widedesc
.FaceName
)/sizeof(WCHAR
));
864 return D3DXCreateFontIndirectW(device
, &widedesc
, font
);
867 /***********************************************************************
868 * D3DXCreateFontIndirectW (D3DX9_36.@)
870 HRESULT WINAPI
D3DXCreateFontIndirectW(LPDIRECT3DDEVICE9 device
, CONST D3DXFONT_DESCW
*desc
, LPD3DXFONT
*font
)
872 D3DDEVICE_CREATION_PARAMETERS cpars
;
874 ID3DXFontImpl
*object
;
880 if( !device
|| !desc
|| !font
) return D3DERR_INVALIDCALL
;
882 /* the device MUST support D3DFMT_A8R8G8B8 */
883 IDirect3DDevice9_GetDirect3D(device
, &d3d
);
884 IDirect3DDevice9_GetCreationParameters(device
, &cpars
);
885 IDirect3DDevice9_GetDisplayMode(device
, 0, &mode
);
886 hr
= IDirect3D9_CheckDeviceFormat(d3d
, cpars
.AdapterOrdinal
, cpars
.DeviceType
, mode
.Format
, 0, D3DRTYPE_TEXTURE
, D3DFMT_A8R8G8B8
);
888 IDirect3D9_Release(d3d
);
889 return D3DXERR_INVALIDDATA
;
891 IDirect3D9_Release(d3d
);
893 object
=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ID3DXFontImpl
));
896 return E_OUTOFMEMORY
;
898 object
->lpVtbl
=&D3DXFont_Vtbl
;
900 object
->device
=device
;
903 object
->hdc
= CreateCompatibleDC(NULL
);
905 HeapFree(GetProcessHeap(), 0, object
);
906 return D3DXERR_INVALIDDATA
;
909 object
->hfont
= CreateFontW(desc
->Height
, desc
->Width
, 0, 0, desc
->Weight
, desc
->Italic
, FALSE
, FALSE
, desc
->CharSet
,
910 desc
->OutputPrecision
, CLIP_DEFAULT_PRECIS
, desc
->Quality
, desc
->PitchAndFamily
, desc
->FaceName
);
911 if( !object
->hfont
) {
912 DeleteDC(object
->hdc
);
913 HeapFree(GetProcessHeap(), 0, object
);
914 return D3DXERR_INVALIDDATA
;
916 SelectObject(object
->hdc
, object
->hfont
);
918 /* allocate common memory usage */
919 object
->AllocatedGlyphs
= 32;
920 object
->pGlyphs
= HeapAlloc(GetProcessHeap(), 0, object
->AllocatedGlyphs
* sizeof(GLYPH
));
921 object
->BufSize1
= 32;
922 object
->pBuf1
= HeapAlloc(GetProcessHeap(), 0, object
->BufSize1
);
923 object
->BufSize2
= 32;
924 object
->pBuf2
= HeapAlloc(GetProcessHeap(), 0, object
->BufSize2
);
926 GetTextMetricsW(object
->hdc
, &metrics
);
927 object
->FontAscent
= metrics
.tmAscent
;
928 object
->FontDescent
= metrics
.tmDescent
;
929 object
->GridSize
= make_pow2(metrics
.tmHeight
);
930 if(object
->GridSize
* 3 / 4 < metrics
.tmAscent
) object
->GridSize
*= 2;
931 object
->TexSize
= max(255, object
->GridSize
<< 2); /* TODO: check how the native dll handles this */
932 object
->GlyphsPerTex
= object
->TexSize
* object
->TexSize
/ object
->GridSize
/ object
->GridSize
;
934 IDirect3DDevice9_AddRef(device
);
935 *font
=(LPD3DXFONT
)object
;