MLibraryV1.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  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. using System.Threading.Tasks;
  10. using System.Windows.Forms;
  11. namespace LibraryEditor
  12. {
  13. /// <summary>
  14. /// V1 Library
  15. /// Uses DXT1 Images
  16. /// </summary>
  17. public sealed class MLibraryV1
  18. {
  19. public const int LibVersion = 1;
  20. public static bool Load = true;
  21. public string FileName;
  22. public List<MImage> Images = new List<MImage>();
  23. public List<int> IndexList = new List<int>();
  24. public int Count;
  25. private bool _initialized;
  26. private BinaryReader _reader;
  27. private FileStream _stream;
  28. public MLibraryV1(string filename)
  29. {
  30. FileName = filename;
  31. Initialize();
  32. Close();
  33. }
  34. public void Initialize()
  35. {
  36. int CurrentVersion;
  37. _initialized = true;
  38. if (!File.Exists(FileName))
  39. return;
  40. _stream = new FileStream(FileName, FileMode.Open, FileAccess.ReadWrite);
  41. _reader = new BinaryReader(_stream);
  42. CurrentVersion = _reader.ReadInt32();
  43. if (CurrentVersion != LibVersion)
  44. {
  45. MessageBox.Show("Wrong version, expecting lib version: " + LibVersion.ToString() + " found version: " + CurrentVersion.ToString() + ".", "Failed to open", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
  46. return;
  47. }
  48. Count = _reader.ReadInt32();
  49. Images = new List<MImage>();
  50. IndexList = new List<int>();
  51. for (int i = 0; i < Count; i++)
  52. IndexList.Add(_reader.ReadInt32());
  53. for (int i = 0; i < Count; i++)
  54. Images.Add(null);
  55. for (int i = 0; i < Count; i++)
  56. CheckImage(i);
  57. }
  58. public void Close()
  59. {
  60. if (_stream != null)
  61. _stream.Dispose();
  62. // if (_reader != null)
  63. // _reader.Dispose();
  64. }
  65. public void Save()
  66. {
  67. Close();
  68. MemoryStream stream = new MemoryStream();
  69. BinaryWriter writer = new BinaryWriter(stream);
  70. Count = Images.Count;
  71. IndexList.Clear();
  72. int offSet = 8 + Count * 4;
  73. for (int i = 0; i < Count; i++)
  74. {
  75. IndexList.Add((int)stream.Length + offSet);
  76. Images[i].Save(writer);
  77. }
  78. writer.Flush();
  79. byte[] fBytes = stream.ToArray();
  80. // writer.Dispose();
  81. _stream = File.Create(FileName);
  82. writer = new BinaryWriter(_stream);
  83. writer.Write(LibVersion);
  84. writer.Write(Count);
  85. for (int i = 0; i < Count; i++)
  86. writer.Write(IndexList[i]);
  87. writer.Write(fBytes);
  88. writer.Flush();
  89. writer.Close();
  90. writer.Dispose();
  91. Close();
  92. }
  93. private void CheckImage(int index)
  94. {
  95. if (!_initialized)
  96. Initialize();
  97. if (Images == null || index < 0 || index >= Images.Count)
  98. return;
  99. if (Images[index] == null)
  100. {
  101. _stream.Position = IndexList[index];
  102. Images[index] = new MImage(_reader);
  103. }
  104. if (!Load) return;
  105. MImage mi = Images[index];
  106. if (!mi.TextureValid)
  107. {
  108. _stream.Seek(IndexList[index] + 12, SeekOrigin.Begin);
  109. mi.CreateTexture(_reader);
  110. }
  111. }
  112. public void ToMLibrary()
  113. {
  114. string fileName = Path.ChangeExtension(FileName, ".Lib");
  115. fileName = fileName.Replace(".Lib", "-converted.Lib");
  116. if (File.Exists(fileName))
  117. File.Delete(fileName);
  118. MLibraryV2 library = new MLibraryV2(fileName) { Images = new List<MLibraryV2.MImage>(), IndexList = new List<int>(), Count = Images.Count };
  119. //library.Save();
  120. for (int i = 0; i < library.Count; i++)
  121. library.Images.Add(null);
  122. ParallelOptions options = new ParallelOptions { MaxDegreeOfParallelism = 8 };
  123. try
  124. {
  125. Parallel.For(0, Images.Count, options, i =>
  126. {
  127. MImage image = Images[i];
  128. if (image.HasMask)
  129. library.Images[i] = new MLibraryV2.MImage(image.Image, image.MaskImage) { X = image.X, Y = image.Y, ShadowX = image.ShadowX, ShadowY = image.ShadowY, Shadow = image.Shadow, MaskX = image.X, MaskY = image.Y };
  130. else
  131. library.Images[i] = new MLibraryV2.MImage(image.Image) { X = image.X, Y = image.Y, ShadowX = image.ShadowX, ShadowY = image.ShadowY, Shadow = image.Shadow };
  132. });
  133. }
  134. catch (System.Exception)
  135. {
  136. throw;
  137. }
  138. finally
  139. {
  140. library.Save();
  141. }
  142. // Operation finished.
  143. // System.Windows.Forms.MessageBox.Show("Converted " + fileName + " successfully.",
  144. // "Wemade Information",
  145. // System.Windows.Forms.MessageBoxButtons.OK,
  146. // System.Windows.Forms.MessageBoxIcon.Information,
  147. // System.Windows.Forms.MessageBoxDefaultButton.Button1);
  148. }
  149. public Point GetOffSet(int index)
  150. {
  151. if (!_initialized)
  152. Initialize();
  153. if (Images == null || index < 0 || index >= Images.Count)
  154. return Point.Empty;
  155. if (Images[index] == null)
  156. {
  157. _stream.Seek(IndexList[index], SeekOrigin.Begin);
  158. Images[index] = new MImage(_reader);
  159. }
  160. return new Point(Images[index].X, Images[index].Y);
  161. }
  162. public Size GetSize(int index)
  163. {
  164. if (!_initialized)
  165. Initialize();
  166. if (Images == null || index < 0 || index >= Images.Count)
  167. return Size.Empty;
  168. if (Images[index] == null)
  169. {
  170. _stream.Seek(IndexList[index], SeekOrigin.Begin);
  171. Images[index] = new MImage(_reader);
  172. }
  173. return new Size(Images[index].Width, Images[index].Height);
  174. }
  175. public MImage GetMImage(int index)
  176. {
  177. if (index < 0 || index >= Images.Count)
  178. return null;
  179. return Images[index];
  180. }
  181. public Bitmap GetPreview(int index)
  182. {
  183. if (index < 0 || index >= Images.Count)
  184. return new Bitmap(1, 1);
  185. MImage image = Images[index];
  186. if (image == null || image.Image == null)
  187. return new Bitmap(1, 1);
  188. if (image.Preview == null)
  189. image.CreatePreview();
  190. return image.Preview;
  191. }
  192. public void AddImage(Bitmap image, short x, short y)
  193. {
  194. MImage mImage = new MImage(image) { X = x, Y = y };
  195. Count++;
  196. Images.Add(mImage);
  197. }
  198. public void ReplaceImage(int Index, Bitmap image, short x, short y)
  199. {
  200. MImage mImage = new MImage(image) { X = x, Y = y };
  201. Images[Index] = mImage;
  202. }
  203. public void InsertImage(int index, Bitmap image, short x, short y)
  204. {
  205. MImage mImage = new MImage(image) { X = x, Y = y };
  206. Count++;
  207. Images.Insert(index, mImage);
  208. }
  209. public void RemoveImage(int index)
  210. {
  211. if (Images == null || Count <= 1)
  212. {
  213. Count = 0;
  214. Images = new List<MImage>();
  215. return;
  216. }
  217. Count--;
  218. Images.RemoveAt(index);
  219. }
  220. public static bool CompareBytes(byte[] a, byte[] b)
  221. {
  222. if (a == b) return true;
  223. if (a == null || b == null || a.Length != b.Length) return false;
  224. for (int i = 0; i < a.Length; i++) if (a[i] != b[i]) return false;
  225. return true;
  226. }
  227. public void RemoveBlanks(bool safe = false)
  228. {
  229. for (int i = Count - 1; i >= 0; i--)
  230. {
  231. if (Images[i].FBytes == null || Images[i].FBytes.Length <= 8)
  232. {
  233. if (!safe)
  234. RemoveImage(i);
  235. else if (Images[i].X == 0 && Images[i].Y == 0)
  236. RemoveImage(i);
  237. }
  238. }
  239. }
  240. public sealed class MImage
  241. {
  242. public short Width, Height, X, Y, ShadowX, ShadowY;
  243. public byte Shadow;
  244. public int Length;
  245. public byte[] FBytes;
  246. public bool TextureValid;
  247. public Bitmap Image, Preview;
  248. //layer 2:
  249. public short MaskWidth, MaskHeight, MaskX, MaskY;
  250. public int MaskLength;
  251. public byte[] MaskFBytes;
  252. public Bitmap MaskImage;
  253. public Boolean HasMask;
  254. public MImage(BinaryReader reader)
  255. {
  256. //read layer 1
  257. Width = reader.ReadInt16();
  258. Height = reader.ReadInt16();
  259. X = reader.ReadInt16();
  260. Y = reader.ReadInt16();
  261. ShadowX = reader.ReadInt16();
  262. ShadowY = reader.ReadInt16();
  263. Shadow = reader.ReadByte();
  264. Length = reader.ReadInt32();
  265. FBytes = reader.ReadBytes(Length);
  266. //check if there's a second layer and read it
  267. HasMask = ((Shadow >> 7) == 1) ? true : false;
  268. if (HasMask)
  269. {
  270. MaskWidth = reader.ReadInt16();
  271. MaskHeight = reader.ReadInt16();
  272. MaskX = reader.ReadInt16();
  273. MaskY = reader.ReadInt16();
  274. MaskLength = reader.ReadInt32();
  275. MaskFBytes = reader.ReadBytes(MaskLength);
  276. }
  277. }
  278. public MImage(byte[] image, short Width, short Height)//only use this when converting from old to new type!
  279. {
  280. FBytes = image;
  281. this.Width = Width;
  282. this.Height = Height;
  283. }
  284. public MImage(Bitmap image)
  285. {
  286. if (image == null)
  287. {
  288. FBytes = new byte[0];
  289. return;
  290. }
  291. Width = (short)image.Width;
  292. Height = (short)image.Height;
  293. Image = FixImageSize(image);
  294. FBytes = ConvertBitmapToArray(Image);
  295. }
  296. public MImage(Bitmap image, Bitmap Maskimage)
  297. {
  298. if (image == null)
  299. {
  300. FBytes = new byte[0];
  301. return;
  302. }
  303. Width = (short)image.Width;
  304. Height = (short)image.Height;
  305. Image = FixImageSize(image);
  306. FBytes = ConvertBitmapToArray(Image);
  307. if (Maskimage == null)
  308. {
  309. MaskFBytes = new byte[0];
  310. return;
  311. }
  312. HasMask = true;
  313. MaskWidth = (short)Maskimage.Width;
  314. MaskHeight = (short)Maskimage.Height;
  315. MaskImage = FixImageSize(Maskimage);
  316. MaskFBytes = ConvertBitmapToArray(MaskImage);
  317. }
  318. private Bitmap FixImageSize(Bitmap input)
  319. {
  320. int w = input.Width + (4 - input.Width % 4) % 4;
  321. int h = input.Height + (4 - input.Height % 4) % 4;
  322. if (input.Width != w || input.Height != h)
  323. {
  324. Bitmap temp = new Bitmap(w, h);
  325. using (Graphics g = Graphics.FromImage(temp))
  326. {
  327. g.Clear(Color.Transparent);
  328. g.InterpolationMode = InterpolationMode.NearestNeighbor;
  329. g.DrawImage(input, 0, 0);
  330. g.Save();
  331. }
  332. input.Dispose();
  333. input = temp;
  334. }
  335. return input;
  336. }
  337. private unsafe byte[] ConvertBitmapToArray(Bitmap input)
  338. {
  339. byte[] output;
  340. BitmapData data = input.LockBits(new Rectangle(0, 0, input.Width, input.Height), ImageLockMode.ReadOnly,
  341. PixelFormat.Format32bppArgb);
  342. byte[] pixels = new byte[input.Width * input.Height * 4];
  343. Marshal.Copy(data.Scan0, pixels, 0, pixels.Length);
  344. input.UnlockBits(data);
  345. for (int i = 0; i < pixels.Length; i += 4)
  346. {
  347. //Reverse Red/Blue
  348. byte b = pixels[i];
  349. pixels[i] = pixels[i + 2];
  350. pixels[i + 2] = b;
  351. if (pixels[i] == 0 && pixels[i + 1] == 0 && pixels[i + 2] == 0)
  352. pixels[i + 3] = 0; //Make Transparent
  353. }
  354. int count = Squish.GetStorageRequirements(input.Width, input.Height, SquishFlags.Dxt1);
  355. output = new byte[count];
  356. fixed (byte* dest = output)
  357. fixed (byte* source = pixels)
  358. {
  359. Squish.CompressImage((IntPtr)source, input.Width, input.Height, (IntPtr)dest, SquishFlags.Dxt1);
  360. }
  361. return output;
  362. }
  363. public void Save(BinaryWriter writer)
  364. {
  365. writer.Write(Width);
  366. writer.Write(Height);
  367. writer.Write(X);
  368. writer.Write(Y);
  369. writer.Write(ShadowX);
  370. writer.Write(ShadowY);
  371. writer.Write(HasMask ? (byte)(Shadow | 0x80) : (byte)Shadow);
  372. writer.Write(FBytes.Length);
  373. writer.Write(FBytes);
  374. if (HasMask)
  375. {
  376. writer.Write(MaskWidth);
  377. writer.Write(MaskHeight);
  378. writer.Write(MaskX);
  379. writer.Write(MaskY);
  380. writer.Write(MaskFBytes.Length);
  381. writer.Write(MaskFBytes);
  382. }
  383. }
  384. public unsafe void CreateTexture(BinaryReader reader)
  385. {
  386. int w = Width + (4 - Width % 4) % 4;
  387. int h = Height + (4 - Height % 4) % 4;
  388. if (w == 0 || h == 0)
  389. {
  390. return;
  391. }
  392. Image = new Bitmap(w, h);
  393. BitmapData data = Image.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite,
  394. PixelFormat.Format32bppArgb);
  395. fixed (byte* source = FBytes)
  396. Squish.DecompressImage(data.Scan0, w, h, (IntPtr)source, SquishFlags.Dxt1);
  397. byte* dest = (byte*)data.Scan0;
  398. for (int i = 0; i < h * w * 4; i += 4)
  399. {
  400. //Reverse Red/Blue
  401. byte b = dest[i];
  402. dest[i] = dest[i + 2];
  403. dest[i + 2] = b;
  404. }
  405. Image.UnlockBits(data);
  406. if (HasMask)
  407. {
  408. w = MaskWidth + (4 - MaskWidth % 4) % 4;
  409. h = MaskHeight + (4 - MaskHeight % 4) % 4;
  410. if (w == 0 || h == 0)
  411. {
  412. return;
  413. }
  414. MaskImage = new Bitmap(w, h);
  415. data = MaskImage.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite,
  416. PixelFormat.Format32bppArgb);
  417. fixed (byte* source = MaskFBytes)
  418. Squish.DecompressImage(data.Scan0, w, h, (IntPtr)source, SquishFlags.Dxt1);
  419. dest = (byte*)data.Scan0;
  420. for (int i = 0; i < h * w * 4; i += 4)
  421. {
  422. //Reverse Red/Blue
  423. byte b = dest[i];
  424. dest[i] = dest[i + 2];
  425. dest[i + 2] = b;
  426. }
  427. MaskImage.UnlockBits(data);
  428. }
  429. }
  430. public void CreatePreview()
  431. {
  432. if (Image == null)
  433. {
  434. Preview = new Bitmap(1, 1);
  435. return;
  436. }
  437. Preview = new Bitmap(64, 64);
  438. using (Graphics g = Graphics.FromImage(Preview))
  439. {
  440. g.InterpolationMode = InterpolationMode.NearestNeighbor;//HighQualityBicubic
  441. g.Clear(Color.Transparent);
  442. int w = Math.Min((int)Width, 64);
  443. int h = Math.Min((int)Height, 64);
  444. g.DrawImage(Image, new Rectangle((64 - w) / 2, (64 - h) / 2, w, h), new Rectangle(0, 0, Width, Height), GraphicsUnit.Pixel);
  445. g.Save();
  446. }
  447. }
  448. }
  449. }
  450. }