From 5a3f82ebeee77cf78393aa1d59df0b03fcc64135 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sun, 7 Jun 2009 02:44:46 +0000 Subject: [PATCH] Hi, I have prepared a set of patches to readd WindowsCE support to SDL 1.3. I've created a new GAPI/Rawframebuffer and a DirectDraw renderer. Both renderers are work in progress and there are several unimplemented cases. (Notably RenderLine/RenderPoint/RenderFill/QueryTexturePixels/UpdateTexture and texture blending ) Nevertheless I am successfully using these renderers together with the SDL software renderer. (On most devices the SDL software renderer will be much faster as there are only badly optimized vendor drivers available) I send these patches now in this unpolished state because there seems to be some interest in win ce and someone has to start supporting SDL 1.3 Now on to the patches: wince_events_window_fixes.patch fixes some wince incompatibilities and adds fullscreen support via SHFullScreen. NOTE: This patch shouldn't have any side effects on Windows, but I have NOT tested it on Windows, so please double-check. This patch doesn't dependent on the following ones. wince_renderers_system.patch This patch does all necessary modifications to the SDL system. - it adds the renderers to the configure system - it adds the renderers to win32video SDL_ceddrawrender.c SDL_ceddrawrender.h SDL_gapirender_c.h SDL_gapirender.c SDL_gapirender.h these files add the new render drivers and should be placed in src/video/win32 Some notes to people who want to test this: - I have only compiled sdl with ming32ce, so the VisualC files are not up to date - As mingw32ce has no ddraw.h this file must be taken from the MS SDK and modified to work with gcc - I had to modify line 2611 in configure.in to EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lcoredll -lcommctrl -lmmtimer -Wl,--image-base -Wl,0x10000" otherwise GetCPinfo wouldn't link. If someone knows whats causing this I'd be happy to hear about it. It would be great if these patches could make their way into SVN as this would make collaboration much much easier. I'm out of office for the next week and therefore will be unavailable via email. Regards Stefan --- configure.in | 25 + include/SDL_config.h.in | 3 +- src/video/win32/SDL_ceddrawrender.c | 831 ++++++++++++++++++++++++++++ src/video/win32/SDL_ceddrawrender.h | 31 ++ src/video/win32/SDL_gapirender.c | 646 +++++++++++++++++++++ src/video/win32/SDL_gapirender.h | 33 ++ src/video/win32/SDL_gapirender_c.h | 121 ++++ src/video/win32/SDL_win32events.c | 13 +- src/video/win32/SDL_win32video.c | 30 + src/video/win32/SDL_win32video.h | 11 + src/video/win32/SDL_win32window.c | 105 +++- 11 files changed, 1836 insertions(+), 13 deletions(-) create mode 100644 src/video/win32/SDL_ceddrawrender.c create mode 100644 src/video/win32/SDL_ceddrawrender.h create mode 100644 src/video/win32/SDL_gapirender.c create mode 100644 src/video/win32/SDL_gapirender.h create mode 100644 src/video/win32/SDL_gapirender_c.h diff --git a/configure.in b/configure.in index d8b1bcf80..4648823ec 100644 --- a/configure.in +++ b/configure.in @@ -2077,6 +2077,18 @@ CheckWIN32() ]) fi + AC_MSG_CHECKING(Windows CE) + have_wince=no + AC_TRY_COMPILE([ +#ifndef _WIN32_WCE +#error This is not Windows CE +#endif + ],[ + ],[ + have_wince=yes + ]) + AC_MSG_RESULT($have_wince) + dnl See if the user wants to redirect standard output to files AC_ARG_ENABLE(stdio-redirect, AC_HELP_STRING([--enable-stdio-redirect], [Redirect STDIO to files on Win32 [[default=yes]]]), @@ -2094,6 +2106,7 @@ AC_HELP_STRING([--enable-directx], [use DirectX for Win32 audio/video [[default= , enable_directx=yes) if test x$enable_directx = xyes; then AC_CHECK_HEADER(d3d9.h, have_d3d=yes) + AC_CHECK_HEADER(ddraw.h, have_ddraw=yes) AC_CHECK_HEADER(dsound.h, have_dsound=yes) AC_CHECK_HEADER(dinput.h, have_dinput=yes) fi @@ -2556,6 +2569,18 @@ AC_HELP_STRING([--enable-render-gdi], [enable the GDI render driver [[default=ye if test x$enable_render_gdi = xyes; then AC_DEFINE(SDL_VIDEO_RENDER_GDI) fi + AC_ARG_ENABLE(render-gapi, +AC_HELP_STRING([--enable-render-gapi], [enable the GAPI/RAWFRAMEBUFFER render driver [[default=yes]]]), + , enable_render_gapi=yes) + if test x$enable_render_gapi = xyes -a x$have_wince = xyes; then + AC_DEFINE(SDL_VIDEO_RENDER_GAPI) + fi + AC_ARG_ENABLE(render-ddraw, +AC_HELP_STRING([--enable-render-ddraw], [enable the Mobile DirectDraw render driver [[default=yes]]]), + , enable_render_ddraw=yes) + if test x$enable_render_ddraw = xyes -a x$have_wince = xyes -a x$have_ddraw = xyes; then + AC_DEFINE(SDL_VIDEO_RENDER_DDRAW) + fi AC_ARG_ENABLE(render-d3d, AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[default=yes]]]), , enable_render_d3d=yes) diff --git a/include/SDL_config.h.in b/include/SDL_config.h.in index c02193596..68ac2809c 100644 --- a/include/SDL_config.h.in +++ b/include/SDL_config.h.in @@ -278,7 +278,6 @@ #undef SDL_VIDEO_DRIVER_DIRECTFB_DYNAMIC #undef SDL_VIDEO_DRIVER_DUMMY #undef SDL_VIDEO_DRIVER_FBCON -#undef SDL_VIDEO_DRIVER_GAPI #undef SDL_VIDEO_DRIVER_GEM #undef SDL_VIDEO_DRIVER_IPOD #undef SDL_VIDEO_DRIVER_NANOX @@ -312,6 +311,8 @@ #undef SDL_VIDEO_RENDER_OGL #undef SDL_VIDEO_RENDER_OGL_ES #undef SDL_VIDEO_RENDER_X11 +#undef SDL_VIDEO_RENDER_GAPI +#undef SDL_VIDEO_RENDER_DDRAW /* Enable OpenGL support */ #undef SDL_VIDEO_OPENGL diff --git a/src/video/win32/SDL_ceddrawrender.c b/src/video/win32/SDL_ceddrawrender.c new file mode 100644 index 000000000..29db3ccb6 --- /dev/null +++ b/src/video/win32/SDL_ceddrawrender.c @@ -0,0 +1,831 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2009 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org + + Stefan Klug + klug.stefan@gmx.de +*/ +#include "SDL_config.h" + +#if SDL_VIDEO_RENDER_DDRAW + +#include "SDL_win32video.h" +#include "../SDL_yuv_sw_c.h" + +#if 0 +#define DDRAW_LOG(...) printf(__VA_ARGS__) +#else +#define DDRAW_LOG(...) +#endif + + +/* DirectDraw renderer implementation */ + +static SDL_Renderer *DDRAW_CreateRenderer(SDL_Window * window, Uint32 flags); +static int DDRAW_DisplayModeChanged(SDL_Renderer * renderer); +static int DDRAW_CreateTexture(SDL_Renderer * renderer, + SDL_Texture * texture); +static int DDRAW_QueryTexturePixels(SDL_Renderer * renderer, + SDL_Texture * texture, void **pixels, + int *pitch); +static int DDRAW_SetTextureColorMod(SDL_Renderer * renderer, + SDL_Texture * texture); +static int DDRAW_SetTextureAlphaMod(SDL_Renderer * renderer, + SDL_Texture * texture); +static int DDRAW_SetTextureBlendMode(SDL_Renderer * renderer, + SDL_Texture * texture); +static int DDRAW_SetTextureScaleMode(SDL_Renderer * renderer, + SDL_Texture * texture); +static int DDRAW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, const void *pixels, + int pitch); +static int DDRAW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, int markDirty, + void **pixels, int *pitch); +static void DDRAW_UnlockTexture(SDL_Renderer * renderer, + SDL_Texture * texture); +static void DDRAW_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, + int numrects, const SDL_Rect * rects); +static int DDRAW_RenderPoint(SDL_Renderer * renderer, int x, int y); +static int DDRAW_RenderLine(SDL_Renderer * renderer, int x1, int y1, int x2, + int y2); +static int DDRAW_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect); +static int DDRAW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * srcrect, + const SDL_Rect * dstrect); +static void DDRAW_RenderPresent(SDL_Renderer * renderer); +static void DDRAW_DestroyTexture(SDL_Renderer * renderer, + SDL_Texture * texture); +static void DDRAW_DestroyRenderer(SDL_Renderer * renderer); + + +SDL_RenderDriver DDRAW_RenderDriver = { + DDRAW_CreateRenderer, + { + "ddraw", + (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTCOPY | + SDL_RENDERER_PRESENTFLIP2 | SDL_RENDERER_PRESENTFLIP3 | + SDL_RENDERER_PRESENTDISCARD | SDL_RENDERER_ACCELERATED), + (SDL_TEXTUREMODULATE_NONE), + (SDL_BLENDMODE_NONE), + (SDL_TEXTURESCALEMODE_NONE), + 0, + {0}, + 0, + 0} +}; + +typedef struct +{ + IDirectDraw *ddraw; + IDirectDrawSurface *primary; +} DDRAW_RenderData; + +typedef struct +{ + RECT lock; + IDirectDrawSurface *surface; +} DDRAW_TextureData; + + +static void +DDRAW_SetError(const char *prefix, HRESULT result) +{ + const char *error; + + switch (result) { + case DDERR_CANTCREATEDC: + error = "CANTCREATEDC"; + break; + case DDERR_CANTLOCKSURFACE: + error = "CANTLOCKSURFACE"; + break; + case DDERR_CLIPPERISUSINGHWND: + error = "CLIPPERISUSINGHWND"; + break; + case DDERR_COLORKEYNOTSET: + error = "COLORKEYNOTSET"; + break; + case DDERR_CURRENTLYNOTAVAIL: + error = "CURRENTLYNOTAVAIL"; + break; + case DDERR_DCALREADYCREATED: + error = "DCALREADYCREATED"; + break; + case DDERR_DEVICEDOESNTOWNSURFACE: + error = "DEVICEDOESNTOWNSURFACE"; + break; + case DDERR_DIRECTDRAWALREADYCREATED: + error = "DIRECTDRAWALREADYCREATED"; + break; + case DDERR_EXCLUSIVEMODEALREADYSET: + error = "EXCLUSIVEMODEALREADYSET"; + break; + case DDERR_GENERIC: + error = "GENERIC"; + break; + case DDERR_HEIGHTALIGN: + error = "HEIGHTALIGN"; + break; + case DDERR_IMPLICITLYCREATED: + error = "IMPLICITLYCREATED"; + break; + case DDERR_INCOMPATIBLEPRIMARY: + error = "INCOMPATIBLEPRIMARY"; + break; + case DDERR_INVALIDCAPS: + error = "INVALIDCAPS"; + break; + case DDERR_INVALIDCLIPLIST: + error = "INVALIDCLIPLIST"; + break; + case DDERR_INVALIDMODE: + error = "INVALIDMODE"; + break; + case DDERR_INVALIDOBJECT: + error = "INVALIDOBJECT"; + break; + case DDERR_INVALIDPARAMS: + error = "INVALIDPARAMS"; + break; + case DDERR_INVALIDPIXELFORMAT: + error = "INVALIDPIXELFORMAT"; + break; + case DDERR_INVALIDPOSITION: + error = "INVALIDPOSITION"; + break; + case DDERR_INVALIDRECT: + error = "INVALIDRECT"; + break; + case DDERR_LOCKEDSURFACES: + error = "LOCKEDSURFACES"; + break; + case DDERR_MOREDATA: + error = "MOREDATA"; + break; + case DDERR_NOALPHAHW: + error = "NOALPHAHW"; + break; + case DDERR_NOBLTHW: + error = "NOBLTHW"; + break; + case DDERR_NOCLIPLIST: + error = "NOCLIPLIST"; + break; + case DDERR_NOCLIPPERATTACHED: + error = "NOCLIPPERATTACHED"; + break; + case DDERR_NOCOLORCONVHW: + error = "NOCOLORCONVHW"; + break; + case DDERR_NOCOLORKEYHW: + error = "NOCOLORKEYHW"; + break; + case DDERR_NOCOOPERATIVELEVELSET: + error = "NOCOOPERATIVELEVELSET"; + break; + case DDERR_NODC: + error = "NODC"; + break; + case DDERR_NOFLIPHW: + error = "NOFLIPHW"; + break; + case DDERR_NOOVERLAYDEST: + error = "NOOVERLAYDEST"; + break; + case DDERR_NOOVERLAYHW: + error = "NOOVERLAYHW"; + break; + case DDERR_NOPALETTEATTACHED: + error = "NOPALETTEATTACHED"; + break; + case DDERR_NOPALETTEHW: + error = "NOPALETTEHW"; + break; + case DDERR_NORASTEROPHW: + error = "NORASTEROPHW"; + break; + case DDERR_NOSTRETCHHW: + error = "NOSTRETCHHW"; + break; + case DDERR_NOTAOVERLAYSURFACE: + error = "NOTAOVERLAYSURFACE"; + break; + case DDERR_NOTFLIPPABLE: + error = "NOTFLIPPABLE"; + break; + case DDERR_NOTFOUND: + error = "NOTFOUND"; + break; + case DDERR_NOTLOCKED: + error = "NOTLOCKED"; + break; + case DDERR_NOTPALETTIZED: + error = "NOTPALETTIZED"; + break; + case DDERR_NOVSYNCHW: + error = "NOVSYNCHW"; + break; + case DDERR_NOZOVERLAYHW: + error = "NOZOVERLAYHW"; + break; + case DDERR_OUTOFCAPS: + error = "OUTOFCAPS"; + break; + case DDERR_OUTOFMEMORY: + error = "OUTOFMEMORY"; + break; + case DDERR_OUTOFVIDEOMEMORY: + error = "OUTOFVIDEOMEMORY"; + break; + case DDERR_OVERLAPPINGRECTS: + error = "OVERLAPPINGRECTS"; + break; + case DDERR_OVERLAYNOTVISIBLE: + error = "OVERLAYNOTVISIBLE"; + break; + case DDERR_PALETTEBUSY: + error = "PALETTEBUSY"; + break; + case DDERR_PRIMARYSURFACEALREADYEXISTS: + error = "PRIMARYSURFACEALREADYEXISTS"; + break; + case DDERR_REGIONTOOSMALL: + error = "REGIONTOOSMALL"; + break; + case DDERR_SURFACEBUSY: + error = "SURFACEBUSY"; + break; + case DDERR_SURFACELOST: + error = "SURFACELOST"; + break; + case DDERR_TOOBIGHEIGHT: + error = "TOOBIGHEIGHT"; + break; + case DDERR_TOOBIGSIZE: + error = "TOOBIGSIZE"; + break; + case DDERR_TOOBIGWIDTH: + error = "TOOBIGWIDTH"; + break; + case DDERR_UNSUPPORTED: + error = "UNSUPPORTED"; + break; + case DDERR_UNSUPPORTEDFORMAT: + error = "UNSUPPORTEDFORMAT"; + break; + case DDERR_VERTICALBLANKINPROGRESS: + error = "VERTICALBLANKINPROGRESS"; + break; + case DDERR_VIDEONOTACTIVE: + error = "VIDEONOTACTIVE"; + break; + case DDERR_WASSTILLDRAWING: + error = "WASSTILLDRAWING"; + break; + case DDERR_WRONGMODE: + error = "WRONGMODE"; + break; + default: + error = "UNKNOWN"; + break; + } + SDL_SetError("%s: %s", prefix, error); +} + +static SDL_bool +PixelFormatToDDPIXELFORMAT(Uint32 format, LPDDPIXELFORMAT dst) +{ + SDL_zerop(dst); + dst->dwSize = sizeof(*dst); + + if (SDL_ISPIXELFORMAT_FOURCC(format)) { + dst->dwFlags = DDPF_FOURCC; + dst->dwFourCC = format; + } else if (SDL_ISPIXELFORMAT_INDEXED(format)) { + SDL_SetError("Indexed pixelformats are not supported."); + return SDL_FALSE; + } else { + int bpp; + Uint32 Rmask, Gmask, Bmask, Amask; + if (!SDL_PixelFormatEnumToMasks + (format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) { + SDL_SetError("pixelformat not supported"); + return SDL_FALSE; + } + + if (!Rmask && !Gmask && !Bmask) { + dst->dwFlags = DDPF_ALPHA; + dst->dwAlphaBitDepth = bpp; + } else { + dst->dwFlags = DDPF_RGB; + dst->dwRGBBitCount = bpp; + dst->dwRBitMask = Rmask; + dst->dwGBitMask = Gmask; + dst->dwBBitMask = Bmask; + + if (Amask) { + dst->dwFlags |= DDPF_ALPHAPIXELS; + dst->dwRGBAlphaBitMask = Amask; + } + } + } + + return SDL_TRUE; +} + +static SDL_bool +DDRAW_IsTextureFormatAvailable(IDirectDraw * ddraw, Uint32 display_format, + Uint32 texture_format) +{ + int bpp; + Uint32 Rmask, Gmask, Bmask, Amask; + + if (SDL_ISPIXELFORMAT_FOURCC(texture_format)) { + //TODO I don't expect DDRAW to support all 4CC formats, but I don't know which ones + return SDL_TRUE; + } + //These are only basic checks + if (SDL_ISPIXELFORMAT_INDEXED(texture_format)) { + return SDL_FALSE; + } + + if (!SDL_PixelFormatEnumToMasks + (texture_format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) { + return SDL_FALSE; + } + + switch (bpp) { + case 4: + case 8: + case 16: + case 24: + case 32: + break; + default: + return SDL_FALSE; + } + + return SDL_TRUE; +} + +void +DDRAW_AddRenderDriver(_THIS) +{ + SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; + SDL_RendererInfo *info = &DDRAW_RenderDriver.info; + SDL_DisplayMode *mode = &SDL_CurrentDisplay.desktop_mode; + + if (data->ddraw) { + int i; + int formats[] = { + SDL_PIXELFORMAT_INDEX8, + SDL_PIXELFORMAT_RGB332, + SDL_PIXELFORMAT_RGB444, + SDL_PIXELFORMAT_RGB555, + SDL_PIXELFORMAT_ARGB4444, + SDL_PIXELFORMAT_ARGB1555, + SDL_PIXELFORMAT_RGB565, + SDL_PIXELFORMAT_RGB888, + SDL_PIXELFORMAT_ARGB8888, + SDL_PIXELFORMAT_ARGB2101010, + }; + + for (i = 0; i < SDL_arraysize(formats); ++i) { + if (DDRAW_IsTextureFormatAvailable + (data->ddraw, mode->format, formats[i])) { + info->texture_formats[info->num_texture_formats++] = + formats[i]; + } + } + + //TODO the fourcc formats should get fetched from IDirectDraw::GetFourCCCodes + info->texture_formats[info->num_texture_formats++] = + SDL_PIXELFORMAT_YV12; + info->texture_formats[info->num_texture_formats++] = + SDL_PIXELFORMAT_IYUV; + info->texture_formats[info->num_texture_formats++] = + SDL_PIXELFORMAT_YUY2; + info->texture_formats[info->num_texture_formats++] = + SDL_PIXELFORMAT_UYVY; + info->texture_formats[info->num_texture_formats++] = + SDL_PIXELFORMAT_YVYU; + + SDL_AddRenderDriver(0, &DDRAW_RenderDriver); + } +} + +SDL_Renderer * +DDRAW_CreateRenderer(SDL_Window * window, Uint32 flags) +{ + SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window); + SDL_VideoData *videodata = (SDL_VideoData *) display->device->driverdata; + SDL_WindowData *windowdata = (SDL_WindowData *) window->driverdata; + SDL_Renderer *renderer; + DDRAW_RenderData *data; + HRESULT result; + DDSURFACEDESC ddsd; + + renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); + if (!renderer) { + SDL_OutOfMemory(); + return NULL; + } + + data = (DDRAW_RenderData *) SDL_calloc(1, sizeof(*data)); + if (!data) { + DDRAW_DestroyRenderer(renderer); + SDL_OutOfMemory(); + return NULL; + } + data->ddraw = videodata->ddraw; + + renderer->DisplayModeChanged = DDRAW_DisplayModeChanged; + renderer->CreateTexture = DDRAW_CreateTexture; + renderer->QueryTexturePixels = DDRAW_QueryTexturePixels; + + renderer->SetTextureColorMod = DDRAW_SetTextureColorMod; + renderer->SetTextureAlphaMod = DDRAW_SetTextureAlphaMod; + renderer->SetTextureBlendMode = DDRAW_SetTextureBlendMode; + renderer->SetTextureScaleMode = DDRAW_SetTextureScaleMode; + renderer->UpdateTexture = DDRAW_UpdateTexture; + renderer->LockTexture = DDRAW_LockTexture; + renderer->UnlockTexture = DDRAW_UnlockTexture; + renderer->DirtyTexture = DDRAW_DirtyTexture; + renderer->RenderPoint = DDRAW_RenderPoint; + renderer->RenderLine = DDRAW_RenderLine; + renderer->RenderFill = DDRAW_RenderFill; + renderer->RenderCopy = DDRAW_RenderCopy; + renderer->RenderPresent = DDRAW_RenderPresent; + renderer->DestroyTexture = DDRAW_DestroyTexture; + renderer->DestroyRenderer = DDRAW_DestroyRenderer; + renderer->info = DDRAW_RenderDriver.info; + renderer->window = window->id; + renderer->driverdata = data; + + renderer->info.flags = SDL_RENDERER_ACCELERATED; + + SDL_zero(ddsd); + ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_CAPS; + + if (window->flags & SDL_WINDOW_FULLSCREEN) { + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + } else { + //TODO handle non fullscreen + SDL_SetError("DirectDraw renderer has only fullscreen implemented"); + DDRAW_DestroyRenderer(renderer); + return NULL; + } + + if (flags & SDL_RENDERER_PRESENTFLIP2) { + ddsd.dwFlags |= DDSD_BACKBUFFERCOUNT; + ddsd.dwBackBufferCount = 2; + } else if (flags & SDL_RENDERER_PRESENTFLIP3) { + ddsd.dwFlags |= DDSD_BACKBUFFERCOUNT; + ddsd.dwBackBufferCount = 3; + } else if (flags & SDL_RENDERER_PRESENTCOPY) { + //TODO what is the best approximation to this mode + } else { + + } + + if (flags & SDL_RENDERER_PRESENTVSYNC) { + SDL_SetError("DirectDraw renderer with v-sync is not implemented"); + DDRAW_DestroyRenderer(renderer); + return NULL; + } + + result = + data->ddraw->lpVtbl->SetCooperativeLevel(data->ddraw, + windowdata->hwnd, + DDSCL_NORMAL); + if (result != DD_OK) { + DDRAW_SetError("CreateDevice()", result); + DDRAW_DestroyRenderer(renderer); + return NULL; + } + + result = + data->ddraw->lpVtbl->CreateSurface(data->ddraw, &ddsd, &data->primary, + NULL); + if (result != DD_OK) { + DDRAW_SetError("CreateDevice()", result); + DDRAW_DestroyRenderer(renderer); + return NULL; + } + + return renderer; +} + +static int +DDRAW_Reset(SDL_Renderer * renderer) +{ + //TODO implement + /*D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; + HRESULT result; + + result = IDirect3DDevice9_Reset(data->device, &data->pparams); + if (FAILED(result)) { + if (result == D3DERR_DEVICELOST) { + /* Don't worry about it, we'll reset later... * + return 0; + } else { + D3D_SetError("Reset()", result); + return -1; + } + } + IDirect3DDevice9_SetVertexShader(data->device, NULL); + IDirect3DDevice9_SetFVF(data->device, + D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1); + IDirect3DDevice9_SetRenderState(data->device, D3DRS_CULLMODE, + D3DCULL_NONE); + IDirect3DDevice9_SetRenderState(data->device, D3DRS_LIGHTING, FALSE); */ + return 0; +} + +static int +DDRAW_DisplayModeChanged(SDL_Renderer * renderer) +{ + //TODO implement + /*D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; + SDL_Window *window = SDL_GetWindowFromID(renderer->window); + SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window); + + data->pparams.BackBufferWidth = window->w; + data->pparams.BackBufferHeight = window->h; + if (window->flags & SDL_WINDOW_FULLSCREEN) { + data->pparams.BackBufferFormat = + PixelFormatToD3DFMT(display->fullscreen_mode.format); + } else { + data->pparams.BackBufferFormat = D3DFMT_UNKNOWN; + } + return D3D_Reset(renderer); */ + return 0; +} + +static int +DDRAW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) +{ + DDRAW_RenderData *renderdata = (DDRAW_RenderData *) renderer->driverdata; + SDL_Window *window = SDL_GetWindowFromID(renderer->window); + SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window); + Uint32 display_format = display->current_mode.format; + DDRAW_TextureData *data; + DDSURFACEDESC ddsd; + HRESULT result; + + data = (DDRAW_TextureData *) SDL_calloc(1, sizeof(*data)); + if (!data) { + SDL_OutOfMemory(); + return -1; + } + + SDL_zero(ddsd); + ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_PIXELFORMAT | DDSD_HEIGHT | DDSD_WIDTH; + ddsd.dwWidth = texture->w; + ddsd.dwHeight = texture->h; + + + if (!PixelFormatToDDPIXELFORMAT(texture->format, &ddsd.ddpfPixelFormat)) { + SDL_free(data); + return -1; + } + + texture->driverdata = data; + + result = + renderdata->ddraw->lpVtbl->CreateSurface(renderdata->ddraw, &ddsd, + &data->surface, NULL); + if (result != DD_OK) { + SDL_free(data); + DDRAW_SetError("CreateTexture", result); + return -1; + } + + return 0; +} + +static int +DDRAW_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture, + void **pixels, int *pitch) +{ + //TODO implement + SDL_SetError("QueryTexturePixels is not implemented"); + return -1; +} + +static int +DDRAW_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture) +{ + return 0; +} + +static int +DDRAW_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture) +{ + return 0; +} + +static int +DDRAW_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture) +{ + switch (texture->blendMode) { + case SDL_BLENDMODE_NONE: + return 0; + default: + SDL_Unsupported(); + texture->blendMode = SDL_BLENDMODE_NONE; + return -1; + } +} + +static int +DDRAW_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture) +{ + switch (texture->scaleMode) { + case SDL_TEXTURESCALEMODE_NONE: + default: + SDL_Unsupported(); + texture->scaleMode = SDL_TEXTURESCALEMODE_NONE; + return -1; + } + return 0; +} + +static int +DDRAW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, const void *pixels, int pitch) +{ + DDRAW_TextureData *data = (DDRAW_TextureData *) texture->driverdata; + + //TODO implement + SDL_SetError("UpdateTexture is not implemented"); + return 0; +} + +static int +DDRAW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, int markDirty, void **pixels, + int *pitch) +{ + DDRAW_TextureData *data = (DDRAW_TextureData *) texture->driverdata; + HRESULT result; + DDSURFACEDESC ddsd; + + SDL_zero(ddsd); + ddsd.dwSize = sizeof(ddsd); + + /** + * On a Axim x51v locking a subrect returns the startaddress of the whole surface, + * wheras on my ASUS MyPal 696 the startaddress of the locked area is returned, + * thats why I always lock the whole surface and calculate the pixels pointer by hand. + * This shouldn't be a speed problem, as multiple locks aren't available on DDraw Mobile + * see http://msdn.microsoft.com/en-us/library/ms858221.aspx + */ + + result = data->surface->lpVtbl->Lock(data->surface, NULL, &ddsd, 0, NULL); + if (result != DD_OK) { + DDRAW_SetError("LockRect()", result); + return -1; + } + + *pixels = ddsd.lpSurface + rect->y * ddsd.lPitch + rect->x * ddsd.lXPitch; + *pitch = ddsd.lPitch; + return 0; +} + +static void +DDRAW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) +{ + DDRAW_TextureData *data = (DDRAW_TextureData *) texture->driverdata; + + data->surface->lpVtbl->Unlock(data->surface, NULL); +} + +static void +DDRAW_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, + int numrects, const SDL_Rect * rects) +{ +} + +static void +DDRAW_SetBlendMode(DDRAW_RenderData * data, int blendMode) +{ + switch (blendMode) { + + } +} + +static int +DDRAW_RenderPoint(SDL_Renderer * renderer, int x, int y) +{ + return -1; +} + +static int +DDRAW_RenderLine(SDL_Renderer * renderer, int x1, int y1, int x2, int y2) +{ + return -1; +} + +static int +DDRAW_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect) +{ + return -1; +} + +static int +DDRAW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * srcrect, const SDL_Rect * dstrect) +{ + DDRAW_RenderData *data = (DDRAW_RenderData *) renderer->driverdata; + DDRAW_TextureData *texturedata = + (DDRAW_TextureData *) texture->driverdata; + HRESULT result; + RECT srcr; + RECT dstr; + DDBLTFX bltfx; + + srcr.left = srcrect->x; + srcr.top = srcrect->y; + srcr.right = srcrect->x + srcrect->w; + srcr.bottom = srcrect->y + srcrect->h; + + dstr.left = dstrect->x; + dstr.top = dstrect->y; + dstr.right = dstrect->x + dstrect->w; + dstr.bottom = dstrect->y + dstrect->h; + + SDL_zero(bltfx); + bltfx.dwSize = sizeof(bltfx); + bltfx.dwROP = SRCCOPY; + + data->primary->lpVtbl->Blt(data->primary, &dstr, texturedata->surface, + &srcr, DDBLT_ROP, &bltfx); + + return 0; +} + +static void +DDRAW_RenderPresent(SDL_Renderer * renderer) +{ + DDRAW_RenderData *data = (DDRAW_RenderData *) renderer->driverdata; + HRESULT result; + + return; + + result = + data->primary->lpVtbl->Flip(data->primary, NULL, DDFLIP_INTERVAL1); + if (result != DD_OK) { + DDRAW_SetError("Present()", result); + } +} + +static void +DDRAW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) +{ + DDRAW_TextureData *data = (DDRAW_TextureData *) texture->driverdata; + + if (!data) { + return; + } + + data->surface->lpVtbl->Release(data->surface); + SDL_free(data); + texture->driverdata = NULL; +} + +static void +DDRAW_DestroyRenderer(SDL_Renderer * renderer) +{ + DDRAW_RenderData *data = (DDRAW_RenderData *) renderer->driverdata; + + if (data) { + data->primary->lpVtbl->Release(data->primary); + SDL_free(data); + } + SDL_free(renderer); +} + +#endif /* SDL_VIDEO_RENDER_DDRAW */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/win32/SDL_ceddrawrender.h b/src/video/win32/SDL_ceddrawrender.h new file mode 100644 index 000000000..873825e08 --- /dev/null +++ b/src/video/win32/SDL_ceddrawrender.h @@ -0,0 +1,31 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2009 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org + + Stefan Klug + klug.stefan@gmx.de +*/ +#include "SDL_config.h" + +#if SDL_VIDEO_RENDER_DDRAW +extern void DDRAW_AddRenderDriver(_THIS); +#endif + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/win32/SDL_gapirender.c b/src/video/win32/SDL_gapirender.c new file mode 100644 index 000000000..30908d034 --- /dev/null +++ b/src/video/win32/SDL_gapirender.c @@ -0,0 +1,646 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2009 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org + + Stefan Klug + klug.stefan@gmx.de +*/ +#include "SDL_config.h" + +#if SDL_VIDEO_RENDER_GAPI + +#include "SDL_win32video.h" +//#include "../SDL_sysvideo.h" +#include "../SDL_yuv_sw_c.h" +#include "../SDL_renderer_sw.h" + +#include "SDL_gapirender_c.h" + +#define GAPI_RENDERER_DEBUG 1 + +/* GAPI renderer implementation */ + +static SDL_Renderer *GAPI_CreateRenderer(SDL_Window * window, Uint32 flags); +static int GAPI_RenderPoint(SDL_Renderer * renderer, int x, int y); +static int GAPI_RenderLine(SDL_Renderer * renderer, int x1, int y1, + int x2, int y2); +static int GAPI_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect); +static int GAPI_RenderCopy(SDL_Renderer * renderer, + SDL_Texture * texture, + const SDL_Rect * srcrect, + const SDL_Rect * dstrect); +static void GAPI_RenderPresent(SDL_Renderer * renderer); +static void GAPI_DestroyRenderer(SDL_Renderer * renderer); + + +SDL_RenderDriver GAPI_RenderDriver = { + GAPI_CreateRenderer, + { + "gapi", + (SDL_RENDERER_SINGLEBUFFER), + } +}; + +static HMODULE g_hGapiLib = 0; + +// for testing with GapiEmu +#define USE_GAPI_EMU 0 +#define EMULATE_AXIM_X30 0 + +#if 0 +#define GAPI_LOG(...) printf(__VA_ARGS__) +#else +#define GAPI_LOG(...) +#endif + + +#if USE_GAPI_EMU && !REPORT_VIDEO_INFO +#pragma message("Warning: Using GapiEmu in release build. I assume you'd like to set USE_GAPI_EMU to zero.") +#endif + + +static void +GAPI_SetError(const char *prefix, HRESULT result) +{ + const char *error; + + switch (result) { + default: + error = "UNKNOWN"; + break; + } + SDL_SetError("%s: %s", prefix, error); +} + +void +GAPI_AddRenderDriver(_THIS) +{ + /* TODO: should we check for support of GetRawFramebuffer here? + */ +#if USE_GAPI_EMU + g_hGapiLib = LoadLibrary(L"GAPI_Emu.dll"); +#else + g_hGapiLib = LoadLibrary(L"\\Windows\\gx.dll"); +#endif + + if (g_hGapiLib) { +#define LINK(name,import) gx.name = (PFN##name)GetProcAddress( g_hGapiLib, L##import ); + + LINK(GXOpenDisplay, "?GXOpenDisplay@@YAHPAUHWND__@@K@Z") + LINK(GXCloseDisplay, "?GXCloseDisplay@@YAHXZ") + LINK(GXBeginDraw, "?GXBeginDraw@@YAPAXXZ") + LINK(GXEndDraw, "?GXEndDraw@@YAHXZ") + LINK(GXOpenInput, "?GXOpenInput@@YAHXZ") + LINK(GXCloseInput, "?GXCloseInput@@YAHXZ") + LINK(GXGetDisplayProperties, + "?GXGetDisplayProperties@@YA?AUGXDisplayProperties@@XZ") + LINK(GXGetDefaultKeys, "?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z") + LINK(GXSuspend, "?GXSuspend@@YAHXZ") + LINK(GXResume, "?GXResume@@YAHXZ") + LINK(GXSetViewport, "?GXSetViewport@@YAHKKKK@Z") + LINK(GXIsDisplayDRAMBuffer, "?GXIsDisplayDRAMBuffer@@YAHXZ") + + /* wrong gapi.dll */ + if (!gx.GXOpenDisplay) { + FreeLibrary(g_hGapiLib); + g_hGapiLib = 0; + } +#undef LINK + } + + SDL_AddRenderDriver(0, &GAPI_RenderDriver); +} + +typedef enum +{ + USAGE_GX_FUNCS = 0x0001, /* enable to use GXOpen/GXClose/GXBeginDraw... */ + USAGE_DATA_PTR_CONSTANT = 0x0002 /* the framebuffer is at a constant location, don't use values from GXBeginDraw() */ +} GAPI_UsageFlags; + + + +typedef struct +{ + int w; + int h; + int xPitch; /* bytes to move to go to the next pixel */ + int yPitch; /* bytes to move to go to the next line */ + int offset; /* data offset, to add to the data returned from GetFramebuffer, before processing */ + + void *data; + Uint32 usageFlags; /* these flags contain options to define screen handling and to reliably workarounds */ + + Uint32 format; /* pixel format as defined in SDL_pixels.h */ + +} GAPI_RenderData; + + +static Uint32 +GuessPixelFormatFromBpp(int bpp) +{ + switch (bpp) { + case 15: + return SDL_PIXELFORMAT_RGB555; + case 16: + return SDL_PIXELFORMAT_RGB565; + default: + return SDL_PIXELFORMAT_UNKNOWN; + break; + } +} + +static GAPI_RenderData * +FillRenderDataRawFramebuffer(SDL_Window * window) +{ + RawFrameBufferInfo rbi; + GAPI_RenderData *renderdata; + HDC hdc; + + //TODO should we use the hdc of the window? + hdc = GetDC(NULL); + int result = ExtEscape(hdc, GETRAWFRAMEBUFFER, 0, NULL, + sizeof(RawFrameBufferInfo), + (char *) &rbi); + ReleaseDC(NULL, hdc); + + if (!(result > 0)) { + return NULL; + } + + /* Asus A696 returns wrong results so we do a sanity check + See: + http://groups.google.com/group/microsoft.public.smartphone.developer/browse_thread/thread/4fde5bddd477de81 + */ + if (rbi.cxPixels <= 0 || + rbi.cyPixels <= 0 || + rbi.cxStride == 0 || rbi.cyStride == 0 || rbi.pFramePointer == 0) { + return NULL; + } + + + renderdata = (GAPI_RenderData *) SDL_calloc(1, sizeof(*renderdata)); + if (!renderdata) { + SDL_OutOfMemory(); + return NULL; + } + //Try to match the window size + //TODO add rotation support + if (rbi.cxPixels != window->w || rbi.cyPixels != window->h) { + SDL_free(renderdata); + return NULL; + } + //Check that the display uses a known display format + switch (rbi.wFormat) { + case FORMAT_565: + renderdata->format = SDL_PIXELFORMAT_RGB565; + break; + case FORMAT_555: + renderdata->format = SDL_PIXELFORMAT_RGB555; + break; + default: + //TODO we should add support for other formats + SDL_free(renderdata); + return NULL; + } + + renderdata->usageFlags = USAGE_DATA_PTR_CONSTANT; + renderdata->data = rbi.pFramePointer; + renderdata->w = rbi.cxPixels; + renderdata->h = rbi.cyPixels; + renderdata->xPitch = rbi.cxStride; + renderdata->yPitch = rbi.cyStride; + + return renderdata; + +} + + +static GAPI_RenderData * +FillRenderDataGAPI(SDL_Window * window) +{ + GAPI_RenderData *renderdata; + struct GXDisplayProperties gxdp; + int tmp; + +#ifdef _ARM_ + WCHAR oemstr[100]; +#endif + + if (!g_hGapiLib) { + return NULL; + } + + renderdata = (GAPI_RenderData *) SDL_calloc(1, sizeof(GAPI_RenderData)); + if (!renderdata) { + SDL_OutOfMemory(); + return NULL; + } + + gxdp = gx.GXGetDisplayProperties(); + renderdata->usageFlags = USAGE_GX_FUNCS; + renderdata->w = gxdp.cxWidth; + renderdata->h = gxdp.cyHeight; + renderdata->xPitch = gxdp.cbxPitch; + renderdata->yPitch = gxdp.cbyPitch; + + //Check that the display uses a known display format + if (gxdp.ffFormat & kfDirect565) { + renderdata->format = SDL_PIXELFORMAT_RGB565; + } else if (gxdp.ffFormat & kfDirect555) { + renderdata->format = SDL_PIXELFORMAT_RGB555; + } else { + renderdata->format = SDL_PIXELFORMAT_UNKNOWN; + } + + /* apply some device specific corrections */ +#ifdef _ARM_ + SystemParametersInfo(SPI_GETOEMINFO, sizeof(oemstr), oemstr, 0); + + // buggy iPaq38xx + if ((oemstr[12] == 'H') && (oemstr[13] == '3') + && (oemstr[14] == '8') + && (gxdp.cbxPitch > 0)) { + renderdata->data = (void *) 0xac0755a0; + renderdata->xPitch = -640; + renderdata->yPitch = 2; + } +#if (EMULATE_AXIM_X30 == 0) + // buggy Dell Axim X30 + if (_tcsncmp(oemstr, L"Dell Axim X30", 13) == 0) +#endif + { + GXDeviceInfo gxInfo = { 0 }; + HDC hdc = GetDC(NULL); + int result; + + gxInfo.Version = 100; + result = + ExtEscape(hdc, GETGXINFO, 0, NULL, sizeof(gxInfo), + (char *) &gxInfo); + if (result > 0) { + renderdata->usageFlags = USAGE_DATA_PTR_CONSTANT; /* no more GAPI usage from now */ + renderdata->data = gxInfo.pvFrameBuffer; + this->hidden->needUpdate = 0; + renderdata->xPitch = 2; + renderdata->yPitch = 480; + renderdata->w = gxInfo.cxWidth; + renderdata->h = gxInfo.cyHeight; + + //Check that the display uses a known display format + switch (rbi->wFormat) { + case FORMAT_565: + renderdata->format = SDL_PIXELFORMAT_RGB565; + break; + case FORMAT_555: + renderdata->format = SDL_PIXELFORMAT_RGB555; + break; + default: + //TODO we should add support for other formats + SDL_free(renderdata); + return NULL; + } + } + } +#endif + + + if (renderdata->format == SDL_PIXELFORMAT_UNKNOWN) { + SDL_SetError("Gapi Pixelformat is unknown"); + SDL_free(renderdata); + return NULL; + } + + /* Gapi always returns values in standard orientation, so we manually apply + the current orientation + */ + + DEVMODE settings; + SDL_memset(&settings, 0, sizeof(DEVMODE)); + settings.dmSize = sizeof(DEVMODE); + + settings.dmFields = DM_DISPLAYORIENTATION; + ChangeDisplaySettingsEx(NULL, &settings, NULL, CDS_TEST, NULL); + + if (settings.dmDisplayOrientation == DMDO_90) { + + tmp = renderdata->w; + renderdata->w = renderdata->h; + renderdata->h = tmp; + + tmp = renderdata->xPitch; + renderdata->xPitch = -renderdata->yPitch; + renderdata->yPitch = tmp; + + renderdata->offset = -renderdata->w * renderdata->xPitch; + + } else if (settings.dmDisplayOrientation == DMDO_180) { + + renderdata->xPitch = -renderdata->xPitch; + renderdata->yPitch = -renderdata->yPitch; + + renderdata->offset = -renderdata->h * renderdata->yPitch + - renderdata->w * renderdata->xPitch; + + } else if (settings.dmDisplayOrientation == DMDO_270) { + + tmp = renderdata->w; + renderdata->w = renderdata->h; + renderdata->h = tmp; + + tmp = renderdata->xPitch; + renderdata->xPitch = renderdata->yPitch; + renderdata->yPitch = -tmp; + + renderdata->offset = -renderdata->h * renderdata->yPitch; + + } + + if (renderdata->w != window->w || renderdata->h != window->h) { + GAPI_LOG("GAPI open failed, wrong size %i %i %i %i\n", renderdata->w, + renderdata->h, renderdata->xPitch, renderdata->yPitch); + SDL_free(renderdata); + return NULL; + } + + return renderdata; + +} + + +/* This function does the whole encapsulation of Gapi/RAWFRAMEBUFFER + it should handle all the device dependent details and fill the device INDEPENDENT + RenderData structure. + */ +GAPI_RenderData * +FillRenderData(SDL_Window * window) +{ + /* We try to match the requested window to the modes available by GAPI and RAWFRAMEBUFFER. + First RAWFRAMEBUFFER is tried, as it is the most reliable one + Look here for detailed discussions: + http://pdaphonehome.com/forums/samsung-i700/28087-just-saw.html + http://blogs.msdn.com/windowsmobile/archive/2007/08/13/have-you-migrated-to-directdraw-yet.aspx + */ + + GAPI_RenderData *res; + + res = FillRenderDataRawFramebuffer(window); + GAPI_LOG("FillRenderDataRawFramebuffer: %p\n", res); + if (res) { + return res; + } + //Now we try gapi + res = FillRenderDataGAPI(window); + GAPI_LOG("FillRenderDataGAPI: %p\n", res); + + return res; +} + +void * +GetFramebuffer() +{ + +} + + +SDL_Renderer * +GAPI_CreateRenderer(SDL_Window * window, Uint32 flags) +{ + SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window); + SDL_WindowData *windowdata = (SDL_WindowData *) window->driverdata; + SDL_DisplayMode *displayMode = &display->current_mode; + SDL_Renderer *renderer; + GAPI_RenderData *data; + int i, n; + int bpp; + Uint32 Rmask, Gmask, Bmask, Amask; + + if (!(window->flags & SDL_WINDOW_FULLSCREEN)) { + SDL_SetError("Gapi supports only fullscreen windows"); + return NULL; + } + + if (!SDL_PixelFormatEnumToMasks + (displayMode->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) { + SDL_SetError("Unknown display format"); + return NULL; + } + + renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); + if (!renderer) { + SDL_OutOfMemory(); + return NULL; + } + + data = FillRenderData(window); + if (!data) { + GAPI_DestroyRenderer(renderer); + SDL_OutOfMemory(); + return NULL; + } + + renderer->RenderPoint = GAPI_RenderPoint; + renderer->RenderLine = GAPI_RenderLine; + renderer->RenderFill = GAPI_RenderFill; + renderer->RenderCopy = GAPI_RenderCopy; + renderer->RenderPresent = GAPI_RenderPresent; + renderer->DestroyRenderer = GAPI_DestroyRenderer; + renderer->info.name = GAPI_RenderDriver.info.name; + renderer->info.flags = 0; + renderer->window = window->id; + renderer->driverdata = data; + + /* Gapi provides only a framebuffer so lets use software implementation */ + Setup_SoftwareRenderer(renderer); + +#ifdef GAPI_RENDERER_DEBUG + printf("Created gapi renderer\n"); + printf("use GX functions: %i\n", data->usageFlags & USAGE_GX_FUNCS); + printf("framebuffer is constant: %i\n", + data->usageFlags & USAGE_DATA_PTR_CONSTANT); + printf("w: %i h: %i\n", data->w, data->h); + printf("data ptr: %p\n", data->data); /* this can be 0 in case of GAPI usage */ + printf("xPitch: %i\n", data->xPitch); + printf("yPitch: %i\n", data->yPitch); + printf("offset: %i\n", data->offset); + printf("format: %x\n", data->format); +#endif + + if (data->usageFlags & USAGE_GX_FUNCS) { + if (gx.GXOpenDisplay(windowdata->hwnd, GX_FULLSCREEN) == 0) { + GAPI_DestroyRenderer(renderer); + return NULL; + } + } + + return renderer; +} + +static int +GAPI_RenderPoint(SDL_Renderer * renderer, int x, int y) +{ + //TODO implement + return -1; +} + +static int +GAPI_RenderLine(SDL_Renderer * renderer, int x1, int y1, int x2, int y2) +{ + //TODO implement + return -11; +} + +static int +GAPI_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect) +{ + //TODO implement + return -1; +} + +/* Video memory is very slow so lets optimize as much as possible */ +static void +updateLine16to16(char *src, int srcXPitch, int srcYPitch, + char *dst, int dstXPitch, int dstYPitch, int width, + int height) +{ + char *srcLine, *dstLine; + char *srcPix, *dstPix; + + int x, y; + + //First dumb solution + if (srcXPitch == 2 && dstXPitch == 2) { + srcLine = src; + dstLine = dst; + y = height; + while (y--) { + SDL_memcpy(dstLine, srcLine, width * sizeof(Uint16)); + srcLine += srcYPitch; + dstLine += dstYPitch; + } + } else { + //printf("GAPI uses slow blit path %i, %i\n", dstXPitch, dstYPitch); + srcLine = src; + dstLine = dst; + y = height; + while (y--) { + srcPix = srcLine; + dstPix = dstLine; + x = width; + while (x--) { + *((Uint16 *) dstPix) = *((Uint16 *) srcPix); + dstPix += dstXPitch; + srcPix += srcXPitch; + } + srcLine += srcYPitch; + dstLine += dstYPitch; + } + } +} + +static int +GAPI_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * srcrect, const SDL_Rect * dstrect) +{ + GAPI_RenderData *data = (GAPI_RenderData *) renderer->driverdata; + int bpp; + int bytespp; + int status; + Uint32 Rmask, Gmask, Bmask, Amask; + + if (texture->format != data->format) { + SDL_SetError("Gapi got wrong texture"); + return -1; + } + + GAPI_LOG("GAPI_RenderCopy\n"); + + if (data->usageFlags & USAGE_GX_FUNCS) { + char *buffer; + buffer = gx.GXBeginDraw(); + if (!(data->usageFlags & USAGE_DATA_PTR_CONSTANT)) { + data->data = buffer; + } + } + + GAPI_LOG("GAPI_RenderCopy blit\n"); + /* If our framebuffer has an xPitch which matches the pixelsize, we + can convert the framebuffer to a SDL_surface and blit there, + otherwise, we have to use our own blitting routine + */ + SDL_PixelFormatEnumToMasks(data->format, &bpp, &Rmask, &Gmask, &Bmask, + &Amask); + bytespp = bpp >> 3; + if (data->xPitch == bytespp && 0) { + SDL_Surface *screen = + SDL_CreateRGBSurfaceFrom(data->data, data->w, data->h, + bpp, data->yPitch, Rmask, Gmask, Bmask, + Amask); + status = + SDL_UpperBlit((SDL_Surface *) texture->driverdata, srcrect, + screen, dstrect); + SDL_FreeSurface(screen); + } else { /* screen is rotated, we have to blit on our own */ + SDL_Surface *surface = (SDL_Surface *) texture->driverdata; + + char *src, *dst; + src = surface->pixels; + src += srcrect->y * surface->pitch + srcrect->x * 2; + + dst = data->data + data->offset; + dst += dstrect->y * data->yPitch + dstrect->x * data->xPitch; + + updateLine16to16(src, 2, surface->pitch, + dst, data->xPitch, data->yPitch, + srcrect->w, srcrect->h); + + } + + Uint32 ticks = SDL_GetTicks(); + if (data->usageFlags & USAGE_GX_FUNCS) { + gx.GXEndDraw(); + } + GAPI_LOG("GAPI_RenderCopy %i\n", SDL_GetTicks() - ticks); + return status; +} + +static void +GAPI_RenderPresent(SDL_Renderer * renderer) +{ + /* Nothing todo as we rendered directly to the screen on RenderCopy */ +} + +static void +GAPI_DestroyRenderer(SDL_Renderer * renderer) +{ + GAPI_RenderData *data = (GAPI_RenderData *) renderer->driverdata; + + if (data->usageFlags & USAGE_GX_FUNCS) { + gx.GXCloseDisplay(); + } + + if (data) { + SDL_free(data); + } + SDL_free(renderer); +} + +#endif /* SDL_VIDEO_RENDER_GAPI */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/win32/SDL_gapirender.h b/src/video/win32/SDL_gapirender.h new file mode 100644 index 000000000..b517a5151 --- /dev/null +++ b/src/video/win32/SDL_gapirender.h @@ -0,0 +1,33 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2009 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org + + Stefan Klug + klug.stefan@gmx.de +*/ +#include "SDL_config.h" + +/* SDL surface based renderer implementation */ + +#if SDL_VIDEO_RENDER_GAPI +extern void GAPI_AddRenderDriver(_THIS); +#endif + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/win32/SDL_gapirender_c.h b/src/video/win32/SDL_gapirender_c.h new file mode 100644 index 000000000..25dff6739 --- /dev/null +++ b/src/video/win32/SDL_gapirender_c.h @@ -0,0 +1,121 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2009 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org + + Stefan Klug + klug.stefan@gmx.de +*/ + +#define WIN32_LEAN_AND_MEAN +#include + +/* hi res definitions */ +typedef struct _RawFrameBufferInfo +{ + WORD wFormat; + WORD wBPP; + VOID *pFramePointer; + int cxStride; + int cyStride; + int cxPixels; + int cyPixels; +} RawFrameBufferInfo; + +#define GETRAWFRAMEBUFFER 0x00020001 + +#define FORMAT_565 1 +#define FORMAT_555 2 +#define FORMAT_OTHER 3 + + +/* From gx.h, since it's not really C compliant */ + +struct GXDisplayProperties +{ + DWORD cxWidth; + DWORD cyHeight; // notice lack of 'th' in the word height. + long cbxPitch; // number of bytes to move right one x pixel - can be negative. + long cbyPitch; // number of bytes to move down one y pixel - can be negative. + long cBPP; // # of bits in each pixel + DWORD ffFormat; // format flags. +}; + +struct GXKeyList +{ + short vkUp; // key for up + POINT ptUp; // x,y position of key/button. Not on screen but in screen coordinates. + short vkDown; + POINT ptDown; + short vkLeft; + POINT ptLeft; + short vkRight; + POINT ptRight; + short vkA; + POINT ptA; + short vkB; + POINT ptB; + short vkC; + POINT ptC; + short vkStart; + POINT ptStart; +}; + +typedef int (*PFNGXOpenDisplay) (HWND hWnd, DWORD dwFlags); +typedef int (*PFNGXCloseDisplay) (); +typedef void *(*PFNGXBeginDraw) (); +typedef int (*PFNGXEndDraw) (); +typedef int (*PFNGXOpenInput) (); +typedef int (*PFNGXCloseInput) (); +typedef struct GXDisplayProperties (*PFNGXGetDisplayProperties) (); +typedef struct GXKeyList (*PFNGXGetDefaultKeys) (int iOptions); +typedef int (*PFNGXSuspend) (); +typedef int (*PFNGXResume) (); +typedef int (*PFNGXSetViewport) (DWORD dwTop, DWORD dwHeight, + DWORD dwReserved1, DWORD dwReserved2); +typedef BOOL(*PFNGXIsDisplayDRAMBuffer) (); + +struct GapiFunc +{ + PFNGXOpenDisplay GXOpenDisplay; + PFNGXCloseDisplay GXCloseDisplay; + PFNGXBeginDraw GXBeginDraw; + PFNGXEndDraw GXEndDraw; + PFNGXOpenInput GXOpenInput; + PFNGXCloseInput GXCloseInput; + PFNGXGetDisplayProperties GXGetDisplayProperties; + PFNGXGetDefaultKeys GXGetDefaultKeys; + PFNGXSuspend GXSuspend; + PFNGXResume GXResume; + PFNGXSetViewport GXSetViewport; + PFNGXIsDisplayDRAMBuffer GXIsDisplayDRAMBuffer; +} gx; + +#define kfLandscape 0x8 // Screen is rotated 270 degrees +#define kfPalette 0x10 // Pixel values are indexes into a palette +#define kfDirect 0x20 // Pixel values contain actual level information +#define kfDirect555 0x40 // 5 bits each for red, green and blue values in a pixel. +#define kfDirect565 0x80 // 5 red bits, 6 green bits and 5 blue bits per pixel +#define kfDirect888 0x100 // 8 bits each for red, green and blue values in a pixel. +#define kfDirect444 0x200 // 4 red, 4 green, 4 blue +#define kfDirectInverted 0x400 + +#define GX_FULLSCREEN 0x01 // for OpenDisplay() +#define GX_NORMALKEYS 0x02 +#define GX_LANDSCAPEKEYS 0x03 diff --git a/src/video/win32/SDL_win32events.c b/src/video/win32/SDL_win32events.c index c38da64d4..4c301602c 100644 --- a/src/video/win32/SDL_win32events.c +++ b/src/video/win32/SDL_win32events.c @@ -473,6 +473,7 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) int x, y; int w, h; int style; + BOOL menu; /* If we allow resizing, let the resize happen naturally */ if (SDL_GetWindowFlags(data->windowID) & SDL_WINDOW_RESIZABLE) { @@ -491,15 +492,19 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) size.bottom = h; size.right = w; + + style = GetWindowLong(hwnd, GWL_STYLE); +#ifdef _WIN32_WCE + menu = FALSE; +#else /* DJM - according to the docs for GetMenu(), the return value is undefined if hwnd is a child window. Aparently it's too difficult for MS to check inside their function, so I have to do it here. */ - style = GetWindowLong(hwnd, GWL_STYLE); - AdjustWindowRect(&size, style, - style & WS_CHILDWINDOW ? FALSE : GetMenu(hwnd) - != NULL); + menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL); +#endif + AdjustWindowRectEx(&size, style, menu, 0); w = size.right - size.left; h = size.bottom - size.top; diff --git a/src/video/win32/SDL_win32video.c b/src/video/win32/SDL_win32video.c index 22e574262..28f60f28d 100644 --- a/src/video/win32/SDL_win32video.c +++ b/src/video/win32/SDL_win32video.c @@ -59,6 +59,12 @@ WIN_DeleteDevice(SDL_VideoDevice * device) IDirect3D9_Release(data->d3d); FreeLibrary(data->d3dDLL); } +#endif +#if SDL_VIDEO_RENDER_DDRAW + if (data->ddraw) { + data->ddraw->lpVtbl->Release(data->ddraw); + FreeLibrary(data->ddrawDLL); + } #endif if (data->wintabDLL) { FreeLibrary(data->wintabDLL); @@ -106,6 +112,24 @@ WIN_CreateDevice(int devindex) } } #endif /* SDL_VIDEO_RENDER_D3D */ +#if SDL_VIDEO_RENDER_DDRAW + data->ddrawDLL = LoadLibrary(TEXT("ddraw.dll")); + if (data->ddrawDLL) { + IDirectDraw *(WINAPI * DDCreate) (GUID FAR * lpGUID, + LPDIRECTDRAW FAR * lplpDD, + IUnknown FAR * pUnkOuter); + + DDCreate = + (IDirectDraw * + (WINAPI *) (GUID FAR *, LPDIRECTDRAW FAR *, IUnknown FAR *)) + GetProcAddress(data->ddrawDLL, TEXT("DirectDrawCreate")); + if (!DDCreate || DDCreate(NULL, &data->ddraw, NULL) != DD_OK) { + FreeLibrary(data->ddrawDLL); + data->ddrawDLL = NULL; + data->ddraw = NULL; + } + } +#endif /* SDL_VIDEO_RENDER_DDRAW */ data->wintabDLL = LoadLibrary(TEXT("WINTAB32.DLL")); if (data->wintabDLL) { @@ -188,9 +212,15 @@ WIN_VideoInit(_THIS) #if SDL_VIDEO_RENDER_D3D D3D_AddRenderDriver(_this); #endif +#if SDL_VIDEO_RENDER_DDRAW + DDRAW_AddRenderDriver(_this); +#endif #if SDL_VIDEO_RENDER_GDI GDI_AddRenderDriver(_this); #endif +#if SDL_VIDEO_RENDER_GAPI + GAPI_AddRenderDriver(_this); +#endif g_hCtx = SDL_malloc(sizeof(HCTX)); WIN_InitKeyboard(_this); diff --git a/src/video/win32/SDL_win32video.h b/src/video/win32/SDL_win32video.h index eb6f56241..9454193c4 100644 --- a/src/video/win32/SDL_win32video.h +++ b/src/video/win32/SDL_win32video.h @@ -37,6 +37,12 @@ #include "d3d9.h" #endif +#if SDL_VIDEO_RENDER_DDRAW +/* WIN32_LEAN_AND_MEAN was defined, so we have to include this by hand */ +#include +#include "ddraw.h" +#endif + #include "wactab/wintab.h" #define PACKETDATA ( PK_X | PK_Y | PK_BUTTONS | PK_NORMAL_PRESSURE | PK_CURSOR) #define PACKETMODE 0 @@ -66,6 +72,11 @@ typedef struct SDL_VideoData HANDLE d3dDLL; IDirect3D9 *d3d; #endif +#if SDL_VIDEO_RENDER_DDRAW + HANDLE ddrawDLL; + IDirectDraw *ddraw; +#endif + /* *INDENT-OFF* */ /* Function pointers for the Wacom API */ HANDLE wintabDLL; diff --git a/src/video/win32/SDL_win32window.c b/src/video/win32/SDL_win32window.c index cec704886..a8e40b49a 100644 --- a/src/video/win32/SDL_win32window.c +++ b/src/video/win32/SDL_win32window.c @@ -38,6 +38,41 @@ /* This is included after SDL_win32video.h, which includes windows.h */ #include "SDL_syswm.h" + +#define SHFS_SHOWTASKBAR 0x0001 +#define SHFS_HIDETASKBAR 0x0002 +#define SHFS_SHOWSIPBUTTON 0x0004 +#define SHFS_HIDESIPBUTTON 0x0008 +#define SHFS_SHOWSTARTICON 0x0010 +#define SHFS_HIDESTARTICON 0x0020 + +#ifdef _WIN32_WCE +// dynamically load aygshell dll because we want SDL to work on HPC and be300 +int aygshell_loaded = 0; +BOOL(WINAPI * SHFullScreen) (HWND hwndRequester, DWORD dwState) = 0; + + +static BOOL +CE_SHFullScreen(HWND hwndRequester, DWORD dwState) +{ + if (SHFullScreen == 0 && aygshell_loaded == 0) { + aygshell_loaded = 0; + void *lib = SDL_LoadObject("aygshell.dll"); + if (lib) { + SHFullScreen = + (BOOL(WINAPI *) (HWND, DWORD)) SDL_LoadFunction(lib, + "SHFullScreen"); + } + } + + if (SHFullScreen) { + SHFullScreen(hwndRequester, dwState); + //printf("SHFullscreen(%i)\n",dwState); + } +} + +#endif + extern HCTX *g_hCtx; /* the table of tablet event contexts, each windows has to have it's own tablet context */ static Uint32 highestId = 0; /* the highest id of the tablet context */ @@ -385,6 +420,7 @@ WIN_SetWindowPosition(_THIS, SDL_Window * window) RECT rect; DWORD style; HWND top; + BOOL menu; int x, y; /* Figure out what the window area will be */ @@ -398,9 +434,12 @@ WIN_SetWindowPosition(_THIS, SDL_Window * window) rect.top = 0; rect.right = window->w; rect.bottom = window->h; - AdjustWindowRectEx(&rect, style, - (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != - NULL), 0); +#ifdef _WIN32_WCE + menu = FALSE; +#else + menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL); +#endif + AdjustWindowRectEx(&rect, style, menu, 0); if ((window->flags & SDL_WINDOW_FULLSCREEN) || window->x == SDL_WINDOWPOS_CENTERED) { @@ -425,6 +464,7 @@ WIN_SetWindowSize(_THIS, SDL_Window * window) RECT rect; DWORD style; HWND top; + BOOL menu; int w, h; /* Figure out what the window area will be */ @@ -438,9 +478,12 @@ WIN_SetWindowSize(_THIS, SDL_Window * window) rect.top = 0; rect.right = window->w; rect.bottom = window->h; - AdjustWindowRectEx(&rect, style, - (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != - NULL), 0); +#ifdef _WIN32_WCE + menu = FALSE; +#else + menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL); +#endif + AdjustWindowRectEx(&rect, style, menu, 0); w = (rect.right - rect.left); h = (rect.bottom - rect.top); @@ -453,6 +496,14 @@ WIN_ShowWindow(_THIS, SDL_Window * window) HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; ShowWindow(hwnd, SW_SHOW); + +#ifdef _WIN32_WCE + if (window->flags & SDL_WINDOW_FULLSCREEN) { + CE_SHFullScreen(hwnd, + SHFS_HIDESTARTICON | SHFS_HIDETASKBAR | + SHFS_HIDESIPBUTTON); + } +#endif } void @@ -461,6 +512,14 @@ WIN_HideWindow(_THIS, SDL_Window * window) HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; ShowWindow(hwnd, SW_HIDE); + +#ifdef _WIN32_WCE + if (window->flags & SDL_WINDOW_FULLSCREEN) { + CE_SHFullScreen(hwnd, + SHFS_SHOWSTARTICON | SHFS_SHOWTASKBAR | + SHFS_SHOWSIPBUTTON); + } +#endif } void @@ -475,6 +534,14 @@ WIN_RaiseWindow(_THIS, SDL_Window * window) top = HWND_NOTOPMOST; } SetWindowPos(hwnd, top, 0, 0, 0, 0, (SWP_NOMOVE | SWP_NOSIZE)); + +#ifdef _WIN32_WCE + if (window->flags & SDL_WINDOW_FULLSCREEN) { + CE_SHFullScreen(hwnd, + SHFS_HIDESTARTICON | SHFS_HIDETASKBAR | + SHFS_HIDESIPBUTTON); + } +#endif } void @@ -483,6 +550,14 @@ WIN_MaximizeWindow(_THIS, SDL_Window * window) HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; ShowWindow(hwnd, SW_MAXIMIZE); + +#ifdef _WIN32_WCE + if (window->flags & SDL_WINDOW_FULLSCREEN) { + CE_SHFullScreen(hwnd, + SHFS_HIDESTARTICON | SHFS_HIDETASKBAR | + SHFS_HIDESIPBUTTON); + } +#endif } void @@ -491,6 +566,14 @@ WIN_MinimizeWindow(_THIS, SDL_Window * window) HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; ShowWindow(hwnd, SW_MINIMIZE); + +#ifdef _WIN32_WCE + if (window->flags & SDL_WINDOW_FULLSCREEN) { + CE_SHFullScreen(hwnd, + SHFS_SHOWSTARTICON | SHFS_SHOWTASKBAR | + SHFS_SHOWSIPBUTTON); + } +#endif } void @@ -579,12 +662,18 @@ SDL_HelperWindowCreate(void) return -1; } + HWND hWndParent = NULL; +#ifndef _WIN32_WCE + /* WinCE doesn't have HWND_MESSAGE */ + hWndParent = HWND_MESSAGE; +#endif + /* Create the window. */ SDL_HelperWindow = CreateWindowEx(0, SDL_HelperWindowClassName, SDL_HelperWindowName, - WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, + WS_OVERLAPPED, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, HWND_MESSAGE, NULL, + CW_USEDEFAULT, hWndParent, NULL, hInstance, NULL); if (SDL_HelperWindow == NULL) { UnregisterClass(SDL_HelperWindowClassName, hInstance);