231cdb1790b3ac140c54179d099ab19bd3353484
[reactos.git] / dll / directx / wine / d3dx9_36 / font.c
1 /*
2 * Copyright (C) 2008 Tony Wasserka
3 *
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.
8 *
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.
13 *
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
17 *
18 */
19
20 #include "d3dx9_36_private.h"
21
22 struct d3dx_font
23 {
24 ID3DXFont ID3DXFont_iface;
25 LONG ref;
26
27 IDirect3DDevice9 *device;
28 D3DXFONT_DESCW desc;
29
30 HDC hdc;
31 HFONT hfont;
32
33 UINT tex_width;
34 UINT tex_height;
35 IDirect3DTexture9 *texture;
36 HBITMAP bitmap;
37 BYTE *bits;
38 };
39
40 /* Returns the smallest power of 2 which is greater than or equal to num */
41 static UINT make_pow2(UINT num)
42 {
43 UINT result = 1;
44
45 /* In the unlikely event somebody passes a large value, make sure we don't enter an infinite loop */
46 if (num >= 0x80000000)
47 return 0x80000000;
48
49 while (result < num)
50 result <<= 1;
51
52 return result;
53 }
54
55 static inline struct d3dx_font *impl_from_ID3DXFont(ID3DXFont *iface)
56 {
57 return CONTAINING_RECORD(iface, struct d3dx_font, ID3DXFont_iface);
58 }
59
60 static HRESULT WINAPI ID3DXFontImpl_QueryInterface(ID3DXFont *iface, REFIID riid, void **out)
61 {
62 TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
63
64 if (IsEqualGUID(riid, &IID_ID3DXFont)
65 || IsEqualGUID(riid, &IID_IUnknown))
66 {
67 IUnknown_AddRef(iface);
68 *out = iface;
69 return S_OK;
70 }
71
72 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
73
74 *out = NULL;
75 return E_NOINTERFACE;
76 }
77
78 static ULONG WINAPI ID3DXFontImpl_AddRef(ID3DXFont *iface)
79 {
80 struct d3dx_font *This = impl_from_ID3DXFont(iface);
81 ULONG ref = InterlockedIncrement(&This->ref);
82
83 TRACE("%p increasing refcount to %u\n", iface, ref);
84
85 return ref;
86 }
87
88 static ULONG WINAPI ID3DXFontImpl_Release(ID3DXFont *iface)
89 {
90 struct d3dx_font *This = impl_from_ID3DXFont(iface);
91 ULONG ref = InterlockedDecrement(&This->ref);
92
93 TRACE("%p decreasing refcount to %u\n", iface, ref);
94
95 if (!ref)
96 {
97 if (This->texture)
98 {
99 IDirect3DTexture9_Release(This->texture);
100 DeleteObject(This->bitmap);
101 }
102 DeleteObject(This->hfont);
103 DeleteDC(This->hdc);
104 IDirect3DDevice9_Release(This->device);
105 HeapFree(GetProcessHeap(), 0, This);
106 }
107 return ref;
108 }
109
110 static HRESULT WINAPI ID3DXFontImpl_GetDevice(ID3DXFont *iface, IDirect3DDevice9 **device)
111 {
112 struct d3dx_font *This = impl_from_ID3DXFont(iface);
113
114 TRACE("iface %p, device %p\n", iface, device);
115
116 if( !device ) return D3DERR_INVALIDCALL;
117 *device = This->device;
118 IDirect3DDevice9_AddRef(This->device);
119
120 return D3D_OK;
121 }
122
123 static HRESULT WINAPI ID3DXFontImpl_GetDescA(ID3DXFont *iface, D3DXFONT_DESCA *desc)
124 {
125 struct d3dx_font *This = impl_from_ID3DXFont(iface);
126
127 TRACE("iface %p, desc %p\n", iface, desc);
128
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);
132
133 return D3D_OK;
134 }
135
136 static HRESULT WINAPI ID3DXFontImpl_GetDescW(ID3DXFont *iface, D3DXFONT_DESCW *desc)
137 {
138 struct d3dx_font *This = impl_from_ID3DXFont(iface);
139
140 TRACE("iface %p, desc %p\n", iface, desc);
141
142 if( !desc ) return D3DERR_INVALIDCALL;
143 *desc = This->desc;
144
145 return D3D_OK;
146 }
147
148 static BOOL WINAPI ID3DXFontImpl_GetTextMetricsA(ID3DXFont *iface, TEXTMETRICA *metrics)
149 {
150 struct d3dx_font *This = impl_from_ID3DXFont(iface);
151 TRACE("iface %p, metrics %p\n", iface, metrics);
152 return GetTextMetricsA(This->hdc, metrics);
153 }
154
155 static BOOL WINAPI ID3DXFontImpl_GetTextMetricsW(ID3DXFont *iface, TEXTMETRICW *metrics)
156 {
157 struct d3dx_font *This = impl_from_ID3DXFont(iface);
158 TRACE("iface %p, metrics %p\n", iface, metrics);
159 return GetTextMetricsW(This->hdc, metrics);
160 }
161
162 static HDC WINAPI ID3DXFontImpl_GetDC(ID3DXFont *iface)
163 {
164 struct d3dx_font *This = impl_from_ID3DXFont(iface);
165 TRACE("iface %p\n", iface);
166 return This->hdc;
167 }
168
169 static HRESULT WINAPI ID3DXFontImpl_GetGlyphData(ID3DXFont *iface, UINT glyph,
170 IDirect3DTexture9 **texture, RECT *blackbox, POINT *cellinc)
171 {
172 FIXME("iface %p, glyph %#x, texture %p, blackbox %p, cellinc %p stub!\n",
173 iface, glyph, texture, blackbox, cellinc);
174 return E_NOTIMPL;
175 }
176
177 static HRESULT WINAPI ID3DXFontImpl_PreloadCharacters(ID3DXFont *iface, UINT first, UINT last)
178 {
179 FIXME("iface %p, first %u, last %u stub!\n", iface, first, last);
180 return S_OK;
181 }
182
183 static HRESULT WINAPI ID3DXFontImpl_PreloadGlyphs(ID3DXFont *iface, UINT first, UINT last)
184 {
185 FIXME("iface %p, first %u, last %u stub!\n", iface, first, last);
186 return E_NOTIMPL;
187 }
188
189 static HRESULT WINAPI ID3DXFontImpl_PreloadTextA(ID3DXFont *iface, const char *string, INT count)
190 {
191 FIXME("iface %p, string %s, count %d stub!\n", iface, debugstr_a(string), count);
192 return E_NOTIMPL;
193 }
194
195 static HRESULT WINAPI ID3DXFontImpl_PreloadTextW(ID3DXFont *iface, const WCHAR *string, INT count)
196 {
197 FIXME("iface %p, string %s, count %d stub!\n", iface, debugstr_w(string), count);
198 return E_NOTIMPL;
199 }
200
201 static INT WINAPI ID3DXFontImpl_DrawTextA(ID3DXFont *iface, ID3DXSprite *sprite,
202 const char *string, INT count, RECT *rect, DWORD format, D3DCOLOR color)
203 {
204 LPWSTR stringW;
205 INT countW, ret = 0;
206
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);
209
210 if (!string || count == 0)
211 return 0;
212
213 if (count < 0)
214 count = -1;
215
216 countW = MultiByteToWideChar(CP_ACP, 0, string, count, NULL, 0);
217 stringW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR));
218 if (stringW)
219 {
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);
223 }
224
225 return ret;
226 }
227
228 static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite,
229 const WCHAR *string, INT count, RECT *rect, DWORD format, D3DCOLOR color)
230 {
231 struct d3dx_font *This = impl_from_ID3DXFont(iface);
232 RECT calc_rect;
233 INT height;
234
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);
237
238 if (!string || count == 0)
239 return 0;
240
241 if (count < 0)
242 count = lstrlenW(string);
243
244 /* Strip terminating NULL characters */
245 while (count > 0 && !string[count-1])
246 count--;
247
248 if (rect)
249 calc_rect = *rect;
250
251 height = DrawTextW(This->hdc, string, count, &calc_rect, format | DT_CALCRECT);
252
253 if (format & DT_CALCRECT)
254 {
255 if (rect)
256 *rect = calc_rect;
257 return height;
258 }
259
260 if (format & DT_CENTER)
261 {
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;
265 }
266
267 if (height && (calc_rect.left < calc_rect.right))
268 {
269 D3DLOCKED_RECT locked_rect;
270 D3DXVECTOR3 position;
271 UINT text_width, text_height;
272 RECT text_rect;
273 ID3DXSprite *target = sprite;
274 HRESULT hr;
275 int i, j;
276
277 /* Get rect position and dimensions */
278 position.x = calc_rect.left;
279 position.y = calc_rect.top;
280 position.z = 0;
281 text_width = calc_rect.right - calc_rect.left;
282 text_height = calc_rect.bottom - calc_rect.top;
283 text_rect.left = 0;
284 text_rect.top = 0;
285 text_rect.right = text_width;
286 text_rect.bottom = text_height;
287
288 /* We need to flush as it seems all draws in the begin/end sequence use only the latest updated texture */
289 if (sprite)
290 ID3DXSprite_Flush(sprite);
291
292 /* Extend texture and DIB section to contain text */
293 if ((text_width > This->tex_width) || (text_height > This->tex_height))
294 {
295 BITMAPINFOHEADER header;
296
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);
301
302 if (This->texture)
303 {
304 IDirect3DTexture9_Release(This->texture);
305 DeleteObject(This->bitmap);
306 }
307
308 hr = D3DXCreateTexture(This->device, This->tex_width, This->tex_height, 1, 0,
309 D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &This->texture);
310 if (FAILED(hr))
311 {
312 This->texture = NULL;
313 return 0;
314 }
315
316 header.biSize = sizeof(header);
317 header.biWidth = This->tex_width;
318 header.biHeight = -This->tex_height;
319 header.biPlanes = 1;
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;
327
328 This->bitmap = CreateDIBSection(This->hdc, (const BITMAPINFO*)&header,
329 DIB_RGB_COLORS, (void**)&This->bits, NULL, 0);
330 if (!This->bitmap)
331 {
332 IDirect3DTexture9_Release(This->texture);
333 This->texture = NULL;
334 return 0;
335 }
336
337 SelectObject(This->hdc, This->bitmap);
338 }
339
340 if (FAILED(IDirect3DTexture9_LockRect(This->texture, 0, &locked_rect, &text_rect, D3DLOCK_DISCARD)))
341 return 0;
342
343 /* Clear rect */
344 for (i = 0; i < text_height; i++)
345 memset(This->bits + i * This->tex_width * sizeof(DWORD), 0,
346 text_width * sizeof(DWORD));
347
348 DrawTextW(This->hdc, string, count, &text_rect, format);
349
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++)
353 {
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++)
357 {
358 *dst++ = (*src++ << 24) | 0xFFFFFF;
359 }
360 }
361
362 IDirect3DTexture9_UnlockRect(This->texture, 0);
363
364 if (!sprite)
365 {
366 hr = D3DXCreateSprite(This->device, &target);
367 if (FAILED(hr))
368 return 0;
369 ID3DXSprite_Begin(target, 0);
370 }
371
372 hr = target->lpVtbl->Draw(target, This->texture, &text_rect, NULL, &position, color);
373
374 if (!sprite)
375 {
376 ID3DXSprite_End(target);
377 ID3DXSprite_Release(target);
378 }
379
380 if (FAILED(hr))
381 return 0;
382 }
383
384 return height;
385 }
386
387 static HRESULT WINAPI ID3DXFontImpl_OnLostDevice(ID3DXFont *iface)
388 {
389 FIXME("iface %p stub!\n", iface);
390 return D3D_OK;
391 }
392
393 static HRESULT WINAPI ID3DXFontImpl_OnResetDevice(ID3DXFont *iface)
394 {
395 FIXME("iface %p stub\n", iface);
396 return D3D_OK;
397 }
398
399 static const ID3DXFontVtbl D3DXFont_Vtbl =
400 {
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,
411 ID3DXFontImpl_GetDC,
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
421 };
422
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)
426 {
427 D3DXFONT_DESCA desc;
428
429 if( !device || !font ) return D3DERR_INVALIDCALL;
430
431 desc.Height=height;
432 desc.Width=width;
433 desc.Weight=weight;
434 desc.MipLevels=miplevels;
435 desc.Italic=italic;
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';
442
443 return D3DXCreateFontIndirectA(device, &desc, font);
444 }
445
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)
448 {
449 D3DXFONT_DESCW desc;
450
451 if( !device || !font ) return D3DERR_INVALIDCALL;
452
453 desc.Height=height;
454 desc.Width=width;
455 desc.Weight=weight;
456 desc.MipLevels=miplevels;
457 desc.Italic=italic;
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';
464
465 return D3DXCreateFontIndirectW(device, &desc, font);
466 }
467
468 /***********************************************************************
469 * D3DXCreateFontIndirectA (D3DX9_36.@)
470 */
471 HRESULT WINAPI D3DXCreateFontIndirectA(IDirect3DDevice9 *device, const D3DXFONT_DESCA *desc, ID3DXFont **font)
472 {
473 D3DXFONT_DESCW widedesc;
474
475 if( !device || !desc || !font ) return D3DERR_INVALIDCALL;
476
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);
483 }
484
485 /***********************************************************************
486 * D3DXCreateFontIndirectW (D3DX9_36.@)
487 */
488 HRESULT WINAPI D3DXCreateFontIndirectW(IDirect3DDevice9 *device, const D3DXFONT_DESCW *desc, ID3DXFont **font)
489 {
490 D3DDEVICE_CREATION_PARAMETERS cpars;
491 D3DDISPLAYMODE mode;
492 struct d3dx_font *object;
493 IDirect3D9 *d3d;
494 HRESULT hr;
495
496 TRACE("(%p, %p, %p)\n", device, desc, font);
497
498 if (!device || !desc || !font) return D3DERR_INVALIDCALL;
499
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));
502
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);
508 if (FAILED(hr))
509 {
510 IDirect3D9_Release(d3d);
511 return D3DXERR_INVALIDDATA;
512 }
513 IDirect3D9_Release(d3d);
514
515 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct d3dx_font));
516 if (!object)
517 {
518 *font = NULL;
519 return E_OUTOFMEMORY;
520 }
521 object->ID3DXFont_iface.lpVtbl = &D3DXFont_Vtbl;
522 object->ref = 1;
523 object->device = device;
524 object->desc = *desc;
525
526 object->hdc = CreateCompatibleDC(NULL);
527 if (!object->hdc)
528 {
529 HeapFree(GetProcessHeap(), 0, object);
530 return D3DXERR_INVALIDDATA;
531 }
532
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);
535 if (!object->hfont)
536 {
537 DeleteDC(object->hdc);
538 HeapFree(GetProcessHeap(), 0, object);
539 return D3DXERR_INVALIDDATA;
540 }
541 SelectObject(object->hdc, object->hfont);
542 SetTextColor(object->hdc, 0x00ffffff);
543 SetBkColor(object->hdc, 0x00000000);
544
545 IDirect3DDevice9_AddRef(device);
546 *font = &object->ID3DXFont_iface;
547
548 return D3D_OK;
549 }