Ramflx.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2016 RWS Inc, All Rights Reserved
  4. //
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of version 2 of the GNU General Public License as published by
  7. // the Free Software Foundation
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License along
  15. // with this program; if not, write to the Free Software Foundation, Inc.,
  16. // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. //
  18. ///////////////////////////////////////////////////////////////////////////////
  19. //
  20. // RAMFLX.CPP
  21. //
  22. // History:
  23. // 08/05/94 MR Started. (10h)
  24. //
  25. // 08/07/94 MR Got decompression working (except for SS2) and started
  26. // on compression. (13h)
  27. //
  28. // 08/08/94 MR General cleanup of interfaces, etc. (12h)
  29. //
  30. // 08/09/94 MR Finished up basic compression.
  31. //
  32. // 08/12/94 MR Added flags to FLX_BUF struct that indicate whether the
  33. // pixels and/or the colors were modified by a "Read".
  34. //
  35. // 08/15/94 MR Fixed bug in ReadFrame() -- if the requested frame was
  36. // the current frame, it was not copied to the specified buf.
  37. //
  38. // Also added a function that returns the last frame that
  39. // was written.
  40. //
  41. // 05/02/95 JW Added functionality for RAM buffer to store flic
  42. //
  43. // 05/03/95 JW Added ability to play uncompressed flics without having
  44. // to seek to the first frame.
  45. //
  46. // 11/03/95 JMI Converted to newest CImage and CNFile.
  47. //
  48. // 03/04/96 JMI ReadFrame now remembers whether the m_sColorsModified and
  49. // m_sPixelsModified flags were set at all during a read that
  50. // required parsing many frames and sets them to TRUE in such
  51. // a case.
  52. //
  53. ///////////////////////////////////////////////////////////////////////////////
  54. //
  55. // THIS FILE CONTAINS ONLY THE PUBLIC FUNCTIONS.
  56. // THE PRIVATE FUNCTIONS ARE IN FLXP.CPP
  57. //
  58. ///////////////////////////////////////////////////////////////////////////////
  59. //
  60. // Offers a clean and simple interface for reading and writing .FLC files.
  61. //
  62. // MEGA WARNING: The memory management being used in this module relies
  63. // completely on the memory model under which it is compiled. The recommended
  64. // model is large. However, in large model, flics larger than 320 x 200 are
  65. // not possible since the image data would exceed 64k! In the 32-bit future,
  66. // this will no longer be a problem. For now, we're stuck with it.
  67. // Note that using the huge memory model will not help because many of the
  68. // math and the indexes are "short" (16 bits), so the results would not be/
  69. // valid for larger than 320 x 200!
  70. //
  71. ///////////////////////////////////////////////////////////////////////////////
  72. #include <string.h>
  73. #include <malloc.h>
  74. #include <SMRTHEAP.HPP>
  75. #include "common/system.h"
  76. #include "ramflx/ramflx.h"
  77. ///////////////////////////////////////////////////////////////////////////////
  78. //
  79. // Default constructor. If this is used, then Setup() must be called before
  80. // any other function can be called.
  81. //
  82. ///////////////////////////////////////////////////////////////////////////////
  83. CRamFlx::CRamFlx(void)
  84. {
  85. // Set flags to default states
  86. m_sOpenForRead = FALSE;
  87. // Init CImage
  88. InitBuf(&m_imagePrev);
  89. // Clear file header
  90. ClearHeader();
  91. }
  92. ///////////////////////////////////////////////////////////////////////////////
  93. //
  94. // Destructor.
  95. //
  96. ///////////////////////////////////////////////////////////////////////////////
  97. CRamFlx::~CRamFlx()
  98. {
  99. // Close in case file was left open
  100. Close();
  101. // Clear header in case it's illegally accessed after we're destroyed
  102. ClearHeader();
  103. // Free any memory that needs freeing
  104. FreeBuf(&m_imagePrev);
  105. // Clear flags to default values (same reason we cleared header)
  106. m_sOpenForRead = FALSE;
  107. }
  108. ///////////////////////////////////////////////////////////////////////////////
  109. //
  110. // Open an existing FLC/FLI file for reading. You can optionally get a copy of
  111. // the file header and can optionally have your buf memory allocated for you.
  112. // Returns 0 if successfull, non-zero otherwise.
  113. //
  114. // 10/20/94, Paul Lin, add code to reset error conditions on the fstream object
  115. // so that the next time this function is called, it doesn't fail
  116. //
  117. ///////////////////////////////////////////////////////////////////////////////
  118. short CRamFlx::Open(
  119. char* pszFileName, // Full path and filename of flic file
  120. FLX_FILE_HDR* pfilehdr, // Copy of header returned here if not NULL
  121. CImage* pimage) // Memory allocated within struct if not NULL
  122. {
  123. short sError = 0;
  124. // Close in case it was left open
  125. Close();
  126. // Clear file header. This is done primarily for the older FLI files
  127. // so that all fields, even those that aren't used by FLI files, will
  128. // be set to default values.
  129. ClearHeader();
  130. CNFile file;
  131. // Open file (only if it already exists -- do not create new file!)
  132. if (file.Open(pszFileName, "rb", ENDIAN_LITTLE) == 0)
  133. {
  134. // Read the header. Regardless of whether it's a FLC or FLI file,
  135. // the header is returned as if it was a FLC file.
  136. if (ReadHeader(&file) == 0)
  137. {
  138. // Restart animation
  139. Restart();
  140. // Default is to read both pixels and color data from flic
  141. m_sReadPixels = TRUE;
  142. m_sReadColors = TRUE;
  143. // Is this a flic with no delta compression?
  144. if (m_filehdr.sReserveA == FLX_RSP_NODELTA)
  145. {
  146. // Create list of pointers to frames in the flic(no delta compression)
  147. sError = CreateFramePointers();
  148. // Make sure the memory file pointer resets to the first frame
  149. Restart();
  150. // Flic has no delta compression
  151. m_sNoDelta = TRUE;
  152. }
  153. else
  154. {
  155. // Flic has delta compression
  156. m_sNoDelta = FALSE;
  157. }
  158. // If user doesn' specify a buffer, then we need to allocate buffers for the
  159. // previous frame and the previous color palette.
  160. if (pimage == NULL)
  161. {
  162. sError = AllocBuf(&m_imagePrev, (long)m_filehdr.sWidth, (long)m_filehdr.sHeight, 256);
  163. }
  164. }
  165. else
  166. sError = 1;
  167. // Close the file, the flic is loaded into the buffer
  168. file.Close();
  169. }
  170. else
  171. sError = 1;
  172. // Final check for file errors
  173. if ((sError == 0) && m_file.Error() == TRUE)
  174. sError = 1;
  175. // If pointer to header not NULL, then return copy of header there
  176. if ((sError == 0) && (pfilehdr != NULL))
  177. *pfilehdr = m_filehdr;
  178. // If pointer to buf not NULL, then allocate memory
  179. if ((sError == 0) && (pimage != NULL))
  180. sError = CreateBuf(pimage, (long)m_filehdr.sWidth, (long)m_filehdr.sHeight, 256);
  181. // If no errors, then file is finally marked "open for reading"
  182. if (sError == 0)
  183. m_sOpenForRead = TRUE;
  184. return sError;
  185. }
  186. ///////////////////////////////////////////////////////////////////////////////
  187. //
  188. // Close the currently open file (if any). If a flic was being written to the
  189. // file, this will NOT properly complete the file. A separate function is
  190. // supplied for that, and it should be called before this function.
  191. // Returns 0 if successfull, non-zero otherwise.
  192. //
  193. ///////////////////////////////////////////////////////////////////////////////
  194. short CRamFlx::Close(CImage* pimage)
  195. {
  196. short sError = 1;
  197. // If file is open, try to close it.
  198. if (m_sOpenForRead)
  199. {
  200. // Clear flags
  201. m_sOpenForRead = FALSE;
  202. // Free any memory associated with image buf, flic buf, and frame pointers
  203. FreeBuf(&m_imagePrev);
  204. if (m_pucFlxBuf != NULL)
  205. {
  206. m_file.Close();
  207. free(m_pucFlxBuf);
  208. }
  209. if (m_sNoDelta == TRUE)
  210. {
  211. free(m_plFrames);
  212. }
  213. // Successfull
  214. sError = 0;
  215. }
  216. else
  217. sError = 0;
  218. // let's free the buffer passed in, if valid
  219. if (pimage != NULL)
  220. FreeBuf(pimage);
  221. return sError;
  222. }
  223. ///////////////////////////////////////////////////////////////////////////////
  224. //
  225. // Get copy of flic file header (file must have been opened or created). When
  226. // creating a new file, certain fields are not valid until the file is closed.
  227. // Returns 0 if successfull, non-zero otherwise.
  228. //
  229. ///////////////////////////////////////////////////////////////////////////////
  230. short CRamFlx::GetHeader(FLX_FILE_HDR* pFileHdr)
  231. {
  232. short sError = 1;
  233. if (m_sOpenForRead)
  234. {
  235. // Copy our header struct to user's struct
  236. *pFileHdr = m_filehdr;
  237. sError = 0;
  238. }
  239. return sError;
  240. }
  241. ///////////////////////////////////////////////////////////////////////////////
  242. //
  243. // Get the current frame number. When reading, this is the frame that was
  244. // last read. When writing, this is the frame that was last written. In both
  245. // cases, a value of 0 indicates that no frames have been read or written.
  246. // Otherwise, the number will be from 1 to n.
  247. //
  248. ///////////////////////////////////////////////////////////////////////////////
  249. short CRamFlx::GetFrameNum(void)
  250. {
  251. return m_sFrameNum;
  252. }
  253. ///////////////////////////////////////////////////////////////////////////////
  254. //
  255. // Read the specified flic frame (1 to n, anything else is an error). The
  256. // time it takes to get the frame is proportional to the number of frames
  257. // between it and the last frame that was read. In simple mode, if the same
  258. // frame is requested more than once in a row, that frame is simply returned
  259. // each time. In non-simple mode, requesting the same frame again requires
  260. // us to restart the animation and work our way up to that frame again.
  261. // Returns 0 if successfull, non-zero otherwise.
  262. //
  263. ///////////////////////////////////////////////////////////////////////////////
  264. short CRamFlx::ReadFrame(
  265. short sFrameNum, // Frame number to be read
  266. CImage* pimageRead) // Buffer for frame being read
  267. {
  268. short sError = 0;
  269. if (m_sOpenForRead &&
  270. (sFrameNum >= 1) &&
  271. (sFrameNum <= m_filehdr.sNumFrames))
  272. {
  273. if (m_sNoDelta == TRUE)
  274. {
  275. // Flics with no delta compression
  276. if (sFrameNum != m_sFrameNum)
  277. {
  278. // Set position in buffer for frame
  279. m_file.Seek(m_plFrames[sFrameNum], SEEK_SET);
  280. // Decompress packets into image buffer
  281. sError = ReadNextFrame(pimageRead);
  282. // Set the frame number to the correct frame currently in image buffer
  283. m_sFrameNum = sFrameNum;
  284. }
  285. }
  286. else
  287. {
  288. if (sFrameNum != m_sFrameNum)
  289. {
  290. short sColorsModified = FALSE;
  291. short sPixelsModified = FALSE;
  292. // If specified frame is before (or equal to) the current frame,
  293. // we need to restart the animation.
  294. if (sFrameNum <= m_sFrameNum)
  295. {
  296. Restart();
  297. // When restarting, we should set these flags for lack
  298. // of a way of knowing for sure.
  299. sColorsModified = TRUE;
  300. sPixelsModified = TRUE;
  301. }
  302. // Go frame-by-frame to the requested frame
  303. while ((m_sFrameNum < sFrameNum) && (sError == 0))
  304. {
  305. sError = ReadNextFrame(pimageRead);
  306. // If the colors are modified . . .
  307. if (m_sColorsModified != FALSE)
  308. {
  309. // We need to store this info since the next
  310. // frame may set m_sColorsModified to FALSE.
  311. sColorsModified = TRUE;
  312. }
  313. // If the pixels are modified . . .
  314. if (m_sPixelsModified != FALSE)
  315. {
  316. // We need to store this info since the next
  317. // frame may set m_sPixelsModified to FALSE.
  318. sPixelsModified = TRUE;
  319. }
  320. }
  321. // If flags were set at all during the loop,
  322. // they need to be set now.
  323. m_sColorsModified = sColorsModified;
  324. m_sPixelsModified = sPixelsModified;
  325. }
  326. }
  327. }
  328. else
  329. sError = 1;
  330. return sError;
  331. }
  332. ///////////////////////////////////////////////////////////////////////////////
  333. //
  334. // Read the next flic frame (if flic was just opened, this will read frame 1).
  335. // The "modified" flags are updated in the specified CImage.
  336. // Returns 0 if successfull, non-zero otherwise.
  337. //
  338. ///////////////////////////////////////////////////////////////////////////////
  339. short CRamFlx::ReadNextFrame(
  340. CImage* pimageRead) // Buffer for frame being read
  341. {
  342. short sError = 0;
  343. if (m_sOpenForRead)
  344. {
  345. if (pimageRead == NULL)
  346. {
  347. // Apply delta to our buf
  348. DoReadFrame(&m_imagePrev);
  349. }
  350. else
  351. {
  352. // Apply delta directly to user buf
  353. DoReadFrame(pimageRead);
  354. }
  355. }
  356. else
  357. sError = 1;
  358. return sError;
  359. }
  360. ///////////////////////////////////////////////////////////////////////////////
  361. //
  362. // Create a CImage based on the specified width, height, and number of colors.
  363. // Returns 0 if successfull, non-zero otherwise.
  364. //
  365. ///////////////////////////////////////////////////////////////////////////////
  366. short CRamFlx::CreateBuf(CImage* pimage, long lWidth, long lHeight, short sColors)
  367. {
  368. InitBuf(pimage);
  369. return AllocBuf(pimage, lWidth, lHeight, sColors);
  370. }
  371. ///////////////////////////////////////////////////////////////////////////////
  372. //
  373. // Destroy a CImage that was previously created using CreateBuf().
  374. // The CImage must not be used after this call!
  375. //
  376. ///////////////////////////////////////////////////////////////////////////////
  377. void CRamFlx::DestroyBuf(CImage* pimage)
  378. {
  379. FreeBuf(pimage);
  380. }
  381. ///////////////////////////////////////////////////////////////////////////////
  382. // EOF
  383. ///////////////////////////////////////////////////////////////////////////////