예제 #1
0
 /// <summary>
 /// Load a material from a file buffer, with labels.
 /// </summary>
 /// <param name="file">byte array representing file</param>
 /// <param name="address">address of this material within 'file' byte array.</param>
 /// <param name="labels"></param>
 public NJS_MATERIAL(byte[] file, int address, Dictionary <int, string> labels)
 {
     if (ByteConverter.BigEndian)
     {
         //"Reverse" is for the order used in SADX Gamecube
         if (ByteConverter.Reverse)
         {
             DiffuseColor  = Color.FromArgb(file[address + 3], file[address], file[address + 1], file[address + 2]);
             SpecularColor = Color.FromArgb(file[address + 7], file[address + 4], file[address + 5], file[address + 6]);
         }
         else
         {
             DiffuseColor  = Color.FromArgb(file[address], file[address + 1], file[address + 2], file[address + 3]);
             SpecularColor = Color.FromArgb(file[address + 4], file[address + 5], file[address + 6], file[address + 7]);
         }
     }
     else
     {
         DiffuseColor  = Color.FromArgb(file[address + 3], file[address + 2], file[address + 1], file[address]);
         SpecularColor = Color.FromArgb(file[address + 7], file[address + 6], file[address + 5], file[address + 4]);
     }
     Exponent  = ByteConverter.ToSingle(file, address + 8);
     TextureID = ByteConverter.ToInt32(file, address + 0xC);
     Flags     = ByteConverter.ToUInt32(file, address + 0x10);
 }
예제 #2
0
 public EventEntity(byte[] file, int address, uint imageBase, bool battle, Dictionary <string, NJS_OBJECT> models, List <NJS_MOTION> motions)
 {
     Model = Event.GetModel(file, address, imageBase, models);
     if (battle)
     {
         Motion      = motions[ByteConverter.ToInt32(file, address + 4)];
         ShapeMotion = motions[ByteConverter.ToInt32(file, address + 8)];
         GCModel     = Event.GetGCModel(file, address + 12, imageBase, models);
         ShadowModel = Event.GetModel(file, address + 16, imageBase, models);
         Position    = new Vertex(file, address + 24);
         Flags       = ByteConverter.ToUInt32(file, address + 36);
         Layer       = ByteConverter.ToUInt32(file, address + 40);
     }
     else
     {
         int ptr = file.GetPointer(address + 4, imageBase);
         if (ptr != 0)
         {
             Motion = new NJS_MOTION(file, ptr, imageBase, Model.CountAnimated());
         }
         ptr = file.GetPointer(address + 8, imageBase);
         if (ptr != 0)
         {
             ShapeMotion = new NJS_MOTION(file, ptr, imageBase, Model.CountMorph());
         }
         Position = new Vertex(file, address + 16);
         Flags    = ByteConverter.ToUInt32(file, address + 28);
     }
 }
예제 #3
0
        public GeoAnimData(byte[] file, int address, uint imageBase, LandTableFormat format, Dictionary <int, string> labels, Dictionary <int, Attach> attaches)
        {
            ModelFormat mfmt = 0;

            switch (format)
            {
            case LandTableFormat.SA1:
                mfmt = ModelFormat.Basic;
                break;

            case LandTableFormat.SADX:
                mfmt = ModelFormat.BasicDX;
                break;

            case LandTableFormat.SA2:
                mfmt = ModelFormat.Chunk;
                break;
            }
            AnimationFrame = ByteConverter.ToSingle(file, address);
            AnimationSpeed = ByteConverter.ToSingle(file, address + 4);
            MaxFrame       = ByteConverter.ToSingle(file, address + 8);
            Model          = new NJS_OBJECT(file, (int)(ByteConverter.ToUInt32(file, address + 0xC) - imageBase), imageBase, mfmt, labels, attaches);
            int actionaddr = (int)(ByteConverter.ToUInt32(file, address + 0x10) - imageBase);

            TexlistPointer = ByteConverter.ToUInt32(file, address + 0x14);
            NJS_ACTION action = new NJS_ACTION(file, actionaddr, imageBase, mfmt, labels, attaches);

            Animation = action.Animation;
        }
예제 #4
0
        public ChunkAttach(byte[] file, int address, uint imageBase, Dictionary <int, string> labels)
            : this()
        {
            if (labels.ContainsKey(address))
            {
                Name = labels[address];
            }
            else
            {
                Name = "attach_" + address.ToString("X8");
            }
            ChunkType ctype;
            int       tmpaddr = ByteConverter.ToInt32(file, address);

            if (tmpaddr != 0)
            {
                tmpaddr = (int)unchecked ((uint)tmpaddr - imageBase);
                Vertex  = new List <VertexChunk>();
                if (labels.ContainsKey(tmpaddr))
                {
                    VertexName = labels[tmpaddr];
                }
                else
                {
                    VertexName = "vertex_" + tmpaddr.ToString("X8");
                }
                ctype = (ChunkType)(ByteConverter.ToUInt32(file, tmpaddr) & 0xFF);
                while (ctype != ChunkType.End)
                {
                    VertexChunk chunk = new VertexChunk(file, tmpaddr);
                    Vertex.Add(chunk);
                    tmpaddr += (chunk.Size * 4) + 4;
                    ctype    = (ChunkType)(ByteConverter.ToUInt32(file, tmpaddr) & 0xFF);
                }
            }
            tmpaddr = ByteConverter.ToInt32(file, address + 4);
            if (tmpaddr != 0)
            {
                tmpaddr = (int)unchecked ((uint)tmpaddr - imageBase);
                Poly    = new List <PolyChunk>();
                if (labels.ContainsKey(tmpaddr))
                {
                    PolyName = labels[tmpaddr];
                }
                else
                {
                    PolyName = "poly_" + tmpaddr.ToString("X8");
                }
                PolyChunk chunk = PolyChunk.Load(file, tmpaddr);
                while (chunk.Type != ChunkType.End)
                {
                    //if (chunk.Type != ChunkType.Null)
                    Poly.Add(chunk);
                    tmpaddr += chunk.ByteSize;
                    chunk    = PolyChunk.Load(file, tmpaddr);
                }
            }
            Bounds = new BoundingSphere(file, address + 8);
        }
