video.c 28 KB

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