public static byte[] Encode(byte[] rgba, G_IM_FMT fmt, G_IM_SIZ siz) { switch (fmt) { case G_IM_FMT.G_IM_FMT_RGBA: switch (siz) { case G_IM_SIZ.G_IM_SIZ_16b: return(EncodeRgba16(rgba)); case G_IM_SIZ.G_IM_SIZ_32b: return(EncodeRgba32(rgba)); default: throw new N64TextureException("Invalid Size"); } case G_IM_FMT.G_IM_FMT_YUV: case G_IM_FMT.G_IM_FMT_CI: throw new NotImplementedException(); /* * switch (siz) * { * case G_IM_SIZ.G_IM_SIZ_4b: return EncodeCI4(rgba, tlut); * case G_IM_SIZ.G_IM_SIZ_8b: return EncodeCI8(rgba, tlut); * default: throw new N64TextureException("Invalid Size"); * } */ case G_IM_FMT.G_IM_FMT_IA: switch (siz) { case G_IM_SIZ.G_IM_SIZ_4b: return(EncodeIA4(rgba)); case G_IM_SIZ.G_IM_SIZ_8b: return(EncodeIA8(rgba)); case G_IM_SIZ.G_IM_SIZ_16b: return(EncodeIA16(rgba)); default: throw new N64TextureException("Invalid Size"); } case G_IM_FMT.G_IM_FMT_I: switch (siz) { case G_IM_SIZ.G_IM_SIZ_4b: return(EncodeI4(rgba)); case G_IM_SIZ.G_IM_SIZ_8b: return(EncodeI8(rgba)); default: throw new N64TextureException("Invalid Size"); } default: throw new N64TextureException("Invalid Format"); } }
public static N64TexFormat ConvertFormat(G_IM_FMT fmt, G_IM_SIZ siz) { switch (fmt) { case G_IM_FMT.G_IM_FMT_RGBA: switch (siz) { case G_IM_SIZ.G_IM_SIZ_16b: return(N64TexFormat.RGBA16); case G_IM_SIZ.G_IM_SIZ_32b: return(N64TexFormat.RGBA32); default: throw new N64TextureException("Invalid Size"); } case G_IM_FMT.G_IM_FMT_YUV: case G_IM_FMT.G_IM_FMT_CI: switch (siz) { case G_IM_SIZ.G_IM_SIZ_4b: return(N64TexFormat.CI4); case G_IM_SIZ.G_IM_SIZ_8b: return(N64TexFormat.CI8); default: throw new N64TextureException("Invalid Size"); } case G_IM_FMT.G_IM_FMT_IA: switch (siz) { case G_IM_SIZ.G_IM_SIZ_4b: return(N64TexFormat.IA4); case G_IM_SIZ.G_IM_SIZ_8b: return(N64TexFormat.IA8); case G_IM_SIZ.G_IM_SIZ_16b: return(N64TexFormat.IA16); default: throw new N64TextureException("Invalid Size"); } case G_IM_FMT.G_IM_FMT_I: switch (siz) { case G_IM_SIZ.G_IM_SIZ_4b: return(N64TexFormat.I4); case G_IM_SIZ.G_IM_SIZ_8b: return(N64TexFormat.I8); default: throw new N64TextureException("Invalid Size"); } default: throw new N64TextureException("Invalid Format"); } }
public static byte[] Decode(int texels, G_IM_FMT fmt, G_IM_SIZ siz, byte[] buff, byte[] tlut) { switch (fmt) { case G_IM_FMT.G_IM_FMT_RGBA: switch (siz) { case G_IM_SIZ.G_IM_SIZ_16b: return(DecodeRgba16(texels, buff)); case G_IM_SIZ.G_IM_SIZ_32b: return(DecodeRgba32(texels, buff)); default: throw new N64TextureException("Invalid Size"); } case G_IM_FMT.G_IM_FMT_YUV: case G_IM_FMT.G_IM_FMT_CI: switch (siz) { case G_IM_SIZ.G_IM_SIZ_4b: return(DecodeCI4(texels, buff, tlut)); case G_IM_SIZ.G_IM_SIZ_8b: return(DecodeCI8(texels, buff, tlut)); default: throw new N64TextureException("Invalid Size"); } case G_IM_FMT.G_IM_FMT_IA: switch (siz) { case G_IM_SIZ.G_IM_SIZ_4b: return(DecodeIA4(texels, buff)); case G_IM_SIZ.G_IM_SIZ_8b: return(DecodeIA8(texels, buff)); case G_IM_SIZ.G_IM_SIZ_16b: return(DecodeIA16(texels, buff)); default: throw new N64TextureException("Invalid Size"); } case G_IM_FMT.G_IM_FMT_I: switch (siz) { case G_IM_SIZ.G_IM_SIZ_4b: return(DecodeI4(texels, buff)); case G_IM_SIZ.G_IM_SIZ_8b: return(DecodeI8(texels, buff)); default: throw new N64TextureException("Invalid Size"); } default: throw new N64TextureException("Invalid Format"); } }
public static unsafe byte[] EncodeBitmap(Bitmap bmp, G_IM_FMT fmt, G_IM_SIZ siz) { var bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); byte *argb = (byte *)bmpData.Scan0; byte[] rgba = new byte[bmp.Width * bmp.Height * 4]; for (int i = 0; i < bmp.Width * bmp.Height; i++) { rgba[4 * i + 0] = argb[4 * i + 2]; //R rgba[4 * i + 1] = argb[4 * i + 1]; //G rgba[4 * i + 2] = argb[4 * i + 0]; //B rgba[4 * i + 3] = argb[4 * i + 3]; //A } bmp.UnlockBits(bmpData); return(Encode(rgba, fmt, siz)); }
public static unsafe Bitmap DecodeBitmap(int w, int h, G_IM_FMT fmt, G_IM_SIZ siz, byte[] buff, byte[] tlut = null) { Bitmap bmp = new Bitmap(w, h); var bmpData = bmp.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); byte *argb = (byte *)bmpData.Scan0; byte[] rgba = Decode(w * h, fmt, siz, buff, tlut); for (int i = 0; i < w * h; i++) { argb[4 * i + 3] = rgba[4 * i + 3]; //A argb[4 * i + 2] = rgba[4 * i + 0]; //R argb[4 * i + 1] = rgba[4 * i + 1]; //G argb[4 * i + 0] = rgba[4 * i + 2]; //B } bmp.UnlockBits(bmpData); return(bmp); }
public static List <string> AnalyzeDlists(Z64Object obj, byte[] data, int segmentId) { List <string> errors = new List <string>(); List <int> dlists = new List <int>(); for (int i = 0; i < obj.Entries.Count; i++) { var entry = obj.Entries[i]; if (entry.GetEntryType() == Z64Object.EntryType.DList) { dlists.Add(obj.OffsetOf(entry)); } else { obj.Entries[i] = new Z64Object.UnknowHolder($"unk_{obj.OffsetOf(entry):X8}", entry.GetData()); } } foreach (var dlist in dlists) { uint lastTexAddr = 0xFFFFFFFF; G_IM_FMT lastFmt = (G_IM_FMT)(-1); G_IM_SIZ lastSiz = (G_IM_SIZ)(-1); Z64Object.TextureHolder lastTlut = null; Z64Object.TextureHolder lastCiTex = null; bool exit = false; for (int i = dlist; i < data.Length && !exit; i += 8) { CmdID op = (CmdID)data[i]; switch (op) { case CmdID.G_QUAD: case CmdID.G_TRI2: case CmdID.G_TRI1: case CmdID.G_TEXRECTFLIP: case CmdID.G_TEXRECT: { if (lastCiTex != null && lastTlut != null) { lastCiTex.Tlut = lastTlut; lastCiTex = null; } break; } case CmdID.G_ENDDL: { exit = true; break; } case CmdID.G_MTX: { var gmtx = CmdInfo.DecodeCommand <GMtx>(data, i); var addr = new SegmentedAddress(gmtx.mtxaddr); if (addr.Segmented && addr.SegmentId == segmentId) { obj.AddMtx(1, off: (int)addr.SegmentOff); } break; } case CmdID.G_VTX: { var gvtx = CmdInfo.DecodeCommand <GVtx>(data, i); var addr = new SegmentedAddress(gvtx.vaddr); if (addr.Segmented && addr.SegmentId == segmentId) { try { obj.AddVertices(gvtx.numv, off: (int)addr.SegmentOff); } catch (Exception ex) { errors.Add($"Error in Dlist 0x{new SegmentedAddress(segmentId, dlist).VAddr:X8} : {ex.Message}"); } } break; } case CmdID.G_SETTIMG: { var settimg = CmdInfo.DecodeCommand <GSetTImg>(data, i); lastTexAddr = settimg.imgaddr; break; } case CmdID.G_SETTILE: { var settile = CmdInfo.DecodeCommand <GSetTile>(data, i); if (settile.tile != G_TX_TILE.G_TX_LOADTILE) { lastFmt = settile.fmt; lastSiz = settile.siz; } break; } case CmdID.G_SETTILESIZE: { var settilesize = CmdInfo.DecodeCommand <GLoadTile>(data, i); var addr = new SegmentedAddress(lastTexAddr); if ((int)lastFmt == -1 || (int)lastSiz == -1 || lastTexAddr == 0xFFFFFFFF) { /* can't really thow an exception here since in some object files, there are two gsDPSetTileSize next to each other (see object_en_warp_uzu) */ //throw new Z64ObjectAnalyzerException(); break; } if (addr.Segmented && addr.SegmentId == segmentId) { try { var tex = obj.AddTexture((int)(settilesize.lrs.Float() + 1), (int)(settilesize.lrt.Float() + 1), N64Texture.ConvertFormat(lastFmt, lastSiz), off: (int)addr.SegmentOff); if (lastFmt == G_IM_FMT.G_IM_FMT_CI) { lastCiTex = tex; } } catch (Exception ex) { errors.Add($"Error in Dlist 0x{new SegmentedAddress(segmentId, dlist).VAddr:X8} : {ex.Message}"); } } lastFmt = (G_IM_FMT)(-1); lastSiz = (G_IM_SIZ)(-1); lastTexAddr = 0xFFFFFFFF; break; } case CmdID.G_LOADTLUT: { var loadtlut = CmdInfo.DecodeCommand <GLoadTlut>(data, i); var addr = new SegmentedAddress(lastTexAddr); if (lastTexAddr == 0xFFFFFFFF) { throw new Z64ObjectAnalyzerException(); } int w = GetTlutWidth(loadtlut.count + 1); if (addr.Segmented && addr.SegmentId == segmentId) { try { lastTlut = obj.AddTexture(w, (loadtlut.count + 1) / w, N64Texture.ConvertFormat(G_IM_FMT.G_IM_FMT_RGBA, G_IM_SIZ.G_IM_SIZ_16b), off: (int)addr.SegmentOff); } catch (Exception ex) { errors.Add($"Error in Dlist 0x{new SegmentedAddress(segmentId, dlist).VAddr:X8} : {ex.Message}"); } } break; } } } } // These are carried out here as they are dependent on a lot of heuristics. // Having lots of the object already mapped out reduces possible mis-identifications. FindSkeletons(obj, data, segmentId); FindAnimations(obj, data, segmentId); obj.GroupUnkEntries(); obj.FixNames(); obj.SetData(data); return(errors); }