304 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
		
		
			
		
	
	
			304 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
|  | import { _decorator, Asset, assetManager, BufferAsset, Component, error, Node, resources, TextAsset, Texture2D } from 'cc'; | ||
|  | import { ReadStream } from '../Tool/ReadStream'; | ||
|  | import * as pako from 'pako'; | ||
|  | import { Img, ImgInfo, NpkInfo } from '../GlobalInterface/GlobalInterface'; | ||
|  | 
 | ||
|  | 
 | ||
|  | const { ccclass, property } = _decorator; | ||
|  | 
 | ||
|  | 
 | ||
|  | type NewType = Img; | ||
|  | 
 | ||
|  | @ccclass('ImagePack') | ||
|  | export class ImagePack extends Component { | ||
|  | 
 | ||
|  |     //全局单例类
 | ||
|  |     private static instance: ImagePack; | ||
|  | 
 | ||
|  |     private constructor() { | ||
|  |         super(); | ||
|  |     } | ||
|  | 
 | ||
|  |     public static getInstance(): ImagePack { | ||
|  |         if (!ImagePack.instance) { | ||
|  |             ImagePack.instance = new ImagePack(); | ||
|  |         } | ||
|  |         return ImagePack.instance; | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  |     Key: Array<number> = [112, 117, 99, 104, 105, 107, 111, 110, 64, 110, 101, 111, 112, 108, 101, 32, 100, 117, 110, 103, 101, 111, 110, 32, 97, 110, 100, 32, 102, 105, 103, 104, 116, 101, 114, 32, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 68, 78, 70, 0]; | ||
|  | 
 | ||
|  | 
 | ||
|  |     //NPK加载完成后的回调函数
 | ||
|  |     LoadCallBack = undefined; | ||
|  |     //NPK文件数量
 | ||
|  |     private NpkCount = 0; | ||
|  |     //已加载NPK文件数量
 | ||
|  |     private LoadNpkCount = 0; | ||
|  |     //Img的map Key:img路径  Value:Img结构体
 | ||
|  |     private Map_Img: Map<string, NewType> = new Map<string, Img>(); | ||
|  |     //NPK的本地路径 对应的 NPK名字
 | ||
|  |     private Npk_URL_Table: Map<string, string> = new Map<string, string>(); | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  |     start() { | ||
|  | 
 | ||
|  |     } | ||
|  | 
 | ||
|  |     update(deltaTime: number) { | ||
|  | 
 | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     initSuccess(): void { | ||
|  |         if (this.LoadCallBack) this.LoadCallBack(); | ||
|  |     } | ||
|  | 
 | ||
|  |     BundleObject; | ||
|  |     init(Func: Function): void { | ||
|  |         //储存回调
 | ||
|  |         this.LoadCallBack = Func; | ||
|  | 
 | ||
|  |         assetManager.loadBundle('ImagePacks', (err, bundle) => { | ||
|  |             this.BundleObject = bundle; | ||
|  |             this.LoadNpk(); | ||
|  |         }); | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     LoadNpk(): void { | ||
|  |         this.BundleObject.loadDir("", BufferAsset, (err, contents: Array<BufferAsset>) => { | ||
|  |             //记录NPK文件数量
 | ||
|  |             this.NpkCount = contents.length; | ||
|  |             console.log(this.NpkCount); | ||
|  | 
 | ||
|  |             contents.forEach(content => { | ||
|  |                 const Buf = new Uint8Array(content.buffer()); | ||
|  |                 const Ro = new ReadStream(Buf); | ||
|  |                 //文件头
 | ||
|  |                 const Header = Ro.GetString(); | ||
|  |                 if (Header == "NeoplePack_Bill") { | ||
|  |                     //读取img数量
 | ||
|  |                     const ImageCount = Ro.GetInt(); | ||
|  |                     let ImgList: NpkInfo[] = new Array<NpkInfo>(ImageCount); | ||
|  |                     for (let i = 0; i < ImageCount; i++) { | ||
|  |                         ImgList[i] = { | ||
|  |                             Offset: Ro.GetInt(), | ||
|  |                             Length: Ro.GetInt(), | ||
|  |                             Path: Ro.ReadInfo(this.Key), | ||
|  |                         } | ||
|  |                     } | ||
|  |                     for (let i = 0; i < ImageCount; i++) { | ||
|  |                         let Buf: Img = { | ||
|  |                             ImgOffset: ImgList[i].Offset, | ||
|  |                             ImgSize: ImgList[i].Length, | ||
|  |                             Img_Index: i, | ||
|  |                             BelongsFile: content.nativeUrl, | ||
|  |                             ImgName: ImgList[i].Path, | ||
|  |                             Png_List: null, | ||
|  |                             Png_Count: 0 | ||
|  |                         } | ||
|  |                         this.Map_Img.set(ImgList[i].Path, Buf); | ||
|  |                     } | ||
|  |                 } | ||
|  | 
 | ||
|  |                 //完成一个加载
 | ||
|  |                 this.LoadNpkCount = this.LoadNpkCount + 1; | ||
|  |                 //加载完成
 | ||
|  |                 if (this.LoadNpkCount == this.NpkCount) { | ||
|  |                     this.initSuccess(); | ||
|  |                 } | ||
|  |                 //把本地路径和NPK名称挂钩一下
 | ||
|  |                 this.Npk_URL_Table.set(content.nativeUrl, content.name); | ||
|  |                 //载入完成以后需要释放
 | ||
|  |                 assetManager.releaseAsset(content); | ||
|  |             }); | ||
|  |         }); | ||
|  |     } | ||
|  | 
 | ||
|  |     LoadImgToMem(ImgObj: Img, func: Function) { | ||
|  | 
 | ||
|  |         //获取路径 如果不存在直接返回
 | ||
|  |         const Path = this.Npk_URL_Table.get(ImgObj.BelongsFile); | ||
|  |         if (!Path) return; | ||
|  |         this.BundleObject.load(Path, BufferAsset, (err, content) => { | ||
|  |             const Buf = new Uint8Array(content.buffer()); | ||
|  |             const Ro = new ReadStream(Buf); | ||
|  | 
 | ||
|  |             Ro.Seekg(ImgObj.ImgOffset); | ||
|  |             //Img头
 | ||
|  |             const Header = Ro.GetString(); | ||
|  |             //开始读图片
 | ||
|  |             if (Header == "Neople Img File") { | ||
|  |                 //索引表大小
 | ||
|  |                 const TableLength = Ro.GetLongInt(); | ||
|  | 
 | ||
|  |                 //img 版本 4字节
 | ||
|  |                 const ver = Ro.GetInt(); | ||
|  |                 //img 帧数
 | ||
|  |                 const IndexCount = Ro.GetInt(); | ||
|  | 
 | ||
|  |                 ImgObj.Png_Count = IndexCount; | ||
|  | 
 | ||
|  |                 let PngArr: ImgInfo[] = []; | ||
|  |                 for (let index = 0; index < IndexCount; index++) { | ||
|  | 
 | ||
|  |                     let ImgBuf: ImgInfo = {}; | ||
|  | 
 | ||
|  |                     //图片格式
 | ||
|  |                     ImgBuf.Type = Ro.GetInt(); | ||
|  |                     if (ImgBuf.Type == 17) { | ||
|  |                         //引用贴图
 | ||
|  |                         const IndexBuf = Ro.GetInt(); | ||
|  |                         ImgBuf.Offset = PngArr[index - 1].Offset; | ||
|  |                         ImgBuf.Type = 17; | ||
|  |                         ImgBuf.QuoteIndex = IndexBuf; | ||
|  |                         ImgBuf.Size = PngArr[index - 1].Size; | ||
|  |                         PngArr.push(ImgBuf); | ||
|  |                         continue; | ||
|  |                     } | ||
|  |                     //压缩类型
 | ||
|  |                     ImgBuf.CmpType = Ro.GetInt(); | ||
|  |                     //宽度
 | ||
|  |                     ImgBuf.Width = Ro.GetInt(); | ||
|  |                     //高度
 | ||
|  |                     ImgBuf.Height = Ro.GetInt(); | ||
|  |                     //大小
 | ||
|  |                     ImgBuf.Size = Ro.GetInt(); | ||
|  |                     //Xpos
 | ||
|  |                     ImgBuf.Xpos = Ro.GetInt(); | ||
|  |                     //Ypos
 | ||
|  |                     ImgBuf.Ypos = Ro.GetInt(); | ||
|  |                     //帧域X
 | ||
|  |                     ImgBuf.FrameXpos = Ro.GetInt(); | ||
|  |                     //帧域Y
 | ||
|  |                     ImgBuf.FrameYpos = Ro.GetInt(); | ||
|  | 
 | ||
|  |                     if (index == 0) { | ||
|  |                         ImgBuf.Offset = 0 + ImgObj.ImgOffset + Number(TableLength) + 32; | ||
|  |                     } else { | ||
|  |                         ImgBuf.Offset = PngArr[index - 1].Offset + PngArr[index - 1].Size; | ||
|  |                     } | ||
|  |                     PngArr.push(ImgBuf); | ||
|  |                 } | ||
|  | 
 | ||
|  |                 for (let index = 0; index < IndexCount; index++) { | ||
|  |                     let PngObj = PngArr[index]; | ||
|  |                     //引用贴图
 | ||
|  |                     if (PngObj.Type == 17) { | ||
|  |                         const QuoteIndexBuf = PngObj.QuoteIndex; | ||
|  |                         PngArr[index] = PngArr[QuoteIndexBuf]; | ||
|  |                     } | ||
|  |                 } | ||
|  | 
 | ||
|  |                 for (let index = 0; index < IndexCount; index++) { | ||
|  |                     let PngObj = PngArr[index]; | ||
|  | 
 | ||
|  | 
 | ||
|  |                     Ro.Seekg(PngObj.Offset); | ||
|  |                     //PNG压缩原始数据
 | ||
|  |                     let DataBuf = Ro.GetBufferByLength(PngObj.Size); | ||
|  | 
 | ||
|  |                     //图片数据应有大小
 | ||
|  |                     let PngBufSize = PngObj.Width * PngObj.Height * 4; | ||
|  |                     // 使用pako 解压 zlib的inflate函数解压缩数据
 | ||
|  |                     let Bsf; | ||
|  |                     try { | ||
|  |                         Bsf = pako.inflate(DataBuf); | ||
|  |                     } | ||
|  |                     catch (error) { | ||
|  |                         Bsf = DataBuf; | ||
|  |                     } | ||
|  | 
 | ||
|  |                     if (PngObj.Type != 16) { | ||
|  |                         let PngByteSize = Bsf.length * 2; | ||
|  |                         PngObj.PNGdata = new Uint8Array(PngByteSize); | ||
|  |                         for (let e = 0; e < PngByteSize; e += 4) { | ||
|  |                             let BarBuf = new Uint8Array(2); | ||
|  | 
 | ||
|  |                             let Pos = (e / 4) * 2; | ||
|  |                             BarBuf[0] = Bsf[Pos]; | ||
|  |                             BarBuf[1] = Bsf[Pos + 1]; | ||
|  |                             this.ReadColor(BarBuf, PngObj, e); | ||
|  |                         } | ||
|  |                     } | ||
|  |                     else { | ||
|  |                         PngObj.PNGdata = new Uint8Array(Bsf.length); | ||
|  |                         for (let index = 0; index < Bsf.length; index += 4) { | ||
|  |                             PngObj.PNGdata[index] = Bsf[index + 2]; | ||
|  |                             PngObj.PNGdata[index + 1] = Bsf[index + 1]; | ||
|  |                             PngObj.PNGdata[index + 2] = Bsf[index]; | ||
|  |                             PngObj.PNGdata[index + 3] = Bsf[index + 3]; | ||
|  |                         } | ||
|  |                     } | ||
|  |                 } | ||
|  |                 ImgObj.Png_List = PngArr; | ||
|  |                 func(ImgObj); | ||
|  |             } | ||
|  | 
 | ||
|  |             //载入完成以后需要释放
 | ||
|  |             assetManager.releaseAsset(content); | ||
|  |         }); | ||
|  |     } | ||
|  | 
 | ||
|  |     ReadColor(Bar: Uint8Array, PngObj: ImgInfo, Offset: number) { | ||
|  |         let a: number = 0; | ||
|  |         let r: number = 0; | ||
|  |         let g: number = 0; | ||
|  |         let b: number = 0; | ||
|  |         switch (PngObj.Type) { | ||
|  |             case 0x0e: | ||
|  |                 a = Bar[1] >> 7; | ||
|  |                 r = (Bar[1] >> 2) & 0x1f; | ||
|  |                 g = (Bar[0] >> 5) | ((Bar[1] & 3) << 3); | ||
|  |                 b = Bar[0] & 0x1f; | ||
|  |                 a = a * 0xff; | ||
|  |                 r = (r << 3) | (r >> 2); | ||
|  |                 g = (g << 3) | (g >> 2); | ||
|  |                 b = (b << 3) | (b >> 2); | ||
|  |                 break; | ||
|  |             case 0x0f: | ||
|  |                 a = Bar[1] & 0xf0; | ||
|  |                 r = (Bar[1] & 0xf) << 4; | ||
|  |                 g = Bar[0] & 0xf0; | ||
|  |                 b = (Bar[0] & 0xf) << 4; | ||
|  |                 break; | ||
|  |             default: | ||
|  |                 console.log(PngObj.Type); | ||
|  |                 break; | ||
|  |         } | ||
|  |         PngObj.PNGdata[Offset + 0] = r; | ||
|  |         PngObj.PNGdata[Offset + 1] = g; | ||
|  |         PngObj.PNGdata[Offset + 2] = b; | ||
|  |         PngObj.PNGdata[Offset + 3] = a; | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     //读取Img数据
 | ||
|  |     ReadNpkTable(imgname: string, func: Function): boolean { | ||
|  |         let ImgObj: Img = this.Map_Img.get(imgname); | ||
|  |         if (ImgObj) { | ||
|  |             //没有图片数据 需要加载
 | ||
|  |             if (ImgObj.Png_List == null) { | ||
|  |                 //加载Img进内存
 | ||
|  |                 this.LoadImgToMem(ImgObj, func); | ||
|  |                 return true; | ||
|  |             } | ||
|  |             else { | ||
|  |                 func(ImgObj); | ||
|  |                 return true; | ||
|  |             } | ||
|  |         } | ||
|  |         return false; | ||
|  |     } | ||
|  | 
 | ||
|  |     ReleaseNpkTable(p: Img): void { | ||
|  |         // implementation
 | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | 
 |