예제 #5
0
        // Scan for Actions in a specific range
        static int ScanActions(uint addr, uint nummdl, ModelFormat modelfmt)
        {
            int count = 0;

            ByteConverter.BigEndian = BigEndian;
            if (nummdl == 0)
            {
                return(0);
            }
            for (uint address = addr; address < datafile.Length - 8; address += 1)
            {
                CurrentAddress = address;
                if (CancelScan)
                {
                    break;
                }
                if (ByteConverter.ToUInt32(datafile, (int)address) != addr + ImageBase)
                {
                    continue;
                }
                uint motaddr = ByteConverter.ToUInt32(datafile, (int)address + 4);
                if (motaddr < ImageBase)
                {
                    continue;
                }
                try
                {
                    NJS_MOTION mot = new NJS_MOTION(datafile, (int)(motaddr - ImageBase), ImageBase, (int)nummdl, null, false);
                    if (mot.Models.Count == 0)
                    {
                        continue;
                    }
                    addresslist.Add(motaddr - ImageBase, "NJS_MOTION");
                    Console.WriteLine("\rMotion found for model {0} at address {1}", addr.ToString("X8"), (motaddr - ImageBase).ToString("X"));
                    string fileOutputPath = Path.Combine(OutputFolder, "actions", (motaddr - ImageBase).ToString("X8"));
                    if (SingleOutputFolder)
                    {
                        fileOutputPath = Path.Combine(OutputFolder, (motaddr - ImageBase).ToString("X8"));
                    }
                    mot.Save(fileOutputPath + ".saanim", NoMeta);
                    uint[] arr = new uint[2];
                    arr[0] = addr;
                    arr[1] = nummdl;
                    actionlist.Add(motaddr - ImageBase, arr);
                    AddAction(addr, motaddr - ImageBase);
                    address += 7;
                    count++;
                }
                catch (Exception)
                {
                    continue;
                }
            }
            return(count);
        }
예제 #6
0
        public static Color FromBytes(byte[] file, int address, ColorType type)
        {
            switch (type)
            {
            case ColorType.RGBA8888_32:
                if (address > file.Length - 4)
                {
                    return(Color.FromArgb(0, 0, 0, 0));
                }
                return(Color.FromArgb(file[address + 3], file[address], file[address + 1], file[address + 2]));

            case ColorType.ARGB8888_32:
                if (address > file.Length - 4)
                {
                    return(Color.FromArgb(0, 0, 0, 0));
                }
                // "Reverse" mode is for SADX Gamecube/SA2B/SA2PC where the color order is ABGR
                if (ByteConverter.BigEndian)
                {
                    if (ByteConverter.Reverse)
                    {
                        return(Color.FromArgb(file[address + 3], file[address], file[address + 1], file[address + 2]));
                    }
                    else
                    {
                        return(Color.FromArgb(file[address], file[address + 1], file[address + 2], file[address + 3]));
                    }
                }
                else if (ByteConverter.Reverse)
                {
                    return(Color.FromArgb(file[address], file[address + 3], file[address + 2], file[address + 1]));
                }
                else
                {
                    return(Color.FromArgb(file[address + 3], file[address + 2], file[address + 1], file[address]));
                }

            case ColorType.XRGB8888_32:
                return(Color.FromArgb(unchecked ((int)(ByteConverter.ToUInt32(file, address) | 0xFF000000u))));

            case ColorType.ARGB8888_16:
                return(Color.FromArgb((ByteConverter.ToUInt16(file, address + 2) << 16) | ByteConverter.ToUInt16(file, address)));

            case ColorType.XRGB8888_16:
                return(Color.FromArgb(unchecked ((int)((uint)((ByteConverter.ToUInt16(file, address + 2) << 16) | ByteConverter.ToUInt16(file, address)) | 0xFF000000u))));

            case ColorType.ARGB4444:
                ushort value = ByteConverter.ToUInt16(file, address);
                int    a     = value >> 12;
                int    r     = (value >> 8) & 0xF;
                int    g     = (value >> 4) & 0xF;
                int    b     = value & 0xF;
                return(Color.FromArgb(
                           a | (a << 4),
                           r | (r << 4),
                           g | (g << 4),
                           b | (b << 4)
                           ));

            case ColorType.RGB565:
                value = ByteConverter.ToUInt16(file, address);
                r     = value >> 11;
                g     = (value >> 5) & 0x3F;
                b     = value & 0x1F;
                return(Color.FromArgb(
                           r << 3 | r >> 2,
                               g << 2 | g >> 4,
                               b << 3 | b >> 2
                           ));
            }
            throw new ArgumentOutOfRangeException("type");
        }
