video.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260
  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 "main.h"
  23. // Screen buffer
  24. SDL_Surface *gpScreen = NULL;
  25. // Backup screen buffer
  26. SDL_Surface *gpScreenBak = NULL;
  27. // The global palette
  28. static SDL_Palette *gpPalette = NULL;
  29. #if SDL_VERSION_ATLEAST(2,0,0)
  30. SDL_Window *gpWindow = NULL;
  31. static SDL_Renderer *gpRenderer = NULL;
  32. static SDL_Texture *gpTexture = NULL;
  33. static SDL_Texture *gpTouchOverlay = NULL;
  34. static SDL_Rect gOverlayRect;
  35. static SDL_Rect gTextureRect;
  36. #endif
  37. // The real screen surface
  38. static SDL_Surface *gpScreenReal = NULL;
  39. volatile BOOL g_bRenderPaused = FALSE;
  40. static BOOL bScaleScreen = PAL_SCALE_SCREEN;
  41. // Shake times and level
  42. static WORD g_wShakeTime = 0;
  43. static WORD g_wShakeLevel = 0;
  44. #if SDL_VERSION_ATLEAST(2, 0, 0)
  45. #define SDL_SoftStretch SDL_UpperBlit
  46. #include <float.h>
  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;
  493. //
  494. // Get the original palette.
  495. //
  496. for (i = 0; i < gpScreenReal->format->palette->ncolors; i++)
  497. {
  498. palette[i] = gpScreenReal->format->palette->colors[i];
  499. }
  500. //
  501. // Create the screen surface.
  502. //
  503. flags = gpScreenReal->flags;
  504. SDL_FreeSurface(gpScreenReal);
  505. gpScreenReal = SDL_SetVideoMode(w, h, 8, flags);
  506. if (gpScreenReal == NULL)
  507. {
  508. //
  509. // Fall back to software windowed mode in default size.
  510. //
  511. gpScreenReal = SDL_SetVideoMode(PAL_DEFAULT_WINDOW_WIDTH, PAL_DEFAULT_WINDOW_HEIGHT, 8, SDL_SWSURFACE);
  512. }
  513. SDL_SetPalette(gpScreenReal, SDL_PHYSPAL | SDL_LOGPAL, palette, 0, i);
  514. VIDEO_UpdateScreen(NULL);
  515. gpPalette = gpScreenReal->format->palette;
  516. #endif
  517. }
  518. SDL_Color *
  519. VIDEO_GetPalette(
  520. VOID
  521. )
  522. /*++
  523. Purpose:
  524. Get the current palette of the screen.
  525. Parameters:
  526. None.
  527. Return value:
  528. Pointer to the current palette.
  529. --*/
  530. {
  531. return gpPalette->colors;
  532. }
  533. VOID
  534. VIDEO_ToggleScaleScreen(
  535. VOID
  536. )
  537. /*++
  538. Purpose:
  539. Toggle scalescreen mode, only used in some platforms.
  540. Parameters:
  541. None.
  542. Return value:
  543. None.
  544. --*/
  545. {
  546. bScaleScreen = !bScaleScreen;
  547. VIDEO_Resize(PAL_DEFAULT_WINDOW_WIDTH, PAL_DEFAULT_WINDOW_HEIGHT);
  548. VIDEO_UpdateScreen(NULL);
  549. }
  550. VOID
  551. VIDEO_ToggleFullscreen(
  552. VOID
  553. )
  554. /*++
  555. Purpose:
  556. Toggle fullscreen mode.
  557. Parameters:
  558. None.
  559. Return value:
  560. None.
  561. --*/
  562. {
  563. #if SDL_VERSION_ATLEAST(2,0,0)
  564. if (gConfig.fFullScreen)
  565. {
  566. SDL_SetWindowFullscreen(gpWindow, 0);
  567. gConfig.fFullScreen = FALSE;
  568. }
  569. else
  570. {
  571. SDL_SetWindowFullscreen(gpWindow, SDL_WINDOW_FULLSCREEN_DESKTOP);
  572. gConfig.fFullScreen = TRUE;
  573. }
  574. #else
  575. DWORD flags;
  576. PAL_LARGE SDL_Color palette[256];
  577. int i;
  578. //
  579. // Get the original palette.
  580. //
  581. for (i = 0; i < gpScreenReal->format->palette->ncolors; i++)
  582. {
  583. palette[i] = gpScreenReal->format->palette->colors[i];
  584. }
  585. //
  586. // Get the flags of the original screen surface
  587. //
  588. flags = gpScreenReal->flags;
  589. if (flags & SDL_FULLSCREEN)
  590. {
  591. //
  592. // Already in fullscreen mode. Remove the fullscreen flag.
  593. //
  594. flags &= ~SDL_FULLSCREEN;
  595. flags |= SDL_RESIZABLE;
  596. SDL_ShowCursor(TRUE);
  597. }
  598. else
  599. {
  600. //
  601. // Not in fullscreen mode. Set the fullscreen flag.
  602. //
  603. flags |= SDL_FULLSCREEN;
  604. SDL_ShowCursor(FALSE);
  605. }
  606. //
  607. // Free the original screen surface
  608. //
  609. SDL_FreeSurface(gpScreenReal);
  610. //
  611. // ... and create a new one
  612. //
  613. if (gConfig.dwScreenWidth == 640 && gConfig.dwScreenHeight == 400 && (flags & SDL_FULLSCREEN))
  614. {
  615. gpScreenReal = SDL_SetVideoMode(640, 480, 8, flags);
  616. }
  617. else if (gConfig.dwScreenWidth == 640 && gConfig.dwScreenHeight == 480 && !(flags & SDL_FULLSCREEN))
  618. {
  619. gpScreenReal = SDL_SetVideoMode(640, 400, 8, flags);
  620. }
  621. else
  622. {
  623. gpScreenReal = SDL_SetVideoMode(gConfig.dwScreenWidth, gConfig.dwScreenHeight, 8, flags);
  624. }
  625. VIDEO_SetPalette(palette);
  626. //
  627. // Update the screen
  628. //
  629. VIDEO_UpdateScreen(NULL);
  630. #endif
  631. }
  632. VOID
  633. VIDEO_SaveScreenshot(
  634. VOID
  635. )
  636. /*++
  637. Purpose:
  638. Save the screenshot of current screen to a BMP file.
  639. Parameters:
  640. None.
  641. Return value:
  642. None.
  643. --*/
  644. {
  645. char filename[32];
  646. #ifdef _WIN32
  647. SYSTEMTIME st;
  648. GetLocalTime(&st);
  649. sprintf(filename, "%04d%02d%02d%02d%02d%02d%03d.bmp", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
  650. #elif !defined( GEKKO )
  651. struct timeval tv;
  652. struct tm *ptm;
  653. gettimeofday(&tv, NULL);
  654. ptm = localtime(&tv.tv_sec);
  655. 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));
  656. #endif
  657. //
  658. // Save the screenshot.
  659. //
  660. #if SDL_VERSION_ATLEAST(2,0,0)
  661. SDL_SaveBMP(gpScreen, PAL_CombinePath(0, gConfig.pszSavePath, filename));
  662. #else
  663. SDL_SaveBMP(gpScreenReal, PAL_CombinePath(0, gConfig.pszSavePath, filename));
  664. #endif
  665. }
  666. VOID
  667. VIDEO_ShakeScreen(
  668. WORD wShakeTime,
  669. WORD wShakeLevel
  670. )
  671. /*++
  672. Purpose:
  673. Set the screen shake time and level.
  674. Parameters:
  675. [IN] wShakeTime - how many times should we shake the screen.
  676. [IN] wShakeLevel - level of shaking.
  677. Return value:
  678. None.
  679. --*/
  680. {
  681. g_wShakeTime = wShakeTime;
  682. g_wShakeLevel = wShakeLevel;
  683. }
  684. VOID
  685. VIDEO_SwitchScreen(
  686. WORD wSpeed
  687. )
  688. /*++
  689. Purpose:
  690. Switch the screen from the backup screen buffer to the current screen buffer.
  691. NOTE: This will destroy the backup buffer.
  692. Parameters:
  693. [IN] wSpeed - speed of fading (the larger value, the slower).
  694. Return value:
  695. None.
  696. --*/
  697. {
  698. int i, j;
  699. const int rgIndex[6] = {0, 3, 1, 5, 2, 4};
  700. SDL_Rect dstrect;
  701. short offset = 240 - 200;
  702. short screenRealHeight = gpScreenReal->h;
  703. short screenRealY = 0;
  704. if (!bScaleScreen)
  705. {
  706. screenRealHeight -= offset;
  707. screenRealY = offset / 2;
  708. }
  709. wSpeed++;
  710. wSpeed *= 10;
  711. for (i = 0; i < 6; i++)
  712. {
  713. for (j = rgIndex[i]; j < gpScreen->pitch * gpScreen->h; j += 6)
  714. {
  715. ((LPBYTE)(gpScreenBak->pixels))[j] = ((LPBYTE)(gpScreen->pixels))[j];
  716. }
  717. //
  718. // Draw the backup buffer to the screen
  719. //
  720. dstrect.x = 0;
  721. dstrect.y = screenRealY;
  722. dstrect.w = gpScreenReal->w;
  723. dstrect.h = screenRealHeight;
  724. if (SDL_MUSTLOCK(gpScreenReal))
  725. {
  726. if (SDL_LockSurface(gpScreenReal) < 0)
  727. return;
  728. }
  729. SDL_SoftStretch(gpScreenBak, NULL, gpScreenReal, &dstrect);
  730. #if SDL_VERSION_ATLEAST(2, 0, 0)
  731. VIDEO_RenderCopy();
  732. #else
  733. SDL_UpdateRect(gpScreenReal, 0, 0, gpScreenReal->w, gpScreenReal->h);
  734. #endif
  735. if (SDL_MUSTLOCK(gpScreenReal))
  736. {
  737. SDL_UnlockSurface(gpScreenReal);
  738. }
  739. UTIL_Delay(wSpeed);
  740. }
  741. }
  742. VOID
  743. VIDEO_FadeScreen(
  744. WORD wSpeed
  745. )
  746. /*++
  747. Purpose:
  748. Fade from the backup screen buffer to the current screen buffer.
  749. NOTE: This will destroy the backup buffer.
  750. Parameters:
  751. [IN] wSpeed - speed of fading (the larger value, the slower).
  752. Return value:
  753. None.
  754. --*/
  755. {
  756. int i, j, k;
  757. DWORD time;
  758. BYTE a, b;
  759. const int rgIndex[6] = {0, 3, 1, 5, 2, 4};
  760. SDL_Rect dstrect;
  761. short offset = 240 - 200;
  762. short screenRealHeight = gpScreenReal->h;
  763. short screenRealY = 0;
  764. //
  765. // Lock surface if needed
  766. //
  767. if (SDL_MUSTLOCK(gpScreenReal))
  768. {
  769. if (SDL_LockSurface(gpScreenReal) < 0)
  770. return;
  771. }
  772. if (!bScaleScreen)
  773. {
  774. screenRealHeight -= offset;
  775. screenRealY = offset / 2;
  776. }
  777. time = SDL_GetTicks();
  778. wSpeed++;
  779. wSpeed *= 10;
  780. for (i = 0; i < 12; i++)
  781. {
  782. for (j = 0; j < 6; j++)
  783. {
  784. PAL_ProcessEvent();
  785. while (!SDL_TICKS_PASSED(SDL_GetTicks(), time))
  786. {
  787. PAL_ProcessEvent();
  788. SDL_Delay(5);
  789. }
  790. time = SDL_GetTicks() + wSpeed;
  791. //
  792. // Blend the pixels in the 2 buffers, and put the result into the
  793. // backup buffer
  794. //
  795. for (k = rgIndex[j]; k < gpScreen->pitch * gpScreen->h; k += 6)
  796. {
  797. a = ((LPBYTE)(gpScreen->pixels))[k];
  798. b = ((LPBYTE)(gpScreenBak->pixels))[k];
  799. if (i > 0)
  800. {
  801. if ((a & 0x0F) > (b & 0x0F))
  802. {
  803. b++;
  804. }
  805. else if ((a & 0x0F) < (b & 0x0F))
  806. {
  807. b--;
  808. }
  809. }
  810. ((LPBYTE)(gpScreenBak->pixels))[k] = ((a & 0xF0) | (b & 0x0F));
  811. }
  812. //
  813. // Draw the backup buffer to the screen
  814. //
  815. if (g_wShakeTime != 0)
  816. {
  817. //
  818. // Shake the screen
  819. //
  820. SDL_Rect srcrect, dstrect;
  821. srcrect.x = 0;
  822. srcrect.y = 0;
  823. srcrect.w = 320;
  824. srcrect.h = 200 - g_wShakeLevel;
  825. dstrect.x = 0;
  826. dstrect.y = screenRealY;
  827. dstrect.w = 320 * gpScreenReal->w / gpScreen->w;
  828. dstrect.h = (200 - g_wShakeLevel) * screenRealHeight / gpScreen->h;
  829. if (g_wShakeTime & 1)
  830. {
  831. srcrect.y = g_wShakeLevel;
  832. }
  833. else
  834. {
  835. dstrect.y = (screenRealY + g_wShakeLevel) * screenRealHeight / gpScreen->h;
  836. }
  837. SDL_SoftStretch(gpScreenBak, &srcrect, gpScreenReal, &dstrect);
  838. if (g_wShakeTime & 1)
  839. {
  840. dstrect.y = (screenRealY + screenRealHeight - g_wShakeLevel) * screenRealHeight / gpScreen->h;
  841. }
  842. else
  843. {
  844. dstrect.y = screenRealY;
  845. }
  846. dstrect.h = g_wShakeLevel * screenRealHeight / gpScreen->h;
  847. SDL_FillRect(gpScreenReal, &dstrect, 0);
  848. #if SDL_VERSION_ATLEAST(2, 0, 0)
  849. VIDEO_RenderCopy();
  850. #else
  851. SDL_UpdateRect(gpScreenReal, 0, 0, gpScreenReal->w, gpScreenReal->h);
  852. #endif
  853. g_wShakeTime--;
  854. }
  855. else
  856. {
  857. dstrect.x = 0;
  858. dstrect.y = screenRealY;
  859. dstrect.w = gpScreenReal->w;
  860. dstrect.h = screenRealHeight;
  861. SDL_SoftStretch(gpScreenBak, NULL, gpScreenReal, &dstrect);
  862. #if SDL_VERSION_ATLEAST(2, 0, 0)
  863. VIDEO_RenderCopy();
  864. #else
  865. SDL_UpdateRect(gpScreenReal, 0, 0, gpScreenReal->w, gpScreenReal->h);
  866. #endif
  867. }
  868. }
  869. }
  870. if (SDL_MUSTLOCK(gpScreenReal))
  871. {
  872. SDL_UnlockSurface(gpScreenReal);
  873. }
  874. //
  875. // Draw the result buffer to the screen as the final step
  876. //
  877. VIDEO_UpdateScreen(NULL);
  878. }
  879. void
  880. VIDEO_SetWindowTitle(
  881. const char* pszTitle
  882. )
  883. /*++
  884. Purpose:
  885. Set the caption of the window.
  886. Parameters:
  887. [IN] pszTitle - the new caption of the window.
  888. Return value:
  889. None.
  890. --*/
  891. {
  892. #if SDL_VERSION_ATLEAST(2,0,0)
  893. SDL_SetWindowTitle(gpWindow, pszTitle);
  894. #else
  895. SDL_WM_SetCaption(pszTitle, NULL);
  896. #endif
  897. }
  898. SDL_Surface *
  899. VIDEO_CreateCompatibleSurface(
  900. SDL_Surface *pSource
  901. )
  902. {
  903. return VIDEO_CreateCompatibleSizedSurface(pSource, NULL);
  904. }
  905. SDL_Surface *
  906. VIDEO_CreateCompatibleSizedSurface(
  907. SDL_Surface *pSource,
  908. const SDL_Rect *pSize
  909. )
  910. /*++
  911. Purpose:
  912. Create a surface that compatible with the source surface.
  913. Parameters:
  914. [IN] pSource - the source surface from which attributes are taken.
  915. [IN] pSize - the size (width & height) of the created surface.
  916. Return value:
  917. None.
  918. --*/
  919. {
  920. //
  921. // Create the surface
  922. //
  923. SDL_Surface *dest = SDL_CreateRGBSurface(pSource->flags,
  924. pSize ? pSize->w : pSource->w,
  925. pSize ? pSize->h : pSource->h,
  926. pSource->format->BitsPerPixel,
  927. pSource->format->Rmask, pSource->format->Gmask,
  928. pSource->format->Bmask, pSource->format->Amask);
  929. if (dest)
  930. {
  931. VIDEO_UpdateSurfacePalette(dest);
  932. }
  933. return dest;
  934. }
  935. SDL_Surface *
  936. VIDEO_DuplicateSurface(
  937. SDL_Surface *pSource,
  938. const SDL_Rect *pRect
  939. )
  940. /*++
  941. Purpose:
  942. Duplicate the selected area from the source surface into new surface.
  943. Parameters:
  944. [IN] pSource - the source surface.
  945. [IN] pRect - the area to be duplicated, NULL for entire surface.
  946. Return value:
  947. None.
  948. --*/
  949. {
  950. SDL_Surface* dest = VIDEO_CreateCompatibleSizedSurface(pSource, pRect);
  951. if (dest)
  952. {
  953. VIDEO_CopySurface(pSource, pRect, dest, NULL);
  954. }
  955. return dest;
  956. }
  957. void
  958. VIDEO_UpdateSurfacePalette(
  959. SDL_Surface *pSurface
  960. )
  961. /*++
  962. Purpose:
  963. Use the global palette to update the palette of pSurface.
  964. Parameters:
  965. [IN] pSurface - the surface whose palette should be updated.
  966. Return value:
  967. None.
  968. --*/
  969. {
  970. #if SDL_VERSION_ATLEAST(2, 0, 0)
  971. SDL_SetSurfacePalette(pSurface, gpPalette);
  972. #else
  973. SDL_SetPalette(pSurface, SDL_PHYSPAL | SDL_LOGPAL, gpPalette->colors, 0, 256);
  974. #endif
  975. }
  976. VOID
  977. VIDEO_DrawSurfaceToScreen(
  978. SDL_Surface *pSurface
  979. )
  980. /*++
  981. Purpose:
  982. Draw a surface directly to screen.
  983. Parameters:
  984. [IN] pSurface - the surface which needs to be drawn to screen.
  985. Return value:
  986. None.
  987. --*/
  988. {
  989. #if SDL_VERSION_ATLEAST(2, 0, 0)
  990. //
  991. // Draw the surface to screen.
  992. //
  993. if (g_bRenderPaused)
  994. {
  995. return;
  996. }
  997. SDL_BlitScaled(pSurface, NULL, gpScreenReal, NULL);
  998. VIDEO_RenderCopy();
  999. #else
  1000. SDL_Surface *pCompatSurface;
  1001. SDL_Rect rect;
  1002. rect.x = rect.y = 0;
  1003. rect.w = pSurface->w;
  1004. rect.h = pSurface->h;
  1005. pCompatSurface = VIDEO_CreateCompatibleSizedSurface(gpScreenReal, &rect);
  1006. //
  1007. // First convert the surface to compatible format.
  1008. //
  1009. SDL_BlitSurface(pSurface, NULL, pCompatSurface, NULL);
  1010. //
  1011. // Draw the surface to screen.
  1012. //
  1013. SDL_SoftStretch(pCompatSurface, NULL, gpScreenReal, NULL);
  1014. SDL_UpdateRect(gpScreenReal, 0, 0, gpScreenReal->w, gpScreenReal->h);
  1015. SDL_FreeSurface(pCompatSurface);
  1016. #endif
  1017. }