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