GraphicData.cs 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843
  1. /**
  2. * 魔力宝贝图档解析脚本 - CGTool
  3. *
  4. * @Author HonorLee (dev@honorlee.me)
  5. * @Version 1.0 (2023-11-20)
  6. * @License GPL-3.0
  7. *
  8. * GraphicData.cs 图档解析类
  9. */
  10. using System;
  11. using System.Collections;
  12. using System.Collections.Generic;
  13. using System.IO;
  14. using System.Linq;
  15. using Unity.Burst;
  16. using Unity.Collections;
  17. using Unity.Jobs;
  18. using UnityEngine;
  19. namespace CrossgateToolkit
  20. {
  21. //图档数据详情
  22. public class GraphicDetail
  23. {
  24. //索引
  25. public uint Index;
  26. //编号
  27. public uint Serial;
  28. //图档宽度
  29. public uint Width;
  30. //图档高度
  31. public uint Height;
  32. //图档偏移X
  33. public int OffsetX;
  34. //图档偏移Y
  35. public int OffsetY;
  36. //Palet调色板Index
  37. public int Palet;
  38. //图档Sprite
  39. public Sprite Sprite;
  40. //图档Sprite(100%PPU)
  41. public Sprite SpritePPU100;
  42. //图档主色调,用于小地图绘制
  43. public Color32 PrimaryColor;
  44. }
  45. // 图档数据
  46. public static class GraphicData
  47. {
  48. // 常规图档缓存
  49. public static Dictionary<GraphicInfoData,Dictionary<int,GraphicDetail>> _cache = new Dictionary<GraphicInfoData, Dictionary<int, GraphicDetail>>();
  50. // 线性图档缓存
  51. public static Dictionary<GraphicInfoData,Dictionary<int,GraphicDetail>> _linearCache = new Dictionary<GraphicInfoData, Dictionary<int, GraphicDetail>>();
  52. // 获取图档
  53. public static GraphicDetail GetGraphicDetail(GraphicInfoData graphicInfoData, int palet = 0,int subPalet = -1,bool asLinear = false,bool cache = true)
  54. {
  55. GraphicDetail graphicDetail = null;
  56. if (cache)
  57. {
  58. var checkCache = asLinear ? _linearCache : _cache;
  59. if (checkCache.ContainsKey(graphicInfoData))
  60. {
  61. if (checkCache[graphicInfoData].ContainsKey(palet))
  62. {
  63. graphicDetail = checkCache[graphicInfoData][palet];
  64. }
  65. else
  66. {
  67. graphicDetail = _loadGraphicDetail(graphicInfoData, palet, subPalet, asLinear);
  68. checkCache[graphicInfoData].Add(palet, graphicDetail);
  69. }
  70. }
  71. else
  72. {
  73. graphicDetail = _loadGraphicDetail(graphicInfoData, palet, subPalet, asLinear);
  74. checkCache.Add(graphicInfoData, new Dictionary<int, GraphicDetail>());
  75. checkCache[graphicInfoData].Add(palet, graphicDetail);
  76. }
  77. }
  78. else
  79. {
  80. graphicDetail = _loadGraphicDetail(graphicInfoData, palet, subPalet, asLinear);
  81. }
  82. return graphicDetail;
  83. }
  84. public static void ClearCache(uint serial,int palet =0,bool asLinear = false)
  85. {
  86. var checkCache = asLinear ? _linearCache : _cache;
  87. GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoData(serial);
  88. if (graphicInfoData == null) return;
  89. if (checkCache.ContainsKey(graphicInfoData))
  90. {
  91. if (checkCache[graphicInfoData].ContainsKey(palet))
  92. {
  93. GraphicDetail graphicDetail = checkCache[graphicInfoData][palet];
  94. if (graphicDetail != null)
  95. {
  96. UnityEngine.Object.Destroy(graphicDetail.Sprite.texture);
  97. if (graphicDetail.Sprite != null)
  98. {
  99. UnityEngine.Object.Destroy(graphicDetail.Sprite);
  100. UnityEngine.Object.Destroy(graphicDetail.SpritePPU100);
  101. }
  102. graphicDetail = null;
  103. }
  104. checkCache[graphicInfoData].Remove(palet);
  105. }
  106. }
  107. }
  108. // 解析图档
  109. private static GraphicDetail _loadGraphicDetail(GraphicInfoData graphicInfoData,int palet = 0,int subPalet = -1,bool asLinear = false)
  110. {
  111. GraphicDetail graphicDetail = new GraphicDetail();
  112. //获取图像数据
  113. List<Color32> pixels = UnpackGraphic(graphicInfoData, palet, subPalet);
  114. if(pixels==null) return null;
  115. graphicDetail.PrimaryColor = pixels.Last();
  116. pixels.RemoveAt(pixels.Count - 1);
  117. //直接通过Texture2D做偏移,并转为Sprite的偏移量
  118. Vector2 offset = new Vector2(0f, 1f);
  119. offset.x += -(graphicInfoData.OffsetX * 1f) / graphicInfoData.Width;
  120. offset.y -= (-graphicInfoData.OffsetY * 1f) / graphicInfoData.Height;
  121. //创建Texture2D对象
  122. Texture2D texture2D;
  123. Sprite sprite;
  124. // RGBA4444 减少内存占用-对边缘增加1px空白,避免黑线
  125. texture2D = new Texture2D((int) graphicInfoData.Width, (int) graphicInfoData.Height,
  126. TextureFormat.RGBA4444, false, asLinear);
  127. // 固定点过滤
  128. if (asLinear) texture2D.filterMode = FilterMode.Bilinear;
  129. else texture2D.filterMode = FilterMode.Point;
  130. texture2D.wrapMode = TextureWrapMode.Clamp;
  131. texture2D.SetPixels32(pixels.ToArray());
  132. texture2D.Apply();
  133. sprite = Sprite.Create(texture2D, new Rect(0, 0, texture2D.width, texture2D.height), offset, 1,0,SpriteMeshType.FullRect);
  134. // 创建PPU为100的sprite
  135. Sprite spritePPU100 = Sprite.Create(texture2D, new Rect(0, 0, texture2D.width, texture2D.height), offset, 100,0,SpriteMeshType.FullRect);
  136. //写入数据
  137. graphicDetail.Index = graphicInfoData.Index;
  138. graphicDetail.Serial = graphicInfoData.Serial;
  139. graphicDetail.Width = graphicInfoData.Width;
  140. graphicDetail.Height = graphicInfoData.Height;
  141. graphicDetail.OffsetX = graphicInfoData.OffsetX;
  142. graphicDetail.OffsetY = graphicInfoData.OffsetY;
  143. graphicDetail.Palet = palet;
  144. graphicDetail.Sprite = sprite;
  145. graphicDetail.SpritePPU100 = spritePPU100;
  146. return graphicDetail;
  147. }
  148. #region 地图合批
  149. // 合批数据
  150. private class BatchData
  151. {
  152. public int BatchOffsetX;
  153. public int BatchOffsetY;
  154. public GraphicInfoData GraphicInfoData;
  155. // public List<Color32> Pixels;
  156. public Color32 PrimaryColor;
  157. public GraphicDetail GraphicDetail;
  158. }
  159. // 图档合批
  160. private class TextureData
  161. {
  162. public int MaxHeight;
  163. public int MaxWidth;
  164. public List<BatchData> BatchDatas = new List<BatchData>();
  165. public List<GraphicInfoData> GraphicInfoDatas = new List<GraphicInfoData>();
  166. }
  167. /// <summary>
  168. /// 合批图档
  169. /// 通过指定图档序列,对图档进行合批处理,并返回合批后的图档数据
  170. /// </summary>
  171. /// <param name="graphicInfoDatas">图档索引数据序列</param>
  172. /// <param name="AsSerialBatch">以图档编号而非索引号返回合批数据</param>
  173. /// <param name="palet">调色板序号</param>
  174. /// <param name="subPalet">副调色板编号(针对动画)</param>
  175. /// <param name="linear">线性过滤</param>
  176. /// <param name="maxTextureSize">单个Texture最大尺寸,地面数据建议2048,物件数据建议4096</param>
  177. /// <param name="padding">图档间隔,可以有效避免图档渲染时出现多余的黑边或像素黏连</param>
  178. /// <param name="compress">启用压缩</param>
  179. /// <returns>合批后的图档数据,Key(unit)为图档数据编号(或AsSerialBatch为false时为图档序号),Value为图档数据</returns>
  180. public static Dictionary<uint, GraphicDetail> BakeGraphics(List<GraphicInfoData> graphicInfoDatas,bool AsSerialBatch = true,int palet = 0,int subPalet = -1,bool linear = false,int maxTextureSize = 2048,int padding = 0,bool compress = false)
  181. {
  182. // 单个Texture最大尺寸
  183. int maxWidth = maxTextureSize;
  184. int maxHeight = maxTextureSize;
  185. List<TextureData> textureDatas = new List<TextureData>();
  186. // 根据objectInfos的内,GraphicInfoData的Width,Height进行排序,优先排序Width,使图档从小到大排列
  187. graphicInfoDatas = graphicInfoDatas.OrderBy(obj => obj.Width).ThenBy(obj => obj.Height).ToList();
  188. // 去重
  189. graphicInfoDatas = graphicInfoDatas.Distinct().ToList();
  190. int offsetX = 0; // X轴偏移量
  191. int offsetY = 0; // Y轴偏移量
  192. int maxRowHeight = 0; // 当前行最大高度
  193. TextureData textureData = new TextureData();
  194. for (var i = 0; i < graphicInfoDatas.Count; i++)
  195. {
  196. GraphicInfoData graphicInfoData = graphicInfoDatas[i];
  197. // 如果宽度超过4096,则换行
  198. if((graphicInfoData.Width + offsetX) > maxWidth)
  199. {
  200. offsetX = 0;
  201. offsetY = offsetY + maxRowHeight + padding;
  202. maxRowHeight = 0;
  203. }
  204. // 如果高度超过2048,则生成新的Texture2D
  205. if ((graphicInfoData.Height + offsetY) > maxHeight)
  206. {
  207. offsetX = 0;
  208. offsetY = 0;
  209. maxRowHeight = 0;
  210. textureDatas.Add(textureData);
  211. textureData = new TextureData();
  212. }
  213. BatchData batchData = new BatchData();
  214. batchData.BatchOffsetX = offsetX;
  215. batchData.BatchOffsetY = offsetY;
  216. batchData.GraphicDetail = GetGraphicDetail(graphicInfoData, palet, subPalet, linear, true);
  217. batchData.GraphicInfoData = graphicInfoData;
  218. batchData.PrimaryColor = batchData.GraphicDetail.PrimaryColor;
  219. textureData.BatchDatas.Add(batchData);
  220. textureData.GraphicInfoDatas.Add(graphicInfoData);
  221. maxRowHeight = Mathf.Max(maxRowHeight, (int) graphicInfoData.Height);
  222. textureData.MaxHeight = Mathf.Max(textureData.MaxHeight, offsetY + maxRowHeight);
  223. textureData.MaxWidth = Mathf.Max(textureData.MaxWidth, offsetX + (int) graphicInfoData.Width);
  224. offsetX += (int) graphicInfoData.Width + padding;
  225. }
  226. //最后一次合并
  227. if (textureData.BatchDatas.Count > 0) textureDatas.Add(textureData);
  228. Dictionary<uint, GraphicDetail> graphicDataDic = new Dictionary<uint, GraphicDetail>();
  229. //合并Texture2D
  230. for (var i = 0; i < textureDatas.Count; i++)
  231. {
  232. TextureData textureDataPiece = textureDatas[i];
  233. // 将最大高宽调整为4的倍数,提高渲染效率及适配压缩
  234. textureDataPiece.MaxWidth = (int) Math.Ceiling(textureDataPiece.MaxWidth / 4f) * 4;
  235. textureDataPiece.MaxHeight = (int) Math.Ceiling(textureDataPiece.MaxHeight / 4f) * 4;
  236. // Debug.Log($"合并第{i}个Texture2D,最大高度:{textureDataPiece.MaxHeight},图像数量:{textureDataPiece.GraphicDatas.Count}");
  237. Color32[] colors = Enumerable.Repeat(new Color32(0,0,0,0), textureDataPiece.MaxWidth * textureDataPiece.MaxHeight).ToArray();
  238. Texture2D texture2DPiece = new Texture2D(textureDataPiece.MaxWidth, textureDataPiece.MaxHeight, TextureFormat.RGBA4444, false, linear);
  239. texture2DPiece.filterMode = linear ? FilterMode.Bilinear : FilterMode.Point;
  240. texture2DPiece.wrapMode = TextureWrapMode.Clamp;
  241. texture2DPiece.SetPixels32(colors);
  242. texture2DPiece.Apply();
  243. for (var n = 0; n < textureDataPiece.BatchDatas.Count; n++)
  244. {
  245. BatchData batchData = textureDataPiece.BatchDatas[n];
  246. GraphicInfoData graphicInfoData = textureDataPiece.GraphicInfoDatas[n];
  247. Graphics.CopyTexture(batchData.GraphicDetail.Sprite.texture, 0, 0, 0, 0, (int) graphicInfoData.Width,
  248. (int) graphicInfoData.Height, texture2DPiece, 0, 0, batchData.BatchOffsetX,
  249. batchData.BatchOffsetY);
  250. }
  251. Combine(texture2DPiece, textureDataPiece.BatchDatas);
  252. }
  253. void Combine(Texture2D texture2D,List<BatchData> batchDatas)
  254. {
  255. for (var i = 0; i < batchDatas.Count; i++)
  256. {
  257. BatchData batchData = batchDatas[i];
  258. //直接通过Texture2D做偏移,并转为Sprite的偏移量
  259. Vector2 offset = new Vector2(0f, 1f);
  260. offset.x += -(batchData.GraphicInfoData.OffsetX * 1f) / batchData.GraphicInfoData.Width;
  261. offset.y -= (-batchData.GraphicInfoData.OffsetY * 1f) / batchData.GraphicInfoData.Height;
  262. Sprite sprite = Sprite.Create(texture2D,
  263. new Rect(batchData.BatchOffsetX, batchData.BatchOffsetY, (int)batchData.GraphicInfoData.Width,
  264. (int)batchData.GraphicInfoData.Height), offset, 1, 0, SpriteMeshType.FullRect);
  265. Sprite spritePPU100 = Sprite.Create(texture2D,
  266. new Rect(batchData.BatchOffsetX, batchData.BatchOffsetY, (int)batchData.GraphicInfoData.Width,
  267. (int)batchData.GraphicInfoData.Height), offset, 100, 0, SpriteMeshType.FullRect);
  268. GraphicDetail graphicDetail = new GraphicDetail()
  269. {
  270. Index = batchData.GraphicInfoData.Index,
  271. Serial = batchData.GraphicInfoData.Serial,
  272. Width = batchData.GraphicInfoData.Width,
  273. Height = batchData.GraphicInfoData.Height,
  274. OffsetX = batchData.GraphicInfoData.OffsetX,
  275. OffsetY = batchData.GraphicInfoData.OffsetY,
  276. Palet = palet,
  277. Sprite = sprite,
  278. SpritePPU100 = spritePPU100,
  279. PrimaryColor = batchData.PrimaryColor
  280. };
  281. // graphicDataPiece.Sprite = sprite;
  282. if (AsSerialBatch) graphicDataDic[graphicDetail.Serial] = graphicDetail;
  283. else graphicDataDic[graphicDetail.Index] = graphicDetail;
  284. ClearCache(graphicDetail.Serial);
  285. if(compress) texture2D.Compress(true);
  286. }
  287. }
  288. return graphicDataDic;
  289. }
  290. #endregion
  291. //解压图像数据
  292. public static List<Color32> UnpackGraphic(GraphicInfoData graphicInfoData, int PaletIndex = 0,
  293. int SubPaletIndex = -1)
  294. {
  295. List<Color32> pixels = new List<Color32>();
  296. //获取调色板
  297. List<Color32> palet = null;
  298. //调整流指针
  299. BinaryReader fileReader = graphicInfoData.GraphicReader;
  300. BinaryReader contentReader = null;
  301. if(graphicInfoData.IsEncrypted)
  302. {
  303. // 解密
  304. long position = graphicInfoData.Addr + 3;
  305. byte[] content;
  306. // 由于秘钥被嵌入到数据流中,先检查当前位与秘钥位置和长度关系,且图档文件最开始多3个字节的头信息
  307. // 1.不包含:位置+数据长度小于秘钥索引
  308. if (position + graphicInfoData.Length < graphicInfoData.EncryptInfo.PwdIndex)
  309. {
  310. // Debug.Log($"不包含秘钥:{graphicInfoData.Index}");
  311. // 不处理
  312. fileReader.BaseStream.Position = position;
  313. content = fileReader.ReadBytes((int)graphicInfoData.Length);
  314. }else // 2.包含秘钥:位置小于秘钥索引,但是位置+数据长度大于秘钥索引,秘钥将数据分割
  315. if (position < graphicInfoData.EncryptInfo.PwdIndex && // 数据索引小于秘钥索引
  316. position + graphicInfoData.Length > graphicInfoData.EncryptInfo.PwdIndex) // 数据索引+数据长度大于秘钥索引
  317. {
  318. // Debug.Log($"包含秘钥:{graphicInfoData.Index}");
  319. // 读取秘钥前数据,注意这里的长度是秘钥索引-数据索引+3
  320. int preLen = (int)(graphicInfoData.EncryptInfo.PwdIndex - position + 3);
  321. fileReader.BaseStream.Position = position;
  322. byte[] preContent = fileReader.ReadBytes(preLen);
  323. // 读取秘钥后数据
  324. int nextLen = (int)(graphicInfoData.Length - preLen);
  325. fileReader.BaseStream.Position = graphicInfoData.EncryptInfo.PwdIndex + graphicInfoData.EncryptInfo.PwdLen;
  326. byte[] nextContent = fileReader.ReadBytes(nextLen);
  327. // 合并数据
  328. content = preContent.Concat(nextContent).ToArray();
  329. }
  330. else // 3.秘钥之后:位置大于秘钥索引,数据位置需要加上秘钥长度
  331. {
  332. // Debug.Log($"秘钥之后:{graphicInfoData.Index}");
  333. fileReader.BaseStream.Position = position + graphicInfoData.EncryptInfo.PwdLen;
  334. content = fileReader.ReadBytes((int)graphicInfoData.Length);
  335. }
  336. // 读取缓存字节集
  337. contentReader = new BinaryReader(new MemoryStream(content));
  338. int pwdIndex = 0;
  339. byte[] head = contentReader.ReadBytes(2);
  340. // 寻找解密头数据的密码索引
  341. for (int i = 0; i < graphicInfoData.EncryptInfo.Pwd.Length; i++)
  342. {
  343. if((head[0]^graphicInfoData.EncryptInfo.Pwd[i]) == 0x52)
  344. {
  345. int next = i + 1;
  346. if (i == graphicInfoData.EncryptInfo.Pwd.Length - 1) next = 0;
  347. if ((head[1] ^ graphicInfoData.EncryptInfo.Pwd[next]) == 0x44)
  348. {
  349. pwdIndex = i;
  350. break;
  351. }
  352. }
  353. }
  354. contentReader.Dispose();
  355. // 解密数据
  356. for (int i = 0; i < content.Length; i++)
  357. {
  358. content[i] = (byte)(content[i] ^ graphicInfoData.EncryptInfo.Pwd[pwdIndex]);
  359. pwdIndex++;
  360. if(pwdIndex >= graphicInfoData.EncryptInfo.Pwd.Length) pwdIndex = 0;
  361. }
  362. //读取缓存字节集
  363. contentReader = new BinaryReader(new MemoryStream(content));
  364. }
  365. else
  366. {
  367. fileReader.BaseStream.Position = graphicInfoData.Addr;
  368. //读入目标字节集
  369. byte[] Content = fileReader.ReadBytes((int)graphicInfoData.Length);
  370. //读取缓存字节集
  371. contentReader = new BinaryReader(new MemoryStream(Content));
  372. }
  373. //16字节头信息
  374. byte[] RD = contentReader.ReadBytes(2);
  375. // 研究了几个图档数据,这个字节分别有 0~3 不同类型
  376. // 猜想一下的话
  377. // 0:图档无压缩无内置图档
  378. // 1:图档压缩无内置图档
  379. // 2:图档无压缩有内置图档
  380. // 3:图档压缩有内置图档
  381. int Version = contentReader.ReadByte();
  382. int Unknow = contentReader.ReadByte();
  383. uint Width = contentReader.ReadUInt32();
  384. uint Height = contentReader.ReadUInt32();
  385. uint DataLen = contentReader.ReadUInt32();
  386. uint innerPaletLen = 0;
  387. // 低版本头部长度为16,高版本为20
  388. int headLen = 16;
  389. if (Version > 1)
  390. {
  391. headLen = 20;
  392. innerPaletLen = contentReader.ReadUInt32();
  393. }
  394. //数据长度
  395. int contentLen = (int)(DataLen - headLen);
  396. int pixelLen = (int)(graphicInfoData.Width * graphicInfoData.Height);
  397. byte[] paletIndexs = graphicInfoData.UnpackedPaletIndex;
  398. if (paletIndexs == null)
  399. {
  400. //解压数据
  401. byte[] contentBytes =
  402. contentReader.ReadBytes((int)Version % 2 == 0 ? (int)(pixelLen + innerPaletLen) : contentLen);
  403. NativeArray<byte> bytes = new NativeArray<byte>((int)contentBytes.Length, Allocator.TempJob);
  404. bytes.CopyFrom(contentBytes);
  405. long decompressLen = pixelLen + innerPaletLen;
  406. NativeArray<byte> colorIndexs =
  407. new NativeArray<byte>((int)decompressLen, Allocator.TempJob);
  408. DecompressJob decompressJob = new DecompressJob()
  409. {
  410. bytes = bytes,
  411. compressd = Version % 2 != 0,
  412. colorIndexs = colorIndexs
  413. };
  414. // decompressJob.Execute();
  415. decompressJob.Schedule().Complete();
  416. paletIndexs = colorIndexs.ToArray();
  417. graphicInfoData.UnpackedPaletIndex = paletIndexs;
  418. // 如果存在内置调色板,则读取内置调色板
  419. if (innerPaletLen > 0 && graphicInfoData.InnerPalet == null)
  420. {
  421. byte[] innerPaletIndex = paletIndexs.Skip(pixelLen).Take((int)innerPaletLen).ToArray();
  422. graphicInfoData.InnerPalet = AnalysisInnerPalet(innerPaletIndex).ToList();
  423. }
  424. bytes.Dispose();
  425. colorIndexs.Dispose();
  426. }
  427. paletIndexs = paletIndexs.Take(pixelLen).ToArray();
  428. // palet = Palet.GetPalet(PaletIndex);
  429. // Debug.Log($"PaletIndex:{PaletIndex},SubPaletIndex:{SubPaletIndex},palet:{palet!=null},InnerPalet:{graphicInfoData.InnerPalet!=null}");
  430. // 如果指定了外置调色板
  431. if (SubPaletIndex >= 0)
  432. {
  433. palet = Palet.GetPalet(SubPaletIndex);
  434. if (palet == null)
  435. {
  436. GraphicInfoData subPaletInfoData = GraphicInfo.GetGraphicInfoData((uint)SubPaletIndex);
  437. if (subPaletInfoData != null)
  438. {
  439. Graphic.GetGraphicDetail((uint)SubPaletIndex);
  440. if (subPaletInfoData.InnerPalet != null)
  441. {
  442. palet = subPaletInfoData.InnerPalet;
  443. Palet.AddPalet(SubPaletIndex, palet);
  444. }
  445. }
  446. }
  447. }
  448. if (palet == null)
  449. {
  450. if (graphicInfoData.InnerPalet != null)
  451. {
  452. // 没有指定外置调色板,存在内置调色板,则读取内置调色板
  453. palet = graphicInfoData.InnerPalet;
  454. }
  455. else
  456. {
  457. palet = Palet.GetPalet(PaletIndex);
  458. if (palet == null) palet = Palet.GetPalet(0);
  459. }
  460. }
  461. //释放连接
  462. contentReader.Dispose();
  463. contentReader.Close();
  464. //主色调色值
  465. int r = 0;
  466. int g = 0;
  467. int b = 0;
  468. foreach (int index in paletIndexs)
  469. {
  470. Color32 color32;
  471. if (index == 0 || (index > palet.Count - 1))
  472. {
  473. color32 = Color.clear;
  474. }
  475. else
  476. {
  477. color32 = palet[index];
  478. }
  479. pixels.Add(color32);
  480. r += color32.r;
  481. g += color32.g;
  482. b += color32.b;
  483. }
  484. //主色调计算及提亮
  485. r = r / pixels.Count * 3;
  486. g = g / pixels.Count * 3;
  487. b = b / pixels.Count * 3;
  488. if (r > 255) r = 255;
  489. if (g > 255) g = 255;
  490. if (b > 255) b = 255;
  491. int len = (int) (graphicInfoData.Width * graphicInfoData.Height);
  492. if (pixels.Count != len)
  493. {
  494. if (pixels.Count > len)
  495. {
  496. pixels = pixels.GetRange(0, len);
  497. }
  498. else
  499. {
  500. Color32[] temc = new Color32[len - pixels.Count];
  501. ArrayList.Repeat(Color.clear, len - pixels.Count).CopyTo(temc);
  502. pixels.AddRange(temc);
  503. }
  504. }
  505. //主色调加入最后
  506. pixels.Add(new Color32((byte) r, (byte) g, (byte) b, 255));
  507. return pixels;
  508. }
  509. //分析高版本内部调色板
  510. private static Color32[] AnalysisInnerPalet(byte[] bytes)
  511. {
  512. int colorLen = bytes.Length / 3;
  513. Color32[] palet = new Color32[colorLen + 1];
  514. for (var i = 0; i < colorLen; i++)
  515. {
  516. byte[] paletBytes = bytes.Skip(i * 3).Take(3).ToArray();
  517. Color32 color32 = new Color32();
  518. color32.r = (byte)paletBytes[2];
  519. color32.g = (byte)paletBytes[1];
  520. color32.b = (byte)paletBytes[0];
  521. color32.a = (byte)(i == 0 ? 0x00 : 0xFF);
  522. palet[i] = color32;
  523. }
  524. palet[colorLen] = Color.clear;
  525. return palet;
  526. }
  527. #region 测试解压
  528. private static int[] TestDecompress(byte[] bytes)
  529. {
  530. List<int> colorIndexs = new List<int>();
  531. int _index = -1;
  532. int next()
  533. {
  534. _index++;
  535. if (_index > bytes.Length - 1) return -1;
  536. return bytes[_index];
  537. }
  538. while (_index < (bytes.Length - 1))
  539. {
  540. int head = next();
  541. if (head == -1) break;
  542. int repeat = 0;
  543. if (head < 0x10)
  544. {
  545. repeat = head;
  546. for (var i = 0; i < repeat; i++)
  547. {
  548. colorIndexs.Add(next());
  549. }
  550. }
  551. else if (head < 0x20)
  552. {
  553. repeat = head % 0x10 * 0x100 + next();
  554. for (var i = 0; i < repeat; i++)
  555. {
  556. colorIndexs.Add(next());
  557. }
  558. }
  559. else if (head < 0x80)
  560. {
  561. repeat = head % 0x20 * 0x10000 + next() * 0x100 + next();
  562. for (var i = 0; i < repeat; i++)
  563. {
  564. colorIndexs.Add(next());
  565. }
  566. }
  567. else if (head < 0x90)
  568. {
  569. repeat = head % 0x80;
  570. int index = next();
  571. for (var i = 0; i < repeat; i++)
  572. {
  573. colorIndexs.Add(index);
  574. }
  575. }
  576. else if (head < 0xa0)
  577. {
  578. int index = next();
  579. repeat = head % 0x90 * 0x100 + next();
  580. for (var i = 0; i < repeat; i++)
  581. {
  582. colorIndexs.Add(index);
  583. }
  584. }
  585. else if (head < 0xc0)
  586. {
  587. int index = next();
  588. repeat = head % 0xa0 * 0x10000 + next() * 0x100 + next();
  589. for (var i = 0; i < repeat; i++)
  590. {
  591. colorIndexs.Add(index);
  592. }
  593. }
  594. else if (head < 0xd0)
  595. {
  596. repeat = head % 0xc0;
  597. for (var i = 0; i < repeat; i++)
  598. {
  599. colorIndexs.Add(0);
  600. }
  601. }
  602. else if (head < 0xe0)
  603. {
  604. repeat = head % 0xd0 * 0x100 + next();
  605. for (var i = 0; i < repeat; i++)
  606. {
  607. colorIndexs.Add(0);
  608. }
  609. }
  610. else if (head < 0xff)
  611. {
  612. repeat = head % 0xe0 * 0x10000 + next() * 0x100 + next();
  613. for (var i = 0; i < repeat; i++)
  614. {
  615. colorIndexs.Add(0);
  616. }
  617. }
  618. }
  619. return colorIndexs.ToArray();
  620. }
  621. #endregion 测试解压
  622. }
  623. //解压缩交给IJob处理
  624. [BurstCompile]
  625. public struct DecompressJob : IJob
  626. {
  627. [ReadOnly]
  628. public NativeArray<byte> bytes;
  629. public bool compressd;
  630. public NativeArray<byte> colorIndexs;
  631. private int _maxIndex;
  632. private int _index;
  633. private int _colorIndex;
  634. private int NextByte()
  635. {
  636. _index++;
  637. if (_index > _maxIndex) return -1;
  638. return bytes[_index];
  639. }
  640. private void AddColorIndex(byte index)
  641. {
  642. if (_colorIndex > colorIndexs.Length - 1) return;
  643. colorIndexs[_colorIndex] = index;
  644. _colorIndex++;
  645. }
  646. [BurstCompile]
  647. public void Execute()
  648. {
  649. _maxIndex = bytes.Length - 1;
  650. _index = -1;
  651. _colorIndex = 0;
  652. if (!compressd)
  653. {
  654. while (_index<=_maxIndex)
  655. {
  656. int pindex = NextByte();
  657. if(pindex==-1) break;
  658. AddColorIndex((byte)pindex);
  659. }
  660. }
  661. else
  662. //压缩型数据解压
  663. {
  664. // int count = 0;
  665. while (_index<=_maxIndex)
  666. {
  667. // count++;
  668. int head = NextByte();
  669. if(head==-1) break;
  670. int repeat = 0;
  671. if (head < 0x10)
  672. {
  673. repeat = head;
  674. for (var i = 0; i < repeat; i++)
  675. {
  676. AddColorIndex((byte)NextByte());
  677. }
  678. }
  679. else if (head < 0x20)
  680. {
  681. repeat = head % 0x10 * 0x100 + NextByte();
  682. for (var i = 0; i < repeat; i++)
  683. {
  684. AddColorIndex((byte)NextByte());
  685. }
  686. }
  687. else if (head < 0x80)
  688. {
  689. repeat = head % 0x20 * 0x10000 + NextByte() * 0x100 + NextByte();
  690. for (var i = 0; i < repeat; i++)
  691. {
  692. AddColorIndex((byte)NextByte());
  693. }
  694. }
  695. else if (head < 0x90)
  696. {
  697. repeat = head % 0x80;
  698. byte index = (byte)NextByte();
  699. for (var i = 0; i < repeat; i++)
  700. {
  701. AddColorIndex(index);
  702. }
  703. }
  704. else if (head < 0xa0)
  705. {
  706. byte index = (byte)NextByte();
  707. repeat = head % 0x90 * 0x100 + NextByte();
  708. for (var i = 0; i < repeat; i++)
  709. {
  710. AddColorIndex(index);
  711. }
  712. }
  713. else if (head < 0xc0)
  714. {
  715. byte index = (byte)NextByte();
  716. repeat = head % 0xa0 * 0x10000 + NextByte() * 0x100 + NextByte();
  717. for (var i = 0; i < repeat; i++)
  718. {
  719. AddColorIndex(index);
  720. }
  721. }
  722. else if (head < 0xd0)
  723. {
  724. repeat = head % 0xc0;
  725. for (var i = 0; i < repeat; i++)
  726. {
  727. AddColorIndex(0);
  728. }
  729. }
  730. else if (head < 0xe0)
  731. {
  732. repeat = head % 0xd0 * 0x100 + NextByte();
  733. for (var i = 0; i < repeat; i++)
  734. {
  735. AddColorIndex(0);
  736. }
  737. }
  738. else
  739. {
  740. repeat = head % 0xe0 * 0x10000 + NextByte() * 0x100 + NextByte();
  741. for (var i = 0; i < repeat; i++)
  742. {
  743. AddColorIndex(0);
  744. }
  745. }
  746. }
  747. }
  748. }
  749. }
  750. }