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