rngplay.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. /* -*- mode: c; tab-width: 4; c-basic-offset: 3; c-file-style: "linux" -*- */
  2. //
  3. // Copyright (c) 2009, Wei Mingzhi <whistler_wmz@users.sf.net>.
  4. // All rights reserved.
  5. //
  6. // Portions based on PalLibrary by Lou Yihua <louyihua@21cn.com>.
  7. // Copyright (c) 2006-2007, Lou Yihua.
  8. //
  9. // This file is part of SDLPAL.
  10. //
  11. // SDLPAL is free software: you can redistribute it and/or modify
  12. // it under the terms of the GNU General Public License as published by
  13. // the Free Software Foundation, either version 3 of the License, or
  14. // (at your option) any later version.
  15. //
  16. // This program is distributed in the hope that it will be useful,
  17. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. // GNU General Public License for more details.
  20. //
  21. // You should have received a copy of the GNU General Public License
  22. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  23. //
  24. #include "main.h"
  25. static INT
  26. PAL_RNGReadFrame(
  27. LPBYTE lpBuffer,
  28. UINT uiBufferSize,
  29. UINT uiRngNum,
  30. UINT uiFrameNum,
  31. FILE *fpRngMKF
  32. )
  33. /*++
  34. Purpose:
  35. Read a frame from a RNG animation.
  36. Parameters:
  37. [OUT] lpBuffer - pointer to the destination buffer.
  38. [IN] uiBufferSize - size of the destination buffer.
  39. [IN] uiRngNum - the number of the RNG animation in the MKF archive.
  40. [IN] uiFrameNum - frame number in the RNG animation.
  41. [IN] fpRngMKF - pointer to the fopen'ed MKF file.
  42. Return value:
  43. Integer value which indicates the size of the chunk.
  44. -1 if there are error in parameters.
  45. -2 if buffer size is not enough.
  46. --*/
  47. {
  48. UINT uiOffset = 0;
  49. UINT uiSubOffset = 0;
  50. UINT uiNextOffset = 0;
  51. UINT uiChunkCount = 0;
  52. INT iChunkLen = 0;
  53. if (lpBuffer == NULL || fpRngMKF == NULL || uiBufferSize == 0)
  54. {
  55. return -1;
  56. }
  57. //
  58. // Get the total number of chunks.
  59. //
  60. uiChunkCount = PAL_MKFGetChunkCount(fpRngMKF);
  61. if (uiRngNum >= uiChunkCount)
  62. {
  63. return -1;
  64. }
  65. //
  66. // Get the offset of the chunk.
  67. //
  68. fseek(fpRngMKF, 4 * uiRngNum, SEEK_SET);
  69. fread(&uiOffset, sizeof(UINT), 1, fpRngMKF);
  70. fread(&uiNextOffset, sizeof(UINT), 1, fpRngMKF);
  71. uiOffset = SDL_SwapLE32(uiOffset);
  72. uiNextOffset = SDL_SwapLE32(uiNextOffset);
  73. //
  74. // Get the length of the chunk.
  75. //
  76. iChunkLen = uiNextOffset - uiOffset;
  77. if (iChunkLen != 0)
  78. {
  79. fseek(fpRngMKF, uiOffset, SEEK_SET);
  80. }
  81. else
  82. {
  83. return -1;
  84. }
  85. //
  86. // Get the number of sub chunks.
  87. //
  88. fread(&uiChunkCount, sizeof(UINT), 1, fpRngMKF);
  89. uiChunkCount = (SDL_SwapLE32(uiChunkCount) - 4) / 4;
  90. if (uiFrameNum >= uiChunkCount)
  91. {
  92. return -1;
  93. }
  94. //
  95. // Get the offset of the sub chunk.
  96. //
  97. fseek(fpRngMKF, uiOffset + 4 * uiFrameNum, SEEK_SET);
  98. fread(&uiSubOffset, sizeof(UINT), 1, fpRngMKF);
  99. fread(&uiNextOffset, sizeof(UINT), 1, fpRngMKF);
  100. uiSubOffset = SDL_SwapLE32(uiSubOffset);
  101. uiNextOffset = SDL_SwapLE32(uiNextOffset);
  102. //
  103. // Get the length of the sub chunk.
  104. //
  105. iChunkLen = uiNextOffset - uiSubOffset;
  106. if ((UINT)iChunkLen > uiBufferSize)
  107. {
  108. return -2;
  109. }
  110. if (iChunkLen != 0)
  111. {
  112. fseek(fpRngMKF, uiOffset + uiSubOffset, SEEK_SET);
  113. fread(lpBuffer, iChunkLen, 1, fpRngMKF);
  114. }
  115. else
  116. {
  117. return -1;
  118. }
  119. return iChunkLen;
  120. }
  121. static INT
  122. PAL_RNGBlitToSurface(
  123. INT iNumRNG,
  124. INT iNumFrame,
  125. SDL_Surface *lpDstSurface,
  126. FILE *fpRngMKF
  127. )
  128. /*++
  129. Purpose:
  130. Blit one frame in an RNG animation to an SDL surface.
  131. The surface should contain the last frame of the RNG, or blank if it's the first
  132. frame.
  133. NOTE: Assume the surface is already locked, and the surface is a 320x200 8-bit one.
  134. Parameters:
  135. [IN] iNumRNG - The number of the animation in the MKF archive.
  136. [IN] iNumFrame - The number of the frame in the animation.
  137. [OUT] lpDstSurface - pointer to the destination SDL surface.
  138. [IN] fpRngMKF - Pointer to the fopen'ed rng.mkf file.
  139. Return value:
  140. 0 = success, -1 = error.
  141. --*/
  142. {
  143. INT ptr = 0;
  144. INT dst_ptr = 0;
  145. BYTE data = 0;
  146. WORD wdata = 0;
  147. INT x, y, i, n;
  148. LPBYTE rng = NULL;
  149. LPBYTE buf = NULL;
  150. //
  151. // Check for invalid parameters.
  152. //
  153. if (lpDstSurface == NULL || iNumRNG < 0 || iNumFrame < 0)
  154. {
  155. return -1;
  156. }
  157. buf = (LPBYTE)calloc(1, 65000);
  158. if (buf == NULL)
  159. {
  160. return -1;
  161. }
  162. //
  163. // Read the frame.
  164. //
  165. if (PAL_RNGReadFrame(buf, 65000, iNumRNG, iNumFrame, fpRngMKF) < 0)
  166. {
  167. free(buf);
  168. return -1;
  169. }
  170. //
  171. // Decompress the frame.
  172. //
  173. rng = (LPBYTE)calloc(1, 65000);
  174. if (rng == NULL)
  175. {
  176. free(buf);
  177. return -1;
  178. }
  179. Decompress(buf, rng, 65000);
  180. free(buf);
  181. //
  182. // Draw the frame to the surface.
  183. // FIXME: Dirty and ineffective code, needs to be cleaned up
  184. //
  185. while (TRUE)
  186. {
  187. data = rng[ptr++];
  188. switch (data)
  189. {
  190. case 0x00:
  191. case 0x13:
  192. //
  193. // End
  194. //
  195. goto end;
  196. case 0x02:
  197. dst_ptr += 2;
  198. break;
  199. case 0x03:
  200. data = rng[ptr++];
  201. dst_ptr += (data + 1) * 2;
  202. break;
  203. case 0x04:
  204. wdata = rng[ptr] | (rng[ptr + 1] << 8);
  205. ptr += 2;
  206. dst_ptr += ((unsigned int)wdata + 1) * 2;
  207. break;
  208. case 0x0a:
  209. x = dst_ptr % 320;
  210. y = dst_ptr / 320;
  211. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  212. if (++x >= 320)
  213. {
  214. x = 0;
  215. ++y;
  216. }
  217. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  218. dst_ptr += 2;
  219. case 0x09:
  220. x = dst_ptr % 320;
  221. y = dst_ptr / 320;
  222. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  223. if (++x >= 320)
  224. {
  225. x = 0;
  226. ++y;
  227. }
  228. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  229. dst_ptr += 2;
  230. case 0x08:
  231. x = dst_ptr % 320;
  232. y = dst_ptr / 320;
  233. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  234. if (++x >= 320)
  235. {
  236. x = 0;
  237. ++y;
  238. }
  239. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  240. dst_ptr += 2;
  241. case 0x07:
  242. x = dst_ptr % 320;
  243. y = dst_ptr / 320;
  244. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  245. if (++x >= 320)
  246. {
  247. x = 0;
  248. ++y;
  249. }
  250. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  251. dst_ptr += 2;
  252. case 0x06:
  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. break;
  264. case 0x0b:
  265. data = *(rng + ptr++);
  266. for (i = 0; i <= data; i++)
  267. {
  268. x = dst_ptr % 320;
  269. y = dst_ptr / 320;
  270. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  271. if (++x >= 320)
  272. {
  273. x = 0;
  274. ++y;
  275. }
  276. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  277. dst_ptr += 2;
  278. }
  279. break;
  280. case 0x0c:
  281. wdata = rng[ptr] | (rng[ptr + 1] << 8);
  282. ptr += 2;
  283. for (i = 0; i <= wdata; i++)
  284. {
  285. x = dst_ptr % 320;
  286. y = dst_ptr / 320;
  287. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  288. if (++x >= 320)
  289. {
  290. x = 0;
  291. ++y;
  292. }
  293. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr++];
  294. dst_ptr += 2;
  295. }
  296. break;
  297. case 0x0d:
  298. case 0x0e:
  299. case 0x0f:
  300. case 0x10:
  301. for (i = 0; i < data - (0x0d - 2); i++)
  302. {
  303. x = dst_ptr % 320;
  304. y = dst_ptr / 320;
  305. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr];
  306. if (++x >= 320)
  307. {
  308. x = 0;
  309. ++y;
  310. }
  311. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr + 1];
  312. dst_ptr += 2;
  313. }
  314. ptr += 2;
  315. break;
  316. case 0x11:
  317. data = *(rng + ptr++);
  318. for (i = 0; i <= data; i++)
  319. {
  320. x = dst_ptr % 320;
  321. y = dst_ptr / 320;
  322. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr];
  323. if (++x >= 320)
  324. {
  325. x = 0;
  326. ++y;
  327. }
  328. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr + 1];
  329. dst_ptr += 2;
  330. }
  331. ptr += 2;
  332. break;
  333. case 0x12:
  334. n = (rng[ptr] | (rng[ptr + 1] << 8)) + 1;
  335. ptr += 2;
  336. for (i = 0; i < n; i++)
  337. {
  338. x = dst_ptr % 320;
  339. y = dst_ptr / 320;
  340. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr];
  341. if (++x >= 320)
  342. {
  343. x = 0;
  344. ++y;
  345. }
  346. ((LPBYTE)(lpDstSurface->pixels))[y * lpDstSurface->pitch + x] = rng[ptr + 1];
  347. dst_ptr += 2;
  348. }
  349. ptr += 2;
  350. break;
  351. }
  352. }
  353. end:
  354. free(rng);
  355. return 0;
  356. }
  357. VOID
  358. PAL_RNGPlay(
  359. INT iNumRNG,
  360. INT iStartFrame,
  361. INT iEndFrame,
  362. INT iSpeed
  363. )
  364. /*++
  365. Purpose:
  366. Play a RNG movie.
  367. Parameters:
  368. [IN] iNumRNG - number of the RNG movie.
  369. [IN] iStartFrame - start frame number.
  370. [IN] iEndFrame - end frame number.
  371. [IN] iSpeed - speed of playing.
  372. Return value:
  373. None.
  374. --*/
  375. {
  376. UINT iTime;
  377. int iDelay = 800 / (iSpeed == 0 ? 16 : iSpeed);
  378. FILE *fp;
  379. fp = UTIL_OpenRequiredFile("rng.mkf");
  380. for (; iStartFrame <= iEndFrame; iStartFrame++)
  381. {
  382. iTime = SDL_GetTicks() + iDelay;
  383. if (PAL_RNGBlitToSurface(iNumRNG, iStartFrame, gpScreen, fp) == -1)
  384. {
  385. //
  386. // Failed to get the frame, don't go further
  387. //
  388. fclose(fp);
  389. return;
  390. }
  391. //
  392. // Update the screen
  393. //
  394. VIDEO_UpdateScreen(NULL);
  395. //
  396. // Fade in the screen if needed
  397. //
  398. if (gpGlobals->fNeedToFadeIn)
  399. {
  400. PAL_FadeIn(gpGlobals->wNumPalette, gpGlobals->fNightPalette, 1);
  401. gpGlobals->fNeedToFadeIn = FALSE;
  402. }
  403. //
  404. // Delay for a while
  405. //
  406. PAL_DelayUntil(iTime);
  407. }
  408. fclose(fp);
  409. }