2 * Copyright (C) 2009-2010 Tony Wasserka
3 * Copyright (C) 2012 Józef Kucia
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.
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.
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
22 #include "wine/port.h"
24 #include "d3dx9_private.h"
30 #include "wine/wined3d.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(d3dx
);
35 /* Wine-specific WIC GUIDs */
36 DEFINE_GUID(GUID_WineContainerFormatTga
, 0x0c44fda1,0xa5c5,0x4298,0x96,0x85,0x47,0x3f,0xc1,0x7c,0xd3,0x22);
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
}
54 static D3DFORMAT
wic_guid_to_d3dformat(const GUID
*guid
)
58 for (i
= 0; i
< ARRAY_SIZE(wic_pixel_formats
); i
++)
60 if (IsEqualGUID(wic_pixel_formats
[i
].wic_guid
, guid
))
61 return wic_pixel_formats
[i
].d3dformat
;
64 return D3DFMT_UNKNOWN
;
67 static const GUID
*d3dformat_to_wic_guid(D3DFORMAT format
)
71 for (i
= 0; i
< ARRAY_SIZE(wic_pixel_formats
); i
++)
73 if (wic_pixel_formats
[i
].d3dformat
== format
)
74 return wic_pixel_formats
[i
].wic_guid
;
80 /* dds_header.flags */
82 #define DDS_HEIGHT 0x2
85 #define DDS_PIXELFORMAT 0x1000
86 #define DDS_MIPMAPCOUNT 0x20000
87 #define DDS_LINEARSIZE 0x80000
88 #define DDS_DEPTH 0x800000
91 #define DDS_CAPS_COMPLEX 0x8
92 #define DDS_CAPS_TEXTURE 0x1000
93 #define DDS_CAPS_MIPMAP 0x400000
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
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
118 struct dds_pixel_format
137 DWORD pitch_or_linear_size
;
141 struct dds_pixel_format pixel_format
;
149 static D3DFORMAT
dds_fourcc_to_d3dformat(DWORD fourcc
)
152 static const DWORD known_fourcc
[] = {
164 D3DFMT_A16B16G16R16F
,
167 D3DFMT_A32B32G32R32F
,
170 for (i
= 0; i
< ARRAY_SIZE(known_fourcc
); i
++)
172 if (known_fourcc
[i
] == fourcc
)
176 WARN("Unknown FourCC %#x\n", fourcc
);
177 return D3DFMT_UNKNOWN
;
180 static const struct {
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
},
205 static D3DFORMAT
dds_rgb_to_d3dformat(const struct dds_pixel_format
*pixel_format
)
209 for (i
= 0; i
< ARRAY_SIZE(rgb_pixel_formats
); i
++)
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
)
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
;
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
;
228 static D3DFORMAT
dds_luminance_to_d3dformat(const struct dds_pixel_format
*pixel_format
)
230 if (pixel_format
->bpp
== 8)
232 if (pixel_format
->rmask
== 0xff)
234 if ((pixel_format
->flags
& DDS_PF_ALPHA
) && pixel_format
->rmask
== 0x0f && pixel_format
->amask
== 0xf0)
237 if (pixel_format
->bpp
== 16)
239 if (pixel_format
->rmask
== 0xffff)
241 if ((pixel_format
->flags
& DDS_PF_ALPHA
) && pixel_format
->rmask
== 0x00ff && pixel_format
->amask
== 0xff00)
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
;
250 static D3DFORMAT
dds_alpha_to_d3dformat(const struct dds_pixel_format
*pixel_format
)
252 if (pixel_format
->bpp
== 8 && pixel_format
->amask
== 0xff)
255 WARN("Unknown Alpha pixel format (%u, %#x)\n", pixel_format
->bpp
, pixel_format
->rmask
);
256 return D3DFMT_UNKNOWN
;
259 static D3DFORMAT
dds_bump_to_d3dformat(const struct dds_pixel_format
*pixel_format
)
261 if (pixel_format
->bpp
== 16 && pixel_format
->rmask
== 0x00ff && pixel_format
->gmask
== 0xff00)
263 if (pixel_format
->bpp
== 32 && pixel_format
->rmask
== 0x0000ffff && pixel_format
->gmask
== 0xffff0000)
264 return D3DFMT_V16U16
;
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
;
271 static D3DFORMAT
dds_bump_luminance_to_d3dformat(const struct dds_pixel_format
*pixel_format
)
273 if (pixel_format
->bpp
== 32 && pixel_format
->rmask
== 0x000000ff && pixel_format
->gmask
== 0x0000ff00
274 && pixel_format
->bmask
== 0x00ff0000)
275 return D3DFMT_X8L8V8U8
;
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
;
282 static D3DFORMAT
dds_pixel_format_to_d3dformat(const struct dds_pixel_format
*pixel_format
)
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
);
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
);
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
;
308 static HRESULT
d3dformat_to_dds_pixel_format(struct dds_pixel_format
*pixel_format
, D3DFORMAT d3dformat
)
312 memset(pixel_format
, 0, sizeof(*pixel_format
));
314 pixel_format
->size
= sizeof(*pixel_format
);
316 for (i
= 0; i
< ARRAY_SIZE(rgb_pixel_formats
); i
++)
318 if (rgb_pixel_formats
[i
].format
== d3dformat
)
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
;
331 /* Reuse dds_fourcc_to_d3dformat as D3DFORMAT and FOURCC are DWORD with same values */
332 if (dds_fourcc_to_d3dformat(d3dformat
) != D3DFMT_UNKNOWN
)
334 pixel_format
->flags
|= DDS_PF_FOURCC
;
335 pixel_format
->fourcc
= d3dformat
;
339 WARN("Unknown pixel format %#x\n", d3dformat
);
343 static HRESULT
calculate_dds_surface_size(D3DFORMAT format
, UINT width
, UINT height
,
344 UINT
*pitch
, UINT
*size
)
346 const struct pixel_format_desc
*format_desc
= get_format_info(format
);
347 if (format_desc
->type
== FORMAT_UNKNOWN
)
350 if (format_desc
->block_width
!= 1 || format_desc
->block_height
!= 1)
352 *pitch
= format_desc
->block_byte_count
353 * max(1, (width
+ format_desc
->block_width
- 1) / format_desc
->block_width
);
355 * max(1, (height
+ format_desc
->block_height
- 1) / format_desc
->block_height
);
359 *pitch
= width
* format_desc
->bytes_per_pixel
;
360 *size
= *pitch
* height
;
366 static UINT
calculate_dds_file_size(D3DFORMAT format
, UINT width
, UINT height
, UINT depth
,
367 UINT miplevels
, UINT faces
)
369 UINT i
, file_size
= 0;
371 for (i
= 0; i
< miplevels
; i
++)
373 UINT pitch
, size
= 0;
374 calculate_dds_surface_size(format
, width
, height
, &pitch
, &size
);
377 width
= max(1, width
/ 2);
378 height
= max(1, height
/ 2);
379 depth
= max(1, depth
/ 2);
383 file_size
+= sizeof(struct dds_header
);
387 /************************************************************
388 * get_image_info_from_dds
390 * Fills a D3DXIMAGE_INFO structure with information
391 * about a DDS file stored in the memory.
394 * buffer [I] pointer to DDS data
395 * length [I] size of DDS data
396 * info [O] pointer to D3DXIMAGE_INFO structure
400 * Failure: D3DXERR_INVALIDDATA
403 static HRESULT
get_image_info_from_dds(const void *buffer
, UINT length
, D3DXIMAGE_INFO
*info
)
406 UINT expected_length
;
407 const struct dds_header
*header
= buffer
;
409 if (length
< sizeof(*header
) || !info
)
410 return D3DXERR_INVALIDDATA
;
412 if (header
->pixel_format
.size
!= sizeof(header
->pixel_format
))
413 return D3DXERR_INVALIDDATA
;
415 info
->Width
= header
->width
;
416 info
->Height
= header
->height
;
418 info
->MipLevels
= header
->miplevels
? header
->miplevels
: 1;
420 info
->Format
= dds_pixel_format_to_d3dformat(&header
->pixel_format
);
421 if (info
->Format
== D3DFMT_UNKNOWN
)
422 return D3DXERR_INVALIDDATA
;
424 TRACE("Pixel format is %#x\n", info
->Format
);
426 if (header
->caps2
& DDS_CAPS2_VOLUME
)
428 info
->Depth
= header
->depth
;
429 info
->ResourceType
= D3DRTYPE_VOLUMETEXTURE
;
431 else if (header
->caps2
& DDS_CAPS2_CUBEMAP
)
435 for (face
= DDS_CAPS2_CUBEMAP_POSITIVEX
; face
<= DDS_CAPS2_CUBEMAP_NEGATIVEZ
; face
<<= 1)
437 if (header
->caps2
& face
)
440 info
->ResourceType
= D3DRTYPE_CUBETEXTURE
;
444 info
->ResourceType
= D3DRTYPE_TEXTURE
;
447 expected_length
= calculate_dds_file_size(info
->Format
, info
->Width
, info
->Height
, info
->Depth
,
448 info
->MipLevels
, faces
);
449 if (length
< expected_length
)
451 WARN("File is too short %u, expected at least %u bytes\n", length
, expected_length
);
452 return D3DXERR_INVALIDDATA
;
455 info
->ImageFileFormat
= D3DXIFF_DDS
;
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
)
465 const struct dds_header
*header
= src_data
;
466 const BYTE
*pixels
= (BYTE
*)(header
+ 1);
468 if (src_info
->ResourceType
!= D3DRTYPE_TEXTURE
)
469 return D3DXERR_INVALIDDATA
;
471 if (FAILED(calculate_dds_surface_size(src_info
->Format
, src_info
->Width
, src_info
->Height
, &src_pitch
, &size
)))
474 return D3DXLoadSurfaceFromMemory(dst_surface
, dst_palette
, dst_rect
, pixels
, src_info
->Format
,
475 src_pitch
, NULL
, src_rect
, filter
, color_key
);
478 static HRESULT
save_dds_surface_to_memory(ID3DXBuffer
**dst_buffer
, IDirect3DSurface9
*src_surface
, const RECT
*src_rect
)
481 UINT dst_pitch
, surface_size
, file_size
;
482 D3DSURFACE_DESC src_desc
;
483 D3DLOCKED_RECT locked_rect
;
485 struct dds_header
*header
;
487 struct volume volume
;
488 const struct pixel_format_desc
*pixel_format
;
492 FIXME("Saving a part of a surface to a DDS file is not implemented yet\n");
496 hr
= IDirect3DSurface9_GetDesc(src_surface
, &src_desc
);
497 if (FAILED(hr
)) return hr
;
499 pixel_format
= get_format_info(src_desc
.Format
);
500 if (pixel_format
->type
== FORMAT_UNKNOWN
) return E_NOTIMPL
;
502 file_size
= calculate_dds_file_size(src_desc
.Format
, src_desc
.Width
, src_desc
.Height
, 1, 1, 1);
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
;
507 hr
= D3DXCreateBuffer(file_size
, &buffer
);
508 if (FAILED(hr
)) return hr
;
510 header
= ID3DXBuffer_GetBufferPointer(buffer
);
511 pixels
= (BYTE
*)(header
+ 1);
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
);
524 ID3DXBuffer_Release(buffer
);
528 hr
= IDirect3DSurface9_LockRect(src_surface
, &locked_rect
, NULL
, D3DLOCK_READONLY
);
531 ID3DXBuffer_Release(buffer
);
535 volume
.width
= src_desc
.Width
;
536 volume
.height
= src_desc
.Height
;
538 copy_pixels(locked_rect
.pBits
, locked_rect
.Pitch
, 0, pixels
, dst_pitch
, 0,
539 &volume
, pixel_format
);
541 IDirect3DSurface9_UnlockRect(src_surface
);
543 *dst_buffer
= buffer
;
547 static HRESULT
get_surface(D3DRESOURCETYPE type
, struct IDirect3DBaseTexture9
*tex
,
548 int face
, UINT level
, struct IDirect3DSurface9
**surf
)
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
);
557 ERR("Unexpected texture type\n");
562 HRESULT
save_dds_texture_to_memory(ID3DXBuffer
**dst_buffer
, IDirect3DBaseTexture9
*src_texture
, const PALETTEENTRY
*src_palette
)
565 D3DRESOURCETYPE type
;
567 IDirect3DSurface9
*surface
;
569 type
= IDirect3DBaseTexture9_GetType(src_texture
);
571 if ((type
!= D3DRTYPE_TEXTURE
) && (type
!= D3DRTYPE_CUBETEXTURE
) && (type
!= D3DRTYPE_VOLUMETEXTURE
))
572 return D3DERR_INVALIDCALL
;
574 if (type
== D3DRTYPE_CUBETEXTURE
)
576 FIXME("Cube texture not supported yet\n");
579 else if (type
== D3DRTYPE_VOLUMETEXTURE
)
581 FIXME("Volume texture not supported yet\n");
585 mip_levels
= IDirect3DTexture9_GetLevelCount(src_texture
);
589 FIXME("Mipmap not supported yet\n");
595 FIXME("Saving surfaces with palettized pixel formats not implemented yet\n");
599 hr
= get_surface(type
, src_texture
, D3DCUBEMAP_FACE_POSITIVE_X
, 0, &surface
);
603 hr
= save_dds_surface_to_memory(dst_buffer
, surface
, NULL
);
604 IDirect3DSurface9_Release(surface
);
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
)
613 UINT row_pitch
, slice_pitch
;
614 const struct dds_header
*header
= src_data
;
615 const BYTE
*pixels
= (BYTE
*)(header
+ 1);
617 if (src_info
->ResourceType
!= D3DRTYPE_VOLUMETEXTURE
)
618 return D3DXERR_INVALIDDATA
;
620 if (FAILED(calculate_dds_surface_size(src_info
->Format
, src_info
->Width
, src_info
->Height
, &row_pitch
, &slice_pitch
)))
623 return D3DXLoadVolumeFromMemory(dst_volume
, dst_palette
, dst_box
, pixels
, src_info
->Format
,
624 row_pitch
, slice_pitch
, NULL
, src_box
, filter
, color_key
);
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
)
638 IDirect3DSurface9
*surface
;
639 const struct dds_header
*header
= src_data
;
640 const BYTE
*pixels
= (BYTE
*)(header
+ 1);
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
))
648 WARN("Trying to load a %u resource as a 2D texture, returning failure.\n", src_info
->ResourceType
);
649 return D3DXERR_INVALIDDATA
;
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
)
657 for (mip_level
= 0; mip_level
< mip_levels
+ skip_levels
; ++mip_level
)
659 hr
= calculate_dds_surface_size(src_info
->Format
, width
, height
, &src_pitch
, &mip_level_size
);
660 if (FAILED(hr
)) return hr
;
662 if (mip_level
>= skip_levels
)
664 SetRect(&src_rect
, 0, 0, width
, height
);
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
);
674 pixels
+= mip_level_size
;
675 width
= max(1, width
/ 2);
676 height
= max(1, height
/ 2);
679 *loaded_miplevels
= mip_levels
- skip_levels
;
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
)
695 IDirect3DSurface9
*surface
;
696 const struct dds_header
*header
= src_data
;
697 const BYTE
*pixels
= (BYTE
*)(header
+ 1);
699 if (src_info
->ResourceType
!= D3DRTYPE_CUBETEXTURE
)
700 return D3DXERR_INVALIDDATA
;
702 if ((header
->caps2
& DDS_CAPS2_CUBEMAP_ALL_FACES
) != DDS_CAPS2_CUBEMAP_ALL_FACES
)
704 WARN("Only full cubemaps are supported\n");
705 return D3DXERR_INVALIDDATA
;
708 mip_levels
= min(src_info
->MipLevels
, IDirect3DCubeTexture9_GetLevelCount(cube_texture
));
709 for (face
= D3DCUBEMAP_FACE_POSITIVE_X
; face
<= D3DCUBEMAP_FACE_NEGATIVE_Z
; face
++)
711 size
= src_info
->Width
;
712 for (mip_level
= 0; mip_level
< src_info
->MipLevels
; mip_level
++)
714 hr
= calculate_dds_surface_size(src_info
->Format
, size
, size
, &src_pitch
, &mip_level_size
);
715 if (FAILED(hr
)) return hr
;
717 /* if texture has fewer mip levels than DDS file, skip excessive mip levels */
718 if (mip_level
< mip_levels
)
720 SetRect(&src_rect
, 0, 0, size
, size
);
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
;
729 pixels
+= mip_level_size
;
730 size
= max(1, size
/ 2);
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
)
743 UINT src_slice_pitch
;
746 UINT width
, height
, depth
;
747 IDirect3DVolume9
*volume
;
748 const struct dds_header
*header
= src_data
;
749 const BYTE
*pixels
= (BYTE
*)(header
+ 1);
751 if (src_info
->ResourceType
!= D3DRTYPE_VOLUMETEXTURE
)
752 return D3DXERR_INVALIDDATA
;
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
));
759 for (mip_level
= 0; mip_level
< mip_levels
; mip_level
++)
761 hr
= calculate_dds_surface_size(src_info
->Format
, width
, height
, &src_row_pitch
, &src_slice_pitch
);
762 if (FAILED(hr
)) return hr
;
764 hr
= IDirect3DVolumeTexture9_GetVolumeLevel(volume_texture
, mip_level
, &volume
);
765 if (FAILED(hr
)) return hr
;
769 src_box
.Right
= width
;
770 src_box
.Bottom
= height
;
772 src_box
.Back
= depth
;
774 hr
= D3DXLoadVolumeFromMemory(volume
, palette
, NULL
, pixels
, src_info
->Format
,
775 src_row_pitch
, src_slice_pitch
, NULL
, &src_box
, filter
, color_key
);
777 IDirect3DVolume9_Release(volume
);
778 if (FAILED(hr
)) return hr
;
780 pixels
+= depth
* src_slice_pitch
;
781 width
= max(1, width
/ 2);
782 height
= max(1, height
/ 2);
783 depth
= max(1, depth
/ 2);
789 static BOOL
convert_dib_to_bmp(void **data
, UINT
*size
)
794 BITMAPFILEHEADER
*header
;
798 if ((*size
< 4) || (*size
< (header_size
= *(ULONG
*)*data
)))
801 if ((header_size
== sizeof(BITMAPINFOHEADER
)) ||
802 (header_size
== sizeof(BITMAPV4HEADER
)) ||
803 (header_size
== sizeof(BITMAPV5HEADER
)) ||
804 (header_size
== 64 /* sizeof(BITMAPCOREHEADER2) */))
806 /* All structures begin with the same memory layout as BITMAPINFOHEADER */
807 BITMAPINFOHEADER
*info_header
= (BITMAPINFOHEADER
*)*data
;
808 count
= info_header
->biClrUsed
;
810 if (!count
&& info_header
->biBitCount
<= 8)
811 count
= 1 << info_header
->biBitCount
;
813 offset
= sizeof(BITMAPFILEHEADER
) + header_size
+ sizeof(RGBQUAD
) * count
;
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
);
819 else if (header_size
== sizeof(BITMAPCOREHEADER
))
821 BITMAPCOREHEADER
*core_header
= (BITMAPCOREHEADER
*)*data
;
823 if (core_header
->bcBitCount
<= 8)
824 count
= 1 << core_header
->bcBitCount
;
826 offset
= sizeof(BITMAPFILEHEADER
) + header_size
+ sizeof(RGBTRIPLE
) * count
;
833 TRACE("Converting DIB file to BMP\n");
835 new_size
= *size
+ sizeof(BITMAPFILEHEADER
);
836 new_data
= HeapAlloc(GetProcessHeap(), 0, new_size
);
837 CopyMemory(new_data
+ sizeof(BITMAPFILEHEADER
), *data
, *size
);
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
;
847 /* Update input data */
854 /************************************************************
855 * D3DXGetImageInfoFromFileInMemory
857 * Fills a D3DXIMAGE_INFO structure with info about an image
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
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
872 * datasize may be bigger than the actual file size
875 HRESULT WINAPI
D3DXGetImageInfoFromFileInMemory(const void *data
, UINT datasize
, D3DXIMAGE_INFO
*info
)
877 IWICImagingFactory
*factory
;
878 IWICBitmapDecoder
*decoder
= NULL
;
884 TRACE("(%p, %d, %p)\n", data
, datasize
, info
);
886 if (!data
|| !datasize
)
887 return D3DERR_INVALIDCALL
;
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
);
897 /* In case of DIB file, convert it to BMP */
898 dib
= convert_dib_to_bmp((void**)&data
, &datasize
);
900 initresult
= CoInitializeEx(NULL
, COINIT_APARTMENTTHREADED
);
902 hr
= CoCreateInstance(&CLSID_WICImagingFactory
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IWICImagingFactory
, (void**)&factory
);
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
);
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");
922 GUID container_format
;
925 hr
= IWICBitmapDecoder_GetContainerFormat(decoder
, &container_format
);
927 if (IsEqualGUID(&container_format
, &GUID_ContainerFormatBmp
)) {
929 TRACE("File type is DIB\n");
930 info
->ImageFileFormat
= D3DXIFF_DIB
;
932 TRACE("File type is BMP\n");
933 info
->ImageFileFormat
= D3DXIFF_BMP
;
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
;
945 WARN("Unsupported image file format %s\n", debugstr_guid(&container_format
));
946 hr
= D3DXERR_INVALIDDATA
;
951 hr
= IWICBitmapDecoder_GetFrameCount(decoder
, &frame_count
);
952 if (SUCCEEDED(hr
) && !frame_count
)
953 hr
= D3DXERR_INVALIDDATA
;
956 IWICBitmapFrameDecode
*frame
= NULL
;
958 hr
= IWICBitmapDecoder_GetFrame(decoder
, 0, &frame
);
961 hr
= IWICBitmapFrameDecode_GetSize(frame
, &info
->Width
, &info
->Height
);
964 WICPixelFormatGUID pixel_format
;
966 hr
= IWICBitmapFrameDecode_GetPixelFormat(frame
, &pixel_format
);
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
;
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
);
984 for (i
= 0; i
< info
->Width
* info
->Height
; i
++) {
986 info
->Format
= D3DFMT_A8R8G8B8
;
991 HeapFree(GetProcessHeap(), 0, buffer
);
995 IWICBitmapFrameDecode_Release(frame
);
999 info
->ResourceType
= D3DRTYPE_TEXTURE
;
1004 IWICBitmapDecoder_Release(decoder
);
1006 if (SUCCEEDED(initresult
))
1010 HeapFree(GetProcessHeap(), 0, (void*)data
);
1013 TRACE("Invalid or unsupported image file\n");
1014 return D3DXERR_INVALIDDATA
;
1020 /************************************************************
1021 * D3DXGetImageInfoFromFile
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
1031 HRESULT WINAPI
D3DXGetImageInfoFromFileA(const char *file
, D3DXIMAGE_INFO
*info
)
1037 TRACE("file %s, info %p.\n", debugstr_a(file
), info
);
1039 if( !file
) return D3DERR_INVALIDCALL
;
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
);
1045 hr
= D3DXGetImageInfoFromFileW(widename
, info
);
1046 HeapFree(GetProcessHeap(), 0, widename
);
1051 HRESULT WINAPI
D3DXGetImageInfoFromFileW(const WCHAR
*file
, D3DXIMAGE_INFO
*info
)
1057 TRACE("file %s, info %p.\n", debugstr_w(file
), info
);
1060 return D3DERR_INVALIDCALL
;
1062 if (FAILED(map_view_of_file(file
, &buffer
, &size
)))
1063 return D3DXERR_INVALIDDATA
;
1065 hr
= D3DXGetImageInfoFromFileInMemory(buffer
, size
, info
);
1066 UnmapViewOfFile(buffer
);
1071 /************************************************************
1072 * D3DXGetImageInfoFromResource
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
1080 HRESULT WINAPI
D3DXGetImageInfoFromResourceA(HMODULE module
, const char *resource
, D3DXIMAGE_INFO
*info
)
1086 TRACE("module %p, resource %s, info %p.\n", module
, debugstr_a(resource
), info
);
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
;
1093 if (FAILED(load_resource_into_memory(module
, resinfo
, &buffer
, &size
)))
1094 return D3DXERR_INVALIDDATA
;
1096 return D3DXGetImageInfoFromFileInMemory(buffer
, size
, info
);
1099 HRESULT WINAPI
D3DXGetImageInfoFromResourceW(HMODULE module
, const WCHAR
*resource
, D3DXIMAGE_INFO
*info
)
1105 TRACE("module %p, resource %s, info %p.\n", module
, debugstr_w(resource
), info
);
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
;
1112 if (FAILED(load_resource_into_memory(module
, resinfo
, &buffer
, &size
)))
1113 return D3DXERR_INVALIDDATA
;
1115 return D3DXGetImageInfoFromFileInMemory(buffer
, size
, info
);
1118 /************************************************************
1119 * D3DXLoadSurfaceFromFileInMemory
1121 * Loads data from a given buffer into a surface and fills a given
1122 * D3DXIMAGE_INFO structure with info about the source data.
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
1137 * Failure: D3DERR_INVALIDCALL, if pDestSurface, pSrcData or SrcDataSize is NULL
1138 * D3DXERR_INVALIDDATA, if pSrcData is no valid image file
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
)
1145 D3DXIMAGE_INFO imginfo
;
1146 HRESULT hr
, com_init
;
1148 IWICImagingFactory
*factory
= NULL
;
1149 IWICBitmapDecoder
*decoder
;
1150 IWICBitmapFrameDecode
*bitmapframe
;
1153 const struct pixel_format_desc
*formatdesc
;
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
);
1162 if (!pDestSurface
|| !pSrcData
|| !SrcDataSize
)
1163 return D3DERR_INVALIDCALL
;
1165 hr
= D3DXGetImageInfoFromFileInMemory(pSrcData
, SrcDataSize
, &imginfo
);
1172 wicrect
.X
= pSrcRect
->left
;
1173 wicrect
.Y
= pSrcRect
->top
;
1174 wicrect
.Width
= pSrcRect
->right
- pSrcRect
->left
;
1175 wicrect
.Height
= pSrcRect
->bottom
- pSrcRect
->top
;
1181 wicrect
.Width
= imginfo
.Width
;
1182 wicrect
.Height
= imginfo
.Height
;
1185 SetRect(&rect
, 0, 0, wicrect
.Width
, wicrect
.Height
);
1187 if (imginfo
.ImageFileFormat
== D3DXIFF_DDS
)
1189 hr
= load_surface_from_dds(pDestSurface
, pDestPalette
, pDestRect
, pSrcData
, &rect
,
1190 dwFilter
, Colorkey
, &imginfo
);
1191 if (SUCCEEDED(hr
) && pSrcInfo
)
1192 *pSrcInfo
= imginfo
;
1196 if (imginfo
.ImageFileFormat
== D3DXIFF_DIB
)
1197 convert_dib_to_bmp((void**)&pSrcData
, &SrcDataSize
);
1199 com_init
= CoInitializeEx(NULL
, COINIT_APARTMENTTHREADED
);
1201 if (FAILED(CoCreateInstance(&CLSID_WICImagingFactory
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IWICImagingFactory
, (void**)&factory
)))
1204 if (FAILED(IWICImagingFactory_CreateStream(factory
, &stream
)))
1206 IWICImagingFactory_Release(factory
);
1211 IWICStream_InitializeFromMemory(stream
, (BYTE
*)pSrcData
, SrcDataSize
);
1213 hr
= IWICImagingFactory_CreateDecoderFromStream(factory
, (IStream
*)stream
, NULL
, 0, &decoder
);
1215 IWICStream_Release(stream
);
1220 hr
= IWICBitmapDecoder_GetFrame(decoder
, 0, &bitmapframe
);
1225 formatdesc
= get_format_info(imginfo
.Format
);
1227 if (formatdesc
->type
== FORMAT_UNKNOWN
)
1229 FIXME("Unsupported pixel format\n");
1230 hr
= D3DXERR_INVALIDDATA
;
1236 PALETTEENTRY
*palette
= NULL
;
1237 WICColor
*colors
= NULL
;
1239 pitch
= formatdesc
->bytes_per_pixel
* wicrect
.Width
;
1240 buffer
= HeapAlloc(GetProcessHeap(), 0, pitch
* wicrect
.Height
);
1242 hr
= IWICBitmapFrameDecode_CopyPixels(bitmapframe
, &wicrect
, pitch
,
1243 pitch
* wicrect
.Height
, buffer
);
1245 if (SUCCEEDED(hr
) && (formatdesc
->type
== FORMAT_INDEX
))
1247 IWICPalette
*wic_palette
= NULL
;
1250 hr
= IWICImagingFactory_CreatePalette(factory
, &wic_palette
);
1252 hr
= IWICBitmapFrameDecode_CopyPalette(bitmapframe
, wic_palette
);
1254 hr
= IWICPalette_GetColorCount(wic_palette
, &nb_colors
);
1257 colors
= HeapAlloc(GetProcessHeap(), 0, nb_colors
* sizeof(colors
[0]));
1258 palette
= HeapAlloc(GetProcessHeap(), 0, nb_colors
* sizeof(palette
[0]));
1259 if (!colors
|| !palette
)
1263 hr
= IWICPalette_GetColors(wic_palette
, nb_colors
, colors
, &nb_colors
);
1268 /* Convert colors from WICColor (ARGB) to PALETTEENTRY (ABGR) */
1269 for (i
= 0; i
< nb_colors
; i
++)
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 */
1278 IWICPalette_Release(wic_palette
);
1283 hr
= D3DXLoadSurfaceFromMemory(pDestSurface
, pDestPalette
, pDestRect
,
1284 buffer
, imginfo
.Format
, pitch
,
1285 palette
, &rect
, dwFilter
, Colorkey
);
1288 HeapFree(GetProcessHeap(), 0, colors
);
1289 HeapFree(GetProcessHeap(), 0, palette
);
1290 HeapFree(GetProcessHeap(), 0, buffer
);
1293 IWICBitmapFrameDecode_Release(bitmapframe
);
1296 IWICBitmapDecoder_Release(decoder
);
1300 IWICImagingFactory_Release(factory
);
1302 if (SUCCEEDED(com_init
))
1305 if (imginfo
.ImageFileFormat
== D3DXIFF_DIB
)
1306 HeapFree(GetProcessHeap(), 0, (void*)pSrcData
);
1309 return D3DXERR_INVALIDDATA
;
1312 *pSrcInfo
= imginfo
;
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
)
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
);
1330 if (!src_file
|| !dst_surface
)
1331 return D3DERR_INVALIDCALL
;
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
);
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
);
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
)
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
);
1357 if (!src_file
|| !dst_surface
)
1358 return D3DERR_INVALIDCALL
;
1360 if (FAILED(map_view_of_file(src_file
, &data
, &data_size
)))
1361 return D3DXERR_INVALIDDATA
;
1363 hr
= D3DXLoadSurfaceFromFileInMemory(dst_surface
, dst_palette
, dst_rect
,
1364 data
, data_size
, src_rect
, filter
, color_key
, src_info
);
1365 UnmapViewOfFile(data
);
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
)
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
);
1384 return D3DERR_INVALIDCALL
;
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
;
1391 if (FAILED(load_resource_into_memory(src_module
, resinfo
, &data
, &data_size
)))
1392 return D3DXERR_INVALIDDATA
;
1394 return D3DXLoadSurfaceFromFileInMemory(dst_surface
, dst_palette
, dst_rect
,
1395 data
, data_size
, src_rect
, filter
, color_key
, src_info
);
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
)
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
);
1412 return D3DERR_INVALIDCALL
;
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
;
1419 if (FAILED(load_resource_into_memory(src_module
, resinfo
, &data
, &data_size
)))
1420 return D3DXERR_INVALIDDATA
;
1422 return D3DXLoadSurfaceFromFileInMemory(dst_surface
, dst_palette
, dst_rect
,
1423 data
, data_size
, src_rect
, filter
, color_key
, src_info
);
1427 /************************************************************
1428 * helper functions for D3DXLoadSurfaceFromMemory
1430 struct argb_conversion_info
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];
1440 static void init_argb_conversion_info(const struct pixel_format_desc
*srcformat
, const struct pixel_format_desc
*destformat
, struct argb_conversion_info
*info
)
1443 ZeroMemory(info
->process_channel
, 4 * sizeof(BOOL
));
1444 info
->channelmask
= 0;
1446 info
->srcformat
= srcformat
;
1447 info
->destformat
= destformat
;
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);
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);
1456 info
->srcmask
[i
] = ((1 << srcformat
->bits
[i
]) - 1) << srcformat
->shift
[i
];
1457 info
->destmask
[i
] = ((1 << destformat
->bits
[i
]) - 1) << destformat
->shift
[i
];
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
];
1467 /************************************************************
1468 * get_relevant_argb_components
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.
1473 static void get_relevant_argb_components(const struct argb_conversion_info
*info
, const BYTE
*col
, DWORD
*out
)
1476 unsigned int component
, mask
;
1478 for (i
= 0; i
< 4; ++i
)
1480 if (!info
->process_channel
[i
])
1484 mask
= info
->srcmask
[i
];
1485 for (j
= 0; j
< 4 && mask
; ++j
)
1487 if (info
->srcshift
[i
] < j
* 8)
1488 component
|= (col
[j
] & mask
) << (j
* 8 - info
->srcshift
[i
]);
1490 component
|= (col
[j
] & mask
) >> (info
->srcshift
[i
] - j
* 8);
1497 /************************************************************
1500 * Recombines the output of get_relevant_argb_components and converts
1501 * it to the destination format.
1503 static DWORD
make_argb_color(const struct argb_conversion_info
*info
, const DWORD
*in
)
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 */
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
];
1516 val
|= info
->channelmask
; /* new channels are set to their maximal value */
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
)
1526 for (c
= 0; c
< 4; ++c
)
1528 static const unsigned int component_offsets
[4] = {3, 0, 1, 2};
1529 float *dst_component
= (float *)dst
+ component_offsets
[c
];
1531 if (format
->bits
[c
])
1533 mask
= ~0u >> (32 - format
->bits
[c
]);
1535 memcpy(&tmp
, src
+ format
->shift
[c
] / 8,
1536 min(sizeof(DWORD
), (format
->shift
[c
] % 8 + format
->bits
[c
] + 7) / 8));
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
;
1543 *dst_component
= (float)((tmp
>> format
->shift
[c
] % 8) & mask
) / mask
;
1546 *dst_component
= 1.0f
;
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
)
1556 memset(dst
, 0, format
->bytes_per_pixel
);
1558 for (c
= 0; c
< 4; ++c
)
1560 static const unsigned int component_offsets
[4] = {3, 0, 1, 2};
1561 const float src_component
= *((const float *)src
+ component_offsets
[c
]);
1563 if (!format
->bits
[c
])
1566 mask32
= ~0u >> (32 - format
->bits
[c
]);
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
;
1573 v
= (DWORD
)(src_component
* ((1 << format
->bits
[c
]) - 1) + 0.5f
);
1575 for (i
= format
->shift
[c
] / 8 * 8; i
< format
->shift
[c
] + format
->bits
[c
]; i
+= 8)
1579 if (format
->shift
[c
] > i
)
1581 mask
= mask32
<< (format
->shift
[c
] - i
);
1582 byte
= (v
<< (format
->shift
[c
] - i
)) & mask
;
1586 mask
= mask32
>> (i
- format
->shift
[c
]);
1587 byte
= (v
>> (i
- format
->shift
[c
])) & mask
;
1594 /************************************************************
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.
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
)
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
;
1611 for (slice
= 0; slice
< size
->depth
; slice
++)
1613 src_addr
= src
+ slice
* src_slice_pitch
;
1614 dst_addr
= dst
+ slice
* dst_slice_pitch
;
1616 for (row
= 0; row
< row_count
; row
++)
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
;
1625 /************************************************************
1626 * convert_argb_pixels
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.
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
)
1637 struct argb_conversion_info conv_info
, ck_conv_info
;
1638 const struct pixel_format_desc
*ck_format
= NULL
;
1640 UINT min_width
, min_height
, min_depth
;
1643 ZeroMemory(channels
, sizeof(channels
));
1644 init_argb_conversion_info(src_format
, dst_format
, &conv_info
);
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
);
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
);
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
;
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
;
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)
1672 get_relevant_argb_components(&conv_info
, src_ptr
, channels
);
1673 val
= make_argb_color(&conv_info
, channels
);
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];
1684 memcpy(dst_ptr
, &val
, dst_format
->bytes_per_pixel
);
1688 struct vec4 color
, tmp
;
1690 format_to_vec4(src_format
, src_ptr
, &color
);
1691 if (src_format
->to_rgba
)
1692 src_format
->to_rgba(&color
, &tmp
, palette
);
1700 format_from_vec4(ck_format
, &tmp
, (BYTE
*)&ck_pixel
);
1701 if (ck_pixel
== color_key
)
1705 if (dst_format
->from_rgba
)
1706 dst_format
->from_rgba(&tmp
, &color
);
1710 format_from_vec4(dst_format
, &color
, dst_ptr
);
1713 src_ptr
+= src_format
->bytes_per_pixel
;
1714 dst_ptr
+= dst_format
->bytes_per_pixel
;
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
));
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
));
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
));
1728 /************************************************************
1729 * point_filter_argb_pixels
1731 * Copies the source buffer to the destination buffer, performing
1732 * any necessary format conversion, color keying and stretching
1733 * using a point filter.
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
)
1740 struct argb_conversion_info conv_info
, ck_conv_info
;
1741 const struct pixel_format_desc
*ck_format
= NULL
;
1745 ZeroMemory(channels
, sizeof(channels
));
1746 init_argb_conversion_info(src_format
, dst_format
, &conv_info
);
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
);
1755 for (z
= 0; z
< dst_size
->depth
; z
++)
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
);
1760 for (y
= 0; y
< dst_size
->height
; y
++)
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
);
1765 for (x
= 0; x
< dst_size
->width
; x
++)
1767 const BYTE
*src_ptr
= src_row_ptr
+ (x
* src_size
->width
/ dst_size
->width
) * src_format
->bytes_per_pixel
;
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)
1775 get_relevant_argb_components(&conv_info
, src_ptr
, channels
);
1776 val
= make_argb_color(&conv_info
, channels
);
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];
1787 memcpy(dst_ptr
, &val
, dst_format
->bytes_per_pixel
);
1791 struct vec4 color
, tmp
;
1793 format_to_vec4(src_format
, src_ptr
, &color
);
1794 if (src_format
->to_rgba
)
1795 src_format
->to_rgba(&color
, &tmp
, palette
);
1803 format_from_vec4(ck_format
, &tmp
, (BYTE
*)&ck_pixel
);
1804 if (ck_pixel
== color_key
)
1808 if (dst_format
->from_rgba
)
1809 dst_format
->from_rgba(&tmp
, &color
);
1813 format_from_vec4(dst_format
, &color
, dst_ptr
);
1816 dst_ptr
+= dst_format
->bytes_per_pixel
;
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
);
1825 static dxtn_conversion_func
get_dxtn_conversion_func(D3DFORMAT format
, BOOL encode
)
1830 return encode
? wined3d_dxt1_encode
: wined3d_dxt1_decode
;
1832 return encode
? wined3d_dxt3_encode
: wined3d_dxt3_decode
;
1834 return encode
? wined3d_dxt5_encode
: wined3d_dxt5_decode
;
1840 /************************************************************
1841 * D3DXLoadSurfaceFromMemory
1843 * Loads data from a given memory chunk into a surface,
1844 * applying any of the specified filters.
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
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
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.
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
)
1877 const struct pixel_format_desc
*srcformatdesc
, *destformatdesc
;
1878 D3DSURFACE_DESC surfdesc
;
1879 D3DLOCKED_RECT lockrect
;
1880 struct volume src_size
, dst_size
;
1881 HRESULT ret
= D3D_OK
;
1883 TRACE("(%p, %p, %s, %p, %#x, %u, %p, %s, %#x, 0x%08x)\n",
1884 dst_surface
, dst_palette
, wine_dbgstr_rect(dst_rect
), src_memory
, src_format
,
1885 src_pitch
, src_palette
, wine_dbgstr_rect(src_rect
), filter
, color_key
);
1887 if (!dst_surface
|| !src_memory
|| !src_rect
)
1889 WARN("Invalid argument specified.\n");
1890 return D3DERR_INVALIDCALL
;
1892 if (src_format
== D3DFMT_UNKNOWN
1893 || src_rect
->left
>= src_rect
->right
1894 || src_rect
->top
>= src_rect
->bottom
)
1896 WARN("Invalid src_format or src_rect.\n");
1900 if (filter
== D3DX_DEFAULT
)
1901 filter
= D3DX_FILTER_TRIANGLE
| D3DX_FILTER_DITHER
;
1903 IDirect3DSurface9_GetDesc(dst_surface
, &surfdesc
);
1905 src_size
.width
= src_rect
->right
- src_rect
->left
;
1906 src_size
.height
= src_rect
->bottom
- src_rect
->top
;
1910 dst_size
.width
= surfdesc
.Width
;
1911 dst_size
.height
= surfdesc
.Height
;
1915 if (dst_rect
->left
> dst_rect
->right
|| dst_rect
->right
> surfdesc
.Width
1916 || dst_rect
->top
> dst_rect
->bottom
|| dst_rect
->bottom
> surfdesc
.Height
1917 || dst_rect
->left
< 0 || dst_rect
->top
< 0)
1919 WARN("Invalid dst_rect specified.\n");
1920 return D3DERR_INVALIDCALL
;
1922 dst_size
.width
= dst_rect
->right
- dst_rect
->left
;
1923 dst_size
.height
= dst_rect
->bottom
- dst_rect
->top
;
1924 if (!dst_size
.width
|| !dst_size
.height
)
1929 srcformatdesc
= get_format_info(src_format
);
1930 destformatdesc
= get_format_info(surfdesc
.Format
);
1931 if (srcformatdesc
->type
== FORMAT_UNKNOWN
|| destformatdesc
->type
== FORMAT_UNKNOWN
)
1933 FIXME("Unsupported pixel format conversion %#x -> %#x\n", src_format
, surfdesc
.Format
);
1937 if (src_format
== surfdesc
.Format
1938 && dst_size
.width
== src_size
.width
1939 && dst_size
.height
== src_size
.height
1940 && color_key
== 0) /* Simple copy. */
1942 if (src_rect
->left
& (srcformatdesc
->block_width
- 1)
1943 || src_rect
->top
& (srcformatdesc
->block_height
- 1)
1944 || (src_rect
->right
& (srcformatdesc
->block_width
- 1)
1945 && src_size
.width
!= surfdesc
.Width
)
1946 || (src_rect
->bottom
& (srcformatdesc
->block_height
- 1)
1947 && src_size
.height
!= surfdesc
.Height
))
1949 WARN("Source rect %s is misaligned.\n", wine_dbgstr_rect(src_rect
));
1950 return D3DXERR_INVALIDDATA
;
1953 if (FAILED(IDirect3DSurface9_LockRect(dst_surface
, &lockrect
, dst_rect
, 0)))
1954 return D3DXERR_INVALIDDATA
;
1956 copy_pixels(src_memory
, src_pitch
, 0, lockrect
.pBits
, lockrect
.Pitch
, 0,
1957 &src_size
, srcformatdesc
);
1959 IDirect3DSurface9_UnlockRect(dst_surface
);
1961 else /* Stretching or format conversion. */
1963 dxtn_conversion_func pre_convert
, post_convert
;
1964 void *tmp_src_memory
= NULL
, *tmp_dst_memory
= NULL
;
1965 UINT tmp_src_pitch
, tmp_dst_pitch
;
1967 pre_convert
= get_dxtn_conversion_func(srcformatdesc
->format
, FALSE
);
1968 post_convert
= get_dxtn_conversion_func(destformatdesc
->format
, TRUE
);
1970 if ((!pre_convert
&& !is_conversion_from_supported(srcformatdesc
)) ||
1971 (!post_convert
&& !is_conversion_to_supported(destformatdesc
)))
1973 FIXME("Unsupported format conversion %#x -> %#x.\n", src_format
, surfdesc
.Format
);
1977 if (FAILED(IDirect3DSurface9_LockRect(dst_surface
, &lockrect
, dst_rect
, 0)))
1978 return D3DXERR_INVALIDDATA
;
1980 /* handle pre-conversion */
1983 tmp_src_memory
= HeapAlloc(GetProcessHeap(), 0, src_size
.width
* src_size
.height
* sizeof(DWORD
));
1984 if (!tmp_src_memory
)
1986 ret
= E_OUTOFMEMORY
;
1989 tmp_src_pitch
= src_size
.width
* sizeof(DWORD
);
1990 if (!pre_convert(src_memory
, tmp_src_memory
, src_pitch
, tmp_src_pitch
,
1991 WINED3DFMT_B8G8R8A8_UNORM
, src_size
.width
, src_size
.height
))
1996 srcformatdesc
= get_format_info(D3DFMT_A8R8G8B8
);
2000 tmp_src_memory
= (void *)src_memory
;
2001 tmp_src_pitch
= src_pitch
;
2004 /* handle post-conversion */
2007 tmp_dst_memory
= HeapAlloc(GetProcessHeap(), 0, dst_size
.width
* dst_size
.height
* sizeof(DWORD
));
2008 if (!tmp_dst_memory
)
2010 ret
= E_OUTOFMEMORY
;
2013 tmp_dst_pitch
= dst_size
.width
* sizeof(DWORD
);
2014 destformatdesc
= get_format_info(D3DFMT_A8R8G8B8
);
2018 tmp_dst_memory
= lockrect
.pBits
;
2019 tmp_dst_pitch
= lockrect
.Pitch
;
2022 if ((filter
& 0xf) == D3DX_FILTER_NONE
)
2024 convert_argb_pixels(tmp_src_memory
, tmp_src_pitch
, 0, &src_size
, srcformatdesc
,
2025 tmp_dst_memory
, tmp_dst_pitch
, 0, &dst_size
, destformatdesc
, color_key
, src_palette
);
2027 else /* if ((filter & 0xf) == D3DX_FILTER_POINT) */
2029 if ((filter
& 0xf) != D3DX_FILTER_POINT
)
2030 FIXME("Unhandled filter %#x.\n", filter
);
2032 /* Always apply a point filter until D3DX_FILTER_LINEAR,
2033 * D3DX_FILTER_TRIANGLE and D3DX_FILTER_BOX are implemented. */
2034 point_filter_argb_pixels(tmp_src_memory
, tmp_src_pitch
, 0, &src_size
, srcformatdesc
,
2035 tmp_dst_memory
, tmp_dst_pitch
, 0, &dst_size
, destformatdesc
, color_key
, src_palette
);
2038 /* handle post-conversion */
2041 if (!post_convert(tmp_dst_memory
, lockrect
.pBits
, tmp_dst_pitch
, lockrect
.Pitch
,
2042 WINED3DFMT_B8G8R8A8_UNORM
, dst_size
.width
, dst_size
.height
))
2051 HeapFree(GetProcessHeap(), 0, tmp_src_memory
);
2053 HeapFree(GetProcessHeap(), 0, tmp_dst_memory
);
2054 IDirect3DSurface9_UnlockRect(dst_surface
);
2060 /************************************************************
2061 * D3DXLoadSurfaceFromSurface
2063 * Copies the contents from one surface to another, performing any required
2064 * format conversion, resizing or filtering.
2067 * pDestSurface [I] pointer to the destination surface
2068 * pDestPalette [I] palette to use
2069 * pDestRect [I] to be filled area of the surface
2070 * pSrcSurface [I] pointer to the source surface
2071 * pSrcPalette [I] palette used for the source surface
2072 * pSrcRect [I] area of the source data to load
2073 * dwFilter [I] filter to apply on resizing
2074 * Colorkey [I] any ARGB value or 0 to disable color-keying
2078 * Failure: D3DERR_INVALIDCALL, if pDestSurface or pSrcSurface is NULL
2079 * D3DXERR_INVALIDDATA, if one of the surfaces is not lockable
2082 HRESULT WINAPI
D3DXLoadSurfaceFromSurface(IDirect3DSurface9
*dst_surface
,
2083 const PALETTEENTRY
*dst_palette
, const RECT
*dst_rect
, IDirect3DSurface9
*src_surface
,
2084 const PALETTEENTRY
*src_palette
, const RECT
*src_rect
, DWORD filter
, D3DCOLOR color_key
)
2087 D3DLOCKED_RECT lock
;
2088 D3DSURFACE_DESC SrcDesc
;
2091 TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_surface %p, "
2092 "src_palette %p, src_rect %s, filter %#x, color_key 0x%08x.\n",
2093 dst_surface
, dst_palette
, wine_dbgstr_rect(dst_rect
), src_surface
,
2094 src_palette
, wine_dbgstr_rect(src_rect
), filter
, color_key
);
2096 if (!dst_surface
|| !src_surface
)
2097 return D3DERR_INVALIDCALL
;
2099 IDirect3DSurface9_GetDesc(src_surface
, &SrcDesc
);
2102 SetRect(&rect
, 0, 0, SrcDesc
.Width
, SrcDesc
.Height
);
2106 if (FAILED(IDirect3DSurface9_LockRect(src_surface
, &lock
, NULL
, D3DLOCK_READONLY
)))
2107 return D3DXERR_INVALIDDATA
;
2109 hr
= D3DXLoadSurfaceFromMemory(dst_surface
, dst_palette
, dst_rect
,
2110 lock
.pBits
, SrcDesc
.Format
, lock
.Pitch
, src_palette
, &rect
, filter
, color_key
);
2112 IDirect3DSurface9_UnlockRect(src_surface
);
2118 HRESULT WINAPI
D3DXSaveSurfaceToFileA(const char *dst_filename
, D3DXIMAGE_FILEFORMAT file_format
,
2119 IDirect3DSurface9
*src_surface
, const PALETTEENTRY
*src_palette
, const RECT
*src_rect
)
2124 ID3DXBuffer
*buffer
;
2126 TRACE("(%s, %#x, %p, %p, %s): relay\n",
2127 wine_dbgstr_a(dst_filename
), file_format
, src_surface
, src_palette
, wine_dbgstr_rect(src_rect
));
2129 if (!dst_filename
) return D3DERR_INVALIDCALL
;
2131 len
= MultiByteToWideChar(CP_ACP
, 0, dst_filename
, -1, NULL
, 0);
2132 filename
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2133 if (!filename
) return E_OUTOFMEMORY
;
2134 MultiByteToWideChar(CP_ACP
, 0, dst_filename
, -1, filename
, len
);
2136 hr
= D3DXSaveSurfaceToFileInMemory(&buffer
, file_format
, src_surface
, src_palette
, src_rect
);
2139 hr
= write_buffer_to_file(filename
, buffer
);
2140 ID3DXBuffer_Release(buffer
);
2143 HeapFree(GetProcessHeap(), 0, filename
);
2147 HRESULT WINAPI
D3DXSaveSurfaceToFileW(const WCHAR
*dst_filename
, D3DXIMAGE_FILEFORMAT file_format
,
2148 IDirect3DSurface9
*src_surface
, const PALETTEENTRY
*src_palette
, const RECT
*src_rect
)
2151 ID3DXBuffer
*buffer
;
2153 TRACE("(%s, %#x, %p, %p, %s): relay\n",
2154 wine_dbgstr_w(dst_filename
), file_format
, src_surface
, src_palette
, wine_dbgstr_rect(src_rect
));
2156 if (!dst_filename
) return D3DERR_INVALIDCALL
;
2158 hr
= D3DXSaveSurfaceToFileInMemory(&buffer
, file_format
, src_surface
, src_palette
, src_rect
);
2161 hr
= write_buffer_to_file(dst_filename
, buffer
);
2162 ID3DXBuffer_Release(buffer
);
2168 HRESULT WINAPI
D3DXSaveSurfaceToFileInMemory(ID3DXBuffer
**dst_buffer
, D3DXIMAGE_FILEFORMAT file_format
,
2169 IDirect3DSurface9
*src_surface
, const PALETTEENTRY
*src_palette
, const RECT
*src_rect
)
2171 IWICBitmapEncoder
*encoder
= NULL
;
2172 IWICBitmapFrameEncode
*frame
= NULL
;
2173 IPropertyBag2
*encoder_options
= NULL
;
2174 IStream
*stream
= NULL
;
2177 const CLSID
*encoder_clsid
;
2178 const GUID
*pixel_format_guid
;
2179 WICPixelFormatGUID wic_pixel_format
;
2180 D3DFORMAT d3d_pixel_format
;
2181 D3DSURFACE_DESC src_surface_desc
;
2182 D3DLOCKED_RECT locked_rect
;
2184 STATSTG stream_stats
;
2185 HGLOBAL stream_hglobal
;
2186 ID3DXBuffer
*buffer
;
2189 TRACE("(%p, %#x, %p, %p, %s)\n",
2190 dst_buffer
, file_format
, src_surface
, src_palette
, wine_dbgstr_rect(src_rect
));
2192 if (!dst_buffer
|| !src_surface
) return D3DERR_INVALIDCALL
;
2196 FIXME("Saving surfaces with palettized pixel formats is not implemented yet\n");
2197 return D3DERR_INVALIDCALL
;
2200 switch (file_format
)
2204 encoder_clsid
= &CLSID_WICBmpEncoder
;
2207 encoder_clsid
= &CLSID_WICPngEncoder
;
2210 encoder_clsid
= &CLSID_WICJpegEncoder
;
2213 return save_dds_surface_to_memory(dst_buffer
, src_surface
, src_rect
);
2218 FIXME("File format %#x is not supported yet\n", file_format
);
2221 return D3DERR_INVALIDCALL
;
2224 IDirect3DSurface9_GetDesc(src_surface
, &src_surface_desc
);
2227 if (src_rect
->left
== src_rect
->right
|| src_rect
->top
== src_rect
->bottom
)
2229 WARN("Invalid rectangle with 0 area\n");
2230 return D3DXCreateBuffer(64, dst_buffer
);
2232 if (src_rect
->left
< 0 || src_rect
->top
< 0)
2233 return D3DERR_INVALIDCALL
;
2234 if (src_rect
->left
> src_rect
->right
|| src_rect
->top
> src_rect
->bottom
)
2235 return D3DERR_INVALIDCALL
;
2236 if (src_rect
->right
> src_surface_desc
.Width
|| src_rect
->bottom
> src_surface_desc
.Height
)
2237 return D3DERR_INVALIDCALL
;
2239 width
= src_rect
->right
- src_rect
->left
;
2240 height
= src_rect
->bottom
- src_rect
->top
;
2244 width
= src_surface_desc
.Width
;
2245 height
= src_surface_desc
.Height
;
2248 initresult
= CoInitializeEx(NULL
, COINIT_APARTMENTTHREADED
);
2250 hr
= CoCreateInstance(encoder_clsid
, NULL
, CLSCTX_INPROC_SERVER
,
2251 &IID_IWICBitmapEncoder
, (void **)&encoder
);
2252 if (FAILED(hr
)) goto cleanup_err
;
2254 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, &stream
);
2255 if (FAILED(hr
)) goto cleanup_err
;
2257 hr
= IWICBitmapEncoder_Initialize(encoder
, stream
, WICBitmapEncoderNoCache
);
2258 if (FAILED(hr
)) goto cleanup_err
;
2260 hr
= IWICBitmapEncoder_CreateNewFrame(encoder
, &frame
, &encoder_options
);
2261 if (FAILED(hr
)) goto cleanup_err
;
2263 hr
= IWICBitmapFrameEncode_Initialize(frame
, encoder_options
);
2264 if (FAILED(hr
)) goto cleanup_err
;
2266 hr
= IWICBitmapFrameEncode_SetSize(frame
, width
, height
);
2267 if (FAILED(hr
)) goto cleanup_err
;
2269 pixel_format_guid
= d3dformat_to_wic_guid(src_surface_desc
.Format
);
2270 if (!pixel_format_guid
)
2272 FIXME("Pixel format %#x is not supported yet\n", src_surface_desc
.Format
);
2277 memcpy(&wic_pixel_format
, pixel_format_guid
, sizeof(GUID
));
2278 hr
= IWICBitmapFrameEncode_SetPixelFormat(frame
, &wic_pixel_format
);
2279 d3d_pixel_format
= wic_guid_to_d3dformat(&wic_pixel_format
);
2280 if (SUCCEEDED(hr
) && d3d_pixel_format
!= D3DFMT_UNKNOWN
)
2282 TRACE("Using pixel format %s %#x\n", debugstr_guid(&wic_pixel_format
), d3d_pixel_format
);
2284 if (src_surface_desc
.Format
== d3d_pixel_format
) /* Simple copy */
2286 hr
= IDirect3DSurface9_LockRect(src_surface
, &locked_rect
, src_rect
, D3DLOCK_READONLY
);
2289 IWICBitmapFrameEncode_WritePixels(frame
, height
,
2290 locked_rect
.Pitch
, height
* locked_rect
.Pitch
, locked_rect
.pBits
);
2291 IDirect3DSurface9_UnlockRect(src_surface
);
2294 else /* Pixel format conversion */
2296 const struct pixel_format_desc
*src_format_desc
, *dst_format_desc
;
2301 src_format_desc
= get_format_info(src_surface_desc
.Format
);
2302 dst_format_desc
= get_format_info(d3d_pixel_format
);
2303 if (!is_conversion_from_supported(src_format_desc
)
2304 || !is_conversion_to_supported(dst_format_desc
))
2306 FIXME("Unsupported format conversion %#x -> %#x.\n",
2307 src_surface_desc
.Format
, d3d_pixel_format
);
2313 size
.height
= height
;
2315 dst_pitch
= width
* dst_format_desc
->bytes_per_pixel
;
2316 dst_data
= HeapAlloc(GetProcessHeap(), 0, dst_pitch
* height
);
2323 hr
= IDirect3DSurface9_LockRect(src_surface
, &locked_rect
, src_rect
, D3DLOCK_READONLY
);
2326 convert_argb_pixels(locked_rect
.pBits
, locked_rect
.Pitch
, 0, &size
, src_format_desc
,
2327 dst_data
, dst_pitch
, 0, &size
, dst_format_desc
, 0, NULL
);
2328 IDirect3DSurface9_UnlockRect(src_surface
);
2331 IWICBitmapFrameEncode_WritePixels(frame
, height
, dst_pitch
, dst_pitch
* height
, dst_data
);
2332 HeapFree(GetProcessHeap(), 0, dst_data
);
2335 hr
= IWICBitmapFrameEncode_Commit(frame
);
2336 if (SUCCEEDED(hr
)) hr
= IWICBitmapEncoder_Commit(encoder
);
2338 else WARN("Unsupported pixel format %#x\n", src_surface_desc
.Format
);
2340 /* copy data from stream to ID3DXBuffer */
2341 hr
= IStream_Stat(stream
, &stream_stats
, STATFLAG_NONAME
);
2342 if (FAILED(hr
)) goto cleanup_err
;
2344 if (stream_stats
.cbSize
.u
.HighPart
!= 0)
2346 hr
= D3DXERR_INVALIDDATA
;
2349 size
= stream_stats
.cbSize
.u
.LowPart
;
2351 /* Remove BMP header for DIB */
2352 if (file_format
== D3DXIFF_DIB
)
2353 size
-= sizeof(BITMAPFILEHEADER
);
2355 hr
= D3DXCreateBuffer(size
, &buffer
);
2356 if (FAILED(hr
)) goto cleanup
;
2358 hr
= GetHGlobalFromStream(stream
, &stream_hglobal
);
2361 void *buffer_pointer
= ID3DXBuffer_GetBufferPointer(buffer
);
2362 void *stream_data
= GlobalLock(stream_hglobal
);
2363 /* Remove BMP header for DIB */
2364 if (file_format
== D3DXIFF_DIB
)
2365 stream_data
= (void*)((BYTE
*)stream_data
+ sizeof(BITMAPFILEHEADER
));
2366 memcpy(buffer_pointer
, stream_data
, size
);
2367 GlobalUnlock(stream_hglobal
);
2368 *dst_buffer
= buffer
;
2370 else ID3DXBuffer_Release(buffer
);
2373 if (FAILED(hr
) && hr
!= E_OUTOFMEMORY
)
2374 hr
= D3DERR_INVALIDCALL
;
2377 if (stream
) IStream_Release(stream
);
2379 if (frame
) IWICBitmapFrameEncode_Release(frame
);
2380 if (encoder_options
) IPropertyBag2_Release(encoder_options
);
2382 if (encoder
) IWICBitmapEncoder_Release(encoder
);
2384 if (SUCCEEDED(initresult
)) CoUninitialize();