예제 #7
0
        // Scan for Motions
        static void ScanMotions()
        {
            CurrentStep++;
            CurrentScanData = "Motions" + (ModelParts > 0 ? " with " + ModelParts.ToString() + " or more nodes" : "");
            Console.WriteLine("Step {0}: Scanning for motions with at least {1} model parts... ", CurrentStep, ModelParts);
            if (ShortRot)
            {
                Console.WriteLine("Using short rotations");
            }
            ByteConverter.BigEndian = BigEndian;
            if (!SingleOutputFolder)
            {
                Directory.CreateDirectory(Path.Combine(OutputFolder, "actions"));
            }
            for (uint address = StartAddress; address < EndAddress; address += 1)
            {
                if (CancelScan)
                {
                    break;
                }
                if (ConsoleMode && address % 1000 == 0)
                {
                    Console.Write("\r{0} ", address.ToString("X8"));
                }
                CurrentAddress = address;
                // Check for a valid MDATA pointer
                uint mdatap = ByteConverter.ToUInt32(datafile, (int)address);
                if (mdatap < ImageBase || mdatap >= datafile.Length - 12 + ImageBase || mdatap == 0)
                {
                    //Console.WriteLine("Mdatap {0} fail", mdatap.ToString("X8"));
                    continue;
                }
                uint frames = ByteConverter.ToUInt32(datafile, (int)address + 4);
                if (frames > 2000 || frames < 1)
                {
                    //Console.WriteLine("Frames {0} fail", frames.ToString());
                    continue;
                }
                AnimFlags animtype = (AnimFlags)ByteConverter.ToUInt16(datafile, (int)address + 8);
                if (animtype == 0)
                {
                    continue;
                }
                int mdata = 0;
                //Console.WriteLine("Flags: {0}", animtype.ToString());
                if (animtype.HasFlag(AnimFlags.Position))
                {
                    mdata++;
                }
                if (animtype.HasFlag(AnimFlags.Rotation))
                {
                    mdata++;
                }
                if (animtype.HasFlag(AnimFlags.Scale))
                {
                    mdata++;
                }
                if (animtype.HasFlag(AnimFlags.Vector))
                {
                    mdata++;
                }
                if (animtype.HasFlag(AnimFlags.Vertex))
                {
                    mdata++;
                }
                if (animtype.HasFlag(AnimFlags.Normal))
                {
                    mdata++;
                }
                if (animtype.HasFlag(AnimFlags.Color))
                {
                    continue;
                }
                if (animtype.HasFlag(AnimFlags.Intensity))
                {
                    continue;
                }
                if (animtype.HasFlag(AnimFlags.Target))
                {
                    continue;
                }
                if (animtype.HasFlag(AnimFlags.Spot))
                {
                    continue;
                }
                if (animtype.HasFlag(AnimFlags.Point))
                {
                    continue;
                }
                if (animtype.HasFlag(AnimFlags.Roll))
                {
                    continue;
                }
                int  mdatasize = 0;
                bool lost      = false;
                switch (mdata)
                {
                case 1:
                case 2:
                    mdatasize = 16;
                    break;

                case 3:
                    mdatasize = 24;
                    break;

                case 4:
                    mdatasize = 32;
                    break;

                case 5:
                    mdatasize = 40;
                    break;

                default:
                    lost = true;
                    break;
                }
                if (lost)
                {
                    continue;
                }
                // Check MKEY pointers
                int mdatas = 0;
                for (int u = 0; u < 255; u++)
                {
                    for (int m = 0; m < mdata; m++)
                    {
                        if (lost)
                        {
                            continue;
                        }
                        uint pointer = ByteConverter.ToUInt32(datafile, (int)(mdatap - ImageBase) + mdatasize * u + 4 * m);
                        if (pointer < ImageBase || pointer >= datafile.Length - 8 + ImageBase)
                        {
                            if (pointer != 0)
                            {
                                lost = true;
                                //Console.WriteLine("Mkey pointer {0} lost", pointer.ToString("X8"));
                            }
                        }
                        if (!lost)
                        {
                            // Read frame count
                            int framecount = ByteConverter.ToInt32(datafile, (int)(mdatap - ImageBase) + mdatasize * u + 4 * mdata + 4 * m);
                            if (framecount < 0 || framecount > 2000)
                            {
                                //Console.WriteLine("Framecount lost: {0}", framecount.ToString("X8"));
                                lost = true;
                            }
                            if (pointer == 0 && framecount != 0)
                            {
                                //Console.WriteLine("Framecount non zero");
                                lost = true;
                            }
                            //if (!lost) Console.WriteLine("Mdata size: {0}, MkeyP: {1}, Frames: {2}", mdatasize, pointer.ToString("X8"), framecount.ToString());
                        }
                    }
                    if (!lost)
                    {
                        mdatas++;
                        //Console.WriteLine("Mdata {0}, total {1}", u, mdatas);
                    }
                }
                if (mdatas > 0 && mdatas >= ModelParts)
                {
                    try
                    {
                        Console.WriteLine("\rAdding motion at {0}: {1} nodes", address.ToString("X8"), mdatas);
                        //Console.WriteLine("trying Address: {0}, MdataP: {1}, mdatas: {2}", address.ToString("X8"), mdatap.ToString("X8"), mdata);
                        NJS_MOTION mot = NJS_MOTION.ReadDirect(datafile, mdatas, (int)address, ImageBase, new Dictionary <int, Attach>(), ShortRot);
                        if (mot.ModelParts <= 0)
                        {
                            continue;
                        }
                        if (mot.Frames <= 0)
                        {
                            continue;
                        }
                        if (mot.Models.Count == 0)
                        {
                            continue;
                        }
                        string fileOutputPath = Path.Combine(OutputFolder, "actions", address.ToString("X8") + ".saanim");
                        if (SingleOutputFolder)
                        {
                            fileOutputPath = Path.Combine(OutputFolder, address.ToString("X8") + ".saanim");
                        }
                        mot.Save(fileOutputPath, NoMeta);
                        FoundMotions++;
                        addresslist.Add(address, "NJS_MOTION");
                        uint[] arr = new uint[2];
                        arr[0] = address;
                        arr[1] = (uint)mot.ModelParts;
                        actionlist.Add(address, arr);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("\rError adding motion at {0}: {1}", address.ToString("X8"), ex.Message);
                    }
                }
            }
            Console.WriteLine("\rFound {0} motions", FoundMotions);
        }
