rngplay.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  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. fread(&uiOffset, sizeof(UINT), 1, fpRngMKF);
  71. 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. 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. fread(&uiSubOffset, sizeof(UINT), 1, fpRngMKF);
  100. 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. fread(lpBuffer, iChunkLen, 1, fpRngMKF);
  115. }
  116. else
  117. {
  118. return -1;
  119. }
  120. return iChunkLen;
  121. }
  122. static INT
  123. PAL_RNGBlitToSurface(
  124. INT iNumRNG,
  125. INT iNumFrame,
  126. SDL_Surface *lpDstSurface,
  127. FILE *fpRngMKF
  128. )
  129. /*++
  130. Purpose:
  131. Blit one frame in an RNG animation to an SDL surface.
  132. The surface should contain the last frame of the RNG, or blank if it's the first
  133. frame.
  134. NOTE: Assume the surface is already locked, and the surface is a 320x200 8-bit one.
  135. Parameters:
  136. [IN] iNumRNG - The number of the animation in the MKF archive.
  137. [IN] iNumFrame - The number of the frame in the animation.
  138. [OUT] lpDstSurface - pointer to the destination SDL surface.
  139. [IN] fpRngMKF - Pointer to the fopen'ed rng.mkf file.
  140. Return value:
  141. 0 = success, -1 = error.
  142. --*/
  143. {
  144. INT ptr = 0;
  145. INT dst_ptr = 0;
  146. BYTE data = 0;
  147. WORD wdata = 0;
  148. INT x, y, i, n;
  149. LPBYTE rng = NULL;
  150. LPBYTE buf = NULL;
  151. //
  152. // Check for invalid parameters.
  153. //
  154. if (lpDstSurface == NULL || iNumRNG < 0 || iNumFrame < 0)
  155. {
  156. return -1;
  157. }
  158. buf = (LPBYTE)calloc(1, 65000);
  159. if (buf == NULL)
  160. {
  161. return -1;
  162. }
  163. //
  164. // Read the frame.
  165. //
  166. if (PAL_RNGReadFrame(buf, 65000, iNumRNG, iNumFrame, fpRngMKF) < 0)
  167. {
  168. free(buf);
  169. return -1;
  170. }
  171. //
  172. // Decompress the frame.
  173. //
  174. rng = (LPBYTE)calloc(1, 65000);
  175. if (rng == NULL)
  176. {
  177. free(buf);
  178. return -1;
  179. }
  180. Decompress(buf, rng, 65000);
  181. free(buf);
  182. //
  183. // Draw the frame to the surface.
  184. // FIXME: Dirty and ineffective code, needs to be cleaned up
  185. //
  186. while (TRUE)
  187. {
  188. data = rng[ptr++];
  189. switch (data)
  190. {
  191. case 0x00:
  192. case 0x13:
  193. //
  194. // End
  195. //
  196. goto end;
  197. case 0x02:
  198. dst_ptr += 2;
  199. break;
  200. case 0x03:
  201. data = rng[ptr++];
  202. dst_ptr += (data + 1) * 2;
  203. break;
  204. case 0x04:
  205. wdata = rng[ptr] | (rng[ptr + 1] << 8);
  206. ptr += 2;
  207. dst_ptr += ((unsigned int)wdata + 1) * 2;
  208. break;
  209. case 0x0a:
  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 0x09:
  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. case 0x08:
  232. x = dst_ptr % 320;
  233. y = dst_ptr / 320;
  234. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  235. if (++x >= 320)
  236. {
  237. x = 0;
  238. ++y;
  239. }
  240. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  241. dst_ptr += 2;
  242. case 0x07:
  243. x = dst_ptr % 320;
  244. y = dst_ptr / 320;
  245. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  246. if (++x >= 320)
  247. {
  248. x = 0;
  249. ++y;
  250. }
  251. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  252. dst_ptr += 2;
  253. case 0x06:
  254. x = dst_ptr % 320;
  255. y = dst_ptr / 320;
  256. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  257. if (++x >= 320)
  258. {
  259. x = 0;
  260. ++y;
  261. }
  262. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  263. dst_ptr += 2;
  264. break;
  265. case 0x0b:
  266. data = *(rng + ptr++);
  267. for (i = 0; i <= data; i++)
  268. {
  269. x = dst_ptr % 320;
  270. y = dst_ptr / 320;
  271. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  272. if (++x >= 320)
  273. {
  274. x = 0;
  275. ++y;
  276. }
  277. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  278. dst_ptr += 2;
  279. }
  280. break;
  281. case 0x0c:
  282. wdata = rng[ptr] | (rng[ptr + 1] << 8);
  283. ptr += 2;
  284. for (i = 0; i <= wdata; i++)
  285. {
  286. x = dst_ptr % 320;
  287. y = dst_ptr / 320;
  288. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  289. if (++x >= 320)
  290. {
  291. x = 0;
  292. ++y;
  293. }
  294. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  295. dst_ptr += 2;
  296. }
  297. break;
  298. case 0x0d:
  299. case 0x0e:
  300. case 0x0f:
  301. case 0x10:
  302. for (i = 0; i < data - (0x0d - 2); i++)
  303. {
  304. x = dst_ptr % 320;
  305. y = dst_ptr / 320;
  306. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr];
  307. if (++x >= 320)
  308. {
  309. x = 0;
  310. ++y;
  311. }
  312. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr + 1];
  313. dst_ptr += 2;
  314. }
  315. ptr += 2;
  316. break;
  317. case 0x11:
  318. data = *(rng + ptr++);
  319. for (i = 0; i <= data; i++)
  320. {
  321. x = dst_ptr % 320;
  322. y = dst_ptr / 320;
  323. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr];
  324. if (++x >= 320)
  325. {
  326. x = 0;
  327. ++y;
  328. }
  329. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr + 1];
  330. dst_ptr += 2;
  331. }
  332. ptr += 2;
  333. break;
  334. case 0x12:
  335. n = (rng[ptr] | (rng[ptr + 1] << 8)) + 1;
  336. ptr += 2;
  337. for (i = 0; i < n; i++)
  338. {
  339. x = dst_ptr % 320;
  340. y = dst_ptr / 320;
  341. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr];
  342. if (++x >= 320)
  343. {
  344. x = 0;
  345. ++y;
  346. }
  347. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr + 1];
  348. dst_ptr += 2;
  349. }
  350. ptr += 2;
  351. break;
  352. }
  353. }
  354. end:
  355. free(rng);
  356. return 0;
  357. }
  358. VOID
  359. PAL_RNGPlay(
  360. INT iNumRNG,
  361. INT iStartFrame,
  362. INT iEndFrame,
  363. INT iSpeed
  364. )
  365. /*++
  366. Purpose:
  367. Play a RNG movie.
  368. Parameters:
  369. [IN] iNumRNG - number of the RNG movie.
  370. [IN] iStartFrame - start frame number.
  371. [IN] iEndFrame - end frame number.
  372. [IN] iSpeed - speed of playing.
  373. Return value:
  374. None.
  375. --*/
  376. {
  377. UINT iTime;
  378. int iDelay = 800 / (iSpeed == 0 ? 16 : iSpeed);
  379. FILE *fp;
  380. fp = UTIL_OpenRequiredFile("rng.mkf");
  381. for (; iStartFrame <= iEndFrame; iStartFrame++)
  382. {
  383. iTime = SDL_GetTicks() + iDelay;
  384. if (PAL_RNGBlitToSurface(iNumRNG, iStartFrame, gpScreen, fp) == -1)
  385. {
  386. //
  387. // Failed to get the frame, don't go further
  388. //
  389. fclose(fp);
  390. return;
  391. }
  392. //
  393. // Update the screen
  394. //
  395. VIDEO_UpdateScreen(NULL);
  396. //
  397. // Fade in the screen if needed
  398. //
  399. if (gpGlobals->fNeedToFadeIn)
  400. {
  401. PAL_FadeIn(gpGlobals->wNumPalette, gpGlobals->fNightPalette, 1);
  402. gpGlobals->fNeedToFadeIn = FALSE;
  403. }
  404. //
  405. // Delay for a while
  406. //
  407. PAL_DelayUntil(iTime);
  408. }
  409. fclose(fp);
  410. }