il_pic.c
Upload User: wmy0603
Upload Date: 2022-05-02
Package Size: 1808k
Code Size: 9k
Development Platform:

Visual C++

  1. //-----------------------------------------------------------------------------
  2. //
  3. // ImageLib Sources
  4. // Copyright (C) 2000-2009 by Denton Woods
  5. // Last modified: 03/07/2009
  6. //
  7. // Filename: src-IL/src/il_pic.c
  8. //
  9. // Description: Softimage Pic (.pic) functions
  10. // Lots of this code is taken from Paul Bourke's Softimage Pic code at
  11. // http://local.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/
  12. //
  13. //-----------------------------------------------------------------------------
  14. #include "il_internal.h"
  15. #ifndef IL_NO_PIC
  16. #include "il_pic.h"
  17. #include "il_manip.h"
  18. #include <string.h>
  19. //! Checks if the file specified in FileName is a valid .pic file.
  20. ILboolean ilIsValid_PIC(ILconst_string FileName)
  21. {
  22. ILHANDLE PicFile;
  23. ILboolean bPic = IL_FALSE;
  24. if (!iCheckExtension(FileName, IL_TEXT("pic"))) {
  25. ilSetError(IL_INVALID_EXTENSION);
  26. return bPic;
  27. }
  28. PicFile = iopenr(FileName);
  29. if (PicFile == NULL) {
  30. ilSetError(IL_COULD_NOT_OPEN_FILE);
  31. return bPic;
  32. }
  33. bPic = ilIsValidF_PIC(PicFile);
  34. icloser(PicFile);
  35. return bPic;
  36. }
  37. //! Checks if the ILHANDLE contains a valid .pic file at the current position.
  38. ILboolean ilIsValidF_PIC(ILHANDLE File)
  39. {
  40. ILuint FirstPos;
  41. ILboolean bRet;
  42. iSetInputFile(File);
  43. FirstPos = itell();
  44. bRet = iIsValidPic();
  45. iseek(FirstPos, IL_SEEK_SET);
  46. return bRet;
  47. }
  48. //! Checks if Lump is a valid .pic lump.
  49. ILboolean ilIsValidL_PIC(const void *Lump, ILuint Size)
  50. {
  51. iSetInputLump(Lump, Size);
  52. return iIsValidPic();
  53. }
  54. // Internal function used to get the .pic header from the current file.
  55. ILboolean iGetPicHead(PIC_HEAD *Header)
  56. {
  57. Header->Magic = GetBigInt();
  58. Header->Version = GetBigFloat();
  59. iread(Header->Comment, 1, 80);
  60. iread(Header->Id, 1, 4);
  61. Header->Width = GetBigShort();
  62. Header->Height = GetBigShort();
  63. Header->Ratio = GetBigFloat();
  64. Header->Fields = GetBigShort();
  65. Header->Padding = GetBigShort();
  66. return IL_TRUE;
  67. }
  68. // Internal function to get the header and check it.
  69. ILboolean iIsValidPic()
  70. {
  71. PIC_HEAD Head;
  72. if (!iGetPicHead(&Head))
  73. return IL_FALSE;
  74. iseek(-(ILint)sizeof(PIC_HEAD), IL_SEEK_CUR);  // Go ahead and restore to previous state
  75. return iCheckPic(&Head);
  76. }
  77. // Internal function used to check if the header is a valid .pic header.
  78. ILboolean iCheckPic(PIC_HEAD *Header)
  79. {
  80. if (Header->Magic != 0x5380F634)
  81. return IL_FALSE;
  82. if (strncmp((const char*)Header->Id, "PICT", 4))
  83. return IL_FALSE;
  84. if (Header->Width == 0)
  85. return IL_FALSE;
  86. if (Header->Height == 0)
  87. return IL_FALSE;
  88. return IL_TRUE;
  89. }
  90. //! Reads a .pic file
  91. ILboolean ilLoad_PIC(ILconst_string FileName)
  92. {
  93. ILHANDLE PicFile;
  94. ILboolean bPic = IL_FALSE;
  95. PicFile = iopenr(FileName);
  96. if (PicFile == NULL) {
  97. ilSetError(IL_COULD_NOT_OPEN_FILE);
  98. return bPic;
  99. }
  100. bPic = ilLoadF_PIC(PicFile);
  101. icloser(PicFile);
  102. return bPic;
  103. }
  104. //! Reads an already-opened .pic file
  105. ILboolean ilLoadF_PIC(ILHANDLE File)
  106. {
  107. ILuint FirstPos;
  108. ILboolean bRet;
  109. iSetInputFile(File);
  110. FirstPos = itell();
  111. bRet = iLoadPicInternal();
  112. iseek(FirstPos, IL_SEEK_SET);
  113. return bRet;
  114. }
  115. //! Reads from a memory "lump" that contains a .pic
  116. ILboolean ilLoadL_PIC(const void *Lump, ILuint Size)
  117. {
  118. iSetInputLump(Lump, Size);
  119. return iLoadPicInternal();
  120. }
  121. // Internal function used to load the .pic
  122. ILboolean iLoadPicInternal()
  123. {
  124. ILuint Alpha = IL_FALSE;
  125. ILubyte Chained;
  126. CHANNEL *Channel = NULL, *Channels = NULL, *Prev;
  127. PIC_HEAD Header;
  128. ILboolean Read;
  129. if (iCurImage == NULL) {
  130. ilSetError(IL_ILLEGAL_OPERATION);
  131. return IL_FALSE;
  132. }
  133. if (!iGetPicHead(&Header))
  134. return IL_FALSE;
  135. if (!iCheckPic(&Header)) {
  136. ilSetError(IL_INVALID_FILE_HEADER);
  137. return IL_FALSE;
  138. }
  139. // Read channels
  140. do {
  141. if (Channel == NULL) {
  142. Channel = Channels = (CHANNEL*)ialloc(sizeof(CHANNEL));
  143. if (Channels == NULL)
  144. return IL_FALSE;
  145. }
  146. else {
  147. Channels->Next = (CHANNEL*)ialloc(sizeof(CHANNEL));
  148. if (Channels->Next == NULL) {
  149. // Clean up the list before erroring out.
  150. while (Channel) {
  151. Prev = Channel;
  152. Channel = (CHANNEL*)Channel->Next;
  153. ifree(Prev);
  154. }
  155. return IL_FALSE;
  156. }
  157. Channels = (CHANNEL*)Channels->Next;
  158. }
  159. Channels->Next = NULL;
  160. Chained = igetc();
  161. Channels->Size = igetc();
  162. Channels->Type = igetc();
  163. Channels->Chan = igetc();
  164. if (ieof()) {
  165. Read = IL_FALSE;
  166. goto finish;
  167. }
  168. // See if we have an alpha channel in there
  169. if (Channels->Chan & PIC_ALPHA_CHANNEL)
  170. Alpha = IL_TRUE;
  171. } while (Chained);
  172. if (Alpha) {  // Has an alpha channel
  173. if (!ilTexImage(Header.Width, Header.Height, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL)) {
  174. Read = IL_FALSE;
  175. goto finish;  // Have to destroy Channels first.
  176. }
  177. }
  178. else {  // No alpha channel
  179. if (!ilTexImage(Header.Width, Header.Height, 1, 3, IL_RGBA, IL_UNSIGNED_BYTE, NULL)) {
  180. Read = IL_FALSE;
  181. goto finish;  // Have to destroy Channels first.
  182. }
  183. }
  184. iCurImage->Origin = IL_ORIGIN_LOWER_LEFT;
  185. Read = readScanlines((ILuint*)iCurImage->Data, Header.Width, Header.Height, Channel, Alpha);
  186. finish:
  187. // Destroy channels
  188. while (Channel) {
  189. Prev = Channel;
  190. Channel = (CHANNEL*)Channel->Next;
  191. ifree(Prev);
  192. }
  193. if (Read == IL_FALSE)
  194. return IL_FALSE;
  195. return ilFixImage();
  196. }
  197. ILboolean readScanlines(ILuint *image, ILint width, ILint height, CHANNEL *channel, ILuint alpha)
  198. {
  199. ILint i;
  200. ILuint *scan;
  201. (void)alpha;
  202. for (i = height - 1; i >= 0; i--) {
  203. scan = image + i * width;
  204. if (!readScanline((ILubyte *)scan, width, channel, alpha ? 4 : 3)) {
  205. ilSetError(IL_ILLEGAL_FILE_VALUE);
  206. return IL_FALSE;
  207. }
  208. }
  209. return IL_TRUE;
  210. }
  211. ILuint readScanline(ILubyte *scan, ILint width, CHANNEL *channel, ILint bytes)
  212. {
  213. ILint noCol;
  214. ILint off[4];
  215. ILuint status=0;
  216. while (channel) {
  217. noCol = 0;
  218. if(channel->Chan & PIC_RED_CHANNEL) {
  219. off[noCol] = 0;
  220. noCol++;
  221. }
  222. if(channel->Chan & PIC_GREEN_CHANNEL) {
  223. off[noCol] = 1;
  224. noCol++;
  225. }
  226. if(channel->Chan & PIC_BLUE_CHANNEL) {
  227. off[noCol] = 2;
  228. noCol++;
  229. }
  230. if(channel->Chan & PIC_ALPHA_CHANNEL) {
  231. off[noCol] = 3;
  232. noCol++;
  233. //@TODO: Find out if this is possible.
  234. if (bytes == 3)  // Alpha channel in a 24-bit image.  Do not know what to do with this.
  235. return 0;
  236. }
  237. switch(channel->Type & 0x0F)
  238. {
  239. case PIC_UNCOMPRESSED:
  240. status = channelReadRaw(scan, width, noCol, off, bytes);
  241. break;
  242. case PIC_PURE_RUN_LENGTH:
  243. status = channelReadPure(scan, width, noCol, off, bytes);
  244. break;
  245. case PIC_MIXED_RUN_LENGTH:
  246. status = channelReadMixed(scan, width, noCol, off, bytes);
  247. break;
  248. }
  249. if (!status)
  250. break;
  251. channel = (CHANNEL*)channel->Next;
  252. }
  253. return status;
  254. }
  255. ILboolean channelReadRaw(ILubyte *scan, ILint width, ILint noCol, ILint *off, ILint bytes)
  256. {
  257. ILint i, j;
  258. for (i = 0; i < width; i++) {
  259. if (ieof())
  260. return IL_FALSE;
  261. for (j = 0; j < noCol; j++)
  262. if (iread(&scan[off[j]], 1, 1) != 1)
  263. return IL_FALSE;
  264. scan += bytes;
  265. }
  266. return IL_TRUE;
  267. }
  268. ILboolean channelReadPure(ILubyte *scan, ILint width, ILint noCol, ILint *off, ILint bytes)
  269. {
  270. ILubyte col[4];
  271. ILint count;
  272. int i, j, k;
  273. for (i = width; i > 0; ) {
  274. count = igetc();
  275. if (count == IL_EOF)
  276. return IL_FALSE;
  277. if (count > width)
  278. count = width;
  279. i -= count;
  280. if (ieof())
  281. return IL_FALSE;
  282. for (j = 0; j < noCol; j++)
  283. if (iread(&col[j], 1, 1) != 1)
  284. return IL_FALSE;
  285. for (k = 0; k < count; k++, scan += bytes) {
  286. for(j = 0; j < noCol; j++)
  287. scan[off[j] + k] = col[j];
  288. }
  289. }
  290. return IL_TRUE;
  291. }
  292. ILboolean channelReadMixed(ILubyte *scan, ILint width, ILint noCol, ILint *off, ILint bytes)
  293. {
  294. ILint count;
  295. int i, j, k;
  296. ILubyte col[4];
  297. for(i = 0; i < width; i += count) {
  298. if (ieof())
  299. return IL_FALSE;
  300. count = igetc();
  301. if (count == IL_EOF)
  302. return IL_FALSE;
  303. if (count >= 128) {  // Repeated sequence
  304. if (count == 128) {  // Long run
  305. count = GetBigUShort();
  306. if (ieof()) {
  307. ilSetError(IL_FILE_READ_ERROR);
  308. return IL_FALSE;
  309. }
  310. }
  311. else
  312. count -= 127;
  313. // We've run past...
  314. if ((i + count) > width) {
  315. //fprintf(stderr, "ERROR: FF_PIC_load(): Overrun scanline (Repeat) [%d + %d > %d] (NC=%d)n", i, count, width, noCol);
  316. ilSetError(IL_ILLEGAL_FILE_VALUE);
  317. return IL_FALSE;
  318. }
  319. for (j = 0; j < noCol; j++)
  320. if (iread(&col[j], 1, 1) != 1) {
  321. ilSetError(IL_FILE_READ_ERROR);
  322. return IL_FALSE;
  323. }
  324. for (k = 0; k < count; k++, scan += bytes) {
  325. for (j = 0; j < noCol; j++)
  326. scan[off[j]] = col[j];
  327. }
  328. } else { // Raw sequence
  329. count++;
  330. if ((i + count) > width) {
  331. //fprintf(stderr, "ERROR: FF_PIC_load(): Overrun scanline (Raw) [%d + %d > %d] (NC=%d)n", i, count, width, noCol);
  332. ilSetError(IL_ILLEGAL_FILE_VALUE);
  333. return IL_FALSE;
  334. }
  335. for (k = count; k > 0; k--, scan += bytes) {
  336. for (j = 0; j < noCol; j++)
  337. if (iread(&scan[off[j]], 1, 1) != 1) {
  338. ilSetError(IL_FILE_READ_ERROR);
  339. return IL_FALSE;
  340. }
  341. }
  342. }
  343. }
  344. return IL_TRUE;
  345. }
  346. #endif//IL_NO_PIC