video.c 25 KB

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