rngplay.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  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. // Portions based on PalLibrary by Lou Yihua <louyihua@21cn.com>.
  23. // Copyright (c) 2006-2007, Lou Yihua.
  24. //
  25. #include "main.h"
  26. static INT
  27. PAL_RNGReadFrame(
  28. LPBYTE lpBuffer,
  29. UINT uiBufferSize,
  30. UINT uiRngNum,
  31. UINT uiFrameNum,
  32. FILE *fpRngMKF
  33. )
  34. /*++
  35. Purpose:
  36. Read a frame from a RNG animation.
  37. Parameters:
  38. [OUT] lpBuffer - pointer to the destination buffer.
  39. [IN] uiBufferSize - size of the destination buffer.
  40. [IN] uiRngNum - the number of the RNG animation in the MKF archive.
  41. [IN] uiFrameNum - frame number in the RNG animation.
  42. [IN] fpRngMKF - pointer to the fopen'ed MKF file.
  43. Return value:
  44. Integer value which indicates the size of the chunk.
  45. -1 if there are error in parameters.
  46. -2 if buffer size is not enough.
  47. --*/
  48. {
  49. UINT uiOffset = 0;
  50. UINT uiSubOffset = 0;
  51. UINT uiNextOffset = 0;
  52. UINT uiChunkCount = 0;
  53. INT iChunkLen = 0;
  54. if (lpBuffer == NULL || fpRngMKF == NULL || uiBufferSize == 0)
  55. {
  56. return -1;
  57. }
  58. //
  59. // Get the total number of chunks.
  60. //
  61. uiChunkCount = PAL_MKFGetChunkCount(fpRngMKF);
  62. if (uiRngNum >= uiChunkCount)
  63. {
  64. return -1;
  65. }
  66. //
  67. // Get the offset of the chunk.
  68. //
  69. fseek(fpRngMKF, 4 * uiRngNum, SEEK_SET);
  70. PAL_fread(&uiOffset, sizeof(UINT), 1, fpRngMKF);
  71. PAL_fread(&uiNextOffset, sizeof(UINT), 1, fpRngMKF);
  72. uiOffset = SDL_SwapLE32(uiOffset);
  73. uiNextOffset = SDL_SwapLE32(uiNextOffset);
  74. //
  75. // Get the length of the chunk.
  76. //
  77. iChunkLen = uiNextOffset - uiOffset;
  78. if (iChunkLen != 0)
  79. {
  80. fseek(fpRngMKF, uiOffset, SEEK_SET);
  81. }
  82. else
  83. {
  84. return -1;
  85. }
  86. //
  87. // Get the number of sub chunks.
  88. //
  89. PAL_fread(&uiChunkCount, sizeof(UINT), 1, fpRngMKF);
  90. uiChunkCount = (SDL_SwapLE32(uiChunkCount) - 4) / 4;
  91. if (uiFrameNum >= uiChunkCount)
  92. {
  93. return -1;
  94. }
  95. //
  96. // Get the offset of the sub chunk.
  97. //
  98. fseek(fpRngMKF, uiOffset + 4 * uiFrameNum, SEEK_SET);
  99. PAL_fread(&uiSubOffset, sizeof(UINT), 1, fpRngMKF);
  100. PAL_fread(&uiNextOffset, sizeof(UINT), 1, fpRngMKF);
  101. uiSubOffset = SDL_SwapLE32(uiSubOffset);
  102. uiNextOffset = SDL_SwapLE32(uiNextOffset);
  103. //
  104. // Get the length of the sub chunk.
  105. //
  106. iChunkLen = uiNextOffset - uiSubOffset;
  107. if ((UINT)iChunkLen > uiBufferSize)
  108. {
  109. return -2;
  110. }
  111. if (iChunkLen != 0)
  112. {
  113. fseek(fpRngMKF, uiOffset + uiSubOffset, SEEK_SET);
  114. return (int)fread(lpBuffer, 1, iChunkLen, fpRngMKF);
  115. }
  116. return -1;
  117. }
  118. static INT
  119. PAL_RNGBlitToSurface(
  120. const uint8_t *rng,
  121. int length,
  122. SDL_Surface *lpDstSurface
  123. )
  124. /*++
  125. Purpose:
  126. Blit one frame in an RNG animation to an SDL surface.
  127. The surface should contain the last frame of the RNG, or blank if it's the first
  128. frame.
  129. NOTE: Assume the surface is already locked, and the surface is a 320x200 8-bit one.
  130. Parameters:
  131. [IN] rng - Pointer to the RNG data.
  132. [IN] length - Length of the RNG data.
  133. [OUT] lpDstSurface - pointer to the destination SDL surface.
  134. Return value:
  135. 0 = success, -1 = error.
  136. --*/
  137. {
  138. int ptr = 0;
  139. int dst_ptr = 0;
  140. uint16_t wdata = 0;
  141. int x, y, i, n;
  142. //
  143. // Check for invalid parameters.
  144. //
  145. if (lpDstSurface == NULL || length < 0)
  146. {
  147. return -1;
  148. }
  149. //
  150. // Draw the frame to the surface.
  151. // FIXME: Dirty and ineffective code, needs to be cleaned up
  152. //
  153. while (ptr < length)
  154. {
  155. uint8_t data = rng[ptr++];
  156. switch (data)
  157. {
  158. case 0x00:
  159. case 0x13:
  160. //
  161. // End
  162. //
  163. goto end;
  164. case 0x02:
  165. dst_ptr += 2;
  166. break;
  167. case 0x03:
  168. data = rng[ptr++];
  169. dst_ptr += (data + 1) * 2;
  170. break;
  171. case 0x04:
  172. wdata = rng[ptr] | (rng[ptr + 1] << 8);
  173. ptr += 2;
  174. dst_ptr += ((unsigned int)wdata + 1) * 2;
  175. break;
  176. case 0x0a:
  177. x = dst_ptr % 320;
  178. y = dst_ptr / 320;
  179. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  180. if (++x >= 320)
  181. {
  182. x = 0;
  183. ++y;
  184. }
  185. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  186. dst_ptr += 2;
  187. case 0x09:
  188. x = dst_ptr % 320;
  189. y = dst_ptr / 320;
  190. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  191. if (++x >= 320)
  192. {
  193. x = 0;
  194. ++y;
  195. }
  196. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  197. dst_ptr += 2;
  198. case 0x08:
  199. x = dst_ptr % 320;
  200. y = dst_ptr / 320;
  201. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  202. if (++x >= 320)
  203. {
  204. x = 0;
  205. ++y;
  206. }
  207. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  208. dst_ptr += 2;
  209. case 0x07:
  210. x = dst_ptr % 320;
  211. y = dst_ptr / 320;
  212. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  213. if (++x >= 320)
  214. {
  215. x = 0;
  216. ++y;
  217. }
  218. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  219. dst_ptr += 2;
  220. case 0x06:
  221. x = dst_ptr % 320;
  222. y = dst_ptr / 320;
  223. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  224. if (++x >= 320)
  225. {
  226. x = 0;
  227. ++y;
  228. }
  229. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  230. dst_ptr += 2;
  231. break;
  232. case 0x0b:
  233. data = *(rng + ptr++);
  234. for (i = 0; i <= data; i++)
  235. {
  236. x = dst_ptr % 320;
  237. y = dst_ptr / 320;
  238. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  239. if (++x >= 320)
  240. {
  241. x = 0;
  242. ++y;
  243. }
  244. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  245. dst_ptr += 2;
  246. }
  247. break;
  248. case 0x0c:
  249. wdata = rng[ptr] | (rng[ptr + 1] << 8);
  250. ptr += 2;
  251. for (i = 0; i <= wdata; i++)
  252. {
  253. x = dst_ptr % 320;
  254. y = dst_ptr / 320;
  255. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  256. if (++x >= 320)
  257. {
  258. x = 0;
  259. ++y;
  260. }
  261. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  262. dst_ptr += 2;
  263. }
  264. break;
  265. case 0x0d:
  266. case 0x0e:
  267. case 0x0f:
  268. case 0x10:
  269. for (i = 0; i < data - (0x0d - 2); i++)
  270. {
  271. x = dst_ptr % 320;
  272. y = dst_ptr / 320;
  273. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr];
  274. if (++x >= 320)
  275. {
  276. x = 0;
  277. ++y;
  278. }
  279. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr + 1];
  280. dst_ptr += 2;
  281. }
  282. ptr += 2;
  283. break;
  284. case 0x11:
  285. data = *(rng + ptr++);
  286. for (i = 0; i <= data; i++)
  287. {
  288. x = dst_ptr % 320;
  289. y = dst_ptr / 320;
  290. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr];
  291. if (++x >= 320)
  292. {
  293. x = 0;
  294. ++y;
  295. }
  296. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr + 1];
  297. dst_ptr += 2;
  298. }
  299. ptr += 2;
  300. break;
  301. case 0x12:
  302. n = (rng[ptr] | (rng[ptr + 1] << 8)) + 1;
  303. ptr += 2;
  304. for (i = 0; i < n; i++)
  305. {
  306. x = dst_ptr % 320;
  307. y = dst_ptr / 320;
  308. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr];
  309. if (++x >= 320)
  310. {
  311. x = 0;
  312. ++y;
  313. }
  314. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr + 1];
  315. dst_ptr += 2;
  316. }
  317. ptr += 2;
  318. break;
  319. }
  320. }
  321. end:
  322. return 0;
  323. }
  324. VOID
  325. PAL_RNGPlay(
  326. INT iNumRNG,
  327. INT iStartFrame,
  328. INT iEndFrame,
  329. INT iSpeed
  330. )
  331. /*++
  332. Purpose:
  333. Play a RNG movie.
  334. Parameters:
  335. [IN] iNumRNG - number of the RNG movie.
  336. [IN] iStartFrame - start frame number.
  337. [IN] iEndFrame - end frame number.
  338. [IN] iSpeed - speed of playing.
  339. Return value:
  340. None.
  341. --*/
  342. {
  343. int iDelay = 800 / (iSpeed == 0 ? 16 : iSpeed);
  344. uint8_t *rng = (uint8_t *)malloc(65000);
  345. uint8_t *buf = (uint8_t *)malloc(65000);
  346. FILE *fp = UTIL_OpenRequiredFile("rng.mkf");
  347. for (; rng && buf && iStartFrame <= iEndFrame; iStartFrame++)
  348. {
  349. uint32_t iTime = SDL_GetTicks() + iDelay;
  350. //
  351. // Read, decompress and render the frame
  352. //
  353. if (PAL_RNGReadFrame(buf, 65000, iNumRNG, iStartFrame, fp) < 0 ||
  354. PAL_RNGBlitToSurface(rng, Decompress(buf, rng, 65000), gpScreen) == -1)
  355. {
  356. //
  357. // Failed to get the frame, don't go further
  358. //
  359. break;
  360. }
  361. //
  362. // Update the screen
  363. //
  364. VIDEO_UpdateScreen(NULL);
  365. //
  366. // Fade in the screen if needed
  367. //
  368. if (gpGlobals->fNeedToFadeIn)
  369. {
  370. PAL_FadeIn(gpGlobals->wNumPalette, gpGlobals->fNightPalette, 1);
  371. gpGlobals->fNeedToFadeIn = FALSE;
  372. }
  373. //
  374. // Delay for a while
  375. //
  376. PAL_DelayUntil(iTime);
  377. }
  378. fclose(fp);
  379. free(rng);
  380. free(buf);
  381. }