From: Aaryaman Vasishta Subject: [PATCH 2/4] d3drm: Partially implement IDirect3DRMTexture*::InitFromFile. (v7) Message-Id: <20181018225124.5250-2-jem456.vasishta@gmail.com> Date: Fri, 19 Oct 2018 07:51:22 +0900 In-Reply-To: <20181018225124.5250-1-jem456.vasishta@gmail.com> References: <20181018225124.5250-1-jem456.vasishta@gmail.com> v7: Split patch. v6: Rebased on top of master as of this patch date. v5: Redundant newline removed. --- dlls/d3drm/d3drm_private.h | 1 + dlls/d3drm/texture.c | 325 ++++++++++++++++++++++++++++++++++++- 2 files changed, 320 insertions(+), 6 deletions(-) diff --git a/dlls/d3drm/d3drm_private.h b/dlls/d3drm/d3drm_private.h index 858911f350..333b809896 100644 --- a/dlls/d3drm/d3drm_private.h +++ b/dlls/d3drm/d3drm_private.h @@ -26,6 +26,7 @@ #define COBJMACROS #include #include +#include #include "dxfile.h" #include "d3drmwin.h" #include "rmxfguid.h" diff --git a/dlls/d3drm/texture.c b/dlls/d3drm/texture.c index fd56e76ff9..4c81c788bf 100644 --- a/dlls/d3drm/texture.c +++ b/dlls/d3drm/texture.c @@ -2,6 +2,7 @@ * Implementation of IDirect3DRMTextureX interfaces * * Copyright 2012 Christian Costa + * Copyright 2016 Aaryaman Vasishta * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -67,6 +68,294 @@ static BOOL d3drm_validate_image(D3DRMIMAGE *image) return TRUE; } +static void CDECL destroy_image_callback(IDirect3DRMObject *obj, void *arg) +{ + D3DRMIMAGE *image = arg; + + TRACE("image %p texture object %p.\n", arg, obj); + + HeapFree(GetProcessHeap(), 0, image->buffer1); + HeapFree(GetProcessHeap(), 0, image); +} + +HRESULT d3drm_texture_load(struct d3drm_texture *texture, const char *path, BOOL load_upside_down, D3DRMIMAGE **image_out) +{ + BITMAPINFO *info; + BITMAPFILEHEADER *bmp_header; + unsigned char *buffer; + DWORD size; + HANDLE hfile, hmapping; + HRESULT hr = D3DRM_OK; + D3DRMPALETTEENTRY *colors = NULL; + D3DRMIMAGE *image = NULL; + BOOL black_used = FALSE, palette_used; + LONG w; + LONG h; + UINT i, j, k; + UINT idx, buffer1_idx; + unsigned char *buffer1; + UINT bpp; + UINT bpl; + UINT num_colors = 0; + struct colors_24bpp + { + BYTE red; + BYTE green; + BYTE blue; + } *color = NULL; + + /* Load the bitmap data */ + hfile = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); + if (hfile == INVALID_HANDLE_VALUE) + return D3DRMERR_BADOBJECT; + + size = GetFileSize(hfile, NULL); + if (size == INVALID_FILE_SIZE) + { + CloseHandle(hfile); + return D3DRMERR_BADVALUE; + } + if (!(hmapping = CreateFileMappingA(hfile, NULL, PAGE_READONLY, 0, 0, NULL))) + { + CloseHandle(hfile); + return D3DRMERR_BADVALUE; + } + if (!(buffer = MapViewOfFile(hmapping, FILE_MAP_READ, 0, 0, 0))) + { + CloseHandle(hmapping); + CloseHandle(hfile); + return D3DRMERR_BADVALUE; + } + + bmp_header = (BITMAPFILEHEADER *)buffer; + if (bmp_header->bfType != 0x4d42) /* BM */ + { + hr = D3DRMERR_BADFILE; + goto cleanup; + } + + info = (BITMAPINFO *)(bmp_header + 1); + /* Only allow version 1 DIB's (BITMAPINFOHEADER) to be loaded */ + if (info->bmiHeader.biSize != sizeof(info->bmiHeader)) + { + hr = D3DRMERR_BADFILE; + goto cleanup; + } + + bpp = info->bmiHeader.biBitCount == 24 ? 32 : info->bmiHeader.biBitCount; + w = info->bmiHeader.biWidth; + h = abs(info->bmiHeader.biHeight); + + if (bpp == 8) + { + buffer += sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER) + 256 * sizeof(RGBQUAD); + palette_used = TRUE; + } + else if (bpp == 32) + { + buffer += sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER); + palette_used = FALSE; + } + else + { + hr = D3DRMERR_BADFILE; + goto cleanup; + } + + /* Create and initialize the image struct. */ + color = (struct colors_24bpp *)buffer; + + if (palette_used) + bpl = w; + else if ((bpl = ((w + 3) & ~3)) > UINT_MAX / (bpp / 8)) + { + hr = D3DRMERR_BADALLOC; + goto cleanup; + } + + bpl = bpl * bpp / 8; + + if (bpl > UINT_MAX / h) + { + hr = D3DRMERR_BADALLOC; + goto cleanup; + } + + if (!(colors = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 256 * sizeof(*colors)))) + { + WARN("Not enough memory to allocate palette, returning NULL.\n"); + hr = D3DRMERR_BADALLOC; + goto cleanup; + } + + if (!(image = HeapAlloc(GetProcessHeap(), 0, sizeof(*image)))) + { + WARN("Not enough memory to allocate image struct, returning NULL.\n"); + hr = D3DRMERR_BADALLOC; + goto cleanup; + } + image->buffer1 = NULL; + + if (!(image->buffer1 = HeapAlloc(GetProcessHeap(), 0, bpl * h))) + { + WARN("Not enough memory to allocate image buffer, returning NULL.\n"); + hr = D3DRMERR_BADALLOC; + goto cleanup; + } + + buffer1 = image->buffer1; + memset(buffer1, 0xff, bpl * h); + if (!palette_used) + { + for (i = 0; i < h; i++) + { + for (j = 0; j < w; j++) + { + buffer1_idx = ((w + 3) & ~3) * i + j; + idx = load_upside_down ? (h - 1 - i) * w + j : i * w + j; + for (k = 0; k < 256; k++) + { + if (color[idx].blue == colors[k].blue && + color[idx].green == colors[k].green && + color[idx].red == colors[k].red) + { + if (color[idx].blue == 0 && + color[idx].green == 0 && + color[idx].red == 0 && + !black_used) + { + black_used = TRUE; + colors[num_colors++].flags = D3DRMPALETTE_READONLY; + } + buffer1[buffer1_idx] = k; + + break; + } + } + if (k == 256) + { + if (num_colors == 256) + { + num_colors++; + i = h; + break; + } + buffer1[buffer1_idx] = num_colors; + colors[num_colors].red = color[idx].red; + colors[num_colors].green = color[idx].green; + colors[num_colors].blue = color[idx].blue; + colors[num_colors++].flags = D3DRMPALETTE_READONLY; + } + } + } + + if (num_colors <= 256) + { + if (!(image->palette = HeapAlloc(GetProcessHeap(), 0, num_colors * sizeof(*image->palette)))) + { + WARN("Not enough memory to allocate image palette, returning NULL.\n"); + hr = D3DRMERR_BADALLOC; + goto cleanup; + } + image->red_mask = 0xff; + image->green_mask = 0xff; + image->blue_mask = 0xff; + image->rgb = 0; + bpl = bpl / (bpp / 8); + memcpy(image->palette, colors, num_colors * sizeof(D3DRMPALETTEENTRY)); + image->palette_size = num_colors; + palette_used = TRUE; + } + else + { + bpl = w * 4; + image->rgb = 1; + image->palette = NULL; + image->palette_size = 0; + for (i = 0; i < h; ++i) + { + for (j = 0; j < w; ++j) + { + unsigned char *ptr = &buffer1[i * bpl + j * 4]; + idx = load_upside_down ? (h - 1 - i) * w * 3 + j * 3 : i * w * 3 + j * 3; + ptr[0] = buffer[idx]; + ptr[1] = buffer[idx + 1]; + ptr[2] = buffer[idx + 2]; + ptr[3] = 0xff; + } + } + + image->red_mask = 0xff0000; + image->green_mask = 0x00ff00; + image->blue_mask = 0x0000ff; + } + } + else + { + if (!(image->palette = HeapAlloc(GetProcessHeap(), 0, 256 * sizeof(*image->palette)))) + { + WARN("Not enough memory to allocate image palette, returning NULL.\n"); + hr = D3DRMERR_BADALLOC; + goto cleanup; + } + + memcpy(image->palette, info->bmiColors, 256 * sizeof(D3DRMPALETTEENTRY)); + for (i = 0; i < 256; i++) + { + image->palette[i].flags = D3DRMPALETTE_READONLY; + } + if (load_upside_down) + { + for (i = 0; i < h; i++) + { + for (j = 0; j < w; j++) + { + idx = (h - 1 - i) * bpl + j; + buffer1[i * bpl + j] = buffer[idx]; + } + } + } + else + { + memcpy(buffer1, buffer, bpl * h); + } + image->palette_size = 256; + image->red_mask = 0xff; + image->green_mask = 0xff; + image->blue_mask = 0xff; + image->rgb = 0; + } + image->width = w; + image->height = h; + image->aspectx = 1; + image->aspecty = 1; + image->alpha_mask = 0; + image->depth = palette_used ? 8 : bpp; + image->bytes_per_line = bpl; + image->buffer2 = NULL; + + /* Use an internal destroy callback to destroy image struct */ + hr = IDirect3DRMObject_AddDestroyCallback(&texture->IDirect3DRMTexture3_iface, destroy_image_callback, image); + + *image_out = image; + +cleanup: + UnmapViewOfFile(buffer); + CloseHandle(hmapping); + CloseHandle(hfile); + + HeapFree(GetProcessHeap(), 0, colors); + + if (FAILED(hr)) + { + if (image) + HeapFree(GetProcessHeap(), 0, image->buffer1); + HeapFree(GetProcessHeap(), 0, image); + } + + return hr; +} + static HRESULT WINAPI d3drm_texture1_QueryInterface(IDirect3DRMTexture *iface, REFIID riid, void **out) { struct d3drm_texture *texture = impl_from_IDirect3DRMTexture(iface); @@ -171,9 +460,18 @@ static HRESULT WINAPI d3drm_texture1_GetClassName(IDirect3DRMTexture *iface, DWO static HRESULT WINAPI d3drm_texture1_InitFromFile(IDirect3DRMTexture *iface, const char *filename) { - FIXME("iface %p, filename %s stub!\n", iface, debugstr_a(filename)); + struct d3drm_texture *texture = impl_from_IDirect3DRMTexture(iface); + D3DRMIMAGE *image; + HRESULT hr; - return E_NOTIMPL; + TRACE("iface %p, filename %s.\n", iface, debugstr_a(filename)); + + if (FAILED(hr = d3drm_texture_load(texture, filename, FALSE, &image))) + return hr; + + hr = IDirect3DRMTexture3_InitFromImage(&texture->IDirect3DRMTexture3_iface, image); + + return hr; } static HRESULT WINAPI d3drm_texture1_InitFromSurface(IDirect3DRMTexture *iface, @@ -473,9 +771,15 @@ static HRESULT WINAPI d3drm_texture2_GetClassName(IDirect3DRMTexture2 *iface, DW static HRESULT WINAPI d3drm_texture2_InitFromFile(IDirect3DRMTexture2 *iface, const char *filename) { - FIXME("iface %p, filename %s stub!\n", iface, debugstr_a(filename)); + struct d3drm_texture *object = impl_from_IDirect3DRMTexture2(iface); + HRESULT hr; - return E_NOTIMPL; + TRACE("iface %p, filename %s.\n", iface, debugstr_a(filename)); + + if (FAILED(hr = IDirect3DRMTexture3_InitFromFile(&object->IDirect3DRMTexture3_iface, filename))) + return hr; + + return D3DRM_OK; } static HRESULT WINAPI d3drm_texture2_InitFromSurface(IDirect3DRMTexture2 *iface, @@ -833,9 +1137,18 @@ static HRESULT WINAPI d3drm_texture3_GetClassName(IDirect3DRMTexture3 *iface, DW static HRESULT WINAPI d3drm_texture3_InitFromFile(IDirect3DRMTexture3 *iface, const char *filename) { - FIXME("iface %p, filename %s stub!\n", iface, debugstr_a(filename)); + struct d3drm_texture *texture = impl_from_IDirect3DRMTexture3(iface); + D3DRMIMAGE *image; + HRESULT hr; - return E_NOTIMPL; + TRACE("iface %p, filename %s.\n", iface, debugstr_a(filename)); + + if (FAILED(hr = d3drm_texture_load(texture, filename, TRUE, &image))) + return hr; + + hr = IDirect3DRMTexture3_InitFromImage(iface, image); + + return hr; } static HRESULT WINAPI d3drm_texture3_InitFromSurface(IDirect3DRMTexture3 *iface, -- 2.17.1