예제 #8
0
        public ModelFile(byte[] file, string filename = null)
        {
            int  tmpaddr;
            bool be = ByteConverter.BigEndian;

            ByteConverter.BigEndian = false;
            ulong magic   = ByteConverter.ToUInt64(file, 0) & FormatMask;
            byte  version = file[7];

            if (version > CurrentVersion)
            {
                throw new FormatException("Not a valid SA1MDL/SA2MDL file.");
            }
            Metadata = new Dictionary <uint, byte[]>();
            Dictionary <int, string> labels   = new Dictionary <int, string>();
            Dictionary <int, Attach> attaches = new Dictionary <int, Attach>();

            if (version < 2)
            {
                if (version == 1)
                {
                    tmpaddr = ByteConverter.ToInt32(file, 0x14);
                    if (tmpaddr != 0)
                    {
                        int addr = ByteConverter.ToInt32(file, tmpaddr);
                        while (addr != -1)
                        {
                            labels.Add(addr, file.GetCString(ByteConverter.ToInt32(file, tmpaddr + 4)));
                            tmpaddr += 8;
                            addr     = ByteConverter.ToInt32(file, tmpaddr);
                        }
                    }
                }
                switch (magic)
                {
                case SA1MDL:
                    Format = ModelFormat.Basic;
                    break;

                case SA2MDL:
                    Format = ModelFormat.Chunk;
                    break;

                default:
                    throw new FormatException("Not a valid SA1MDL/SA2MDL file.");
                }
                Model = new NJS_OBJECT(file, ByteConverter.ToInt32(file, 8), 0, Format, labels, attaches);
                if (filename != null)
                {
                    tmpaddr = ByteConverter.ToInt32(file, 0xC);
                    if (tmpaddr != 0)
                    {
                        List <string> animfiles = new List <string>();
                        int           addr      = ByteConverter.ToInt32(file, tmpaddr);
                        while (addr != -1)
                        {
                            animfiles.Add(file.GetCString(addr));
                            tmpaddr += 4;
                            addr     = ByteConverter.ToInt32(file, tmpaddr);
                        }
                        animationFiles = animfiles.ToArray();
                    }
                    else
                    {
                        animationFiles = new string[0];
                    }
                    string            path  = Path.GetDirectoryName(filename);
                    List <NJS_MOTION> anims = new List <NJS_MOTION>();
                    try
                    {
                        foreach (string item in animationFiles)
                        {
                            anims.Add(NJS_MOTION.Load(Path.Combine(path, item), Model.CountAnimated()));
                        }
                    }
                    catch
                    {
                        anims.Clear();
                    }
                    Animations = anims.AsReadOnly();
                }
            }
            else
            {
                animationFiles = new string[0];
                tmpaddr        = ByteConverter.ToInt32(file, 0xC);
                if (tmpaddr != 0)
                {
                    bool finished = false;
                    while (!finished)
                    {
                        ChunkTypes type      = (ChunkTypes)ByteConverter.ToUInt32(file, tmpaddr);
                        int        chunksz   = ByteConverter.ToInt32(file, tmpaddr + 4);
                        int        nextchunk = tmpaddr + 8 + chunksz;
                        tmpaddr += 8;
                        if (version == 2)
                        {
                            switch (type)
                            {
                            case ChunkTypes.Label:
                                while (ByteConverter.ToInt64(file, tmpaddr) != -1)
                                {
                                    labels.Add(ByteConverter.ToInt32(file, tmpaddr), file.GetCString(ByteConverter.ToInt32(file, tmpaddr + 4)));
                                    tmpaddr += 8;
                                }
                                break;

                            case ChunkTypes.Animation:
                                List <string> animfiles = new List <string>();
                                while (ByteConverter.ToInt32(file, tmpaddr) != -1)
                                {
                                    animfiles.Add(file.GetCString(ByteConverter.ToInt32(file, tmpaddr)));
                                    tmpaddr += 4;
                                }
                                animationFiles = animfiles.ToArray();
                                break;

                            case ChunkTypes.Morph:
                                break;

                            case ChunkTypes.Author:
                                Author = file.GetCString(tmpaddr);
                                break;

                            case ChunkTypes.Tool:
                                break;

                            case ChunkTypes.Description:
                                Description = file.GetCString(tmpaddr);
                                break;

                            case ChunkTypes.Texture:
                                break;

                            case ChunkTypes.End:
                                finished = true;
                                break;
                            }
                        }
                        else
                        {
                            byte[] chunk = new byte[chunksz];
                            Array.Copy(file, tmpaddr, chunk, 0, chunksz);
                            int chunkaddr = 0;
                            switch (type)
                            {
                            case ChunkTypes.Label:
                                while (ByteConverter.ToInt64(chunk, chunkaddr) != -1)
                                {
                                    labels.Add(ByteConverter.ToInt32(chunk, chunkaddr),
                                               chunk.GetCString(ByteConverter.ToInt32(chunk, chunkaddr + 4)));
                                    chunkaddr += 8;
                                }
                                break;

                            case ChunkTypes.Animation:
                                List <string> animchunks = new List <string>();
                                while (ByteConverter.ToInt32(chunk, chunkaddr) != -1)
                                {
                                    animchunks.Add(chunk.GetCString(ByteConverter.ToInt32(chunk, chunkaddr)));
                                    chunkaddr += 4;
                                }
                                animationFiles = animchunks.ToArray();
                                break;

                            case ChunkTypes.Morph:
                                break;

                            case ChunkTypes.Author:
                                Author = chunk.GetCString(chunkaddr);
                                break;

                            case ChunkTypes.Tool:
                                break;

                            case ChunkTypes.Description:
                                Description = chunk.GetCString(chunkaddr);
                                break;

                            case ChunkTypes.End:
                                finished = true;
                                break;

                            default:
                                Metadata.Add((uint)type, chunk);
                                break;
                            }
                        }
                        tmpaddr = nextchunk;
                    }
                }
                switch (magic)
                {
                case SA1MDL:
                    Format = ModelFormat.Basic;
                    break;

                case SA2MDL:
                    Format = ModelFormat.Chunk;
                    break;

                case SA2BMDL:
                    Format = ModelFormat.GC;
                    break;

                case XJMDL:
                    Format = ModelFormat.XJ;
                    break;

                default:
                    throw new FormatException("Not a valid SA1MDL/SA2MDL file.");
                }
                Model = new NJS_OBJECT(file, ByteConverter.ToInt32(file, 8), 0, Format, labels, attaches);
                if (filename != null)
                {
                    string path = Path.GetDirectoryName(filename);
                    if (File.Exists(Path.GetFileNameWithoutExtension(filename) + ".action"))
                    {
                        using (TextReader tr = File.OpenText(Path.GetFileNameWithoutExtension(filename) + ".action"))
                        {
                            List <string> animlist = new List <string>();
                            int           count    = File.ReadLines(Path.GetFileNameWithoutExtension(filename) + ".action").Count();
                            for (int i = 0; i < count; i++)
                            {
                                string line = tr.ReadLine();
                                if (File.Exists(Path.Combine(path, line)))
                                {
                                    animlist.Add(line);
                                }
                            }
                            animationFiles = animlist.ToArray();
                        }
                    }
                    List <NJS_MOTION> anims = new List <NJS_MOTION>();
                    try
                    {
                        foreach (string item in animationFiles)
                        {
                            if (Path.GetExtension(item).ToLowerInvariant() == ".json")
                            {
                                JsonSerializer js = new JsonSerializer()
                                {
                                    Culture = System.Globalization.CultureInfo.InvariantCulture
                                };
                                using (TextReader tr = File.OpenText(Path.Combine(path, item)))
                                {
                                    using (JsonTextReader jtr = new JsonTextReader(tr))
                                        anims.Add(js.Deserialize <NJS_MOTION>(jtr));
                                }
                            }
                            else
                            {
                                anims.Add(NJS_MOTION.Load(Path.Combine(path, item), Model.CountAnimated()));
                            }
                        }
                    }
                    catch
                    {
                        anims.Clear();
                    }
                    Animations = anims.AsReadOnly();
                }
            }
            ByteConverter.BigEndian = be;
        }
