d3dx9: Apply current transform in ID3DXSprite_Draw instead of ID3DXSprite_Flush.
[wine/d3dx9TW.git] / dlls / d3dx9_36 / font.c
blobcf1aecff33c94197af8969e90428c4fef1b258e2
1 /*
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
20 #include "config.h"
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);
36 *object=This;
37 return S_OK;
39 WARN("(%p)->(%s, %p): not found\n", iface, debugstr_guid(riid), *object);
40 return E_NOINTERFACE;
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);
48 return ref;
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);
57 if(ref==0) {
58 UINT i;
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);
69 DeleteDC(This->hdc);
70 IDirect3DDevice9_Release(This->device);
71 HeapFree(GetProcessHeap(), 0, This);
73 return ref;
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);
85 return D3D_OK;
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);
97 return D3D_OK;
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;
106 *desc = This->desc;
108 return D3D_OK;
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);
129 return This->hdc;
132 /************************************************************
133 * ID3DXFont_GetGlyphData
135 * Returns the internally stored texture and some info about
136 * the position of the requested glyph on that texture
138 * PARAMS
139 * glyph [I] glyph
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
144 * RETURNS
145 * Success: D3D_OK
146 * Failure: D3DERR_INVALIDCALL
147 * D3DXERR_INVALIDDATA
149 * NOTES
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;
156 HRESULT hr;
157 int i;
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);
168 return D3D_OK;
171 hr = ID3DXFont_PreloadGlyphs(iface, glyph, glyph);
172 if(FAILED(hr)) return hr;
174 /* Try again */
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);
181 return D3D_OK;
184 return D3DXERR_INVALIDDATA;
187 /************************************************************
188 * ID3DXFont_PreloadCharacters
190 * Preloads the specified character series into the internal texture
192 * PARAMS
193 * first [I] first character to be preloaded
194 * last [I] last character to be preloaded
196 * RETURNS
197 * Success: D3D_OK
198 * Failure: D3DERR_INVALIDCALL
200 * NOTES
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;
208 UINT i;
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]));
234 return D3D_OK;
237 /************************************************************
238 * ID3DXFont_PreloadGlyphs
240 * Preloads the specified glyph series into the internal texture
242 * PARAMS
243 * first [I] first glyph to be preloaded
244 * last [I] last glyph to be preloaded
246 * RETURNS
247 * Success: D3D_OK
249 * NOTES
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
257 * 33 34 ...
258 * ...
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;
268 DWORD newsize;
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)
284 break;
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);
342 This->CurGlyph++;
343 This->TotalGlyphs++;
345 D3DXFilterTexture((IDirect3DBaseTexture9*)This->pTexture, NULL, 0, D3DX_DEFAULT);
347 return D3D_OK;
350 /************************************************************
351 * ID3DXFont_PreloadText
353 * Preloads a string into the internal texture
355 * PARAMS
356 * string [I] string to be preloaded
357 * count [I] length of the string
359 * RETURNS
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)
367 LPWSTR widestr;
368 HRESULT hr;
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);
381 return hr;
384 static HRESULT WINAPI ID3DXFontImpl_PreloadTextW(LPD3DXFONT iface, LPCWSTR string, INT count)
386 ID3DXFontImpl *This=(ID3DXFontImpl*)iface;
387 GCP_RESULTSW results;
388 UINT i;
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]);
410 return D3D_OK;
413 /************************************************************
414 * ID3DXFont_DrawText
416 * Renders the specified string to the screen
418 * PARAMS
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
426 * RETURNS
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)
432 LPWSTR widestr;
433 INT ret;
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);
446 return ret;
449 #define TAB 9
450 #define LF 10
451 #define CR 13
452 #define SPACE 32
453 #define PREFIX 38
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)
460 WCHAR *p;
461 int word_fits;
463 p = str + chars_fit;
464 word_fits = TRUE;
466 if (!chars_fit);
467 else if (*p == SPACE) p--;
468 else {
469 while (p > str && *(--p) != SPACE);
471 word_fits = (p != str || *p == SPACE);
474 if (word_fits) {
475 int next_is_space;
477 if (!(format & (DT_RIGHT | DT_CENTER)) || *p != SPACE) p++;
479 next_is_space = (p - str) < *len_str && *p == SPACE;
480 *len_str = p - str;
482 *chars_used = *len_str;
483 if (next_is_space) (*chars_used)++;
484 } else {
485 const WCHAR *e = str + *len_str;
486 p = str + chars_fit;
487 while (p < e && *p != SPACE) p++;
488 *chars_used = p - str;
489 if (p < e) (*chars_used)++;
491 *len_str = p - str;
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,
498 int max, int n)
500 const WCHAR *str_on_entry = start_str;
501 max -= n;
503 while (n--)
504 if (*start_str++ == PREFIX && max--)
505 start_str++;
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)
517 int i = 0, j = 0;
518 int plen = 0;
519 SIZE size;
520 int maxl = *len;
521 int seg_i, seg_count, seg_j;
522 int max_seg_width;
523 int num_fit;
524 int word_broken;
525 int line_fits;
526 unsigned int j_in_seg;
528 retsize->cy = 0;
529 while (*count) {
530 /* Expand tabs */
531 if (str[i] == TAB && (format & DT_EXPANDTABS)) {
532 plen = ((plen/tabwidth)+1)*tabwidth;
533 (*count)--;
534 if (j < maxl) dest[j++] = str[i++];
535 else i++;
537 while (*count && str[i] == TAB) {
538 plen += tabwidth;
539 (*count)--;
540 if (j < maxl) dest[j++] = str[i++];
541 else i++;
545 seg_i = i;
546 seg_count = *count;
547 seg_j = j;
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) {
551 (*count)--,
552 i++;
553 if (str[i] == PREFIX) {
554 (*count)--;
555 if (j < maxl) dest[j++] = str[i];
556 i++;
558 } else {
559 (*count)--;
560 if (j < maxl) dest[j++] = str[i];
561 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);
569 /* break words */
570 word_broken = 0;
571 line_fits = (num_fit >= j_in_seg);
572 if (!line_fits && (format & DT_WORDBREAK))
574 const WCHAR *s;
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);
581 i = s - str;
582 word_broken = 1;
585 j = seg_j + j_in_seg;
586 plen += size.cx;
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) {
593 (*count)--;
594 i++;
595 if (*count && (str[i] == CR || str[i] == LF) && str[i] != str[i-1]) {
596 (*count)--;
597 i++;
599 break;
603 retsize->cx = plen;
604 *len = j;
605 if (*count) return (&str[i]);
606 else return NULL;
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;
612 ID3DXSprite *target;
614 SIZE size;
615 const WCHAR *strPtr;
616 WCHAR line[MAX_BUFFER];
617 int len, lh;
618 TEXTMETRICW tm;
619 int x, y;
620 int width;
621 int max_width = 0;
622 int last_line;
623 int tabwidth = 0;
624 RECT textrect;
625 RECT bufrect;
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;
635 if( !rect) {
636 bufrect.left = 0;
637 bufrect.right = 0;
638 bufrect.top = 0;
639 bufrect.bottom = 0;
640 y = ID3DXFont_DrawTextW(iface, sprite, string, count, &bufrect, DT_CALCRECT, 0);
641 if(format & DT_CALCRECT) return y;
642 textrect = bufrect;
643 } else {
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;
667 strPtr = string;
669 GetTextMetricsW(This->hdc, &tm);
670 lh = tm.tmHeight;
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;
677 else {
678 D3DXCreateSprite(This->device, &target);
679 ID3DXSprite_Begin(target, 0);
683 do {
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;
690 int xseg = x;
692 while (len) {
693 int len_seg;
694 SIZE size;
695 if ((format & DT_EXPANDTABS)) {
696 const WCHAR *p;
697 p = str; while (p < str+len && *p != TAB) p++;
698 len_seg = p - str;
699 if (len_seg != len && !GetTextExtentPointW(This->hdc, str, len_seg, &size)) return 0;
700 } else len_seg = len;
703 GCP_RESULTSW results;
704 TEXTMETRICW metrics;
705 UINT stringlength;
706 D3DXVECTOR3 pos;
707 UINT i;
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);
726 pos.x = xseg;
727 for(i = 0;i < results.nGlyphs;i++) {
728 LPDIRECT3DTEXTURE9 tex;
729 RECT bbox;
730 POINT cinc;
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;
737 pos.y = cinc.y + y;
739 ID3DXSprite_Draw(target, tex, &bbox, NULL, &pos, color);
740 IDirect3DTexture9_Release(tex);
744 len -= len_seg;
745 str += len_seg;
746 if (len) {
747 len--; str++;
748 xseg += ((size.cx/tabwidth)+1)*tabwidth;
751 } else if (size.cx > max_width) max_width = size.cx;
753 y += lh;
754 } while (strPtr && !last_line);
756 textrect.right = textrect.left + max_width;
757 textrect.bottom = y;
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);
772 return D3D_OK;
775 static HRESULT WINAPI ID3DXFontImpl_OnResetDevice(LPD3DXFONT iface)
777 ID3DXFontImpl *This=(ID3DXFontImpl*)iface;
778 FIXME("(%p): stub\n", This);
779 return D3D_OK;
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,
794 ID3DXFontImpl_GetDC,
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)
809 D3DXFONT_DESCA desc;
811 if( !device || !font ) return D3DERR_INVALIDCALL;
813 desc.Height=height;
814 desc.Width=width;
815 desc.Weight=weight;
816 desc.MipLevels=miplevels;
817 desc.Italic=italic;
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)
831 D3DXFONT_DESCW desc;
833 if( !device || !font ) return D3DERR_INVALIDCALL;
835 desc.Height=height;
836 desc.Width=width;
837 desc.Weight=weight;
838 desc.MipLevels=miplevels;
839 desc.Italic=italic;
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;
873 D3DDISPLAYMODE mode;
874 ID3DXFontImpl *object;
875 IDirect3D9 *d3d;
876 TEXTMETRICW metrics;
877 HRESULT hr;
878 TRACE("(void)\n");
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);
887 if(FAILED(hr)) {
888 IDirect3D9_Release(d3d);
889 return D3DXERR_INVALIDDATA;
891 IDirect3D9_Release(d3d);
893 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ID3DXFontImpl));
894 if(object==NULL) {
895 *font=NULL;
896 return E_OUTOFMEMORY;
898 object->lpVtbl=&D3DXFont_Vtbl;
899 object->ref=1;
900 object->device=device;
901 object->desc=*desc;
903 object->hdc = CreateCompatibleDC(NULL);
904 if( !object->hdc ) {
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;
937 return D3D_OK;