public override void SetData(byte[] data) { int validSize = N64Texture.GetTexSize(Width * Height, Format); if (data.Length != validSize) { throw new Z64ObjectException($"Invalid data size (0x{data.Length:X} instead of 0x{validSize:X})"); } Texture = data; }
private void UpdateTexture(object sender = null, EventArgs e = null) { N64TexFormat fmt = (N64TexFormat)comboBoxTexFmt.SelectedIndex; int w = (int)valueW.Value; int h = (int)valueH.Value; int texSize = N64Texture.GetTexSize(w * h, fmt); if (!uint.TryParse(textBoxTexAddr.Text, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out uint texAddr)) { return; } byte[] tlut = null; if ((fmt == N64TexFormat.CI4 || fmt == N64TexFormat.CI8) && uint.TryParse(textBoxTlutAddr.Text, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out uint tlutAddr)) { try { if (fmt == N64TexFormat.CI4) { tlut = ReadBytes(tlutAddr, 64); } else if (fmt == N64TexFormat.CI8) { tlut = ReadBytes(tlutAddr, 256); } } catch (Exception) { return; } } try { byte[] tex = ReadBytes(texAddr, texSize); textureBox1.Image = N64Texture.DecodeBitmap(w, h, fmt, tex, tlut); } catch (Exception) { return; } }
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); }
private static Tuple <List <int>, List <ReservedRegion> > FindRegions(byte[] data, int segmentId, Config cfg) { List <ReservedRegion> regions = new List <ReservedRegion>(); List <int> dlists = new List <int>(); var codeEnds = Utils.FindData(data, new byte[] { (byte)CmdID.G_ENDDL, 0, 0, 0, 0, 0, 0, 0, }, 8); codeEnds.Insert(0, 0); for (int i = 1; i < codeEnds.Count; i++) { int end = codeEnds[i]; int texels = -1; uint half1 = 0xFFFFFFFF; for (int off = end; off >= codeEnds[i - 1] + 8; off -= 8) { CmdID op = (CmdID)data[off]; if (IsOverlap(off, regions) || !IsOpCodeCorrect(data, off, cfg)) { break; } switch (op) { case CmdID.G_RDPHALF_1: { half1 = CmdInfo.DecodeCommand <GRdpHalf>(data, off).word; break; } case CmdID.G_BRANCH_Z: { AddDlist(dlists, segmentId, half1, data.Length); break; } case CmdID.G_DL: { var gdl = CmdInfo.DecodeCommand <GDl>(data, off); AddDlist(dlists, segmentId, gdl.dl, data.Length); break; } case CmdID.G_VTX: { var gmtx = CmdInfo.DecodeCommand <GVtx>(data, off); AddRegion(regions, segmentId, gmtx.vaddr, gmtx.numv * 0x10, data.Length); break; } case CmdID.G_SETTIMG: { var settimg = CmdInfo.DecodeCommand <GSetTImg>(data, off); if (texels == -1) { break; } AddRegion(regions, segmentId, settimg.imgaddr, N64Texture.GetTexSize(texels, settimg.siz), data.Length); texels = -1; break; } case CmdID.G_LOADBLOCK: { var loadblock = CmdInfo.DecodeCommand <GLoadBlock>(data, off); texels = loadblock.texels + 1; break; } case CmdID.G_LOADTLUT: { var loadtlut = CmdInfo.DecodeCommand <GLoadTlut>(data, off); texels = loadtlut.count + 1; break; } default: break; } } } return(new Tuple <List <int>, List <ReservedRegion> >(dlists, regions)); }
public Bitmap GetBitmap() { return(N64Texture.DecodeBitmap(Width, Height, Format, Texture, Tlut?.Texture)); }