예제 #9
0
        public LandTable(byte[] file, int address, uint imageBase, LandTableFormat format, Dictionary <int, string> labels)
        {
            Format = format;
            if (labels.ContainsKey(address))
            {
                Name = labels[address];
            }
            else
            {
                Name = "landtable_" + address.ToString("X8");
            }
            short colcnt = ByteConverter.ToInt16(file, address);
            Dictionary <int, Attach> attaches = new Dictionary <int, Attach>();

            switch (format)
            {
            case LandTableFormat.SA1:
            case LandTableFormat.SADX:
                short anicnt = ByteConverter.ToInt16(file, address + 2);
                Attributes  = (SA1LandtableAttributes)ByteConverter.ToInt16(file, address + 4);
                Flags       = ByteConverter.ToInt16(file, address + 6);
                FarClipping = ByteConverter.ToSingle(file, address + 8);
                COL         = new List <COL>();
                int tmpaddr = ByteConverter.ToInt32(file, address + 0xC);
                if (tmpaddr != 0)
                {
                    tmpaddr = (int)unchecked ((uint)tmpaddr - imageBase);
                    if (labels.ContainsKey(tmpaddr))
                    {
                        COLName = labels[tmpaddr];
                    }
                    else
                    {
                        COLName = "collist_" + tmpaddr.ToString("X8");
                    }
                    for (int i = 0; i < colcnt; i++)
                    {
                        COL.Add(new COL(file, tmpaddr, imageBase, format, labels, attaches));
                        tmpaddr += SAModel.COL.Size(format);
                    }
                }
                else
                {
                    COLName = "collist_" + Extensions.GenerateIdentifier();
                }
                Anim    = new List <GeoAnimData>();
                tmpaddr = ByteConverter.ToInt32(file, address + 0x10);
                if (tmpaddr != 0)
                {
                    tmpaddr = (int)unchecked ((uint)tmpaddr - imageBase);
                    if (labels.ContainsKey(tmpaddr))
                    {
                        AnimName = labels[tmpaddr];
                    }
                    else
                    {
                        AnimName = "animlist_" + tmpaddr.ToString("X8");
                    }
                    for (int i = 0; i < anicnt; i++)
                    {
                        Anim.Add(new GeoAnimData(file, tmpaddr, imageBase, format, labels, attaches));
                        tmpaddr += GeoAnimData.Size;
                    }
                }
                else
                {
                    AnimName = "animlist_" + Extensions.GenerateIdentifier();
                }
                tmpaddr = ByteConverter.ToInt32(file, address + 0x14);
                if (tmpaddr != 0)
                {
                    tmpaddr         = (int)unchecked ((uint)tmpaddr - imageBase);
                    TextureFileName = file.GetCString(tmpaddr, Encoding.ASCII);
                }
                TextureList        = ByteConverter.ToUInt32(file, address + 0x18);
                BinaryFilename     = ByteConverter.ToInt32(file, address + 0x1C);
                BinaryLoadFunction = ByteConverter.ToInt32(file, address + 0x20);
                break;

            case LandTableFormat.SA2:
            case LandTableFormat.SA2B:
                short cnkcnt = ByteConverter.ToInt16(file, address + 2);
                FarClipping = ByteConverter.ToSingle(file, address + 0xC);
                COL         = new List <COL>();
                tmpaddr     = ByteConverter.ToInt32(file, address + 0x10);
                if (tmpaddr != 0)
                {
                    tmpaddr = (int)unchecked ((uint)tmpaddr - imageBase);
                    if (labels.ContainsKey(tmpaddr))
                    {
                        COLName = labels[tmpaddr];
                    }
                    else
                    {
                        COLName = "collist_" + tmpaddr.ToString("X8");
                    }
                    for (int i = 0; i < colcnt; i++)
                    {
                        COL.Add(new COL(file, tmpaddr, imageBase, format, labels, cnkcnt < 0 ? null : (bool?)(i >= cnkcnt), attaches));
                        tmpaddr += SAModel.COL.Size(format);
                    }
                }
                else
                {
                    COLName = "collist_" + Extensions.GenerateIdentifier();
                }
                Anim     = new List <GeoAnimData>();
                AnimName = "animlist_" + Extensions.GenerateIdentifier();
                tmpaddr  = ByteConverter.ToInt32(file, address + 0x18);
                if (tmpaddr != 0)
                {
                    tmpaddr         = (int)unchecked ((uint)tmpaddr - imageBase);
                    TextureFileName = file.GetCString(tmpaddr, Encoding.ASCII);
                }
                TextureList = ByteConverter.ToUInt32(file, address + 0x1C);
                break;
            }
            Metadata = new Dictionary <uint, byte[]>();
        }
