Home | History | Annotate | Download | only in gapi
      1 /*
      2     SDL - Simple DirectMedia Layer
      3     Copyright (C) 1997-2006 Sam Lantinga
      4 
      5     This library is free software; you can redistribute it and/or
      6     modify it under the terms of the GNU Lesser General Public
      7     License as published by the Free Software Foundation; either
      8     version 2.1 of the License, or (at your option) any later version.
      9 
     10     This library is distributed in the hope that it will be useful,
     11     but WITHOUT ANY WARRANTY; without even the implied warranty of
     12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13     Lesser General Public License for more details.
     14 
     15     You should have received a copy of the GNU Lesser General Public
     16     License along with this library; if not, write to the Free Software
     17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     18 
     19     Sam Lantinga
     20     slouken (at) libsdl.org
     21 */
     22 #include "SDL_config.h"
     23 
     24 /* Pocket PC GAPI SDL video driver implementation;
     25 Implemented by Dmitry Yakimov - support (at) activekitten.com
     26 Inspired by http://arisme.free.fr/ports/SDL.php
     27 */
     28 
     29 // TODO: copy surface on window when lost focus
     30 // TODO: test buttons rotation
     31 // TODO: test on be300 and HPC ( check WinDib fullscreen keys catching )
     32 // TODO: test on smartphones
     33 // TODO: windib on SH3 PPC2000 landscape test
     34 // TODO: optimize 8bpp landscape mode
     35 
     36 // there is some problems in runnings apps from a device landscape mode
     37 // due to WinCE bugs. Some works and some - does not.
     38 // TODO: finish Axim Dell X30 and user landscape mode, device landscape mode
     39 // TODO: finish Axim Dell X30 user portrait, device landscape stylus conversion
     40 // TODO: fix running GAPI apps from landscape mode -
     41 //       wince goes to portrait mode, but does not update video memory
     42 
     43 
     44 #include "SDL.h"
     45 #include "SDL_error.h"
     46 #include "SDL_video.h"
     47 #include "SDL_mouse.h"
     48 #include "../SDL_sysvideo.h"
     49 #include "../SDL_pixels_c.h"
     50 #include "../../events/SDL_events_c.h"
     51 #include "../wincommon/SDL_syswm_c.h"
     52 #include "../wincommon/SDL_sysmouse_c.h"
     53 #include "../windib/SDL_dibevents_c.h"
     54 
     55 #include "SDL_gapivideo.h"
     56 
     57 #define GAPIVID_DRIVER_NAME "gapi"
     58 
     59 #if defined(DEBUG) || defined (_DEBUG) || defined(NDEBUG)
     60 #define REPORT_VIDEO_INFO 1
     61 #else
     62 #define REPORT_VIDEO_INFO 0
     63 #endif
     64 
     65 // for testing with GapiEmu
     66 #define USE_GAPI_EMU 0
     67 #define EMULATE_AXIM_X30 0
     68 #define WITHOUT_GAPI 0
     69 
     70 #if USE_GAPI_EMU && !REPORT_VIDEO_INFO
     71 #pragma message("Warning: Using GapiEmu in release build. I assume you'd like to set USE_GAPI_EMU to zero.")
     72 #endif
     73 
     74 // defined and used in SDL_sysevents.c
     75 extern HINSTANCE aygshell;
     76 extern void SDL_UnregisterApp();
     77 extern int DIB_AddMode(_THIS, int bpp, int w, int h);
     78 
     79 /* Initialization/Query functions */
     80 static int GAPI_VideoInit(_THIS, SDL_PixelFormat *vformat);
     81 static SDL_Rect **GAPI_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
     82 static SDL_Surface *GAPI_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
     83 static int GAPI_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors);
     84 static void GAPI_VideoQuit(_THIS);
     85 
     86 /* Hardware surface functions */
     87 static int GAPI_AllocHWSurface(_THIS, SDL_Surface *surface);
     88 static int GAPI_LockHWSurface(_THIS, SDL_Surface *surface);
     89 static void GAPI_UnlockHWSurface(_THIS, SDL_Surface *surface);
     90 static void GAPI_FreeHWSurface(_THIS, SDL_Surface *surface);
     91 
     92 /* Windows message handling functions, will not be processed */
     93 static void GAPI_RealizePalette(_THIS);
     94 static void GAPI_PaletteChanged(_THIS, HWND window);
     95 static void GAPI_WinPAINT(_THIS, HDC hdc);
     96 
     97 /* etc. */
     98 static void GAPI_UpdateRects(_THIS, int numrects, SDL_Rect *rects);
     99 
    100 static HMODULE g_hGapiLib = 0;
    101 #define LINK(type,name,import) \
    102 	if( g_hGapiLib ) \
    103 		name = (PFN##type)GetProcAddress( g_hGapiLib, _T(import) );
    104 
    105 static char g_bRawBufferAvailable = 0;
    106 
    107 /* GAPI driver bootstrap functions */
    108 
    109 /* hi res definitions */
    110 typedef struct _RawFrameBufferInfo
    111 {
    112    WORD wFormat;
    113    WORD wBPP;
    114    VOID *pFramePointer;
    115    int  cxStride;
    116    int  cyStride;
    117    int  cxPixels;
    118    int  cyPixels;
    119 } RawFrameBufferInfo;
    120 
    121 static struct _RawFrameBufferInfo g_RawFrameBufferInfo = {0};
    122 
    123 #define GETRAWFRAMEBUFFER   0x00020001
    124 
    125 #define FORMAT_565 1
    126 #define FORMAT_555 2
    127 #define FORMAT_OTHER 3
    128 
    129 /* Dell Axim x30 hangs when we use GAPI from landscape,
    130    so lets avoid using GxOpenDisplay there via GETGXINFO trick
    131    It seems that GAPI subsystem use the same ExtEscape code.
    132 */
    133 #define GETGXINFO 0x00020000
    134 
    135 typedef struct GXDeviceInfo
    136 {
    137 long Version; //00 (should filled with 100 before calling ExtEscape)
    138 void * pvFrameBuffer; //04
    139 unsigned long cbStride; //08
    140 unsigned long cxWidth; //0c
    141 unsigned long cyHeight; //10
    142 unsigned long cBPP; //14
    143 unsigned long ffFormat; //18
    144 char Unused[0x84-7*4];
    145 } GXDeviceInfo;
    146 
    147 static int GAPI_Available(void)
    148 {
    149 	// try to use VGA display, even on emulator
    150 	HDC hdc = GetDC(NULL);
    151 	int result = ExtEscape(hdc, GETRAWFRAMEBUFFER, 0, NULL, sizeof(RawFrameBufferInfo), (char *)&g_RawFrameBufferInfo);
    152 	ReleaseDC(NULL, hdc);
    153 	g_bRawBufferAvailable = result > 0;
    154 
    155 #if WITHOUT_GAPI
    156 	return g_bRawBufferAvailable;
    157 #endif
    158 
    159 #if USE_GAPI_EMU
    160 	g_hGapiLib = LoadLibrary(_T("GAPI_Emu.dll"));
    161 	if( !g_hGapiLib )
    162 	{
    163 		SDL_SetError("Gapi Emu not found!");
    164 	}
    165 	return g_hGapiLib != 0;
    166 #endif
    167 
    168 	// try to find gx.dll
    169 	g_hGapiLib = LoadLibrary(_T("\\Windows\\gx.dll"));
    170 	if( !g_hGapiLib )
    171 	{
    172 		g_hGapiLib = LoadLibrary(_T("gx.dll"));
    173 		if( !g_hGapiLib ) return g_bRawBufferAvailable;
    174 	}
    175 
    176 	return(1);
    177 }
    178 
    179 static int cmpmodes(const void *va, const void *vb)
    180 {
    181     SDL_Rect *a = *(SDL_Rect **)va;
    182     SDL_Rect *b = *(SDL_Rect **)vb;
    183     if ( a->w == b->w )
    184         return b->h - a->h;
    185     else
    186         return b->w - a->w;
    187 }
    188 
    189 static int GAPI_AddMode(_THIS, int bpp, int w, int h)
    190 {
    191 	SDL_Rect *mode;
    192 	int i, index;
    193 	int next_mode;
    194 
    195 	/* Check to see if we already have this mode */
    196 	if ( bpp < 8 ) {  /* Not supported */
    197 		return(0);
    198 	}
    199 	index = ((bpp+7)/8)-1;
    200 	for ( i=0; i<gapi->SDL_nummodes[index]; ++i ) {
    201 		mode = gapi->SDL_modelist[index][i];
    202 		if ( (mode->w == w) && (mode->h == h) ) {
    203 			return(0);
    204 		}
    205 	}
    206 
    207 	/* Set up the new video mode rectangle */
    208 	mode = (SDL_Rect *)SDL_malloc(sizeof *mode);
    209 	if ( mode == NULL ) {
    210 		SDL_OutOfMemory();
    211 		return(-1);
    212 	}
    213 	mode->x = 0;
    214 	mode->y = 0;
    215 	mode->w = w;
    216 	mode->h = h;
    217 
    218 	/* Allocate the new list of modes, and fill in the new mode */
    219 	next_mode = gapi->SDL_nummodes[index];
    220 	gapi->SDL_modelist[index] = (SDL_Rect **)
    221 	       SDL_realloc(gapi->SDL_modelist[index], (1+next_mode+1)*sizeof(SDL_Rect *));
    222 	if ( gapi->SDL_modelist[index] == NULL ) {
    223 		SDL_OutOfMemory();
    224 		gapi->SDL_nummodes[index] = 0;
    225 		SDL_free(mode);
    226 		return(-1);
    227 	}
    228 	gapi->SDL_modelist[index][next_mode] = mode;
    229 	gapi->SDL_modelist[index][next_mode+1] = NULL;
    230 	gapi->SDL_nummodes[index]++;
    231 
    232 	return(0);
    233 }
    234 
    235 static void GAPI_DeleteDevice(SDL_VideoDevice *device)
    236 {
    237 	if( g_hGapiLib )
    238 	{
    239 		FreeLibrary(g_hGapiLib);
    240 		g_hGapiLib = 0;
    241 	}
    242 	SDL_free(device->hidden);
    243 	SDL_free(device);
    244 }
    245 
    246 static SDL_VideoDevice *GAPI_CreateDevice(int devindex)
    247 {
    248 	SDL_VideoDevice *device;
    249 
    250 	if( !g_hGapiLib && !g_bRawBufferAvailable)
    251 	{
    252 		if( !GAPI_Available() )
    253 		{
    254 			SDL_SetError("GAPI dll is not found and VGA mode is not available!");
    255 			return 0;
    256 		}
    257 	}
    258 
    259 	/* Initialize all variables that we clean on shutdown */
    260 	device = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice));
    261 	if ( device ) {
    262 		SDL_memset(device, 0, (sizeof *device));
    263 		device->hidden = (struct SDL_PrivateVideoData *)
    264 				SDL_malloc((sizeof *device->hidden));
    265 	}
    266 	if ( (device == NULL) || (device->hidden == NULL) ) {
    267 		SDL_OutOfMemory();
    268 		if ( device ) {
    269 			SDL_free(device);
    270 		}
    271 		return(0);
    272 	}
    273 	SDL_memset(device->hidden, 0, (sizeof *device->hidden));
    274 
    275 	/* Set the function pointers */
    276 	device->VideoInit = GAPI_VideoInit;
    277 	device->ListModes = GAPI_ListModes;
    278 	device->SetVideoMode = GAPI_SetVideoMode;
    279 	device->UpdateMouse = WIN_UpdateMouse;
    280 	device->CreateYUVOverlay = NULL;
    281 	device->SetColors = GAPI_SetColors;
    282 	device->UpdateRects = GAPI_UpdateRects;
    283 	device->VideoQuit = GAPI_VideoQuit;
    284 	device->AllocHWSurface = GAPI_AllocHWSurface;
    285 	device->CheckHWBlit = NULL;
    286 	device->FillHWRect = NULL;
    287 	device->SetHWColorKey = NULL;
    288 	device->SetHWAlpha = NULL;
    289 	device->LockHWSurface = GAPI_LockHWSurface;
    290 	device->UnlockHWSurface = GAPI_UnlockHWSurface;
    291 	device->FlipHWSurface = NULL;
    292 	device->FreeHWSurface = GAPI_FreeHWSurface;
    293 	device->SetCaption = WIN_SetWMCaption;
    294 	device->SetIcon = WIN_SetWMIcon;
    295 	device->IconifyWindow = WIN_IconifyWindow;
    296 	device->GrabInput = WIN_GrabInput;
    297 	device->GetWMInfo = WIN_GetWMInfo;
    298 	device->FreeWMCursor = WIN_FreeWMCursor;
    299 	device->CreateWMCursor = WIN_CreateWMCursor;
    300 	device->ShowWMCursor = WIN_ShowWMCursor;
    301 	device->WarpWMCursor = WIN_WarpWMCursor;
    302     device->CheckMouseMode = WIN_CheckMouseMode;
    303 	device->InitOSKeymap = DIB_InitOSKeymap;
    304 	device->PumpEvents = DIB_PumpEvents;
    305 
    306 	/* Set up the windows message handling functions */
    307 	WIN_RealizePalette = GAPI_RealizePalette;
    308 	WIN_PaletteChanged = GAPI_PaletteChanged;
    309 	WIN_WinPAINT = GAPI_WinPAINT;
    310 	HandleMessage = DIB_HandleMessage;
    311 
    312 	device->free = GAPI_DeleteDevice;
    313 
    314 	/* Load gapi library */
    315 #define gx device->hidden->gxFunc
    316 
    317     LINK( GXOpenDisplay, gx.GXOpenDisplay,         "?GXOpenDisplay@@YAHPAUHWND__@@K@Z" )
    318     LINK( GXCloseDisplay, gx.GXCloseDisplay,        "?GXCloseDisplay@@YAHXZ" )
    319     LINK( GXBeginDraw, gx.GXBeginDraw,           "?GXBeginDraw@@YAPAXXZ" )
    320     LINK( GXEndDraw, gx.GXEndDraw,             "?GXEndDraw@@YAHXZ" )
    321     LINK( GXOpenInput, gx.GXOpenInput,           "?GXOpenInput@@YAHXZ" )
    322     LINK( GXCloseInput, gx.GXCloseInput,          "?GXCloseInput@@YAHXZ" )
    323     LINK( GXGetDisplayProperties, gx.GXGetDisplayProperties,"?GXGetDisplayProperties@@YA?AUGXDisplayProperties@@XZ" )
    324     LINK( GXGetDefaultKeys, gx.GXGetDefaultKeys,      "?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z" )
    325     LINK( GXSuspend, gx.GXSuspend,             "?GXSuspend@@YAHXZ" )
    326     LINK( GXResume, gx.GXResume,              "?GXResume@@YAHXZ" )
    327     LINK( GXSetViewport, gx.GXSetViewport,         "?GXSetViewport@@YAHKKKK@Z" )
    328     LINK( GXIsDisplayDRAMBuffer, gx.GXIsDisplayDRAMBuffer, "?GXIsDisplayDRAMBuffer@@YAHXZ" )
    329 
    330 	/* wrong gapi.dll */
    331 	if( !gx.GXOpenDisplay )
    332 	{
    333 		if( g_hGapiLib )
    334 		{
    335 			FreeLibrary(g_hGapiLib);
    336 			g_hGapiLib = 0;
    337 		}
    338 	}
    339 
    340 	if( !gx.GXOpenDisplay && !g_bRawBufferAvailable)
    341 	{
    342 		SDL_SetError("Error: damaged or unknown gapi.dll!\n");
    343 		GAPI_DeleteDevice(device);
    344 		return 0;
    345 	}
    346 
    347 	return device;
    348 }
    349 
    350 VideoBootStrap GAPI_bootstrap = {
    351 	GAPIVID_DRIVER_NAME, "WinCE GAPI video driver",
    352 	GAPI_Available, GAPI_CreateDevice
    353 };
    354 
    355 static void FillStructs(_THIS, BOOL useVga)
    356 {
    357 #ifdef _ARM_
    358 	WCHAR oemstr[100];
    359 #endif
    360 	/* fill a device properties */
    361 
    362 	if( !useVga )
    363 	{
    364 		this->hidden->gxProperties = this->hidden->gxFunc.GXGetDisplayProperties();
    365 		this->hidden->needUpdate = 1;
    366 		this->hidden->hiresFix = 0;
    367 		this->hidden->useVga = 0;
    368 		this->hidden->useGXOpenDisplay = 1;
    369 
    370 #ifdef _ARM_
    371 		/* check some devices and extract addition info */
    372 		SystemParametersInfo( SPI_GETOEMINFO, sizeof( oemstr ), oemstr, 0 );
    373 
    374 		// buggy iPaq38xx
    375 		if ((oemstr[12] == 'H') && (oemstr[13] == '3') && (oemstr[14] == '8') && (this->hidden->gxProperties.cbxPitch > 0))
    376 		{
    377 			this->hidden->videoMem = (PIXEL*)0xac0755a0;
    378 			this->hidden->gxProperties.cbxPitch = -640;
    379 			this->hidden->gxProperties.cbyPitch = 2;
    380 			this->hidden->needUpdate = 0;
    381 		}
    382 #if (EMULATE_AXIM_X30 == 0)
    383 		// buggy Dell Axim X30
    384 		if( _tcsncmp(oemstr, L"Dell Axim X30", 13) == 0 )
    385 #endif
    386 		{
    387 			GXDeviceInfo gxInfo = {0};
    388 			HDC hdc = GetDC(NULL);
    389 			int result;
    390 
    391 			gxInfo.Version = 100;
    392 			result = ExtEscape(hdc, GETGXINFO, 0, NULL, sizeof(gxInfo), (char *)&gxInfo);
    393 			if( result > 0 )
    394 			{
    395 				this->hidden->useGXOpenDisplay = 0;
    396 				this->hidden->videoMem = gxInfo.pvFrameBuffer;
    397 				this->hidden->needUpdate = 0;
    398 				this->hidden->gxProperties.cbxPitch = 2;
    399 				this->hidden->gxProperties.cbyPitch = 480;
    400 				this->hidden->gxProperties.cxWidth = gxInfo.cxWidth;
    401 				this->hidden->gxProperties.cyHeight = gxInfo.cyHeight;
    402 				this->hidden->gxProperties.ffFormat = gxInfo.ffFormat;
    403 			}
    404 		}
    405 #endif
    406 	} else
    407 	{
    408 	    this->hidden->needUpdate = 0;
    409 		this->hidden->hiresFix = 0;
    410 		this->hidden->gxProperties.cBPP = g_RawFrameBufferInfo.wBPP;
    411 		this->hidden->gxProperties.cbxPitch = g_RawFrameBufferInfo.cxStride;
    412 		this->hidden->gxProperties.cbyPitch = g_RawFrameBufferInfo.cyStride;
    413 		this->hidden->gxProperties.cxWidth = g_RawFrameBufferInfo.cxPixels;
    414 		this->hidden->gxProperties.cyHeight = g_RawFrameBufferInfo.cyPixels;
    415 		this->hidden->videoMem = g_RawFrameBufferInfo.pFramePointer;
    416 		this->hidden->useVga = 1;
    417 
    418 		switch( g_RawFrameBufferInfo.wFormat )
    419 		{
    420 		case FORMAT_565:
    421 			this->hidden->gxProperties.ffFormat = kfDirect565;
    422 			break;
    423 		case FORMAT_555:
    424 			this->hidden->gxProperties.ffFormat = kfDirect555;
    425 			break;
    426 		default:
    427 			/* unknown pixel format, try define by BPP! */
    428 			switch( g_RawFrameBufferInfo.wBPP )
    429 			{
    430 			case 4:
    431 			case 8:
    432 				this->hidden->gxProperties.ffFormat = kfDirect;
    433 			case 16:
    434 				this->hidden->gxProperties.ffFormat = kfDirect565;
    435 			default:
    436 				this->hidden->gxProperties.ffFormat = kfDirect;
    437 				break;
    438 			}
    439 		}
    440 	}
    441 
    442 	if( this->hidden->gxProperties.cBPP != 16 )
    443 	{
    444 		this->hidden->gapiOrientation = SDL_ORIENTATION_UP;
    445 	} else
    446 	if( (this->hidden->gxProperties.cbxPitch > 0) && (this->hidden->gxProperties.cbyPitch > 0 ))
    447 	{
    448 		this->hidden->gapiOrientation = SDL_ORIENTATION_UP;
    449 	} else
    450 	if( (this->hidden->gxProperties.cbxPitch > 0) && (this->hidden->gxProperties.cbyPitch < 0 ))
    451 	{
    452 		this->hidden->gapiOrientation = SDL_ORIENTATION_RIGHT; // ipaq 3660
    453 	} else
    454 	if( (this->hidden->gxProperties.cbxPitch < 0) && (this->hidden->gxProperties.cbyPitch > 0 ))
    455 	{
    456 		this->hidden->gapiOrientation = SDL_ORIENTATION_LEFT; // ipaq 3800
    457 	}
    458 }
    459 
    460 static void GAPI_CreatePalette(int ncolors, SDL_Color *colors)
    461 {
    462   // Setup a custom color palette
    463    BYTE buffer[ sizeof(LOGPALETTE) + 255 * sizeof(PALETTEENTRY) ];
    464    int i;
    465    LOGPALETTE*   pLogical = (LOGPALETTE*)buffer;
    466    PALETTEENTRY* entries  = pLogical->palPalEntry;
    467    HPALETTE hPalette;
    468    HDC hdc;
    469 
    470    for (i = 0; i < ncolors; ++i)
    471    {
    472       // Find intensity by replicating the bit patterns over a byte
    473       entries[i].peRed   = colors[i].r;
    474       entries[i].peGreen = colors[i].g;
    475       entries[i].peBlue  = colors[i].b;
    476       entries[i].peFlags = 0;
    477    }
    478 
    479    // Create the GDI palette object
    480    pLogical->palVersion    = 0x0300;
    481    pLogical->palNumEntries = ncolors;
    482 
    483    hPalette = CreatePalette( pLogical );
    484    ASSERT(hPalette);
    485 
    486 
    487    // Realize the palette
    488    hdc = GetDC(0);
    489 
    490    SelectPalette( hdc, hPalette, FALSE );
    491    RealizePalette( hdc );
    492 
    493    ReleaseDC( 0, hdc );
    494    DeleteObject( hPalette );
    495 }
    496 
    497 int GAPI_VideoInit(_THIS, SDL_PixelFormat *vformat)
    498 {
    499 	int i,bpp;
    500 
    501 	/* Create the window */
    502 	if ( DIB_CreateWindow(this) < 0 ) {
    503 		return(-1);
    504 	}
    505 
    506 	if( g_hGapiLib )
    507 	{
    508 		FillStructs(this, 0);
    509 
    510 		// SDL does not supports 2/4bpp mode, so use 16 bpp
    511 		bpp = gapi->gxProperties.cBPP < 8 ? 16 : gapi->gxProperties.cBPP;
    512 
    513 		/* set up normal and landscape mode */
    514 		GAPI_AddMode(this, bpp, gapi->gxProperties.cyHeight, gapi->gxProperties.cxWidth);
    515 		GAPI_AddMode(this, bpp, gapi->gxProperties.cxWidth, gapi->gxProperties.cyHeight);
    516 	}
    517 
    518 	/* add hi-res mode */
    519 	if( g_bRawBufferAvailable &&
    520 		!((gapi->gxProperties.cxWidth == (unsigned)g_RawFrameBufferInfo.cxPixels) && (gapi->gxProperties.cyHeight == (unsigned)g_RawFrameBufferInfo.cyPixels)))
    521 	{
    522 		FillStructs(this, 1);
    523 
    524 		// SDL does not supports 2/4bpp mode, so use 16 bpp
    525 		bpp = gapi->gxProperties.cBPP < 8 ? 16 : gapi->gxProperties.cBPP;
    526 
    527 		/* set up normal and landscape mode */
    528 		GAPI_AddMode(this, bpp, gapi->gxProperties.cyHeight, gapi->gxProperties.cxWidth);
    529 		GAPI_AddMode(this, bpp, gapi->gxProperties.cxWidth, gapi->gxProperties.cyHeight);
    530 	}
    531 
    532 	/* Determine the current screen size */
    533 	this->info.current_w = gapi->gxProperties.cxWidth;
    534 	this->info.current_h = gapi->gxProperties.cyHeight;
    535 
    536 	/* Sort the mode lists */
    537 	for ( i=0; i<NUM_MODELISTS; ++i ) {
    538 		if ( gapi->SDL_nummodes[i] > 0 ) {
    539 			SDL_qsort(gapi->SDL_modelist[i], gapi->SDL_nummodes[i], sizeof *gapi->SDL_modelist[i], cmpmodes);
    540 		}
    541 	}
    542 
    543 	vformat->BitsPerPixel = this->hidden->gxProperties.cBPP < 8 ? 16 : (unsigned char)this->hidden->gxProperties.cBPP;
    544 
    545 	// Get color mask
    546 	if (this->hidden->gxProperties.ffFormat & kfDirect565) {
    547 		vformat->BitsPerPixel = 16;
    548 		vformat->Rmask = 0x0000f800;
    549 		vformat->Gmask = 0x000007e0;
    550 		vformat->Bmask = 0x0000001f;
    551 		this->hidden->videoMode = GAPI_DIRECT_565;
    552 	}
    553 	else
    554 	if (this->hidden->gxProperties.ffFormat & kfDirect555) {
    555 		vformat->BitsPerPixel = 16;
    556 		vformat->Rmask = 0x00007c00;
    557 		vformat->Gmask = 0x000003e0;
    558 		vformat->Bmask = 0x0000001f;
    559 		this->hidden->videoMode = GAPI_DIRECT_555;
    560 	}
    561 	else
    562 	if ((this->hidden->gxProperties.ffFormat & kfDirect) && (this->hidden->gxProperties.cBPP < 8)) {
    563 		// We'll perform the conversion
    564 		vformat->BitsPerPixel = 16;
    565 		vformat->Rmask = 0x0000f800; // 16 bit 565
    566 		vformat->Gmask = 0x000007e0;
    567 		vformat->Bmask = 0x0000001f;
    568 		if (this->hidden->gxProperties.ffFormat & kfDirectInverted)
    569 			this->hidden->invert = (1 << this->hidden->gxProperties.cBPP) - 1;
    570 		this->hidden->colorscale = this->hidden->gxProperties.cBPP < 8 ? 8 - this->hidden->gxProperties.cBPP : 0;
    571 		this->hidden->videoMode = GAPI_MONO;
    572 	}
    573 	else
    574 	if (this->hidden->gxProperties.ffFormat & kfPalette) {
    575 		this->hidden->videoMode = GAPI_PALETTE;
    576 	}
    577 
    578 	/* We're done! */
    579 	return(0);
    580 }
    581 
    582 SDL_Rect **GAPI_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
    583 {
    584 	return(this->hidden->SDL_modelist[((format->BitsPerPixel+7)/8)-1]);
    585 //  	 return (SDL_Rect **) -1;
    586 }
    587 
    588 SDL_Surface *GAPI_SetVideoMode(_THIS, SDL_Surface *current,
    589 				int width, int height, int bpp, Uint32 flags)
    590 {
    591 	SDL_Surface *video;
    592 	Uint32 Rmask, Gmask, Bmask;
    593 	DWORD style;
    594 	SDL_Rect allScreen;
    595 
    596 	if( bpp < 4 )
    597 	{
    598 		SDL_SetError("1 bpp and 2 bpp modes is not implemented yet!");
    599 		return 0;
    600 	}
    601 
    602 	/* Recalculate bitmasks if necessary */
    603 	if (bpp == current->format->BitsPerPixel) {
    604 		video = current;
    605 	}
    606 	else {
    607 		switch(bpp) {
    608 			case 8:
    609 				Rmask = 0;
    610 				Gmask = 0;
    611 				Bmask = 0;
    612 				break;
    613 			case 15:
    614 			case 16:
    615 				/* Default is 565 unless the display is specifically 555 */
    616 				if (this->hidden->gxProperties.ffFormat & kfDirect555) {
    617 					Rmask = 0x00007c00;
    618 					Gmask = 0x000003e0;
    619 					Bmask = 0x0000001f;
    620 				}
    621 				else {
    622 					Rmask = 0x0000f800;
    623 					Gmask = 0x000007e0;
    624 					Bmask = 0x0000001f;
    625 				}
    626 				break;
    627 			case 24:
    628 			case 32:
    629 				Rmask = 0x00ff0000;
    630 				Gmask = 0x0000ff00;
    631 				Bmask = 0x000000ff;
    632 				break;
    633 			default:
    634 				SDL_SetError("Unsupported Bits Per Pixel format requested");
    635 				return NULL;
    636 		}
    637 		video = SDL_CreateRGBSurface(SDL_SWSURFACE,
    638 					0, 0, bpp, Rmask, Gmask, Bmask, 0);
    639 		if ( video == NULL ) {
    640 			SDL_OutOfMemory();
    641 			return(NULL);
    642 		}
    643 	}
    644 
    645 	gapi->userOrientation = SDL_ORIENTATION_UP;
    646 	video->flags = SDL_FULLSCREEN;	/* Clear flags, GAPI supports fullscreen only */
    647 
    648 	/* GAPI or VGA? */
    649 	if( g_hGapiLib )
    650 	{
    651 		FillStructs(this, 0);
    652 		if( (((unsigned)width != gapi->gxProperties.cxWidth) || ((unsigned)height != gapi->gxProperties.cyHeight))
    653 			&& (((unsigned)width != gapi->gxProperties.cyHeight) || ((unsigned)height != gapi->gxProperties.cxWidth)))
    654 			FillStructs(this, 1); // gapi is found but we use VGA resolution
    655 	} else
    656 		FillStructs(this, 1);
    657 
    658 	if ( !this->hidden->needUpdate && !this->hidden->videoMem) {
    659 		SDL_SetError("Couldn't get address of video memory, may be unsupported device or bug");
    660 		return(NULL);
    661 	}
    662 
    663 	/* detect user landscape mode */
    664 	if( (width > height) && (GetSystemMetrics(SM_CXSCREEN) < GetSystemMetrics(SM_CYSCREEN)))
    665 		gapi->userOrientation = SDL_ORIENTATION_RIGHT;
    666 
    667 	/* shall we apply hires fix? for example when we do not use hires resource */
    668 	gapi->hiresFix = 0;
    669 	if( gapi->userOrientation == SDL_ORIENTATION_RIGHT )
    670 	{
    671 		if( (width > GetSystemMetrics(SM_CYSCREEN)) || (height > GetSystemMetrics(SM_CXSCREEN)))
    672 			gapi->hiresFix = 1;
    673 	} else
    674 		if( (width > GetSystemMetrics(SM_CXSCREEN)) || (height > GetSystemMetrics(SM_CYSCREEN)))
    675 			if( !((width == GetSystemMetrics(SM_CYSCREEN)) && (height == GetSystemMetrics(SM_CXSCREEN)))) // user portrait, device landscape
    676 				gapi->hiresFix = 1;
    677 
    678 	switch( gapi->userOrientation )
    679 	{
    680 	case SDL_ORIENTATION_UP:
    681 		gapi->startOffset = 0;
    682 		gapi->dstLineStep = gapi->gxProperties.cbyPitch;
    683 		gapi->dstPixelStep = gapi->gxProperties.cbxPitch;
    684 		break;
    685 	case SDL_ORIENTATION_RIGHT:
    686 		switch( gapi->gapiOrientation )
    687 		{
    688 		case SDL_ORIENTATION_UP:
    689 		case SDL_ORIENTATION_RIGHT:
    690 		case SDL_ORIENTATION_LEFT:
    691 			if( (this->hidden->videoMode == GAPI_MONO) )
    692 				gapi->startOffset = -gapi->gxProperties.cbxPitch + 1; // monochrome mode
    693 			else
    694 				gapi->startOffset = gapi->gxProperties.cbyPitch * (gapi->gxProperties.cyHeight - 1);
    695 
    696 			gapi->dstLineStep = gapi->gxProperties.cbxPitch;
    697 			gapi->dstPixelStep = -gapi->gxProperties.cbyPitch;
    698 			break;
    699 		}
    700 	}
    701 
    702 	video->w = this->hidden->w = width;
    703 	video->h = this->hidden->h = height;
    704 	video->pitch = SDL_CalculatePitch(video);
    705 
    706 	/* Small fix for WinCE/Win32 - when activating window
    707 	   SDL_VideoSurface is equal to zero, so activating code
    708 	   is not called properly for fullscreen windows because
    709 	   macros WINDIB_FULLSCREEN uses SDL_VideoSurface
    710 	*/
    711 	SDL_VideoSurface = video;
    712 
    713 	/* GAPI is always fullscreen, title bar is useless */
    714 	style = 0;
    715 
    716 	if (!SDL_windowid)
    717 		SetWindowLong(SDL_Window, GWL_STYLE, style);
    718 
    719 	/* Allocate bitmap */
    720 	if(gapiBuffer)
    721 	{
    722 		SDL_free(gapiBuffer);
    723 		gapiBuffer = NULL;
    724 	}
    725 	gapiBuffer = SDL_malloc(video->h * video->pitch);
    726 	video->pixels = gapiBuffer;
    727 
    728 	if ( ! this->hidden->buffer ) {
    729 		SDL_SetError("Couldn't allocate buffer for requested mode");
    730 		return(NULL);
    731 	}
    732 
    733 	SDL_memset(gapiBuffer, 255, video->h * video->pitch);
    734 	MoveWindow(SDL_Window, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), FALSE);
    735 	ShowWindow(SDL_Window, SW_SHOW);
    736 	SetForegroundWindow(SDL_Window);
    737 
    738 	/* JC 14 Mar 2006
    739 		Flush the message loop or this can cause big problems later
    740 		Especially if the user decides to use dialog boxes or assert()!
    741 	*/
    742 	WIN_FlushMessageQueue();
    743 
    744 	/* Open GAPI display */
    745 	if( !gapi->useVga && this->hidden->useGXOpenDisplay )
    746 		if( !gapi->gxFunc.GXOpenDisplay(SDL_Window, GX_FULLSCREEN) )
    747 		{
    748 			SDL_SetError("Couldn't initialize GAPI");
    749 			return(NULL);
    750 		}
    751 
    752 #if REPORT_VIDEO_INFO
    753 	printf("Video properties:\n");
    754 	printf("display bpp: %d\n", gapi->gxProperties.cBPP);
    755 	printf("display width: %d\n", gapi->gxProperties.cxWidth);
    756 	printf("display height: %d\n", gapi->gxProperties.cyHeight);
    757 	printf("x pitch: %d\n", gapi->gxProperties.cbxPitch);
    758 	printf("y pitch: %d\n", gapi->gxProperties.cbyPitch);
    759 	printf("gapi flags: 0x%x\n", gapi->gxProperties.ffFormat);
    760 
    761 	if( !gapi->useVga && this->hidden->useGXOpenDisplay && gapi->needUpdate)
    762 	{
    763 		gapi->videoMem = gapi->gxFunc.GXBeginDraw();
    764 		gapi->gxFunc.GXEndDraw();
    765 	}
    766 
    767 	printf("video memory: 0x%x\n", gapi->videoMem);
    768 	printf("need update: %d\n", gapi->needUpdate);
    769 	printf("hi-res fix: %d\n", gapi->hiresFix);
    770 	printf("VGA is available on the device: %d\n", g_bRawBufferAvailable);
    771 	printf("use raw framebuffer: %d\n", gapi->useVga);
    772 	printf("video surface bpp: %d\n", video->format->BitsPerPixel);
    773 	printf("video surface width: %d\n", video->w);
    774 	printf("video surface height: %d\n", video->h);
    775 #endif
    776 
    777 
    778 	/* Blank screen */
    779 	allScreen.x = allScreen.y = 0;
    780 	allScreen.w = video->w - 1;
    781 	allScreen.h = video->h - 1;
    782 	GAPI_UpdateRects(this, 1, &allScreen);
    783 
    784 	/* We're done */
    785 	return(video);
    786 }
    787 
    788 /* We don't actually allow hardware surfaces other than the main one */
    789 static int GAPI_AllocHWSurface(_THIS, SDL_Surface *surface)
    790 {
    791 	return(-1);
    792 }
    793 static void GAPI_FreeHWSurface(_THIS, SDL_Surface *surface)
    794 {
    795 	return;
    796 }
    797 
    798 /* We need to wait for vertical retrace on page flipped displays */
    799 static int GAPI_LockHWSurface(_THIS, SDL_Surface *surface)
    800 {
    801 	return(0);
    802 }
    803 
    804 static void GAPI_UnlockHWSurface(_THIS, SDL_Surface *surface)
    805 {
    806 	return;
    807 }
    808 
    809 static int updateLine8to8(_THIS, unsigned char *srcPointer, unsigned char *destPointer, int width, int height, int lines)
    810 {
    811 	if( gapi->dstPixelStep == 1) /* optimized blitting on most devices */
    812 	{
    813 		SDL_memcpy(destPointer, srcPointer, width);
    814 		return 1;
    815 	} else
    816 	{
    817 		// TODO: read 4 pixels, write DWORD
    818 		int step = gapi->dstPixelStep;
    819 		while(width--)
    820 		{
    821 			*destPointer = *srcPointer++;
    822 			destPointer += step;
    823 		}
    824 	}
    825 	return 1;
    826 }
    827 
    828 /* Video memory is very slow so lets optimize as much as possible */
    829 static int updateLine16to16(_THIS, PIXEL *srcPointer, PIXEL *destPointer, int width, int height, int lines)
    830 {
    831 	PIXEL *line1, *line2;
    832 	int step = gapi->dstPixelStep / 2;
    833 
    834 	if( step == 1 ) /* optimized blitting on most devices */
    835 	{
    836 		SDL_memcpy(destPointer, srcPointer, width * sizeof(PIXEL));
    837 		return 1;
    838 	}
    839 	else
    840 	{
    841 		if( (gapi->gapiOrientation != SDL_ORIENTATION_UP) &&
    842 			(gapi->userOrientation == SDL_ORIENTATION_UP )) // iPaq 3660/3800 and user orientation up
    843 		{
    844 			// to prevent data misalignment copy only one line
    845 			if( ((((unsigned)destPointer & 3) != 0) && (gapi->gapiOrientation == SDL_ORIENTATION_LEFT))
    846 				|| ((((unsigned)destPointer & 3) == 0) && (gapi->gapiOrientation != SDL_ORIENTATION_LEFT))
    847 				|| (lines == 1) )
    848 			{
    849 				while(width--)
    850 				{
    851 					*destPointer = *srcPointer++;
    852 					destPointer += step;
    853 				}
    854 				return 1;
    855 			}
    856 
    857 			/* read two lines at the same time, write DWORD */
    858 			line1 = srcPointer;
    859 			line2 = srcPointer + SDL_VideoSurface->pitch / 2;
    860 
    861 			if( gapi->gapiOrientation == SDL_ORIENTATION_LEFT )
    862 				while(width--) // iPaq 3800
    863 				{
    864 					*(DWORD*)destPointer =(*line2++ << 16) | *line1++;
    865 					destPointer += step;
    866 				}
    867 			else
    868 			{
    869 				destPointer += gapi->gxProperties.cbyPitch / 2;
    870 
    871 				while(width--) // iPaq 3660
    872 				{
    873 					*(DWORD*)destPointer =(*line1++ << 16) | *line2++;
    874 					destPointer += step;
    875 				}
    876 			}
    877 			return 2;
    878 		} else
    879 		{
    880 			// iPaq 3800 and user orientation landscape
    881 			if( gapi->gapiOrientation == SDL_ORIENTATION_LEFT )
    882 			{
    883 				int w1;
    884 
    885 				// to prevent data misalignment copy only one pixel
    886 				if( (((unsigned)destPointer & 3) == 0) && (width > 0))
    887 				{
    888 					*destPointer-- = *srcPointer++;
    889 					width--;
    890 				}
    891 
    892 				destPointer--;
    893 
    894 				w1 = width / 2;
    895 
    896 				while(w1--)
    897 				{
    898 					DWORD p = *(DWORD*)srcPointer;
    899 					*((DWORD*)destPointer) = (p << 16) | (p >> 16);
    900 					destPointer -= 2;
    901 					srcPointer += 2;
    902 				}
    903 
    904 				if( width & 1 ) // copy the last pixel
    905 				{
    906 					destPointer++;
    907 					*destPointer = *srcPointer;
    908 				}
    909 
    910 				return 1;
    911 			}
    912 
    913 			// modern iPaqs and user orientation landscape
    914 			// read two pixels, write DWORD
    915 
    916 			line1 = srcPointer;
    917 			line2 = srcPointer + SDL_VideoSurface->pitch / 2;
    918 
    919 			if( (((unsigned)destPointer & 3) != 0) || (lines == 1) )
    920 			{
    921 				while(width--)
    922 				{
    923 					*destPointer = *srcPointer++;
    924 					destPointer += step;
    925 				}
    926 				return 1;
    927 			}
    928 
    929 			while(width--)
    930 			{
    931 				*(DWORD*)destPointer =(*line2++ << 16) | *line1++;
    932 				destPointer -= gapi->gxProperties.cbyPitch / 2;
    933 			}
    934 			return 2;
    935 		}
    936 	}
    937 }
    938 
    939 // Color component masks for 565
    940 #define REDMASK (31<<11)
    941 #define GREENMASK (63<<5)
    942 #define BLUEMASK (31)
    943 
    944 
    945 static int updateLine16to4(_THIS, PIXEL *srcPointer, unsigned char *destPointer, int width, int height, int lines, int yNibble, int xNibble)
    946 {
    947 	PIXEL *line1, *line2;
    948 	int step = gapi->dstPixelStep;
    949 
    950 	if( gapi->userOrientation == SDL_ORIENTATION_UP )
    951 	{
    952 		if( yNibble ) // copy bottom half of a line
    953 		{
    954 			while(width--)
    955 			{
    956 				PIXEL c1 = *srcPointer++;
    957 				c1 = ((c1 & REDMASK) >> 11) + ((c1 & GREENMASK) >> 5) + (c1 & BLUEMASK);
    958 				*destPointer = (*destPointer & 0x0F) | ((~(c1 >> 3) << 4));
    959 				destPointer += step;
    960 			}
    961 			return 1;
    962 		}
    963 
    964 		// either 1 pixel picture or tail, anyway this is the last line
    965 		if( lines == 1 )
    966 		{
    967 			while(width--)
    968 			{
    969 				PIXEL c1 = *srcPointer++;
    970 				c1 = ((c1 & REDMASK) >> 11) + ((c1 & GREENMASK) >> 5) + (c1 & BLUEMASK);
    971 				*destPointer = (*destPointer & 0xF0) | ((~(c1 >> 3) & 0xF));
    972 				destPointer += step;
    973 			}
    974 			return 1;
    975 		}
    976 
    977 		line1 = srcPointer;
    978 		line2 = srcPointer + SDL_VideoSurface->pitch / 2;
    979 
    980 		while(width--)
    981 		{
    982 			PIXEL c1 = *line1++;
    983 			PIXEL c2 = *line2++;
    984 			c1 = ((c1 & REDMASK) >> 11) + ((c1 & GREENMASK) >> 5) + (c1 & BLUEMASK);
    985 			c2 = ((c2 & REDMASK) >> 11) + ((c2 & GREENMASK) >> 5) + (c2 & BLUEMASK);
    986 			*destPointer = ~((c1 >> 3) + ((c2 >> 3) << 4));
    987 			destPointer += step;
    988 		}
    989 		return 2;
    990 	} else
    991 	{
    992 		int w1;
    993 		w1 = width / 2;
    994 
    995 		if( xNibble )
    996 		{
    997 			// copy one pixel
    998 			PIXEL c1 = *srcPointer++;
    999 			c1 = ((c1 & REDMASK) >> 11) + ((c1 & GREENMASK) >> 5) + (c1 & BLUEMASK);
   1000 			*destPointer = (*destPointer & 0xF0) | ((~(c1 >> 3) & 0xF));
   1001 			destPointer++;
   1002 		}
   1003 
   1004 		while(w1--)
   1005 		{
   1006 			PIXEL c1 = *srcPointer;
   1007 			PIXEL c2 = *(srcPointer + 1);
   1008 			c1 = ((c1 & REDMASK) >> 11) + ((c1 & GREENMASK) >> 5) + (c1 & BLUEMASK);
   1009 			c2 = ((c2 & REDMASK) >> 11) + ((c2 & GREENMASK) >> 5) + (c2 & BLUEMASK);
   1010 			*destPointer++ = ~((c2 >> 3) + ((c1 >> 3) << 4));
   1011 			srcPointer += 2;
   1012 		}
   1013 
   1014 		// copy tail
   1015 		if( (width & 1) && !xNibble )
   1016 		{
   1017 			PIXEL c1 = *srcPointer;
   1018 			c1 = ((c1 & REDMASK) >> 11) + ((c1 & GREENMASK) >> 5) + (c1 & BLUEMASK);
   1019 			*destPointer = (*destPointer & 0x0F) | ((~(c1 >> 3) << 4));
   1020 		}
   1021 
   1022 		return 1;
   1023 	}
   1024 }
   1025 
   1026 static void GAPI_UpdateRectsMono(_THIS, int numrects, SDL_Rect *rects)
   1027 {
   1028 	int i, height;
   1029 	int linesProcessed;
   1030 	int xNibble, yNibble;
   1031 
   1032 	for (i=0; i<numrects; i++)
   1033 	{
   1034 		unsigned char *destPointer;
   1035 		unsigned char *srcPointer;
   1036 
   1037 		if( gapi->userOrientation == SDL_ORIENTATION_UP )
   1038 			destPointer = (unsigned char*) gapi->videoMem + gapi->startOffset - rects[i].y * gapi->gxProperties.cBPP / 8 + rects[i].x * gapi->dstPixelStep;
   1039 		else
   1040 			destPointer = (unsigned char*) gapi->videoMem + gapi->startOffset + rects[i].x * gapi->gxProperties.cBPP / 8 + rects[i].y * gapi->dstLineStep;
   1041 
   1042 		srcPointer = ((unsigned char*) SDL_VideoSurface->pixels) + rects[i].y * SDL_VideoSurface->pitch + rects[i].x * 2;
   1043 		yNibble = rects[i].y & 1; // TODO: only for 4 bpp
   1044 		xNibble = rects[i].x & 1;
   1045 		height = rects[i].h;
   1046 		while (height > 0)
   1047 		{
   1048 			switch(gapi->gxProperties.cBPP)
   1049 			{
   1050 			case 2: // TODO
   1051 			case 4:
   1052 					linesProcessed = updateLine16to4(this, (PIXEL*) srcPointer, destPointer, rects[i].w, rects[i].h, height, yNibble, xNibble);
   1053 					yNibble = 0;
   1054 			}
   1055 			height -= linesProcessed;
   1056 			if( gapi->userOrientation == SDL_ORIENTATION_UP )
   1057 				destPointer--; // always fill 1 byte
   1058 			else destPointer += gapi->dstLineStep;
   1059 			srcPointer += SDL_VideoSurface->pitch * linesProcessed; // pitch in bytes
   1060 		}
   1061 	}
   1062 }
   1063 
   1064 static void GAPI_UpdateRectsColor(_THIS, int numrects, SDL_Rect *rects)
   1065 {
   1066 	int i, height;
   1067 	int bytesPerPixel = (gapi->gxProperties.cBPP + 1) / 8;
   1068 	int linesProcessed;
   1069 	for (i=0; i<numrects; i++) {
   1070 		unsigned char *destPointer = (unsigned char*) gapi->videoMem + gapi->startOffset + rects[i].y * gapi->dstLineStep + rects[i].x * gapi->dstPixelStep;
   1071 		unsigned char *srcPointer = ((unsigned char*) SDL_VideoSurface->pixels) + rects[i].y * SDL_VideoSurface->pitch + rects[i].x * bytesPerPixel;
   1072 		height = rects[i].h;
   1073 
   1074 //		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);
   1075 //		fflush(stderr);
   1076 		linesProcessed = height;
   1077 
   1078 		while (height > 0) {
   1079 			switch(bytesPerPixel)
   1080 			{
   1081 			case 1:
   1082 				linesProcessed = updateLine8to8(this, srcPointer, (unsigned char *) destPointer, rects[i].w, rects[i].h, height);
   1083 				break;
   1084 			case 2:
   1085 #pragma warning(disable: 4133)
   1086 				linesProcessed = updateLine16to16(this, (PIXEL*) srcPointer, destPointer, rects[i].w, rects[i].h, height);
   1087 				break;
   1088 			}
   1089 			height -= linesProcessed;
   1090 			destPointer += gapi->dstLineStep * linesProcessed;
   1091 			srcPointer += SDL_VideoSurface->pitch * linesProcessed; // pitch in bytes
   1092 		}
   1093 //		fprintf(stderr, "End of rect\n");
   1094 //		fflush(stderr);
   1095 	}
   1096 }
   1097 
   1098 
   1099 static void GAPI_UpdateRects(_THIS, int numrects, SDL_Rect *rects)
   1100 {
   1101 	// we do not want to corrupt video memory
   1102 	if( gapi->suspended ) return;
   1103 
   1104 	if( gapi->needUpdate )
   1105 		gapi->videoMem = gapi->gxFunc.GXBeginDraw();
   1106 
   1107 	if( gapi->gxProperties.cBPP < 8 )
   1108 		GAPI_UpdateRectsMono(this, numrects, rects);
   1109 	else
   1110 		GAPI_UpdateRectsColor(this, numrects, rects);
   1111 
   1112 	if( gapi->needUpdate )
   1113 		gapi->gxFunc.GXEndDraw();
   1114 }
   1115 
   1116 /* Note:  If we are terminated, this could be called in the middle of
   1117    another SDL video routine -- notably UpdateRects.
   1118 */
   1119 void GAPI_VideoQuit(_THIS)
   1120 {
   1121 	int i, j;
   1122 	/* Destroy the window and everything associated with it */
   1123 	if ( SDL_Window )
   1124 	{
   1125 	    if ((g_hGapiLib != 0) && this && this->hidden && this->hidden->gxFunc.GXCloseDisplay && !this->hidden->useVga)
   1126 			this->hidden->gxFunc.GXCloseDisplay();
   1127 
   1128 		if (this->screen->pixels != NULL)
   1129 		{
   1130 			SDL_free(this->screen->pixels);
   1131 			this->screen->pixels = NULL;
   1132 		}
   1133 		if ( screen_icn ) {
   1134 			DestroyIcon(screen_icn);
   1135 			screen_icn = NULL;
   1136 		}
   1137 
   1138 		DIB_DestroyWindow(this);
   1139 		SDL_UnregisterApp();
   1140 
   1141 		SDL_Window = NULL;
   1142 #if defined(_WIN32_WCE)
   1143 
   1144 // Unload wince aygshell library to prevent leak
   1145 		if( aygshell )
   1146 		{
   1147 			FreeLibrary(aygshell);
   1148 			aygshell = NULL;
   1149 		}
   1150 #endif
   1151 
   1152 	/* Free video mode lists */
   1153 	for ( i=0; i<NUM_MODELISTS; ++i ) {
   1154 		if ( gapi->SDL_modelist[i] != NULL ) {
   1155 			for ( j=0; gapi->SDL_modelist[i][j]; ++j )
   1156 				SDL_free(gapi->SDL_modelist[i][j]);
   1157 			SDL_free(gapi->SDL_modelist[i]);
   1158 			gapi->SDL_modelist[i] = NULL;
   1159 		}
   1160 	}
   1161 
   1162 	}
   1163 
   1164 }
   1165 
   1166 static void GAPI_RealizePalette(_THIS)
   1167 {
   1168 	OutputDebugString(TEXT("GAPI_RealizePalette NOT IMPLEMENTED !\r\n"));
   1169 }
   1170 
   1171 static void GAPI_PaletteChanged(_THIS, HWND window)
   1172 {
   1173 	OutputDebugString(TEXT("GAPI_PaletteChanged NOT IMPLEMENTED !\r\n"));
   1174 }
   1175 
   1176 static void GAPI_WinPAINT(_THIS, HDC hdc)
   1177 {
   1178 	// draw current offscreen buffer on hdc
   1179 
   1180 	int bpp = 16; // we always use either 8 or 16 bpp internally
   1181 	HGDIOBJ prevObject;
   1182 	unsigned short *bitmapData;
   1183 	HBITMAP hb;
   1184 	HDC srcDC;
   1185 
   1186     // Create a DIB
   1187     BYTE buffer[sizeof(BITMAPINFOHEADER) + 3 * sizeof(RGBQUAD)] = {0};
   1188     BITMAPINFO*       pBMI    = (BITMAPINFO*)buffer;
   1189     BITMAPINFOHEADER* pHeader = &pBMI->bmiHeader;
   1190     DWORD*            pColors = (DWORD*)&pBMI->bmiColors;
   1191 
   1192 	// CreateDIBSection does not support 332 pixel format on wce
   1193 	if( gapi->gxProperties.cBPP == 8 ) return;
   1194 
   1195     // DIB Header
   1196     pHeader->biSize            = sizeof(BITMAPINFOHEADER);
   1197     pHeader->biWidth           = this->hidden->w;
   1198     pHeader->biHeight          = -this->hidden->h;
   1199     pHeader->biPlanes          = 1;
   1200     pHeader->biBitCount        = bpp;
   1201     pHeader->biCompression     = BI_RGB;
   1202     pHeader->biSizeImage       = (this->hidden->w * this->hidden->h * bpp) / 8;
   1203 
   1204     // Color masks
   1205 	if( bpp == 16 )
   1206 	{
   1207 		pColors[0] = REDMASK;
   1208 		pColors[1] = GREENMASK;
   1209 		pColors[2] = BLUEMASK;
   1210 		pHeader->biCompression = BI_BITFIELDS;
   1211 	}
   1212     // Create the DIB
   1213     hb =  CreateDIBSection( 0, pBMI, DIB_RGB_COLORS, (void**)&bitmapData, 0, 0 );
   1214 
   1215 	// copy data
   1216 	// FIXME: prevent misalignment, but I've never seen non aligned width of screen
   1217 	memcpy(bitmapData, this->hidden->buffer, pHeader->biSizeImage);
   1218 	srcDC = CreateCompatibleDC(hdc);
   1219 	prevObject = SelectObject(srcDC, hb);
   1220 
   1221 	BitBlt(hdc, 0, 0, this->hidden->w, this->hidden->h, srcDC, 0, 0, SRCCOPY);
   1222 
   1223 	SelectObject(srcDC, prevObject);
   1224 	DeleteObject(hb);
   1225 	DeleteDC(srcDC);
   1226 }
   1227 
   1228 int GAPI_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
   1229 {
   1230 	GAPI_CreatePalette(ncolors, colors);
   1231 	return 1;
   1232 }
   1233