1 /* 2 * Copyright (C) 2009-2010 Tony Wasserka 3 * Copyright (C) 2012 Józef Kucia 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 18 * 19 */ 20 21 #include "config.h" 22 #include "wine/port.h" 23 24 #include "d3dx9_private.h" 25 26 #include "initguid.h" 27 #include "ole2.h" 28 #include "wincodec.h" 29 30 #include "wine/wined3d.h" 31 32 WINE_DEFAULT_DEBUG_CHANNEL(d3dx); 33 34 35 /* Wine-specific WIC GUIDs */ 36 DEFINE_GUID(GUID_WineContainerFormatTga, 0x0c44fda1,0xa5c5,0x4298,0x96,0x85,0x47,0x3f,0xc1,0x7c,0xd3,0x22); 37 38 static const struct 39 { 40 const GUID *wic_guid; 41 D3DFORMAT d3dformat; 42 } wic_pixel_formats[] = { 43 { &GUID_WICPixelFormat8bppIndexed, D3DFMT_P8 }, 44 { &GUID_WICPixelFormat1bppIndexed, D3DFMT_P8 }, 45 { &GUID_WICPixelFormat4bppIndexed, D3DFMT_P8 }, 46 { &GUID_WICPixelFormat8bppGray, D3DFMT_L8 }, 47 { &GUID_WICPixelFormat16bppBGR555, D3DFMT_X1R5G5B5 }, 48 { &GUID_WICPixelFormat16bppBGR565, D3DFMT_R5G6B5 }, 49 { &GUID_WICPixelFormat24bppBGR, D3DFMT_R8G8B8 }, 50 { &GUID_WICPixelFormat32bppBGR, D3DFMT_X8R8G8B8 }, 51 { &GUID_WICPixelFormat32bppBGRA, D3DFMT_A8R8G8B8 } 52 }; 53 54 static D3DFORMAT wic_guid_to_d3dformat(const GUID *guid) 55 { 56 unsigned int i; 57 58 for (i = 0; i < ARRAY_SIZE(wic_pixel_formats); i++) 59 { 60 if (IsEqualGUID(wic_pixel_formats[i].wic_guid, guid)) 61 return wic_pixel_formats[i].d3dformat; 62 } 63 64 return D3DFMT_UNKNOWN; 65 } 66 67 static const GUID *d3dformat_to_wic_guid(D3DFORMAT format) 68 { 69 unsigned int i; 70 71 for (i = 0; i < ARRAY_SIZE(wic_pixel_formats); i++) 72 { 73 if (wic_pixel_formats[i].d3dformat == format) 74 return wic_pixel_formats[i].wic_guid; 75 } 76 77 return NULL; 78 } 79 80 /* dds_header.flags */ 81 #define DDS_CAPS 0x1 82 #define DDS_HEIGHT 0x2 83 #define DDS_WIDTH 0x4 84 #define DDS_PITCH 0x8 85 #define DDS_PIXELFORMAT 0x1000 86 #define DDS_MIPMAPCOUNT 0x20000 87 #define DDS_LINEARSIZE 0x80000 88 #define DDS_DEPTH 0x800000 89 90 /* dds_header.caps */ 91 #define DDS_CAPS_COMPLEX 0x8 92 #define DDS_CAPS_TEXTURE 0x1000 93 #define DDS_CAPS_MIPMAP 0x400000 94 95 /* dds_header.caps2 */ 96 #define DDS_CAPS2_CUBEMAP 0x200 97 #define DDS_CAPS2_CUBEMAP_POSITIVEX 0x400 98 #define DDS_CAPS2_CUBEMAP_NEGATIVEX 0x800 99 #define DDS_CAPS2_CUBEMAP_POSITIVEY 0x1000 100 #define DDS_CAPS2_CUBEMAP_NEGATIVEY 0x2000 101 #define DDS_CAPS2_CUBEMAP_POSITIVEZ 0x4000 102 #define DDS_CAPS2_CUBEMAP_NEGATIVEZ 0x8000 103 #define DDS_CAPS2_CUBEMAP_ALL_FACES ( DDS_CAPS2_CUBEMAP_POSITIVEX | DDS_CAPS2_CUBEMAP_NEGATIVEX \ 104 | DDS_CAPS2_CUBEMAP_POSITIVEY | DDS_CAPS2_CUBEMAP_NEGATIVEY \ 105 | DDS_CAPS2_CUBEMAP_POSITIVEZ | DDS_CAPS2_CUBEMAP_NEGATIVEZ ) 106 #define DDS_CAPS2_VOLUME 0x200000 107 108 /* dds_pixel_format.flags */ 109 #define DDS_PF_ALPHA 0x1 110 #define DDS_PF_ALPHA_ONLY 0x2 111 #define DDS_PF_FOURCC 0x4 112 #define DDS_PF_RGB 0x40 113 #define DDS_PF_YUV 0x200 114 #define DDS_PF_LUMINANCE 0x20000 115 #define DDS_PF_BUMPLUMINANCE 0x40000 116 #define DDS_PF_BUMPDUDV 0x80000 117 118 struct dds_pixel_format 119 { 120 DWORD size; 121 DWORD flags; 122 DWORD fourcc; 123 DWORD bpp; 124 DWORD rmask; 125 DWORD gmask; 126 DWORD bmask; 127 DWORD amask; 128 }; 129 130 struct dds_header 131 { 132 DWORD signature; 133 DWORD size; 134 DWORD flags; 135 DWORD height; 136 DWORD width; 137 DWORD pitch_or_linear_size; 138 DWORD depth; 139 DWORD miplevels; 140 DWORD reserved[11]; 141 struct dds_pixel_format pixel_format; 142 DWORD caps; 143 DWORD caps2; 144 DWORD caps3; 145 DWORD caps4; 146 DWORD reserved2; 147 }; 148 149 static D3DFORMAT dds_fourcc_to_d3dformat(DWORD fourcc) 150 { 151 unsigned int i; 152 static const DWORD known_fourcc[] = { 153 D3DFMT_UYVY, 154 D3DFMT_YUY2, 155 D3DFMT_R8G8_B8G8, 156 D3DFMT_G8R8_G8B8, 157 D3DFMT_DXT1, 158 D3DFMT_DXT2, 159 D3DFMT_DXT3, 160 D3DFMT_DXT4, 161 D3DFMT_DXT5, 162 D3DFMT_R16F, 163 D3DFMT_G16R16F, 164 D3DFMT_A16B16G16R16F, 165 D3DFMT_R32F, 166 D3DFMT_G32R32F, 167 D3DFMT_A32B32G32R32F, 168 }; 169 170 for (i = 0; i < ARRAY_SIZE(known_fourcc); i++) 171 { 172 if (known_fourcc[i] == fourcc) 173 return fourcc; 174 } 175 176 WARN("Unknown FourCC %#x\n", fourcc); 177 return D3DFMT_UNKNOWN; 178 } 179 180 static const struct { 181 DWORD bpp; 182 DWORD rmask; 183 DWORD gmask; 184 DWORD bmask; 185 DWORD amask; 186 D3DFORMAT format; 187 } rgb_pixel_formats[] = { 188 { 8, 0xe0, 0x1c, 0x03, 0, D3DFMT_R3G3B2 }, 189 { 16, 0xf800, 0x07e0, 0x001f, 0x0000, D3DFMT_R5G6B5 }, 190 { 16, 0x7c00, 0x03e0, 0x001f, 0x8000, D3DFMT_A1R5G5B5 }, 191 { 16, 0x7c00, 0x03e0, 0x001f, 0x0000, D3DFMT_X1R5G5B5 }, 192 { 16, 0x0f00, 0x00f0, 0x000f, 0xf000, D3DFMT_A4R4G4B4 }, 193 { 16, 0x0f00, 0x00f0, 0x000f, 0x0000, D3DFMT_X4R4G4B4 }, 194 { 16, 0x00e0, 0x001c, 0x0003, 0xff00, D3DFMT_A8R3G3B2 }, 195 { 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000, D3DFMT_R8G8B8 }, 196 { 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000, D3DFMT_A8R8G8B8 }, 197 { 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000, D3DFMT_X8R8G8B8 }, 198 { 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000, D3DFMT_A2B10G10R10 }, 199 { 32, 0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000, D3DFMT_A2R10G10B10 }, 200 { 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000, D3DFMT_G16R16 }, 201 { 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000, D3DFMT_A8B8G8R8 }, 202 { 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000, D3DFMT_X8B8G8R8 }, 203 }; 204 205 static D3DFORMAT dds_rgb_to_d3dformat(const struct dds_pixel_format *pixel_format) 206 { 207 unsigned int i; 208 209 for (i = 0; i < ARRAY_SIZE(rgb_pixel_formats); i++) 210 { 211 if (rgb_pixel_formats[i].bpp == pixel_format->bpp 212 && rgb_pixel_formats[i].rmask == pixel_format->rmask 213 && rgb_pixel_formats[i].gmask == pixel_format->gmask 214 && rgb_pixel_formats[i].bmask == pixel_format->bmask) 215 { 216 if ((pixel_format->flags & DDS_PF_ALPHA) && rgb_pixel_formats[i].amask == pixel_format->amask) 217 return rgb_pixel_formats[i].format; 218 if (rgb_pixel_formats[i].amask == 0) 219 return rgb_pixel_formats[i].format; 220 } 221 } 222 223 WARN("Unknown RGB pixel format (%#x, %#x, %#x, %#x)\n", 224 pixel_format->rmask, pixel_format->gmask, pixel_format->bmask, pixel_format->amask); 225 return D3DFMT_UNKNOWN; 226 } 227 228 static D3DFORMAT dds_luminance_to_d3dformat(const struct dds_pixel_format *pixel_format) 229 { 230 if (pixel_format->bpp == 8) 231 { 232 if (pixel_format->rmask == 0xff) 233 return D3DFMT_L8; 234 if ((pixel_format->flags & DDS_PF_ALPHA) && pixel_format->rmask == 0x0f && pixel_format->amask == 0xf0) 235 return D3DFMT_A4L4; 236 } 237 if (pixel_format->bpp == 16) 238 { 239 if (pixel_format->rmask == 0xffff) 240 return D3DFMT_L16; 241 if ((pixel_format->flags & DDS_PF_ALPHA) && pixel_format->rmask == 0x00ff && pixel_format->amask == 0xff00) 242 return D3DFMT_A8L8; 243 } 244 245 WARN("Unknown luminance pixel format (bpp %u, l %#x, a %#x)\n", 246 pixel_format->bpp, pixel_format->rmask, pixel_format->amask); 247 return D3DFMT_UNKNOWN; 248 } 249 250 static D3DFORMAT dds_alpha_to_d3dformat(const struct dds_pixel_format *pixel_format) 251 { 252 if (pixel_format->bpp == 8 && pixel_format->amask == 0xff) 253 return D3DFMT_A8; 254 255 WARN("Unknown Alpha pixel format (%u, %#x)\n", pixel_format->bpp, pixel_format->rmask); 256 return D3DFMT_UNKNOWN; 257 } 258 259 static D3DFORMAT dds_bump_to_d3dformat(const struct dds_pixel_format *pixel_format) 260 { 261 if (pixel_format->bpp == 16 && pixel_format->rmask == 0x00ff && pixel_format->gmask == 0xff00) 262 return D3DFMT_V8U8; 263 if (pixel_format->bpp == 32 && pixel_format->rmask == 0x0000ffff && pixel_format->gmask == 0xffff0000) 264 return D3DFMT_V16U16; 265 266 WARN("Unknown bump pixel format (%u, %#x, %#x, %#x, %#x)\n", pixel_format->bpp, 267 pixel_format->rmask, pixel_format->gmask, pixel_format->bmask, pixel_format->amask); 268 return D3DFMT_UNKNOWN; 269 } 270 271 static D3DFORMAT dds_bump_luminance_to_d3dformat(const struct dds_pixel_format *pixel_format) 272 { 273 if (pixel_format->bpp == 32 && pixel_format->rmask == 0x000000ff && pixel_format->gmask == 0x0000ff00 274 && pixel_format->bmask == 0x00ff0000) 275 return D3DFMT_X8L8V8U8; 276 277 WARN("Unknown bump pixel format (%u, %#x, %#x, %#x, %#x)\n", pixel_format->bpp, 278 pixel_format->rmask, pixel_format->gmask, pixel_format->bmask, pixel_format->amask); 279 return D3DFMT_UNKNOWN; 280 } 281 282 static D3DFORMAT dds_pixel_format_to_d3dformat(const struct dds_pixel_format *pixel_format) 283 { 284 TRACE("pixel_format: size %u, flags %#x, fourcc %#x, bpp %u.\n", pixel_format->size, 285 pixel_format->flags, pixel_format->fourcc, pixel_format->bpp); 286 TRACE("rmask %#x, gmask %#x, bmask %#x, amask %#x.\n", pixel_format->rmask, pixel_format->gmask, 287 pixel_format->bmask, pixel_format->amask); 288 289 if (pixel_format->flags & DDS_PF_FOURCC) 290 return dds_fourcc_to_d3dformat(pixel_format->fourcc); 291 if (pixel_format->flags & DDS_PF_RGB) 292 return dds_rgb_to_d3dformat(pixel_format); 293 if (pixel_format->flags & DDS_PF_LUMINANCE) 294 return dds_luminance_to_d3dformat(pixel_format); 295 if (pixel_format->flags & DDS_PF_ALPHA_ONLY) 296 return dds_alpha_to_d3dformat(pixel_format); 297 if (pixel_format->flags & DDS_PF_BUMPDUDV) 298 return dds_bump_to_d3dformat(pixel_format); 299 if (pixel_format->flags & DDS_PF_BUMPLUMINANCE) 300 return dds_bump_luminance_to_d3dformat(pixel_format); 301 302 WARN("Unknown pixel format (flags %#x, fourcc %#x, bpp %u, r %#x, g %#x, b %#x, a %#x)\n", 303 pixel_format->flags, pixel_format->fourcc, pixel_format->bpp, 304 pixel_format->rmask, pixel_format->gmask, pixel_format->bmask, pixel_format->amask); 305 return D3DFMT_UNKNOWN; 306 } 307 308 static HRESULT d3dformat_to_dds_pixel_format(struct dds_pixel_format *pixel_format, D3DFORMAT d3dformat) 309 { 310 unsigned int i; 311 312 memset(pixel_format, 0, sizeof(*pixel_format)); 313 314 pixel_format->size = sizeof(*pixel_format); 315 316 for (i = 0; i < ARRAY_SIZE(rgb_pixel_formats); i++) 317 { 318 if (rgb_pixel_formats[i].format == d3dformat) 319 { 320 pixel_format->flags |= DDS_PF_RGB; 321 pixel_format->bpp = rgb_pixel_formats[i].bpp; 322 pixel_format->rmask = rgb_pixel_formats[i].rmask; 323 pixel_format->gmask = rgb_pixel_formats[i].gmask; 324 pixel_format->bmask = rgb_pixel_formats[i].bmask; 325 pixel_format->amask = rgb_pixel_formats[i].amask; 326 if (pixel_format->amask) pixel_format->flags |= DDS_PF_ALPHA; 327 return D3D_OK; 328 } 329 } 330 331 /* Reuse dds_fourcc_to_d3dformat as D3DFORMAT and FOURCC are DWORD with same values */ 332 if (dds_fourcc_to_d3dformat(d3dformat) != D3DFMT_UNKNOWN) 333 { 334 pixel_format->flags |= DDS_PF_FOURCC; 335 pixel_format->fourcc = d3dformat; 336 return D3D_OK; 337 } 338 339 WARN("Unknown pixel format %#x\n", d3dformat); 340 return E_NOTIMPL; 341 } 342 343 static HRESULT calculate_dds_surface_size(D3DFORMAT format, UINT width, UINT height, 344 UINT *pitch, UINT *size) 345 { 346 const struct pixel_format_desc *format_desc = get_format_info(format); 347 if (format_desc->type == FORMAT_UNKNOWN) 348 return E_NOTIMPL; 349 350 if (format_desc->block_width != 1 || format_desc->block_height != 1) 351 { 352 *pitch = format_desc->block_byte_count 353 * max(1, (width + format_desc->block_width - 1) / format_desc->block_width); 354 *size = *pitch 355 * max(1, (height + format_desc->block_height - 1) / format_desc->block_height); 356 } 357 else 358 { 359 *pitch = width * format_desc->bytes_per_pixel; 360 *size = *pitch * height; 361 } 362 363 return D3D_OK; 364 } 365 366 static UINT calculate_dds_file_size(D3DFORMAT format, UINT width, UINT height, UINT depth, 367 UINT miplevels, UINT faces) 368 { 369 UINT i, file_size = 0; 370 371 for (i = 0; i < miplevels; i++) 372 { 373 UINT pitch, size = 0; 374 calculate_dds_surface_size(format, width, height, &pitch, &size); 375 size *= depth; 376 file_size += size; 377 width = max(1, width / 2); 378 height = max(1, height / 2); 379 depth = max(1, depth / 2); 380 } 381 382 file_size *= faces; 383 file_size += sizeof(struct dds_header); 384 return file_size; 385 } 386 387 /************************************************************ 388 * get_image_info_from_dds 389 * 390 * Fills a D3DXIMAGE_INFO structure with information 391 * about a DDS file stored in the memory. 392 * 393 * PARAMS 394 * buffer [I] pointer to DDS data 395 * length [I] size of DDS data 396 * info [O] pointer to D3DXIMAGE_INFO structure 397 * 398 * RETURNS 399 * Success: D3D_OK 400 * Failure: D3DXERR_INVALIDDATA 401 * 402 */ 403 static HRESULT get_image_info_from_dds(const void *buffer, UINT length, D3DXIMAGE_INFO *info) 404 { 405 UINT faces = 1; 406 UINT expected_length; 407 const struct dds_header *header = buffer; 408 409 if (length < sizeof(*header) || !info) 410 return D3DXERR_INVALIDDATA; 411 412 if (header->pixel_format.size != sizeof(header->pixel_format)) 413 return D3DXERR_INVALIDDATA; 414 415 info->Width = header->width; 416 info->Height = header->height; 417 info->Depth = 1; 418 info->MipLevels = header->miplevels ? header->miplevels : 1; 419 420 info->Format = dds_pixel_format_to_d3dformat(&header->pixel_format); 421 if (info->Format == D3DFMT_UNKNOWN) 422 return D3DXERR_INVALIDDATA; 423 424 TRACE("Pixel format is %#x\n", info->Format); 425 426 if (header->caps2 & DDS_CAPS2_VOLUME) 427 { 428 info->Depth = header->depth; 429 info->ResourceType = D3DRTYPE_VOLUMETEXTURE; 430 } 431 else if (header->caps2 & DDS_CAPS2_CUBEMAP) 432 { 433 DWORD face; 434 faces = 0; 435 for (face = DDS_CAPS2_CUBEMAP_POSITIVEX; face <= DDS_CAPS2_CUBEMAP_NEGATIVEZ; face <<= 1) 436 { 437 if (header->caps2 & face) 438 faces++; 439 } 440 info->ResourceType = D3DRTYPE_CUBETEXTURE; 441 } 442 else 443 { 444 info->ResourceType = D3DRTYPE_TEXTURE; 445 } 446 447 expected_length = calculate_dds_file_size(info->Format, info->Width, info->Height, info->Depth, 448 info->MipLevels, faces); 449 if (length < expected_length) 450 { 451 WARN("File is too short %u, expected at least %u bytes\n", length, expected_length); 452 return D3DXERR_INVALIDDATA; 453 } 454 455 info->ImageFileFormat = D3DXIFF_DDS; 456 return D3D_OK; 457 } 458 459 static HRESULT load_surface_from_dds(IDirect3DSurface9 *dst_surface, const PALETTEENTRY *dst_palette, 460 const RECT *dst_rect, const void *src_data, const RECT *src_rect, DWORD filter, D3DCOLOR color_key, 461 const D3DXIMAGE_INFO *src_info) 462 { 463 UINT size; 464 UINT src_pitch; 465 const struct dds_header *header = src_data; 466 const BYTE *pixels = (BYTE *)(header + 1); 467 468 if (src_info->ResourceType != D3DRTYPE_TEXTURE) 469 return D3DXERR_INVALIDDATA; 470 471 if (FAILED(calculate_dds_surface_size(src_info->Format, src_info->Width, src_info->Height, &src_pitch, &size))) 472 return E_NOTIMPL; 473 474 return D3DXLoadSurfaceFromMemory(dst_surface, dst_palette, dst_rect, pixels, src_info->Format, 475 src_pitch, NULL, src_rect, filter, color_key); 476 } 477 478 static HRESULT save_dds_surface_to_memory(ID3DXBuffer **dst_buffer, IDirect3DSurface9 *src_surface, const RECT *src_rect) 479 { 480 HRESULT hr; 481 UINT dst_pitch, surface_size, file_size; 482 D3DSURFACE_DESC src_desc; 483 D3DLOCKED_RECT locked_rect; 484 ID3DXBuffer *buffer; 485 struct dds_header *header; 486 BYTE *pixels; 487 struct volume volume; 488 const struct pixel_format_desc *pixel_format; 489 490 if (src_rect) 491 { 492 FIXME("Saving a part of a surface to a DDS file is not implemented yet\n"); 493 return E_NOTIMPL; 494 } 495 496 hr = IDirect3DSurface9_GetDesc(src_surface, &src_desc); 497 if (FAILED(hr)) return hr; 498 499 pixel_format = get_format_info(src_desc.Format); 500 if (pixel_format->type == FORMAT_UNKNOWN) return E_NOTIMPL; 501 502 file_size = calculate_dds_file_size(src_desc.Format, src_desc.Width, src_desc.Height, 1, 1, 1); 503 504 hr = calculate_dds_surface_size(src_desc.Format, src_desc.Width, src_desc.Height, &dst_pitch, &surface_size); 505 if (FAILED(hr)) return hr; 506 507 hr = D3DXCreateBuffer(file_size, &buffer); 508 if (FAILED(hr)) return hr; 509 510 header = ID3DXBuffer_GetBufferPointer(buffer); 511 pixels = (BYTE *)(header + 1); 512 513 memset(header, 0, sizeof(*header)); 514 header->signature = MAKEFOURCC('D','D','S',' '); 515 /* The signature is not really part of the DDS header */ 516 header->size = sizeof(*header) - FIELD_OFFSET(struct dds_header, size); 517 header->flags = DDS_CAPS | DDS_HEIGHT | DDS_WIDTH | DDS_PIXELFORMAT; 518 header->height = src_desc.Height; 519 header->width = src_desc.Width; 520 header->caps = DDS_CAPS_TEXTURE; 521 hr = d3dformat_to_dds_pixel_format(&header->pixel_format, src_desc.Format); 522 if (FAILED(hr)) 523 { 524 ID3DXBuffer_Release(buffer); 525 return hr; 526 } 527 528 hr = IDirect3DSurface9_LockRect(src_surface, &locked_rect, NULL, D3DLOCK_READONLY); 529 if (FAILED(hr)) 530 { 531 ID3DXBuffer_Release(buffer); 532 return hr; 533 } 534 535 volume.width = src_desc.Width; 536 volume.height = src_desc.Height; 537 volume.depth = 1; 538 copy_pixels(locked_rect.pBits, locked_rect.Pitch, 0, pixels, dst_pitch, 0, 539 &volume, pixel_format); 540 541 IDirect3DSurface9_UnlockRect(src_surface); 542 543 *dst_buffer = buffer; 544 return D3D_OK; 545 } 546 547 static HRESULT get_surface(D3DRESOURCETYPE type, struct IDirect3DBaseTexture9 *tex, 548 int face, UINT level, struct IDirect3DSurface9 **surf) 549 { 550 switch (type) 551 { 552 case D3DRTYPE_TEXTURE: 553 return IDirect3DTexture9_GetSurfaceLevel((IDirect3DTexture9*) tex, level, surf); 554 case D3DRTYPE_CUBETEXTURE: 555 return IDirect3DCubeTexture9_GetCubeMapSurface((IDirect3DCubeTexture9*) tex, face, level, surf); 556 default: 557 ERR("Unexpected texture type\n"); 558 return E_NOTIMPL; 559 } 560 } 561 562 HRESULT save_dds_texture_to_memory(ID3DXBuffer **dst_buffer, IDirect3DBaseTexture9 *src_texture, const PALETTEENTRY *src_palette) 563 { 564 HRESULT hr; 565 D3DRESOURCETYPE type; 566 UINT mip_levels; 567 IDirect3DSurface9 *surface; 568 569 type = IDirect3DBaseTexture9_GetType(src_texture); 570 571 if ((type != D3DRTYPE_TEXTURE) && (type != D3DRTYPE_CUBETEXTURE) && (type != D3DRTYPE_VOLUMETEXTURE)) 572 return D3DERR_INVALIDCALL; 573 574 if (type == D3DRTYPE_CUBETEXTURE) 575 { 576 FIXME("Cube texture not supported yet\n"); 577 return E_NOTIMPL; 578 } 579 else if (type == D3DRTYPE_VOLUMETEXTURE) 580 { 581 FIXME("Volume texture not supported yet\n"); 582 return E_NOTIMPL; 583 } 584 585 mip_levels = IDirect3DTexture9_GetLevelCount(src_texture); 586 587 if (mip_levels > 1) 588 { 589 FIXME("Mipmap not supported yet\n"); 590 return E_NOTIMPL; 591 } 592 593 if (src_palette) 594 { 595 FIXME("Saving surfaces with palettized pixel formats not implemented yet\n"); 596 return E_NOTIMPL; 597 } 598 599 hr = get_surface(type, src_texture, D3DCUBEMAP_FACE_POSITIVE_X, 0, &surface); 600 601 if (SUCCEEDED(hr)) 602 { 603 hr = save_dds_surface_to_memory(dst_buffer, surface, NULL); 604 IDirect3DSurface9_Release(surface); 605 } 606 607 return hr; 608 } 609 HRESULT load_volume_from_dds(IDirect3DVolume9 *dst_volume, const PALETTEENTRY *dst_palette, 610 const D3DBOX *dst_box, const void *src_data, const D3DBOX *src_box, DWORD filter, D3DCOLOR color_key, 611 const D3DXIMAGE_INFO *src_info) 612 { 613 UINT row_pitch, slice_pitch; 614 const struct dds_header *header = src_data; 615 const BYTE *pixels = (BYTE *)(header + 1); 616 617 if (src_info->ResourceType != D3DRTYPE_VOLUMETEXTURE) 618 return D3DXERR_INVALIDDATA; 619 620 if (FAILED(calculate_dds_surface_size(src_info->Format, src_info->Width, src_info->Height, &row_pitch, &slice_pitch))) 621 return E_NOTIMPL; 622 623 return D3DXLoadVolumeFromMemory(dst_volume, dst_palette, dst_box, pixels, src_info->Format, 624 row_pitch, slice_pitch, NULL, src_box, filter, color_key); 625 } 626 627 HRESULT load_texture_from_dds(IDirect3DTexture9 *texture, const void *src_data, const PALETTEENTRY *palette, 628 DWORD filter, D3DCOLOR color_key, const D3DXIMAGE_INFO *src_info, unsigned int skip_levels, 629 unsigned int *loaded_miplevels) 630 { 631 HRESULT hr; 632 RECT src_rect; 633 UINT src_pitch; 634 UINT mip_level; 635 UINT mip_levels; 636 UINT mip_level_size; 637 UINT width, height; 638 IDirect3DSurface9 *surface; 639 const struct dds_header *header = src_data; 640 const BYTE *pixels = (BYTE *)(header + 1); 641 642 /* Loading a cube texture as a simple texture is also supported 643 * (only first face texture is taken). Same with volume textures. */ 644 if ((src_info->ResourceType != D3DRTYPE_TEXTURE) 645 && (src_info->ResourceType != D3DRTYPE_CUBETEXTURE) 646 && (src_info->ResourceType != D3DRTYPE_VOLUMETEXTURE)) 647 { 648 WARN("Trying to load a %u resource as a 2D texture, returning failure.\n", src_info->ResourceType); 649 return D3DXERR_INVALIDDATA; 650 } 651 652 width = src_info->Width; 653 height = src_info->Height; 654 mip_levels = min(src_info->MipLevels, IDirect3DTexture9_GetLevelCount(texture)); 655 if (src_info->ResourceType == D3DRTYPE_VOLUMETEXTURE) 656 mip_levels = 1; 657 for (mip_level = 0; mip_level < mip_levels + skip_levels; ++mip_level) 658 { 659 hr = calculate_dds_surface_size(src_info->Format, width, height, &src_pitch, &mip_level_size); 660 if (FAILED(hr)) return hr; 661 662 if (mip_level >= skip_levels) 663 { 664 SetRect(&src_rect, 0, 0, width, height); 665 666 IDirect3DTexture9_GetSurfaceLevel(texture, mip_level - skip_levels, &surface); 667 hr = D3DXLoadSurfaceFromMemory(surface, palette, NULL, pixels, src_info->Format, src_pitch, 668 NULL, &src_rect, filter, color_key); 669 IDirect3DSurface9_Release(surface); 670 if (FAILED(hr)) 671 return hr; 672 } 673 674 pixels += mip_level_size; 675 width = max(1, width / 2); 676 height = max(1, height / 2); 677 } 678 679 *loaded_miplevels = mip_levels - skip_levels; 680 681 return D3D_OK; 682 } 683 684 HRESULT load_cube_texture_from_dds(IDirect3DCubeTexture9 *cube_texture, const void *src_data, 685 const PALETTEENTRY *palette, DWORD filter, DWORD color_key, const D3DXIMAGE_INFO *src_info) 686 { 687 HRESULT hr; 688 int face; 689 UINT mip_level; 690 UINT size; 691 RECT src_rect; 692 UINT src_pitch; 693 UINT mip_levels; 694 UINT mip_level_size; 695 IDirect3DSurface9 *surface; 696 const struct dds_header *header = src_data; 697 const BYTE *pixels = (BYTE *)(header + 1); 698 699 if (src_info->ResourceType != D3DRTYPE_CUBETEXTURE) 700 return D3DXERR_INVALIDDATA; 701 702 if ((header->caps2 & DDS_CAPS2_CUBEMAP_ALL_FACES) != DDS_CAPS2_CUBEMAP_ALL_FACES) 703 { 704 WARN("Only full cubemaps are supported\n"); 705 return D3DXERR_INVALIDDATA; 706 } 707 708 mip_levels = min(src_info->MipLevels, IDirect3DCubeTexture9_GetLevelCount(cube_texture)); 709 for (face = D3DCUBEMAP_FACE_POSITIVE_X; face <= D3DCUBEMAP_FACE_NEGATIVE_Z; face++) 710 { 711 size = src_info->Width; 712 for (mip_level = 0; mip_level < src_info->MipLevels; mip_level++) 713 { 714 hr = calculate_dds_surface_size(src_info->Format, size, size, &src_pitch, &mip_level_size); 715 if (FAILED(hr)) return hr; 716 717 /* if texture has fewer mip levels than DDS file, skip excessive mip levels */ 718 if (mip_level < mip_levels) 719 { 720 SetRect(&src_rect, 0, 0, size, size); 721 722 IDirect3DCubeTexture9_GetCubeMapSurface(cube_texture, face, mip_level, &surface); 723 hr = D3DXLoadSurfaceFromMemory(surface, palette, NULL, pixels, src_info->Format, src_pitch, 724 NULL, &src_rect, filter, color_key); 725 IDirect3DSurface9_Release(surface); 726 if (FAILED(hr)) return hr; 727 } 728 729 pixels += mip_level_size; 730 size = max(1, size / 2); 731 } 732 } 733 734 return D3D_OK; 735 } 736 737 HRESULT load_volume_texture_from_dds(IDirect3DVolumeTexture9 *volume_texture, const void *src_data, 738 const PALETTEENTRY *palette, DWORD filter, DWORD color_key, const D3DXIMAGE_INFO *src_info) 739 { 740 HRESULT hr; 741 UINT mip_level; 742 UINT mip_levels; 743 UINT src_slice_pitch; 744 UINT src_row_pitch; 745 D3DBOX src_box; 746 UINT width, height, depth; 747 IDirect3DVolume9 *volume; 748 const struct dds_header *header = src_data; 749 const BYTE *pixels = (BYTE *)(header + 1); 750 751 if (src_info->ResourceType != D3DRTYPE_VOLUMETEXTURE) 752 return D3DXERR_INVALIDDATA; 753 754 width = src_info->Width; 755 height = src_info->Height; 756 depth = src_info->Depth; 757 mip_levels = min(src_info->MipLevels, IDirect3DVolumeTexture9_GetLevelCount(volume_texture)); 758 759 for (mip_level = 0; mip_level < mip_levels; mip_level++) 760 { 761 hr = calculate_dds_surface_size(src_info->Format, width, height, &src_row_pitch, &src_slice_pitch); 762 if (FAILED(hr)) return hr; 763 764 hr = IDirect3DVolumeTexture9_GetVolumeLevel(volume_texture, mip_level, &volume); 765 if (FAILED(hr)) return hr; 766 767 src_box.Left = 0; 768 src_box.Top = 0; 769 src_box.Right = width; 770 src_box.Bottom = height; 771 src_box.Front = 0; 772 src_box.Back = depth; 773 774 hr = D3DXLoadVolumeFromMemory(volume, palette, NULL, pixels, src_info->Format, 775 src_row_pitch, src_slice_pitch, NULL, &src_box, filter, color_key); 776 777 IDirect3DVolume9_Release(volume); 778 if (FAILED(hr)) return hr; 779 780 pixels += depth * src_slice_pitch; 781 width = max(1, width / 2); 782 height = max(1, height / 2); 783 depth = max(1, depth / 2); 784 } 785 786 return D3D_OK; 787 } 788 789 static BOOL convert_dib_to_bmp(void **data, UINT *size) 790 { 791 ULONG header_size; 792 ULONG count = 0; 793 ULONG offset; 794 BITMAPFILEHEADER *header; 795 BYTE *new_data; 796 UINT new_size; 797 798 if ((*size < 4) || (*size < (header_size = *(ULONG*)*data))) 799 return FALSE; 800 801 if ((header_size == sizeof(BITMAPINFOHEADER)) || 802 (header_size == sizeof(BITMAPV4HEADER)) || 803 (header_size == sizeof(BITMAPV5HEADER)) || 804 (header_size == 64 /* sizeof(BITMAPCOREHEADER2) */)) 805 { 806 /* All structures begin with the same memory layout as BITMAPINFOHEADER */ 807 BITMAPINFOHEADER *info_header = (BITMAPINFOHEADER*)*data; 808 count = info_header->biClrUsed; 809 810 if (!count && info_header->biBitCount <= 8) 811 count = 1 << info_header->biBitCount; 812 813 offset = sizeof(BITMAPFILEHEADER) + header_size + sizeof(RGBQUAD) * count; 814 815 /* For BITMAPINFOHEADER with BI_BITFIELDS compression, there are 3 additional color masks after header */ 816 if ((info_header->biSize == sizeof(BITMAPINFOHEADER)) && (info_header->biCompression == BI_BITFIELDS)) 817 offset += 3 * sizeof(DWORD); 818 } 819 else if (header_size == sizeof(BITMAPCOREHEADER)) 820 { 821 BITMAPCOREHEADER *core_header = (BITMAPCOREHEADER*)*data; 822 823 if (core_header->bcBitCount <= 8) 824 count = 1 << core_header->bcBitCount; 825 826 offset = sizeof(BITMAPFILEHEADER) + header_size + sizeof(RGBTRIPLE) * count; 827 } 828 else 829 { 830 return FALSE; 831 } 832 833 TRACE("Converting DIB file to BMP\n"); 834 835 new_size = *size + sizeof(BITMAPFILEHEADER); 836 new_data = HeapAlloc(GetProcessHeap(), 0, new_size); 837 CopyMemory(new_data + sizeof(BITMAPFILEHEADER), *data, *size); 838 839 /* Add BMP header */ 840 header = (BITMAPFILEHEADER*)new_data; 841 header->bfType = 0x4d42; /* BM */ 842 header->bfSize = new_size; 843 header->bfReserved1 = 0; 844 header->bfReserved2 = 0; 845 header->bfOffBits = offset; 846 847 /* Update input data */ 848 *data = new_data; 849 *size = new_size; 850 851 return TRUE; 852 } 853 854 /************************************************************ 855 * D3DXGetImageInfoFromFileInMemory 856 * 857 * Fills a D3DXIMAGE_INFO structure with info about an image 858 * 859 * PARAMS 860 * data [I] pointer to the image file data 861 * datasize [I] size of the passed data 862 * info [O] pointer to the destination structure 863 * 864 * RETURNS 865 * Success: D3D_OK, if info is not NULL and data and datasize make up a valid image file or 866 * if info is NULL and data and datasize are not NULL 867 * Failure: D3DXERR_INVALIDDATA, if data is no valid image file and datasize and info are not NULL 868 * D3DERR_INVALIDCALL, if data is NULL or 869 * if datasize is 0 870 * 871 * NOTES 872 * datasize may be bigger than the actual file size 873 * 874 */ 875 HRESULT WINAPI D3DXGetImageInfoFromFileInMemory(const void *data, UINT datasize, D3DXIMAGE_INFO *info) 876 { 877 IWICImagingFactory *factory; 878 IWICBitmapDecoder *decoder = NULL; 879 IWICStream *stream; 880 HRESULT hr; 881 HRESULT initresult; 882 BOOL dib; 883 884 TRACE("(%p, %d, %p)\n", data, datasize, info); 885 886 if (!data || !datasize) 887 return D3DERR_INVALIDCALL; 888 889 if (!info) 890 return D3D_OK; 891 892 if ((datasize >= 4) && !strncmp(data, "DDS ", 4)) { 893 TRACE("File type is DDS\n"); 894 return get_image_info_from_dds(data, datasize, info); 895 } 896 897 /* In case of DIB file, convert it to BMP */ 898 dib = convert_dib_to_bmp((void**)&data, &datasize); 899 900 initresult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); 901 902 hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, &IID_IWICImagingFactory, (void**)&factory); 903 904 if (SUCCEEDED(hr)) { 905 IWICImagingFactory_CreateStream(factory, &stream); 906 IWICStream_InitializeFromMemory(stream, (BYTE*)data, datasize); 907 hr = IWICImagingFactory_CreateDecoderFromStream(factory, (IStream*)stream, NULL, 0, &decoder); 908 IWICStream_Release(stream); 909 IWICImagingFactory_Release(factory); 910 } 911 912 if (FAILED(hr)) { 913 if ((datasize >= 2) && (!strncmp(data, "P3", 2) || !strncmp(data, "P6", 2))) 914 FIXME("File type PPM is not supported yet\n"); 915 else if ((datasize >= 10) && !strncmp(data, "#?RADIANCE", 10)) 916 FIXME("File type HDR is not supported yet\n"); 917 else if ((datasize >= 2) && (!strncmp(data, "PF", 2) || !strncmp(data, "Pf", 2))) 918 FIXME("File type PFM is not supported yet\n"); 919 } 920 921 if (SUCCEEDED(hr)) { 922 GUID container_format; 923 UINT frame_count; 924 925 hr = IWICBitmapDecoder_GetContainerFormat(decoder, &container_format); 926 if (SUCCEEDED(hr)) { 927 if (IsEqualGUID(&container_format, &GUID_ContainerFormatBmp)) { 928 if (dib) { 929 TRACE("File type is DIB\n"); 930 info->ImageFileFormat = D3DXIFF_DIB; 931 } else { 932 TRACE("File type is BMP\n"); 933 info->ImageFileFormat = D3DXIFF_BMP; 934 } 935 } else if (IsEqualGUID(&container_format, &GUID_ContainerFormatPng)) { 936 TRACE("File type is PNG\n"); 937 info->ImageFileFormat = D3DXIFF_PNG; 938 } else if(IsEqualGUID(&container_format, &GUID_ContainerFormatJpeg)) { 939 TRACE("File type is JPG\n"); 940 info->ImageFileFormat = D3DXIFF_JPG; 941 } else if(IsEqualGUID(&container_format, &GUID_WineContainerFormatTga)) { 942 TRACE("File type is TGA\n"); 943 info->ImageFileFormat = D3DXIFF_TGA; 944 } else { 945 WARN("Unsupported image file format %s\n", debugstr_guid(&container_format)); 946 hr = D3DXERR_INVALIDDATA; 947 } 948 } 949 950 if (SUCCEEDED(hr)) 951 hr = IWICBitmapDecoder_GetFrameCount(decoder, &frame_count); 952 if (SUCCEEDED(hr) && !frame_count) 953 hr = D3DXERR_INVALIDDATA; 954 955 if (SUCCEEDED(hr)) { 956 IWICBitmapFrameDecode *frame = NULL; 957 958 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame); 959 960 if (SUCCEEDED(hr)) 961 hr = IWICBitmapFrameDecode_GetSize(frame, &info->Width, &info->Height); 962 963 if (SUCCEEDED(hr)) { 964 WICPixelFormatGUID pixel_format; 965 966 hr = IWICBitmapFrameDecode_GetPixelFormat(frame, &pixel_format); 967 if (SUCCEEDED(hr)) { 968 info->Format = wic_guid_to_d3dformat(&pixel_format); 969 if (info->Format == D3DFMT_UNKNOWN) { 970 WARN("Unsupported pixel format %s\n", debugstr_guid(&pixel_format)); 971 hr = D3DXERR_INVALIDDATA; 972 } 973 } 974 } 975 976 /* For 32 bpp BMP, windowscodecs.dll never returns a format with alpha while 977 * d3dx9_xx.dll returns one if at least 1 pixel has a non zero alpha component */ 978 if (SUCCEEDED(hr) && (info->Format == D3DFMT_X8R8G8B8) && (info->ImageFileFormat == D3DXIFF_BMP)) { 979 DWORD size = sizeof(DWORD) * info->Width * info->Height; 980 BYTE *buffer = HeapAlloc(GetProcessHeap(), 0, size); 981 hr = IWICBitmapFrameDecode_CopyPixels(frame, NULL, sizeof(DWORD) * info->Width, size, buffer); 982 if (SUCCEEDED(hr)) { 983 DWORD i; 984 for (i = 0; i < info->Width * info->Height; i++) { 985 if (buffer[i*4+3]) { 986 info->Format = D3DFMT_A8R8G8B8; 987 break; 988 } 989 } 990 } 991 HeapFree(GetProcessHeap(), 0, buffer); 992 } 993 994 if (frame) 995 IWICBitmapFrameDecode_Release(frame); 996 997 info->Depth = 1; 998 info->MipLevels = 1; 999 info->ResourceType = D3DRTYPE_TEXTURE; 1000 } 1001 } 1002 1003 if (decoder) 1004 IWICBitmapDecoder_Release(decoder); 1005 1006 if (SUCCEEDED(initresult)) 1007 CoUninitialize(); 1008 1009 if (dib) 1010 HeapFree(GetProcessHeap(), 0, (void*)data); 1011 1012 if (FAILED(hr)) { 1013 TRACE("Invalid or unsupported image file\n"); 1014 return D3DXERR_INVALIDDATA; 1015 } 1016 1017 return D3D_OK; 1018 } 1019 1020 /************************************************************ 1021 * D3DXGetImageInfoFromFile 1022 * 1023 * RETURNS 1024 * Success: D3D_OK, if we successfully load a valid image file or 1025 * if we successfully load a file which is no valid image and info is NULL 1026 * Failure: D3DXERR_INVALIDDATA, if we fail to load file or 1027 * if file is not a valid image file and info is not NULL 1028 * D3DERR_INVALIDCALL, if file is NULL 1029 * 1030 */ 1031 HRESULT WINAPI D3DXGetImageInfoFromFileA(const char *file, D3DXIMAGE_INFO *info) 1032 { 1033 WCHAR *widename; 1034 HRESULT hr; 1035 int strlength; 1036 1037 TRACE("file %s, info %p.\n", debugstr_a(file), info); 1038 1039 if( !file ) return D3DERR_INVALIDCALL; 1040 1041 strlength = MultiByteToWideChar(CP_ACP, 0, file, -1, NULL, 0); 1042 widename = HeapAlloc(GetProcessHeap(), 0, strlength * sizeof(*widename)); 1043 MultiByteToWideChar(CP_ACP, 0, file, -1, widename, strlength); 1044 1045 hr = D3DXGetImageInfoFromFileW(widename, info); 1046 HeapFree(GetProcessHeap(), 0, widename); 1047 1048 return hr; 1049 } 1050 1051 HRESULT WINAPI D3DXGetImageInfoFromFileW(const WCHAR *file, D3DXIMAGE_INFO *info) 1052 { 1053 void *buffer; 1054 HRESULT hr; 1055 DWORD size; 1056 1057 TRACE("file %s, info %p.\n", debugstr_w(file), info); 1058 1059 if (!file) 1060 return D3DERR_INVALIDCALL; 1061 1062 if (FAILED(map_view_of_file(file, &buffer, &size))) 1063 return D3DXERR_INVALIDDATA; 1064 1065 hr = D3DXGetImageInfoFromFileInMemory(buffer, size, info); 1066 UnmapViewOfFile(buffer); 1067 1068 return hr; 1069 } 1070 1071 /************************************************************ 1072 * D3DXGetImageInfoFromResource 1073 * 1074 * RETURNS 1075 * Success: D3D_OK, if resource is a valid image file 1076 * Failure: D3DXERR_INVALIDDATA, if resource is no valid image file or NULL or 1077 * if we fail to load resource 1078 * 1079 */ 1080 HRESULT WINAPI D3DXGetImageInfoFromResourceA(HMODULE module, const char *resource, D3DXIMAGE_INFO *info) 1081 { 1082 HRSRC resinfo; 1083 void *buffer; 1084 DWORD size; 1085 1086 TRACE("module %p, resource %s, info %p.\n", module, debugstr_a(resource), info); 1087 1088 if (!(resinfo = FindResourceA(module, resource, (const char *)RT_RCDATA)) 1089 /* Try loading the resource as bitmap data (which is in DIB format D3DXIFF_DIB) */ 1090 && !(resinfo = FindResourceA(module, resource, (const char *)RT_BITMAP))) 1091 return D3DXERR_INVALIDDATA; 1092 1093 if (FAILED(load_resource_into_memory(module, resinfo, &buffer, &size))) 1094 return D3DXERR_INVALIDDATA; 1095 1096 return D3DXGetImageInfoFromFileInMemory(buffer, size, info); 1097 } 1098 1099 HRESULT WINAPI D3DXGetImageInfoFromResourceW(HMODULE module, const WCHAR *resource, D3DXIMAGE_INFO *info) 1100 { 1101 HRSRC resinfo; 1102 void *buffer; 1103 DWORD size; 1104 1105 TRACE("module %p, resource %s, info %p.\n", module, debugstr_w(resource), info); 1106 1107 if (!(resinfo = FindResourceW(module, resource, (const WCHAR *)RT_RCDATA)) 1108 /* Try loading the resource as bitmap data (which is in DIB format D3DXIFF_DIB) */ 1109 && !(resinfo = FindResourceW(module, resource, (const WCHAR *)RT_BITMAP))) 1110 return D3DXERR_INVALIDDATA; 1111 1112 if (FAILED(load_resource_into_memory(module, resinfo, &buffer, &size))) 1113 return D3DXERR_INVALIDDATA; 1114 1115 return D3DXGetImageInfoFromFileInMemory(buffer, size, info); 1116 } 1117 1118 /************************************************************ 1119 * D3DXLoadSurfaceFromFileInMemory 1120 * 1121 * Loads data from a given buffer into a surface and fills a given 1122 * D3DXIMAGE_INFO structure with info about the source data. 1123 * 1124 * PARAMS 1125 * pDestSurface [I] pointer to the surface 1126 * pDestPalette [I] palette to use 1127 * pDestRect [I] to be filled area of the surface 1128 * pSrcData [I] pointer to the source data 1129 * SrcDataSize [I] size of the source data in bytes 1130 * pSrcRect [I] area of the source data to load 1131 * dwFilter [I] filter to apply on stretching 1132 * Colorkey [I] colorkey 1133 * pSrcInfo [O] pointer to a D3DXIMAGE_INFO structure 1134 * 1135 * RETURNS 1136 * Success: D3D_OK 1137 * Failure: D3DERR_INVALIDCALL, if pDestSurface, pSrcData or SrcDataSize is NULL 1138 * D3DXERR_INVALIDDATA, if pSrcData is no valid image file 1139 * 1140 */ 1141 HRESULT WINAPI D3DXLoadSurfaceFromFileInMemory(IDirect3DSurface9 *pDestSurface, 1142 const PALETTEENTRY *pDestPalette, const RECT *pDestRect, const void *pSrcData, UINT SrcDataSize, 1143 const RECT *pSrcRect, DWORD dwFilter, D3DCOLOR Colorkey, D3DXIMAGE_INFO *pSrcInfo) 1144 { 1145 D3DXIMAGE_INFO imginfo; 1146 HRESULT hr, com_init; 1147 1148 IWICImagingFactory *factory = NULL; 1149 IWICBitmapDecoder *decoder; 1150 IWICBitmapFrameDecode *bitmapframe; 1151 IWICStream *stream; 1152 1153 const struct pixel_format_desc *formatdesc; 1154 WICRect wicrect; 1155 RECT rect; 1156 1157 TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_data %p, src_data_size %u, " 1158 "src_rect %s, filter %#x, color_key 0x%08x, src_info %p.\n", 1159 pDestSurface, pDestPalette, wine_dbgstr_rect(pDestRect), pSrcData, SrcDataSize, 1160 wine_dbgstr_rect(pSrcRect), dwFilter, Colorkey, pSrcInfo); 1161 1162 if (!pDestSurface || !pSrcData || !SrcDataSize) 1163 return D3DERR_INVALIDCALL; 1164 1165 hr = D3DXGetImageInfoFromFileInMemory(pSrcData, SrcDataSize, &imginfo); 1166 1167 if (FAILED(hr)) 1168 return hr; 1169 1170 if (pSrcRect) 1171 { 1172 wicrect.X = pSrcRect->left; 1173 wicrect.Y = pSrcRect->top; 1174 wicrect.Width = pSrcRect->right - pSrcRect->left; 1175 wicrect.Height = pSrcRect->bottom - pSrcRect->top; 1176 } 1177 else 1178 { 1179 wicrect.X = 0; 1180 wicrect.Y = 0; 1181 wicrect.Width = imginfo.Width; 1182 wicrect.Height = imginfo.Height; 1183 } 1184 1185 SetRect(&rect, 0, 0, wicrect.Width, wicrect.Height); 1186 1187 if (imginfo.ImageFileFormat == D3DXIFF_DDS) 1188 { 1189 hr = load_surface_from_dds(pDestSurface, pDestPalette, pDestRect, pSrcData, &rect, 1190 dwFilter, Colorkey, &imginfo); 1191 if (SUCCEEDED(hr) && pSrcInfo) 1192 *pSrcInfo = imginfo; 1193 return hr; 1194 } 1195 1196 if (imginfo.ImageFileFormat == D3DXIFF_DIB) 1197 convert_dib_to_bmp((void**)&pSrcData, &SrcDataSize); 1198 1199 com_init = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); 1200 1201 if (FAILED(CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, &IID_IWICImagingFactory, (void**)&factory))) 1202 goto cleanup_err; 1203 1204 if (FAILED(IWICImagingFactory_CreateStream(factory, &stream))) 1205 { 1206 IWICImagingFactory_Release(factory); 1207 factory = NULL; 1208 goto cleanup_err; 1209 } 1210 1211 IWICStream_InitializeFromMemory(stream, (BYTE*)pSrcData, SrcDataSize); 1212 1213 hr = IWICImagingFactory_CreateDecoderFromStream(factory, (IStream*)stream, NULL, 0, &decoder); 1214 1215 IWICStream_Release(stream); 1216 1217 if (FAILED(hr)) 1218 goto cleanup_err; 1219 1220 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &bitmapframe); 1221 1222 if (FAILED(hr)) 1223 goto cleanup_bmp; 1224 1225 formatdesc = get_format_info(imginfo.Format); 1226 1227 if (formatdesc->type == FORMAT_UNKNOWN) 1228 { 1229 FIXME("Unsupported pixel format\n"); 1230 hr = D3DXERR_INVALIDDATA; 1231 } 1232 else 1233 { 1234 BYTE *buffer; 1235 DWORD pitch; 1236 PALETTEENTRY *palette = NULL; 1237 WICColor *colors = NULL; 1238 1239 pitch = formatdesc->bytes_per_pixel * wicrect.Width; 1240 buffer = HeapAlloc(GetProcessHeap(), 0, pitch * wicrect.Height); 1241 1242 hr = IWICBitmapFrameDecode_CopyPixels(bitmapframe, &wicrect, pitch, 1243 pitch * wicrect.Height, buffer); 1244 1245 if (SUCCEEDED(hr) && (formatdesc->type == FORMAT_INDEX)) 1246 { 1247 IWICPalette *wic_palette = NULL; 1248 UINT nb_colors; 1249 1250 hr = IWICImagingFactory_CreatePalette(factory, &wic_palette); 1251 if (SUCCEEDED(hr)) 1252 hr = IWICBitmapFrameDecode_CopyPalette(bitmapframe, wic_palette); 1253 if (SUCCEEDED(hr)) 1254 hr = IWICPalette_GetColorCount(wic_palette, &nb_colors); 1255 if (SUCCEEDED(hr)) 1256 { 1257 colors = HeapAlloc(GetProcessHeap(), 0, nb_colors * sizeof(colors[0])); 1258 palette = HeapAlloc(GetProcessHeap(), 0, nb_colors * sizeof(palette[0])); 1259 if (!colors || !palette) 1260 hr = E_OUTOFMEMORY; 1261 } 1262 if (SUCCEEDED(hr)) 1263 hr = IWICPalette_GetColors(wic_palette, nb_colors, colors, &nb_colors); 1264 if (SUCCEEDED(hr)) 1265 { 1266 UINT i; 1267 1268 /* Convert colors from WICColor (ARGB) to PALETTEENTRY (ABGR) */ 1269 for (i = 0; i < nb_colors; i++) 1270 { 1271 palette[i].peRed = (colors[i] >> 16) & 0xff; 1272 palette[i].peGreen = (colors[i] >> 8) & 0xff; 1273 palette[i].peBlue = colors[i] & 0xff; 1274 palette[i].peFlags = (colors[i] >> 24) & 0xff; /* peFlags is the alpha component in DX8 and higher */ 1275 } 1276 } 1277 if (wic_palette) 1278 IWICPalette_Release(wic_palette); 1279 } 1280 1281 if (SUCCEEDED(hr)) 1282 { 1283 hr = D3DXLoadSurfaceFromMemory(pDestSurface, pDestPalette, pDestRect, 1284 buffer, imginfo.Format, pitch, 1285 palette, &rect, dwFilter, Colorkey); 1286 } 1287 1288 HeapFree(GetProcessHeap(), 0, colors); 1289 HeapFree(GetProcessHeap(), 0, palette); 1290 HeapFree(GetProcessHeap(), 0, buffer); 1291 } 1292 1293 IWICBitmapFrameDecode_Release(bitmapframe); 1294 1295 cleanup_bmp: 1296 IWICBitmapDecoder_Release(decoder); 1297 1298 cleanup_err: 1299 if (factory) 1300 IWICImagingFactory_Release(factory); 1301 1302 if (SUCCEEDED(com_init)) 1303 CoUninitialize(); 1304 1305 if (imginfo.ImageFileFormat == D3DXIFF_DIB) 1306 HeapFree(GetProcessHeap(), 0, (void*)pSrcData); 1307 1308 if (FAILED(hr)) 1309 return D3DXERR_INVALIDDATA; 1310 1311 if (pSrcInfo) 1312 *pSrcInfo = imginfo; 1313 1314 return D3D_OK; 1315 } 1316 1317 HRESULT WINAPI D3DXLoadSurfaceFromFileA(IDirect3DSurface9 *dst_surface, 1318 const PALETTEENTRY *dst_palette, const RECT *dst_rect, const char *src_file, 1319 const RECT *src_rect, DWORD filter, D3DCOLOR color_key, D3DXIMAGE_INFO *src_info) 1320 { 1321 WCHAR *src_file_w; 1322 HRESULT hr; 1323 int strlength; 1324 1325 TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_file %s, " 1326 "src_rect %s, filter %#x, color_key 0x%08x, src_info %p.\n", 1327 dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), debugstr_a(src_file), 1328 wine_dbgstr_rect(src_rect), filter, color_key, src_info); 1329 1330 if (!src_file || !dst_surface) 1331 return D3DERR_INVALIDCALL; 1332 1333 strlength = MultiByteToWideChar(CP_ACP, 0, src_file, -1, NULL, 0); 1334 src_file_w = HeapAlloc(GetProcessHeap(), 0, strlength * sizeof(*src_file_w)); 1335 MultiByteToWideChar(CP_ACP, 0, src_file, -1, src_file_w, strlength); 1336 1337 hr = D3DXLoadSurfaceFromFileW(dst_surface, dst_palette, dst_rect, 1338 src_file_w, src_rect, filter, color_key, src_info); 1339 HeapFree(GetProcessHeap(), 0, src_file_w); 1340 1341 return hr; 1342 } 1343 1344 HRESULT WINAPI D3DXLoadSurfaceFromFileW(IDirect3DSurface9 *dst_surface, 1345 const PALETTEENTRY *dst_palette, const RECT *dst_rect, const WCHAR *src_file, 1346 const RECT *src_rect, DWORD filter, D3DCOLOR color_key, D3DXIMAGE_INFO *src_info) 1347 { 1348 UINT data_size; 1349 void *data; 1350 HRESULT hr; 1351 1352 TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_file %s, " 1353 "src_rect %s, filter %#x, color_key 0x%08x, src_info %p.\n", 1354 dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), debugstr_w(src_file), 1355 wine_dbgstr_rect(src_rect), filter, color_key, src_info); 1356 1357 if (!src_file || !dst_surface) 1358 return D3DERR_INVALIDCALL; 1359 1360 if (FAILED(map_view_of_file(src_file, &data, &data_size))) 1361 return D3DXERR_INVALIDDATA; 1362 1363 hr = D3DXLoadSurfaceFromFileInMemory(dst_surface, dst_palette, dst_rect, 1364 data, data_size, src_rect, filter, color_key, src_info); 1365 UnmapViewOfFile(data); 1366 1367 return hr; 1368 } 1369 1370 HRESULT WINAPI D3DXLoadSurfaceFromResourceA(IDirect3DSurface9 *dst_surface, 1371 const PALETTEENTRY *dst_palette, const RECT *dst_rect, HMODULE src_module, const char *resource, 1372 const RECT *src_rect, DWORD filter, D3DCOLOR color_key, D3DXIMAGE_INFO *src_info) 1373 { 1374 UINT data_size; 1375 HRSRC resinfo; 1376 void *data; 1377 1378 TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_module %p, resource %s, " 1379 "src_rect %s, filter %#x, color_key 0x%08x, src_info %p.\n", 1380 dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), src_module, debugstr_a(resource), 1381 wine_dbgstr_rect(src_rect), filter, color_key, src_info); 1382 1383 if (!dst_surface) 1384 return D3DERR_INVALIDCALL; 1385 1386 if (!(resinfo = FindResourceA(src_module, resource, (const char *)RT_RCDATA)) 1387 /* Try loading the resource as bitmap data (which is in DIB format D3DXIFF_DIB) */ 1388 && !(resinfo = FindResourceA(src_module, resource, (const char *)RT_BITMAP))) 1389 return D3DXERR_INVALIDDATA; 1390 1391 if (FAILED(load_resource_into_memory(src_module, resinfo, &data, &data_size))) 1392 return D3DXERR_INVALIDDATA; 1393 1394 return D3DXLoadSurfaceFromFileInMemory(dst_surface, dst_palette, dst_rect, 1395 data, data_size, src_rect, filter, color_key, src_info); 1396 } 1397 1398 HRESULT WINAPI D3DXLoadSurfaceFromResourceW(IDirect3DSurface9 *dst_surface, 1399 const PALETTEENTRY *dst_palette, const RECT *dst_rect, HMODULE src_module, const WCHAR *resource, 1400 const RECT *src_rect, DWORD filter, D3DCOLOR color_key, D3DXIMAGE_INFO *src_info) 1401 { 1402 UINT data_size; 1403 HRSRC resinfo; 1404 void *data; 1405 1406 TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_module %p, resource %s, " 1407 "src_rect %s, filter %#x, color_key 0x%08x, src_info %p.\n", 1408 dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), src_module, debugstr_w(resource), 1409 wine_dbgstr_rect(src_rect), filter, color_key, src_info); 1410 1411 if (!dst_surface) 1412 return D3DERR_INVALIDCALL; 1413 1414 if (!(resinfo = FindResourceW(src_module, resource, (const WCHAR *)RT_RCDATA)) 1415 /* Try loading the resource as bitmap data (which is in DIB format D3DXIFF_DIB) */ 1416 && !(resinfo = FindResourceW(src_module, resource, (const WCHAR *)RT_BITMAP))) 1417 return D3DXERR_INVALIDDATA; 1418 1419 if (FAILED(load_resource_into_memory(src_module, resinfo, &data, &data_size))) 1420 return D3DXERR_INVALIDDATA; 1421 1422 return D3DXLoadSurfaceFromFileInMemory(dst_surface, dst_palette, dst_rect, 1423 data, data_size, src_rect, filter, color_key, src_info); 1424 } 1425 1426 1427 /************************************************************ 1428 * helper functions for D3DXLoadSurfaceFromMemory 1429 */ 1430 struct argb_conversion_info 1431 { 1432 const struct pixel_format_desc *srcformat; 1433 const struct pixel_format_desc *destformat; 1434 DWORD srcshift[4], destshift[4]; 1435 DWORD srcmask[4], destmask[4]; 1436 BOOL process_channel[4]; 1437 DWORD channelmask; 1438 }; 1439 1440 static void init_argb_conversion_info(const struct pixel_format_desc *srcformat, const struct pixel_format_desc *destformat, struct argb_conversion_info *info) 1441 { 1442 UINT i; 1443 ZeroMemory(info->process_channel, 4 * sizeof(BOOL)); 1444 info->channelmask = 0; 1445 1446 info->srcformat = srcformat; 1447 info->destformat = destformat; 1448 1449 for(i = 0;i < 4;i++) { 1450 /* srcshift is used to extract the _relevant_ components */ 1451 info->srcshift[i] = srcformat->shift[i] + max( srcformat->bits[i] - destformat->bits[i], 0); 1452 1453 /* destshift is used to move the components to the correct position */ 1454 info->destshift[i] = destformat->shift[i] + max(destformat->bits[i] - srcformat->bits[i], 0); 1455 1456 info->srcmask[i] = ((1 << srcformat->bits[i]) - 1) << srcformat->shift[i]; 1457 info->destmask[i] = ((1 << destformat->bits[i]) - 1) << destformat->shift[i]; 1458 1459 /* channelmask specifies bits which aren't used in the source format but in the destination one */ 1460 if(destformat->bits[i]) { 1461 if(srcformat->bits[i]) info->process_channel[i] = TRUE; 1462 else info->channelmask |= info->destmask[i]; 1463 } 1464 } 1465 } 1466 1467 /************************************************************ 1468 * get_relevant_argb_components 1469 * 1470 * Extracts the relevant components from the source color and 1471 * drops the less significant bits if they aren't used by the destination format. 1472 */ 1473 static void get_relevant_argb_components(const struct argb_conversion_info *info, const BYTE *col, DWORD *out) 1474 { 1475 unsigned int i, j; 1476 unsigned int component, mask; 1477 1478 for (i = 0; i < 4; ++i) 1479 { 1480 if (!info->process_channel[i]) 1481 continue; 1482 1483 component = 0; 1484 mask = info->srcmask[i]; 1485 for (j = 0; j < 4 && mask; ++j) 1486 { 1487 if (info->srcshift[i] < j * 8) 1488 component |= (col[j] & mask) << (j * 8 - info->srcshift[i]); 1489 else 1490 component |= (col[j] & mask) >> (info->srcshift[i] - j * 8); 1491 mask >>= 8; 1492 } 1493 out[i] = component; 1494 } 1495 } 1496 1497 /************************************************************ 1498 * make_argb_color 1499 * 1500 * Recombines the output of get_relevant_argb_components and converts 1501 * it to the destination format. 1502 */ 1503 static DWORD make_argb_color(const struct argb_conversion_info *info, const DWORD *in) 1504 { 1505 UINT i; 1506 DWORD val = 0; 1507 1508 for(i = 0;i < 4;i++) { 1509 if(info->process_channel[i]) { 1510 /* necessary to make sure that e.g. an X4R4G4B4 white maps to an R8G8B8 white instead of 0xf0f0f0 */ 1511 signed int shift; 1512 for(shift = info->destshift[i]; shift > info->destformat->shift[i]; shift -= info->srcformat->bits[i]) val |= in[i] << shift; 1513 val |= (in[i] >> (info->destformat->shift[i] - shift)) << info->destformat->shift[i]; 1514 } 1515 } 1516 val |= info->channelmask; /* new channels are set to their maximal value */ 1517 return val; 1518 } 1519 1520 /* It doesn't work for components bigger than 32 bits (or somewhat smaller but unaligned). */ 1521 static void format_to_vec4(const struct pixel_format_desc *format, const BYTE *src, struct vec4 *dst) 1522 { 1523 DWORD mask, tmp; 1524 unsigned int c; 1525 1526 for (c = 0; c < 4; ++c) 1527 { 1528 static const unsigned int component_offsets[4] = {3, 0, 1, 2}; 1529 float *dst_component = (float *)dst + component_offsets[c]; 1530 1531 if (format->bits[c]) 1532 { 1533 mask = ~0u >> (32 - format->bits[c]); 1534 1535 memcpy(&tmp, src + format->shift[c] / 8, 1536 min(sizeof(DWORD), (format->shift[c] % 8 + format->bits[c] + 7) / 8)); 1537 1538 if (format->type == FORMAT_ARGBF16) 1539 *dst_component = float_16_to_32(tmp); 1540 else if (format->type == FORMAT_ARGBF) 1541 *dst_component = *(float *)&tmp; 1542 else 1543 *dst_component = (float)((tmp >> format->shift[c] % 8) & mask) / mask; 1544 } 1545 else 1546 *dst_component = 1.0f; 1547 } 1548 } 1549 1550 /* It doesn't work for components bigger than 32 bits. */ 1551 static void format_from_vec4(const struct pixel_format_desc *format, const struct vec4 *src, BYTE *dst) 1552 { 1553 DWORD v, mask32; 1554 unsigned int c, i; 1555 1556 memset(dst, 0, format->bytes_per_pixel); 1557 1558 for (c = 0; c < 4; ++c) 1559 { 1560 static const unsigned int component_offsets[4] = {3, 0, 1, 2}; 1561 const float src_component = *((const float *)src + component_offsets[c]); 1562 1563 if (!format->bits[c]) 1564 continue; 1565 1566 mask32 = ~0u >> (32 - format->bits[c]); 1567 1568 if (format->type == FORMAT_ARGBF16) 1569 v = float_32_to_16(src_component); 1570 else if (format->type == FORMAT_ARGBF) 1571 v = *(DWORD *)&src_component; 1572 else 1573 v = (DWORD)(src_component * ((1 << format->bits[c]) - 1) + 0.5f); 1574 1575 for (i = format->shift[c] / 8 * 8; i < format->shift[c] + format->bits[c]; i += 8) 1576 { 1577 BYTE mask, byte; 1578 1579 if (format->shift[c] > i) 1580 { 1581 mask = mask32 << (format->shift[c] - i); 1582 byte = (v << (format->shift[c] - i)) & mask; 1583 } 1584 else 1585 { 1586 mask = mask32 >> (i - format->shift[c]); 1587 byte = (v >> (i - format->shift[c])) & mask; 1588 } 1589 dst[i / 8] |= byte; 1590 } 1591 } 1592 } 1593 1594 /************************************************************ 1595 * copy_pixels 1596 * 1597 * Copies the source buffer to the destination buffer. 1598 * Works for any pixel format. 1599 * The source and the destination must be block-aligned. 1600 */ 1601 void copy_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, 1602 BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, const struct volume *size, 1603 const struct pixel_format_desc *format) 1604 { 1605 UINT row, slice; 1606 BYTE *dst_addr; 1607 const BYTE *src_addr; 1608 UINT row_block_count = (size->width + format->block_width - 1) / format->block_width; 1609 UINT row_count = (size->height + format->block_height - 1) / format->block_height; 1610 1611 for (slice = 0; slice < size->depth; slice++) 1612 { 1613 src_addr = src + slice * src_slice_pitch; 1614 dst_addr = dst + slice * dst_slice_pitch; 1615 1616 for (row = 0; row < row_count; row++) 1617 { 1618 memcpy(dst_addr, src_addr, row_block_count * format->block_byte_count); 1619 src_addr += src_row_pitch; 1620 dst_addr += dst_row_pitch; 1621 } 1622 } 1623 } 1624 1625 /************************************************************ 1626 * convert_argb_pixels 1627 * 1628 * Copies the source buffer to the destination buffer, performing 1629 * any necessary format conversion and color keying. 1630 * Pixels outsize the source rect are blacked out. 1631 */ 1632 void convert_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, const struct volume *src_size, 1633 const struct pixel_format_desc *src_format, BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, 1634 const struct volume *dst_size, const struct pixel_format_desc *dst_format, D3DCOLOR color_key, 1635 const PALETTEENTRY *palette) 1636 { 1637 struct argb_conversion_info conv_info, ck_conv_info; 1638 const struct pixel_format_desc *ck_format = NULL; 1639 DWORD channels[4]; 1640 UINT min_width, min_height, min_depth; 1641 UINT x, y, z; 1642 1643 ZeroMemory(channels, sizeof(channels)); 1644 init_argb_conversion_info(src_format, dst_format, &conv_info); 1645 1646 min_width = min(src_size->width, dst_size->width); 1647 min_height = min(src_size->height, dst_size->height); 1648 min_depth = min(src_size->depth, dst_size->depth); 1649 1650 if (color_key) 1651 { 1652 /* Color keys are always represented in D3DFMT_A8R8G8B8 format. */ 1653 ck_format = get_format_info(D3DFMT_A8R8G8B8); 1654 init_argb_conversion_info(src_format, ck_format, &ck_conv_info); 1655 } 1656 1657 for (z = 0; z < min_depth; z++) { 1658 const BYTE *src_slice_ptr = src + z * src_slice_pitch; 1659 BYTE *dst_slice_ptr = dst + z * dst_slice_pitch; 1660 1661 for (y = 0; y < min_height; y++) { 1662 const BYTE *src_ptr = src_slice_ptr + y * src_row_pitch; 1663 BYTE *dst_ptr = dst_slice_ptr + y * dst_row_pitch; 1664 1665 for (x = 0; x < min_width; x++) { 1666 if (!src_format->to_rgba && !dst_format->from_rgba 1667 && src_format->type == dst_format->type 1668 && src_format->bytes_per_pixel <= 4 && dst_format->bytes_per_pixel <= 4) 1669 { 1670 DWORD val; 1671 1672 get_relevant_argb_components(&conv_info, src_ptr, channels); 1673 val = make_argb_color(&conv_info, channels); 1674 1675 if (color_key) 1676 { 1677 DWORD ck_pixel; 1678 1679 get_relevant_argb_components(&ck_conv_info, src_ptr, channels); 1680 ck_pixel = make_argb_color(&ck_conv_info, channels); 1681 if (ck_pixel == color_key) 1682 val &= ~conv_info.destmask[0]; 1683 } 1684 memcpy(dst_ptr, &val, dst_format->bytes_per_pixel); 1685 } 1686 else 1687 { 1688 struct vec4 color, tmp; 1689 1690 format_to_vec4(src_format, src_ptr, &color); 1691 if (src_format->to_rgba) 1692 src_format->to_rgba(&color, &tmp, palette); 1693 else 1694 tmp = color; 1695 1696 if (ck_format) 1697 { 1698 DWORD ck_pixel; 1699 1700 format_from_vec4(ck_format, &tmp, (BYTE *)&ck_pixel); 1701 if (ck_pixel == color_key) 1702 tmp.w = 0.0f; 1703 } 1704 1705 if (dst_format->from_rgba) 1706 dst_format->from_rgba(&tmp, &color); 1707 else 1708 color = tmp; 1709 1710 format_from_vec4(dst_format, &color, dst_ptr); 1711 } 1712 1713 src_ptr += src_format->bytes_per_pixel; 1714 dst_ptr += dst_format->bytes_per_pixel; 1715 } 1716 1717 if (src_size->width < dst_size->width) /* black out remaining pixels */ 1718 memset(dst_ptr, 0, dst_format->bytes_per_pixel * (dst_size->width - src_size->width)); 1719 } 1720 1721 if (src_size->height < dst_size->height) /* black out remaining pixels */ 1722 memset(dst + src_size->height * dst_row_pitch, 0, dst_row_pitch * (dst_size->height - src_size->height)); 1723 } 1724 if (src_size->depth < dst_size->depth) /* black out remaining pixels */ 1725 memset(dst + src_size->depth * dst_slice_pitch, 0, dst_slice_pitch * (dst_size->depth - src_size->depth)); 1726 } 1727 1728 /************************************************************ 1729 * point_filter_argb_pixels 1730 * 1731 * Copies the source buffer to the destination buffer, performing 1732 * any necessary format conversion, color keying and stretching 1733 * using a point filter. 1734 */ 1735 void point_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, const struct volume *src_size, 1736 const struct pixel_format_desc *src_format, BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, 1737 const struct volume *dst_size, const struct pixel_format_desc *dst_format, D3DCOLOR color_key, 1738 const PALETTEENTRY *palette) 1739 { 1740 struct argb_conversion_info conv_info, ck_conv_info; 1741 const struct pixel_format_desc *ck_format = NULL; 1742 DWORD channels[4]; 1743 UINT x, y, z; 1744 1745 ZeroMemory(channels, sizeof(channels)); 1746 init_argb_conversion_info(src_format, dst_format, &conv_info); 1747 1748 if (color_key) 1749 { 1750 /* Color keys are always represented in D3DFMT_A8R8G8B8 format. */ 1751 ck_format = get_format_info(D3DFMT_A8R8G8B8); 1752 init_argb_conversion_info(src_format, ck_format, &ck_conv_info); 1753 } 1754 1755 for (z = 0; z < dst_size->depth; z++) 1756 { 1757 BYTE *dst_slice_ptr = dst + z * dst_slice_pitch; 1758 const BYTE *src_slice_ptr = src + src_slice_pitch * (z * src_size->depth / dst_size->depth); 1759 1760 for (y = 0; y < dst_size->height; y++) 1761 { 1762 BYTE *dst_ptr = dst_slice_ptr + y * dst_row_pitch; 1763 const BYTE *src_row_ptr = src_slice_ptr + src_row_pitch * (y * src_size->height / dst_size->height); 1764 1765 for (x = 0; x < dst_size->width; x++) 1766 { 1767 const BYTE *src_ptr = src_row_ptr + (x * src_size->width / dst_size->width) * src_format->bytes_per_pixel; 1768 1769 if (!src_format->to_rgba && !dst_format->from_rgba 1770 && src_format->type == dst_format->type 1771 && src_format->bytes_per_pixel <= 4 && dst_format->bytes_per_pixel <= 4) 1772 { 1773 DWORD val; 1774 1775 get_relevant_argb_components(&conv_info, src_ptr, channels); 1776 val = make_argb_color(&conv_info, channels); 1777 1778 if (color_key) 1779 { 1780 DWORD ck_pixel; 1781 1782 get_relevant_argb_components(&ck_conv_info, src_ptr, channels); 1783 ck_pixel = make_argb_color(&ck_conv_info, channels); 1784 if (ck_pixel == color_key) 1785 val &= ~conv_info.destmask[0]; 1786 } 1787 memcpy(dst_ptr, &val, dst_format->bytes_per_pixel); 1788 } 1789 else 1790 { 1791 struct vec4 color, tmp; 1792 1793 format_to_vec4(src_format, src_ptr, &color); 1794 if (src_format->to_rgba) 1795 src_format->to_rgba(&color, &tmp, palette); 1796 else 1797 tmp = color; 1798 1799 if (ck_format) 1800 { 1801 DWORD ck_pixel; 1802 1803 format_from_vec4(ck_format, &tmp, (BYTE *)&ck_pixel); 1804 if (ck_pixel == color_key) 1805 tmp.w = 0.0f; 1806 } 1807 1808 if (dst_format->from_rgba) 1809 dst_format->from_rgba(&tmp, &color); 1810 else 1811 color = tmp; 1812 1813 format_from_vec4(dst_format, &color, dst_ptr); 1814 } 1815 1816 dst_ptr += dst_format->bytes_per_pixel; 1817 } 1818 } 1819 } 1820 } 1821 1822 typedef BOOL (*dxtn_conversion_func)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, 1823 enum wined3d_format_id format, unsigned int w, unsigned int h); 1824 1825 static dxtn_conversion_func get_dxtn_conversion_func(D3DFORMAT format, BOOL encode) 1826 { 1827 switch (format) 1828 { 1829 case D3DFMT_DXT1: 1830 if (!wined3d_dxtn_supported()) return NULL; 1831 return encode ? wined3d_dxt1_encode : wined3d_dxt1_decode; 1832 case D3DFMT_DXT3: 1833 if (!wined3d_dxtn_supported()) return NULL; 1834 return encode ? wined3d_dxt3_encode : wined3d_dxt3_decode; 1835 case D3DFMT_DXT5: 1836 if (!wined3d_dxtn_supported()) return NULL; 1837 return encode ? wined3d_dxt5_encode : wined3d_dxt5_decode; 1838 default: 1839 return NULL; 1840 } 1841 } 1842 1843 /************************************************************ 1844 * D3DXLoadSurfaceFromMemory 1845 * 1846 * Loads data from a given memory chunk into a surface, 1847 * applying any of the specified filters. 1848 * 1849 * PARAMS 1850 * pDestSurface [I] pointer to the surface 1851 * pDestPalette [I] palette to use 1852 * pDestRect [I] to be filled area of the surface 1853 * pSrcMemory [I] pointer to the source data 1854 * SrcFormat [I] format of the source pixel data 1855 * SrcPitch [I] number of bytes in a row 1856 * pSrcPalette [I] palette used in the source image 1857 * pSrcRect [I] area of the source data to load 1858 * dwFilter [I] filter to apply on stretching 1859 * Colorkey [I] colorkey 1860 * 1861 * RETURNS 1862 * Success: D3D_OK, if we successfully load the pixel data into our surface or 1863 * if pSrcMemory is NULL but the other parameters are valid 1864 * Failure: D3DERR_INVALIDCALL, if pDestSurface, SrcPitch or pSrcRect is NULL or 1865 * if SrcFormat is an invalid format (other than D3DFMT_UNKNOWN) or 1866 * if DestRect is invalid 1867 * D3DXERR_INVALIDDATA, if we fail to lock pDestSurface 1868 * E_FAIL, if SrcFormat is D3DFMT_UNKNOWN or the dimensions of pSrcRect are invalid 1869 * 1870 * NOTES 1871 * pSrcRect specifies the dimensions of the source data; 1872 * negative values for pSrcRect are allowed as we're only looking at the width and height anyway. 1873 * 1874 */ 1875 HRESULT WINAPI D3DXLoadSurfaceFromMemory(IDirect3DSurface9 *dst_surface, 1876 const PALETTEENTRY *dst_palette, const RECT *dst_rect, const void *src_memory, 1877 D3DFORMAT src_format, UINT src_pitch, const PALETTEENTRY *src_palette, const RECT *src_rect, 1878 DWORD filter, D3DCOLOR color_key) 1879 { 1880 const struct pixel_format_desc *srcformatdesc, *destformatdesc; 1881 D3DSURFACE_DESC surfdesc; 1882 D3DLOCKED_RECT lockrect; 1883 struct volume src_size, dst_size; 1884 HRESULT ret = D3D_OK; 1885 1886 TRACE("(%p, %p, %s, %p, %#x, %u, %p, %s, %#x, 0x%08x)\n", 1887 dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), src_memory, src_format, 1888 src_pitch, src_palette, wine_dbgstr_rect(src_rect), filter, color_key); 1889 1890 if (!dst_surface || !src_memory || !src_rect) 1891 { 1892 WARN("Invalid argument specified.\n"); 1893 return D3DERR_INVALIDCALL; 1894 } 1895 if (src_format == D3DFMT_UNKNOWN 1896 || src_rect->left >= src_rect->right 1897 || src_rect->top >= src_rect->bottom) 1898 { 1899 WARN("Invalid src_format or src_rect.\n"); 1900 return E_FAIL; 1901 } 1902 1903 if (filter == D3DX_DEFAULT) 1904 filter = D3DX_FILTER_TRIANGLE | D3DX_FILTER_DITHER; 1905 1906 IDirect3DSurface9_GetDesc(dst_surface, &surfdesc); 1907 1908 src_size.width = src_rect->right - src_rect->left; 1909 src_size.height = src_rect->bottom - src_rect->top; 1910 src_size.depth = 1; 1911 if (!dst_rect) 1912 { 1913 dst_size.width = surfdesc.Width; 1914 dst_size.height = surfdesc.Height; 1915 } 1916 else 1917 { 1918 if (dst_rect->left > dst_rect->right || dst_rect->right > surfdesc.Width 1919 || dst_rect->top > dst_rect->bottom || dst_rect->bottom > surfdesc.Height 1920 || dst_rect->left < 0 || dst_rect->top < 0) 1921 { 1922 WARN("Invalid dst_rect specified.\n"); 1923 return D3DERR_INVALIDCALL; 1924 } 1925 dst_size.width = dst_rect->right - dst_rect->left; 1926 dst_size.height = dst_rect->bottom - dst_rect->top; 1927 if (!dst_size.width || !dst_size.height) 1928 return D3D_OK; 1929 } 1930 dst_size.depth = 1; 1931 1932 srcformatdesc = get_format_info(src_format); 1933 destformatdesc = get_format_info(surfdesc.Format); 1934 if (srcformatdesc->type == FORMAT_UNKNOWN || destformatdesc->type == FORMAT_UNKNOWN) 1935 { 1936 FIXME("Unsupported pixel format conversion %#x -> %#x\n", src_format, surfdesc.Format); 1937 return E_NOTIMPL; 1938 } 1939 1940 if (src_format == surfdesc.Format 1941 && dst_size.width == src_size.width 1942 && dst_size.height == src_size.height 1943 && color_key == 0) /* Simple copy. */ 1944 { 1945 if (src_rect->left & (srcformatdesc->block_width - 1) 1946 || src_rect->top & (srcformatdesc->block_height - 1) 1947 || (src_rect->right & (srcformatdesc->block_width - 1) 1948 && src_size.width != surfdesc.Width) 1949 || (src_rect->bottom & (srcformatdesc->block_height - 1) 1950 && src_size.height != surfdesc.Height)) 1951 { 1952 WARN("Source rect %s is misaligned.\n", wine_dbgstr_rect(src_rect)); 1953 return D3DXERR_INVALIDDATA; 1954 } 1955 1956 if (FAILED(IDirect3DSurface9_LockRect(dst_surface, &lockrect, dst_rect, 0))) 1957 return D3DXERR_INVALIDDATA; 1958 1959 copy_pixels(src_memory, src_pitch, 0, lockrect.pBits, lockrect.Pitch, 0, 1960 &src_size, srcformatdesc); 1961 1962 IDirect3DSurface9_UnlockRect(dst_surface); 1963 } 1964 else /* Stretching or format conversion. */ 1965 { 1966 dxtn_conversion_func pre_convert, post_convert; 1967 void *tmp_src_memory = NULL, *tmp_dst_memory = NULL; 1968 UINT tmp_src_pitch, tmp_dst_pitch; 1969 1970 pre_convert = get_dxtn_conversion_func(srcformatdesc->format, FALSE); 1971 post_convert = get_dxtn_conversion_func(destformatdesc->format, TRUE); 1972 1973 if ((!pre_convert && !is_conversion_from_supported(srcformatdesc)) || 1974 (!post_convert && !is_conversion_to_supported(destformatdesc))) 1975 { 1976 FIXME("Unsupported format conversion %#x -> %#x.\n", src_format, surfdesc.Format); 1977 return E_NOTIMPL; 1978 } 1979 1980 if (FAILED(IDirect3DSurface9_LockRect(dst_surface, &lockrect, dst_rect, 0))) 1981 return D3DXERR_INVALIDDATA; 1982 1983 /* handle pre-conversion */ 1984 if (pre_convert) 1985 { 1986 tmp_src_memory = HeapAlloc(GetProcessHeap(), 0, src_size.width * src_size.height * sizeof(DWORD)); 1987 if (!tmp_src_memory) 1988 { 1989 ret = E_OUTOFMEMORY; 1990 goto error; 1991 } 1992 tmp_src_pitch = src_size.width * sizeof(DWORD); 1993 if (!pre_convert(src_memory, tmp_src_memory, src_pitch, tmp_src_pitch, 1994 WINED3DFMT_B8G8R8A8_UNORM, src_size.width, src_size.height)) 1995 { 1996 ret = E_FAIL; 1997 goto error; 1998 } 1999 srcformatdesc = get_format_info(D3DFMT_A8R8G8B8); 2000 } 2001 else 2002 { 2003 tmp_src_memory = (void *)src_memory; 2004 tmp_src_pitch = src_pitch; 2005 } 2006 2007 /* handle post-conversion */ 2008 if (post_convert) 2009 { 2010 tmp_dst_memory = HeapAlloc(GetProcessHeap(), 0, dst_size.width * dst_size.height * sizeof(DWORD)); 2011 if (!tmp_dst_memory) 2012 { 2013 ret = E_OUTOFMEMORY; 2014 goto error; 2015 } 2016 tmp_dst_pitch = dst_size.width * sizeof(DWORD); 2017 destformatdesc = get_format_info(D3DFMT_A8R8G8B8); 2018 } 2019 else 2020 { 2021 tmp_dst_memory = lockrect.pBits; 2022 tmp_dst_pitch = lockrect.Pitch; 2023 } 2024 2025 if ((filter & 0xf) == D3DX_FILTER_NONE) 2026 { 2027 convert_argb_pixels(tmp_src_memory, tmp_src_pitch, 0, &src_size, srcformatdesc, 2028 tmp_dst_memory, tmp_dst_pitch, 0, &dst_size, destformatdesc, color_key, src_palette); 2029 } 2030 else /* if ((filter & 0xf) == D3DX_FILTER_POINT) */ 2031 { 2032 if ((filter & 0xf) != D3DX_FILTER_POINT) 2033 FIXME("Unhandled filter %#x.\n", filter); 2034 2035 /* Always apply a point filter until D3DX_FILTER_LINEAR, 2036 * D3DX_FILTER_TRIANGLE and D3DX_FILTER_BOX are implemented. */ 2037 point_filter_argb_pixels(tmp_src_memory, tmp_src_pitch, 0, &src_size, srcformatdesc, 2038 tmp_dst_memory, tmp_dst_pitch, 0, &dst_size, destformatdesc, color_key, src_palette); 2039 } 2040 2041 /* handle post-conversion */ 2042 if (post_convert) 2043 { 2044 if (!post_convert(tmp_dst_memory, lockrect.pBits, tmp_dst_pitch, lockrect.Pitch, 2045 WINED3DFMT_B8G8R8A8_UNORM, dst_size.width, dst_size.height)) 2046 { 2047 ret = E_FAIL; 2048 goto error; 2049 } 2050 } 2051 2052 error: 2053 if (pre_convert) 2054 HeapFree(GetProcessHeap(), 0, tmp_src_memory); 2055 if (post_convert) 2056 HeapFree(GetProcessHeap(), 0, tmp_dst_memory); 2057 IDirect3DSurface9_UnlockRect(dst_surface); 2058 } 2059 2060 return ret; 2061 } 2062 2063 /************************************************************ 2064 * D3DXLoadSurfaceFromSurface 2065 * 2066 * Copies the contents from one surface to another, performing any required 2067 * format conversion, resizing or filtering. 2068 * 2069 * PARAMS 2070 * pDestSurface [I] pointer to the destination surface 2071 * pDestPalette [I] palette to use 2072 * pDestRect [I] to be filled area of the surface 2073 * pSrcSurface [I] pointer to the source surface 2074 * pSrcPalette [I] palette used for the source surface 2075 * pSrcRect [I] area of the source data to load 2076 * dwFilter [I] filter to apply on resizing 2077 * Colorkey [I] any ARGB value or 0 to disable color-keying 2078 * 2079 * RETURNS 2080 * Success: D3D_OK 2081 * Failure: D3DERR_INVALIDCALL, if pDestSurface or pSrcSurface is NULL 2082 * D3DXERR_INVALIDDATA, if one of the surfaces is not lockable 2083 * 2084 */ 2085 HRESULT WINAPI D3DXLoadSurfaceFromSurface(IDirect3DSurface9 *dst_surface, 2086 const PALETTEENTRY *dst_palette, const RECT *dst_rect, IDirect3DSurface9 *src_surface, 2087 const PALETTEENTRY *src_palette, const RECT *src_rect, DWORD filter, D3DCOLOR color_key) 2088 { 2089 RECT rect; 2090 D3DLOCKED_RECT lock; 2091 D3DSURFACE_DESC SrcDesc; 2092 HRESULT hr; 2093 2094 TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_surface %p, " 2095 "src_palette %p, src_rect %s, filter %#x, color_key 0x%08x.\n", 2096 dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), src_surface, 2097 src_palette, wine_dbgstr_rect(src_rect), filter, color_key); 2098 2099 if (!dst_surface || !src_surface) 2100 return D3DERR_INVALIDCALL; 2101 2102 IDirect3DSurface9_GetDesc(src_surface, &SrcDesc); 2103 2104 if (!src_rect) 2105 SetRect(&rect, 0, 0, SrcDesc.Width, SrcDesc.Height); 2106 else 2107 rect = *src_rect; 2108 2109 if (FAILED(IDirect3DSurface9_LockRect(src_surface, &lock, NULL, D3DLOCK_READONLY))) 2110 return D3DXERR_INVALIDDATA; 2111 2112 hr = D3DXLoadSurfaceFromMemory(dst_surface, dst_palette, dst_rect, 2113 lock.pBits, SrcDesc.Format, lock.Pitch, src_palette, &rect, filter, color_key); 2114 2115 IDirect3DSurface9_UnlockRect(src_surface); 2116 2117 return hr; 2118 } 2119 2120 2121 HRESULT WINAPI D3DXSaveSurfaceToFileA(const char *dst_filename, D3DXIMAGE_FILEFORMAT file_format, 2122 IDirect3DSurface9 *src_surface, const PALETTEENTRY *src_palette, const RECT *src_rect) 2123 { 2124 int len; 2125 WCHAR *filename; 2126 HRESULT hr; 2127 ID3DXBuffer *buffer; 2128 2129 TRACE("(%s, %#x, %p, %p, %s): relay\n", 2130 wine_dbgstr_a(dst_filename), file_format, src_surface, src_palette, wine_dbgstr_rect(src_rect)); 2131 2132 if (!dst_filename) return D3DERR_INVALIDCALL; 2133 2134 len = MultiByteToWideChar(CP_ACP, 0, dst_filename, -1, NULL, 0); 2135 filename = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 2136 if (!filename) return E_OUTOFMEMORY; 2137 MultiByteToWideChar(CP_ACP, 0, dst_filename, -1, filename, len); 2138 2139 hr = D3DXSaveSurfaceToFileInMemory(&buffer, file_format, src_surface, src_palette, src_rect); 2140 if (SUCCEEDED(hr)) 2141 { 2142 hr = write_buffer_to_file(filename, buffer); 2143 ID3DXBuffer_Release(buffer); 2144 } 2145 2146 HeapFree(GetProcessHeap(), 0, filename); 2147 return hr; 2148 } 2149 2150 HRESULT WINAPI D3DXSaveSurfaceToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEFORMAT file_format, 2151 IDirect3DSurface9 *src_surface, const PALETTEENTRY *src_palette, const RECT *src_rect) 2152 { 2153 HRESULT hr; 2154 ID3DXBuffer *buffer; 2155 2156 TRACE("(%s, %#x, %p, %p, %s): relay\n", 2157 wine_dbgstr_w(dst_filename), file_format, src_surface, src_palette, wine_dbgstr_rect(src_rect)); 2158 2159 if (!dst_filename) return D3DERR_INVALIDCALL; 2160 2161 hr = D3DXSaveSurfaceToFileInMemory(&buffer, file_format, src_surface, src_palette, src_rect); 2162 if (SUCCEEDED(hr)) 2163 { 2164 hr = write_buffer_to_file(dst_filename, buffer); 2165 ID3DXBuffer_Release(buffer); 2166 } 2167 2168 return hr; 2169 } 2170 2171 HRESULT WINAPI D3DXSaveSurfaceToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE_FILEFORMAT file_format, 2172 IDirect3DSurface9 *src_surface, const PALETTEENTRY *src_palette, const RECT *src_rect) 2173 { 2174 IWICBitmapEncoder *encoder = NULL; 2175 IWICBitmapFrameEncode *frame = NULL; 2176 IPropertyBag2 *encoder_options = NULL; 2177 IStream *stream = NULL; 2178 HRESULT hr; 2179 HRESULT initresult; 2180 const CLSID *encoder_clsid; 2181 const GUID *pixel_format_guid; 2182 WICPixelFormatGUID wic_pixel_format; 2183 D3DFORMAT d3d_pixel_format; 2184 D3DSURFACE_DESC src_surface_desc; 2185 D3DLOCKED_RECT locked_rect; 2186 int width, height; 2187 STATSTG stream_stats; 2188 HGLOBAL stream_hglobal; 2189 ID3DXBuffer *buffer; 2190 DWORD size; 2191 2192 TRACE("(%p, %#x, %p, %p, %s)\n", 2193 dst_buffer, file_format, src_surface, src_palette, wine_dbgstr_rect(src_rect)); 2194 2195 if (!dst_buffer || !src_surface) return D3DERR_INVALIDCALL; 2196 2197 if (src_palette) 2198 { 2199 FIXME("Saving surfaces with palettized pixel formats is not implemented yet\n"); 2200 return D3DERR_INVALIDCALL; 2201 } 2202 2203 switch (file_format) 2204 { 2205 case D3DXIFF_BMP: 2206 case D3DXIFF_DIB: 2207 encoder_clsid = &CLSID_WICBmpEncoder; 2208 break; 2209 case D3DXIFF_PNG: 2210 encoder_clsid = &CLSID_WICPngEncoder; 2211 break; 2212 case D3DXIFF_JPG: 2213 encoder_clsid = &CLSID_WICJpegEncoder; 2214 break; 2215 case D3DXIFF_DDS: 2216 return save_dds_surface_to_memory(dst_buffer, src_surface, src_rect); 2217 case D3DXIFF_HDR: 2218 case D3DXIFF_PFM: 2219 case D3DXIFF_TGA: 2220 case D3DXIFF_PPM: 2221 FIXME("File format %#x is not supported yet\n", file_format); 2222 return E_NOTIMPL; 2223 default: 2224 return D3DERR_INVALIDCALL; 2225 } 2226 2227 IDirect3DSurface9_GetDesc(src_surface, &src_surface_desc); 2228 if (src_rect) 2229 { 2230 if (src_rect->left == src_rect->right || src_rect->top == src_rect->bottom) 2231 { 2232 WARN("Invalid rectangle with 0 area\n"); 2233 return D3DXCreateBuffer(64, dst_buffer); 2234 } 2235 if (src_rect->left < 0 || src_rect->top < 0) 2236 return D3DERR_INVALIDCALL; 2237 if (src_rect->left > src_rect->right || src_rect->top > src_rect->bottom) 2238 return D3DERR_INVALIDCALL; 2239 if (src_rect->right > src_surface_desc.Width || src_rect->bottom > src_surface_desc.Height) 2240 return D3DERR_INVALIDCALL; 2241 2242 width = src_rect->right - src_rect->left; 2243 height = src_rect->bottom - src_rect->top; 2244 } 2245 else 2246 { 2247 width = src_surface_desc.Width; 2248 height = src_surface_desc.Height; 2249 } 2250 2251 initresult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); 2252 2253 hr = CoCreateInstance(encoder_clsid, NULL, CLSCTX_INPROC_SERVER, 2254 &IID_IWICBitmapEncoder, (void **)&encoder); 2255 if (FAILED(hr)) goto cleanup_err; 2256 2257 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); 2258 if (FAILED(hr)) goto cleanup_err; 2259 2260 hr = IWICBitmapEncoder_Initialize(encoder, stream, WICBitmapEncoderNoCache); 2261 if (FAILED(hr)) goto cleanup_err; 2262 2263 hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frame, &encoder_options); 2264 if (FAILED(hr)) goto cleanup_err; 2265 2266 hr = IWICBitmapFrameEncode_Initialize(frame, encoder_options); 2267 if (FAILED(hr)) goto cleanup_err; 2268 2269 hr = IWICBitmapFrameEncode_SetSize(frame, width, height); 2270 if (FAILED(hr)) goto cleanup_err; 2271 2272 pixel_format_guid = d3dformat_to_wic_guid(src_surface_desc.Format); 2273 if (!pixel_format_guid) 2274 { 2275 FIXME("Pixel format %#x is not supported yet\n", src_surface_desc.Format); 2276 hr = E_NOTIMPL; 2277 goto cleanup; 2278 } 2279 2280 memcpy(&wic_pixel_format, pixel_format_guid, sizeof(GUID)); 2281 hr = IWICBitmapFrameEncode_SetPixelFormat(frame, &wic_pixel_format); 2282 d3d_pixel_format = wic_guid_to_d3dformat(&wic_pixel_format); 2283 if (SUCCEEDED(hr) && d3d_pixel_format != D3DFMT_UNKNOWN) 2284 { 2285 TRACE("Using pixel format %s %#x\n", debugstr_guid(&wic_pixel_format), d3d_pixel_format); 2286 2287 if (src_surface_desc.Format == d3d_pixel_format) /* Simple copy */ 2288 { 2289 hr = IDirect3DSurface9_LockRect(src_surface, &locked_rect, src_rect, D3DLOCK_READONLY); 2290 if (SUCCEEDED(hr)) 2291 { 2292 IWICBitmapFrameEncode_WritePixels(frame, height, 2293 locked_rect.Pitch, height * locked_rect.Pitch, locked_rect.pBits); 2294 IDirect3DSurface9_UnlockRect(src_surface); 2295 } 2296 } 2297 else /* Pixel format conversion */ 2298 { 2299 const struct pixel_format_desc *src_format_desc, *dst_format_desc; 2300 struct volume size; 2301 DWORD dst_pitch; 2302 void *dst_data; 2303 2304 src_format_desc = get_format_info(src_surface_desc.Format); 2305 dst_format_desc = get_format_info(d3d_pixel_format); 2306 if (!is_conversion_from_supported(src_format_desc) 2307 || !is_conversion_to_supported(dst_format_desc)) 2308 { 2309 FIXME("Unsupported format conversion %#x -> %#x.\n", 2310 src_surface_desc.Format, d3d_pixel_format); 2311 hr = E_NOTIMPL; 2312 goto cleanup; 2313 } 2314 2315 size.width = width; 2316 size.height = height; 2317 size.depth = 1; 2318 dst_pitch = width * dst_format_desc->bytes_per_pixel; 2319 dst_data = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height); 2320 if (!dst_data) 2321 { 2322 hr = E_OUTOFMEMORY; 2323 goto cleanup; 2324 } 2325 2326 hr = IDirect3DSurface9_LockRect(src_surface, &locked_rect, src_rect, D3DLOCK_READONLY); 2327 if (SUCCEEDED(hr)) 2328 { 2329 convert_argb_pixels(locked_rect.pBits, locked_rect.Pitch, 0, &size, src_format_desc, 2330 dst_data, dst_pitch, 0, &size, dst_format_desc, 0, NULL); 2331 IDirect3DSurface9_UnlockRect(src_surface); 2332 } 2333 2334 IWICBitmapFrameEncode_WritePixels(frame, height, dst_pitch, dst_pitch * height, dst_data); 2335 HeapFree(GetProcessHeap(), 0, dst_data); 2336 } 2337 2338 hr = IWICBitmapFrameEncode_Commit(frame); 2339 if (SUCCEEDED(hr)) hr = IWICBitmapEncoder_Commit(encoder); 2340 } 2341 else WARN("Unsupported pixel format %#x\n", src_surface_desc.Format); 2342 2343 /* copy data from stream to ID3DXBuffer */ 2344 hr = IStream_Stat(stream, &stream_stats, STATFLAG_NONAME); 2345 if (FAILED(hr)) goto cleanup_err; 2346 2347 if (stream_stats.cbSize.u.HighPart != 0) 2348 { 2349 hr = D3DXERR_INVALIDDATA; 2350 goto cleanup; 2351 } 2352 size = stream_stats.cbSize.u.LowPart; 2353 2354 /* Remove BMP header for DIB */ 2355 if (file_format == D3DXIFF_DIB) 2356 size -= sizeof(BITMAPFILEHEADER); 2357 2358 hr = D3DXCreateBuffer(size, &buffer); 2359 if (FAILED(hr)) goto cleanup; 2360 2361 hr = GetHGlobalFromStream(stream, &stream_hglobal); 2362 if (SUCCEEDED(hr)) 2363 { 2364 void *buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer); 2365 void *stream_data = GlobalLock(stream_hglobal); 2366 /* Remove BMP header for DIB */ 2367 if (file_format == D3DXIFF_DIB) 2368 stream_data = (void*)((BYTE*)stream_data + sizeof(BITMAPFILEHEADER)); 2369 memcpy(buffer_pointer, stream_data, size); 2370 GlobalUnlock(stream_hglobal); 2371 *dst_buffer = buffer; 2372 } 2373 else ID3DXBuffer_Release(buffer); 2374 2375 cleanup_err: 2376 if (FAILED(hr) && hr != E_OUTOFMEMORY) 2377 hr = D3DERR_INVALIDCALL; 2378 2379 cleanup: 2380 if (stream) IStream_Release(stream); 2381 2382 if (frame) IWICBitmapFrameEncode_Release(frame); 2383 if (encoder_options) IPropertyBag2_Release(encoder_options); 2384 2385 if (encoder) IWICBitmapEncoder_Release(encoder); 2386 2387 if (SUCCEEDED(initresult)) CoUninitialize(); 2388 2389 return hr; 2390 } 2391