예제 #10
0
        public static LandTable LoadFromFile(string filename)
        {
            bool be = ByteConverter.BigEndian;

            ByteConverter.BigEndian = false;
            byte[] file    = File.ReadAllBytes(filename);
            ulong  magic   = ByteConverter.ToUInt64(file, 0) & FormatMask;
            byte   version = file[7];

            if (version > CurrentVersion)
            {
                throw new FormatException("Not a valid SA1LVL/SA2LVL file.");
            }
            Dictionary <int, string> labels = new Dictionary <int, string>();
            string author = null, description = null;
            Dictionary <uint, byte[]> meta = new Dictionary <uint, byte[]>();

            if (version < 2)
            {
                if (version == 1)
                {
                    int tmpaddr = ByteConverter.ToInt32(file, 0xC);
                    if (tmpaddr != 0)
                    {
                        int addr = ByteConverter.ToInt32(file, tmpaddr);
                        while (addr != -1)
                        {
                            labels.Add(addr, file.GetCString(ByteConverter.ToInt32(file, tmpaddr + 4)));
                            tmpaddr += 8;
                            addr     = ByteConverter.ToInt32(file, tmpaddr);
                        }
                    }
                }
            }
            else
            {
                int tmpaddr = ByteConverter.ToInt32(file, 0xC);
                if (tmpaddr != 0)
                {
                    bool finished = false;
                    while (!finished)
                    {
                        ChunkTypes type      = (ChunkTypes)ByteConverter.ToUInt32(file, tmpaddr);
                        int        chunksz   = ByteConverter.ToInt32(file, tmpaddr + 4);
                        int        nextchunk = tmpaddr + 8 + chunksz;
                        tmpaddr += 8;
                        if (version == 2)
                        {
                            switch (type)
                            {
                            case ChunkTypes.Label:
                                while (ByteConverter.ToInt64(file, tmpaddr) != -1)
                                {
                                    labels.Add(ByteConverter.ToInt32(file, tmpaddr), file.GetCString(ByteConverter.ToInt32(file, tmpaddr + 4)));
                                    tmpaddr += 8;
                                }
                                break;

                            case ChunkTypes.Author:
                                author = file.GetCString(tmpaddr);
                                break;

                            case ChunkTypes.Tool:
                                break;

                            case ChunkTypes.Description:
                                description = file.GetCString(tmpaddr);
                                break;

                            case ChunkTypes.End:
                                finished = true;
                                break;
                            }
                        }
                        else
                        {
                            byte[] chunk = new byte[chunksz];
                            Array.Copy(file, tmpaddr, chunk, 0, chunksz);
                            int chunkaddr = 0;
                            switch (type)
                            {
                            case ChunkTypes.Label:
                                while (ByteConverter.ToInt64(chunk, chunkaddr) != -1)
                                {
                                    labels.Add(ByteConverter.ToInt32(chunk, chunkaddr),
                                               chunk.GetCString(ByteConverter.ToInt32(chunk, chunkaddr + 4)));
                                    chunkaddr += 8;
                                }
                                break;

                            case ChunkTypes.Author:
                                author = chunk.GetCString(0);
                                break;

                            case ChunkTypes.Tool:
                                break;

                            case ChunkTypes.Description:
                                description = chunk.GetCString(0);
                                break;

                            case ChunkTypes.End:
                                finished = true;
                                break;

                            default:
                                meta.Add((uint)type, chunk);
                                break;
                            }
                        }
                        tmpaddr = nextchunk;
                    }
                }
            }
            if (magic == SA1LVL)
            {
                LandTable table = new LandTable(file, ByteConverter.ToInt32(file, 8), 0, LandTableFormat.SA1, labels)
                {
                    Author      = author,
                    Description = description,
                    Metadata    = meta
                };
                ByteConverter.BigEndian = be;
                return(table);
            }
            if (magic == SA2LVL)
            {
                LandTable table = new LandTable(file, ByteConverter.ToInt32(file, 8), 0, LandTableFormat.SA2, labels)
                {
                    Author      = author,
                    Description = description,
                    Metadata    = meta
                };
                ByteConverter.BigEndian = be;
                return(table);
            }
            if (magic == SA2BLVL)
            {
                LandTable table = new LandTable(file, ByteConverter.ToInt32(file, 8), 0, LandTableFormat.SA2B, labels)
                {
                    Author      = author,
                    Description = description,
                    Metadata    = meta
                };
                ByteConverter.BigEndian = be;
                return(table);
            }
            ByteConverter.BigEndian = be;
            throw new FormatException("Not a valid SA1LVL/SA2LVL file.");
        }
예제 #11
0
파일: COL.cs 프로젝트: Shadowth117/sa_tools
        public COL(byte[] file, int address, uint imageBase, LandTableFormat format, Dictionary <int, string> labels, bool?forceBasic, Dictionary <int, Attach> attaches)
        {
            Bounds = new BoundingSphere(file, address);
            ModelFormat mfmt = 0;

            switch (format)
            {
            case LandTableFormat.SA1:
                mfmt = ModelFormat.Basic;
                break;

            case LandTableFormat.SADX:
                mfmt = ModelFormat.BasicDX;
                break;

            case LandTableFormat.SA2:
                if (forceBasic.HasValue && forceBasic.Value)
                {
                    mfmt = ModelFormat.Basic;
                }
                else
                {
                    mfmt = ModelFormat.Chunk;
                }
                break;

            case LandTableFormat.SA2B:
                if (forceBasic.HasValue && forceBasic.Value)
                {
                    mfmt = ModelFormat.Basic;
                }
                else
                {
                    mfmt = ModelFormat.GC;
                }
                break;
            }
            switch (format)
            {
            case LandTableFormat.SA1:
            case LandTableFormat.SADX:
                WidthY = ByteConverter.ToSingle(file, address + 0x10);
                WidthZ = ByteConverter.ToSingle(file, address + 0x14);
                uint tmpaddr = ByteConverter.ToUInt32(file, address + 0x18) - imageBase;
                Model     = new NJS_OBJECT(file, (int)tmpaddr, imageBase, mfmt, labels, attaches);
                BlockBits = ByteConverter.ToUInt32(file, address + 0x1C);
                Flags     = ByteConverter.ToInt32(file, address + 0x20);
                break;

            case LandTableFormat.SA2:
            case LandTableFormat.SA2B:
                Flags = ByteConverter.ToInt32(file, address + 0x1C);
                if (!forceBasic.HasValue && Flags >= 0)
                {
                    mfmt = ModelFormat.Basic;
                }
                tmpaddr   = ByteConverter.ToUInt32(file, address + 0x10) - imageBase;
                Model     = new NJS_OBJECT(file, (int)tmpaddr, imageBase, mfmt, labels, attaches);
                WidthZ    = ByteConverter.ToInt32(file, address + 0x14);
                BlockBits = ByteConverter.ToUInt32(file, address + 0x18);
                break;
            }
        }
