/* 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 */ #include "SDL_config.h" /* Pocket PC GAPI SDL video driver implementation; Implemented by Dmitry Yakimov - support@activekitten.com Inspired by http://arisme.free.fr/ports/SDL.php */ // TODO: copy surface on window when lost focus // TODO: test buttons rotation // TODO: test on be300 and HPC ( check WinDib fullscreen keys catching ) // TODO: test on smartphones // TODO: windib on SH3 PPC2000 landscape test // TODO: optimize 8bpp landscape mode // there is some problems in runnings apps from a device landscape mode // due to WinCE bugs. Some works and some - does not. // TODO: finish Axim Dell X30 and user landscape mode, device landscape mode // TODO: finish Axim Dell X30 user portrait, device landscape stylus conversion // TODO: fix running GAPI apps from landscape mode - // wince goes to portrait mode, but does not update video memory #include "SDL_error.h" #include "SDL_video.h" #include "SDL_mouse.h" #include "../SDL_sysvideo.h" #include "../SDL_pixels_c.h" #include "../../events/SDL_events_c.h" #include "../wincommon/SDL_syswm_c.h" #include "../wincommon/SDL_sysmouse_c.h" #include "../windib/SDL_dibevents_c.h" #include "SDL_gapivideo.h" #define GAPIVID_DRIVER_NAME "gapi" #if defined(DEBUG) || defined (_DEBUG) || defined(NDEBUG) #define REPORT_VIDEO_INFO 1 #else #define REPORT_VIDEO_INFO 0 #endif // for testing with GapiEmu #define USE_GAPI_EMU 0 #define EMULATE_AXIM_X30 0 #define WITHOUT_GAPI 0 #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 // defined and used in SDL_sysevents.c extern HINSTANCE aygshell; extern void SDL_UnregisterApp(); extern int DIB_AddMode(_THIS, int bpp, int w, int h); /* Initialization/Query functions */ static int GAPI_VideoInit(_THIS, SDL_PixelFormat * vformat); static SDL_Rect **GAPI_ListModes(_THIS, SDL_PixelFormat * format, Uint32 flags); static SDL_Surface *GAPI_SetVideoMode(_THIS, SDL_Surface * current, int width, int height, int bpp, Uint32 flags); static int GAPI_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color * colors); static void GAPI_VideoQuit(_THIS); /* Hardware surface functions */ static int GAPI_AllocHWSurface(_THIS, SDL_Surface * surface); static int GAPI_LockHWSurface(_THIS, SDL_Surface * surface); static void GAPI_UnlockHWSurface(_THIS, SDL_Surface * surface); static void GAPI_FreeHWSurface(_THIS, SDL_Surface * surface); /* Windows message handling functions, will not be processed */ static void GAPI_RealizePalette(_THIS); static void GAPI_PaletteChanged(_THIS, HWND window); static void GAPI_WinPAINT(_THIS, HDC hdc); /* etc. */ static void GAPI_UpdateRects(_THIS, int numrects, SDL_Rect * rects); static HMODULE g_hGapiLib = 0; #define LINK(type,name,import) \ if( g_hGapiLib ) \ name = (PFN##type)GetProcAddress( g_hGapiLib, _T(import) ); static char g_bRawBufferAvailable = 0; /* GAPI driver bootstrap functions */ /* hi res definitions */ typedef struct _RawFrameBufferInfo { WORD wFormat; WORD wBPP; VOID *pFramePointer; int cxStride; int cyStride; int cxPixels; int cyPixels; } RawFrameBufferInfo; static struct _RawFrameBufferInfo g_RawFrameBufferInfo = { 0 }; #define GETRAWFRAMEBUFFER 0x00020001 #define FORMAT_565 1 #define FORMAT_555 2 #define FORMAT_OTHER 3 /* Dell Axim x30 hangs when we use GAPI from landscape, so lets avoid using GxOpenDisplay there via GETGXINFO trick It seems that GAPI subsystem use the same ExtEscape code. */ #define GETGXINFO 0x00020000 typedef struct GXDeviceInfo { long Version; //00 (should filled with 100 before calling ExtEscape) void *pvFrameBuffer; //04 unsigned long cbStride; //08 unsigned long cxWidth; //0c unsigned long cyHeight; //10 unsigned long cBPP; //14 unsigned long ffFormat; //18 char Unused[0x84 - 7 * 4]; } GXDeviceInfo; static int GAPI_Available(void) { // try to use VGA display, even on emulator HDC hdc = GetDC(NULL); int result = ExtEscape(hdc, GETRAWFRAMEBUFFER, 0, NULL, sizeof(RawFrameBufferInfo), (char *) &g_RawFrameBufferInfo); ReleaseDC(NULL, hdc); g_bRawBufferAvailable = result > 0; #if WITHOUT_GAPI return g_bRawBufferAvailable; #endif #if USE_GAPI_EMU g_hGapiLib = LoadLibrary(_T("GAPI_Emu.dll")); if (!g_hGapiLib) { SDL_SetError("Gapi Emu not found!"); } return g_hGapiLib != 0; #endif // try to find gx.dll g_hGapiLib = LoadLibrary(_T("\\Windows\\gx.dll")); if (!g_hGapiLib) { g_hGapiLib = LoadLibrary(_T("gx.dll")); if (!g_hGapiLib) return g_bRawBufferAvailable; } return (1); } static int cmpmodes(const void *va, const void *vb) { SDL_Rect *a = *(SDL_Rect **) va; SDL_Rect *b = *(SDL_Rect **) vb; if (a->w == b->w) return b->h - a->h; else return b->w - a->w; } static int GAPI_AddMode(_THIS, int bpp, int w, int h) { SDL_Rect *mode; int i, index; int next_mode; /* Check to see if we already have this mode */ if (bpp < 8) { /* Not supported */ return (0); } index = ((bpp + 7) / 8) - 1; for (i = 0; i < gapi->SDL_nummodes[index]; ++i) { mode = gapi->SDL_modelist[index][i]; if ((mode->w == w) && (mode->h == h)) { return (0); } } /* Set up the new video mode rectangle */ mode = (SDL_Rect *) SDL_malloc(sizeof *mode); if (mode == NULL) { SDL_OutOfMemory(); return (-1); } mode->x = 0; mode->y = 0; mode->w = w; mode->h = h; /* Allocate the new list of modes, and fill in the new mode */ next_mode = gapi->SDL_nummodes[index]; gapi->SDL_modelist[index] = (SDL_Rect **) SDL_realloc(gapi->SDL_modelist[index], (1 + next_mode + 1) * sizeof(SDL_Rect *)); if (gapi->SDL_modelist[index] == NULL) { SDL_OutOfMemory(); gapi->SDL_nummodes[index] = 0; SDL_free(mode); return (-1); } gapi->SDL_modelist[index][next_mode] = mode; gapi->SDL_modelist[index][next_mode + 1] = NULL; gapi->SDL_nummodes[index]++; return (0); } static void GAPI_DeleteDevice(SDL_VideoDevice * device) { if (g_hGapiLib) { FreeLibrary(g_hGapiLib); g_hGapiLib = 0; } SDL_free(device->hidden); SDL_free(device); } static SDL_VideoDevice * GAPI_CreateDevice(int devindex) { SDL_VideoDevice *device; if (!g_hGapiLib && !g_bRawBufferAvailable) { if (!GAPI_Available()) { SDL_SetError ("GAPI dll is not found and VGA mode is not available!"); return 0; } } /* Initialize all variables that we clean on shutdown */ device = (SDL_VideoDevice *) SDL_malloc(sizeof(SDL_VideoDevice)); if (device) { SDL_memset(device, 0, (sizeof *device)); device->hidden = (struct SDL_PrivateVideoData *) SDL_malloc((sizeof *device->hidden)); } if ((device == NULL) || (device->hidden == NULL)) { SDL_OutOfMemory(); if (device) { SDL_free(device); } return (0); } SDL_memset(device->hidden, 0, (sizeof *device->hidden)); /* Set the function pointers */ device->VideoInit = GAPI_VideoInit; device->ListModes = GAPI_ListModes; device->SetVideoMode = GAPI_SetVideoMode; device->UpdateMouse = WIN_UpdateMouse; device->CreateYUVOverlay = NULL; device->SetColors = GAPI_SetColors; device->UpdateRects = GAPI_UpdateRects; device->VideoQuit = GAPI_VideoQuit; device->AllocHWSurface = GAPI_AllocHWSurface; device->CheckHWBlit = NULL; device->FillHWRect = NULL; device->SetHWColorKey = NULL; device->SetHWAlpha = NULL; device->LockHWSurface = GAPI_LockHWSurface; device->UnlockHWSurface = GAPI_UnlockHWSurface; device->FlipHWSurface = NULL; device->FreeHWSurface = GAPI_FreeHWSurface; device->SetCaption = WIN_SetWMCaption; device->SetIcon = WIN_SetWMIcon; device->IconifyWindow = WIN_IconifyWindow; device->GrabInput = WIN_GrabInput; device->GetWMInfo = WIN_GetWMInfo; device->FreeWMCursor = WIN_FreeWMCursor; device->CreateWMCursor = WIN_CreateWMCursor; device->ShowWMCursor = WIN_ShowWMCursor; device->WarpWMCursor = WIN_WarpWMCursor; device->CheckMouseMode = WIN_CheckMouseMode; device->InitOSKeymap = DIB_InitOSKeymap; device->PumpEvents = DIB_PumpEvents; /* Set up the windows message handling functions */ WIN_RealizePalette = GAPI_RealizePalette; WIN_PaletteChanged = GAPI_PaletteChanged; WIN_WinPAINT = GAPI_WinPAINT; HandleMessage = DIB_HandleMessage; device->free = GAPI_DeleteDevice; /* Load gapi library */ #define gx device->hidden->gxFunc LINK(GXOpenDisplay, gx.GXOpenDisplay, "?GXOpenDisplay@@YAHPAUHWND__@@K@Z") LINK(GXCloseDisplay, gx.GXCloseDisplay, "?GXCloseDisplay@@YAHXZ") LINK(GXBeginDraw, gx.GXBeginDraw, "?GXBeginDraw@@YAPAXXZ") LINK(GXEndDraw, gx.GXEndDraw, "?GXEndDraw@@YAHXZ") LINK(GXOpenInput, gx.GXOpenInput, "?GXOpenInput@@YAHXZ") LINK(GXCloseInput, gx.GXCloseInput, "?GXCloseInput@@YAHXZ") LINK(GXGetDisplayProperties, gx.GXGetDisplayProperties, "?GXGetDisplayProperties@@YA?AUGXDisplayProperties@@XZ") LINK(GXGetDefaultKeys, gx.GXGetDefaultKeys, "?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z") LINK(GXSuspend, gx.GXSuspend, "?GXSuspend@@YAHXZ") LINK(GXResume, gx.GXResume, "?GXResume@@YAHXZ") LINK(GXSetViewport, gx.GXSetViewport, "?GXSetViewport@@YAHKKKK@Z") LINK(GXIsDisplayDRAMBuffer, gx.GXIsDisplayDRAMBuffer, "?GXIsDisplayDRAMBuffer@@YAHXZ") /* wrong gapi.dll */ if (!gx.GXOpenDisplay) { if (g_hGapiLib) { FreeLibrary(g_hGapiLib); g_hGapiLib = 0; } } if (!gx.GXOpenDisplay && !g_bRawBufferAvailable) { SDL_SetError("Error: damaged or unknown gapi.dll!\n"); GAPI_DeleteDevice(device); return 0; } return device; } VideoBootStrap GAPI_bootstrap = { GAPIVID_DRIVER_NAME, "WinCE GAPI video driver", GAPI_Available, GAPI_CreateDevice }; static void FillStructs(_THIS, BOOL useVga) { #ifdef _ARM_ WCHAR oemstr[100]; #endif /* fill a device properties */ if (!useVga) { this->hidden->gxProperties = this->hidden->gxFunc.GXGetDisplayProperties(); this->hidden->needUpdate = 1; this->hidden->hiresFix = 0; this->hidden->useVga = 0; this->hidden->useGXOpenDisplay = 1; #ifdef _ARM_ /* check some devices and extract addition info */ SystemParametersInfo(SPI_GETOEMINFO, sizeof(oemstr), oemstr, 0); // buggy iPaq38xx if ((oemstr[12] == 'H') && (oemstr[13] == '3') && (oemstr[14] == '8') && (this->hidden->gxProperties.cbxPitch > 0)) { this->hidden->videoMem = (PIXEL *) 0xac0755a0; this->hidden->gxProperties.cbxPitch = -640; this->hidden->gxProperties.cbyPitch = 2; this->hidden->needUpdate = 0; } #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) { this->hidden->useGXOpenDisplay = 0; this->hidden->videoMem = gxInfo.pvFrameBuffer; this->hidden->needUpdate = 0; this->hidden->gxProperties.cbxPitch = 2; this->hidden->gxProperties.cbyPitch = 480; this->hidden->gxProperties.cxWidth = gxInfo.cxWidth; this->hidden->gxProperties.cyHeight = gxInfo.cyHeight; this->hidden->gxProperties.ffFormat = gxInfo.ffFormat; } } #endif } else { this->hidden->needUpdate = 0; this->hidden->hiresFix = 0; this->hidden->gxProperties.cBPP = g_RawFrameBufferInfo.wBPP; this->hidden->gxProperties.cbxPitch = g_RawFrameBufferInfo.cxStride; this->hidden->gxProperties.cbyPitch = g_RawFrameBufferInfo.cyStride; this->hidden->gxProperties.cxWidth = g_RawFrameBufferInfo.cxPixels; this->hidden->gxProperties.cyHeight = g_RawFrameBufferInfo.cyPixels; this->hidden->videoMem = g_RawFrameBufferInfo.pFramePointer; this->hidden->useVga = 1; switch (g_RawFrameBufferInfo.wFormat) { case FORMAT_565: this->hidden->gxProperties.ffFormat = kfDirect565; break; case FORMAT_555: this->hidden->gxProperties.ffFormat = kfDirect555; break; default: /* unknown pixel format, try define by BPP! */ switch (g_RawFrameBufferInfo.wBPP) { case 4: case 8: this->hidden->gxProperties.ffFormat = kfDirect; case 16: this->hidden->gxProperties.ffFormat = kfDirect565; default: this->hidden->gxProperties.ffFormat = kfDirect; break; } } } if (this->hidden->gxProperties.cBPP != 16) { this->hidden->gapiOrientation = SDL_ORIENTATION_UP; } else if ((this->hidden->gxProperties.cbxPitch > 0) && (this->hidden->gxProperties.cbyPitch > 0)) { this->hidden->gapiOrientation = SDL_ORIENTATION_UP; } else if ((this->hidden->gxProperties.cbxPitch > 0) && (this->hidden->gxProperties.cbyPitch < 0)) { this->hidden->gapiOrientation = SDL_ORIENTATION_RIGHT; // ipaq 3660 } else if ((this->hidden->gxProperties.cbxPitch < 0) && (this->hidden->gxProperties.cbyPitch > 0)) { this->hidden->gapiOrientation = SDL_ORIENTATION_LEFT; // ipaq 3800 } } static void GAPI_CreatePalette(int ncolors, SDL_Color * colors) { // Setup a custom color palette BYTE buffer[sizeof(LOGPALETTE) + 255 * sizeof(PALETTEENTRY)]; int i; LOGPALETTE *pLogical = (LOGPALETTE *) buffer; PALETTEENTRY *entries = pLogical->palPalEntry; HPALETTE hPalette; HDC hdc; for (i = 0; i < ncolors; ++i) { // Find intensity by replicating the bit patterns over a byte entries[i].peRed = colors[i].r; entries[i].peGreen = colors[i].g; entries[i].peBlue = colors[i].b; entries[i].peFlags = 0; } // Create the GDI palette object pLogical->palVersion = 0x0300; pLogical->palNumEntries = ncolors; hPalette = CreatePalette(pLogical); ASSERT(hPalette); // Realize the palette hdc = GetDC(0); SelectPalette(hdc, hPalette, FALSE); RealizePalette(hdc); ReleaseDC(0, hdc); DeleteObject(hPalette); } int GAPI_VideoInit(_THIS, SDL_PixelFormat * vformat) { int i, bpp; /* Create the window */ if (DIB_CreateWindow(this) < 0) { return (-1); } if (g_hGapiLib) { FillStructs(this, 0); // SDL does not supports 2/4bpp mode, so use 16 bpp bpp = gapi->gxProperties.cBPP < 8 ? 16 : gapi->gxProperties.cBPP; /* set up normal and landscape mode */ GAPI_AddMode(this, bpp, gapi->gxProperties.cyHeight, gapi->gxProperties.cxWidth); GAPI_AddMode(this, bpp, gapi->gxProperties.cxWidth, gapi->gxProperties.cyHeight); } /* add hi-res mode */ if (g_bRawBufferAvailable && !((gapi->gxProperties.cxWidth == (unsigned) g_RawFrameBufferInfo.cxPixels) && (gapi->gxProperties.cyHeight == (unsigned) g_RawFrameBufferInfo.cyPixels))) { FillStructs(this, 1); // SDL does not supports 2/4bpp mode, so use 16 bpp bpp = gapi->gxProperties.cBPP < 8 ? 16 : gapi->gxProperties.cBPP; /* set up normal and landscape mode */ GAPI_AddMode(this, bpp, gapi->gxProperties.cyHeight, gapi->gxProperties.cxWidth); GAPI_AddMode(this, bpp, gapi->gxProperties.cxWidth, gapi->gxProperties.cyHeight); } /* Determine the current screen size */ this->info.current_w = gapi->gxProperties.cxWidth; this->info.current_h = gapi->gxProperties.cyHeight; /* Sort the mode lists */ for (i = 0; i < NUM_MODELISTS; ++i) { if (gapi->SDL_nummodes[i] > 0) { SDL_qsort(gapi->SDL_modelist[i], gapi->SDL_nummodes[i], sizeof *gapi->SDL_modelist[i], cmpmodes); } } vformat->BitsPerPixel = this->hidden->gxProperties.cBPP < 8 ? 16 : (unsigned char) this->hidden->gxProperties.cBPP; // Get color mask if (this->hidden->gxProperties.ffFormat & kfDirect565) { vformat->BitsPerPixel = 16; vformat->Rmask = 0x0000f800; vformat->Gmask = 0x000007e0; vformat->Bmask = 0x0000001f; this->hidden->videoMode = GAPI_DIRECT_565; } else if (this->hidden->gxProperties.ffFormat & kfDirect555) { vformat->BitsPerPixel = 16; vformat->Rmask = 0x00007c00; vformat->Gmask = 0x000003e0; vformat->Bmask = 0x0000001f; this->hidden->videoMode = GAPI_DIRECT_555; } else if ((this->hidden->gxProperties.ffFormat & kfDirect) && (this->hidden->gxProperties.cBPP < 8)) { // We'll perform the conversion vformat->BitsPerPixel = 16; vformat->Rmask = 0x0000f800; // 16 bit 565 vformat->Gmask = 0x000007e0; vformat->Bmask = 0x0000001f; if (this->hidden->gxProperties.ffFormat & kfDirectInverted) this->hidden->invert = (1 << this->hidden->gxProperties.cBPP) - 1; this->hidden->colorscale = this->hidden->gxProperties.cBPP < 8 ? 8 - this->hidden->gxProperties.cBPP : 0; this->hidden->videoMode = GAPI_MONO; } else if (this->hidden->gxProperties.ffFormat & kfPalette) { this->hidden->videoMode = GAPI_PALETTE; } /* We're done! */ return (0); } SDL_Rect ** GAPI_ListModes(_THIS, SDL_PixelFormat * format, Uint32 flags) { return (this->hidden->SDL_modelist[((format->BitsPerPixel + 7) / 8) - 1]); // return (SDL_Rect **) -1; } SDL_Surface * GAPI_SetVideoMode(_THIS, SDL_Surface * current, int width, int height, int bpp, Uint32 flags) { SDL_Surface *video; Uint32 Rmask, Gmask, Bmask; DWORD style; SDL_Rect allScreen; if (bpp < 4) { SDL_SetError("1 bpp and 2 bpp modes is not implemented yet!"); return 0; } /* Recalculate bitmasks if necessary */ if (bpp == current->format->BitsPerPixel) { video = current; } else { switch (bpp) { case 8: Rmask = 0; Gmask = 0; Bmask = 0; break; case 15: case 16: /* Default is 565 unless the display is specifically 555 */ if (this->hidden->gxProperties.ffFormat & kfDirect555) { Rmask = 0x00007c00; Gmask = 0x000003e0; Bmask = 0x0000001f; } else { Rmask = 0x0000f800; Gmask = 0x000007e0; Bmask = 0x0000001f; } break; case 24: case 32: Rmask = 0x00ff0000; Gmask = 0x0000ff00; Bmask = 0x000000ff; break; default: SDL_SetError("Unsupported Bits Per Pixel format requested"); return NULL; } video = SDL_CreateRGBSurface(SDL_SWSURFACE, 0, 0, bpp, Rmask, Gmask, Bmask, 0); if (video == NULL) { SDL_OutOfMemory(); return (NULL); } } gapi->userOrientation = SDL_ORIENTATION_UP; video->flags = SDL_FULLSCREEN; /* Clear flags, GAPI supports fullscreen only */ /* GAPI or VGA? */ if (g_hGapiLib) { FillStructs(this, 0); if ((((unsigned) width != gapi->gxProperties.cxWidth) || ((unsigned) height != gapi->gxProperties.cyHeight)) && (((unsigned) width != gapi->gxProperties.cyHeight) || ((unsigned) height != gapi->gxProperties.cxWidth))) FillStructs(this, 1); // gapi is found but we use VGA resolution } else FillStructs(this, 1); if (!this->hidden->needUpdate && !this->hidden->videoMem) { SDL_SetError ("Couldn't get address of video memory, may be unsupported device or bug"); return (NULL); } /* detect user landscape mode */ if ((width > height) && (GetSystemMetrics(SM_CXSCREEN) < GetSystemMetrics(SM_CYSCREEN))) gapi->userOrientation = SDL_ORIENTATION_RIGHT; /* shall we apply hires fix? for example when we do not use hires resource */ gapi->hiresFix = 0; if (gapi->userOrientation == SDL_ORIENTATION_RIGHT) { if ((width > GetSystemMetrics(SM_CYSCREEN)) || (height > GetSystemMetrics(SM_CXSCREEN))) gapi->hiresFix = 1; } else if ((width > GetSystemMetrics(SM_CXSCREEN)) || (height > GetSystemMetrics(SM_CYSCREEN))) if (!((width == GetSystemMetrics(SM_CYSCREEN)) && (height == GetSystemMetrics(SM_CXSCREEN)))) // user portrait, device landscape gapi->hiresFix = 1; switch (gapi->userOrientation) { case SDL_ORIENTATION_UP: gapi->startOffset = 0; gapi->dstLineStep = gapi->gxProperties.cbyPitch; gapi->dstPixelStep = gapi->gxProperties.cbxPitch; break; case SDL_ORIENTATION_RIGHT: switch (gapi->gapiOrientation) { case SDL_ORIENTATION_UP: case SDL_ORIENTATION_RIGHT: case SDL_ORIENTATION_LEFT: if ((this->hidden->videoMode == GAPI_MONO)) gapi->startOffset = -gapi->gxProperties.cbxPitch + 1; // monochrome mode else gapi->startOffset = gapi->gxProperties.cbyPitch * (gapi->gxProperties.cyHeight - 1); gapi->dstLineStep = gapi->gxProperties.cbxPitch; gapi->dstPixelStep = -gapi->gxProperties.cbyPitch; break; } } video->w = this->hidden->w = width; video->h = this->hidden->h = height; video->pitch = SDL_CalculatePitch(video); /* Small fix for WinCE/Win32 - when activating window SDL_VideoSurface is equal to zero, so activating code is not called properly for fullscreen windows because macros WINDIB_FULLSCREEN uses SDL_VideoSurface */ SDL_VideoSurface = video; /* GAPI is always fullscreen, title bar is useless */ style = 0; if (!SDL_windowid) SetWindowLong(SDL_Window, GWL_STYLE, style); /* Allocate bitmap */ if (gapiBuffer) { SDL_free(gapiBuffer); gapiBuffer = NULL; } gapiBuffer = SDL_malloc(video->h * video->pitch); video->pixels = gapiBuffer; if (!this->hidden->buffer) { SDL_SetError("Couldn't allocate buffer for requested mode"); return (NULL); } SDL_memset(gapiBuffer, 255, video->h * video->pitch); MoveWindow(SDL_Window, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), FALSE); ShowWindow(SDL_Window, SW_SHOW); SetForegroundWindow(SDL_Window); /* JC 14 Mar 2006 Flush the message loop or this can cause big problems later Especially if the user decides to use dialog boxes or assert()! */ WIN_FlushMessageQueue(); /* Open GAPI display */ if (!gapi->useVga && this->hidden->useGXOpenDisplay) if (!gapi->gxFunc.GXOpenDisplay(SDL_Window, GX_FULLSCREEN)) { SDL_SetError("Couldn't initialize GAPI"); return (NULL); } #if REPORT_VIDEO_INFO printf("Video properties:\n"); printf("display bpp: %d\n", gapi->gxProperties.cBPP); printf("display width: %d\n", gapi->gxProperties.cxWidth); printf("display height: %d\n", gapi->gxProperties.cyHeight); printf("x pitch: %d\n", gapi->gxProperties.cbxPitch); printf("y pitch: %d\n", gapi->gxProperties.cbyPitch); printf("gapi flags: 0x%x\n", gapi->gxProperties.ffFormat); if (!gapi->useVga && this->hidden->useGXOpenDisplay && gapi->needUpdate) { gapi->videoMem = gapi->gxFunc.GXBeginDraw(); gapi->gxFunc.GXEndDraw(); } printf("video memory: 0x%x\n", gapi->videoMem); printf("need update: %d\n", gapi->needUpdate); printf("hi-res fix: %d\n", gapi->hiresFix); printf("VGA is available on the device: %d\n", g_bRawBufferAvailable); printf("use raw framebuffer: %d\n", gapi->useVga); printf("video surface bpp: %d\n", video->format->BitsPerPixel); printf("video surface width: %d\n", video->w); printf("video surface height: %d\n", video->h); #endif /* Blank screen */ allScreen.x = allScreen.y = 0; allScreen.w = video->w - 1; allScreen.h = video->h - 1; GAPI_UpdateRects(this, 1, &allScreen); /* We're done */ return (video); } /* We don't actually allow hardware surfaces other than the main one */ static int GAPI_AllocHWSurface(_THIS, SDL_Surface * surface) { return (-1); } static void GAPI_FreeHWSurface(_THIS, SDL_Surface * surface) { return; } /* We need to wait for vertical retrace on page flipped displays */ static int GAPI_LockHWSurface(_THIS, SDL_Surface * surface) { return (0); } static void GAPI_UnlockHWSurface(_THIS, SDL_Surface * surface) { return; } static int updateLine8to8(_THIS, unsigned char *srcPointer, unsigned char *destPointer, int width, int height, int lines) { if (gapi->dstPixelStep == 1) { /* optimized blitting on most devices */ SDL_memcpy(destPointer, srcPointer, width); return 1; } else { // TODO: read 4 pixels, write DWORD int step = gapi->dstPixelStep; while (width--) { *destPointer = *srcPointer++; destPointer += step; } } return 1; } /* Video memory is very slow so lets optimize as much as possible */ static int updateLine16to16(_THIS, PIXEL * srcPointer, PIXEL * destPointer, int width, int height, int lines) { PIXEL *line1, *line2; int step = gapi->dstPixelStep / 2; if (step == 1) { /* optimized blitting on most devices */ SDL_memcpy(destPointer, srcPointer, width * sizeof(PIXEL)); return 1; } else { if ((gapi->gapiOrientation != SDL_ORIENTATION_UP) && (gapi->userOrientation == SDL_ORIENTATION_UP)) // iPaq 3660/3800 and user orientation up { // to prevent data misalignment copy only one line if (((((unsigned) destPointer & 3) != 0) && (gapi->gapiOrientation == SDL_ORIENTATION_LEFT)) || ((((unsigned) destPointer & 3) == 0) && (gapi->gapiOrientation != SDL_ORIENTATION_LEFT)) || (lines == 1)) { while (width--) { *destPointer = *srcPointer++; destPointer += step; } return 1; } /* read two lines at the same time, write DWORD */ line1 = srcPointer; line2 = srcPointer + SDL_VideoSurface->pitch / 2; if (gapi->gapiOrientation == SDL_ORIENTATION_LEFT) while (width--) // iPaq 3800 { *(DWORD *) destPointer = (*line2++ << 16) | *line1++; destPointer += step; } else { destPointer += gapi->gxProperties.cbyPitch / 2; while (width--) // iPaq 3660 { *(DWORD *) destPointer = (*line1++ << 16) | *line2++; destPointer += step; } } return 2; } else { // iPaq 3800 and user orientation landscape if (gapi->gapiOrientation == SDL_ORIENTATION_LEFT) { int w1; // to prevent data misalignment copy only one pixel if ((((unsigned) destPointer & 3) == 0) && (width > 0)) { *destPointer-- = *srcPointer++; width--; } destPointer--; w1 = width / 2; while (w1--) { DWORD p = *(DWORD *) srcPointer; *((DWORD *) destPointer) = (p << 16) | (p >> 16); destPointer -= 2; srcPointer += 2; } if (width & 1) // copy the last pixel { destPointer++; *destPointer = *srcPointer; } return 1; } // modern iPaqs and user orientation landscape // read two pixels, write DWORD line1 = srcPointer; line2 = srcPointer + SDL_VideoSurface->pitch / 2; if ((((unsigned) destPointer & 3) != 0) || (lines == 1)) { while (width--) { *destPointer = *srcPointer++; destPointer += step; } return 1; } while (width--) { *(DWORD *) destPointer = (*line2++ << 16) | *line1++; destPointer -= gapi->gxProperties.cbyPitch / 2; } return 2; } } } // Color component masks for 565 #define REDMASK (31<<11) #define GREENMASK (63<<5) #define BLUEMASK (31) static int updateLine16to4(_THIS, PIXEL * srcPointer, unsigned char *destPointer, int width, int height, int lines, int yNibble, int xNibble) { PIXEL *line1, *line2; int step = gapi->dstPixelStep; if (gapi->userOrientation == SDL_ORIENTATION_UP) { if (yNibble) // copy bottom half of a line { while (width--) { PIXEL c1 = *srcPointer++; c1 = ((c1 & REDMASK) >> 11) + ((c1 & GREENMASK) >> 5) + (c1 & BLUEMASK); *destPointer = (*destPointer & 0x0F) | ((~(c1 >> 3) << 4)); destPointer += step; } return 1; } // either 1 pixel picture or tail, anyway this is the last line if (lines == 1) { while (width--) { PIXEL c1 = *srcPointer++; c1 = ((c1 & REDMASK) >> 11) + ((c1 & GREENMASK) >> 5) + (c1 & BLUEMASK); *destPointer = (*destPointer & 0xF0) | ((~(c1 >> 3) & 0xF)); destPointer += step; } return 1; } line1 = srcPointer; line2 = srcPointer + SDL_VideoSurface->pitch / 2; while (width--) { PIXEL c1 = *line1++; PIXEL c2 = *line2++; c1 = ((c1 & REDMASK) >> 11) + ((c1 & GREENMASK) >> 5) + (c1 & BLUEMASK); c2 = ((c2 & REDMASK) >> 11) + ((c2 & GREENMASK) >> 5) + (c2 & BLUEMASK); *destPointer = ~((c1 >> 3) + ((c2 >> 3) << 4)); destPointer += step; } return 2; } else { int w1; w1 = width / 2; if (xNibble) { // copy one pixel PIXEL c1 = *srcPointer++; c1 = ((c1 & REDMASK) >> 11) + ((c1 & GREENMASK) >> 5) + (c1 & BLUEMASK); *destPointer = (*destPointer & 0xF0) | ((~(c1 >> 3) & 0xF)); destPointer++; } while (w1--) { PIXEL c1 = *srcPointer; PIXEL c2 = *(srcPointer + 1); c1 = ((c1 & REDMASK) >> 11) + ((c1 & GREENMASK) >> 5) + (c1 & BLUEMASK); c2 = ((c2 & REDMASK) >> 11) + ((c2 & GREENMASK) >> 5) + (c2 & BLUEMASK); *destPointer++ = ~((c2 >> 3) + ((c1 >> 3) << 4)); srcPointer += 2; } // copy tail if ((width & 1) && !xNibble) { PIXEL c1 = *srcPointer; c1 = ((c1 & REDMASK) >> 11) + ((c1 & GREENMASK) >> 5) + (c1 & BLUEMASK); *destPointer = (*destPointer & 0x0F) | ((~(c1 >> 3) << 4)); } return 1; } } static void GAPI_UpdateRectsMono(_THIS, int numrects, SDL_Rect * rects) { int i, height; int linesProcessed; int xNibble, yNibble; for (i = 0; i < numrects; i++) { unsigned char *destPointer; unsigned char *srcPointer; if (gapi->userOrientation == SDL_ORIENTATION_UP) destPointer = (unsigned char *) gapi->videoMem + gapi->startOffset - rects[i].y * gapi->gxProperties.cBPP / 8 + rects[i].x * gapi->dstPixelStep; else destPointer = (unsigned char *) gapi->videoMem + gapi->startOffset + rects[i].x * gapi->gxProperties.cBPP / 8 + rects[i].y * gapi->dstLineStep; srcPointer = ((unsigned char *) SDL_VideoSurface->pixels) + rects[i].y * SDL_VideoSurface->pitch + rects[i].x * 2; yNibble = rects[i].y & 1; // TODO: only for 4 bpp xNibble = rects[i].x & 1; height = rects[i].h; while (height > 0) { switch (gapi->gxProperties.cBPP) { case 2: // TODO case 4: linesProcessed = updateLine16to4(this, (PIXEL *) srcPointer, destPointer, rects[i].w, rects[i].h, height, yNibble, xNibble); yNibble = 0; } height -= linesProcessed; if (gapi->userOrientation == SDL_ORIENTATION_UP) destPointer--; // always fill 1 byte else destPointer += gapi->dstLineStep; srcPointer += SDL_VideoSurface->pitch * linesProcessed; // pitch in bytes } } } static void GAPI_UpdateRectsColor(_THIS, int numrects, SDL_Rect * rects) { int i, height; int bytesPerPixel = (gapi->gxProperties.cBPP + 1) / 8; int linesProcessed; for (i = 0; i < numrects; i++) { unsigned char *destPointer = (unsigned char *) gapi->videoMem + gapi->startOffset + rects[i].y * gapi->dstLineStep + rects[i].x * gapi->dstPixelStep; unsigned char *srcPointer = ((unsigned char *) SDL_VideoSurface->pixels) + rects[i].y * SDL_VideoSurface->pitch + rects[i].x * bytesPerPixel; height = rects[i].h; // fprintf(stderr, "Starting rect %dx%d, dst=0x%x, w = %d, h = %d\n", rects[i].w, rects[i].h,destPointer,rects[i].w,rects[i].h); // fflush(stderr); linesProcessed = height; while (height > 0) { switch (bytesPerPixel) { case 1: linesProcessed = updateLine8to8(this, srcPointer, (unsigned char *) destPointer, rects[i].w, rects[i].h, height); break; case 2: #pragma warning(disable: 4133) linesProcessed = updateLine16to16(this, (PIXEL *) srcPointer, destPointer, rects[i].w, rects[i].h, height); break; } height -= linesProcessed; destPointer += gapi->dstLineStep * linesProcessed; srcPointer += SDL_VideoSurface->pitch * linesProcessed; // pitch in bytes } // fprintf(stderr, "End of rect\n"); // fflush(stderr); } } static void GAPI_UpdateRects(_THIS, int numrects, SDL_Rect * rects) { // we do not want to corrupt video memory if (gapi->suspended) return; if (gapi->needUpdate) gapi->videoMem = gapi->gxFunc.GXBeginDraw(); if (gapi->gxProperties.cBPP < 8) GAPI_UpdateRectsMono(this, numrects, rects); else GAPI_UpdateRectsColor(this, numrects, rects); if (gapi->needUpdate) gapi->gxFunc.GXEndDraw(); } /* Note: If we are terminated, this could be called in the middle of another SDL video routine -- notably UpdateRects. */ void GAPI_VideoQuit(_THIS) { int i, j; /* Destroy the window and everything associated with it */ if (SDL_Window) { if ((g_hGapiLib != 0) && this && this->hidden && this->hidden->gxFunc.GXCloseDisplay && !this->hidden->useVga) this->hidden->gxFunc.GXCloseDisplay(); if (this->screen->pixels != NULL) { SDL_free(this->screen->pixels); this->screen->pixels = NULL; } if (screen_icn) { DestroyIcon(screen_icn); screen_icn = NULL; } DIB_DestroyWindow(this); SDL_UnregisterApp(); SDL_Window = NULL; #if defined(_WIN32_WCE) // Unload wince aygshell library to prevent leak if (aygshell) { FreeLibrary(aygshell); aygshell = NULL; } #endif /* Free video mode lists */ for (i = 0; i < NUM_MODELISTS; ++i) { if (gapi->SDL_modelist[i] != NULL) { for (j = 0; gapi->SDL_modelist[i][j]; ++j) SDL_free(gapi->SDL_modelist[i][j]); SDL_free(gapi->SDL_modelist[i]); gapi->SDL_modelist[i] = NULL; } } } } static void GAPI_RealizePalette(_THIS) { OutputDebugString(TEXT("GAPI_RealizePalette NOT IMPLEMENTED !\r\n")); } static void GAPI_PaletteChanged(_THIS, HWND window) { OutputDebugString(TEXT("GAPI_PaletteChanged NOT IMPLEMENTED !\r\n")); } static void GAPI_WinPAINT(_THIS, HDC hdc) { // draw current offscreen buffer on hdc int bpp = 16; // we always use either 8 or 16 bpp internally unsigned short *bitmapData; HBITMAP hb; HDC srcDC; // Create a DIB BYTE buffer[sizeof(BITMAPINFOHEADER) + 3 * sizeof(RGBQUAD)] = { 0 }; BITMAPINFO *pBMI = (BITMAPINFO *) buffer; BITMAPINFOHEADER *pHeader = &pBMI->bmiHeader; DWORD *pColors = (DWORD *) & pBMI->bmiColors; // CreateDIBSection does not support 332 pixel format on wce if (gapi->gxProperties.cBPP == 8) return; // DIB Header pHeader->biSize = sizeof(BITMAPINFOHEADER); pHeader->biWidth = this->hidden->w; pHeader->biHeight = -this->hidden->h; pHeader->biPlanes = 1; pHeader->biBitCount = bpp; pHeader->biCompression = BI_RGB; pHeader->biSizeImage = (this->hidden->w * this->hidden->h * bpp) / 8; // Color masks if (bpp == 16) { pColors[0] = REDMASK; pColors[1] = GREENMASK; pColors[2] = BLUEMASK; pHeader->biCompression = BI_BITFIELDS; } // Create the DIB hb = CreateDIBSection(0, pBMI, DIB_RGB_COLORS, (void **) &bitmapData, 0, 0); // copy data // FIXME: prevent misalignment, but I've never seen non aligned width of screen memcpy(bitmapData, this->hidden->buffer, pHeader->biSizeImage); srcDC = CreateCompatibleDC(hdc); SelectObject(srcDC, hb); BitBlt(hdc, 0, 0, this->hidden->w, this->hidden->h, srcDC, 0, 0, SRCCOPY); DeleteObject(hb); DeleteDC(srcDC); } int GAPI_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color * colors) { GAPI_CreatePalette(ncolors, colors); return 1; } /* vi: set ts=4 sw=4 expandtab: */