Exemple #1
0
        /// <summary>
        ///   Shamelessly copied from GLideN64's source.
        /// </summary>
        private void LoadTile32b_(
            ref TileDescriptor tileDescriptor,
            TimgArgs timgArgs)
        {
            var uls = tileDescriptor.ULS;
            var ult = tileDescriptor.ULT;
            var lrs = tileDescriptor.LRS;
            var lrt = tileDescriptor.LRT;

            var width  = lrs - uls + 1;
            var height = lrt - ult + 1;

            var line  = tileDescriptor.LineSize << 2;
            var tbase = tileDescriptor.TmemOffset << 2;

            IoUtil.SplitAddress(timgArgs.Address, out var bank, out var offset);

            var targetBank = Asserts.Assert(RamBanks.GetBankByIndex(bank));

            var timgWidth = timgArgs.Width;

            for (var j = 0; j < height; ++j)
            {
                var tline  = tbase + line * j;
                var s      = ((j + ult) * timgWidth) + uls;
                var xorval = (j & 1) != 0 ? 3 : 1;

                for (var i = 0; i < width; ++i)
                {
                    var addr = offset + s + i;
                    var c    = IoUtil.ReadUInt32(targetBank, (uint)(4 * addr));

                    var ptr = ((tline + i) ^ xorval) & 0x3ff;

                    var offset1 = 2 * ptr;
                    IoUtil.WriteInt16(targetBank, ref offset1, (ushort)(c >> 16));

                    var offset2 = 2 * (ptr | 0x400);
                    IoUtil.WriteInt16(targetBank, ref offset2, (ushort)(c & 0xffff));
                }
            }
        }
        // TODO: Remove combo box input.
        public static int ReadInDL(
            DlManager dlManager,
            uint address,
            ComboBox dListSelection)
        {
            IoUtil.SplitAddress(address, out var bank, out var offset);
            var data = Asserts.Assert(RamBanks.GetBankByIndex(bank));

            try {
                if (offset < data.Count)
                {
                    // TODO: This jumps into the lowest level DL, but the 0xDE command (DL)
                    // actually allows returning back up and calling more DLs. So this seems
                    // like it will sometimes overlook any DLs that follow.
                    // This should just be deleted and replaced w/ emulating in
                    // F3DEX2_Parser.
                    if (data[(int)offset] == 0xDE)
                    {
                        while (data[(int)offset] == 0xDE)
                        {
                            offset = IoUtil.ReadUInt24(data, (uint)(offset + 5L));
                        }
                    }

                    int index       = dlManager.Count;
                    var displayList = new N64DisplayList();
                    dlManager.Add(displayList);
                    uint EPLoc = offset;
                    dListSelection.Items.Add((index + 1).ToString() +
                                             ". " +
                                             Conversion.Hex(offset));
                    displayList.StartPos        = new ZSegment();
                    displayList.StartPos.Offset = offset;
                    displayList.StartPos.Bank   = data.Segment;
                    displayList.Skip            = false;

                    PickerUtil.NextRgb(out var r, out var g, out var b);
                    displayList.PickCol = new Color3UByte {
                        r = r, g = g, b = b
                    };

                    do
                    {
                        var commands = displayList.Commands;
                        Array.Resize(ref commands, displayList.CommandCount + 1);
                        displayList.Commands = commands;
                        displayList.Commands[displayList.CommandCount] =
                            new DLCommand(data, EPLoc);
                        if (data[(int)EPLoc] == (int)F3DZEX.ENDDL | EPLoc >= data.Count)
                        {
                            EPLoc = (uint)(EPLoc + 8L);
                            break;
                        }

                        EPLoc = (uint)(EPLoc + 8L);
                        displayList.CommandCount += 1;
                    } while (true);
                    return((int)EPLoc);
                }
            } catch (Exception ex) {
                Interaction.MsgBox("Error reading in display list: " + ex.Message,
                                   MsgBoxStyle.Critical,
                                   "Exception");
                return(default);
Exemple #3
0
        /// <summary>
        ///   Parses a limb hierarchy according to the following spec:
        ///   https://wiki.cloudmodding.com/oot/Animation_Format#Hierarchy
        /// </summary>
        public static IList <Limb>?GetHierarchies(
            IBank Data,
            bool isLink,
            DlManager dlManager,
            StaticDlModel model,
            ComboBox dListSelection)
        {
            uint limbIndexAddress;

            model.Reset();
            int j = 0;

            for (int i = 0, loopTo = Data.Count - 8; i <= loopTo; i += 4)
            {
                limbIndexAddress = IoUtil.ReadUInt32(Data, (uint)i);
                IoUtil.SplitAddress(limbIndexAddress,
                                    out var limbIndexBank,
                                    out var limbIndexOffset);
                uint limbCount = Data[i + 4];
                uint limbAddress;

                // Link has an extra set of values for each limb that define LOD model
                // display lists.
                uint limbSize;
                if (isLink)
                {
                    limbSize = 16U;
                }
                else
                {
                    limbSize = 12U;
                }

                if (RamBanks.IsValidBank((byte)limbIndexBank) & limbCount > 0L)
                {
                    var limbIndexBankBuffer = RamBanks.GetBankByIndex(limbIndexBank);

                    if (limbIndexBankBuffer != null &&
                        limbIndexOffset + 4L * limbCount < limbIndexBankBuffer.Count)
                    {
                        byte firstChild;
                        byte nextSibling;
                        bool isValid          = true;
                        bool somethingVisible = false;
                        var  loopTo1          = (int)(limbCount - 1L);
                        for (j = 0; j <= loopTo1; j++)
                        {
                            limbAddress = IoUtil.ReadUInt32(limbIndexBankBuffer,
                                                            (uint)(limbIndexOffset + j * 4));

                            IoUtil.SplitAddress(limbAddress,
                                                out var limbBank,
                                                out var limbOffset);

                            if (!RamBanks.IsValidBank(limbBank))
                            {
                                isValid = false;
                                goto badLimbIndexOffset;
                            }

                            var limbBankBuffer = RamBanks.GetBankByIndex(limbBank);
                            if (limbBankBuffer == null)
                            {
                                isValid = false;
                                goto badLimbIndexOffset;
                            }

                            if (limbOffset + limbSize >= limbBankBuffer.Count)
                            {
                                isValid = false;
                                goto badLimbIndexOffset;
                            }

                            firstChild  = limbBankBuffer[(int)(limbOffset + 6L)];
                            nextSibling = limbBankBuffer[(int)(limbOffset + 7L)];
                            if (firstChild == j | nextSibling == j)
                            {
                                isValid = false;
                                goto badLimbIndexOffset;
                            }

                            var displayListAddress =
                                IoUtil.ReadUInt32(limbBankBuffer, (uint)(limbOffset + 8L));
                            IoUtil.SplitAddress(displayListAddress,
                                                out var displayListBank,
                                                out var displayListOffset);

                            if (displayListBank != 0L)
                            {
                                somethingVisible = true;
                            }

                            if (displayListBank != 0L &
                                !RamBanks.IsValidBank((byte)displayListBank))
                            {
                                isValid = false;
                                goto badLimbIndexOffset;
                            }
                        }

badLimbIndexOffset:

                        if (isValid)
                        {
                            var tmpHierarchy = new Limb[(int)(limbCount - 1L + 1)];
                            for (int k = 0, loopTo2 = (int)(limbCount - 1L);
                                 k <= loopTo2;
                                 k++)
                            {
                                limbAddress = IoUtil.ReadUInt32(limbIndexBankBuffer,
                                                                (uint)(limbIndexOffset +
                                                                       4 * k));
                                IoUtil.SplitAddress(limbAddress,
                                                    out var limbBank,
                                                    out var limbOffset);
                                var limbBankBuffer =
                                    Asserts.Assert(RamBanks.GetBankByIndex(limbBank));

                                {
                                    var limbData =
                                        FinMarshal.Deserialize <LimbData>(
                                            limbBankBuffer,
                                            (int)limbOffset,
                                            true);

                                    var limb = tmpHierarchy[k] = new Limb(limbData);

                                    var displayListAddress = limbData.displayListAddress;
                                    IoUtil.SplitAddress(displayListAddress,
                                                        out var displayListBank,
                                                        out var displayListOffset);

                                    model.AddLimb(limb.Visible,
                                                  limb.x,
                                                  limb.y,
                                                  limb.z,
                                                  limb.firstChild,
                                                  limb.nextSibling);

                                    if (displayListBank != 0L)
                                    {
                                        var displayListBankBuffer =
                                            RamBanks.GetBankByIndex(displayListBank);
                                        DisplayListReader.ReadInDL(dlManager,
                                                                   displayListAddress,
                                                                   dListSelection);
                                    }

                                    // Far model display list (i.e. LOD model). Only used for Link.
                                    // If Data(tmpLimbOff + 12) = Bank Then
                                    // .DisplayListLow = ReadUInt24(Data, tmpLimbOff + 13)
                                    // ReDim Preserve N64DList(N64DList.Length)
                                    // ReadInDL(Data, N64DList, .DisplayListLow, N64DList.Length - 1)
                                    // Else

                                    // End If
                                    PickerUtil.NextRgb(out var r, out var g, out var b);
                                    limb.r = r;
                                    limb.g = g;
                                    limb.b = b;
                                }
                            }

                            if (isValid & !somethingVisible)
                            {
                                throw new NotSupportedException(
                                          "model format is not rendering a valid model!");
                            }

                            return(tmpHierarchy);
                        }
                    }
                }
            }

            return(null);
        }
Exemple #4
0
        // TODO: The other method passes in "texels", not "lrs"???
        /// <summary>
        ///   Shamelessly copied from GLideN64's source.
        /// </summary>
        public void LoadBlock(
            ref TileDescriptor tileDescriptor,
            uint uls,
            uint ult,
            uint lrs,
            uint dxt,
            TimgArgs timgArgs)
        {
            tileDescriptor.ULS = (int)uls >> 2;
            tileDescriptor.ULT = (int)ult >> 2;
            // TODO: This feels like a bug?
            tileDescriptor.LRS = (int)lrs >> 2;
            tileDescriptor.LRT = (int)dxt >> 2;

            var tmem        = tileDescriptor.TmemOffset;
            var colorFormat = tileDescriptor.ColorFormat;
            var bitSize     = tileDescriptor.BitSize;

            /*if (gSP.DMAOffsets.tex_offset != 0) {
             * if (gSP.DMAOffsets.tex_shift % (((lrs >> 2) + 1) << 3)) {
             *  gDP.textureImage.address -= gSP.DMAOffsets.tex_shift;
             *  gSP.DMAOffsets.tex_offset = 0;
             *  gSP.DMAOffsets.tex_shift = 0;
             *  gSP.DMAOffsets.tex_count = 0;
             * } else
             ++gSP.DMAOffsets.tex_count;
             * }*/

            var timgAddress = timgArgs.Address;
            var timgBitSize = timgArgs.BitSize;
            var timgWidth   = timgArgs.Width;
            var timgBpl     = timgWidth << (int)timgBitSize >> 1;


            IoUtil.SplitAddress(timgAddress, out var bank, out var offset);
            tileDescriptor.Address   = (int)timgAddress;
            tileDescriptor.ImageBank = (int)bank;
            tileDescriptor.Offset    = (int)offset;

            var texture = this.cache_[tileDescriptor];

            if (texture != null)
            {
                return;
            }

            /*gDPLoadTileInfo & info = gDP.loadInfo[gDP.loadTile->tmem];
             * info.texAddress = gDP.loadTile->imageAddress;
             * info.uls = static_cast<u16>(gDP.loadTile->uls);
             * info.ult = static_cast<u16>(gDP.loadTile->ult);
             * info.lrs = static_cast<u16>(gDP.loadTile->lrs);
             * info.lrt = static_cast<u16>(gDP.loadTile->lrt);
             * info.width = static_cast<u16>(gDP.loadTile->lrs);
             * info.dxt = dxt;
             * info.size = static_cast<u8>(gDP.textureImage.size);
             * info.loadType = LOADTYPE_BLOCK;*/

            // TODO: This doesn't look right?
            uint jankWidth = (lrs - uls + 1) & 0x0FFF;
            uint bytes     = jankWidth << (int)bitSize >> 1;

            if ((bytes & 7) != 0)
            {
                bytes = (bytes & (~7U)) + 8;
            }


            //info.bytes = bytes;
            uint address = (uint)(timgAddress +
                                  ult * timgBpl +
                                  (uls << (int)timgBitSize >> 1));

            IoUtil.SplitAddress(address, out var specBank, out var specOffset);



            /*if (bytes == 0 || (address + bytes) > RDRAMSize) {
             * DebugMsg(DEBUG_NORMAL | DEBUG_ERROR, "// Attempting to load texture block out of range\n");
             * DebugMsg(DEBUG_NORMAL, "gDPLoadBlock( %i, %i, %i, %i, %i );\n", tile, uls, ult, lrs, dxt);
             * return;
             * }*/

            /*
             * gDP.loadTile->frameBufferAddress = 0;
             * CheckForFrameBufferTexture(address, info.width, bytes); // Load data to TMEM even if FB texture is found. See comment to texturedRectDepthBufferCopy
             */
            /*var texLowerBound = tileDescriptor.TmemOffset;
             * var texUpperBound = texLowerBound + (bytes >> 3);
             * for (var i = 0; i < tile; ++i) {
             * if (gDP.tiles[i].tmem >= texLowerBound && gDP.tiles[i].tmem < texUpperBound) {
             *  gDPLoadTileInfo & info = gDP.loadInfo[gDP.tiles[i].tmem];
             *  info.loadType = LOADTYPE_BLOCK;
             * }
             * }*/

            var targetBuffer = RamBanks.GetBankByIndex(specBank);

            if (targetBuffer == null)
            {
                return;
            }

            uint tmemAddr = tmem;

            if (bitSize == BitSize.S_32B)
            {
                //gDPLoadBlock32(gDP.loadTile->uls, gDP.loadTile->lrs, dxt);
            }
            else if (colorFormat == ColorFormat.YUV)
            {
                //memcpy(TMEM, &RDRAM[address], bytes); // HACK!
            }
            else
            {
                for (var i = 0; i < bytes; ++i)
                {
                    this.impl_[i] = targetBuffer[(int)(specOffset + i)];
                }

                // TODO: Figure out what the heck this stuff below does.

                /*this.UnswapCopyWrap_(targetBuffer,
                 *                   specOffset,
                 *                   this.impl_,
                 *                   tmemAddr << 3,
                 *                   0xFFF,
                 *                   bytes);*/
                /*if (dxt != 0) {
                 * uint dxtCounter = 0;
                 * uint qwords = (bytes >> 3);
                 * uint line = 0;
                 * while (true) {
                 *  do {
                 ++tmemAddr;
                 *    --qwords;
                 *    if (qwords == 0)
                 *      goto end_dxt_test;
                 *    dxtCounter += dxt;
                 *  } while ((dxtCounter & 0x800) == 0);
                 *  do {
                 ++line;
                 *    --qwords;
                 *    if (qwords == 0)
                 *      goto end_dxt_test;
                 *    dxtCounter += dxt;
                 *  } while ((dxtCounter & 0x800) != 0);
                 *  this.DWordInterleaveWrap_(this.impl_, tmemAddr << 1, 0x3FF, line);
                 *  tmemAddr += line;
                 *  line = 0;
                 * }
                 * end_dxt_test:
                 *
                 * this.DWordInterleaveWrap_(this.impl_, tmemAddr << 1, 0x3FF, line);
                 * }*/
            }
        }
        /// <summary>
        ///   Parses a set of animations according to the spec at:
        ///   https://wiki.cloudmodding.com/oot/Animation_Format#Normal_Animations
        /// </summary>
        // TODO: Some jank still slips through, is there a proper list of these
        // addresses somewhere in the file?
        public IList <IAnimation>?GetCommonAnimations(
            IBank bank,
            int limbCount,
            ListBox animationList)
        {
            animationList.Items.Clear();

            uint trackCount = (uint)(limbCount * 3);
            var  animations = new List <IAnimation>();

            // Guesstimating the index by looking for an spot where the header's angle
            // address and track address have the same bank as the param at the top.
            for (var i = 4; i < bank.Count - 12; i += 4)
            {
                var attemptOffset = (uint)(i - 4);

                // Verifies the frame count is positive.
                var frameCount = IoUtil.ReadUInt16(bank, attemptOffset);
                if (frameCount == 0)
                {
                    continue;
                }

                var rotationValuesAddress = IoUtil.ReadUInt32(
                    bank,
                    attemptOffset + 4);
                IoUtil.SplitAddress(rotationValuesAddress,
                                    out var rotationValuesBank,
                                    out var rotationValuesOffset);

                // Verifies the rotation values address has a valid bank.
                if (!RamBanks.IsValidBank(rotationValuesBank))
                {
                    continue;
                }

                // Verifies the rotation indices address has a valid bank.
                var rotationIndicesAddress = IoUtil.ReadUInt32(
                    bank,
                    attemptOffset + 8);
                IoUtil.SplitAddress(rotationIndicesAddress,
                                    out var rotationIndicesBank,
                                    out var rotationIndicesOffset);
                if (!RamBanks.IsValidBank(rotationIndicesBank))
                {
                    continue;
                }

                // Obtains the specified banks.
                var rotationValuesBuffer =
                    Asserts.Assert(RamBanks.GetBankByIndex(rotationValuesBank));
                var rotationIndicesBuffer =
                    Asserts.Assert(RamBanks.GetBankByIndex(rotationIndicesBank));

                // Offsets should be within bounds of the bank.
                var validRotationValuesOffset =
                    rotationValuesOffset < rotationValuesBuffer.Count;
                var validRotationIndicesOffset =
                    rotationIndicesOffset < rotationIndicesBuffer.Count;

                if (!validRotationValuesOffset || !validRotationIndicesOffset)
                {
                    continue;
                }

                // Angle count should be greater than 0.
                var angleCount =
                    (uint)((rotationIndicesOffset - rotationValuesOffset) / 2L);
                var validAngleCount = rotationIndicesOffset > rotationValuesOffset &&
                                      angleCount > 0L;
                if (!validAngleCount)
                {
                    continue;
                }

                // Should have zeroes present in two spots of the animation header.
                var hasZeroes =
                    IoUtil.ReadUInt16(bank, attemptOffset + 2) == 0 &&
                    IoUtil.ReadUInt16(bank, attemptOffset + 14) == 0;
                if (!hasZeroes)
                {
                    continue;
                }

                // All values of "tTrack" should be within the bounds of .Angles.
                var validTTracks = true;
                var limit        = IoUtil.ReadUInt16(bank, attemptOffset + 12);
                for (var i1 = 0; i1 < 3 + trackCount; i1++)
                {
                    var tTrack = IoUtil.ReadUInt16(
                        rotationIndicesBuffer,
                        (uint)(rotationIndicesOffset + 2 * i1));
                    if (tTrack < limit)
                    {
                        if (tTrack >= angleCount)
                        {
                            validTTracks = false;
                            goto badTTracks;
                        }
                    }
                    else if ((uint)(tTrack + frameCount) > angleCount)
                    {
                        validTTracks = false;
                        goto badTTracks;
                    }
                }

badTTracks:
                if (!validTTracks)
                {
                    continue;
                }

                var animation = new NormalAnimation {
                    FrameCount  = frameCount,
                    TrackOffset = rotationIndicesOffset,
                    AngleCount  = angleCount
                };

                animation.Angles = new ushort[animation.AngleCount];
                for (var i1 = 0; i1 < animation.AngleCount; ++i1)
                {
                    animation.Angles[i1] =
                        IoUtil.ReadUInt16(rotationValuesBuffer,
                                          rotationValuesOffset);
                    rotationValuesOffset = (uint)(rotationValuesOffset + 2L);
                }

                // Translation is at the start.
                var xList =
                    ReadFrames_(
                        IoUtil.ReadUInt16(rotationIndicesBuffer,
                                          animation.TrackOffset + 0),
                        limit,
                        animation);
                var yList =
                    ReadFrames_(
                        IoUtil.ReadUInt16(rotationIndicesBuffer,
                                          animation.TrackOffset + 2),
                        limit,
                        animation);
                var zList =
                    ReadFrames_(
                        IoUtil.ReadUInt16(rotationIndicesBuffer,
                                          animation.TrackOffset + 4),
                        limit,
                        animation);

                animation.Positions = new Vec3s[animation.FrameCount];
                for (var pi = 0; pi < animation.FrameCount; ++pi)
                {
                    animation.Positions[pi] = new Vec3s {
                        X = (short)xList[Math.Min(pi, xList.Length - 1)],
                        Y = (short)yList[Math.Min(pi, yList.Length - 1)],
                        Z = (short)zList[Math.Min(pi, zList.Length - 1)],
                    };
                }

                animation.Tracks = new NormalAnimationTrack[trackCount];

                var tTrackOffset = (int)(animation.TrackOffset + 6L);
                for (var i1 = 0; i1 < trackCount; ++i1)
                {
                    var track = animation.Tracks[i1] = new NormalAnimationTrack();

                    var tTrack =
                        IoUtil.ReadUInt16(rotationIndicesBuffer,
                                          (uint)tTrackOffset);
                    if (tTrack < limit)
                    {
                        // Constant (single value)
                        track.Type      = 0;
                        track.Frames    = new ushort[1];
                        track.Frames[0] = animation.Angles[tTrack];
                    }
                    else
                    {
                        // Keyframes
                        track.Type   = 1;
                        track.Frames = new ushort[animation.FrameCount];
                        for (var i2 = 0; i2 < animation.FrameCount; ++i2)
                        {
                            try {
                                track.Frames[i2] = animation.Angles[tTrack + i2];
                            } catch {
                                return(null);
                            }
                        }
                    }

                    tTrackOffset += 2;
                }

                animations.Add(animation);

                animationList.Items.Add("0x" + Conversion.Hex(i));
            }

            return(animations.Count > 0 ? animations : null);
        }