diff --git a/src/win/win_sdl.c b/src/win/win_sdl.c new file mode 100644 index 0000000..1bbf8ab --- /dev/null +++ b/src/win/win_sdl.c @@ -0,0 +1,356 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Rendering module for libSDL2 + * + * NOTE: Given all the problems reported with FULLSCREEN use of SDL, + * we will not use that, but, instead, use a new window which + * coverrs the entire desktop. + * + * Version: @(#)win_sdl.c 1.0.2 2018/05/10 + * + * Authors: Fred N. van Kempen, + * Michael Drüing, + * + * Copyright 2018 Fred N. van Kempen. + * Copyright 2018 Michael Drüing. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#define UNICODE +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include +#include "../emu.h" +#include "../version.h" +#include "../device.h" +#include "../ui/ui.h" +#include "../plat.h" +#include "../devices/video/video.h" +#include "win.h" +#include "win_sdl.h" + + +#if USE_SDL != 1 +# error This module can only be used dynamically. +#endif + + +#define PATH_SDL_DLL "sdl2.dll" + + +static void *sdl_handle = NULL; /* handle to libSDL2 DLL */ +static SDL_Window *sdl_win = NULL; +static SDL_Renderer *sdl_render = NULL; +static SDL_Texture *sdl_tex = NULL; +static HWND sdl_hwnd = NULL; +static int sdl_w, sdl_h; + + +/* Pointers to the real functions. */ +static void (*sdl_GetVersion)(SDL_version *ver); +static char *const (*sdl_GetError)(void); +static int (*sdl_Init)(Uint32 flags); +static void (*sdl_Quit)(void); +static SDL_Window *(*sdl_CreateWindowFrom)(const void *data); +static void (*sdl_DestroyWindow)(SDL_Window *window); +static SDL_Renderer *(*sdl_CreateRenderer)(SDL_Window *window, + int index, Uint32 flags); +static void (*sdl_DestroyRenderer)(SDL_Renderer *renderer); +static SDL_Texture *(*sdl_CreateTexture)(SDL_Renderer *renderer, + Uint32 format, int access, + int w, int h); +static void (*sdl_DestroyTexture)(SDL_Texture *texture); +static int (*sdl_LockTexture)(SDL_Texture *texture, + const SDL_Rect *rect, + void **pixels, int *pitch); +static void (*sdl_UnlockTexture)(SDL_Texture *texture); +static int (*sdl_RenderCopy)(SDL_Renderer *renderer, + SDL_Texture *texture, + const SDL_Rect *srcrect, + const SDL_Rect *dstrect); +static void (*sdl_RenderPresent)(SDL_Renderer *renderer); + + +static const dllimp_t sdl_imports[] = { + { "SDL_GetVersion", &sdl_GetVersion }, + { "SDL_GetError", &sdl_GetError }, + { "SDL_Init", &sdl_Init }, + { "SDL_Quit", &sdl_Quit }, + { "SDL_CreateWindowFrom", &sdl_CreateWindowFrom }, + { "SDL_DestroyWindow", &sdl_DestroyWindow }, + { "SDL_CreateRenderer", &sdl_CreateRenderer }, + { "SDL_DestroyRenderer", &sdl_DestroyRenderer }, + { "SDL_CreateTexture", &sdl_CreateTexture }, + { "SDL_DestroyTexture", &sdl_DestroyTexture }, + { "SDL_LockTexture", &sdl_LockTexture }, + { "SDL_UnlockTexture", &sdl_UnlockTexture }, + { "SDL_RenderCopy", &sdl_RenderCopy }, + { "SDL_RenderPresent", &sdl_RenderPresent }, + { NULL, NULL } +}; + + +static void +sdl_blit(int x, int y, int y1, int y2, int w, int h) +{ + SDL_Rect r_src; + void *pixeldata; + int pitch; + int yy; + + if (buffer32 == NULL) { + video_blit_complete(); + return; + } + + /* + * TODO: + * SDL_UpdateTexture() might be better here, as it is + * (reportedly) slightly faster. + */ + sdl_LockTexture(sdl_tex, 0, &pixeldata, &pitch); + + for (yy = y1; yy < y2; yy++) { + if ((y + yy) >= 0 && (y + yy) < buffer32->h) + memcpy((uint32_t *) &(((uint8_t *)pixeldata)[yy * pitch]), &(((uint32_t *)buffer32->line[y + yy])[x]), w * 4); + } + + video_blit_complete(); + + sdl_UnlockTexture(sdl_tex); + + r_src.x = 0; + r_src.y = 0; + r_src.w = w; + r_src.h = h; + + sdl_RenderCopy(sdl_render, sdl_tex, &r_src, 0); + + sdl_RenderPresent(sdl_render); +} + + +static void +sdl_close(void) +{ + /* Unregister our renderer! */ + video_setblit(NULL); + + if (sdl_tex != NULL) { + sdl_DestroyTexture(sdl_tex); + sdl_tex = NULL; + } + + if (sdl_render != NULL) { + sdl_DestroyRenderer(sdl_render); + sdl_render = NULL; + } + + if (sdl_win != NULL) { + sdl_DestroyWindow(sdl_win); + sdl_win = NULL; + } + + if (sdl_hwnd != NULL) { + plat_set_input(hwndMain); + + DestroyWindow(sdl_hwnd); + sdl_hwnd = NULL; + + SetFocus(hwndMain); + } + + /* Quit and unload the DLL if possible. */ + if (sdl_handle != NULL) { + sdl_Quit(); + + dynld_close(sdl_handle); + sdl_handle = NULL; + } +} + + +static int +sdl_init(int fs) +{ + wchar_t temp[128]; + SDL_version ver; + + pclog("SDL: init (fs=%d)\n", fs); + + cgapal_rebuild(); + + /* Try loading the DLL. */ + sdl_handle = dynld_module(PATH_SDL_DLL, sdl_imports); + if (sdl_handle == NULL) { + pclog("SDL: unable to load '%s', SDL not available.\n", PATH_SDL_DLL); + return(0); + } + + /* Get and log the version of the DLL we are using. */ + sdl_GetVersion(&ver); + pclog("SDL: version %d.%d.%d\n", ver.major, ver.minor, ver.patch); + + /* Initialize the SDL system. */ + if (sdl_Init(SDL_INIT_VIDEO) < 0) { + pclog("SDL: initialization failed (%s)\n", sdl_GetError()); + return(0); + } + + if (fs) { + /* Get the size of the (current) desktop. */ + sdl_w = GetSystemMetrics(SM_CXSCREEN); + sdl_h = GetSystemMetrics(SM_CYSCREEN); + + /* Create the desktop-covering window. */ + _swprintf(temp, L"%s v%s Full-Screen", + TEXT(EMU_NAME), TEXT(EMU_VERSION)); + sdl_hwnd = CreateWindow(FS_CLASS_NAME, + temp, + WS_POPUP, + 0, 0, sdl_w, sdl_h, + HWND_DESKTOP, + NULL, + hInstance, + NULL); +pclog("SDL: FS %dx%d window at %08lx\n", sdl_w, sdl_h, sdl_hwnd); + + /* Redirect RawInput to this new window. */ + plat_set_input(sdl_hwnd); + + /* Show the window, make it topmost, and give it focus. */ + SetWindowPos(sdl_hwnd, HWND_TOPMOST, + 0, 0, sdl_w, sdl_h, SWP_SHOWWINDOW); + + /* Now create the SDL window from that. */ + sdl_win = sdl_CreateWindowFrom((void *)sdl_hwnd); + } else { + /* Redirect RawInput to this new window. */ + plat_set_input(hwndMain); + + ShowWindow(hwndRender, TRUE); + + SetFocus(hwndMain); + + /* Create the SDL window from the render window. */ + sdl_win = sdl_CreateWindowFrom((void *)hwndRender); + } + if (sdl_win == NULL) { + pclog("SDL: unable to CreateWindowFrom (%s)\n", sdl_GetError()); + sdl_close(); + return(0); + } + + /* + * TODO: + * SDL_RENDERER_SOFTWARE, because SDL tries to do funky stuff + * otherwise (it turns off Win7 Aero and it looks like it's + * trying to switch to fullscreen even though the window is + * not a fullscreen window?) + */ + sdl_render = sdl_CreateRenderer(sdl_win, -1, SDL_RENDERER_SOFTWARE); + if (sdl_render == NULL) { + pclog("SDL: unable to create renderer (%s)\n", sdl_GetError()); + sdl_close(); + return(0); + } + + /* + * TODO: + * Actually the source is (apparently) XRGB8888, but the alpha + * channel seems to be set to 255 everywhere, so ARGB8888 works + * just as well. + */ + sdl_tex = sdl_CreateTexture(sdl_render, SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, 2048, 2048); + if (sdl_tex == NULL) { + pclog("SDL: unable to create texture (%s)\n", sdl_GetError()); + sdl_close(); + return(0); + } + + /* Make sure we get a clean exit. */ + atexit(sdl_close); + + /* Register our renderer! */ + video_setblit(sdl_blit); + + return(1); +} + + +static void +sdl_resize(int x, int y) +{ + pclog("SDL: resizing to %dx%d\n", x, y); +} + + +static void +sdl_screenshot(const wchar_t *fn) +{ + /* TODO: implement */ +} + + +/* See if this module is available or not. */ +static int +sdl_available(void) +{ + void *handle; + + handle = dynld_module(PATH_SDL_DLL, NULL); + if (handle != NULL) return(1); + + return(0); +} + + +const vidapi_t sdl_vidapi = { + "SDL", + 1, + sdl_init, + sdl_close, + NULL, + sdl_resize, + NULL, + sdl_screenshot, + sdl_available +}; diff --git a/src/win/win_sdl.h b/src/win/win_sdl.h new file mode 100644 index 0000000..02ed3c9 --- /dev/null +++ b/src/win/win_sdl.h @@ -0,0 +1,56 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Definitions for the libSDL2 rendering module. + * + * Version: @(#)win_sdl.h 1.0.2 2018/05/10 + * + * Authors: Fred N. van Kempen, + * Michael Drüing, + * + * Copyright 2018 Fred N. van Kempen. + * Copyright 2018 Michael Drüing. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef WIN_SDL_H +# define WIN_SDL_H + + +extern const vidapi_t sdl_vidapi; + + +#endif /*WIN_SDL_H*/