MLibraryV0.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. using ManagedSquish;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Drawing;
  5. using System.Drawing.Drawing2D;
  6. using System.Drawing.Imaging;
  7. using System.IO;
  8. using System.Runtime.InteropServices;
  9. namespace LibraryEditor
  10. {
  11. /// <summary>
  12. /// V0 Library
  13. /// DXT1 Images
  14. /// No versioning supported
  15. /// </summary>
  16. public sealed class MLibraryV0
  17. {
  18. public static bool Load = true;
  19. public string FileName;
  20. public List<MImage> Images = new List<MImage>();
  21. public List<int> IndexList = new List<int>();
  22. public int Count;
  23. private bool _initialized;
  24. private BinaryReader _reader;
  25. private FileStream _stream;
  26. public MLibraryV0(string filename)
  27. {
  28. FileName = filename;
  29. Initialize();
  30. Close();
  31. }
  32. public void Initialize()
  33. {
  34. _initialized = true;
  35. if (!File.Exists(FileName))
  36. return;
  37. _stream = new FileStream(FileName, FileMode.Open, FileAccess.ReadWrite);
  38. _reader = new BinaryReader(_stream);
  39. Count = _reader.ReadInt32();
  40. Images = new List<MImage>();
  41. IndexList = new List<int>();
  42. for (int i = 0; i < Count; i++)
  43. IndexList.Add(_reader.ReadInt32());
  44. for (int i = 0; i < Count; i++)
  45. Images.Add(null);
  46. Load = false;//dont need to process all images when converting
  47. for (int i = 0; i < Count; i++)
  48. CheckImage(i);
  49. }
  50. public void Close()
  51. {
  52. if (_stream != null)
  53. _stream.Dispose();
  54. // if (_reader != null)
  55. // _reader.Dispose();
  56. }
  57. public void Save()
  58. {
  59. Close();
  60. MemoryStream stream = new MemoryStream();
  61. BinaryWriter writer = new BinaryWriter(stream);
  62. Count = Images.Count;
  63. IndexList.Clear();
  64. int offSet = 4 + Count * 4;
  65. for (int i = 0; i < Count; i++)
  66. {
  67. IndexList.Add((int)stream.Length + offSet);
  68. Images[i].Save(writer);
  69. }
  70. writer.Flush();
  71. byte[] fBytes = stream.ToArray();
  72. // writer.Dispose();
  73. _stream = File.Create(FileName);
  74. writer = new BinaryWriter(_stream);
  75. writer.Write(Count);
  76. for (int i = 0; i < Count; i++)
  77. writer.Write(IndexList[i]);
  78. writer.Write(fBytes);
  79. writer.Flush();
  80. writer.Close();
  81. writer.Dispose();
  82. Close();
  83. }
  84. private void CheckImage(int index)
  85. {
  86. if (!_initialized)
  87. Initialize();
  88. if (Images == null || index < 0 || index >= Images.Count)
  89. return;
  90. if (Images[index] == null)
  91. {
  92. _stream.Position = IndexList[index];
  93. Images[index] = new MImage(_reader);
  94. }
  95. if (!Load) return;
  96. MImage mi = Images[index];
  97. if (!mi.TextureValid)
  98. {
  99. _stream.Seek(IndexList[index] + 12, SeekOrigin.Begin);
  100. mi.CreateTexture(_reader);
  101. }
  102. }
  103. public Point GetOffSet(int index)
  104. {
  105. if (!_initialized)
  106. Initialize();
  107. if (Images == null || index < 0 || index >= Images.Count)
  108. return Point.Empty;
  109. if (Images[index] == null)
  110. {
  111. _stream.Seek(IndexList[index], SeekOrigin.Begin);
  112. Images[index] = new MImage(_reader);
  113. }
  114. return new Point(Images[index].X, Images[index].Y);
  115. }
  116. public Size GetSize(int index)
  117. {
  118. if (!_initialized)
  119. Initialize();
  120. if (Images == null || index < 0 || index >= Images.Count)
  121. return Size.Empty;
  122. if (Images[index] == null)
  123. {
  124. _stream.Seek(IndexList[index], SeekOrigin.Begin);
  125. Images[index] = new MImage(_reader);
  126. }
  127. return new Size(Images[index].Width, Images[index].Height);
  128. }
  129. public MImage GetMImage(int index)
  130. {
  131. if (index < 0 || index >= Images.Count)
  132. return null;
  133. return Images[index];
  134. }
  135. public Bitmap GetPreview(int index)
  136. {
  137. if (index < 0 || index >= Images.Count)
  138. return new Bitmap(1, 1);
  139. MImage image = Images[index];
  140. if (image == null || image.Image == null)
  141. return new Bitmap(1, 1);
  142. if (image.Preview == null)
  143. image.CreatePreview();
  144. return image.Preview;
  145. }
  146. public void AddImage(Bitmap image, short x, short y)
  147. {
  148. MImage mImage = new MImage(image) { X = x, Y = y };
  149. Count++;
  150. Images.Add(mImage);
  151. }
  152. public void InsertImage(int index, Bitmap image, short x, short y)
  153. {
  154. MImage mImage = new MImage(image) { X = x, Y = y };
  155. Count++;
  156. Images.Insert(index, mImage);
  157. }
  158. public void RemoveImage(int index)
  159. {
  160. if (Images == null || Count <= 1)
  161. {
  162. Count = 0;
  163. Images = new List<MImage>();
  164. return;
  165. }
  166. Count--;
  167. Images.RemoveAt(index);
  168. }
  169. public static bool CompareBytes(byte[] a, byte[] b)
  170. {
  171. if (a == b) return true;
  172. if (a == null || b == null || a.Length != b.Length) return false;
  173. for (int i = 0; i < a.Length; i++) if (a[i] != b[i]) return false;
  174. return true;
  175. }
  176. public void RemoveBlanks(bool safe = false)
  177. {
  178. for (int i = Count - 1; i >= 0; i--)
  179. {
  180. if (Images[i].FBytes == null || Images[i].FBytes.Length <= 8)
  181. {
  182. if (!safe)
  183. RemoveImage(i);
  184. else if (Images[i].X == 0 && Images[i].Y == 0)
  185. RemoveImage(i);
  186. }
  187. }
  188. }
  189. public sealed class MImage
  190. {
  191. public short Width, Height, X, Y;
  192. public int Length;
  193. public bool TextureValid;
  194. public Bitmap Image, Preview;
  195. public byte[] FBytes;
  196. public MImage(BinaryReader reader)
  197. {
  198. Width = reader.ReadInt16();
  199. Height = reader.ReadInt16();
  200. X = reader.ReadInt16();
  201. Y = reader.ReadInt16();
  202. Length = reader.ReadInt32();
  203. FBytes = reader.ReadBytes(Length);
  204. }
  205. public unsafe MImage(Bitmap image)
  206. {
  207. if (image == null)
  208. {
  209. FBytes = new byte[0];
  210. return;
  211. }
  212. Width = (short)image.Width;
  213. Height = (short)image.Height;
  214. int w = image.Width + (4 - image.Width % 4) % 4;
  215. int h = image.Height + (4 - image.Height % 4) % 4;
  216. if (image.Width != w || image.Height != h)
  217. {
  218. Bitmap temp = new Bitmap(w, h);
  219. using (Graphics g = Graphics.FromImage(temp))
  220. {
  221. g.Clear(Color.Transparent);
  222. g.DrawImage(image, 0, 0);
  223. g.Save();
  224. }
  225. image.Dispose();
  226. image = temp;
  227. }
  228. Image = image;
  229. BitmapData data = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly,
  230. PixelFormat.Format32bppArgb);
  231. byte[] pixels = new byte[image.Width * image.Height * 4];
  232. Marshal.Copy(data.Scan0, pixels, 0, pixels.Length);
  233. image.UnlockBits(data);
  234. for (int i = 0; i < pixels.Length; i += 4)
  235. {
  236. //Reverse Red/Blue
  237. byte b = pixels[i];
  238. pixels[i] = pixels[i + 2];
  239. pixels[i + 2] = b;
  240. if (pixels[i] == 0 && pixels[i + 1] == 0 && pixels[i + 2] == 0)
  241. pixels[i + 3] = 0; //Make Transparent
  242. }
  243. int count = Squish.GetStorageRequirements(image.Width, image.Height, SquishFlags.Dxt1);
  244. FBytes = new byte[count];
  245. fixed (byte* dest = FBytes)
  246. fixed (byte* source = pixels)
  247. {
  248. Squish.CompressImage((IntPtr)source, image.Width, image.Height, (IntPtr)dest, SquishFlags.Dxt1);
  249. }
  250. }
  251. public void Save(BinaryWriter writer)
  252. {
  253. writer.Write(Width);
  254. writer.Write(Height);
  255. writer.Write(X);
  256. writer.Write(Y);
  257. writer.Write(FBytes.Length);
  258. writer.Write(FBytes);
  259. }
  260. public unsafe void CreateTexture(BinaryReader reader)
  261. {
  262. int w = Width + (4 - Width % 4) % 4;
  263. int h = Height + (4 - Height % 4) % 4;
  264. if (w == 0 || h == 0)
  265. {
  266. return;
  267. }
  268. Image = new Bitmap(w, h);
  269. BitmapData data = Image.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite,
  270. PixelFormat.Format32bppArgb);
  271. fixed (byte* source = FBytes)
  272. Squish.DecompressImage(data.Scan0, w, h, (IntPtr)source, SquishFlags.Dxt1);
  273. byte* dest = (byte*)data.Scan0;
  274. for (int i = 0; i < h * w * 4; i += 4)
  275. {
  276. //Reverse Red/Blue
  277. byte b = dest[i];
  278. dest[i] = dest[i + 2];
  279. dest[i + 2] = b;
  280. }
  281. Image.UnlockBits(data);
  282. }
  283. public void CreatePreview()
  284. {
  285. if (Image == null)
  286. {
  287. Preview = new Bitmap(1, 1);
  288. return;
  289. }
  290. Preview = new Bitmap(64, 64);
  291. using (Graphics g = Graphics.FromImage(Preview))
  292. {
  293. g.InterpolationMode = InterpolationMode.HighQualityBicubic;
  294. g.Clear(Color.Transparent);
  295. int w = Math.Min((int)Width, 64);
  296. int h = Math.Min((int)Height, 64);
  297. g.DrawImage(Image, new Rectangle((64 - w) / 2, (64 - h) / 2, w, h), new Rectangle(0, 0, Width, Height), GraphicsUnit.Pixel);
  298. g.Save();
  299. }
  300. }
  301. }
  302. }
  303. }