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 Library General Public 7 License as published by the Free Software Foundation; either 8 version 2 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 Library General Public License for more details. 14 15 You should have received a copy of the GNU Library General Public 16 License along with this library; if not, write to the Free 17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 19 Sam Lantinga 20 slouken (at) devolution.com 21 */ 22 23 /* 24 SDL_epocvideo.cpp 25 Epoc based SDL video driver implementation 26 27 Markus Mertama 28 */ 29 30 31 32 #include "epoc_sdl.h" 33 34 #include <stdlib.h> 35 #include <stdio.h> 36 #include <string.h> 37 38 extern "C" { 39 #include "SDL_error.h" 40 #include "SDL_timer.h" 41 #include "SDL_video.h" 42 #undef NULL 43 #include "SDL_pixels_c.h" 44 #include "SDL.h" 45 #include "SDL_mouse.h" 46 } 47 48 #include "SDL_epocvideo.h" 49 #include "SDL_epocevents_c.h" 50 51 52 53 #include <coedef.h> 54 #include <flogger.h> 55 56 #include <eikenv.h> 57 #include <eikappui.h> 58 #include <eikapp.h> 59 #include "sdlepocapi.h" 60 61 62 //////////////////////////////////////////////////////////////// 63 64 65 66 67 _LIT(KLibName, "SDL"); 68 69 void RDebug_Print_b(char* error_str, void* param) 70 { 71 TBuf8<128> error8((TUint8*)error_str); 72 TBuf<128> error; 73 error.Copy(error8); 74 75 #ifndef TRACE_TO_FILE 76 if (param) //!! Do not work if the parameter is really 0!! 77 RDebug::Print(error, param); 78 else 79 RDebug::Print(error); 80 #else 81 if (param) //!! Do not work if the parameter is really 0!! 82 RFileLogger::WriteFormat(KLibName, _L("SDL.txt"), EFileLoggingModeAppend, error, param); 83 else 84 RFileLogger::Write(KLibName, _L("SDL.txt"), EFileLoggingModeAppend, error); 85 #endif 86 87 } 88 89 extern "C" void RDebug_Print(char* error_str, void* param) 90 { 91 RDebug_Print_b(error_str, param); 92 } 93 94 /* 95 int Debug_AvailMem2() 96 { 97 //User::CompressAllHeaps(); 98 TMemoryInfoV1Buf membuf; 99 User::LeaveIfError(UserHal::MemoryInfo(membuf)); 100 TMemoryInfoV1 minfo = membuf(); 101 return(minfo.iFreeRamInBytes); 102 } 103 104 extern "C" int Debug_AvailMem() 105 { 106 return(Debug_AvailMem2()); 107 } 108 109 */ 110 111 extern "C" { 112 113 /* Initialization/Query functions */ 114 115 static int EPOC_VideoInit(_THIS, SDL_PixelFormat *vformat); 116 static SDL_Rect **EPOC_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags); 117 static SDL_Surface *EPOC_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags); 118 static int EPOC_SetColors(_THIS, int firstcolor, int ncolors, 119 SDL_Color *colors); 120 static void EPOC_VideoQuit(_THIS); 121 122 /* Hardware surface functions */ 123 124 static int EPOC_AllocHWSurface(_THIS, SDL_Surface *surface); 125 static int EPOC_LockHWSurface(_THIS, SDL_Surface *surface); 126 static int EPOC_FlipHWSurface(_THIS, SDL_Surface *surface); 127 static void EPOC_UnlockHWSurface(_THIS, SDL_Surface *surface); 128 static void EPOC_FreeHWSurface(_THIS, SDL_Surface *surface); 129 static void EPOC_DirectUpdate(_THIS, int numrects, SDL_Rect *rects); 130 131 static int EPOC_Available(void); 132 static SDL_VideoDevice *EPOC_CreateDevice(int devindex); 133 134 void DrawBackground(_THIS); 135 void DirectDraw(_THIS, int numrects, SDL_Rect *rects, TUint16* screenBuffer); 136 void DirectDrawRotated(_THIS, int numrects, SDL_Rect *rects, TUint16* screenBuffer); 137 138 /* Mouse functions */ 139 140 static WMcursor *EPOC_CreateWMCursor(_THIS, Uint8 *data, Uint8 *mask, int w, int h, int hot_x, int hot_y); 141 static void EPOC_FreeWMCursor(_THIS, WMcursor *cursor); 142 static int EPOC_ShowWMCursor(_THIS, WMcursor *cursor); 143 } 144 145 146 extern "C" 147 { 148 struct WMcursor 149 { 150 }; 151 } 152 153 /* Epoc video driver bootstrap functions */ 154 155 156 static int EPOC_Available(void) 157 { 158 return 1; /* Always available */ 159 } 160 161 static void EPOC_DeleteDevice(SDL_VideoDevice *device) 162 { 163 User::Free(device->hidden); 164 User::Free(device); 165 } 166 167 static SDL_VideoDevice *EPOC_CreateDevice(int /*devindex*/) 168 { 169 SDL_VideoDevice *device; 170 171 SDL_TRACE("SDL:EPOC_CreateDevice"); 172 173 /* Allocate all variables that we free on delete */ 174 device = static_cast<SDL_VideoDevice*>(User::Alloc(sizeof(SDL_VideoDevice))); 175 if ( device ) 176 { 177 Mem::FillZ(device, (sizeof *device)); 178 device->hidden = static_cast<struct SDL_PrivateVideoData*> 179 (User::Alloc((sizeof *device->hidden))); 180 } 181 if ( (device == NULL) || (device->hidden == NULL) ) 182 { 183 SDL_OutOfMemory(); 184 if ( device ) { 185 User::Free(device); 186 } 187 return(0); 188 } 189 Mem::FillZ(device->hidden, (sizeof *device->hidden)); 190 191 /* Set the function pointers */ 192 device->VideoInit = EPOC_VideoInit; 193 device->ListModes = EPOC_ListModes; 194 device->SetVideoMode = EPOC_SetVideoMode; 195 device->SetColors = EPOC_SetColors; 196 device->UpdateRects = NULL; 197 device->VideoQuit = EPOC_VideoQuit; 198 device->AllocHWSurface = EPOC_AllocHWSurface; 199 device->CheckHWBlit = NULL; 200 device->FillHWRect = NULL; 201 device->SetHWColorKey = NULL; 202 device->SetHWAlpha = NULL; 203 device->LockHWSurface = EPOC_LockHWSurface; 204 device->UnlockHWSurface = EPOC_UnlockHWSurface; 205 device->FlipHWSurface = EPOC_FlipHWSurface; 206 device->FreeHWSurface = EPOC_FreeHWSurface; 207 device->SetIcon = NULL; 208 device->SetCaption = NULL; 209 device->GetWMInfo = NULL; 210 device->FreeWMCursor = EPOC_FreeWMCursor; 211 device->CreateWMCursor = EPOC_CreateWMCursor; 212 device->ShowWMCursor = EPOC_ShowWMCursor; 213 device->WarpWMCursor = NULL; 214 device->InitOSKeymap = EPOC_InitOSKeymap; 215 device->PumpEvents = EPOC_PumpEvents; 216 device->free = EPOC_DeleteDevice; 217 218 return device; 219 } 220 221 222 VideoBootStrap EPOC_bootstrap = { 223 "epoc\0\0\0", "EPOC system", 224 EPOC_Available, EPOC_CreateDevice 225 }; 226 227 228 229 void DisableKeyBlocking(_THIS) 230 { 231 EpocSdlEnv::Request(EpocSdlEnv::EDisableKeyBlocking); 232 } 233 234 void ConstructWindowL(_THIS) 235 { 236 SDL_TRACE("SDL:ConstructWindowL"); 237 DisableKeyBlocking(_this); //disable key blocking 238 } 239 240 241 int EPOC_VideoInit(_THIS, SDL_PixelFormat *vformat) 242 { 243 /* Construct Epoc window */ 244 245 ConstructWindowL(_this); 246 247 /* Initialise Epoc frame buffer */ 248 249 250 const TDisplayMode displayMode = EpocSdlEnv::DisplayMode(); 251 252 /* The "best" video format should be returned to caller. */ 253 254 vformat->BitsPerPixel = TDisplayModeUtils::NumDisplayModeBitsPerPixel(displayMode); 255 vformat->BytesPerPixel = TDisplayModeUtils::NumDisplayModeBitsPerPixel(displayMode) / 8; 256 257 258 //?? Private->iWindow->PointerFilter(EPointerFilterDrag, 0); 259 260 Private->iScreenPos = TPoint(0, 0); 261 262 Private->iRect.x = Private->iScreenPos.iX; 263 Private->iRect.y = Private->iScreenPos.iY; 264 265 const TSize sz = EpocSdlEnv::WindowSize(); 266 267 Private->iRect.w = sz.iWidth; 268 Private->iRect.h = sz.iHeight; 269 Private->iRectPtr = &Private->iRect; 270 271 return(0); 272 } 273 274 275 SDL_Rect **EPOC_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags) 276 { 277 if(flags & SDL_HWSURFACE) 278 { 279 if(format->BytesPerPixel != 4) //in HW only full color is supported 280 return NULL; 281 } 282 if(flags & SDL_FULLSCREEN) 283 { 284 return &Private->iRectPtr; 285 } 286 return (SDL_Rect **)(-1); //everythingisok, unless too small shoes 287 } 288 289 290 int EPOC_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors) 291 { 292 if ((firstcolor+ncolors) > 256) 293 return -1; 294 TUint32 palette[256]; 295 const TDisplayMode mode = EpocSdlEnv::DisplayMode(); 296 if(TDisplayModeUtils::NumDisplayModeColors(mode) == 4096) 297 { 298 // Set 12 bit palette 299 for(int i = firstcolor; i < ncolors; i++) 300 { 301 // 4k value: 0000 rrrr gggg bbbb 302 TUint32 color4K = (colors[i].r & 0x0000f0) << 4; 303 color4K |= (colors[i].g & 0x0000f0); 304 color4K |= (colors[i].b & 0x0000f0) >> 4; 305 palette[i] = color4K; 306 } 307 } 308 else if(TDisplayModeUtils::NumDisplayModeColors(mode) == 65536) 309 { 310 for(int i = firstcolor; i < ncolors; i++) 311 { 312 // 64k-colour displays effectively support RGB values 313 // with 5 bits allocated to red, 6 to green and 5 to blue 314 // 64k value: rrrr rggg gggb bbbb 315 TUint32 color64K = (colors[i].r & 0x0000f8) << 8; 316 color64K |= (colors[i].g & 0x0000fc) << 3; 317 color64K |= (colors[i].b & 0x0000f8) >> 3; 318 palette[i] = color64K; 319 } 320 } 321 else if(TDisplayModeUtils::NumDisplayModeColors(mode) == 16777216) 322 { 323 for(int i = firstcolor; i < ncolors; i++) 324 { 325 // 16M-colour 326 //0000 0000 rrrr rrrr gggg gggg bbbb bbbb 327 TUint32 color16M = colors[i].r << 16; 328 color16M |= colors[i].g << 8; 329 color16M |= colors[i].b; 330 palette[i] = color16M; 331 } 332 } 333 else 334 { 335 return -2; 336 } 337 if(EpocSdlEnv::SetPalette(firstcolor, ncolors, palette) == KErrNone) 338 return 0; 339 return -1; 340 } 341 342 343 /* 344 void AllocHWSurfaceL(CFbsBitmap*& aBitmap, const TDisplayMode& aMode, const TSize& aSize) 345 { 346 aBitmap = new (ELeave) CFbsBitmap(); 347 if(KErrNone != aBitmap->CreateHardwareBitmap(aSize, aMode, 348 EpocSdlEnv::EikonEnv().EikAppUi()->Application()->AppDllUid())) 349 //...if it fails - should we use wsbitmaps??? 350 {//the good reason to use hw bitmaps is that they wont need lock heap 351 PANIC_IF_ERROR(aBitmap->Create(aSize, aMode)); 352 } 353 } 354 355 int CreateSurfaceL(_THIS, SDL_Surface* surface) 356 { 357 __ASSERT_ALWAYS(Private->iFrame == NULL, PANIC(KErrAlreadyExists)); 358 ; 359 TInt dmode = EColorLast; 360 361 TDisplayMode displayMode; 362 EpocSdlEnv::GetDiplayMode(displayMode); 363 364 if( 365 TDisplayModeUtils::NumDisplayModeBitsPerPixel(displayMode) 366 == surface->format->BitsPerPixel) 367 { 368 dmode = displayMode; 369 } 370 else 371 { 372 --dmode; 373 while(TDisplayModeUtils::IsDisplayModeColor(TDisplayMode(dmode)) && 374 TDisplayModeUtils::NumDisplayModeBitsPerPixel(TDisplayMode(dmode)) != 375 surface->format->BitsPerPixel) 376 --dmode; 377 } 378 379 __ASSERT_ALWAYS(TDisplayModeUtils::IsDisplayModeColor(TDisplayMode(dmode)), PANIC(KErrNotSupported)); 380 TRAPD(err, AllocHWSurfaceL(Private->iFrame, TDisplayMode(dmode), TSize(surface->w, surface->h))); 381 return err == KErrNone ? 0 : -1; 382 } 383 */ 384 385 TDisplayMode GetDisplayMode(TInt aBitsPerPixel) 386 { 387 const TDisplayMode displayMode = EpocSdlEnv::DisplayMode(); 388 TInt dmode = EColorLast; 389 if( 390 TDisplayModeUtils::NumDisplayModeBitsPerPixel(displayMode) 391 == aBitsPerPixel) 392 { 393 dmode = displayMode; 394 } 395 else 396 { 397 --dmode; 398 while(TDisplayModeUtils::IsDisplayModeColor(TDisplayMode(dmode)) && 399 TDisplayModeUtils::NumDisplayModeBitsPerPixel(TDisplayMode(dmode)) != 400 aBitsPerPixel) 401 --dmode; 402 } 403 return TDisplayMode(dmode); 404 } 405 406 SDL_Surface *EPOC_SetVideoMode(_THIS, SDL_Surface *current, 407 int width, int height, int bpp, Uint32 flags) 408 { 409 const TSize screenSize = EpocSdlEnv::WindowSize(TSize(width, height)); 410 if(width > screenSize.iWidth || height > screenSize.iHeight) 411 { 412 if(flags & SDL_FULLSCREEN) 413 { 414 width = screenSize.iWidth; 415 height = screenSize.iHeight; 416 } 417 else 418 return NULL; 419 } 420 421 if(current && current->pixels) 422 { 423 // free(current->pixels); 424 current->pixels = NULL; 425 } 426 427 if(!SDL_ReallocFormat(current, bpp, 0, 0, 0, 0)) 428 { 429 return(NULL); 430 } 431 432 current->flags = 0; 433 if(width == screenSize.iWidth && height == screenSize.iHeight) 434 current->flags |= SDL_FULLSCREEN; 435 436 const int numBytesPerPixel = ((bpp-1)>>3) + 1; 437 current->pitch = numBytesPerPixel * width; // Number of bytes in scanline 438 439 /* Set up the new mode framebuffer */ 440 current->flags |= SDL_PREALLOC; 441 442 if(bpp <= 8) 443 current->flags |= SDL_HWPALETTE; 444 445 User::Free(Private->iSwSurface); 446 current->pixels = NULL; 447 Private->iSwSurface = NULL; 448 449 if(flags & SDL_HWSURFACE) 450 { 451 current->flags |= SDL_HWSURFACE; 452 // current->pixels = NULL; 453 // Private->iSwSurface = NULL; 454 } 455 else 456 { 457 current->flags |= SDL_SWSURFACE; 458 const TInt surfacesize = width * height * numBytesPerPixel; 459 Private->iSwSurfaceSize = TSize(width, height); 460 delete Private->iSwSurface; 461 Private->iSwSurface = NULL; 462 current->pixels = (TUint8*) User::AllocL(surfacesize); 463 Private->iSwSurface = (TUint8*) current->pixels; 464 const TInt err = EpocSdlEnv::AllocSwSurface 465 (TSize(width, height), GetDisplayMode(current->format->BitsPerPixel)); 466 if(err != KErrNone) 467 return NULL; 468 } 469 470 current->w = width; 471 current->h = height; 472 473 474 475 /* Set the blit function */ 476 _this->UpdateRects = EPOC_DirectUpdate; 477 478 /* 479 * Logic for getting suitable screen dimensions, offset, scaling and orientation 480 */ 481 482 483 /* Centralize game window on device screen */ 484 485 486 Private->iScreenPos.iX = Max(0, (screenSize.iWidth - width) / 2); 487 Private->iScreenPos.iY = Max(0, (screenSize.iHeight - height) / 2); 488 489 // delete (Private->iFrame); 490 // Private->iFrame = NULL; 491 492 // TRAPD(err, CreateSurfaceL(_this, current)); 493 // PANIC_IF_ERROR(err); 494 495 SDL_TRACE1("View width %d", width); 496 SDL_TRACE1("View height %d", height); 497 SDL_TRACE1("View bmode %d", bpp); 498 SDL_TRACE1("View x %d", Private->iScreenPos.iX); 499 SDL_TRACE1("View y %d", Private->iScreenPos.iY); 500 501 EpocSdlEnv::LockPalette(EFalse); 502 /* We're done */ 503 return(current); 504 } 505 506 507 508 static int EPOC_AllocHWSurface(_THIS, SDL_Surface* surface) 509 { 510 return KErrNone == EpocSdlEnv::AllocHwSurface(TSize(surface->w, surface->h), GetDisplayMode(surface->format->BitsPerPixel)); 511 } 512 513 static void EPOC_FreeHWSurface(_THIS, SDL_Surface* /*surface*/) 514 { 515 } 516 517 static int EPOC_LockHWSurface(_THIS, SDL_Surface* surface) 518 { 519 if(EpocSdlEnv::IsDsaAvailable()) 520 { 521 TUint8* address = EpocSdlEnv::LockHwSurface(); 522 if(address != NULL) 523 { 524 surface->pixels = address; 525 return 1; 526 } 527 } 528 return 0; 529 } 530 static void EPOC_UnlockHWSurface(_THIS, SDL_Surface* /*surface*/) 531 { 532 EpocSdlEnv::UnlockHwSurface(); 533 } 534 535 static int EPOC_FlipHWSurface(_THIS, SDL_Surface* /*surface*/) 536 { 537 return(0); 538 } 539 540 static void EPOC_DirectUpdate(_THIS, int numrects, SDL_Rect *rects) 541 { 542 if(EpocSdlEnv::IsDsaAvailable()) 543 { 544 if(Private->iSwSurface) 545 { 546 const TRect target(Private->iScreenPos, Private->iSwSurfaceSize); 547 for(TInt i = 0; i < numrects ;i++) 548 { 549 const TRect rect(TPoint(rects[i].x, rects[i].y), 550 TSize(rects[i].w, rects[i].h)); 551 if(!EpocSdlEnv::AddUpdateRect(Private->iSwSurface, rect, target)) 552 return; //not succesful 553 } 554 EpocSdlEnv::UpdateSwSurface(); 555 } 556 SDL_PauseAudio(0); 557 } 558 else 559 { 560 SDL_PauseAudio(1); 561 EpocSdlEnv::WaitDsaAvailable(); 562 } 563 } 564 565 566 /* Note: If we are terminated, this could be called in the middle of 567 another SDL video routine -- notably UpdateRects. 568 */ 569 void EPOC_VideoQuit(_THIS) 570 { 571 // delete Private->iFrame; 572 // Private->iFrame = NULL; 573 User::Free(Private->iSwSurface); 574 Private->iSwSurface = NULL; 575 EpocSdlEnv::FreeSurface(); 576 } 577 578 579 580 581 WMcursor *EPOC_CreateWMCursor(_THIS, Uint8* /*data*/, Uint8* /*mask*/, int /*w*/, int /*h*/, int /*hot_x*/, int /*hot_y*/) 582 { 583 return (WMcursor*) 1; //hii! prevents SDL to view a std cursor 584 } 585 586 void EPOC_FreeWMCursor(_THIS, WMcursor* /*cursor*/) 587 { 588 } 589 590 int EPOC_ShowWMCursor(_THIS, WMcursor *cursor) 591 { 592 return true; 593 } 594 595