rngplay.c 11 KB

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