video.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140
  1. /* -*- mode: c; tab-width: 4; c-basic-offset: 3; c-file-style: "linux" -*- */
  2. //
  3. // Copyright (c) 2009, Wei Mingzhi <whistler_wmz@users.sf.net>.
  4. // All rights reserved.
  5. //
  6. // This file is part of SDLPAL.
  7. //
  8. // SDLPAL is free software: you can redistribute it and/or modify
  9. // it under the terms of the GNU General Public License as published by
  10. // the Free Software Foundation, either version 3 of the License, or
  11. // (at your option) any later version.
  12. //
  13. // This program is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. // GNU General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU General Public License
  19. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. //
  21. #include "main.h"
  22. // Screen buffer
  23. SDL_Surface *gpScreen = NULL;
  24. // Backup screen buffer
  25. SDL_Surface *gpScreenBak = NULL;
  26. #if SDL_VERSION_ATLEAST(2,0,0)
  27. SDL_Window *gpWindow = NULL;
  28. static SDL_Renderer *gpRenderer = NULL;
  29. static SDL_Texture *gpTexture = NULL;
  30. # if PAL_HAS_TOUCH
  31. static SDL_Texture *gpTouchOverlay = NULL;
  32. # endif
  33. static SDL_Rect *gpRenderRect = NULL;
  34. static SDL_Rect gRenderRect;
  35. #endif
  36. // The real screen surface
  37. static SDL_Surface *gpScreenReal = NULL;
  38. volatile BOOL g_bRenderPaused = FALSE;
  39. #if (defined (__SYMBIAN32__) && !defined (__S60_5X__)) || defined (PSP) || defined (GEKKO)
  40. static BOOL bScaleScreen = FALSE;
  41. #else
  42. static BOOL bScaleScreen = TRUE;
  43. #endif
  44. // Shake times and level
  45. static WORD g_wShakeTime = 0;
  46. static WORD g_wShakeLevel = 0;
  47. #if SDL_VERSION_ATLEAST(2, 0, 0)
  48. #define SDL_SoftStretch SDL_UpperBlit
  49. #endif
  50. INT
  51. VIDEO_Startup(
  52. VOID
  53. )
  54. /*++
  55. Purpose:
  56. Initialze the video subsystem.
  57. Parameters:
  58. None.
  59. Return value:
  60. 0 = success, -1 = fail to create the screen surface,
  61. -2 = fail to create screen buffer.
  62. --*/
  63. {
  64. #if SDL_VERSION_ATLEAST(2,0,0)
  65. //
  66. // Before we can render anything, we need a window and a renderer.
  67. //
  68. gpWindow = SDL_CreateWindow("Pal", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
  69. gConfig.dwScreenWidth, gConfig.dwScreenHeight, PAL_VIDEO_INIT_FLAGS);
  70. if (gpWindow == NULL)
  71. {
  72. return -1;
  73. }
  74. gpRenderer = SDL_CreateRenderer(gpWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
  75. if (gpRenderer == NULL)
  76. {
  77. return -1;
  78. }
  79. #if defined (__IOS__)
  80. SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
  81. SDL_GL_SetAttribute(SDL_GL_RETAINED_BACKING, 1);
  82. #endif
  83. //
  84. // Create the screen buffer and the backup screen buffer.
  85. //
  86. gpScreen = SDL_CreateRGBSurface(SDL_SWSURFACE, 320, 200, 8, 0, 0, 0, 0);
  87. gpScreenBak = SDL_CreateRGBSurface(SDL_SWSURFACE, 320, 200, 8, 0, 0, 0, 0);
  88. gpScreenReal = SDL_CreateRGBSurface(SDL_SWSURFACE, 320, 200, 32,
  89. 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
  90. //
  91. // Create texture for screen.
  92. //
  93. gpTexture = SDL_CreateTexture(gpRenderer, SDL_PIXELFORMAT_ARGB8888,
  94. SDL_TEXTUREACCESS_STREAMING, 320, 200);
  95. //
  96. // Failed?
  97. //
  98. if (gpScreen == NULL || gpScreenBak == NULL || gpScreenReal == NULL || gpTexture == NULL)
  99. {
  100. if (gpScreen != NULL)
  101. {
  102. SDL_FreeSurface(gpScreen);
  103. gpScreen = NULL;
  104. }
  105. if (gpScreenBak != NULL)
  106. {
  107. SDL_FreeSurface(gpScreenBak);
  108. gpScreenBak = NULL;
  109. }
  110. if (gpScreenReal != NULL)
  111. {
  112. SDL_FreeSurface(gpScreenReal);
  113. gpScreenReal = NULL;
  114. }
  115. if (gpTexture != NULL)
  116. {
  117. SDL_DestroyTexture(gpTexture);
  118. gpTexture = NULL;
  119. }
  120. SDL_DestroyRenderer(gpRenderer);
  121. gpRenderer = NULL;
  122. SDL_DestroyWindow(gpWindow);
  123. gpWindow = NULL;
  124. return -2;
  125. }
  126. //
  127. // Create texture for overlay.
  128. //
  129. #if PAL_HAS_TOUCH
  130. if (gConfig.fUseTouchOverlay)
  131. {
  132. extern const void * PAL_LoadOverlayBMP(void);
  133. extern int PAL_OverlayBMPLength();
  134. SDL_Surface *overlay = SDL_LoadBMP_RW(SDL_RWFromConstMem(PAL_LoadOverlayBMP(), PAL_OverlayBMPLength()), 1);
  135. if (overlay != NULL)
  136. {
  137. SDL_SetColorKey(overlay, SDL_RLEACCEL, SDL_MapRGB(overlay->format, 255, 0, 255));
  138. gpTouchOverlay = SDL_CreateTextureFromSurface(gpRenderer, overlay);
  139. SDL_SetTextureAlphaMod(gpTouchOverlay, 120);
  140. SDL_FreeSurface(overlay);
  141. }
  142. }
  143. #endif
  144. //
  145. // Check whether to keep the aspect ratio
  146. //
  147. if (gConfig.fKeepAspectRatio)
  148. {
  149. float ax = (float)gConfig.dwScreenWidth / 320.0f;
  150. float ay = (float)gConfig.dwScreenHeight / 200.0f;
  151. if (ax != ay)
  152. {
  153. float ratio = (ax > ay) ? ay : ax;
  154. WORD w = (WORD)(ratio * 320.0f);
  155. WORD h = (WORD)(ratio * 200.0f);
  156. if (w % 4 != 0) w &= ~0x3;
  157. if (h % 4 != 0) h &= ~0x3;
  158. gRenderRect.x = (gConfig.dwScreenWidth - w) / 2;
  159. gRenderRect.y = (gConfig.dwScreenHeight - h) / 2;
  160. gRenderRect.w = w;
  161. gRenderRect.h = h;
  162. gpRenderRect = &gRenderRect;
  163. # if PAL_HAS_TOUCH
  164. PAL_SetTouchBounds(gConfig.dwScreenWidth, gConfig.dwScreenHeight, gRenderRect);
  165. # endif
  166. }
  167. }
  168. else
  169. gpRenderRect = NULL;
  170. #else
  171. //
  172. // Create the screen surface.
  173. //
  174. gpScreenReal = SDL_SetVideoMode(gConfig.dwScreenWidth, gConfig.dwScreenHeight, 8, PAL_VIDEO_INIT_FLAGS);
  175. if (gpScreenReal == NULL)
  176. {
  177. //
  178. // Fall back to 640x480 software mode.
  179. //
  180. gpScreenReal = SDL_SetVideoMode(640, 480, 8,
  181. SDL_SWSURFACE | (gConfig.fFullScreen ? SDL_FULLSCREEN : 0));
  182. }
  183. //
  184. // Still fail?
  185. //
  186. if (gpScreenReal == NULL)
  187. {
  188. return -1;
  189. }
  190. //
  191. // Create the screen buffer and the backup screen buffer.
  192. //
  193. gpScreen = SDL_CreateRGBSurface(gpScreenReal->flags & ~SDL_HWSURFACE, 320, 200, 8,
  194. gpScreenReal->format->Rmask, gpScreenReal->format->Gmask,
  195. gpScreenReal->format->Bmask, gpScreenReal->format->Amask);
  196. gpScreenBak = SDL_CreateRGBSurface(gpScreenReal->flags & ~SDL_HWSURFACE, 320, 200, 8,
  197. gpScreenReal->format->Rmask, gpScreenReal->format->Gmask,
  198. gpScreenReal->format->Bmask, gpScreenReal->format->Amask);
  199. //
  200. // Failed?
  201. //
  202. if (gpScreen == NULL || gpScreenBak == NULL)
  203. {
  204. if (gpScreen != NULL)
  205. {
  206. SDL_FreeSurface(gpScreen);
  207. gpScreen = NULL;
  208. }
  209. if (gpScreenBak != NULL)
  210. {
  211. SDL_FreeSurface(gpScreenBak);
  212. gpScreenBak = NULL;
  213. }
  214. SDL_FreeSurface(gpScreenReal);
  215. gpScreenReal = NULL;
  216. return -2;
  217. }
  218. if (gConfig.fFullScreen)
  219. {
  220. SDL_ShowCursor(FALSE);
  221. }
  222. #endif
  223. return 0;
  224. }
  225. VOID
  226. VIDEO_Shutdown(
  227. VOID
  228. )
  229. /*++
  230. Purpose:
  231. Shutdown the video subsystem.
  232. Parameters:
  233. None.
  234. Return value:
  235. None.
  236. --*/
  237. {
  238. if (gpScreen != NULL)
  239. {
  240. SDL_FreeSurface(gpScreen);
  241. }
  242. gpScreen = NULL;
  243. if (gpScreenBak != NULL)
  244. {
  245. SDL_FreeSurface(gpScreenBak);
  246. }
  247. gpScreenBak = NULL;
  248. #if SDL_VERSION_ATLEAST(2,0,0)
  249. # if PAL_HAS_TOUCH
  250. if (gpTouchOverlay)
  251. {
  252. SDL_DestroyTexture(gpTouchOverlay);
  253. }
  254. gpTouchOverlay = NULL;
  255. # endif
  256. if (gpTexture)
  257. {
  258. SDL_DestroyTexture(gpTexture);
  259. }
  260. gpTexture = NULL;
  261. if (gpRenderer)
  262. {
  263. SDL_DestroyRenderer(gpRenderer);
  264. }
  265. gpRenderer = NULL;
  266. if (gpWindow)
  267. {
  268. SDL_DestroyWindow(gpWindow);
  269. }
  270. gpWindow = NULL;
  271. #endif
  272. if (gpScreenReal != NULL)
  273. {
  274. SDL_FreeSurface(gpScreenReal);
  275. }
  276. gpScreenReal = NULL;
  277. }
  278. #if SDL_VERSION_ATLEAST(2,0,0)
  279. PAL_FORCE_INLINE
  280. VOID
  281. VIDEO_RenderCopy(
  282. VOID
  283. )
  284. {
  285. SDL_UpdateTexture(gpTexture, NULL, gpScreenReal->pixels, gpScreenReal->pitch);
  286. SDL_RenderCopy(gpRenderer, gpTexture, NULL, gpRenderRect);
  287. #if PAL_HAS_TOUCH
  288. if (gpTouchOverlay)
  289. {
  290. SDL_RenderCopy(gpRenderer, gpTouchOverlay, NULL, gpRenderRect);
  291. }
  292. #endif
  293. SDL_RenderPresent(gpRenderer);
  294. }
  295. #endif
  296. VOID
  297. VIDEO_UpdateScreen(
  298. const SDL_Rect *lpRect
  299. )
  300. /*++
  301. Purpose:
  302. Update the screen area specified by lpRect.
  303. Parameters:
  304. [IN] lpRect - Screen area to update.
  305. Return value:
  306. None.
  307. --*/
  308. {
  309. SDL_Rect srcrect, dstrect;
  310. short offset = 240 - 200;
  311. short screenRealHeight = gpScreenReal->h;
  312. short screenRealY = 0;
  313. #if SDL_VERSION_ATLEAST(2,0,0)
  314. if (g_bRenderPaused)
  315. {
  316. return;
  317. }
  318. #endif
  319. //
  320. // Lock surface if needed
  321. //
  322. if (SDL_MUSTLOCK(gpScreenReal))
  323. {
  324. if (SDL_LockSurface(gpScreenReal) < 0)
  325. return;
  326. }
  327. if (!bScaleScreen)
  328. {
  329. screenRealHeight -= offset;
  330. screenRealY = offset / 2;
  331. }
  332. if (lpRect != NULL)
  333. {
  334. dstrect.x = (SHORT)((INT)(lpRect->x) * gpScreenReal->w / gpScreen->w);
  335. dstrect.y = (SHORT)((INT)(screenRealY + lpRect->y) * screenRealHeight / gpScreen->h);
  336. dstrect.w = (WORD)((DWORD)(lpRect->w) * gpScreenReal->w / gpScreen->w);
  337. dstrect.h = (WORD)((DWORD)(lpRect->h) * screenRealHeight / gpScreen->h);
  338. SDL_SoftStretch(gpScreen, (SDL_Rect *)lpRect, gpScreenReal, &dstrect);
  339. }
  340. else if (g_wShakeTime != 0)
  341. {
  342. //
  343. // Shake the screen
  344. //
  345. srcrect.x = 0;
  346. srcrect.y = 0;
  347. srcrect.w = 320;
  348. srcrect.h = 200 - g_wShakeLevel;
  349. dstrect.x = 0;
  350. dstrect.y = screenRealY;
  351. dstrect.w = 320 * gpScreenReal->w / gpScreen->w;
  352. dstrect.h = (200 - g_wShakeLevel) * screenRealHeight / gpScreen->h;
  353. if (g_wShakeTime & 1)
  354. {
  355. srcrect.y = g_wShakeLevel;
  356. }
  357. else
  358. {
  359. dstrect.y = (screenRealY + g_wShakeLevel) * screenRealHeight / gpScreen->h;
  360. }
  361. SDL_SoftStretch(gpScreen, &srcrect, gpScreenReal, &dstrect);
  362. if (g_wShakeTime & 1)
  363. {
  364. dstrect.y = (screenRealY + screenRealHeight - g_wShakeLevel) * screenRealHeight / gpScreen->h;
  365. }
  366. else
  367. {
  368. dstrect.y = screenRealY;
  369. }
  370. dstrect.h = g_wShakeLevel * screenRealHeight / gpScreen->h;
  371. SDL_FillRect(gpScreenReal, &dstrect, 0);
  372. #if SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION <= 2
  373. dstrect.x = dstrect.y = 0;
  374. dstrect.w = gpScreenReal->w;
  375. dstrect.h = gpScreenReal->h;
  376. #endif
  377. g_wShakeTime--;
  378. }
  379. else
  380. {
  381. dstrect.x = 0;
  382. dstrect.y = screenRealY;
  383. dstrect.w = gpScreenReal->w;
  384. dstrect.h = screenRealHeight;
  385. SDL_SoftStretch(gpScreen, NULL, gpScreenReal, &dstrect);
  386. #if SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION <= 2
  387. dstrect.x = dstrect.y = 0;
  388. dstrect.w = gpScreenReal->w;
  389. dstrect.h = gpScreenReal->h;
  390. #endif
  391. }
  392. #if SDL_VERSION_ATLEAST(2,0,0)
  393. VIDEO_RenderCopy();
  394. #else
  395. SDL_UpdateRect(gpScreenReal, dstrect.x, dstrect.y, dstrect.w, dstrect.h);
  396. #endif
  397. if (SDL_MUSTLOCK(gpScreenReal))
  398. {
  399. SDL_UnlockSurface(gpScreenReal);
  400. }
  401. }
  402. VOID
  403. VIDEO_SetPalette(
  404. SDL_Color rgPalette[256]
  405. )
  406. /*++
  407. Purpose:
  408. Set the palette of the screen.
  409. Parameters:
  410. [IN] rgPalette - array of 256 colors.
  411. Return value:
  412. None.
  413. --*/
  414. {
  415. #if SDL_VERSION_ATLEAST(2,0,0)
  416. SDL_Palette *palette = SDL_AllocPalette(256);
  417. if (palette == NULL)
  418. {
  419. return;
  420. }
  421. SDL_SetPaletteColors(palette, rgPalette, 0, 256);
  422. SDL_SetSurfacePalette(gpScreen, palette);
  423. SDL_SetSurfacePalette(gpScreenBak, palette);
  424. //
  425. // HACKHACK: need to invalidate gpScreen->map otherwise the palette
  426. // would not be effective during blit
  427. //
  428. SDL_SetSurfaceColorMod(gpScreen, 0, 0, 0);
  429. SDL_SetSurfaceColorMod(gpScreen, 0xFF, 0xFF, 0xFF);
  430. SDL_SetSurfaceColorMod(gpScreenBak, 0, 0, 0);
  431. SDL_SetSurfaceColorMod(gpScreenBak, 0xFF, 0xFF, 0xFF);
  432. VIDEO_UpdateScreen(NULL);
  433. // The palette should be freed, or memory leak occurs.
  434. SDL_FreePalette(palette);
  435. #else
  436. SDL_SetPalette(gpScreen, SDL_LOGPAL | SDL_PHYSPAL, rgPalette, 0, 256);
  437. SDL_SetPalette(gpScreenBak, SDL_LOGPAL | SDL_PHYSPAL, rgPalette, 0, 256);
  438. SDL_SetPalette(gpScreenReal, SDL_LOGPAL | SDL_PHYSPAL, rgPalette, 0, 256);
  439. #if (defined (__SYMBIAN32__))
  440. {
  441. static UINT32 time = 0;
  442. if (SDL_GetTicks() - time > 50)
  443. {
  444. SDL_UpdateRect(gpScreenReal, 0, 0, gpScreenReal->w, gpScreenReal->h);
  445. time = SDL_GetTicks();
  446. }
  447. }
  448. #endif
  449. #endif
  450. }
  451. VOID
  452. VIDEO_Resize(
  453. INT w,
  454. INT h
  455. )
  456. /*++
  457. Purpose:
  458. This function is called when user resized the window.
  459. Parameters:
  460. [IN] w - width of the window after resizing.
  461. [IN] h - height of the window after resizing.
  462. Return value:
  463. None.
  464. --*/
  465. {
  466. #if SDL_VERSION_ATLEAST(2,0,0)
  467. // TODO
  468. #else
  469. DWORD flags;
  470. PAL_LARGE SDL_Color palette[256];
  471. int i;
  472. //
  473. // Get the original palette.
  474. //
  475. for (i = 0; i < gpScreenReal->format->palette->ncolors; i++)
  476. {
  477. palette[i] = gpScreenReal->format->palette->colors[i];
  478. }
  479. //
  480. // Create the screen surface.
  481. //
  482. flags = gpScreenReal->flags;
  483. SDL_FreeSurface(gpScreenReal);
  484. gpScreenReal = SDL_SetVideoMode(w, h, 8, flags);
  485. if (gpScreenReal == NULL)
  486. {
  487. #ifdef __SYMBIAN32__
  488. #ifdef __S60_5X__
  489. gpScreenReal = SDL_SetVideoMode(640, 360, 8, SDL_SWSURFACE);
  490. #else
  491. gpScreenReal = SDL_SetVideoMode(320, 240, 8, SDL_SWSURFACE);
  492. #endif
  493. #else
  494. //
  495. // Fall back to 640x480 software windowed mode.
  496. //
  497. gpScreenReal = SDL_SetVideoMode(640, 480, 8, SDL_SWSURFACE);
  498. #endif
  499. }
  500. SDL_SetPalette(gpScreenReal, SDL_PHYSPAL | SDL_LOGPAL, palette, 0, i);
  501. VIDEO_UpdateScreen(NULL);
  502. #endif
  503. }
  504. SDL_Color *
  505. VIDEO_GetPalette(
  506. VOID
  507. )
  508. /*++
  509. Purpose:
  510. Get the current palette of the screen.
  511. Parameters:
  512. None.
  513. Return value:
  514. Pointer to the current palette.
  515. --*/
  516. {
  517. #if SDL_VERSION_ATLEAST(2,0,0)
  518. return gpScreen->format->palette->colors;
  519. #else
  520. return gpScreenReal->format->palette->colors;
  521. #endif
  522. }
  523. VOID
  524. VIDEO_ToggleScaleScreen(
  525. VOID
  526. )
  527. /*++
  528. Purpose:
  529. Toggle scalescreen mode.
  530. Parameters:
  531. None.
  532. Return value:
  533. None.
  534. --*/
  535. {
  536. #ifdef __SYMBIAN32__
  537. bScaleScreen = !bScaleScreen;
  538. VIDEO_Resize(320, 240);
  539. VIDEO_UpdateScreen(NULL);
  540. #endif
  541. }
  542. VOID
  543. VIDEO_ToggleFullscreen(
  544. VOID
  545. )
  546. /*++
  547. Purpose:
  548. Toggle fullscreen mode.
  549. Parameters:
  550. None.
  551. Return value:
  552. None.
  553. --*/
  554. {
  555. #if SDL_VERSION_ATLEAST(2,0,0)
  556. // TODO
  557. #else
  558. DWORD flags;
  559. PAL_LARGE SDL_Color palette[256];
  560. int i;
  561. //
  562. // Get the original palette.
  563. //
  564. for (i = 0; i < gpScreenReal->format->palette->ncolors; i++)
  565. {
  566. palette[i] = gpScreenReal->format->palette->colors[i];
  567. }
  568. //
  569. // Get the flags of the original screen surface
  570. //
  571. flags = gpScreenReal->flags;
  572. if (flags & SDL_FULLSCREEN)
  573. {
  574. //
  575. // Already in fullscreen mode. Remove the fullscreen flag.
  576. //
  577. flags &= ~SDL_FULLSCREEN;
  578. flags |= SDL_RESIZABLE;
  579. SDL_ShowCursor(TRUE);
  580. }
  581. else
  582. {
  583. //
  584. // Not in fullscreen mode. Set the fullscreen flag.
  585. //
  586. flags |= SDL_FULLSCREEN;
  587. SDL_ShowCursor(FALSE);
  588. }
  589. //
  590. // Free the original screen surface
  591. //
  592. SDL_FreeSurface(gpScreenReal);
  593. //
  594. // ... and create a new one
  595. //
  596. if (gConfig.dwScreenWidth == 640 && gConfig.dwScreenHeight == 400 && (flags & SDL_FULLSCREEN))
  597. {
  598. gpScreenReal = SDL_SetVideoMode(640, 480, 8, flags);
  599. }
  600. else if (gConfig.dwScreenWidth == 640 && gConfig.dwScreenHeight == 480 && !(flags & SDL_FULLSCREEN))
  601. {
  602. gpScreenReal = SDL_SetVideoMode(640, 400, 8, flags);
  603. }
  604. else
  605. {
  606. gpScreenReal = SDL_SetVideoMode(gConfig.dwScreenWidth, gConfig.dwScreenHeight, 8, flags);
  607. }
  608. VIDEO_SetPalette(palette);
  609. //
  610. // Update the screen
  611. //
  612. VIDEO_UpdateScreen(NULL);
  613. #endif
  614. }
  615. VOID
  616. VIDEO_SaveScreenshot(
  617. VOID
  618. )
  619. /*++
  620. Purpose:
  621. Save the screenshot of current screen to a BMP file.
  622. Parameters:
  623. None.
  624. Return value:
  625. None.
  626. --*/
  627. {
  628. int iNumBMP = 0;
  629. FILE *fp;
  630. //
  631. // Find a usable BMP filename.
  632. //
  633. for (iNumBMP = 0; iNumBMP <= 9999; iNumBMP++)
  634. {
  635. fp = fopen(va("%sscrn%.4d.bmp", PAL_SCREENSHOT_PREFIX, iNumBMP), "rb");
  636. if (fp == NULL)
  637. {
  638. break;
  639. }
  640. fclose(fp);
  641. }
  642. if (iNumBMP > 9999)
  643. {
  644. return;
  645. }
  646. //
  647. // Save the screenshot.
  648. //
  649. #if SDL_VERSION_ATLEAST(2,0,0)
  650. SDL_SaveBMP(gpScreen, va("%sscrn%.4d.bmp", PAL_SCREENSHOT_PREFIX, iNumBMP));
  651. #else
  652. SDL_SaveBMP(gpScreenReal, va("%sscrn%.4d.bmp", PAL_SCREENSHOT_PREFIX, iNumBMP));
  653. #endif
  654. }
  655. VOID
  656. VIDEO_BackupScreen(
  657. VOID
  658. )
  659. /*++
  660. Purpose:
  661. Backup the screen buffer.
  662. Parameters:
  663. None.
  664. Return value:
  665. None.
  666. --*/
  667. {
  668. SDL_BlitSurface(gpScreen, NULL, gpScreenBak, NULL);
  669. }
  670. VOID
  671. VIDEO_RestoreScreen(
  672. VOID
  673. )
  674. /*++
  675. Purpose:
  676. Restore the screen buffer which has been saved with VIDEO_BackupScreen().
  677. Parameters:
  678. None.
  679. Return value:
  680. None.
  681. --*/
  682. {
  683. SDL_BlitSurface(gpScreenBak, NULL, gpScreen, NULL);
  684. }
  685. VOID
  686. VIDEO_ShakeScreen(
  687. WORD wShakeTime,
  688. WORD wShakeLevel
  689. )
  690. /*++
  691. Purpose:
  692. Set the screen shake time and level.
  693. Parameters:
  694. [IN] wShakeTime - how many times should we shake the screen.
  695. [IN] wShakeLevel - level of shaking.
  696. Return value:
  697. None.
  698. --*/
  699. {
  700. g_wShakeTime = wShakeTime;
  701. g_wShakeLevel = wShakeLevel;
  702. }
  703. VOID
  704. VIDEO_SwitchScreen(
  705. WORD wSpeed
  706. )
  707. /*++
  708. Purpose:
  709. Switch the screen from the backup screen buffer to the current screen buffer.
  710. NOTE: This will destroy the backup buffer.
  711. Parameters:
  712. [IN] wSpeed - speed of fading (the larger value, the slower).
  713. Return value:
  714. None.
  715. --*/
  716. {
  717. int i, j;
  718. const int rgIndex[6] = {0, 3, 1, 5, 2, 4};
  719. SDL_Rect dstrect;
  720. short offset = 240 - 200;
  721. short screenRealHeight = gpScreenReal->h;
  722. short screenRealY = 0;
  723. if (!bScaleScreen)
  724. {
  725. screenRealHeight -= offset;
  726. screenRealY = offset / 2;
  727. }
  728. wSpeed++;
  729. wSpeed *= 10;
  730. for (i = 0; i < 6; i++)
  731. {
  732. for (j = rgIndex[i]; j < gpScreen->pitch * gpScreen->h; j += 6)
  733. {
  734. ((LPBYTE)(gpScreenBak->pixels))[j] = ((LPBYTE)(gpScreen->pixels))[j];
  735. }
  736. //
  737. // Draw the backup buffer to the screen
  738. //
  739. dstrect.x = 0;
  740. dstrect.y = screenRealY;
  741. dstrect.w = gpScreenReal->w;
  742. dstrect.h = screenRealHeight;
  743. if (SDL_MUSTLOCK(gpScreenReal))
  744. {
  745. if (SDL_LockSurface(gpScreenReal) < 0)
  746. return;
  747. }
  748. SDL_SoftStretch(gpScreenBak, NULL, gpScreenReal, &dstrect);
  749. #if SDL_VERSION_ATLEAST(2, 0, 0)
  750. VIDEO_RenderCopy();
  751. #else
  752. SDL_UpdateRect(gpScreenReal, 0, 0, gpScreenReal->w, gpScreenReal->h);
  753. #endif
  754. if (SDL_MUSTLOCK(gpScreenReal))
  755. {
  756. SDL_UnlockSurface(gpScreenReal);
  757. }
  758. UTIL_Delay(wSpeed);
  759. }
  760. }
  761. VOID
  762. VIDEO_FadeScreen(
  763. WORD wSpeed
  764. )
  765. /*++
  766. Purpose:
  767. Fade from the backup screen buffer to the current screen buffer.
  768. NOTE: This will destroy the backup buffer.
  769. Parameters:
  770. [IN] wSpeed - speed of fading (the larger value, the slower).
  771. Return value:
  772. None.
  773. --*/
  774. {
  775. int i, j, k;
  776. DWORD time;
  777. BYTE a, b;
  778. const int rgIndex[6] = {0, 3, 1, 5, 2, 4};
  779. SDL_Rect dstrect;
  780. short offset = 240 - 200;
  781. short screenRealHeight = gpScreenReal->h;
  782. short screenRealY = 0;
  783. //
  784. // Lock surface if needed
  785. //
  786. if (SDL_MUSTLOCK(gpScreenReal))
  787. {
  788. if (SDL_LockSurface(gpScreenReal) < 0)
  789. return;
  790. }
  791. if (!bScaleScreen)
  792. {
  793. screenRealHeight -= offset;
  794. screenRealY = offset / 2;
  795. }
  796. time = SDL_GetTicks();
  797. wSpeed++;
  798. wSpeed *= 10;
  799. for (i = 0; i < 12; i++)
  800. {
  801. for (j = 0; j < 6; j++)
  802. {
  803. PAL_ProcessEvent();
  804. while (!SDL_TICKS_PASSED(SDL_GetTicks(), time))
  805. {
  806. PAL_ProcessEvent();
  807. SDL_Delay(5);
  808. }
  809. time = SDL_GetTicks() + wSpeed;
  810. //
  811. // Blend the pixels in the 2 buffers, and put the result into the
  812. // backup buffer
  813. //
  814. for (k = rgIndex[j]; k < gpScreen->pitch * gpScreen->h; k += 6)
  815. {
  816. a = ((LPBYTE)(gpScreen->pixels))[k];
  817. b = ((LPBYTE)(gpScreenBak->pixels))[k];
  818. if (i > 0)
  819. {
  820. if ((a & 0x0F) > (b & 0x0F))
  821. {
  822. b++;
  823. }
  824. else if ((a & 0x0F) < (b & 0x0F))
  825. {
  826. b--;
  827. }
  828. }
  829. ((LPBYTE)(gpScreenBak->pixels))[k] = ((a & 0xF0) | (b & 0x0F));
  830. }
  831. //
  832. // Draw the backup buffer to the screen
  833. //
  834. if (g_wShakeTime != 0)
  835. {
  836. //
  837. // Shake the screen
  838. //
  839. SDL_Rect srcrect, dstrect;
  840. srcrect.x = 0;
  841. srcrect.y = 0;
  842. srcrect.w = 320;
  843. srcrect.h = 200 - g_wShakeLevel;
  844. dstrect.x = 0;
  845. dstrect.y = screenRealY;
  846. dstrect.w = 320 * gpScreenReal->w / gpScreen->w;
  847. dstrect.h = (200 - g_wShakeLevel) * screenRealHeight / gpScreen->h;
  848. if (g_wShakeTime & 1)
  849. {
  850. srcrect.y = g_wShakeLevel;
  851. }
  852. else
  853. {
  854. dstrect.y = (screenRealY + g_wShakeLevel) * screenRealHeight / gpScreen->h;
  855. }
  856. SDL_SoftStretch(gpScreenBak, &srcrect, gpScreenReal, &dstrect);
  857. if (g_wShakeTime & 1)
  858. {
  859. dstrect.y = (screenRealY + screenRealHeight - g_wShakeLevel) * screenRealHeight / gpScreen->h;
  860. }
  861. else
  862. {
  863. dstrect.y = screenRealY;
  864. }
  865. dstrect.h = g_wShakeLevel * screenRealHeight / gpScreen->h;
  866. SDL_FillRect(gpScreenReal, &dstrect, 0);
  867. #if SDL_VERSION_ATLEAST(2, 0, 0)
  868. VIDEO_RenderCopy();
  869. #else
  870. SDL_UpdateRect(gpScreenReal, 0, 0, gpScreenReal->w, gpScreenReal->h);
  871. #endif
  872. g_wShakeTime--;
  873. }
  874. else
  875. {
  876. dstrect.x = 0;
  877. dstrect.y = screenRealY;
  878. dstrect.w = gpScreenReal->w;
  879. dstrect.h = screenRealHeight;
  880. SDL_SoftStretch(gpScreenBak, NULL, gpScreenReal, &dstrect);
  881. #if SDL_VERSION_ATLEAST(2, 0, 0)
  882. VIDEO_RenderCopy();
  883. #else
  884. SDL_UpdateRect(gpScreenReal, 0, 0, gpScreenReal->w, gpScreenReal->h);
  885. #endif
  886. }
  887. }
  888. }
  889. if (SDL_MUSTLOCK(gpScreenReal))
  890. {
  891. SDL_UnlockSurface(gpScreenReal);
  892. }
  893. //
  894. // Draw the result buffer to the screen as the final step
  895. //
  896. VIDEO_UpdateScreen(NULL);
  897. }
  898. #if SDL_VERSION_ATLEAST(2,0,0)
  899. /*++
  900. Purpose:
  901. Set the caption of the window. For compatibility with SDL2 only.
  902. Parameters:
  903. [IN] lpszCaption - the new caption of the window.
  904. [IN] lpReserved - not used, for compatibility only.
  905. Return value:
  906. None.
  907. --*/
  908. VOID
  909. SDL_WM_SetCaption(
  910. LPCSTR lpszCaption,
  911. LPVOID lpReserved
  912. )
  913. {
  914. if (gpWindow != NULL)
  915. {
  916. SDL_SetWindowTitle(gpWindow, lpszCaption);
  917. }
  918. }
  919. #endif