| 1 | /* |
| 2 | SDL - Simple DirectMedia Layer |
| 3 | Copyright (C) 1997-2009 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; |
| 25 | Implemented by Dmitry Yakimov - support@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 "../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 |
| 86 | extern HINSTANCE aygshell; |
| 87 | extern void SDL_UnregisterApp(); |
| 88 | extern int DIB_AddMode(_THIS, int bpp, int w, int h); |
| 89 | |
| 90 | /* Initialization/Query functions */ |
| 91 | static int GAPI_VideoInit(_THIS, SDL_PixelFormat *vformat); |
| 92 | static SDL_Rect **GAPI_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags); |
| 93 | static SDL_Surface *GAPI_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags); |
| 94 | static int GAPI_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors); |
| 95 | static void GAPI_VideoQuit(_THIS); |
| 96 | |
| 97 | /* Hardware surface functions */ |
| 98 | static int GAPI_AllocHWSurface(_THIS, SDL_Surface *surface); |
| 99 | static int GAPI_LockHWSurface(_THIS, SDL_Surface *surface); |
| 100 | static void GAPI_UnlockHWSurface(_THIS, SDL_Surface *surface); |
| 101 | static void GAPI_FreeHWSurface(_THIS, SDL_Surface *surface); |
| 102 | |
| 103 | /* Windows message handling functions, will not be processed */ |
| 104 | static void GAPI_Activate(_THIS, BOOL active, BOOL minimized); |
| 105 | static void GAPI_RealizePalette(_THIS); |
| 106 | static void GAPI_PaletteChanged(_THIS, HWND window); |
| 107 | static void GAPI_WinPAINT(_THIS, HDC hdc); |
| 108 | |
| 109 | /* etc. */ |
| 110 | static void GAPI_UpdateRects(_THIS, int numrects, SDL_Rect *rects); |
| 111 | |
| 112 | static HMODULE g_hGapiLib = 0; |
| 113 | #define LINK(type,name,import) \ |
| 114 | if( g_hGapiLib ) \ |
| 115 | name = (PFN##type)GetProcAddress( g_hGapiLib, _T(import) ); |
| 116 | |
| 117 | static char g_bRawBufferAvailable = 0; |
| 118 | |
| 119 | /* GAPI driver bootstrap functions */ |
| 120 | |
| 121 | /* hi res definitions */ |
| 122 | typedef 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 | |
| 133 | static 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 | |
| 147 | typedef struct GXDeviceInfo |
| 148 | { |
| 149 | long Version; //00 (should filled with 100 before calling ExtEscape) |
| 150 | void * pvFrameBuffer; //04 |
| 151 | unsigned long cbStride; //08 |
| 152 | unsigned long cxWidth; //0c |
| 153 | unsigned long cyHeight; //10 |
| 154 | unsigned long cBPP; //14 |
| 155 | unsigned long ffFormat; //18 |
| 156 | char Unused[0x84-7*4]; |
| 157 | } GXDeviceInfo; |
| 158 | |
| 159 | static 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 | |
| 196 | static 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 | |
| 206 | static 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 | |
| 252 | static 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 | |
| 264 | static 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 | |
| 378 | VideoBootStrap GAPI_bootstrap = { |
| 379 | GAPIVID_DRIVER_NAME, "WinCE GAPI video driver", |
| 380 | GAPI_Available, GAPI_CreateDevice |
| 381 | }; |
| 382 | |
| 383 | static 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 | |
| 488 | static 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 | |
| 525 | int 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 | |
| 612 | SDL_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 | |
| 618 | SDL_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 */ |
| 839 | static int GAPI_AllocHWSurface(_THIS, SDL_Surface *surface) |
| 840 | { |
| 841 | return(-1); |
| 842 | } |
| 843 | static void GAPI_FreeHWSurface(_THIS, SDL_Surface *surface) |
| 844 | { |
| 845 | return; |
| 846 | } |
| 847 | |
| 848 | /* We need to wait for vertical retrace on page flipped displays */ |
| 849 | static int GAPI_LockHWSurface(_THIS, SDL_Surface *surface) |
| 850 | { |
| 851 | return(0); |
| 852 | } |
| 853 | |
| 854 | static void GAPI_UnlockHWSurface(_THIS, SDL_Surface *surface) |
| 855 | { |
| 856 | return; |
| 857 | } |
| 858 | |
| 859 | static 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 */ |
| 879 | static 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 | |
| 995 | static 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 | |
| 1076 | static 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 | |
| 1114 | static 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 | |
| 1149 | static 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 | */ |
| 1169 | void 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 | |
| 1216 | static void GAPI_Activate(_THIS, BOOL active, BOOL minimized) |
| 1217 | { |
| 1218 | //Nothing to do here (as far as I know) |
| 1219 | } |
| 1220 | |
| 1221 | static void GAPI_RealizePalette(_THIS) |
| 1222 | { |
| 1223 | OutputDebugString(TEXT("GAPI_RealizePalette NOT IMPLEMENTED !\r\n")); |
| 1224 | } |
| 1225 | |
| 1226 | static void GAPI_PaletteChanged(_THIS, HWND window) |
| 1227 | { |
| 1228 | OutputDebugString(TEXT("GAPI_PaletteChanged NOT IMPLEMENTED !\r\n")); |
| 1229 | } |
| 1230 | |
| 1231 | static 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 | |
| 1283 | int GAPI_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors) |
| 1284 | { |
| 1285 | GAPI_CreatePalette(ncolors, colors); |
| 1286 | return 1; |
| 1287 | } |