Flxp.cpp 64 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012
  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. // FLXP.CPP
  21. //
  22. // ??/??/?? ??? Created.
  23. //
  24. // 03/06/96 JMI Converted references from PORTABLE.H (e.g., DWORD) to
  25. // references from SYSTEM.H (e.g., ULONG).
  26. //
  27. ///////////////////////////////////////////////////////////////////////////////
  28. //
  29. // THIS FILE CONTAINS ONLY THE PRIVATE FUNCTIONS.
  30. // THE PUBLIC FUNCTIONS ARE IN FLX.CPP
  31. // ALL MAJOR COMMENT BLOCKS ARE IN FLX.CPP AS WELL.
  32. //
  33. ///////////////////////////////////////////////////////////////////////////////
  34. #include <malloc.h>
  35. #include <memory.h>
  36. #include <SMRTHEAP.HPP>
  37. #include "common/system.H"
  38. #include "flx/FLX.H"
  39. ///////////////////////////////////////////////////////////////////////////////
  40. //
  41. // Helper function that restarts at beginning of the flic.
  42. //
  43. ///////////////////////////////////////////////////////////////////////////////
  44. void CFlx::Restart(void)
  45. {
  46. // Seek to file position of frame 1
  47. m_file.Seek(m_filehdr.lOffsetFrame1, SEEK_SET);
  48. // Set frame number to 0 to indicate that nothing's been read yet.
  49. m_sFrameNum = 0;
  50. }
  51. ///////////////////////////////////////////////////////////////////////////////
  52. //
  53. // Read the next flic frame (if flic was just opened, this will read frame 1).
  54. // The "modified" flags are updated in the specified FLX_BUF.
  55. // Returns 0 if successfull, non-zero otherwise.
  56. //
  57. ///////////////////////////////////////////////////////////////////////////////
  58. short CFlx::DoReadFrame(FLX_BUF* pbufRead)
  59. {
  60. short sError = 0;
  61. // Always clear modified flags to FALSE. The lower-level functions will
  62. // set the appropriate flag to TRUE as necessary.
  63. pbufRead->bPixelsModified = FALSE;
  64. pbufRead->bColorsModified = FALSE;
  65. // Get current file position. After each chunk, we add the chunk size
  66. // to this position to get to the next chunk. We must do that seek
  67. // instead of relying on the amount of data that was read from the
  68. // chunk because that amount may be less than the indicated chunk size!
  69. // (This is not clearly documented, but was discovered the hard way!)
  70. long lFramePos = m_file.Tell();
  71. // Read frame chunk header
  72. FLX_FRAME_HDR framehdr;
  73. m_file.Read(&framehdr.lChunkSize);
  74. m_file.Read(&framehdr.wType);
  75. m_file.Read(&framehdr.sNumSubChunks);
  76. m_file.Read(framehdr.bReserved, 8);
  77. // Verify that it worked and it's the type we're expecting
  78. if (m_file.Error() == FALSE && framehdr.wType == 0xF1FA)
  79. {
  80. //cout << "Frame #" << m_sFrameNum << " has " << framehdr.sNumSubChunks << " data chunks" << endl;
  81. // Go through each of the sub-chunks. If there are no sub-chunks, then
  82. // frame is identical to the previous frame and there's nothing to do.
  83. FLX_DATA_HDR datahdr;
  84. for (short sSub = 0; sSub < framehdr.sNumSubChunks && sError == 0; sSub++)
  85. {
  86. // Get current file position. After each chunk, we add the chunk size
  87. // to this position to get to the next chunk. We must do that seek
  88. // instead of relying on the amount of data that was read from the
  89. // chunk because that amount may be less than the indicated chunk size!
  90. // (This is not clearly documented, but was discovered the hard way!)
  91. long lDataPos = m_file.Tell();
  92. // Read data chunk header
  93. m_file.Read(&datahdr.lChunkSize);
  94. m_file.Read(&datahdr.wType);
  95. if (m_file.Error() == FALSE)
  96. {
  97. // Size of actual data is chunk size minus header size (6)
  98. long lDataSize = datahdr.lChunkSize - 6;
  99. // Call the appropriate function based on data type
  100. switch(datahdr.wType)
  101. {
  102. case FLX_DATA_COLOR256:
  103. //cout << " DATA_COLOR256 of size " << lDataSize << endl;
  104. if (pbufRead->prgbColors != NULL)
  105. sError = ReadDataColor(pbufRead, FLX_DATA_COLOR256);
  106. break;
  107. case FLX_DATA_SS2:
  108. //cout << " DATA_SS2 of size " << lDataSize << endl;
  109. if (pbufRead->pbPixels != NULL)
  110. sError = ReadDataSS2(pbufRead);
  111. break;
  112. case FLX_DATA_COLOR:
  113. //cout << " DATA_COLOR of size " << lDataSize << endl;
  114. if (pbufRead->prgbColors != NULL)
  115. sError = ReadDataColor(pbufRead, FLX_DATA_COLOR);
  116. break;
  117. case FLX_DATA_LC:
  118. //cout << " DATA_LC of size " << lDataSize << endl;
  119. if (pbufRead->pbPixels != NULL)
  120. sError = ReadDataLC(pbufRead);
  121. break;
  122. case FLX_DATA_BLACK:
  123. //cout << " DATA_BLACK of size " << lDataSize << endl;
  124. if (pbufRead->pbPixels != NULL)
  125. sError = ReadDataBlack(pbufRead);
  126. break;
  127. case FLX_DATA_BRUN:
  128. //cout << " DATA_BRUN of size " << lDataSize << endl;
  129. if (pbufRead->pbPixels != NULL)
  130. sError = ReadDataBRun(pbufRead);
  131. break;
  132. case FLX_DATA_COPY:
  133. //cout << " DATA_COPY of size " << lDataSize << endl;
  134. if (pbufRead->pbPixels != NULL)
  135. sError = ReadDataCopy(pbufRead);
  136. break;
  137. case FLX_DATA_PSTAMP:
  138. //cout << " DATA_PSTAMP of size " << lDataSize << endl;
  139. // We always ignore postage stamp data for now.
  140. break;
  141. default:
  142. //cout << " DATA UNKNOWN!!!! of size " << lDataSize << endl;
  143. //comment out the assert 10/20/94 to prevent crash
  144. //assert(0); // Should never get here!
  145. sError = 1;
  146. break;
  147. }
  148. // Adjust file position based on specified chunk size.
  149. m_file.Seek(lDataPos + datahdr.lChunkSize, SEEK_SET);
  150. }
  151. else
  152. sError = 1;
  153. }
  154. // Adjust file position based on specified chunk size.
  155. m_file.Seek(lFramePos + framehdr.lChunkSize, SEEK_SET);
  156. }
  157. else
  158. sError = 1;
  159. // If everything went fine, update the frame number.
  160. if (sError == 0)
  161. {
  162. // If frame number reaches NumFrames+1, then we just did the "ring"
  163. // frame, which is the delta between the flic's last and first frames.
  164. if (++m_sFrameNum == (m_filehdr.sNumFrames + 1))
  165. {
  166. // Reset frame number
  167. m_sFrameNum = 1;
  168. // Seek to file position of frame 2 (the next one we'll do)
  169. m_file.Seek(m_filehdr.lOffsetFrame2, SEEK_SET);
  170. }
  171. }
  172. return sError;
  173. }
  174. ///////////////////////////////////////////////////////////////////////////////
  175. //
  176. // Handler for data chunks containing color information (FLX_DATA_COLOR256 and
  177. // FLX_DATA_COLOR.)
  178. //
  179. // The first word of data specifies the number of "packets" that follow.
  180. // Each packet consists of a byte that specifies the number of colors to
  181. // skip, a byte that specifies the number of colors to do, and three bytes
  182. // of RGB data for each of the colors to do.
  183. //
  184. // The idea is that the color palette index starts out at 0. For each
  185. // packet, we add the number of colors to skip to the color palette index.
  186. // We then get the number of colors to do and, for each one, we read the
  187. // 3 byte RGB data and copy it to the next color in the palette. This is
  188. // repeated for each packet.
  189. //
  190. // NOTE: The Autodesk doc's don't mention this, but if the number of colors
  191. // to do is 0, it really means 256! This was discovered the hard way.
  192. //
  193. // As an example, to change palette colors 2, 7, 8 and 9, the following data
  194. // would be used:
  195. //
  196. // 2 ; word specifies 2 packets
  197. // 2, 1, r,g,b ; skip 2, do 1
  198. // 4, 3, r,g,b, r,g,b, r,g,b ; skip 4, do 3
  199. //
  200. // The only difference between the two color-oriented data types are that
  201. // for FLX_DATA_COLOR256, the RGB values range from 0 to 255, while for
  202. // FLX_DATA_COLOR, they range from 0 to 63. This is an older format, so
  203. // we convert them to the newer format by shifting them left 2 bits.
  204. //
  205. ///////////////////////////////////////////////////////////////////////////////
  206. short CFlx::ReadDataColor(FLX_BUF* pbufRead, short sDataType)
  207. {
  208. //assert(pbufRead->prgbColors != NULL);
  209. // instead of assert, just return error
  210. if (pbufRead->prgbColors == NULL)
  211. return 1;
  212. short sError = 0;
  213. // Read number of packets
  214. short sNumPackets;
  215. m_file.Read(&sNumPackets);
  216. // Start the color index at 0 and then process each of the packets
  217. short sColorIndex = 0;
  218. short sCnt;
  219. short sColorDo;
  220. UCHAR bColorSkip;
  221. UCHAR bVal;
  222. for (short sPack = 0; (sPack < sNumPackets) && (sError == 0); sPack++)
  223. {
  224. // Read number of colors to skip and add to color index
  225. m_file.Read(&bColorSkip);
  226. sColorIndex = sColorIndex + (short)bColorSkip;
  227. // Read number of colors to do. This determines how many sets
  228. // of r,g,b data (3 bytes) will follow. If this count is 0, it
  229. // must be interpreted as a count of 256!
  230. m_file.Read(&bVal);
  231. if (bVal != 0)
  232. sColorDo = (short)bVal;
  233. else
  234. sColorDo = (short)256;
  235. // Make sure we won't index past end of palette! This would only
  236. // happen if we were getting bogus data from the file.
  237. if ((sColorIndex + sColorDo) <= 256)
  238. {
  239. // Read the specified number of RGB values (3 bytes each) into the
  240. // proper color entry(s) in the palette
  241. m_file.Read(&(pbufRead->prgbColors[sColorIndex]), 3 * sColorDo);
  242. if (sDataType == FLX_DATA_COLOR256)
  243. {
  244. sColorIndex = sColorIndex + sColorDo;
  245. }
  246. else
  247. {
  248. // For FLX_DATA_COLOR, the RGB values range from 0 to 63, and must
  249. // be shifted left 2 bits to bring them up to 0 to 255.
  250. for (sCnt = 0; sCnt < sColorDo; sCnt++)
  251. {
  252. pbufRead->prgbColors[sColorIndex].bR <<= 2;
  253. pbufRead->prgbColors[sColorIndex].bG <<= 2;
  254. pbufRead->prgbColors[sColorIndex].bB <<= 2;
  255. sColorIndex++;
  256. }
  257. }
  258. }
  259. else
  260. sError = 1;
  261. }
  262. // Set modified flag
  263. pbufRead->bColorsModified = TRUE;
  264. // If not good, then flag error
  265. if (m_file.Error() != FALSE)
  266. sError = 1;
  267. return sError;
  268. }
  269. ///////////////////////////////////////////////////////////////////////////////
  270. //
  271. // Handler for data chunks of type FLX_DATA_BLACK.
  272. //
  273. // These chunks contain no data. They are essentially a command that tells
  274. // us to clear all the pixels to color index 0.
  275. //
  276. ///////////////////////////////////////////////////////////////////////////////
  277. short CFlx::ReadDataBlack(FLX_BUF* pbufRead)
  278. {
  279. //assert(pbufRead->pbPixels != NULL);
  280. //assert(pbufRead->sPitch > 0);
  281. // let's just return with error instead of asserting and crashing
  282. if ((pbufRead->pbPixels == NULL) || (pbufRead->sPitch <= 0))
  283. return 1;
  284. // Clear the image to 0 one row at a time. Note that we use the pitch
  285. // to move from the start of on row to the start of the next row.
  286. UCHAR* pbMem = pbufRead->pbPixels;
  287. for (short y = 0; y < m_filehdr.sHeight; y++)
  288. {
  289. memset(pbMem, 0, m_filehdr.sWidth);
  290. pbMem += (ULONG)pbufRead->sPitch;
  291. }
  292. // Set modified flag
  293. pbufRead->bPixelsModified = TRUE;
  294. // There can be no error!
  295. return 0;
  296. }
  297. ///////////////////////////////////////////////////////////////////////////////
  298. //
  299. // Handler for data chunks of type FLX_DATA_COPY.
  300. //
  301. // These chunks contain an uncompressed image of the frame. The number of
  302. // bytes following the chunk is the animation's width times its height.
  303. // The data goes from left to right and then top to bottom.
  304. //
  305. // These chunks occur rarely, being used only if the compressed frame would
  306. // take up more room than the uncompressed frame!
  307. //
  308. ///////////////////////////////////////////////////////////////////////////////
  309. short CFlx::ReadDataCopy(FLX_BUF* pbufRead)
  310. {
  311. //assert(pbufRead->pbPixels != NULL);
  312. //assert(pbufRead->sPitch > 0);
  313. // let's just return with error instead of asserting
  314. if ((pbufRead->pbPixels == NULL) || (pbufRead->sPitch <= 0))
  315. return 1;
  316. short sError = 0;
  317. // Read in the image one row at a time. Note that we use the pitch
  318. // to move from the start of on row to the start of the next row.
  319. UCHAR* pbMem = pbufRead->pbPixels;
  320. for (short y = 0; y < m_filehdr.sHeight; y++)
  321. {
  322. m_file.Read(pbMem, m_filehdr.sWidth);
  323. pbMem += (ULONG)pbufRead->sPitch;
  324. }
  325. // Set modified flag
  326. pbufRead->bPixelsModified = TRUE;
  327. // If not good, then flag error
  328. if (m_file.Error() != FALSE)
  329. sError = 1;
  330. return sError;
  331. }
  332. ///////////////////////////////////////////////////////////////////////////////
  333. //
  334. // Handler for data chunks of type FLX_DATA_BRUN.
  335. //
  336. // These chunks contain the entire image in compressed form. This is usually
  337. // used for the first frame or within a postage stamp image chunk.
  338. //
  339. // The data is organized into lines, starting at the top of the image and
  340. // moving down. The number of lines is based on the height in the flic header.
  341. //
  342. // The data for each line starts with a byte that contains the number of
  343. // packets for that line. This is a holdover from the original Autodesk
  344. // Animator which only supported a width of 320, so it didn't need more than
  345. // 255 packets. Animator Pro, which supports much larger widths, may need
  346. // more than 255 packets, so it can't use a byte. The officially sanctioned
  347. // way to deal with this byte is to ignore it, and to instead use the width
  348. // (from the flic header) to determine when each line is done (simply keep
  349. // count of the number of pixels that have been decompressed for that line,
  350. // and when it reaches the width, the line is done).
  351. //
  352. // Each packet contains a count byte followed by one or more pixels. If the
  353. // count is negative (bit 7 = 1) then its absolute value is the number of pixels
  354. // that follow it. If the count is positive (bit 7 = 0) then a single pixel
  355. // follows it and that pixel is to be replicated that number of times.
  356. //
  357. ///////////////////////////////////////////////////////////////////////////////
  358. short CFlx::ReadDataBRun(FLX_BUF* pbufRead)
  359. {
  360. //assert(pbufRead->pbPixels != NULL);
  361. //assert(pbufRead->sPitch > 0);
  362. // let's just return with error instead of asserting
  363. if ((pbufRead->pbPixels == NULL) || (pbufRead->sPitch <= 0))
  364. return 1;
  365. // added 10/20/94 to trap errors and exit! instead of asserting
  366. short sError = 0;
  367. UCHAR bVal;
  368. S8 cVal;
  369. short sCount;
  370. short x;
  371. short y;
  372. UCHAR* pbRow;
  373. UCHAR* pbPix;
  374. // Decompress image one row at a time. Note that we use the pitch
  375. // to move from the start of one row to the start of the next row.
  376. pbRow = pbufRead->pbPixels;
  377. for (y = 0; (y < m_filehdr.sHeight) && (sError == 0); y++)
  378. {
  379. // First byte is number of packets, which can be ignored (Animator used
  380. // it, but Animator Pro, which supports width > 320, does not.)
  381. m_file.Read(&cVal);
  382. // Keep processing packets until we reach the width
  383. pbPix = pbRow;
  384. x = 0;
  385. while ((x < m_filehdr.sWidth) && (sError == 0))
  386. {
  387. // First byte of each packet is type/size. If bit 7 is 1, bits 6-0
  388. // are number of pixels to be copied. If bit 7 is 0, bits 6-0 are
  389. // the number of times to replicate a single pixel.
  390. m_file.Read(&cVal);
  391. //assert(cVal != 0); // Not sure how to handle 0!
  392. if (cVal != 0)
  393. {
  394. sCount = (short)cVal;
  395. if (sCount < 0)
  396. {
  397. sCount = -sCount;
  398. x += sCount;
  399. m_file.Read(pbPix, sCount);
  400. pbPix += (ULONG)sCount;
  401. }
  402. else
  403. {
  404. x += sCount;
  405. m_file.Read(&bVal);
  406. memset(pbPix, (int)bVal, (size_t)sCount);
  407. pbPix += (ULONG)sCount;
  408. }
  409. }
  410. else
  411. {
  412. sError = 1;
  413. }
  414. }
  415. pbRow += (ULONG)pbufRead->sPitch;
  416. }
  417. // just return if error has been set
  418. if (sError == 1)
  419. return sError;
  420. // Set modified flag
  421. pbufRead->bPixelsModified = TRUE;
  422. if (m_file.Error() == FALSE)
  423. return 0;
  424. else
  425. return 1;
  426. }
  427. ///////////////////////////////////////////////////////////////////////////////
  428. //
  429. // Handler for data chunks of type FLX_DATA_LC.
  430. //
  431. // These chunks contain the differences between the previous frame and this
  432. // frame. These are the most common types of pixel data chunks in the older
  433. // FLI files written by the original Autodesk animator. This is no longer used
  434. // by Animator Pro, but they may appear in an Animator Pro file if Animator Pro
  435. // reads an older file and modifies only some of its frames.
  436. //
  437. // The first word (16 bits) specifies the y coordinate of the first line that
  438. // was different from the previous image. This value can range from 0 to
  439. // height - 1.
  440. //
  441. // The second word (16 bits) specifies the number of lines that are represented
  442. // in this data chunk.
  443. //
  444. // The following data is organized into lines, starting at the specified y
  445. // coordinate and moving down.
  446. //
  447. // The data for each line starts with a byte that contains the number of
  448. // packets for that line. (Note: Unlike the BRUN compression, this packet
  449. // count cannot be ignored because there's no other way to know how many pixels
  450. // will be updated on each line.)
  451. //
  452. // Each packet starts with a byte that indicates how many pixels to move to the
  453. // right. At the start of each line, the position is assumed to be at the
  454. // first (left-most) pixel on that line. This skip count is added to that
  455. // position to move to the first pixel that will be changed by this packet.
  456. // This process continues across the line, with each packet adding on to the
  457. // position that the previous packet ended up on. For instance, if the first
  458. // packet specified a skip of 8 and then copied 3 pixels to the screen, then
  459. // second packet would start at 11 and would add its skip count to that.
  460. //
  461. // The skip byte is followed by a count byte which is followed by one or more
  462. // pixels. If the count is positive (bit 7 = 0) then that is the number of
  463. // pixels that follow it. If the count is negative (bit 7 = 1) then a single
  464. // pixel follows it and the count's absolute value specifies how often that
  465. // pixel is to be replicated. (Note: The positive/negative nature of the
  466. // count is reversed from the BTUN compression!)
  467. //
  468. ///////////////////////////////////////////////////////////////////////////////
  469. short CFlx::ReadDataLC(FLX_BUF* pbufRead)
  470. {
  471. //assert(pbufRead->pbPixels != NULL);
  472. //assert(pbufRead->sPitch > 0);
  473. // just return with error instead of asserting
  474. if ((pbufRead->pbPixels == NULL) || (pbufRead->sPitch <= 0))
  475. return 1;
  476. UCHAR bVal;
  477. S8 cVal;
  478. short sCount;
  479. short y;
  480. short lines;
  481. short packets;
  482. UCHAR* pbRow;
  483. UCHAR* pbPix;
  484. // The first word specifies the starting y (another way of looking at it
  485. // is the number of lines that are unchanged from the previous image).
  486. m_file.Read(&y);
  487. // Init row pointer to point at start of specified row
  488. pbRow = pbufRead->pbPixels + ((ULONG)y * (ULONG)pbufRead->sPitch);
  489. // The second word specifies the number of lines in this chunk.
  490. m_file.Read(&lines);
  491. // Let's check to see if the pixels are modified from the previous frame by
  492. // checking the number of delta lines. If the number of delta lines is zero, then
  493. // we know that there is no delta.
  494. if (lines < 1)
  495. {
  496. // Set to unmodified.
  497. pbufRead->bPixelsModified = FALSE;
  498. }
  499. else
  500. {
  501. // Set modified flag
  502. pbufRead->bPixelsModified = TRUE;
  503. }
  504. // If all's well...
  505. if (m_file.Error() == FALSE)
  506. {
  507. while (lines > 0)
  508. {
  509. // Set pixel pointer to start of row
  510. pbPix = pbRow;
  511. // For debugging, prefetch a bunch of values to view them in the debugger
  512. #if 0
  513. long lPos = m_file.Tell();
  514. static UCHAR bData[100];
  515. m_file.Read(bData, sizeof(bData));
  516. m_file.Seek(lPos, SEEK_SET);
  517. #endif
  518. // The first byte for each line is the number of packets.
  519. // This can be 0, which indicates no changes on that line.
  520. m_file.Read(&bVal);
  521. packets = (short)bVal;
  522. while (packets > 0)
  523. {
  524. // The first byte of each packet is a column skip.
  525. // Adjust pixel pointer to skip that number of pixels.
  526. m_file.Read(&bVal);
  527. pbPix = pbPix + (ULONG)bVal;
  528. // Second byte of each packet is type/size. If bit 7 is 0, bits 6-0
  529. // are number of pixels to be copied. If bit 7 is 1, bits 6-0 are
  530. // the number of times to replicate a single pixel.
  531. m_file.Read(&cVal);
  532. // assert(cVal != 0); // Not sure how to handle 0, so stop if it comes up!
  533. if (cVal == 0)
  534. cVal = 0;
  535. sCount = (short)cVal;
  536. if (sCount > 0)
  537. {
  538. m_file.Read(pbPix, sCount);
  539. pbPix += (ULONG)sCount;
  540. }
  541. else
  542. {
  543. sCount = -sCount;
  544. m_file.Read(&bVal);
  545. memset(pbPix, (int)bVal, (size_t)sCount);
  546. pbPix += (ULONG)sCount;
  547. }
  548. // Adjust remaining packets
  549. packets--;
  550. }
  551. // Move row pointer to start of next row
  552. pbRow += (ULONG)pbufRead->sPitch;
  553. // Adjust remaining lines
  554. lines--;
  555. }
  556. }
  557. if (m_file.Error() == FALSE)
  558. return 0;
  559. else
  560. return 1;
  561. }
  562. ///////////////////////////////////////////////////////////////////////////////
  563. //
  564. // Handler for data chunks of type FLX_DATA_SS2.
  565. //
  566. // These chunks contain the differences between the previous frame and this
  567. // frame. They are similar to FLX_DATA_LC, but are word oriented instead of
  568. // byte oriented.
  569. //
  570. // The first word for "each line can begin with some optional words
  571. // that are used to skip lines and set the last byte in the line for
  572. // animations with odd widths." The next word will be the number of
  573. // packets. The first byte of each packet is a column skip.
  574. // Second byte of each packet is type/size. If bit 7 is 0, bits 6-0
  575. // are number of pixel pairs to be copied. If bit 7 is 1, bits 6-0 are
  576. // the number of times to replicate a single pixel pair.
  577. //
  578. ///////////////////////////////////////////////////////////////////////////////
  579. short CFlx::ReadDataSS2(FLX_BUF* pbufRead)
  580. {
  581. //assert(pbufRead->pbPixels != NULL);
  582. //assert(pbufRead->sPitch > 0);
  583. // just return with error instead of asserting
  584. if ((pbufRead->pbPixels == NULL) || (pbufRead->sPitch <= 0))
  585. return 1;
  586. UCHAR bVal;
  587. S8 cVal;
  588. USHORT wVal;
  589. short sCount;
  590. short y;
  591. short lines;
  592. short packets;
  593. UCHAR* pbPix;
  594. UCHAR byLastByte;
  595. short bLastByte = FALSE;
  596. // The first word specifies the starting y (another way of looking at it
  597. // is the number of lines that are unchanged from the previous image).
  598. // The first word specifies the number of lines in this chunk.
  599. m_file.Read(&lines);
  600. // Let's check to see if any actual delta is being processed and set the
  601. // pixels modified flag accordingly.
  602. if (lines < 1)
  603. {
  604. // Make sure the modified flag is FALSE.
  605. pbufRead->bPixelsModified = FALSE;
  606. }
  607. else
  608. {
  609. // Set modified flag to true.
  610. pbufRead->bPixelsModified = TRUE;
  611. }
  612. // If all's well...
  613. if (m_file.Error() == FALSE)
  614. {
  615. // Start at line 0
  616. y = 0;
  617. while (lines > 0)
  618. {
  619. // For debugging, prefetch a bunch of values to view them in the debugger
  620. #if 0
  621. long lPos = m_file.Tell();
  622. static UCHAR bData[100];
  623. m_file.Read(bData, sizeof(bData));
  624. m_file.Seek(lPos, SEEK_SET);
  625. #endif
  626. // The first word for "each line can begin with some optional words
  627. // that are used to skip lines and set the last byte in the line for
  628. // animations with odd widths."
  629. do
  630. {
  631. m_file.Read(&wVal);
  632. // "The high order two bits of the word is used to determine the
  633. // contents of the word."
  634. switch (wVal & 0xC000)
  635. {
  636. // 0 0 The word contains the packet count; the packets follow
  637. // this word. This is our signal to stop processing "optional
  638. // words".
  639. case 0x0000:
  640. break;
  641. // 1 0 "The low order byte is to be stored in the last bye of
  642. // the current line. The packet count always folows this word."
  643. // This is another signal to stop processing "optional words".
  644. case 0x8000:
  645. //assert(bLastByte != TRUE); // We should not have already set the "last byte".
  646. // if this error condition occurs, let's just break out of everything and return error
  647. // this should not cause any problems with the stack since return should clear it
  648. if (bLastByte == TRUE)
  649. return 1;
  650. byLastByte = (UCHAR)(wVal & (USHORT)0x00ff);
  651. bLastByte = TRUE;
  652. // Read the packet count.
  653. m_file.Read(&wVal);
  654. break;
  655. // 1 1 "The word contains a line skip count. The number of
  656. // lines skipped is given by the absolute value of the word.
  657. // This is NOT a signal to stop processing "optional words".
  658. case 0xC000:
  659. // Skip abs(wVal) lines
  660. y += -((short)wVal);
  661. break;
  662. }
  663. } while ((wVal & 0xC000) == 0xC000);
  664. // The packet count should now be in wVal.
  665. packets = (short)wVal;
  666. // Init pointer to point at start of specified row
  667. pbPix = pbufRead->pbPixels + ((ULONG)y * (ULONG)pbufRead->sPitch);
  668. while (packets > 0)
  669. {
  670. // The first byte of each packet is a column skip.
  671. // Adjust pixel pointer to skip that number of pixels.
  672. m_file.Read(&bVal);
  673. pbPix = pbPix + (ULONG)bVal;
  674. // Second byte of each packet is type/size. If bit 7 is 0, bits 6-0
  675. // are number of pixel pairs to be copied. If bit 7 is 1, bits 6-0 are
  676. // the number of times to replicate a single pixel pair.
  677. m_file.Read(&cVal);
  678. // assert(cVal != 0); // Not sure how to handle 0, so stop if it comes up!
  679. #if 0 // this seems to do nothing, so I'm removing it -- Jon 9/28/94
  680. if (cVal == 0)
  681. cVal = 0;
  682. #endif
  683. sCount = (short)cVal;
  684. if (sCount > 0)
  685. {
  686. sCount *= sizeof(USHORT);
  687. m_file.Read(pbPix, sCount);
  688. pbPix += (ULONG)(sCount);
  689. }
  690. else
  691. {
  692. sCount = (short)-sCount;
  693. m_file.Read(&wVal);
  694. // memset(pbPix, (int)wVal, (size_t)sCount);
  695. USHORT* pwPix = (USHORT*)pbPix;
  696. for (short i = 0; i < sCount; i++)
  697. *pwPix++ = wVal;
  698. pbPix = (UCHAR*)pwPix;
  699. }
  700. // Adjust remaining packets
  701. packets--;
  702. }
  703. // Place last byte if specified.
  704. if (bLastByte == TRUE)
  705. {
  706. // Get pointer to end of this row.
  707. pbPix = pbufRead->pbPixels + (((ULONG)y + 1L) * (ULONG)pbufRead->sPitch) - 1L;
  708. // Set pixel at end of row.
  709. *pbPix = byLastByte;
  710. bLastByte = FALSE;
  711. }
  712. // Adjust remaining lines
  713. lines--;
  714. // Go to next line
  715. y++;
  716. }
  717. }
  718. if (m_file.Error() == FALSE)
  719. return 0;
  720. else
  721. return 1;
  722. }
  723. ///////////////////////////////////////////////////////////////////////////////
  724. //
  725. // Helper function that actually writes the delta between two frames, or
  726. // just writes the frame if its the first one.
  727. // Since this is an "internal" function, we can relax our validation tests.
  728. // Always returns with file position at next byte after frame that was written.
  729. // Returns 0 if successfull, non-zero otherwise.
  730. //
  731. ///////////////////////////////////////////////////////////////////////////////
  732. short CFlx::DoWriteFrame(FLX_BUF* pbufWrite, FLX_BUF* pbufPrev)
  733. {
  734. long lDataChunkSize;
  735. short sError = 0;
  736. // Update the frame number
  737. m_sFrameNum++;
  738. // Get current file position. We will seek back to this position to
  739. // update the frame chunk's header after its contents have been written.
  740. long lFramePos = m_file.Tell();
  741. // Set frame chunk header fields to initial values.
  742. FLX_FRAME_HDR framehdr;
  743. framehdr.lChunkSize = 16L; // Start with size of this header
  744. framehdr.wType = 0xF1FA; // Frames are always this type
  745. framehdr.sNumSubChunks = 0; // No sub-chunks yet
  746. memset(framehdr.bReserved, 0, 8); // Zero reserved bytes
  747. // Write temporary frame chunk header
  748. m_file.Write(&framehdr.lChunkSize);
  749. m_file.Write(&framehdr.wType);
  750. m_file.Write(&framehdr.sNumSubChunks);
  751. m_file.Write(framehdr.bReserved, 8);
  752. // Allocate buffer into which delta data can be written. Minumum size
  753. // is width times height plus an extra margin.
  754. // WARNING: This will only support up to 64k!!!
  755. // double dSize = (double)m_filehdr.sWidth * (double)m_filehdr.sHeight * (double)1.5;
  756. UCHAR* pBuf = (UCHAR*)malloc((USHORT)m_filehdr.sWidth * (USHORT)m_filehdr.sHeight);
  757. if (pBuf != NULL)
  758. {
  759. // Generate color palette delta. For first frame, pbufPrev will be
  760. // NULL, so all the colors will be considered as being changed.
  761. sError = WriteColorDelta(pbufWrite, pbufPrev, pBuf, &lDataChunkSize);
  762. if ((sError == 0) && (lDataChunkSize > 0))
  763. {
  764. // Update total frame chunk size and number of sub-chunks
  765. framehdr.lChunkSize += lDataChunkSize;
  766. framehdr.sNumSubChunks++;
  767. }
  768. // Generate pixel delta
  769. sError = WritePixelDelta(pbufWrite, pbufPrev, pBuf, &lDataChunkSize);
  770. if ((sError == 0) && (lDataChunkSize > 0))
  771. {
  772. // Update total frame chunk size and number of sub-chunks
  773. framehdr.lChunkSize += lDataChunkSize;
  774. framehdr.sNumSubChunks++;
  775. }
  776. // Seek back to start of frame header, write the updated version,
  777. // and then seek to position after end of frame chunk.
  778. m_file.Seek(lFramePos, SEEK_SET);
  779. m_file.Write(&framehdr.lChunkSize);
  780. m_file.Write(&framehdr.wType);
  781. m_file.Write(&framehdr.sNumSubChunks);
  782. m_file.Write(framehdr.bReserved, sizeof(framehdr.bReserved));
  783. m_file.Seek(lFramePos + framehdr.lChunkSize, SEEK_SET);
  784. // If we just did frame 1, then the current file position is the start
  785. // of frame 2, which is saved in the flic file header.
  786. if (m_sFrameNum == 1)
  787. m_filehdr.lOffsetFrame2 = m_file.Tell();
  788. // Print diagnostic info about frame
  789. //cout << "Frame #" << m_sFrameNum << " has " << framehdr.sNumSubChunks << " data chunks" << endl;
  790. // Free the buffer
  791. free(pBuf);
  792. }
  793. else
  794. sError = 1; // Out of memory
  795. return sError;
  796. }
  797. ///////////////////////////////////////////////////////////////////////////////
  798. //
  799. // Generate a color delta data chunk based on the differences between the
  800. // two specified palettes. If there is no difference, then no data is written.
  801. // If pBufPrev is NULL, then we assume all the colors changed.
  802. //
  803. ///////////////////////////////////////////////////////////////////////////////
  804. short CFlx::WriteColorDelta(FLX_BUF* pbufNext, FLX_BUF* pbufPrev, UCHAR* pBuf, long* plChunkSize)
  805. {
  806. short sError = 0;
  807. // Always default to chunk size of 0 in case no data is written
  808. *plChunkSize = 0;
  809. // Set up data chunk type based on FLC -vs- FLI.
  810. USHORT wType;
  811. if (m_filehdr.wMagic == FLX_MAGIC_FLC)
  812. wType = FLX_DATA_COLOR256;
  813. else
  814. wType = FLX_DATA_COLOR;
  815. // Set up easier-to-use pointers to colors
  816. FLX_RGB* pNext = pbufNext->prgbColors;
  817. FLX_RGB* pPrev;
  818. if (pbufPrev != NULL)
  819. pPrev = pbufPrev->prgbColors;
  820. // Set up copy of pointer to buffer than can be moved around
  821. UCHAR* pOut = pBuf;
  822. // First word of output is number of packets, which starts out at 0.
  823. USHORT* pwPackets = (USHORT*)pOut;
  824. pOut = pOut + 2;
  825. *pwPackets = 0;
  826. // Keep track of size of output data (includes the word above)
  827. long lSize = 2;
  828. // Keep looping through colors, generating packets that describe the delta
  829. // between the two palettes. Each packet tells how many colors were the
  830. // same, how many changed, and what they changed to (r,g,b).
  831. short sSame;
  832. short sChanged;
  833. short sIndex;
  834. short sStart = 0;
  835. while (sStart < 256)
  836. {
  837. // Count number of colors that are the same (stop on first changed color)
  838. if (pbufPrev != NULL)
  839. {
  840. for (sSame = 0; (sStart + sSame) < 256; sSame++)
  841. {
  842. if ((pNext[sStart + sSame].bR != pPrev[sStart + sSame].bR) ||
  843. (pNext[sStart + sSame].bG != pPrev[sStart + sSame].bG) ||
  844. (pNext[sStart + sSame].bB != pPrev[sStart + sSame].bB))
  845. break;
  846. }
  847. }
  848. else
  849. sSame = 0;
  850. // Adjust start to skip over the colors that were the same
  851. sStart += sSame;
  852. // Count number of colors that have changed (stop on first same color)
  853. // If there are no previous colors, then we say that they all changed
  854. if (pbufPrev != NULL)
  855. {
  856. for (sChanged = 0; (sStart + sChanged) < 256; sChanged++)
  857. {
  858. if ((pNext[sStart + sChanged].bR == pPrev[sStart + sChanged].bR) &&
  859. (pNext[sStart + sChanged].bG == pPrev[sStart + sChanged].bG) &&
  860. (pNext[sStart + sChanged].bB == pPrev[sStart + sChanged].bB))
  861. break;
  862. }
  863. }
  864. else
  865. sChanged = 256;
  866. // If any colors changed, we generate a new packet
  867. if (sChanged > 0)
  868. {
  869. // Adjust number of packets
  870. (*pwPackets)++;
  871. // Write number of colors to skip and number to be changed.
  872. // Note that 256 is written as a 0 since it must fit in a byte!
  873. *pOut++ = (UCHAR)sSame;
  874. *pOut++ = (UCHAR)sChanged;
  875. lSize += 2;
  876. // Write out the r,g,b values for the colors that changed
  877. for (sIndex = 0; sIndex < sChanged; sIndex++)
  878. {
  879. // For FLX_DATA_COLOR256, colors use the full 0-255 range
  880. if (wType == FLX_DATA_COLOR256)
  881. {
  882. *pOut++ = pNext[sStart + sIndex].bR;
  883. *pOut++ = pNext[sStart + sIndex].bG;
  884. *pOut++ = pNext[sStart + sIndex].bB;
  885. }
  886. // For FLX_DATA_COLOR, colors use only a 0-63 range
  887. else
  888. {
  889. *pOut++ = (UCHAR)(pNext[sStart + sIndex].bR >> 2) & (UCHAR)0x3f;
  890. *pOut++ = (UCHAR)(pNext[sStart + sIndex].bG >> 2) & (UCHAR)0x3f;
  891. *pOut++ = (UCHAR)(pNext[sStart + sIndex].bB >> 2) & (UCHAR)0x3f;
  892. }
  893. lSize += 3;
  894. }
  895. }
  896. // Adjust start to skip over the colors that were different
  897. sStart += sChanged;
  898. }
  899. // If any packets were generated, then we need to write out the data
  900. if (*pwPackets > 0)
  901. {
  902. // Write out the data chunk (size is returned into plChunkSize!)
  903. sError = WriteDataChunk(pBuf, lSize, wType, plChunkSize);
  904. }
  905. return sError;
  906. }
  907. ///////////////////////////////////////////////////////////////////////////////
  908. //
  909. // Generate a color delta data chunk based on the differences between the
  910. // two specified palettes. If there is no difference, then no data is written.
  911. //
  912. // This is an outline of the logic that should be used based on the doc's:
  913. // 1. If image is all zeroes then generate FLX_DATA_BLACK chunk
  914. // 2. Compress using FLX_DATA_BRUN or BLX_DATA_SS2 (FLC) or FLX_DATA_LC (FLI)
  915. // 3. If compressed size < original size then write compressed chunk.
  916. // 4. If compressed size > original size then write FLX_DATA_COPY chunk.
  917. //
  918. // Instead, we simply always write out a FLX_DATA_BRUN chunk. This was done
  919. // only because of time constraints. In the future, the "real" logic should
  920. // be implemented.
  921. //
  922. // 10/20/94, Paul Lin, Modified this routine to write both the FLX_DATA_SS2 and
  923. // FLX_DATA_LC formats; either format will automatically be
  924. // selected depending on the file format (FLI/FLC) and whether
  925. // the current frame written is the first frame or any other
  926. // frame.
  927. //
  928. ///////////////////////////////////////////////////////////////////////////////
  929. short CFlx::WritePixelDelta(FLX_BUF* pbufNext, FLX_BUF* pbufPrev, UCHAR* pBuf, long* plChunkSize)
  930. {
  931. short sError = 0;
  932. // Always default to chunk size of 0 in case no data is written
  933. *plChunkSize = 0;
  934. #if 0
  935. // Copy image one row at a time into buffer.
  936. UCHAR* pbSrc = pbufNext->pbPixels;
  937. UCHAR* pbDst = pBuf;
  938. for (short y = 0; y < m_filehdr.sHeight; y++)
  939. {
  940. memcpy(pbDst, pbSrc, m_filehdr.sWidth); // Copy source to buffer
  941. pbSrc += (ULONG)pbufNext->sPitch; // Use pitch on source
  942. pbDst += (ULONG)m_filehdr.sWidth; // Use width on buffer
  943. }
  944. long lSize = (long)m_filehdr.sWidth * (long)m_filehdr.sHeight;
  945. // Write out the chunk
  946. sError = WriteDataChunk(pBuf, lSize, FLX_DATA_COPY, plChunkSize);
  947. #endif
  948. #if 0
  949. long lSize = CompressBRUN(pbufNext->pbPixels, pbufNext->sPitch,
  950. 0, 0, m_filehdr.sWidth, m_filehdr.sHeight, pBuf);
  951. // Write out the chunk
  952. sError = WriteDataChunk(pBuf, lSize, FLX_DATA_BRUN, plChunkSize);
  953. return sError;
  954. #endif
  955. if (pbufNext == NULL)
  956. return 1;
  957. // find out whether we are dealing with the first frame or not
  958. if (pbufPrev == NULL)
  959. {
  960. // since the previous frame buffer has not been defined, let's assume that this is the first frame
  961. // let's first do the BRUN compression and see what is the size returned
  962. long lSizeBRUN = CompressBRUN(pbufNext->pbPixels, pbufNext->sPitch,
  963. 0, 0, m_filehdr.sWidth, m_filehdr.sHeight, pBuf);
  964. long lSizeCOPY = (long)m_filehdr.sWidth * (long)m_filehdr.sHeight;
  965. if (lSizeBRUN <= lSizeCOPY)
  966. {
  967. // the size attained by BRUN compress is smaller,
  968. // let's write out the chunk
  969. sError = WriteDataChunk(pBuf, lSizeBRUN, FLX_DATA_BRUN, plChunkSize);
  970. }
  971. else
  972. {
  973. // the size attained by BRUN is actually larger, must be a complicated image
  974. // let's use the FLX_DATA_COPY format instead!
  975. // Copy image one row at a time into buffer.
  976. UCHAR* pbSrc = pbufNext->pbPixels;
  977. UCHAR* pbDst = pBuf;
  978. for (short y = 0; y < m_filehdr.sHeight; y++)
  979. {
  980. memcpy(pbDst, pbSrc, m_filehdr.sWidth); // Copy source to buffer
  981. pbSrc += (ULONG)pbufNext->sPitch; // Use pitch on source
  982. pbDst += (ULONG)m_filehdr.sWidth; // Use width on buffer
  983. }
  984. // Write out the chunk
  985. sError = WriteDataChunk(pBuf, lSizeCOPY, FLX_DATA_COPY, plChunkSize);
  986. }
  987. }
  988. else
  989. {
  990. // the current frame is not the first frame, we need to determine which encoding scheme to use
  991. if (m_filehdr.wMagic == FLX_MAGIC_FLI)
  992. {
  993. // Since the current format is FLI, let's encode with FLX_DATA_LC
  994. short y; // used to index through the pixel buffers
  995. long lSize; // size of the current compressed line
  996. short sFirstYPos = m_filehdr.sHeight-1; // the first line which is different
  997. short sLineCount = 0; // number of lines in the chunk
  998. UCHAR* pbDst = pBuf + 4; // point to the chunk data storage, the first 4 bytes are used to store
  999. // number of initial unchanged lines and # of lines in the chunk
  1000. long lSizeLC = 4; // size of the chunk in pBuf
  1001. short sEmptyLineCount = 0; // number of empty delta lines encountered back to back
  1002. // Do this line by line.
  1003. for (y = 0; y < m_filehdr.sHeight; y++)
  1004. {
  1005. // Process/encode the current line.
  1006. sError = CompressLineDelta(y, pbufNext, pbufPrev, pbDst, lSize, sizeof(UCHAR), sEmptyLineCount);
  1007. // Trap real errors.
  1008. if (sError == -1)
  1009. return sError;
  1010. // Check to results of the line delta compression.
  1011. if (sError != 0)
  1012. {
  1013. // The current line did not compress. Find out whether previous lines has been compressed before.
  1014. // If no other previous line has been compressed yet, we can simply go onto the next line.
  1015. if (sLineCount != 0)
  1016. {
  1017. // Other previous lines has been compressed already. Determine whether to maintain a empty delta line count.
  1018. // Increment the empty line count.
  1019. sEmptyLineCount++;
  1020. }
  1021. }
  1022. else
  1023. {
  1024. // The current line compressed. We need to check to see if this was the first compressible line.
  1025. if (sEmptyLineCount > 0)
  1026. {
  1027. sLineCount += sEmptyLineCount;
  1028. sEmptyLineCount = 0;
  1029. }
  1030. if (sLineCount == 0)
  1031. {
  1032. // This is the first compressed line. Need to set the line skip for the chunk.
  1033. sFirstYPos = y;
  1034. sLineCount++;
  1035. }
  1036. else
  1037. {
  1038. // Since this is not the first compressed line, increment the line count.
  1039. sLineCount++;
  1040. }
  1041. // Make sure we increment the size count and the chunk pointer.
  1042. pbDst += lSize;
  1043. lSizeLC += lSize;
  1044. }
  1045. }
  1046. // Done with all the lines. Write out the number of lines encoded.
  1047. *(USHORT*)pBuf = (USHORT)sFirstYPos;
  1048. *(USHORT*)(pBuf + 2) = (USHORT)sLineCount;
  1049. // Write out the chunk.
  1050. sError = WriteDataChunk(pBuf, lSizeLC, FLX_DATA_LC, plChunkSize);
  1051. }
  1052. else
  1053. {
  1054. // Since the current format is FLC, let's encode with FLX_DATA_SS2
  1055. short y; // used to index through the pixel buffers
  1056. long lSize; // size of the current compressed line
  1057. UCHAR* pbDst = pBuf + 2; // point to the chunk storage data, past the line count word
  1058. long lSizeSS2 = 2; // size of the chunk in pBuf
  1059. short sLines = 0; // number of line in this chunk
  1060. short sLineSkipCount = 0; // number of lines to skip
  1061. // Do this line by line.
  1062. for (y = 0; y < m_filehdr.sHeight; y++)
  1063. {
  1064. // Process/encode the current line.
  1065. sError = CompressLineDelta(y, pbufNext, pbufPrev, pbDst, lSize, sizeof(USHORT), sLineSkipCount);
  1066. // Trap real errors.
  1067. if (sError == -1)
  1068. return sError;
  1069. // Check to see if the current line compressed.
  1070. if (sError != 0)
  1071. {
  1072. // Since the current line didn't compress, increment the sLineSkipCount to keep track of how many
  1073. // unchanged lines were skipped.
  1074. sLineSkipCount++;
  1075. }
  1076. else
  1077. {
  1078. // The current line compressed. We need to reset the line skip count to zero. Also increment line count.
  1079. sLineSkipCount = 0;
  1080. sLines++;
  1081. // Make sure we increment the size count and the chunk pointer.
  1082. pbDst += lSize;
  1083. lSizeSS2 += lSize;
  1084. }
  1085. }
  1086. // Now that we're done with all the lines, let's write the number of lines in the chunk.
  1087. *(short*)pBuf = sLines;
  1088. // Write out the chunk!
  1089. sError = WriteDataChunk(pBuf, lSizeSS2, FLX_DATA_SS2, plChunkSize);
  1090. }
  1091. }
  1092. return sError;
  1093. }
  1094. /////////////////////////////////////////////////////////////////////////////
  1095. //
  1096. // Name: CompressLineDelta
  1097. //
  1098. // Description: This function will perform either UCHAR/USHORT oriented delta
  1099. // compression, given the current line. If compression is possible,
  1100. // the compressed data will be written to the buffer provided.
  1101. // Otherwise, an error will be returned to indicate no compression.
  1102. //
  1103. // Input: y = current line to compress
  1104. // pbufNext = pointer to the current flx frame
  1105. // pbufPrev = pointer to the previous flx frame
  1106. // pbDst = pointer to the chunk area to be written to, updated
  1107. // lSize = size of the current compressed line
  1108. // sAlign = specifies the data size alignment
  1109. // sLineSkipCount = skip lines for word oriented delta compression for word aligned
  1110. // or contains number of empty lines for byte aligned
  1111. //
  1112. // Output: (short)
  1113. // 0 = Compression success
  1114. // 1 = No compression took place
  1115. // -1 = A real error occurred!
  1116. //
  1117. // History: 10/25/94, Paul Lin, original coding.
  1118. //
  1119. /////////////////////////////////////////////////////////////////////////////
  1120. short CFlx::CompressLineDelta(short y,
  1121. FLX_BUF* pbufNext,
  1122. FLX_BUF* pbufPrev,
  1123. UCHAR* pbDst,
  1124. long& lSize,
  1125. short sAlign,
  1126. short sLineSkipCount)
  1127. {
  1128. // Local variables.
  1129. ULONG dwOffset; // Offset into the pixel data.
  1130. UCHAR* pbSrcNext = pbufNext->pbPixels; // Pointer to the pixel data of the current frame.
  1131. UCHAR* pbSrcPrev = pbufPrev->pbPixels; // Pointer to the pixel data of the previous frame.
  1132. short sPacket = 0; // Count the number of packets.
  1133. UCHAR* pbPacketCount; // Pointer to the packet count.
  1134. short x = 0; // Current position within the current line.
  1135. short sAdjustedPitch; // Pitch of the current line, adjusted if word aligned
  1136. short sSkipCount; // Count the bytes/words skipped over.
  1137. UCHAR* pbByteCount; // Used to hold the position for the byte count temporarily.
  1138. short sIndex; // Used as an index variable.
  1139. // Initialize the size.
  1140. lSize = 0;
  1141. sAdjustedPitch = pbufNext->sPitch;
  1142. // Check to make sure that all pointers to the buffers are not null.
  1143. if ((pbufNext == NULL) || (pbufPrev == NULL) || (pbDst == NULL))
  1144. return -1;
  1145. // First let's see if the current line really need to be compressed.
  1146. dwOffset = (ULONG)y * (ULONG)pbufNext->sPitch;
  1147. if (memcmp(pbSrcNext + dwOffset, pbSrcPrev + dwOffset, (size_t)pbufNext->sPitch) == 0)
  1148. {
  1149. // The current line does not need to be compressed!
  1150. return 1;
  1151. }
  1152. // Since the current line contains delta info between current and previous frame, let's do actual delta compression.
  1153. // Do we need to do anything before we start constructing the packets?
  1154. if ((sAlign == 1) && (sLineSkipCount != 0))
  1155. {
  1156. // Let's put in sLineSkipCount number of 0 packets.
  1157. for (sIndex = 0; sIndex < sLineSkipCount; sIndex++)
  1158. {
  1159. *(pbDst + (ULONG)lSize++) = 0;
  1160. }
  1161. }
  1162. else if (sAlign == 2)
  1163. {
  1164. // For word aligned delta compression, we need to do the optional words, as applicable.
  1165. if (sLineSkipCount > 0)
  1166. {
  1167. // Since we have skipped some lines prior to current line, let's write it to the chunk.
  1168. *(short*)(pbDst + (ULONG)lSize) = -sLineSkipCount;
  1169. lSize += 2;
  1170. }
  1171. // If the pitch is odd, we need to store the last byte if different.
  1172. // if ((pbufNext->sPitch % 2) == 1)
  1173. // {
  1174. dwOffset = ((ULONG)y * (ULONG)pbufNext->sPitch) + (ULONG)(pbufNext->sPitch - 1);
  1175. if (pbSrcNext[dwOffset] != pbSrcPrev[dwOffset])
  1176. {
  1177. // The last byte is different. We need to save it!
  1178. // Put the value in the low-order byte.
  1179. USHORT wLastByte = (USHORT)pbSrcNext[dwOffset];
  1180. wLastByte = wLastByte | 0x8000;
  1181. // Save it to the chunk.
  1182. *(USHORT*)(pbDst + (ULONG)lSize) = wLastByte;
  1183. lSize += 2;
  1184. }
  1185. // Adjust the pitch to eliminate the odd byte. Useful for testing limits later.
  1186. // sAdjustedPitch--;
  1187. // }
  1188. }
  1189. // Save the position in the chunk for storing the packet count.
  1190. pbPacketCount = pbDst + (ULONG)lSize;
  1191. if (sAlign == 1)
  1192. lSize++;
  1193. else
  1194. lSize += 2;
  1195. sSkipCount = 0;
  1196. x = 0;
  1197. sPacket = 0;
  1198. while (((sAlign == 1) && (x < sAdjustedPitch)) || ((sAlign == 2) && (x < sAdjustedPitch - 1)))
  1199. {
  1200. // Do the skip count first.
  1201. dwOffset = (ULONG)y * (ULONG)pbufNext->sPitch;
  1202. while ((x < sAdjustedPitch) && (pbSrcNext[dwOffset + x] == pbSrcPrev[dwOffset + x]))
  1203. {
  1204. // Since the pixel data are still the same, let's increment the skip count and x.
  1205. x++;
  1206. sSkipCount++;
  1207. }
  1208. // Continue only if we have not skipped past the end.
  1209. if (((sAlign == 1) && (x < sAdjustedPitch)) || ((sAlign == 2) && (x < sAdjustedPitch - 1)))
  1210. {
  1211. // Even though the codes are very similar between the byte and word aligned delta compression,
  1212. // for ease of reading and simplification, the two will be separated from this point on.
  1213. if (sAlign == 1)
  1214. {
  1215. // Update the pointer offset.
  1216. dwOffset = (ULONG)y * (ULONG)pbufNext->sPitch + x - sSkipCount;
  1217. // Do delta compression for byte aligned.
  1218. while (sSkipCount > 255)
  1219. {
  1220. // Put in a packet of one byte and 255 for skip count.
  1221. *(pbDst + (ULONG)lSize++) = 255;
  1222. *(pbDst + (ULONG)lSize++) = 1;
  1223. // Increment the pixel data offset by 255
  1224. dwOffset += 255;
  1225. *(pbDst + (ULONG)lSize++) = pbSrcNext[dwOffset];
  1226. // Increment the packet count and decrement the skip count.
  1227. sPacket++;
  1228. sSkipCount -= 256;
  1229. }
  1230. // Write out the skip count for the current packet and reset the skip count.
  1231. *(pbDst + (ULONG)lSize++) = (UCHAR)sSkipCount;
  1232. sSkipCount = 0;
  1233. // Set the byte counter before we start compressing.
  1234. UCHAR nBytes = 1;
  1235. // Determine the packet type.
  1236. dwOffset = (ULONG)y * (ULONG)pbufNext->sPitch;
  1237. if ((x < (sAdjustedPitch - 1)) && (pbSrcNext[dwOffset + x] == pbSrcNext[dwOffset + x + 1]))
  1238. {
  1239. // Let's process as count encoding for bytes of similar values.
  1240. x++;
  1241. while ((nBytes < 127) &&
  1242. (x < sAdjustedPitch) &&
  1243. (pbSrcNext[dwOffset + (x - 1)] == pbSrcNext[dwOffset + x]) &&
  1244. (pbSrcNext[dwOffset + x] != pbSrcPrev[dwOffset + x]))
  1245. {
  1246. x++;
  1247. nBytes++;
  1248. }
  1249. // Write the rest of the packet out.
  1250. // We need the byte count to be in 2's complement (negative).
  1251. nBytes = 255 - nBytes + 1;
  1252. *(pbDst + (ULONG)lSize++) = nBytes;
  1253. *(pbDst + (ULONG)lSize++) = pbSrcNext[dwOffset + (x - 1)];
  1254. sPacket++;
  1255. }
  1256. else
  1257. {
  1258. // Let's process as count of different bytes.
  1259. pbByteCount = pbDst + (ULONG)lSize++;
  1260. *(pbDst + (ULONG)lSize++) = pbSrcNext[dwOffset + x];
  1261. x++;
  1262. while ((nBytes < 127) &&
  1263. (x < sAdjustedPitch) &&
  1264. (pbSrcNext[dwOffset + x] != pbSrcPrev[dwOffset + x]) &&
  1265. !((x < (sAdjustedPitch - 1)) && (pbSrcNext[dwOffset + x] == pbSrcNext[dwOffset + x + 1])))
  1266. {
  1267. *(pbDst + (ULONG)lSize++) = pbSrcNext[dwOffset + x];
  1268. x++;
  1269. nBytes++;
  1270. }
  1271. // Save the byte count to complete the current packet.
  1272. *pbByteCount = nBytes;
  1273. sPacket++;
  1274. }
  1275. }
  1276. else
  1277. {
  1278. // Do delta compression for word aligned.
  1279. // Update the pointer offset.
  1280. dwOffset = (ULONG)y * (ULONG)pbufNext->sPitch + x - sSkipCount;
  1281. // Do delta compression for byte aligned.
  1282. while (sSkipCount > 255)
  1283. {
  1284. // Put in a packet of one byte and 255 for skip count.
  1285. *(pbDst + (ULONG)lSize++) = 254;
  1286. *(pbDst + (ULONG)lSize++) = 1;
  1287. // Increment the pixel data offset by 255. Remember to copy a word value!
  1288. dwOffset += 254;
  1289. *(pbDst + (ULONG)lSize++) = pbSrcNext[dwOffset++];
  1290. *(pbDst + (ULONG)lSize++) = pbSrcNext[dwOffset++];
  1291. // Increment the packet count and decrement the skip count.
  1292. sPacket++;
  1293. sSkipCount -= 256;
  1294. }
  1295. // Write out the skip count for the current packet and reset the skip count.
  1296. *(pbDst + (ULONG)lSize++) = (UCHAR)sSkipCount;
  1297. sSkipCount = 0;
  1298. // Set the byte counter before we start compressing.
  1299. UCHAR nBytes = 1;
  1300. // Determine the packet type.
  1301. dwOffset = (ULONG)y * (ULONG)pbufNext->sPitch;
  1302. if ((x < (sAdjustedPitch - 3)) &&
  1303. (pbSrcNext[dwOffset + x] == pbSrcNext[dwOffset + x + 2]) &&
  1304. (pbSrcNext[dwOffset + x + 1] == pbSrcNext[dwOffset + x + 3]))
  1305. {
  1306. // Let's process as count encoding for words of similar values.
  1307. x += 2;
  1308. while ((nBytes < 127) &&
  1309. (x < (sAdjustedPitch - 1)) &&
  1310. (pbSrcNext[dwOffset + x - 2] == pbSrcNext[dwOffset + x]) &&
  1311. (pbSrcNext[dwOffset + x - 1] == pbSrcNext[dwOffset + x + 1]) &&
  1312. (pbSrcNext[dwOffset + x + 1] != pbSrcPrev[dwOffset + x + 1]) &&
  1313. (pbSrcNext[dwOffset + x] != pbSrcPrev[dwOffset + x]))
  1314. {
  1315. x += 2;
  1316. nBytes++;
  1317. }
  1318. // Write the rest of the packet out.
  1319. // We need the byte count to be in 2's complement (negative).
  1320. nBytes = 255 - nBytes + 1;
  1321. *(pbDst + (ULONG)lSize++) = nBytes;
  1322. *(pbDst + (ULONG)lSize++) = pbSrcNext[dwOffset + x - 2];
  1323. *(pbDst + (ULONG)lSize++) = pbSrcNext[dwOffset + x - 1];
  1324. sPacket++;
  1325. }
  1326. else
  1327. {
  1328. // Let's process as count of different bytes.
  1329. pbByteCount = pbDst + (ULONG)lSize++;
  1330. *(pbDst + (ULONG)lSize++) = pbSrcNext[dwOffset + x];
  1331. *(pbDst + (ULONG)lSize++) = pbSrcNext[dwOffset + x + 1];
  1332. x += 2;
  1333. while ((nBytes < 127) &&
  1334. (x < (sAdjustedPitch - 1)) &&
  1335. ((pbSrcNext[dwOffset + x] != pbSrcPrev[dwOffset + x]) ||
  1336. (pbSrcNext[dwOffset + x + 1] != pbSrcPrev[dwOffset + x + 1])) &&
  1337. !((x < (sAdjustedPitch - 3)) &&
  1338. (pbSrcNext[dwOffset + x] == pbSrcNext[dwOffset + x + 2]) &&
  1339. (pbSrcNext[dwOffset + x + 1] == pbSrcNext[dwOffset + x + 3])))
  1340. {
  1341. *(pbDst + (ULONG)lSize++) = pbSrcNext[dwOffset + x];
  1342. *(pbDst + (ULONG)lSize++) = pbSrcNext[dwOffset + x + 1];
  1343. x += 2;
  1344. nBytes++;
  1345. }
  1346. // Save the byte count to complete the current packet.
  1347. *pbByteCount = nBytes;
  1348. sPacket++;
  1349. }
  1350. }
  1351. }
  1352. }
  1353. // Remember to write out the number of packets.
  1354. if (sAlign == 1)
  1355. *pbPacketCount = (UCHAR)sPacket;
  1356. else
  1357. *(USHORT*)pbPacketCount = (USHORT)sPacket;
  1358. // Compression successful.
  1359. return 0;
  1360. }
  1361. /////////////////////////////////////////////////////////////////////////////
  1362. //
  1363. // Compresses pixels using the BRUN method.
  1364. //
  1365. /////////////////////////////////////////////////////////////////////////////
  1366. long CFlx::CompressBRUN(
  1367. UCHAR* pbIn, // Pointer to input (pixels to be compressed)
  1368. short sPitch, // Pitch (distance from one pixel to the pixel below it)
  1369. short sSrcX, // Starting x of rectangular area to compress
  1370. short sSrcY, // Starting y of rectangular area to compress
  1371. short sWidth, // Width of rectangular area to compress
  1372. short sHeight, // Height of rectangular area to compress
  1373. UCHAR* pbOut) // Pointer to output (compressed data)
  1374. {
  1375. long lUniqueX;
  1376. long lUniqueCnt;
  1377. long lRepeatCnt;
  1378. UCHAR bRepeatPix;
  1379. long x;
  1380. long y;
  1381. long lOutCnt = 0;
  1382. UCHAR* pbPackets;
  1383. // Adjust input pointer based on starting x and y
  1384. pbIn = pbIn + ((ULONG)sSrcY * (ULONG)sPitch) + (ULONG)sSrcX;
  1385. // Loop through the scanlines
  1386. for (y = 0; y < sHeight; y++)
  1387. {
  1388. // Write out number of packets on this line. This is a holdover from
  1389. // the older Animator program. Autodesk recommends that it be ignored
  1390. // and that the width be used to figure out when the line is done.
  1391. // Just to be safe, we update it anyway. Note, however, that if
  1392. // we are compressing a very wide image, then this count could go over
  1393. // 256, but it's only a byte, so it'll get truncated. By the way, this
  1394. // is why Autodesk ignores it in the new FLI file!
  1395. pbPackets = pbOut; // Get pointer to this byte
  1396. *pbPackets = 0; // Init packet count to 0
  1397. pbOut++; // Skip over packet count
  1398. lOutCnt++;
  1399. // Loop through the pixels in the current scanline
  1400. lUniqueCnt = 0;
  1401. lUniqueX = 0;
  1402. x = 0;
  1403. do {
  1404. // Count how many additional pixels match current pixel
  1405. lRepeatCnt = 0;
  1406. bRepeatPix = pbIn[x];
  1407. lRepeatCnt++;
  1408. while ((x + lRepeatCnt < sWidth) && (lRepeatCnt < 127))
  1409. {
  1410. if (pbIn[x + lRepeatCnt] == bRepeatPix)
  1411. lRepeatCnt++;
  1412. else
  1413. break;
  1414. }
  1415. // If repeat is greater than or equal to minimum then it
  1416. // qualifies for its own repeat packet.
  1417. if (lRepeatCnt >= 3)
  1418. {
  1419. // If necessary, write out pending unique packet.
  1420. if (lUniqueCnt > 0)
  1421. {
  1422. (*pbPackets)++;
  1423. *pbOut++ = (UCHAR)(-lUniqueCnt); // Unique counts are negative
  1424. lOutCnt++;
  1425. do {
  1426. *pbOut++ = pbIn[lUniqueX++];
  1427. lOutCnt++;
  1428. } while (--lUniqueCnt);
  1429. }
  1430. // Now write out the repeat packet.
  1431. (*pbPackets)++;
  1432. *pbOut++ = (UCHAR)lRepeatCnt;
  1433. lOutCnt++;
  1434. *pbOut++ = bRepeatPix;
  1435. lOutCnt++;
  1436. // Move ahead to next next pixel after the repeated pixels.
  1437. x += lRepeatCnt;
  1438. // Reset unique stuff
  1439. lUniqueX = x;
  1440. lUniqueCnt = 0;
  1441. }
  1442. else
  1443. {
  1444. // Move ahead to next pixel
  1445. x++;
  1446. // Inc unique size
  1447. lUniqueCnt++;
  1448. // If necessary, write out unique packet.
  1449. if (lUniqueCnt == 127)
  1450. {
  1451. (*pbPackets)++;
  1452. *pbOut++ = (UCHAR)(-lUniqueCnt); // Unique counts are negative
  1453. lOutCnt++;
  1454. do {
  1455. *pbOut++ = pbIn[lUniqueX++];
  1456. lOutCnt++;
  1457. } while (--lUniqueCnt);
  1458. }
  1459. }
  1460. } while (x < sWidth);
  1461. // If necessary, write out pending unique packet.
  1462. if (lUniqueCnt > 0)
  1463. {
  1464. (*pbPackets)++;
  1465. *pbOut++ = (UCHAR)(-lUniqueCnt); // Unique counts are negative
  1466. lOutCnt++;
  1467. do {
  1468. *pbOut++ = pbIn[lUniqueX++];
  1469. lOutCnt++;
  1470. } while (--lUniqueCnt);
  1471. }
  1472. // Update pointer to point at next scan line. Note that we use a
  1473. // different width here since the scan line could be wider than the
  1474. // number of pixels being compressed.
  1475. pbIn += (ULONG)sPitch;
  1476. }
  1477. return lOutCnt;
  1478. }
  1479. ///////////////////////////////////////////////////////////////////////////////
  1480. //
  1481. // Helper function that write a data chunk using the specified data/values.
  1482. //
  1483. ///////////////////////////////////////////////////////////////////////////////
  1484. short CFlx::WriteDataChunk(UCHAR* pbData, long lSize, USHORT wType, long* plChunkSize)
  1485. {
  1486. FLX_DATA_HDR datahdr;
  1487. // Fill in the data chunk header
  1488. datahdr.lChunkSize = 6 + lSize; // Set to header size plus data size
  1489. datahdr.wType = wType; // Set indicated type
  1490. // If chunk size is odd, round it up to the next even value
  1491. if (datahdr.lChunkSize & 1)
  1492. datahdr.lChunkSize++;
  1493. // Get current file position (the start of the data chunk header)
  1494. long lDataPos = m_file.Tell();
  1495. // Write data chunk header
  1496. m_file.Write(&datahdr.lChunkSize);
  1497. m_file.Write(&datahdr.wType);
  1498. // Write the actual data (first make sure there is some!)
  1499. if (lSize > 0)
  1500. {
  1501. // Because intel sucks, we must use multiple writes for large data.
  1502. // The write size is a 16-bit int, so it is limited to <= 32767!
  1503. // We use 16384 (16k) because it's easier to think about.
  1504. while(lSize >= 16384L)
  1505. {
  1506. m_file.Write(pbData, (int)16384);
  1507. pbData += (ULONG)16384;
  1508. lSize -= 16384;
  1509. }
  1510. if (lSize > 0)
  1511. m_file.Write(pbData, lSize);
  1512. }
  1513. // Seek to end of data chunk, which, due to rounding, may be slightly
  1514. // past the end of the data.
  1515. m_file.Seek(lDataPos + datahdr.lChunkSize, SEEK_SET);
  1516. // Return the chunk size, which is different than the data size
  1517. *plChunkSize = datahdr.lChunkSize;
  1518. // If good then return success, otherwise return error.
  1519. if (m_file.Error() == FALSE)
  1520. return 0;
  1521. else
  1522. return 1;
  1523. }
  1524. ///////////////////////////////////////////////////////////////////////////////
  1525. //
  1526. // Helper function that reads the header of the flic file. Always returns
  1527. // with file position at start of frame 1.
  1528. //
  1529. ///////////////////////////////////////////////////////////////////////////////
  1530. short CFlx::ReadHeader(void)
  1531. {
  1532. // Seek to start of file
  1533. m_file.Seek(0, SEEK_SET);
  1534. // Read the part of the file header that's common to FLC and FLI files.
  1535. m_file.Read(&m_filehdr.lEntireFileSize);
  1536. m_file.Read(&m_filehdr.wMagic);
  1537. m_file.Read(&m_filehdr.sNumFrames);
  1538. m_file.Read(&m_filehdr.sWidth);
  1539. m_file.Read(&m_filehdr.sHeight);
  1540. m_file.Read(&m_filehdr.sDepth);
  1541. m_file.Read(&m_filehdr.sFlags);
  1542. // The headers become different at this point
  1543. if (m_filehdr.wMagic == FLX_MAGIC_FLC)
  1544. {
  1545. // Read the remainder of the FLC header
  1546. m_file.Read(&m_filehdr.lMilliPerFrame);
  1547. m_file.Read(&m_filehdr.sReserveA);
  1548. m_file.Read(&m_filehdr.dCreatedTime);
  1549. m_file.Read(&m_filehdr.dCreator);
  1550. m_file.Read(&m_filehdr.dUpdatedTime);
  1551. m_file.Read(&m_filehdr.dUpdater);
  1552. m_file.Read(&m_filehdr.sAspectX);
  1553. m_file.Read(&m_filehdr.sAspectY);
  1554. m_file.Read(m_filehdr.bReservedB, sizeof(m_filehdr.bReservedB));
  1555. m_file.Read(&m_filehdr.lOffsetFrame1);
  1556. m_file.Read(&m_filehdr.lOffsetFrame2);
  1557. m_file.Read(m_filehdr.bReservedC, sizeof(m_filehdr.bReservedC));
  1558. // In FLC files, an optional prefix chunk may follow the header.
  1559. // According to Autodesk it contains information not related to
  1560. // animation playback and should be ignored. They also say that
  1561. // programs other than Animator Pro shouldn't write it.
  1562. // We currently ignore this chunk. In the future, we might
  1563. // consider preserving it in case this flic is written out to a
  1564. // new file. The easiest way to skip over it is to seek directly
  1565. // to the first frame using the offset specified in the header.
  1566. // Seek directly to first frame.
  1567. m_file.Seek(m_filehdr.lOffsetFrame1, SEEK_SET);
  1568. }
  1569. else
  1570. {
  1571. // Read the FLI's jiffies (a jiffy is 1/70th second) and convert to
  1572. // to FLC's milliseconds.
  1573. short sJiffies;
  1574. m_file.Read(&sJiffies);
  1575. m_filehdr.lMilliPerFrame = (long)( (double)sJiffies * ((double)1000 / (double)70L) + (double)0.5 );
  1576. // Set times to 0 for lack of better value (some day, we could read the
  1577. // file's date and time stamp and put it here). We use "FLIB" for the
  1578. // serial numbers, which is safe according to the doc's.
  1579. m_filehdr.dCreatedTime = 0;
  1580. m_filehdr.dCreator = 0x464c4942;
  1581. m_filehdr.dUpdatedTime = 0;
  1582. m_filehdr.dUpdater = 0x464c4942;
  1583. // Aspect ratio for 320x200 (which is the only FLI size) is 6:5
  1584. m_filehdr.sAspectX = 6;
  1585. m_filehdr.sAspectY = 5;
  1586. // Skip to end of header. This is also the starting position of
  1587. // frame 1, which we save in the header.
  1588. m_file.Seek(128, SEEK_SET);
  1589. m_filehdr.lOffsetFrame1 = m_file.Tell();
  1590. // Get size of frame 1's chunk in order to calculate the starting
  1591. // position of frame 2.
  1592. long lSizeFrame1;
  1593. m_file.Read(&lSizeFrame1);
  1594. m_filehdr.lOffsetFrame2 = m_filehdr.lOffsetFrame1 + lSizeFrame1;
  1595. // Seek to start of frame 1
  1596. m_file.Seek(m_filehdr.lOffsetFrame1, SEEK_SET);
  1597. }
  1598. // If good then return success, otherwise return error.
  1599. if (m_file.Error() == FALSE)
  1600. return 0;
  1601. else
  1602. return 1;
  1603. }
  1604. ///////////////////////////////////////////////////////////////////////////////
  1605. //
  1606. // Helper function that writes the header of the flic file. Always returns
  1607. // with file position immediately following the header.
  1608. //
  1609. ///////////////////////////////////////////////////////////////////////////////
  1610. short CFlx::WriteHeader(void)
  1611. {
  1612. // Seek to start of file
  1613. m_file.Seek(0, SEEK_SET);
  1614. // Write the part of the file header that's common to FLC and FLI files.
  1615. m_file.Write(&m_filehdr.lEntireFileSize);
  1616. m_file.Write(&m_filehdr.wMagic);
  1617. m_file.Write(&m_filehdr.sNumFrames);
  1618. m_file.Write(&m_filehdr.sWidth);
  1619. m_file.Write(&m_filehdr.sHeight);
  1620. m_file.Write(&m_filehdr.sDepth);
  1621. m_file.Write(&m_filehdr.sFlags);
  1622. // The headers become different at this point
  1623. if (m_filehdr.wMagic == FLX_MAGIC_FLC)
  1624. {
  1625. // Read the remainder of the FLC header
  1626. m_file.Write(&m_filehdr.lMilliPerFrame);
  1627. m_file.Write(&m_filehdr.sReserveA);
  1628. m_file.Write(&m_filehdr.dCreatedTime);
  1629. m_file.Write(&m_filehdr.dCreator);
  1630. m_file.Write(&m_filehdr.dUpdatedTime);
  1631. m_file.Write(&m_filehdr.dUpdater);
  1632. m_file.Write(&m_filehdr.sAspectX);
  1633. m_file.Write(&m_filehdr.sAspectY);
  1634. m_file.Write(m_filehdr.bReservedB, sizeof(m_filehdr.bReservedB));
  1635. m_file.Write(&m_filehdr.lOffsetFrame1);
  1636. m_file.Write(&m_filehdr.lOffsetFrame2);
  1637. m_file.Write(m_filehdr.bReservedC, sizeof(m_filehdr.bReservedC));
  1638. // In FLC files, an optional prefix chunk may follow the header.
  1639. // According to Autodesk it contains information not related to
  1640. // animation playback and should be ignored. They also say that
  1641. // programs other than Animator Pro shouldn't write it, so we don't.
  1642. // Seek to position immediately after header, which is always 128 bytes.
  1643. m_file.Seek(128, SEEK_SET);
  1644. }
  1645. else
  1646. {
  1647. // Convert from milliseconds to FLI's jiffies (a jiffy is 1/70th second)
  1648. // and write that out.
  1649. short sJiffies = (short)( (double)m_filehdr.lMilliPerFrame * ((double)70 / (double)1000) + (double)0.5 );
  1650. m_file.Write(&sJiffies);
  1651. // Write 0's to rest of header, which is officially reserved
  1652. UCHAR bZero = 0;
  1653. for (short i = 0; i < 110; i++)
  1654. m_file.Write(&bZero);
  1655. // Seek to position immediately after header, which is always 128 bytes.
  1656. m_file.Seek(128, SEEK_SET);
  1657. }
  1658. // If good then return success, otherwise return error.
  1659. if (m_file.Error() == FALSE)
  1660. return 0;
  1661. else
  1662. return 1;
  1663. }
  1664. ///////////////////////////////////////////////////////////////////////////////
  1665. //
  1666. // Helper function that clears file header.
  1667. //
  1668. ///////////////////////////////////////////////////////////////////////////////
  1669. void CFlx::ClearHeader(void)
  1670. {
  1671. // Clear all fields in file header
  1672. short i;
  1673. m_filehdr.lEntireFileSize = 0;
  1674. m_filehdr.wMagic = 0;
  1675. m_filehdr.sNumFrames = 0;
  1676. m_filehdr.sWidth = 0;
  1677. m_filehdr.sHeight = 0;
  1678. m_filehdr.sDepth = 0;
  1679. m_filehdr.sFlags = 0;
  1680. m_filehdr.lMilliPerFrame = 0;
  1681. m_filehdr.sReserveA = 0;
  1682. m_filehdr.dCreatedTime = 0;
  1683. m_filehdr.dCreator = 0;
  1684. m_filehdr.dUpdatedTime = 0;
  1685. m_filehdr.dUpdater = 0;
  1686. m_filehdr.sAspectX = 0;
  1687. m_filehdr.sAspectY = 0;
  1688. for (i = 0; i < sizeof(m_filehdr.bReservedB); i++)
  1689. m_filehdr.bReservedB[i] = 0;
  1690. m_filehdr.lOffsetFrame1 = 0;
  1691. m_filehdr.lOffsetFrame2 = 0;
  1692. for (i = 0; i < sizeof(m_filehdr.bReservedC); i++)
  1693. m_filehdr.bReservedC[i] = 0;
  1694. }
  1695. ///////////////////////////////////////////////////////////////////////////////
  1696. //
  1697. // Helper functions to deal with memory associated with buf's.
  1698. //
  1699. ///////////////////////////////////////////////////////////////////////////////
  1700. void CFlx::InitBuf(FLX_BUF* pbuf)
  1701. {
  1702. // The pointers MUST be cleared to NULL so we can tell later on whether
  1703. // any memory needs to be freed.
  1704. pbuf->pbPixels = NULL;
  1705. pbuf->prgbColors = NULL;
  1706. }
  1707. short CFlx::AllocBuf(FLX_BUF* pbuf, short sWidth, short sHeight, short sColors)
  1708. {
  1709. // Allocate buffer for pixels & set pitch to width
  1710. pbuf->pbPixels = (UCHAR*)malloc((size_t)sWidth * (size_t)sHeight);
  1711. pbuf->sPitch = sWidth;
  1712. // Allocate buffer for colors
  1713. pbuf->prgbColors = (FLX_RGB*)malloc((size_t)sColors * sizeof(FLX_RGB));
  1714. // If it worked then return success
  1715. if ((pbuf->pbPixels != NULL) && (pbuf->prgbColors != NULL))
  1716. return 0;
  1717. // Else free anything that did get allocated and return failure
  1718. else
  1719. {
  1720. FreeBuf(pbuf);
  1721. return 1;
  1722. }
  1723. }
  1724. void CFlx::FreeBuf(FLX_BUF* pbuf)
  1725. {
  1726. if (pbuf->pbPixels != NULL)
  1727. {
  1728. free(pbuf->pbPixels);
  1729. pbuf->pbPixels = NULL;
  1730. }
  1731. if (pbuf->prgbColors != NULL)
  1732. {
  1733. free(pbuf->prgbColors);
  1734. pbuf->prgbColors = NULL;
  1735. }
  1736. }
  1737. void CFlx::CopyBuf(FLX_BUF* pbufDst, FLX_BUF* pbufSrc)
  1738. {
  1739. // Copy pixels one row at a time
  1740. UCHAR* pbSrc = pbufSrc->pbPixels;
  1741. UCHAR* pbDst = pbufDst->pbPixels;
  1742. for (short y = 0; y < m_filehdr.sHeight; y++)
  1743. {
  1744. memcpy(pbDst, pbSrc, m_filehdr.sWidth);
  1745. pbSrc += (ULONG)pbufSrc->sPitch;
  1746. pbDst += (ULONG)pbufDst->sPitch;
  1747. }
  1748. // Copy colors (assume 256 of them)
  1749. memcpy(pbufDst->prgbColors, pbufSrc->prgbColors, 256 * sizeof(FLX_RGB));
  1750. }
  1751. ///////////////////////////////////////////////////////////////////////////////
  1752. // EOF
  1753. ///////////////////////////////////////////////////////////////////////////////