From b9699f4780ff85896cabecec33dd4ea25cf85470 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Wed, 10 Oct 2018 09:58:49 -0400 Subject: [PATCH] gdi: texture load support, fix menu text alignment, support multi-line messages --- gfx/common/gdi_common.h | 14 ++++ gfx/common/win32_common.c | 8 +- gfx/drivers/gdi_gfx.c | 66 +++++++++++++++- gfx/drivers_font/gdi_font.c | 100 ++++++++++++++++++------ menu/drivers_display/menu_display_gdi.c | 62 ++++++++++++++- 5 files changed, 218 insertions(+), 32 deletions(-) diff --git a/gfx/common/gdi_common.h b/gfx/common/gdi_common.h index 0f0b971018..ddb33b3fb3 100644 --- a/gfx/common/gdi_common.h +++ b/gfx/common/gdi_common.h @@ -27,6 +27,7 @@ typedef struct gdi #endif HDC winDC; HDC memDC; + HDC texDC; HBITMAP bmp; HBITMAP bmp_old; unsigned video_width; @@ -35,4 +36,17 @@ typedef struct gdi unsigned screen_height; } gdi_t; +typedef struct gdi_texture +{ + int width; + int height; + int active_width; + int active_height; + + enum texture_filter_type type; + void* data; + HBITMAP bmp; + HBITMAP bmp_old; +} gdi_texture_t; + #endif diff --git a/gfx/common/win32_common.c b/gfx/common/win32_common.c index 69f82746f6..b580a1bcb0 100644 --- a/gfx/common/win32_common.c +++ b/gfx/common/win32_common.c @@ -837,18 +837,18 @@ LRESULT CALLBACK WndProcGDI(HWND hwnd, UINT message, /* draw menu contents behind a gradient background */ if (gdi && gdi->memDC) { - RECT rect; + /*RECT rect; HBRUSH brush = CreateSolidBrush(RGB(1,81,127)); - GetClientRect(hwnd, &rect); + GetClientRect(hwnd, &rect);*/ StretchBlt(gdi->winDC, 0, 0, gdi->screen_width, gdi->screen_height, gdi->memDC, 0, 0, gdi->video_width, gdi->video_height, SRCCOPY); - FillRect(gdi->memDC, &rect, brush); - DeleteObject(brush); + /*FillRect(gdi->memDC, &rect, brush); + DeleteObject(brush);*/ } } else diff --git a/gfx/drivers/gdi_gfx.c b/gfx/drivers/gdi_gfx.c index dae5a1b091..6b820c1e18 100644 --- a/gfx/drivers/gdi_gfx.c +++ b/gfx/drivers/gdi_gfx.c @@ -16,6 +16,7 @@ */ #include +#include #ifdef HAVE_CONFIG_H #include "../../config.h" @@ -192,6 +193,9 @@ static bool gdi_gfx_frame(void *data, const void *frame, HWND hwnd = win32_get_window(); BITMAPINFO *info; + /* FIXME */ + video_info->xmb_shadows_enable = false; + if (!frame || !frame_width || !frame_height) return true; @@ -414,9 +418,16 @@ static void gdi_gfx_free(void *data) if (!gdi) return; + if (gdi->bmp) + DeleteObject(gdi->bmp); + + if (gdi->texDC) + { + DeleteDC(gdi->texDC); + gdi->texDC = 0; + } if (gdi->memDC) { - DeleteObject(gdi->bmp); DeleteDC(gdi->memDC); gdi->memDC = 0; } @@ -532,12 +543,61 @@ static void gdi_set_video_mode(void *data, unsigned width, unsigned height, video_context_driver_set_video_mode(&mode); } +static uintptr_t gdi_load_texture(void *video_data, void *data, + bool threaded, enum texture_filter_type filter_type) +{ + struct texture_image *image = (struct texture_image*)data; + int size = image->width * image->height * sizeof(uint32_t); + gdi_texture_t *texture = NULL; + void *tmpdata = NULL; + + if (!image || image->width > 2048 || image->height > 2048) + return 0; + + texture = calloc(1, sizeof(*texture)); + texture->width = image->width; + texture->height = image->height; + texture->active_width = image->width; + texture->active_height = image->height; + texture->data = calloc(1, texture->width * texture->height * sizeof(uint32_t)); + texture->type = filter_type; + + if (!texture->data) + { + free(texture); + return 0; + } + + memcpy(texture->data, image->pixels, texture->width * texture->height * sizeof(uint32_t)); + + return (uintptr_t)texture; +} + +static void gdi_unload_texture(void *data, uintptr_t handle) +{ + struct gdi_texture *texture = (struct gdi_texture*)handle; + + if (!texture) + return; + + if (texture->data) + free(texture->data); + + if (texture->bmp) + { + DeleteObject(texture->bmp); + texture->bmp = NULL; + } + + free(texture); +} + static const video_poke_interface_t gdi_poke_interface = { NULL, /* get_flags */ NULL, /* set_coords */ NULL, /* set_mvp */ - NULL, - NULL, + gdi_load_texture, + gdi_unload_texture, gdi_set_video_mode, win32_get_refresh_rate, NULL, diff --git a/gfx/drivers_font/gdi_font.c b/gfx/drivers_font/gdi_font.c index 1c37ddd5ed..090ab9c9d8 100644 --- a/gfx/drivers_font/gdi_font.c +++ b/gfx/drivers_font/gdi_font.c @@ -18,6 +18,7 @@ #include #include #include +#include #ifdef HAVE_CONFIG_H #include "../../config.h" @@ -85,65 +86,116 @@ static void gdi_render_msg( void *data, const char *msg, const struct font_params *params) { - float x, y, scale; - unsigned newX, newY, len; + float x, y, scale, drop_mod, alpha, drop_alpha; + int i, drop_x, drop_y, msg_strlen; + unsigned newX, newY, newDropX, newDropY; unsigned align; - unsigned red; - unsigned green; - unsigned blue; + unsigned red, green, blue; + unsigned drop_red, drop_green, drop_blue; gdi_raster_t *font = (gdi_raster_t*)data; unsigned width = video_info->width; unsigned height = video_info->height; + SIZE textSize = {0}; + struct string_list *msg_list = NULL; if (!font || string_is_empty(msg) || !font->gdi) return; if (params) { - x = params->x; - y = params->y; - scale = params->scale; - align = params->text_align; + x = params->x; + y = params->y; + drop_x = params->drop_x; + drop_y = params->drop_y; + drop_mod = params->drop_mod; + drop_alpha = params->drop_alpha; + scale = params->scale; + align = params->text_align; - red = FONT_COLOR_GET_RED(params->color); - green = FONT_COLOR_GET_GREEN(params->color); - blue = FONT_COLOR_GET_BLUE(params->color); + red = FONT_COLOR_GET_RED(params->color); + green = FONT_COLOR_GET_GREEN(params->color); + blue = FONT_COLOR_GET_BLUE(params->color); + alpha = FONT_COLOR_GET_ALPHA(params->color); } else { - x = video_info->font_msg_pos_x; - y = video_info->font_msg_pos_y; - scale = 1.0f; - align = TEXT_ALIGN_LEFT; - red = video_info->font_msg_color_r * 255.0f; - green = video_info->font_msg_color_g * 255.0f; - blue = video_info->font_msg_color_b * 255.0f; + x = video_info->font_msg_pos_x; + y = video_info->font_msg_pos_y; + drop_x = -2; + drop_y = -2; + drop_mod = 0.3f; + drop_alpha = 1.0f; + scale = 1.0f; + align = TEXT_ALIGN_LEFT; + red = video_info->font_msg_color_r * 255.0f; + green = video_info->font_msg_color_g * 255.0f; + blue = video_info->font_msg_color_b * 255.0f; + alpha = 255; } - len = utf8len(msg); + msg_strlen = strlen(msg); + + GetTextExtentPoint32(font->gdi->memDC, msg, msg_strlen, &textSize); switch (align) { case TEXT_ALIGN_LEFT: newX = x * width * scale; + newDropX = drop_x * width * scale; break; case TEXT_ALIGN_RIGHT: - newX = (x * width * scale) - len; + newX = (x * width * scale) - textSize.cx; + newDropX = (drop_x * width * scale) - textSize.cx; break; case TEXT_ALIGN_CENTER: - newX = (x * width * scale) - (len / 2); + newX = (x * width * scale) - (textSize.cx / 2); + newDropX = (drop_x * width * scale) - (textSize.cx / 2); break; default: newX = 0; + newDropX = 0; break; } - newY = height - (y * height * scale); + newY = height - (y * height * scale) - textSize.cy; + newDropY = height - (drop_y * height * scale) - textSize.cy; font->gdi->bmp_old = (HBITMAP)SelectObject(font->gdi->memDC, font->gdi->bmp); + SetBkMode(font->gdi->memDC, TRANSPARENT); + + msg_list = string_split(msg, "\n"); + + if (drop_x || drop_y) + { + float dark_alpha = drop_alpha; + drop_red = red * drop_mod * dark_alpha; + drop_green = green * drop_mod * dark_alpha; + drop_blue = blue * drop_mod * dark_alpha; + + SetTextColor(font->gdi->memDC, RGB(drop_red, drop_green, drop_blue)); + + if (msg_list) + { + for (i = 0; i < msg_list->size; i++) + { + TextOut(font->gdi->memDC, newDropX, newDropY + (textSize.cy * i), msg_list->elems[i].data, utf8len(msg_list->elems[i].data)); + } + } + } + SetTextColor(font->gdi->memDC, RGB(red, green, blue)); - TextOut(font->gdi->memDC, newX, newY, msg, len); + + if (msg_list) + { + for (i = 0; i < msg_list->size; i++) + { + TextOut(font->gdi->memDC, newX, newY + (textSize.cy * i), msg_list->elems[i].data, utf8len(msg_list->elems[i].data)); + } + + string_list_free(msg_list); + } + SelectObject(font->gdi->memDC, font->gdi->bmp_old); } diff --git a/menu/drivers_display/menu_display_gdi.c b/menu/drivers_display/menu_display_gdi.c index 95e41b7b28..552404b069 100644 --- a/menu/drivers_display/menu_display_gdi.c +++ b/menu/drivers_display/menu_display_gdi.c @@ -16,17 +16,20 @@ #include +#include #include #include #include "../../config.def.h" #include "../../gfx/font_driver.h" #include "../../gfx/video_driver.h" +#include "../../verbosity.h" #include "../menu_driver.h" #if defined(_WIN32) && !defined(_XBOX) #include "../../gfx/common/win32_common.h" +#include "../../gfx/common/gdi_common.h" #endif static void *menu_display_gdi_get_default_mvp(video_frame_info_t *video_info) @@ -45,6 +48,63 @@ static void menu_display_gdi_blend_end(video_frame_info_t *video_info) static void menu_display_gdi_draw(menu_display_ctx_draw_t *draw, video_frame_info_t *video_info) { + struct gdi_texture *texture = NULL; + gdi_t *gdi = (gdi_t*)video_driver_get_ptr(false); + BITMAPINFO info = {0}; + + if (!gdi || !draw || draw->x < 0 || draw->y < 0 || draw->width <= 1 || draw->height <= 1) + return; + + texture = (struct gdi_texture*)draw->texture; + + if (!texture || texture->width <= 1 || texture->height <= 1) + return; + + info.bmiHeader.biBitCount = 32; + info.bmiHeader.biWidth = texture->width; + info.bmiHeader.biHeight = -texture->height; + info.bmiHeader.biPlanes = 1; + info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + info.bmiHeader.biSizeImage = 0; + info.bmiHeader.biCompression = BI_RGB; + + if (gdi->memDC) + { + BLENDFUNCTION blend = {0}; + + if (!gdi->texDC) + gdi->texDC = CreateCompatibleDC(gdi->winDC); + + if (texture->bmp) + { + texture->bmp_old = SelectObject(gdi->texDC, texture->bmp); + } + else + { + /* scale texture data into a bitmap we can easily blit later */ + texture->bmp = CreateCompatibleBitmap(gdi->winDC, draw->width, draw->height); + texture->bmp_old = SelectObject(gdi->texDC, texture->bmp); + + StretchDIBits(gdi->texDC, 0, 0, draw->width, draw->height, 0, 0, texture->width, texture->height, texture->data, &info, DIB_RGB_COLORS, SRCCOPY); + } + + gdi->bmp_old = SelectObject(gdi->memDC, gdi->bmp); + + blend.BlendOp = AC_SRC_OVER; + blend.BlendFlags = 0; + blend.SourceConstantAlpha = 255;/*clamp_8bit(draw->coords->color[3] * 255.0f);*/ + blend.AlphaFormat = AC_SRC_ALPHA; + + AlphaBlend(gdi->memDC, draw->x, video_info->height - draw->height - draw->y, draw->width, draw->height, gdi->texDC, 0, 0, draw->width, draw->height, blend); + + /*TransparentBlt(gdi->memDC, draw->x, video_info->height - draw->height - draw->y, draw->width, draw->height, gdi->texDC, 0, 0, draw->width, draw->height, 0);*/ + + /* To draw without blending: */ + /*StretchBlt(gdi->memDC, draw->x, video_info->height - draw->height - draw->y, draw->width, draw->height, gdi->texDC, 0, 0, draw->width, draw->height, SRCCOPY);*/ + + SelectObject(gdi->memDC, gdi->bmp_old); + SelectObject(gdi->texDC, texture->bmp_old); + } } static void menu_display_gdi_draw_pipeline(menu_display_ctx_draw_t *draw, @@ -80,7 +140,7 @@ static bool menu_display_gdi_font_init_first( font_path, font_size, true, is_threaded, FONT_DRIVER_RENDER_GDI))) - return false; + return false; return true; }