예제 #12
0
        public BasicAttach(byte[] file, int address, uint imageBase, bool DX, Dictionary <int, string> labels)
            : this()
        {
            if (labels.ContainsKey(address))
            {
                Name = labels[address];
            }
            else
            {
                Name = "attach_" + address.ToString("X8");
            }
            Vertex = new Vertex[ByteConverter.ToInt32(file, address + 8)];
            Normal = new Vertex[Vertex.Length];
            int tmpaddr = (int)(ByteConverter.ToUInt32(file, address) - imageBase);

            if (labels.ContainsKey(tmpaddr))
            {
                VertexName = labels[tmpaddr];
            }
            else
            {
                VertexName = "vertex_" + tmpaddr.ToString("X8");
            }
            for (int i = 0; i < Vertex.Length; i++)
            {
                Vertex[i] = new Vertex(file, tmpaddr);
                tmpaddr  += SAModel.Vertex.Size;
            }
            tmpaddr = ByteConverter.ToInt32(file, address + 4);
            if (tmpaddr != 0)
            {
                tmpaddr = (int)((uint)tmpaddr - imageBase);
                if (labels.ContainsKey(tmpaddr))
                {
                    NormalName = labels[tmpaddr];
                }
                else
                {
                    NormalName = "normal_" + tmpaddr.ToString("X8");
                }
                for (int i = 0; i < Vertex.Length; i++)
                {
                    Normal[i] = new Vertex(file, tmpaddr);
                    tmpaddr  += SAModel.Vertex.Size;
                }
            }
            else
            {
                for (int i = 0; i < Vertex.Length; i++)
                {
                    Normal[i] = new Vertex(0, 1, 0);
                }
            }
            int maxmat  = -1;
            int meshcnt = ByteConverter.ToInt16(file, address + 0x14);

            tmpaddr = ByteConverter.ToInt32(file, address + 0xC);
            if (tmpaddr != 0)
            {
                tmpaddr = (int)unchecked ((uint)tmpaddr - imageBase);
                if (labels.ContainsKey(tmpaddr))
                {
                    MeshName = labels[tmpaddr];
                }
                else
                {
                    MeshName = "meshlist_" + tmpaddr.ToString("X8");
                }
                for (int i = 0; i < meshcnt; i++)
                {
                    Mesh.Add(new NJS_MESHSET(file, tmpaddr, imageBase, labels));
                    maxmat   = Math.Max(maxmat, Mesh[i].MaterialID);
                    tmpaddr += NJS_MESHSET.Size(DX);
                }
            }
            // fixes case where model declares material array as shorter than it really is
            int matcnt = Math.Max(ByteConverter.ToInt16(file, address + 0x16), maxmat + 1);

            tmpaddr = ByteConverter.ToInt32(file, address + 0x10);
            if (tmpaddr != 0)
            {
                tmpaddr = (int)unchecked ((uint)tmpaddr - imageBase);
                if (labels.ContainsKey(tmpaddr))
                {
                    MaterialName = labels[tmpaddr];
                }
                else
                {
                    MaterialName = "matlist_" + tmpaddr.ToString("X8");
                }
                for (int i = 0; i < matcnt; i++)
                {
                    Material.Add(new NJS_MATERIAL(file, tmpaddr, labels));
                    tmpaddr += NJS_MATERIAL.Size;
                }
            }
            Bounds = new BoundingSphere(file, address + 0x18);
        }
예제 #13
0
        public VertexChunk(byte[] file, int address)
            : this()
        {
            Header1  = ByteConverter.ToUInt32(file, address);
            Header2  = ByteConverter.ToUInt32(file, address + 4);
            address += 8;
            for (int i = 0; i < GetVertCount(); i++)
            {
                switch (Type)
                {
                case ChunkType.Vertex_VertexSH:
                    Vertices.Add(new Vertex(file, address));
                    address += Vertex.Size + sizeof(float);
                    break;

                case ChunkType.Vertex_VertexNormalSH:
                    Vertices.Add(new Vertex(file, address));
                    address += Vertex.Size + sizeof(float);
                    Normals.Add(new Vertex(file, address));
                    address += Vertex.Size + sizeof(float);
                    break;

                case ChunkType.Vertex_Vertex:
                    Vertices.Add(new Vertex(file, address));
                    address += Vertex.Size;
                    break;

                case ChunkType.Vertex_VertexDiffuse8:
                    Vertices.Add(new Vertex(file, address));
                    address += Vertex.Size;
                    Diffuse.Add(VColor.FromBytes(file, address, ColorType.ARGB8888_32));
                    address += VColor.Size(ColorType.ARGB8888_32);
                    break;

                case ChunkType.Vertex_VertexUserFlags:
                    Vertices.Add(new Vertex(file, address));
                    address += Vertex.Size;
                    UserFlags.Add(ByteConverter.ToUInt32(file, address));
                    address += sizeof(uint);
                    break;

                case ChunkType.Vertex_VertexNinjaFlags:
                    Vertices.Add(new Vertex(file, address));
                    address += Vertex.Size;
                    NinjaFlags.Add(ByteConverter.ToUInt32(file, address));
                    address += sizeof(uint);
                    break;

                case ChunkType.Vertex_VertexDiffuseSpecular5:
                    Vertices.Add(new Vertex(file, address));
                    address += Vertex.Size;
                    uint tmpcolor = ByteConverter.ToUInt32(file, address);
                    address += sizeof(uint);
                    Diffuse.Add(VColor.FromBytes(ByteConverter.GetBytes((ushort)(tmpcolor & 0xFFFF)), 0, ColorType.RGB565));
                    Specular.Add(VColor.FromBytes(ByteConverter.GetBytes((ushort)(tmpcolor >> 16)), 0, ColorType.RGB565));
                    break;

                case ChunkType.Vertex_VertexDiffuseSpecular4:
                    Vertices.Add(new Vertex(file, address));
                    address += Vertex.Size;
                    tmpcolor = ByteConverter.ToUInt32(file, address);
                    address += sizeof(uint);
                    Diffuse.Add(VColor.FromBytes(ByteConverter.GetBytes((ushort)(tmpcolor & 0xFFFF)), 0, ColorType.ARGB4444));
                    Specular.Add(VColor.FromBytes(ByteConverter.GetBytes((ushort)(tmpcolor >> 16)), 0, ColorType.RGB565));
                    break;

                case ChunkType.Vertex_VertexNormal:
                    Vertices.Add(new Vertex(file, address));
                    address += Vertex.Size;
                    Normals.Add(new Vertex(file, address));
                    address += Vertex.Size;
                    break;

                case ChunkType.Vertex_VertexNormalDiffuse8:
                    Vertices.Add(new Vertex(file, address));
                    address += Vertex.Size;
                    Normals.Add(new Vertex(file, address));
                    address += Vertex.Size;
                    Diffuse.Add(VColor.FromBytes(file, address, ColorType.ARGB8888_32));
                    address += VColor.Size(ColorType.ARGB8888_32);
                    break;

                case ChunkType.Vertex_VertexNormalUserFlags:
                    Vertices.Add(new Vertex(file, address));
                    address += Vertex.Size;
                    Normals.Add(new Vertex(file, address));
                    address += Vertex.Size;
                    UserFlags.Add(ByteConverter.ToUInt32(file, address));
                    address += sizeof(uint);
                    break;

                case ChunkType.Vertex_VertexNormalNinjaFlags:
                    Vertices.Add(new Vertex(file, address));
                    address += Vertex.Size;
                    Normals.Add(new Vertex(file, address));
                    address += Vertex.Size;
                    NinjaFlags.Add(ByteConverter.ToUInt32(file, address));
                    address += sizeof(uint);
                    break;

                case ChunkType.Vertex_VertexNormalDiffuseSpecular5:
                    Vertices.Add(new Vertex(file, address));
                    address += Vertex.Size;
                    Normals.Add(new Vertex(file, address));
                    address += Vertex.Size;
                    tmpcolor = ByteConverter.ToUInt32(file, address);
                    address += sizeof(uint);
                    Diffuse.Add(VColor.FromBytes(ByteConverter.GetBytes((ushort)(tmpcolor & 0xFFFF)), 0, ColorType.RGB565));
                    Specular.Add(VColor.FromBytes(ByteConverter.GetBytes((ushort)(tmpcolor >> 16)), 0, ColorType.RGB565));
                    break;

                case ChunkType.Vertex_VertexNormalDiffuseSpecular4:
                    Vertices.Add(new Vertex(file, address));
                    address += Vertex.Size;
                    Normals.Add(new Vertex(file, address));
                    address += Vertex.Size;
                    tmpcolor = ByteConverter.ToUInt32(file, address);
                    address += sizeof(uint);
                    Diffuse.Add(VColor.FromBytes(ByteConverter.GetBytes((ushort)(tmpcolor & 0xFFFF)), 0, ColorType.ARGB4444));
                    Specular.Add(VColor.FromBytes(ByteConverter.GetBytes((ushort)(tmpcolor >> 16)), 0, ColorType.RGB565));
                    break;

                default:
                    throw new NotSupportedException("Unsupported chunk type " + Type + " at " + address.ToString("X8") + ".");
                }
            }
        }
