video.c 23 KB

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