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 return encode ? wined3d_dxt1_encode : wined3d_dxt1_decode; 1831 case D3DFMT_DXT3: 1832 return encode ? wined3d_dxt3_encode : wined3d_dxt3_decode; 1833 case D3DFMT_DXT5: 1834 return encode ? wined3d_dxt5_encode : wined3d_dxt5_decode; 1835 default: 1836 return NULL; 1837 } 1838 } 1839 1840 /************************************************************ 1841 * D3DXLoadSurfaceFromMemory 1842 * 1843 * Loads data from a given memory chunk into a surface, 1844 * applying any of the specified filters. 1845 * 1846 * PARAMS 1847 * pDestSurface [I] pointer to the surface 1848 * pDestPalette [I] palette to use 1849 * pDestRect [I] to be filled area of the surface 1850 * pSrcMemory [I] pointer to the source data 1851 * SrcFormat [I] format of the source pixel data 1852 * SrcPitch [I] number of bytes in a row 1853 * pSrcPalette [I] palette used in the source image 1854 * pSrcRect [I] area of the source data to load 1855 * dwFilter [I] filter to apply on stretching 1856 * Colorkey [I] colorkey 1857 * 1858 * RETURNS 1859 * Success: D3D_OK, if we successfully load the pixel data into our surface or 1860 * if pSrcMemory is NULL but the other parameters are valid 1861 * Failure: D3DERR_INVALIDCALL, if pDestSurface, SrcPitch or pSrcRect is NULL or 1862 * if SrcFormat is an invalid format (other than D3DFMT_UNKNOWN) or 1863 * if DestRect is invalid 1864 * D3DXERR_INVALIDDATA, if we fail to lock pDestSurface 1865 * E_FAIL, if SrcFormat is D3DFMT_UNKNOWN or the dimensions of pSrcRect are invalid 1866 * 1867 * NOTES 1868 * pSrcRect specifies the dimensions of the source data; 1869 * negative values for pSrcRect are allowed as we're only looking at the width and height anyway. 1870 * 1871 */ 1872 HRESULT WINAPI D3DXLoadSurfaceFromMemory(IDirect3DSurface9 *dst_surface, 1873 const PALETTEENTRY *dst_palette, const RECT *dst_rect, const void *src_memory, 1874 D3DFORMAT src_format, UINT src_pitch, const PALETTEENTRY *src_palette, const RECT *src_rect, 1875 DWORD filter, D3DCOLOR color_key) 1876 { 1877 const struct pixel_format_desc *srcformatdesc, *destformatdesc; 1878 void *tmp_src_memory = NULL, *tmp_dst_memory = NULL; 1879 dxtn_conversion_func pre_convert = NULL, post_convert = NULL; 1880 IDirect3DSurface9 *surface = dst_surface; 1881 IDirect3DDevice9 *device; 1882 D3DSURFACE_DESC surfdesc; 1883 D3DLOCKED_RECT lockrect; 1884 struct volume src_size, dst_size; 1885 HRESULT hr = D3D_OK; 1886 1887 TRACE("(%p, %p, %s, %p, %#x, %u, %p, %s, %#x, 0x%08x)\n", 1888 dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), src_memory, src_format, 1889 src_pitch, src_palette, wine_dbgstr_rect(src_rect), filter, color_key); 1890 1891 if (!dst_surface || !src_memory || !src_rect) 1892 { 1893 WARN("Invalid argument specified.\n"); 1894 return D3DERR_INVALIDCALL; 1895 } 1896 if (src_format == D3DFMT_UNKNOWN 1897 || src_rect->left >= src_rect->right 1898 || src_rect->top >= src_rect->bottom) 1899 { 1900 WARN("Invalid src_format or src_rect.\n"); 1901 return E_FAIL; 1902 } 1903 1904 if (filter == D3DX_DEFAULT) 1905 filter = D3DX_FILTER_TRIANGLE | D3DX_FILTER_DITHER; 1906 1907 IDirect3DSurface9_GetDesc(dst_surface, &surfdesc); 1908 1909 src_size.width = src_rect->right - src_rect->left; 1910 src_size.height = src_rect->bottom - src_rect->top; 1911 src_size.depth = 1; 1912 if (!dst_rect) 1913 { 1914 dst_size.width = surfdesc.Width; 1915 dst_size.height = surfdesc.Height; 1916 } 1917 else 1918 { 1919 if (dst_rect->left > dst_rect->right || dst_rect->right > surfdesc.Width 1920 || dst_rect->top > dst_rect->bottom || dst_rect->bottom > surfdesc.Height 1921 || dst_rect->left < 0 || dst_rect->top < 0) 1922 { 1923 WARN("Invalid dst_rect specified.\n"); 1924 return D3DERR_INVALIDCALL; 1925 } 1926 dst_size.width = dst_rect->right - dst_rect->left; 1927 dst_size.height = dst_rect->bottom - dst_rect->top; 1928 if (!dst_size.width || !dst_size.height) 1929 return D3D_OK; 1930 } 1931 dst_size.depth = 1; 1932 1933 srcformatdesc = get_format_info(src_format); 1934 destformatdesc = get_format_info(surfdesc.Format); 1935 if (srcformatdesc->type == FORMAT_UNKNOWN || destformatdesc->type == FORMAT_UNKNOWN) 1936 { 1937 FIXME("Unsupported pixel format conversion %#x -> %#x\n", src_format, surfdesc.Format); 1938 return E_NOTIMPL; 1939 } 1940 1941 if (surfdesc.Pool == D3DPOOL_DEFAULT && !(surfdesc.Usage & D3DUSAGE_DYNAMIC)) 1942 { 1943 IDirect3DSurface9_GetDevice(dst_surface, &device); 1944 hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, surfdesc.Width, 1945 surfdesc.Height, surfdesc.Format, D3DPOOL_SYSTEMMEM, &surface, NULL); 1946 IDirect3DDevice9_Release(device); 1947 if (FAILED(hr)) 1948 { 1949 WARN("Failed to create staging surface, hr %#x.\n", hr); 1950 return D3DERR_INVALIDCALL; 1951 } 1952 } 1953 1954 if (FAILED(IDirect3DSurface9_LockRect(surface, &lockrect, dst_rect, 0))) 1955 { 1956 if (surface != dst_surface) 1957 IDirect3DSurface9_Release(surface); 1958 return D3DXERR_INVALIDDATA; 1959 } 1960 1961 if (src_format == surfdesc.Format 1962 && dst_size.width == src_size.width 1963 && dst_size.height == src_size.height 1964 && color_key == 0) /* Simple copy. */ 1965 { 1966 if (src_rect->left & (srcformatdesc->block_width - 1) 1967 || src_rect->top & (srcformatdesc->block_height - 1) 1968 || (src_rect->right & (srcformatdesc->block_width - 1) 1969 && src_size.width != surfdesc.Width) 1970 || (src_rect->bottom & (srcformatdesc->block_height - 1) 1971 && src_size.height != surfdesc.Height)) 1972 { 1973 WARN("Source rect %s is misaligned.\n", wine_dbgstr_rect(src_rect)); 1974 hr = D3DXERR_INVALIDDATA; 1975 goto done; 1976 } 1977 1978 copy_pixels(src_memory, src_pitch, 0, lockrect.pBits, lockrect.Pitch, 0, 1979 &src_size, srcformatdesc); 1980 } 1981 else /* Stretching or format conversion. */ 1982 { 1983 UINT tmp_src_pitch, tmp_dst_pitch; 1984 1985 pre_convert = get_dxtn_conversion_func(srcformatdesc->format, FALSE); 1986 post_convert = get_dxtn_conversion_func(destformatdesc->format, TRUE); 1987 1988 if ((!pre_convert && !is_conversion_from_supported(srcformatdesc)) || 1989 (!post_convert && !is_conversion_to_supported(destformatdesc))) 1990 { 1991 FIXME("Unsupported format conversion %#x -> %#x.\n", src_format, surfdesc.Format); 1992 hr = E_NOTIMPL; 1993 goto done; 1994 } 1995 1996 /* handle pre-conversion */ 1997 if (pre_convert) 1998 { 1999 tmp_src_memory = HeapAlloc(GetProcessHeap(), 0, src_size.width * src_size.height * sizeof(DWORD)); 2000 if (!tmp_src_memory) 2001 { 2002 hr = E_OUTOFMEMORY; 2003 goto done; 2004 } 2005 tmp_src_pitch = src_size.width * sizeof(DWORD); 2006 if (!pre_convert(src_memory, tmp_src_memory, src_pitch, tmp_src_pitch, 2007 WINED3DFMT_B8G8R8A8_UNORM, src_size.width, src_size.height)) 2008 { 2009 hr = E_FAIL; 2010 goto done; 2011 } 2012 srcformatdesc = get_format_info(D3DFMT_A8R8G8B8); 2013 } 2014 else 2015 { 2016 tmp_src_memory = (void *)src_memory; 2017 tmp_src_pitch = src_pitch; 2018 } 2019 2020 /* handle post-conversion */ 2021 if (post_convert) 2022 { 2023 tmp_dst_memory = HeapAlloc(GetProcessHeap(), 0, dst_size.width * dst_size.height * sizeof(DWORD)); 2024 if (!tmp_dst_memory) 2025 { 2026 hr = E_OUTOFMEMORY; 2027 goto done; 2028 } 2029 tmp_dst_pitch = dst_size.width * sizeof(DWORD); 2030 destformatdesc = get_format_info(D3DFMT_A8R8G8B8); 2031 } 2032 else 2033 { 2034 tmp_dst_memory = lockrect.pBits; 2035 tmp_dst_pitch = lockrect.Pitch; 2036 } 2037 2038 if ((filter & 0xf) == D3DX_FILTER_NONE) 2039 { 2040 convert_argb_pixels(tmp_src_memory, tmp_src_pitch, 0, &src_size, srcformatdesc, 2041 tmp_dst_memory, tmp_dst_pitch, 0, &dst_size, destformatdesc, color_key, src_palette); 2042 } 2043 else /* if ((filter & 0xf) == D3DX_FILTER_POINT) */ 2044 { 2045 if ((filter & 0xf) != D3DX_FILTER_POINT) 2046 FIXME("Unhandled filter %#x.\n", filter); 2047 2048 /* Always apply a point filter until D3DX_FILTER_LINEAR, 2049 * D3DX_FILTER_TRIANGLE and D3DX_FILTER_BOX are implemented. */ 2050 point_filter_argb_pixels(tmp_src_memory, tmp_src_pitch, 0, &src_size, srcformatdesc, 2051 tmp_dst_memory, tmp_dst_pitch, 0, &dst_size, destformatdesc, color_key, src_palette); 2052 } 2053 2054 /* handle post-conversion */ 2055 if (post_convert) 2056 { 2057 if (!post_convert(tmp_dst_memory, lockrect.pBits, tmp_dst_pitch, lockrect.Pitch, 2058 WINED3DFMT_B8G8R8A8_UNORM, dst_size.width, dst_size.height)) 2059 { 2060 hr = E_FAIL; 2061 goto done; 2062 } 2063 } 2064 } 2065 2066 done: 2067 IDirect3DSurface9_UnlockRect(surface); 2068 if (surface != dst_surface) 2069 { 2070 if (SUCCEEDED(hr)) 2071 { 2072 IDirect3DSurface9_GetDevice(dst_surface, &device); 2073 hr = IDirect3DDevice9_UpdateSurface(device, surface, NULL, dst_surface, NULL); 2074 IDirect3DDevice9_Release(device); 2075 } 2076 IDirect3DSurface9_Release(surface); 2077 2078 if (pre_convert) 2079 HeapFree(GetProcessHeap(), 0, tmp_src_memory); 2080 if (post_convert) 2081 HeapFree(GetProcessHeap(), 0, tmp_dst_memory); 2082 IDirect3DSurface9_UnlockRect(dst_surface); 2083 } 2084 2085 return hr; 2086 } 2087 2088 /************************************************************ 2089 * D3DXLoadSurfaceFromSurface 2090 * 2091 * Copies the contents from one surface to another, performing any required 2092 * format conversion, resizing or filtering. 2093 * 2094 * PARAMS 2095 * pDestSurface [I] pointer to the destination surface 2096 * pDestPalette [I] palette to use 2097 * pDestRect [I] to be filled area of the surface 2098 * pSrcSurface [I] pointer to the source surface 2099 * pSrcPalette [I] palette used for the source surface 2100 * pSrcRect [I] area of the source data to load 2101 * dwFilter [I] filter to apply on resizing 2102 * Colorkey [I] any ARGB value or 0 to disable color-keying 2103 * 2104 * RETURNS 2105 * Success: D3D_OK 2106 * Failure: D3DERR_INVALIDCALL, if pDestSurface or pSrcSurface is NULL 2107 * D3DXERR_INVALIDDATA, if one of the surfaces is not lockable 2108 * 2109 */ 2110 HRESULT WINAPI D3DXLoadSurfaceFromSurface(IDirect3DSurface9 *dst_surface, 2111 const PALETTEENTRY *dst_palette, const RECT *dst_rect, IDirect3DSurface9 *src_surface, 2112 const PALETTEENTRY *src_palette, const RECT *src_rect, DWORD filter, D3DCOLOR color_key) 2113 { 2114 IDirect3DSurface9 *surface = src_surface; 2115 D3DTEXTUREFILTERTYPE d3d_filter; 2116 IDirect3DDevice9 *device; 2117 D3DSURFACE_DESC src_desc; 2118 D3DLOCKED_RECT lock; 2119 HRESULT hr; 2120 RECT s; 2121 2122 TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_surface %p, " 2123 "src_palette %p, src_rect %s, filter %#x, color_key 0x%08x.\n", 2124 dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), src_surface, 2125 src_palette, wine_dbgstr_rect(src_rect), filter, color_key); 2126 2127 if (!dst_surface || !src_surface) 2128 return D3DERR_INVALIDCALL; 2129 2130 if (!dst_palette && !src_palette && !color_key) 2131 { 2132 switch (filter) 2133 { 2134 case D3DX_FILTER_NONE: 2135 d3d_filter = D3DTEXF_NONE; 2136 break; 2137 2138 case D3DX_FILTER_POINT: 2139 d3d_filter = D3DTEXF_POINT; 2140 break; 2141 2142 case D3DX_FILTER_LINEAR: 2143 d3d_filter = D3DTEXF_LINEAR; 2144 break; 2145 2146 default: 2147 d3d_filter = ~0u; 2148 break; 2149 } 2150 2151 if (d3d_filter != ~0u) 2152 { 2153 IDirect3DSurface9_GetDevice(src_surface, &device); 2154 hr = IDirect3DDevice9_StretchRect(device, src_surface, src_rect, dst_surface, dst_rect, d3d_filter); 2155 IDirect3DDevice9_Release(device); 2156 if (SUCCEEDED(hr)) 2157 return D3D_OK; 2158 } 2159 } 2160 2161 IDirect3DSurface9_GetDesc(src_surface, &src_desc); 2162 2163 if (!src_rect) 2164 { 2165 SetRect(&s, 0, 0, src_desc.Width, src_desc.Height); 2166 src_rect = &s; 2167 } 2168 2169 if (FAILED(IDirect3DSurface9_LockRect(surface, &lock, NULL, D3DLOCK_READONLY))) 2170 { 2171 IDirect3DSurface9_GetDevice(src_surface, &device); 2172 if (FAILED(IDirect3DDevice9_CreateRenderTarget(device, src_desc.Width, src_desc.Height, 2173 src_desc.Format, D3DMULTISAMPLE_NONE, 0, TRUE, &surface, NULL))) 2174 { 2175 IDirect3DDevice9_Release(device); 2176 return D3DXERR_INVALIDDATA; 2177 } 2178 2179 if (SUCCEEDED(hr = IDirect3DDevice9_StretchRect(device, src_surface, NULL, surface, NULL, D3DTEXF_NONE))) 2180 hr = IDirect3DSurface9_LockRect(surface, &lock, NULL, D3DLOCK_READONLY); 2181 IDirect3DDevice9_Release(device); 2182 if (FAILED(hr)) 2183 { 2184 IDirect3DSurface9_Release(surface); 2185 return D3DXERR_INVALIDDATA; 2186 } 2187 } 2188 2189 hr = D3DXLoadSurfaceFromMemory(dst_surface, dst_palette, dst_rect, lock.pBits, 2190 src_desc.Format, lock.Pitch, src_palette, src_rect, filter, color_key); 2191 2192 IDirect3DSurface9_UnlockRect(surface); 2193 if (surface != src_surface) 2194 IDirect3DSurface9_Release(surface); 2195 2196 return hr; 2197 } 2198 2199 2200 HRESULT WINAPI D3DXSaveSurfaceToFileA(const char *dst_filename, D3DXIMAGE_FILEFORMAT file_format, 2201 IDirect3DSurface9 *src_surface, const PALETTEENTRY *src_palette, const RECT *src_rect) 2202 { 2203 int len; 2204 WCHAR *filename; 2205 HRESULT hr; 2206 ID3DXBuffer *buffer; 2207 2208 TRACE("(%s, %#x, %p, %p, %s): relay\n", 2209 wine_dbgstr_a(dst_filename), file_format, src_surface, src_palette, wine_dbgstr_rect(src_rect)); 2210 2211 if (!dst_filename) return D3DERR_INVALIDCALL; 2212 2213 len = MultiByteToWideChar(CP_ACP, 0, dst_filename, -1, NULL, 0); 2214 filename = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 2215 if (!filename) return E_OUTOFMEMORY; 2216 MultiByteToWideChar(CP_ACP, 0, dst_filename, -1, filename, len); 2217 2218 hr = D3DXSaveSurfaceToFileInMemory(&buffer, file_format, src_surface, src_palette, src_rect); 2219 if (SUCCEEDED(hr)) 2220 { 2221 hr = write_buffer_to_file(filename, buffer); 2222 ID3DXBuffer_Release(buffer); 2223 } 2224 2225 HeapFree(GetProcessHeap(), 0, filename); 2226 return hr; 2227 } 2228 2229 HRESULT WINAPI D3DXSaveSurfaceToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEFORMAT file_format, 2230 IDirect3DSurface9 *src_surface, const PALETTEENTRY *src_palette, const RECT *src_rect) 2231 { 2232 HRESULT hr; 2233 ID3DXBuffer *buffer; 2234 2235 TRACE("(%s, %#x, %p, %p, %s): relay\n", 2236 wine_dbgstr_w(dst_filename), file_format, src_surface, src_palette, wine_dbgstr_rect(src_rect)); 2237 2238 if (!dst_filename) return D3DERR_INVALIDCALL; 2239 2240 hr = D3DXSaveSurfaceToFileInMemory(&buffer, file_format, src_surface, src_palette, src_rect); 2241 if (SUCCEEDED(hr)) 2242 { 2243 hr = write_buffer_to_file(dst_filename, buffer); 2244 ID3DXBuffer_Release(buffer); 2245 } 2246 2247 return hr; 2248 } 2249 2250 HRESULT WINAPI D3DXSaveSurfaceToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE_FILEFORMAT file_format, 2251 IDirect3DSurface9 *src_surface, const PALETTEENTRY *src_palette, const RECT *src_rect) 2252 { 2253 IWICBitmapEncoder *encoder = NULL; 2254 IWICBitmapFrameEncode *frame = NULL; 2255 IPropertyBag2 *encoder_options = NULL; 2256 IStream *stream = NULL; 2257 HRESULT hr; 2258 HRESULT initresult; 2259 const CLSID *encoder_clsid; 2260 const GUID *pixel_format_guid; 2261 WICPixelFormatGUID wic_pixel_format; 2262 D3DFORMAT d3d_pixel_format; 2263 D3DSURFACE_DESC src_surface_desc; 2264 D3DLOCKED_RECT locked_rect; 2265 int width, height; 2266 STATSTG stream_stats; 2267 HGLOBAL stream_hglobal; 2268 ID3DXBuffer *buffer; 2269 DWORD size; 2270 2271 TRACE("(%p, %#x, %p, %p, %s)\n", 2272 dst_buffer, file_format, src_surface, src_palette, wine_dbgstr_rect(src_rect)); 2273 2274 if (!dst_buffer || !src_surface) return D3DERR_INVALIDCALL; 2275 2276 if (src_palette) 2277 { 2278 FIXME("Saving surfaces with palettized pixel formats is not implemented yet\n"); 2279 return D3DERR_INVALIDCALL; 2280 } 2281 2282 switch (file_format) 2283 { 2284 case D3DXIFF_BMP: 2285 case D3DXIFF_DIB: 2286 encoder_clsid = &CLSID_WICBmpEncoder; 2287 break; 2288 case D3DXIFF_PNG: 2289 encoder_clsid = &CLSID_WICPngEncoder; 2290 break; 2291 case D3DXIFF_JPG: 2292 encoder_clsid = &CLSID_WICJpegEncoder; 2293 break; 2294 case D3DXIFF_DDS: 2295 return save_dds_surface_to_memory(dst_buffer, src_surface, src_rect); 2296 case D3DXIFF_HDR: 2297 case D3DXIFF_PFM: 2298 case D3DXIFF_TGA: 2299 case D3DXIFF_PPM: 2300 FIXME("File format %#x is not supported yet\n", file_format); 2301 return E_NOTIMPL; 2302 default: 2303 return D3DERR_INVALIDCALL; 2304 } 2305 2306 IDirect3DSurface9_GetDesc(src_surface, &src_surface_desc); 2307 if (src_rect) 2308 { 2309 if (src_rect->left == src_rect->right || src_rect->top == src_rect->bottom) 2310 { 2311 WARN("Invalid rectangle with 0 area\n"); 2312 return D3DXCreateBuffer(64, dst_buffer); 2313 } 2314 if (src_rect->left < 0 || src_rect->top < 0) 2315 return D3DERR_INVALIDCALL; 2316 if (src_rect->left > src_rect->right || src_rect->top > src_rect->bottom) 2317 return D3DERR_INVALIDCALL; 2318 if (src_rect->right > src_surface_desc.Width || src_rect->bottom > src_surface_desc.Height) 2319 return D3DERR_INVALIDCALL; 2320 2321 width = src_rect->right - src_rect->left; 2322 height = src_rect->bottom - src_rect->top; 2323 } 2324 else 2325 { 2326 width = src_surface_desc.Width; 2327 height = src_surface_desc.Height; 2328 } 2329 2330 initresult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); 2331 2332 hr = CoCreateInstance(encoder_clsid, NULL, CLSCTX_INPROC_SERVER, 2333 &IID_IWICBitmapEncoder, (void **)&encoder); 2334 if (FAILED(hr)) goto cleanup_err; 2335 2336 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); 2337 if (FAILED(hr)) goto cleanup_err; 2338 2339 hr = IWICBitmapEncoder_Initialize(encoder, stream, WICBitmapEncoderNoCache); 2340 if (FAILED(hr)) goto cleanup_err; 2341 2342 hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frame, &encoder_options); 2343 if (FAILED(hr)) goto cleanup_err; 2344 2345 hr = IWICBitmapFrameEncode_Initialize(frame, encoder_options); 2346 if (FAILED(hr)) goto cleanup_err; 2347 2348 hr = IWICBitmapFrameEncode_SetSize(frame, width, height); 2349 if (FAILED(hr)) goto cleanup_err; 2350 2351 pixel_format_guid = d3dformat_to_wic_guid(src_surface_desc.Format); 2352 if (!pixel_format_guid) 2353 { 2354 FIXME("Pixel format %#x is not supported yet\n", src_surface_desc.Format); 2355 hr = E_NOTIMPL; 2356 goto cleanup; 2357 } 2358 2359 memcpy(&wic_pixel_format, pixel_format_guid, sizeof(GUID)); 2360 hr = IWICBitmapFrameEncode_SetPixelFormat(frame, &wic_pixel_format); 2361 d3d_pixel_format = wic_guid_to_d3dformat(&wic_pixel_format); 2362 if (SUCCEEDED(hr) && d3d_pixel_format != D3DFMT_UNKNOWN) 2363 { 2364 TRACE("Using pixel format %s %#x\n", debugstr_guid(&wic_pixel_format), d3d_pixel_format); 2365 2366 if (src_surface_desc.Format == d3d_pixel_format) /* Simple copy */ 2367 { 2368 hr = IDirect3DSurface9_LockRect(src_surface, &locked_rect, src_rect, D3DLOCK_READONLY); 2369 if (SUCCEEDED(hr)) 2370 { 2371 IWICBitmapFrameEncode_WritePixels(frame, height, 2372 locked_rect.Pitch, height * locked_rect.Pitch, locked_rect.pBits); 2373 IDirect3DSurface9_UnlockRect(src_surface); 2374 } 2375 } 2376 else /* Pixel format conversion */ 2377 { 2378 const struct pixel_format_desc *src_format_desc, *dst_format_desc; 2379 struct volume size; 2380 DWORD dst_pitch; 2381 void *dst_data; 2382 2383 src_format_desc = get_format_info(src_surface_desc.Format); 2384 dst_format_desc = get_format_info(d3d_pixel_format); 2385 if (!is_conversion_from_supported(src_format_desc) 2386 || !is_conversion_to_supported(dst_format_desc)) 2387 { 2388 FIXME("Unsupported format conversion %#x -> %#x.\n", 2389 src_surface_desc.Format, d3d_pixel_format); 2390 hr = E_NOTIMPL; 2391 goto cleanup; 2392 } 2393 2394 size.width = width; 2395 size.height = height; 2396 size.depth = 1; 2397 dst_pitch = width * dst_format_desc->bytes_per_pixel; 2398 dst_data = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height); 2399 if (!dst_data) 2400 { 2401 hr = E_OUTOFMEMORY; 2402 goto cleanup; 2403 } 2404 2405 hr = IDirect3DSurface9_LockRect(src_surface, &locked_rect, src_rect, D3DLOCK_READONLY); 2406 if (SUCCEEDED(hr)) 2407 { 2408 convert_argb_pixels(locked_rect.pBits, locked_rect.Pitch, 0, &size, src_format_desc, 2409 dst_data, dst_pitch, 0, &size, dst_format_desc, 0, NULL); 2410 IDirect3DSurface9_UnlockRect(src_surface); 2411 } 2412 2413 IWICBitmapFrameEncode_WritePixels(frame, height, dst_pitch, dst_pitch * height, dst_data); 2414 HeapFree(GetProcessHeap(), 0, dst_data); 2415 } 2416 2417 hr = IWICBitmapFrameEncode_Commit(frame); 2418 if (SUCCEEDED(hr)) hr = IWICBitmapEncoder_Commit(encoder); 2419 } 2420 else WARN("Unsupported pixel format %#x\n", src_surface_desc.Format); 2421 2422 /* copy data from stream to ID3DXBuffer */ 2423 hr = IStream_Stat(stream, &stream_stats, STATFLAG_NONAME); 2424 if (FAILED(hr)) goto cleanup_err; 2425 2426 if (stream_stats.cbSize.u.HighPart != 0) 2427 { 2428 hr = D3DXERR_INVALIDDATA; 2429 goto cleanup; 2430 } 2431 size = stream_stats.cbSize.u.LowPart; 2432 2433 /* Remove BMP header for DIB */ 2434 if (file_format == D3DXIFF_DIB) 2435 size -= sizeof(BITMAPFILEHEADER); 2436 2437 hr = D3DXCreateBuffer(size, &buffer); 2438 if (FAILED(hr)) goto cleanup; 2439 2440 hr = GetHGlobalFromStream(stream, &stream_hglobal); 2441 if (SUCCEEDED(hr)) 2442 { 2443 void *buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer); 2444 void *stream_data = GlobalLock(stream_hglobal); 2445 /* Remove BMP header for DIB */ 2446 if (file_format == D3DXIFF_DIB) 2447 stream_data = (void*)((BYTE*)stream_data + sizeof(BITMAPFILEHEADER)); 2448 memcpy(buffer_pointer, stream_data, size); 2449 GlobalUnlock(stream_hglobal); 2450 *dst_buffer = buffer; 2451 } 2452 else ID3DXBuffer_Release(buffer); 2453 2454 cleanup_err: 2455 if (FAILED(hr) && hr != E_OUTOFMEMORY) 2456 hr = D3DERR_INVALIDCALL; 2457 2458 cleanup: 2459 if (stream) IStream_Release(stream); 2460 2461 if (frame) IWICBitmapFrameEncode_Release(frame); 2462 if (encoder_options) IPropertyBag2_Release(encoder_options); 2463 2464 if (encoder) IWICBitmapEncoder_Release(encoder); 2465 2466 if (SUCCEEDED(initresult)) CoUninitialize(); 2467 2468 return hr; 2469 } 2470