예제 #14
0
        public NJS_MESHSET(byte[] file, int address, uint imageBase, Dictionary <int, string> labels)
        {
            MaterialID  = ByteConverter.ToUInt16(file, address);
            PolyType    = (Basic_PolyType)(MaterialID >> 0xE);
            MaterialID &= 0x3FFF;
            Poly[] polys   = new Poly[ByteConverter.ToInt16(file, address + 2)];
            int    tmpaddr = (int)(ByteConverter.ToUInt32(file, address + 4) - imageBase);

            if (labels.ContainsKey(tmpaddr))
            {
                PolyName = labels[tmpaddr];
            }
            else
            {
                PolyName = "poly_" + tmpaddr.ToString("X8");
            }
            int striptotal = 0;

            for (int i = 0; i < polys.Length; i++)
            {
                polys[i]    = SAModel.Poly.CreatePoly(PolyType, file, tmpaddr);
                striptotal += polys[i].Indexes.Length;
                tmpaddr    += polys[i].Size;
            }
            Poly    = new ReadOnlyCollection <Poly>(polys);
            PAttr   = ByteConverter.ToInt32(file, address + 8);
            tmpaddr = ByteConverter.ToInt32(file, address + 0xC);
            if (tmpaddr != 0)
            {
                tmpaddr = (int)unchecked ((uint)tmpaddr - imageBase);
                if (labels.ContainsKey(tmpaddr))
                {
                    PolyNormalName = labels[tmpaddr];
                }
                else
                {
                    PolyNormalName = "polynormal_" + tmpaddr.ToString("X8");
                }
                PolyNormal = new Vertex[polys.Length];
                for (int i = 0; i < polys.Length; i++)
                {
                    PolyNormal[i] = new Vertex(file, tmpaddr);
                    tmpaddr      += Vertex.Size;
                }
            }
            else
            {
                PolyNormalName = "polynormal_" + Extensions.GenerateIdentifier();
            }
            tmpaddr = ByteConverter.ToInt32(file, address + 0x10);
            if (tmpaddr != 0)
            {
                tmpaddr = (int)unchecked ((uint)tmpaddr - imageBase);
                if (labels.ContainsKey(tmpaddr))
                {
                    VColorName = labels[tmpaddr];
                }
                else
                {
                    VColorName = "vcolor_" + tmpaddr.ToString("X8");
                }
                VColor = new Color[striptotal];
                for (int i = 0; i < striptotal; i++)
                {
                    VColor[i] = SAModel.VColor.FromBytes(file, tmpaddr);
                    tmpaddr  += SAModel.VColor.Size(ColorType.ARGB8888_32);
                }
            }
            else
            {
                VColorName = "vcolor_" + Extensions.GenerateIdentifier();
            }
            tmpaddr = ByteConverter.ToInt32(file, address + 0x14);
            if (tmpaddr != 0)
            {
                tmpaddr = (int)unchecked ((uint)tmpaddr - imageBase);
                if (labels.ContainsKey(tmpaddr))
                {
                    UVName = labels[tmpaddr];
                }
                else
                {
                    UVName = "uv_" + tmpaddr.ToString("X8");
                }
                UV = new UV[striptotal];
                for (int i = 0; i < striptotal; i++)
                {
                    UV[i]    = new UV(file, tmpaddr);
                    tmpaddr += SAModel.UV.Size;
                }
            }
            else
            {
                UVName = "uv_" + Extensions.GenerateIdentifier();
            }
        }