Example #1
0
        public NJS_OBJECT Clone()
        {
            NJS_OBJECT result = (NJS_OBJECT)MemberwiseClone();

            if (Attach != null)
            {
                result.Attach = Attach.Clone();
            }
            result.Position = Position.Clone();
            result.Rotation = Rotation.Clone();
            result.Scale    = Scale.Clone();
            result.children = new List <NJS_OBJECT>(children.Count);
            result.Children = new ReadOnlyCollection <NJS_OBJECT>(result.children);
            if (children.Count > 0)
            {
                NJS_OBJECT child = children[0].Clone();
                while (child != null)
                {
                    result.children.Add(child);
                    child = child.Sibling;
                }
            }
            if (Sibling != null)
            {
                result.Sibling = Sibling.Clone();
            }
            return(result);
        }
Example #2
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;
            }
            Unknown1  = ByteConverter.ToInt32(file, address);
            Unknown2  = ByteConverter.ToSingle(file, address + 4);
            Unknown3  = ByteConverter.ToSingle(file, address + 8);
            Model     = new NJS_OBJECT(file, (int)(ByteConverter.ToUInt32(file, address + 0xC) - imageBase), imageBase, mfmt, labels, attaches);
            Animation = NJS_MOTION.ReadHeader(file, (int)(ByteConverter.ToUInt32(file, address + 0x10) - imageBase), imageBase, mfmt, labels, attaches);
            Unknown4  = ByteConverter.ToInt32(file, address + 0x14);
        }
Example #3
0
        private NJS_OBJECT(byte[] file, int address, uint imageBase, ModelFormat format, NJS_OBJECT parent, Dictionary <int, string> labels, Dictionary <int, Attach> attaches)
        {
            if (labels.ContainsKey(address))
            {
                Name = labels[address];
            }
            else
            {
                Name = "object_" + address.ToString("X8");
            }
            ObjectFlags flags = (ObjectFlags)ByteConverter.ToInt32(file, address);

            RotateZYX = (flags & ObjectFlags.RotateZYX) == ObjectFlags.RotateZYX;
            Animate   = (flags & ObjectFlags.NoAnimate) == 0;
            Morph     = (flags & ObjectFlags.NoMorph) == 0;
            int tmpaddr = ByteConverter.ToInt32(file, address + 4);

            if (tmpaddr != 0)
            {
                tmpaddr = (int)unchecked ((uint)tmpaddr - imageBase);
                if (attaches != null && attaches.ContainsKey(tmpaddr))
                {
                    Attach = attaches[tmpaddr];
                }
                else
                {
                    Attach = Attach.Load(file, tmpaddr, imageBase, format, labels);
                    attaches.Add(tmpaddr, Attach);
                }
            }
            Position = new Vertex(file, address + 8);
            Rotation = new Rotation(file, address + 0x14);
            Scale    = new Vertex(file, address + 0x20);
            Parent   = parent;
            children = new List <NJS_OBJECT>();
            Children = new ReadOnlyCollection <NJS_OBJECT>(children);
            NJS_OBJECT child = null;

            tmpaddr = ByteConverter.ToInt32(file, address + 0x2C);
            if (tmpaddr != 0)
            {
                tmpaddr = (int)unchecked ((uint)tmpaddr - imageBase);
                child   = new NJS_OBJECT(file, tmpaddr, imageBase, format, this, labels, attaches);
            }
            while (child != null)
            {
                children.Add(child);
                child = child.Sibling;
            }
            tmpaddr = ByteConverter.ToInt32(file, address + 0x30);
            if (tmpaddr != 0)
            {
                tmpaddr = (int)unchecked ((uint)tmpaddr - imageBase);
                Sibling = new NJS_OBJECT(file, tmpaddr, imageBase, format, parent, labels, attaches);
            }

            //Assimp.AssimpContext context = new AssimpContext();
            //Scene scene = context.ImportFile("F:\\untitled.obj", PostProcessSteps.Triangulate);
            //AssimpLoad(scene, scene.RootNode);
        }
Example #4
0
        public void RemoveChildAt(int index)
        {
            NJS_OBJECT child = children[index];

            children.RemoveAt(index);
            child.Parent = null;
        }
Example #5
0
        public static Animation ReadHeader(byte[] file, int address, uint imageBase, ModelFormat format,
                                           Dictionary <int, string> labels)
        {
            NJS_OBJECT Model = new NJS_OBJECT(file, (int)(ByteConverter.ToUInt32(file, address) - imageBase), imageBase, format);

            return(new Animation(file, (int)(ByteConverter.ToUInt32(file, address + 4) - imageBase), imageBase,
                                 Model.CountAnimated(), labels));
        }
Example #6
0
 public override void Init(IniLevelData data, byte act, Device dev)
 {
     SkyboxScale[] skyboxdata = SkyboxScaleList.Load("Levels/Twinkle Park/Skybox Data.ini");
     if (skyboxdata.Length > act)
         Skybox_Scale = skyboxdata[act].Far.ToVector3();
     model = ObjectHelper.LoadModel("Levels/Twinkle Park/Skybox model.sa1mdl");
     meshes = ObjectHelper.GetMeshes(model, dev);
     NoRender = act == 1;
 }
Example #7
0
 public void AddChild(NJS_OBJECT child)
 {
     children.Add(child);
     child.Parent = this;
     if (child.Sibling != null)
     {
         AddChild(child.Sibling);
     }
 }
Example #8
0
 public override void Init(ObjectData data, string name, Device dev)
 {
     ballmodel = ObjectHelper.LoadModel("Objects/Common/Spike Ball/Spike Ball.sa1mdl");
     ballmeshes = ObjectHelper.GetMeshes(ballmodel, dev);
     cylindermodel = ObjectHelper.LoadModel("Objects/Collision/Cylinder.sa1mdl");
     cylindermeshes = ObjectHelper.GetMeshes(cylindermodel, dev);
     spheremodel = ObjectHelper.LoadModel("Objects/Collision/Sphere.sa1mdl");
     spheremeshes = ObjectHelper.GetMeshes(spheremodel, dev);
 }
Example #9
0
        public override BoundingSphere GetBounds(SETItem item, NJS_OBJECT model)
        {
            float largestScale = (item.Scale.X + 10) / 5f;
            if (item.Scale.Y > largestScale) largestScale = (item.Scale.Y + 10) / 5f;
            if (item.Scale.Z > largestScale) largestScale = (item.Scale.Z + 10) / 5f;

            BoundingSphere boxSphere = new BoundingSphere() { Center = new Vertex(item.Position.X, item.Position.Y, item.Position.Z), Radius = largestScale };

            return boxSphere;
        }
Example #10
0
 public override void Init(IniLevelData data, byte act, Device dev)
 {
     SkyboxScale[] skyboxdata = SkyboxScaleList.Load("Levels/Emerald Coast/Skybox Data.ini");
     if (skyboxdata.Length > act)
         Skybox_Scale = skyboxdata[act].Far.ToVector3();
     model1 = ObjectHelper.LoadModel("Levels/Emerald Coast/Skybox model.sa1mdl");
     mesh1 = ObjectHelper.GetMeshes(model1, dev);
     model2 = ObjectHelper.LoadModel("Levels/Emerald Coast/Skybox bottom model.sa1mdl");
     mesh2 = ObjectHelper.GetMeshes(model2, dev);
 }
Example #11
0
        public void ProcessShapeMotionVertexData(NJS_MOTION motion, int frame)
        {
            int        animindex = -1;
            NJS_OBJECT obj       = this;

            do
            {
                obj.ProcessShapeMotionVertexData(motion, frame, ref animindex);
                obj = obj.Sibling;
            } while (obj != null);
        }
Example #12
0
        public COL(byte[] file, int address, uint imageBase, LandTableFormat format, Dictionary <int, string> labels, bool?forceBasic)
        {
            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;
            }
            switch (format)
            {
            case LandTableFormat.SA1:
            case LandTableFormat.SADX:
                Unknown1 = ByteConverter.ToInt32(file, address + 0x10);
                Unknown2 = ByteConverter.ToInt32(file, address + 0x14);
                uint tmpaddr = ByteConverter.ToUInt32(file, address + 0x18) - imageBase;
                Model    = new NJS_OBJECT(file, (int)tmpaddr, imageBase, mfmt, labels);
                Unknown3 = ByteConverter.ToInt32(file, address + 0x1C);
                Flags    = ByteConverter.ToInt32(file, address + 0x20);
                break;

            case LandTableFormat.SA2:
                Flags = ByteConverter.ToInt32(file, address + 0x1C);
                if (!forceBasic.HasValue)
                {
                    mfmt = Flags < 0 ? ModelFormat.Chunk : ModelFormat.Basic;
                }
                tmpaddr  = ByteConverter.ToUInt32(file, address + 0x10) - imageBase;
                Model    = new NJS_OBJECT(file, (int)tmpaddr, imageBase, mfmt, labels);
                Unknown2 = ByteConverter.ToInt32(file, address + 0x14);
                Unknown3 = ByteConverter.ToInt32(file, address + 0x18);
                break;
            }
        }
Example #13
0
        public NJS_OBJECT(byte[] file, int address, uint imageBase, ModelFormat format, Dictionary <int, string> labels)
        {
            if (labels.ContainsKey(address))
            {
                Name = labels[address];
            }
            else
            {
                Name = "object_" + address.ToString("X8");
            }
            ObjectFlags flags = (ObjectFlags)ByteConverter.ToInt32(file, address);

            RotateZYX = (flags & ObjectFlags.RotateZYX) == ObjectFlags.RotateZYX;
            Animate   = (flags & ObjectFlags.NoAnimate) == 0;
            Morph     = (flags & ObjectFlags.NoMorph) == 0;
            int tmpaddr = ByteConverter.ToInt32(file, address + 4);

            if (tmpaddr != 0)
            {
                tmpaddr = (int)unchecked ((uint)tmpaddr - imageBase);
                Attach  = Attach.Load(file, tmpaddr, imageBase, format, labels);
            }
            Position = new Vertex(file, address + 8);
            Rotation = new Rotation(file, address + 0x14);
            Scale    = new Vertex(file, address + 0x20);
            Children = new List <NJS_OBJECT>();
            NJS_OBJECT child = null;

            tmpaddr = ByteConverter.ToInt32(file, address + 0x2C);
            if (tmpaddr != 0)
            {
                tmpaddr = (int)unchecked ((uint)tmpaddr - imageBase);
                child   = new NJS_OBJECT(file, tmpaddr, imageBase, format, labels);
            }
            while (child != null)
            {
                Children.Add(child);
                child = child.Sibling;
            }
            tmpaddr = ByteConverter.ToInt32(file, address + 0x30);
            if (tmpaddr != 0)
            {
                tmpaddr = (int)unchecked ((uint)tmpaddr - imageBase);
                Sibling = new NJS_OBJECT(file, tmpaddr, imageBase, format, labels);
            }
        }
Example #14
0
        public NJS_OBJECT ToChunkModel()
        {
            List <NJS_OBJECT> newchildren = new List <NJS_OBJECT>(Children.Count);

            foreach (NJS_OBJECT item in Children)
            {
                newchildren.Add(item.ToBasicModel());
            }
            NJS_OBJECT result = new NJS_OBJECT();

            if (Attach != null)
            {
                result.Attach = Attach.ToChunkModel();
            }
            result.Position = Position;
            result.Rotation = Rotation;
            result.Scale    = Scale;
            result.Children = newchildren;
            return(result);
        }
Example #15
0
 public COL(byte[] file, int address, uint imageBase, LandTableFormat format, Dictionary<int, string> labels, bool? forceBasic)
 {
     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;
     }
     switch (format)
     {
         case LandTableFormat.SA1:
         case LandTableFormat.SADX:
             Unknown1 = ByteConverter.ToInt32(file, address + 0x10);
             Unknown2 = ByteConverter.ToInt32(file, address + 0x14);
             uint tmpaddr = ByteConverter.ToUInt32(file, address + 0x18) - imageBase;
             Model = new NJS_OBJECT(file, (int)tmpaddr, imageBase, mfmt, labels);
             Unknown3 = ByteConverter.ToInt32(file, address + 0x1C);
             Flags = ByteConverter.ToInt32(file, address + 0x20);
             break;
         case LandTableFormat.SA2:
             Flags = ByteConverter.ToInt32(file, address + 0x1C);
             if (!forceBasic.HasValue)
                 mfmt = Flags < 0 ? ModelFormat.Chunk : ModelFormat.Basic;
             tmpaddr = ByteConverter.ToUInt32(file, address + 0x10) - imageBase;
             Model = new NJS_OBJECT(file, (int)tmpaddr, imageBase, mfmt, labels);
             Unknown2 = ByteConverter.ToInt32(file, address + 0x14);
             Unknown3 = ByteConverter.ToInt32(file, address + 0x18);
             break;
     }
 }
Example #16
0
 public NJS_OBJECT(byte[] file, int address, uint imageBase, ModelFormat format, Dictionary<int, string> labels)
 {
     if (labels.ContainsKey(address))
         Name = labels[address];
     else
         Name = "object_" + address.ToString("X8");
     ObjectFlags flags = (ObjectFlags)ByteConverter.ToInt32(file, address);
     RotateZYX = (flags & ObjectFlags.RotateZYX) == ObjectFlags.RotateZYX;
     Animate = (flags & ObjectFlags.NoAnimate) == 0;
     Morph = (flags & ObjectFlags.NoMorph) == 0;
     int tmpaddr = ByteConverter.ToInt32(file, address + 4);
     if (tmpaddr != 0)
     {
         tmpaddr = (int)unchecked((uint)tmpaddr - imageBase);
         Attach = Attach.Load(file, tmpaddr, imageBase, format, labels);
     }
     Position = new Vertex(file, address + 8);
     Rotation = new Rotation(file, address + 0x14);
     Scale = new Vertex(file, address + 0x20);
     Children = new List<NJS_OBJECT>();
     NJS_OBJECT child = null;
     tmpaddr = ByteConverter.ToInt32(file, address + 0x2C);
     if (tmpaddr != 0)
     {
         tmpaddr = (int)unchecked((uint)tmpaddr - imageBase);
         child = new NJS_OBJECT(file, tmpaddr, imageBase, format, labels);
     }
     while (child != null)
     {
         Children.Add(child);
         child = child.Sibling;
     }
     tmpaddr = ByteConverter.ToInt32(file, address + 0x30);
     if (tmpaddr != 0)
     {
         tmpaddr = (int)unchecked((uint)tmpaddr - imageBase);
         Sibling = new NJS_OBJECT(file, tmpaddr, imageBase, format, labels);
     }
 }
Example #17
0
 public GeoAnimData(byte[] file, int address, uint imageBase, LandTableFormat format, Dictionary<int, string> labels)
 {
     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;
     }
     Unknown1 = ByteConverter.ToInt32(file, address);
     Unknown2 = ByteConverter.ToSingle(file, address + 4);
     Unknown3 = ByteConverter.ToSingle(file, address + 8);
     Model = new NJS_OBJECT(file, (int)(ByteConverter.ToUInt32(file, address + 0xC) - imageBase), imageBase, mfmt);
     Animation = Animation.ReadHeader(file, (int)(ByteConverter.ToUInt32(file, address + 0x10) - imageBase), imageBase, mfmt, labels);
     Unknown4 = ByteConverter.ToInt32(file, address + 0x14);
 }
Example #18
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;
            }
            Unknown1 = ByteConverter.ToInt32(file, address);
            Unknown2 = ByteConverter.ToSingle(file, address + 4);
            Unknown3 = 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);
            int motionaddr = (int)(ByteConverter.ToUInt32(file, actionaddr + 4) - imageBase);

            Animation = NJS_MOTION.ReadDirect(file, Model.CountAnimated(), motionaddr, imageBase, labels, attaches);
            Unknown4  = ByteConverter.ToInt32(file, address + 0x14);
            if (labels.ContainsKey(actionaddr))
            {
                ActionName = labels[actionaddr];
            }
            else
            {
                NJS_ACTION action = new NJS_ACTION(file, actionaddr, imageBase, mfmt, labels, attaches);
                ActionName = action.Name;
                labels.Add(actionaddr + (int)imageBase, ActionName);
            }
        }
Example #19
0
 public override BoundingSphere GetBounds(SETItem item, NJS_OBJECT model)
 {
     return base.GetBounds(item, model);
 }
Example #20
0
        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.ToInt32(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.ToInt32(file, address + 0x18);
                break;
            }
        }
Example #21
0
 public ModelFile(string filename)
 {
     int tmpaddr;
     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 SA1MDL/SA2MDL file.");
     Metadata = new Dictionary<uint, byte[]>();
     Dictionary<int, string> labels = new Dictionary<int, string>();
     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);
         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<Animation> anims = new List<Animation>();
         foreach (string item in animationFiles)
             anims.Add(Animation.Load(Path.Combine(path, item), Model.CountAnimated()));
         Animations = anims.AsReadOnly();
         if (version == 1)
         {
             tmpaddr = ByteConverter.ToInt32(file, 0x10);
             if (tmpaddr != 0)
             {
                 List<string> morphfiles = new List<string>();
                 int addr = ByteConverter.ToInt32(file, tmpaddr);
                 while (addr != -1)
                 {
                     morphfiles.Add(file.GetCString(addr));
                     tmpaddr += 4;
                     addr = ByteConverter.ToInt32(file, tmpaddr);
                 }
                 morphFiles = morphfiles.ToArray();
             }
             else
                 morphFiles = new string[0];
             List<Animation> morphs = new List<Animation>();
             foreach (string item in morphFiles)
                 morphs.Add(Animation.Load(Path.Combine(path, item), Model.CountMorph()));
             Morphs = morphs.AsReadOnly();
         }
         else
         {
             morphFiles = new string[0];
             Morphs = new ReadOnlyCollection<Animation>(new List<Animation>());
         }
     }
     else
     {
         animationFiles = new string[0];
         morphFiles = 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:
                             List<string> morphfiles = new List<string>();
                             while (ByteConverter.ToInt32(file, tmpaddr) != -1)
                             {
                                 morphfiles.Add(file.GetCString(ByteConverter.ToInt32(file, tmpaddr)));
                                 tmpaddr += 4;
                             }
                             morphFiles = morphfiles.ToArray();
                             break;
                         case ChunkTypes.Author:
                             Author = file.GetCString(tmpaddr);
                             break;
                         case ChunkTypes.Tool:
                             Tool = file.GetCString(tmpaddr);
                             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:
                             List<string> morphchunks = new List<string>();
                             while (ByteConverter.ToInt32(chunk, chunkaddr) != -1)
                             {
                                 morphchunks.Add(chunk.GetCString(ByteConverter.ToInt32(chunk, chunkaddr)));
                                 chunkaddr += 4;
                             }
                             morphFiles = morphchunks.ToArray();
                             break;
                         case ChunkTypes.Author:
                             Author = chunk.GetCString(chunkaddr);
                             break;
                         case ChunkTypes.Tool:
                             Tool = chunk.GetCString(chunkaddr);
                             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;
             default:
                 throw new FormatException("Not a valid SA1MDL/SA2MDL file.");
         }
         Model = new NJS_OBJECT(file, ByteConverter.ToInt32(file, 8), 0, Format, labels);
         string path = Path.GetDirectoryName(filename);
         List<Animation> anims = new List<Animation>();
         foreach (string item in animationFiles)
             anims.Add(Animation.Load(Path.Combine(path, item), Model.CountAnimated()));
         Animations = anims.AsReadOnly();
         List<Animation> morphs = new List<Animation>();
         foreach (string item in morphFiles)
             morphs.Add(Animation.Load(Path.Combine(path, item), Model.CountMorph()));
         Morphs = morphs.AsReadOnly();
     }
     ByteConverter.BigEndian = be;
 }
Example #22
0
        static void Main(string[] args)
        {
            string datafilename, inifilename;

            if (args.Length > 0)
            {
                datafilename = args[0];
                Console.WriteLine("File: {0}", datafilename);
            }
            else
            {
                Console.Write("File: ");
                datafilename = Console.ReadLine();
            }
            if (args.Length > 1)
            {
                inifilename = args[1];
                Console.WriteLine("INI File: {0}", inifilename);
            }
            else
            {
                Console.Write("INI File: ");
                inifilename = Console.ReadLine();
            }
            byte[]  datafile = File.ReadAllBytes(datafilename);
            IniData inifile  = IniSerializer.Deserialize <IniData>(inifilename);

            if (inifile.MD5 != null && inifile.MD5.Count > 0)
            {
                string datahash = HelperFunctions.FileHash(datafile);
                if (!inifile.MD5.Any(h => h.Equals(datahash, StringComparison.OrdinalIgnoreCase)))
                {
                    Console.WriteLine("The file {0} is not valid for use with the INI {1}.", datafilename, inifilename);
                    return;
                }
            }
            SA_Tools.ByteConverter.BigEndian = SonicRetro.SAModel.ByteConverter.BigEndian = inifile.BigEndian;
            Environment.CurrentDirectory     = Path.Combine(Environment.CurrentDirectory, Path.GetDirectoryName(datafilename));
            if (inifile.Compressed)
            {
                datafile = FraGag.Compression.Prs.Decompress(datafile);
            }
            uint imageBase = HelperFunctions.SetupEXE(ref datafile) ?? inifile.ImageBase.Value;

            if (Path.GetExtension(datafilename).Equals(".rel", StringComparison.OrdinalIgnoreCase))
            {
                HelperFunctions.FixRELPointers(datafile);
            }
            bool            SA2      = inifile.Game == Game.SA2 | inifile.Game == Game.SA2B;
            ModelFormat     modelfmt = 0;
            LandTableFormat landfmt  = 0;

            switch (inifile.Game)
            {
            case Game.SA1:
                modelfmt = ModelFormat.Basic;
                landfmt  = LandTableFormat.SA1;
                break;

            case Game.SADX:
                modelfmt = ModelFormat.BasicDX;
                landfmt  = LandTableFormat.SADX;
                break;

            case Game.SA2:
            case Game.SA2B:
                modelfmt = ModelFormat.Chunk;
                landfmt  = LandTableFormat.SA2;
                break;
            }
            int itemcount = 0;
            Dictionary <string, MasterObjectListEntry>     masterobjlist = new Dictionary <string, MasterObjectListEntry>();
            Dictionary <string, Dictionary <string, int> > objnamecounts = new Dictionary <string, Dictionary <string, int> >();
            Stopwatch timer = new Stopwatch();

            timer.Start();
            foreach (KeyValuePair <string, SA_Tools.FileInfo> item in inifile.Files)
            {
                if (string.IsNullOrEmpty(item.Key))
                {
                    continue;
                }
                string                      filedesc         = item.Key;
                SA_Tools.FileInfo           data             = item.Value;
                Dictionary <string, string> customProperties = data.CustomProperties;
                string                      type             = data.Type;
                int  address = data.Address;
                bool nohash  = false;
                Console.WriteLine(item.Key + ": " + data.Address.ToString("X") + " → " + data.Filename);
                Directory.CreateDirectory(Path.GetDirectoryName(data.Filename));
                switch (type)
                {
                case "landtable":
                    new LandTable(datafile, address, imageBase, landfmt)
                    {
                        Description = item.Key, Tool = "split"
                    }.SaveToFile(data.Filename, landfmt);
                    break;

                case "model":
                {
                    SonicRetro.SAModel.NJS_OBJECT mdl = new SonicRetro.SAModel.NJS_OBJECT(datafile, address, imageBase, modelfmt);
                    string[] mdlanis = new string[0];
                    if (customProperties.ContainsKey("animations"))
                    {
                        mdlanis = customProperties["animations"].Split(',');
                    }
                    string[] mdlmorphs = new string[0];
                    if (customProperties.ContainsKey("morphs"))
                    {
                        mdlmorphs = customProperties["morphs"].Split(',');
                    }
                    ModelFile.CreateFile(data.Filename, mdl, mdlanis, mdlmorphs, null, item.Key, "split", null, modelfmt);
                }
                break;

                case "basicmodel":
                {
                    SonicRetro.SAModel.NJS_OBJECT mdl = new SonicRetro.SAModel.NJS_OBJECT(datafile, address, imageBase, ModelFormat.Basic);
                    string[] mdlanis = new string[0];
                    if (customProperties.ContainsKey("animations"))
                    {
                        mdlanis = customProperties["animations"].Split(',');
                    }
                    string[] mdlmorphs = new string[0];
                    if (customProperties.ContainsKey("morphs"))
                    {
                        mdlmorphs = customProperties["morphs"].Split(',');
                    }
                    ModelFile.CreateFile(data.Filename, mdl, mdlanis, mdlmorphs, null, item.Key, "split", null, ModelFormat.Basic);
                }
                break;

                case "basicdxmodel":
                {
                    SonicRetro.SAModel.NJS_OBJECT mdl = new SonicRetro.SAModel.NJS_OBJECT(datafile, address, imageBase, ModelFormat.BasicDX);
                    string[] mdlanis = new string[0];
                    if (customProperties.ContainsKey("animations"))
                    {
                        mdlanis = customProperties["animations"].Split(',');
                    }
                    string[] mdlmorphs = new string[0];
                    if (customProperties.ContainsKey("morphs"))
                    {
                        mdlmorphs = customProperties["morphs"].Split(',');
                    }
                    ModelFile.CreateFile(data.Filename, mdl, mdlanis, mdlmorphs, null, item.Key, "split", null, ModelFormat.BasicDX);
                }
                break;

                case "chunkmodel":
                {
                    SonicRetro.SAModel.NJS_OBJECT mdl = new SonicRetro.SAModel.NJS_OBJECT(datafile, address, imageBase, ModelFormat.Chunk);
                    string[] mdlanis = new string[0];
                    if (customProperties.ContainsKey("animations"))
                    {
                        mdlanis = customProperties["animations"].Split(',');
                    }
                    string[] mdlmorphs = new string[0];
                    if (customProperties.ContainsKey("morphs"))
                    {
                        mdlmorphs = customProperties["morphs"].Split(',');
                    }
                    ModelFile.CreateFile(data.Filename, mdl, mdlanis, mdlmorphs, null, item.Key, "split", null, ModelFormat.Chunk);
                }
                break;

                case "action":
                {
                    AnimationHeader ani = new AnimationHeader(datafile, address, imageBase, modelfmt);
                    ani.Animation.Name = filedesc;
                    ani.Animation.Save(data.Filename);
                }
                break;

                case "animation":
                    new Animation(datafile, address, imageBase, int.Parse(customProperties["numparts"], NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite, NumberFormatInfo.InvariantInfo))
                    {
                        Name = filedesc
                    }
                    .Save(data.Filename);
                    break;

                case "objlist":
                {
                    ObjectListEntry[] objs = ObjectList.Load(datafile, address, imageBase, SA2);
                    if (inifile.MasterObjectList != null)
                    {
                        foreach (ObjectListEntry obj in objs)
                        {
                            if (!masterobjlist.ContainsKey(obj.CodeString))
                            {
                                masterobjlist.Add(obj.CodeString, new MasterObjectListEntry(obj));
                            }
                            if (!objnamecounts.ContainsKey(obj.CodeString))
                            {
                                objnamecounts.Add(obj.CodeString, new Dictionary <string, int>()
                                    {
                                        { obj.Name, 1 }
                                    });
                            }
                            else if (!objnamecounts[obj.CodeString].ContainsKey(obj.Name))
                            {
                                objnamecounts[obj.CodeString].Add(obj.Name, 1);
                            }
                            else
                            {
                                objnamecounts[obj.CodeString][obj.Name]++;
                            }
                        }
                    }
                    objs.Save(data.Filename);
                }
                break;

                case "startpos":
                    if (SA2)
                    {
                        SA2StartPosList.Load(datafile, address).Save(data.Filename);
                    }
                    else
                    {
                        SA1StartPosList.Load(datafile, address).Save(data.Filename);
                    }
                    break;

                case "texlist":
                    TextureList.Load(datafile, address, imageBase).Save(data.Filename);
                    break;

                case "leveltexlist":
                    new LevelTextureList(datafile, address, imageBase).Save(data.Filename);
                    break;

                case "triallevellist":
                    TrialLevelList.Save(TrialLevelList.Load(datafile, address, imageBase), data.Filename);
                    break;

                case "bosslevellist":
                    BossLevelList.Save(BossLevelList.Load(datafile, address), data.Filename);
                    break;

                case "fieldstartpos":
                    FieldStartPosList.Load(datafile, address).Save(data.Filename);
                    break;

                case "soundtestlist":
                    SoundTestList.Load(datafile, address, imageBase).Save(data.Filename);
                    break;

                case "musiclist":
                {
                    int muscnt = int.Parse(customProperties["length"], NumberStyles.Integer, NumberFormatInfo.InvariantInfo);
                    MusicList.Load(datafile, address, imageBase, muscnt).Save(data.Filename);
                }
                break;

                case "soundlist":
                    SoundList.Load(datafile, address, imageBase).Save(data.Filename);
                    break;

                case "stringarray":
                {
                    int       cnt  = int.Parse(customProperties["length"], NumberStyles.Integer, NumberFormatInfo.InvariantInfo);
                    Languages lang = Languages.Japanese;
                    if (data.CustomProperties.ContainsKey("language"))
                    {
                        lang = (Languages)Enum.Parse(typeof(Languages), data.CustomProperties["language"], true);
                    }
                    StringArray.Load(datafile, address, imageBase, cnt, lang).Save(data.Filename);
                }
                break;

                case "nextlevellist":
                    NextLevelList.Load(datafile, address).Save(data.Filename);
                    break;

                case "cutscenetext":
                {
                    int cnt = int.Parse(customProperties["length"], NumberStyles.Integer, NumberFormatInfo.InvariantInfo);
                    new CutsceneText(datafile, address, imageBase, cnt).Save(data.Filename, out string[] hashes);
                    data.MD5Hash = string.Join(",", hashes);
                    nohash       = true;
                }
                break;

                case "recapscreen":
                {
                    int cnt = int.Parse(customProperties["length"], NumberStyles.Integer, NumberFormatInfo.InvariantInfo);
                    RecapScreenList.Load(datafile, address, imageBase, cnt).Save(data.Filename, out string[][] hashes);
                    string[] hash2 = new string[hashes.Length];
                    for (int i = 0; i < hashes.Length; i++)
                    {
                        hash2[i] = string.Join(",", hashes[i]);
                    }
                    data.MD5Hash = string.Join(":", hash2);
                    nohash       = true;
                }
                break;

                case "npctext":
                {
                    int cnt = int.Parse(customProperties["length"], NumberStyles.Integer, NumberFormatInfo.InvariantInfo);
                    NPCTextList.Load(datafile, address, imageBase, cnt).Save(data.Filename, out string[][] hashes);
                    string[] hash2 = new string[hashes.Length];
                    for (int i = 0; i < hashes.Length; i++)
                    {
                        hash2[i] = string.Join(",", hashes[i]);
                    }
                    data.MD5Hash = string.Join(":", hash2);
                    nohash       = true;
                }
                break;

                case "levelclearflags":
                    LevelClearFlagList.Save(LevelClearFlagList.Load(datafile, address), data.Filename);
                    break;

                case "deathzone":
                {
                    List <DeathZoneFlags> flags = new List <DeathZoneFlags>();
                    string        path          = Path.GetDirectoryName(data.Filename);
                    List <string> hashes        = new List <string>();
                    int           num           = 0;
                    while (SA_Tools.ByteConverter.ToUInt32(datafile, address + 4) != 0)
                    {
                        flags.Add(new DeathZoneFlags(datafile, address));
                        string file = Path.Combine(path, num++.ToString(NumberFormatInfo.InvariantInfo) + (modelfmt == ModelFormat.Chunk ? ".sa2mdl" : ".sa1mdl"));
                        ModelFile.CreateFile(file, new SonicRetro.SAModel.NJS_OBJECT(datafile, datafile.GetPointer(address + 4, imageBase), imageBase, modelfmt), null, null, null, null, "split", null, modelfmt);
                        hashes.Add(HelperFunctions.FileHash(file));
                        address += 8;
                    }
                    flags.ToArray().Save(data.Filename);
                    hashes.Insert(0, HelperFunctions.FileHash(data.Filename));
                    data.MD5Hash = string.Join(",", hashes.ToArray());
                    nohash       = true;
                }
                break;

                case "skyboxscale":
                {
                    int cnt = int.Parse(customProperties["count"], NumberStyles.Integer, NumberFormatInfo.InvariantInfo);
                    SkyboxScaleList.Load(datafile, address, imageBase, cnt).Save(data.Filename);
                }
                break;

                case "stageselectlist":
                {
                    int cnt = int.Parse(customProperties["count"], NumberStyles.Integer, NumberFormatInfo.InvariantInfo);
                    StageSelectLevelList.Load(datafile, address, cnt).Save(data.Filename);
                }
                break;

                case "levelrankscores":
                    LevelRankScoresList.Load(datafile, address).Save(data.Filename);
                    break;

                case "levelranktimes":
                    LevelRankTimesList.Load(datafile, address).Save(data.Filename);
                    break;

                case "endpos":
                    SA2EndPosList.Load(datafile, address).Save(data.Filename);
                    break;

                case "animationlist":
                {
                    int cnt = int.Parse(customProperties["count"], NumberStyles.Integer, NumberFormatInfo.InvariantInfo);
                    SA2AnimationInfoList.Load(datafile, address, cnt).Save(data.Filename);
                }
                break;

                case "levelpathlist":
                {
                    List <string> hashes = new List <string>();
                    ushort        lvlnum = (ushort)SA_Tools.ByteConverter.ToUInt32(datafile, address);
                    while (lvlnum != 0xFFFF)
                    {
                        int ptr = SA_Tools.ByteConverter.ToInt32(datafile, address + 4);
                        if (ptr != 0)
                        {
                            ptr = (int)((uint)ptr - imageBase);
                            SA1LevelAct level  = new SA1LevelAct(lvlnum);
                            string      lvldir = Path.Combine(data.Filename, level.ToString());
                            PathList.Load(datafile, ptr, imageBase).Save(lvldir, out string[] lvlhashes);
                            hashes.Add(level.ToString() + ":" + string.Join(",", lvlhashes));
                        }
                        address += 8;
                        lvlnum   = (ushort)SA_Tools.ByteConverter.ToUInt32(datafile, address);
                    }
                    data.MD5Hash = string.Join("|", hashes.ToArray());
                    nohash       = true;
                }
                break;

                case "stagelightdatalist":
                    SA1StageLightDataList.Load(datafile, address).Save(data.Filename);
                    break;

                case "weldlist":
                    WeldList.Load(datafile, address, imageBase).Save(data.Filename);
                    break;

                case "bmitemattrlist":
                    BlackMarketItemAttributesList.Load(datafile, address, imageBase).Save(data.Filename);
                    break;

                case "creditstextlist":
                    CreditsTextList.Load(datafile, address, imageBase).Save(data.Filename);
                    break;

                default:                         // raw binary
                {
                    byte[] bin = new byte[int.Parse(customProperties["size"], NumberStyles.HexNumber)];
                    Array.Copy(datafile, address, bin, 0, bin.Length);
                    File.WriteAllBytes(data.Filename, bin);
                }
                break;
                }
                if (!nohash)
                {
                    data.MD5Hash = HelperFunctions.FileHash(data.Filename);
                }
                itemcount++;
            }
            if (inifile.MasterObjectList != null)
            {
                foreach (KeyValuePair <string, MasterObjectListEntry> obj in masterobjlist)
                {
                    KeyValuePair <string, int> name = new KeyValuePair <string, int>();
                    foreach (KeyValuePair <string, int> it in objnamecounts[obj.Key])
                    {
                        if (it.Value > name.Value)
                        {
                            name = it;
                        }
                    }
                    obj.Value.Name  = name.Key;
                    obj.Value.Names = objnamecounts[obj.Key].Select((it) => it.Key).ToArray();
                }
                IniSerializer.Serialize(masterobjlist, inifile.MasterObjectList);
            }
            IniSerializer.Serialize(inifile, Path.Combine(Environment.CurrentDirectory, Path.GetFileNameWithoutExtension(datafilename)) + "_data.ini");
            timer.Stop();
            Console.WriteLine("Split " + itemcount + " items in " + timer.Elapsed.TotalSeconds + " seconds.");
            Console.WriteLine();
        }
Example #23
0
 static void Main(string[] args)
 {
     string datafilename, inifilename;
     if (args.Length > 0)
     {
         datafilename = args[0];
         Console.WriteLine("File: {0}", datafilename);
     }
     else
     {
         Console.Write("File: ");
         datafilename = Console.ReadLine();
     }
     if (args.Length > 1)
     {
         inifilename = args[1];
         Console.WriteLine("INI File: {0}", inifilename);
     }
     else
     {
         Console.Write("INI File: ");
         inifilename = Console.ReadLine();
     }
     byte[] datafile = File.ReadAllBytes(datafilename);
     IniData inifile = IniSerializer.Deserialize<IniData>(inifilename);
     SA_Tools.ByteConverter.BigEndian = SonicRetro.SAModel.ByteConverter.BigEndian = inifile.BigEndian;
     Environment.CurrentDirectory = Path.Combine(Environment.CurrentDirectory, Path.GetDirectoryName(datafilename));
     if (inifile.Compressed) datafile = FraGag.Compression.Prs.Decompress(datafile);
     uint imageBase = HelperFunctions.SetupEXE(ref datafile) ?? inifile.ImageBase.Value;
     if (Path.GetExtension(datafilename).Equals(".rel", StringComparison.OrdinalIgnoreCase)) HelperFunctions.FixRELPointers(datafile);
     bool SA2 = inifile.Game == Game.SA2 | inifile.Game == Game.SA2B;
     ModelFormat modelfmt = 0;
     LandTableFormat landfmt = 0;
     switch (inifile.Game)
     {
         case Game.SA1:
             modelfmt = ModelFormat.Basic;
             landfmt = LandTableFormat.SA1;
             break;
         case Game.SADX:
             modelfmt = ModelFormat.BasicDX;
             landfmt = LandTableFormat.SADX;
             break;
         case Game.SA2:
         case Game.SA2B:
             modelfmt = ModelFormat.Chunk;
             landfmt = LandTableFormat.SA2;
             break;
     }
     int itemcount = 0;
     Dictionary<string, MasterObjectListEntry> masterobjlist = new Dictionary<string, MasterObjectListEntry>();
     Dictionary<string, Dictionary<string, int>> objnamecounts = new Dictionary<string, Dictionary<string, int>>();
     Stopwatch timer = new Stopwatch();
     timer.Start();
     foreach (KeyValuePair<string, SA_Tools.FileInfo> item in inifile.Files)
     {
         if (string.IsNullOrEmpty(item.Key)) continue;
         string filedesc = item.Key;
         SA_Tools.FileInfo data = item.Value;
         Dictionary<string, string> customProperties = data.CustomProperties;
         string type = data.Type;
         int address = data.Address;
         bool nohash = false;
         Console.WriteLine(item.Key + ": " + data.Address.ToString("X") + " → " + data.Filename);
         Directory.CreateDirectory(Path.GetDirectoryName(data.Filename));
         switch (type)
         {
             case "landtable":
                 new LandTable(datafile, address, imageBase, landfmt) { Description = item.Key, Tool = "split" }.SaveToFile(data.Filename, landfmt);
                 break;
             case "model":
                 {
                     SonicRetro.SAModel.NJS_OBJECT mdl = new SonicRetro.SAModel.NJS_OBJECT(datafile, address, imageBase, modelfmt);
                     string[] mdlanis = new string[0];
                     if (customProperties.ContainsKey("animations"))
                         mdlanis = customProperties["animations"].Split(',');
                     string[] mdlmorphs = new string[0];
                     if (customProperties.ContainsKey("morphs"))
                         mdlmorphs = customProperties["morphs"].Split(',');
                     ModelFile.CreateFile(data.Filename, mdl, mdlanis, mdlmorphs, null, item.Key, "split", null, modelfmt);
                 }
                 break;
             case "basicmodel":
                 {
                     SonicRetro.SAModel.NJS_OBJECT mdl = new SonicRetro.SAModel.NJS_OBJECT(datafile, address, imageBase, ModelFormat.Basic);
                     string[] mdlanis = new string[0];
                     if (customProperties.ContainsKey("animations"))
                         mdlanis = customProperties["animations"].Split(',');
                     string[] mdlmorphs = new string[0];
                     if (customProperties.ContainsKey("morphs"))
                         mdlmorphs = customProperties["morphs"].Split(',');
                     ModelFile.CreateFile(data.Filename, mdl, mdlanis, mdlmorphs, null, item.Key, "split", null, ModelFormat.Basic);
                 }
                 break;
             case "basicdxmodel":
                 {
                     SonicRetro.SAModel.NJS_OBJECT mdl = new SonicRetro.SAModel.NJS_OBJECT(datafile, address, imageBase, ModelFormat.BasicDX);
                     string[] mdlanis = new string[0];
                     if (customProperties.ContainsKey("animations"))
                         mdlanis = customProperties["animations"].Split(',');
                     string[] mdlmorphs = new string[0];
                     if (customProperties.ContainsKey("morphs"))
                         mdlmorphs = customProperties["morphs"].Split(',');
                     ModelFile.CreateFile(data.Filename, mdl, mdlanis, mdlmorphs, null, item.Key, "split", null, ModelFormat.BasicDX);
                 }
                 break;
             case "chunkmodel":
                 {
                     SonicRetro.SAModel.NJS_OBJECT mdl = new SonicRetro.SAModel.NJS_OBJECT(datafile, address, imageBase, ModelFormat.Chunk);
                     string[] mdlanis = new string[0];
                     if (customProperties.ContainsKey("animations"))
                         mdlanis = customProperties["animations"].Split(',');
                     string[] mdlmorphs = new string[0];
                     if (customProperties.ContainsKey("morphs"))
                         mdlmorphs = customProperties["morphs"].Split(',');
                     ModelFile.CreateFile(data.Filename, mdl, mdlanis, mdlmorphs, null, item.Key, "split", null, ModelFormat.Chunk);
                 }
                 break;
             case "action":
                 {
                     AnimationHeader ani = new AnimationHeader(datafile, address, imageBase, modelfmt);
                     ani.Animation.Name = filedesc;
                     ani.Animation.Save(data.Filename);
                 }
                 break;
             case "animation":
                 new Animation(datafile, address, imageBase, int.Parse(customProperties["numparts"], NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite, NumberFormatInfo.InvariantInfo)) { Name = filedesc }
                     .Save(data.Filename);
                 break;
             case "objlist":
                 {
                     ObjectListEntry[] objs = ObjectList.Load(datafile, address, imageBase, SA2);
                     if (inifile.MasterObjectList != null)
                         foreach (ObjectListEntry obj in objs)
                         {
                             if (!masterobjlist.ContainsKey(obj.CodeString))
                                 masterobjlist.Add(obj.CodeString, new MasterObjectListEntry(obj));
                             if (!objnamecounts.ContainsKey(obj.CodeString))
                                 objnamecounts.Add(obj.CodeString, new Dictionary<string, int>() { { obj.Name, 1 } });
                             else if (!objnamecounts[obj.CodeString].ContainsKey(obj.Name))
                                 objnamecounts[obj.CodeString].Add(obj.Name, 1);
                             else
                                 objnamecounts[obj.CodeString][obj.Name]++;
                         }
                     objs.Save(data.Filename);
                 }
                 break;
             case "startpos":
                 if (SA2)
                     SA2StartPosList.Load(datafile, address).Save(data.Filename);
                 else
                     SA1StartPosList.Load(datafile, address).Save(data.Filename);
                 break;
             case "texlist":
                 TextureList.Load(datafile, address, imageBase).Save(data.Filename);
                 break;
             case "leveltexlist":
                 new LevelTextureList(datafile, address, imageBase).Save(data.Filename);
                 break;
             case "triallevellist":
                 TrialLevelList.Save(TrialLevelList.Load(datafile, address, imageBase), data.Filename);
                 break;
             case "bosslevellist":
                 BossLevelList.Save(BossLevelList.Load(datafile, address), data.Filename);
                 break;
             case "fieldstartpos":
                 FieldStartPosList.Load(datafile, address).Save(data.Filename);
                 break;
             case "soundtestlist":
                 SoundTestList.Load(datafile, address, imageBase).Save(data.Filename);
                 break;
             case "musiclist":
                 {
                     int muscnt = int.Parse(customProperties["length"], NumberStyles.Integer, NumberFormatInfo.InvariantInfo);
                     MusicList.Load(datafile, address, imageBase, muscnt).Save(data.Filename);
                 }
                 break;
             case "soundlist":
                 SoundList.Load(datafile, address, imageBase).Save(data.Filename);
                 break;
             case "stringarray":
                 {
                     int cnt = int.Parse(customProperties["length"], NumberStyles.Integer, NumberFormatInfo.InvariantInfo);
                     Languages lang = Languages.Japanese;
                     if (data.CustomProperties.ContainsKey("language"))
                         lang = (Languages)Enum.Parse(typeof(Languages), data.CustomProperties["language"], true);
                     StringArray.Load(datafile, address, imageBase, cnt, lang).Save(data.Filename);
                 }
                 break;
             case "nextlevellist":
                 NextLevelList.Load(datafile, address).Save(data.Filename);
                 break;
             case "cutscenetext":
                 {
                     int cnt = int.Parse(customProperties["length"], NumberStyles.Integer, NumberFormatInfo.InvariantInfo);
                     string[] hashes;
                     new CutsceneText(datafile, address, imageBase, cnt).Save(data.Filename, out hashes);
                     data.MD5Hash = string.Join(",", hashes);
                     nohash = true;
                 }
                 break;
             case "recapscreen":
                 {
                     int cnt = int.Parse(customProperties["length"], NumberStyles.Integer, NumberFormatInfo.InvariantInfo);
                     string[][] hashes;
                     RecapScreenList.Load(datafile, address, imageBase, cnt).Save(data.Filename, out hashes);
                     string[] hash2 = new string[hashes.Length];
                     for (int i = 0; i < hashes.Length; i++)
                     {
                         hash2[i] = string.Join(",", hashes[i]);
                     }
                     data.MD5Hash = string.Join(":", hash2);
                     nohash = true;
                 }
                 break;
             case "npctext":
                 {
                     int cnt = int.Parse(customProperties["length"], NumberStyles.Integer, NumberFormatInfo.InvariantInfo);
                     string[][] hashes;
                     NPCTextList.Load(datafile, address, imageBase, cnt).Save(data.Filename, out hashes);
                     string[] hash2 = new string[hashes.Length];
                     for (int i = 0; i < hashes.Length; i++)
                         hash2[i] = string.Join(",", hashes[i]);
                     data.MD5Hash = string.Join(":", hash2);
                     nohash = true;
                 }
                 break;
             case "levelclearflags":
                 LevelClearFlagList.Save(LevelClearFlagList.Load(datafile, address), data.Filename);
                 break;
             case "deathzone":
                 {
                     List<DeathZoneFlags> flags = new List<DeathZoneFlags>();
                     string path = Path.GetDirectoryName(data.Filename);
                     List<string> hashes = new List<string>();
                     int num = 0;
                     while (SA_Tools.ByteConverter.ToUInt32(datafile, address + 4) != 0)
                     {
                         flags.Add(new DeathZoneFlags(datafile, address));
                         string file = Path.Combine(path, num++.ToString(NumberFormatInfo.InvariantInfo) + (modelfmt == ModelFormat.Chunk ? ".sa2mdl" : ".sa1mdl"));
                         ModelFile.CreateFile(file, new SonicRetro.SAModel.NJS_OBJECT(datafile, datafile.GetPointer(address + 4, imageBase), imageBase, modelfmt), null, null, null, null, "split", null, modelfmt);
                         hashes.Add(HelperFunctions.FileHash(file));
                         address += 8;
                     }
                     flags.ToArray().Save(data.Filename);
                     hashes.Insert(0, HelperFunctions.FileHash(data.Filename));
                     data.MD5Hash = string.Join(",", hashes.ToArray());
                     nohash = true;
                 }
                 break;
             case "skyboxscale":
                 {
                     int cnt = int.Parse(customProperties["count"], NumberStyles.Integer, NumberFormatInfo.InvariantInfo);
                     SkyboxScaleList.Load(datafile, address, imageBase, cnt).Save(data.Filename);
                 }
                 break;
             case "stageselectlist":
                 {
                     int cnt = int.Parse(customProperties["count"], NumberStyles.Integer, NumberFormatInfo.InvariantInfo);
                     StageSelectLevelList.Load(datafile, address, cnt).Save(data.Filename);
                 }
                 break;
             case "levelrankscores":
                 LevelRankScoresList.Load(datafile, address).Save(data.Filename);
                 break;
             case "levelranktimes":
                 LevelRankTimesList.Load(datafile, address).Save(data.Filename);
                 break;
             case "endpos":
                 SA2EndPosList.Load(datafile, address).Save(data.Filename);
                 break;
             case "animationlist":
                 {
                     int cnt = int.Parse(customProperties["count"], NumberStyles.Integer, NumberFormatInfo.InvariantInfo);
                     SA2AnimationInfoList.Load(datafile, address, cnt).Save(data.Filename);
                 }
                 break;
             case "levelpathlist":
                 {
                     List<string> hashes = new List<string>();
                     ushort lvlnum = (ushort)SA_Tools.ByteConverter.ToUInt32(datafile, address);
                     while (lvlnum != 0xFFFF)
                     {
                         int ptr = SA_Tools.ByteConverter.ToInt32(datafile, address + 4);
                         if (ptr != 0)
                         {
                             ptr = (int)((uint)ptr - imageBase);
                             SA1LevelAct level = new SA1LevelAct(lvlnum);
                             string lvldir = Path.Combine(data.Filename, level.ToString());
                             string[] lvlhashes;
                             PathList.Load(datafile, ptr, imageBase).Save(lvldir, out lvlhashes);
                             hashes.Add(level.ToString() + ":" + string.Join(",", lvlhashes));
                         }
                         address += 8;
                         lvlnum = (ushort)SA_Tools.ByteConverter.ToUInt32(datafile, address);
                     }
                     data.MD5Hash = string.Join("|", hashes.ToArray());
                     nohash = true;
                 }
                 break;
             case "stagelightdatalist":
                 SA1StageLightDataList.Load(datafile, address).Save(data.Filename);
                 break;
             default: // raw binary
                 {
                     byte[] bin = new byte[int.Parse(customProperties["size"], NumberStyles.HexNumber)];
                     Array.Copy(datafile, address, bin, 0, bin.Length);
                     File.WriteAllBytes(data.Filename, bin);
                 }
                 break;
         }
         if (!nohash)
             data.MD5Hash = HelperFunctions.FileHash(data.Filename);
         itemcount++;
     }
     if (inifile.MasterObjectList != null)
     {
         foreach (KeyValuePair<string, MasterObjectListEntry> obj in masterobjlist)
         {
             KeyValuePair<string, int> name = new KeyValuePair<string, int>();
             foreach (KeyValuePair<string, int> it in objnamecounts[obj.Key])
                 if (it.Value > name.Value)
                     name = it;
             obj.Value.Name = name.Key;
             obj.Value.Names = objnamecounts[obj.Key].Select((it) => it.Key).ToArray();
         }
         IniSerializer.Serialize(masterobjlist, inifile.MasterObjectList);
     }
     IniSerializer.Serialize(inifile, Path.Combine(Environment.CurrentDirectory, Path.GetFileNameWithoutExtension(datafilename)) + "_data.ini");
     timer.Stop();
     Console.WriteLine("Split " + itemcount + " items in " + timer.Elapsed.TotalSeconds + " seconds.");
     Console.WriteLine();
 }
Example #24
0
        public static void CreateFile(string filename, NJS_OBJECT model, string[] animationFiles, string[] morphFiles,
            string author, string description, string tool, Dictionary<uint, byte[]> metadata, ModelFormat format)
        {
            bool be = ByteConverter.BigEndian;
            ByteConverter.BigEndian = false;
            if (format == ModelFormat.BasicDX)
                format = ModelFormat.Basic;
            List<byte> file = new List<byte>();
            ulong magic;
            switch (format)
            {
                case ModelFormat.Basic:
                case ModelFormat.BasicDX:
                    magic = SA1MDLVer;
                    break;
                case ModelFormat.Chunk:
                    magic = SA2MDLVer;
                    break;
                default:
                    throw new ArgumentException("Cannot save " + format.ToString() + " format models to file!", "format");
            }
            file.AddRange(ByteConverter.GetBytes(magic));
            uint addr;
            Dictionary<string, uint> labels = new Dictionary<string, uint>();
            byte[] mdl = model.GetBytes(0x10, false, labels, out addr);
            file.AddRange(ByteConverter.GetBytes(addr + 0x10));
            file.AddRange(ByteConverter.GetBytes(mdl.Length + 0x10));
            file.AddRange(mdl);

            if (labels.Count > 0)
            {
                List<byte> chunk = new List<byte>((labels.Count * 8) + 8);
                int straddr = (labels.Count * 8) + 8;
                List<byte> strbytes = new List<byte>();
                foreach (KeyValuePair<string, uint> label in labels)
                {
                    chunk.AddRange(ByteConverter.GetBytes(label.Value));
                    chunk.AddRange(ByteConverter.GetBytes(straddr + strbytes.Count));
                    strbytes.AddRange(Encoding.UTF8.GetBytes(label.Key));
                    strbytes.Add(0);
                    strbytes.Align(4);
                }
                chunk.AddRange(ByteConverter.GetBytes(-1L));
                chunk.AddRange(strbytes);
                file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Label));
                file.AddRange(ByteConverter.GetBytes(chunk.Count));
                file.AddRange(chunk);
            }
            if (animationFiles != null && animationFiles.Length > 0)
            {
                List<byte> chunk = new List<byte>((animationFiles.Length + 1) * 4);
                int straddr = (animationFiles.Length + 1) * 4;
                List<byte> strbytes = new List<byte>();
                for (int i = 0; i < animationFiles.Length; i++)
                {
                    chunk.AddRange(ByteConverter.GetBytes(straddr + strbytes.Count));
                    strbytes.AddRange(Encoding.UTF8.GetBytes(animationFiles[i]));
                    strbytes.Add(0);
                    strbytes.Align(4);
                }
                chunk.AddRange(ByteConverter.GetBytes(-1));
                chunk.AddRange(strbytes);
                file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Animation));
                file.AddRange(ByteConverter.GetBytes(chunk.Count));
                file.AddRange(chunk);
            }
            if (morphFiles != null && morphFiles.Length > 0)
            {
                List<byte> chunk = new List<byte>((morphFiles.Length + 1) * 4);
                int straddr = (morphFiles.Length + 1) * 4;
                List<byte> strbytes = new List<byte>();
                for (int i = 0; i < morphFiles.Length; i++)
                {
                    chunk.AddRange(ByteConverter.GetBytes(straddr + strbytes.Count));
                    strbytes.AddRange(Encoding.UTF8.GetBytes(morphFiles[i]));
                    strbytes.Add(0);
                    strbytes.Align(4);
                }
                chunk.AddRange(ByteConverter.GetBytes(-1));
                chunk.AddRange(strbytes);
                file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Morph));
                file.AddRange(ByteConverter.GetBytes(chunk.Count));
                file.AddRange(chunk);
            }
            if (!string.IsNullOrEmpty(author))
            {
                List<byte> chunk = new List<byte>(author.Length + 1);
                chunk.AddRange(Encoding.UTF8.GetBytes(author));
                chunk.Add(0);
                chunk.Align(4);
                file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Author));
                file.AddRange(ByteConverter.GetBytes(chunk.Count));
                file.AddRange(chunk);
            }
            if (!string.IsNullOrEmpty(description))
            {
                List<byte> chunk = new List<byte>(description.Length + 1);
                chunk.AddRange(Encoding.UTF8.GetBytes(description));
                chunk.Add(0);
                chunk.Align(4);
                file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Description));
                file.AddRange(ByteConverter.GetBytes(chunk.Count));
                file.AddRange(chunk);
            }
            if (!string.IsNullOrEmpty(tool))
            {
                List<byte> chunk = new List<byte>(tool.Length + 1);
                chunk.AddRange(Encoding.UTF8.GetBytes(tool));
                chunk.Add(0);
                chunk.Align(4);
                file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Tool));
                file.AddRange(ByteConverter.GetBytes(chunk.Count));
                file.AddRange(chunk);
            }
            if (metadata != null)
            {
                foreach (KeyValuePair<uint, byte[]> item in metadata)
                {
                    file.AddRange(ByteConverter.GetBytes(item.Key));
                    file.AddRange(ByteConverter.GetBytes(item.Value.Length));
                    file.AddRange(item.Value);
                }
            }
            file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.End));
            file.AddRange(new byte[4]);
            File.WriteAllBytes(filename, file.ToArray());
            ByteConverter.BigEndian = be;
        }
Example #25
0
 public override void Init(ObjectData data, string name, Device dev)
 {
     model = ObjectHelper.LoadModel("Objects/Common/Dash Panel.sa1mdl");
     meshes = ObjectHelper.GetMeshes(model, dev);
 }
Example #26
0
        public static void CreateFile(string filename, NJS_OBJECT model, string[] animationFiles, string[] morphFiles,
                                      string author, string description, string tool, Dictionary <uint, byte[]> metadata, ModelFormat format)
        {
            bool be = ByteConverter.BigEndian;

            ByteConverter.BigEndian = false;
            if (format == ModelFormat.BasicDX)
            {
                format = ModelFormat.Basic;
            }
            List <byte> file = new List <byte>();
            ulong       magic;

            switch (format)
            {
            case ModelFormat.Basic:
            case ModelFormat.BasicDX:
                magic = SA1MDLVer;
                break;

            case ModelFormat.Chunk:
                magic = SA2MDLVer;
                break;

            default:
                throw new ArgumentException("Cannot save " + format.ToString() + " format models to file!", "format");
            }
            file.AddRange(ByteConverter.GetBytes(magic));
            Dictionary <string, uint> labels = new Dictionary <string, uint>();

            byte[] mdl = model.GetBytes(0x10, false, labels, out uint addr);
            file.AddRange(ByteConverter.GetBytes(addr + 0x10));
            file.AddRange(ByteConverter.GetBytes(mdl.Length + 0x10));
            file.AddRange(mdl);

            if (labels.Count > 0)
            {
                List <byte> chunk    = new List <byte>((labels.Count * 8) + 8);
                int         straddr  = (labels.Count * 8) + 8;
                List <byte> strbytes = new List <byte>();
                foreach (KeyValuePair <string, uint> label in labels)
                {
                    chunk.AddRange(ByteConverter.GetBytes(label.Value));
                    chunk.AddRange(ByteConverter.GetBytes(straddr + strbytes.Count));
                    strbytes.AddRange(Encoding.UTF8.GetBytes(label.Key));
                    strbytes.Add(0);
                    strbytes.Align(4);
                }
                chunk.AddRange(ByteConverter.GetBytes(-1L));
                chunk.AddRange(strbytes);
                file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Label));
                file.AddRange(ByteConverter.GetBytes(chunk.Count));
                file.AddRange(chunk);
            }
            if (animationFiles != null && animationFiles.Length > 0)
            {
                List <byte> chunk    = new List <byte>((animationFiles.Length + 1) * 4);
                int         straddr  = (animationFiles.Length + 1) * 4;
                List <byte> strbytes = new List <byte>();
                for (int i = 0; i < animationFiles.Length; i++)
                {
                    chunk.AddRange(ByteConverter.GetBytes(straddr + strbytes.Count));
                    strbytes.AddRange(Encoding.UTF8.GetBytes(animationFiles[i]));
                    strbytes.Add(0);
                    strbytes.Align(4);
                }
                chunk.AddRange(ByteConverter.GetBytes(-1));
                chunk.AddRange(strbytes);
                file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Animation));
                file.AddRange(ByteConverter.GetBytes(chunk.Count));
                file.AddRange(chunk);
            }
            if (morphFiles != null && morphFiles.Length > 0)
            {
                List <byte> chunk    = new List <byte>((morphFiles.Length + 1) * 4);
                int         straddr  = (morphFiles.Length + 1) * 4;
                List <byte> strbytes = new List <byte>();
                for (int i = 0; i < morphFiles.Length; i++)
                {
                    chunk.AddRange(ByteConverter.GetBytes(straddr + strbytes.Count));
                    strbytes.AddRange(Encoding.UTF8.GetBytes(morphFiles[i]));
                    strbytes.Add(0);
                    strbytes.Align(4);
                }
                chunk.AddRange(ByteConverter.GetBytes(-1));
                chunk.AddRange(strbytes);
                file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Morph));
                file.AddRange(ByteConverter.GetBytes(chunk.Count));
                file.AddRange(chunk);
            }
            if (!string.IsNullOrEmpty(author))
            {
                List <byte> chunk = new List <byte>(author.Length + 1);
                chunk.AddRange(Encoding.UTF8.GetBytes(author));
                chunk.Add(0);
                chunk.Align(4);
                file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Author));
                file.AddRange(ByteConverter.GetBytes(chunk.Count));
                file.AddRange(chunk);
            }
            if (!string.IsNullOrEmpty(description))
            {
                List <byte> chunk = new List <byte>(description.Length + 1);
                chunk.AddRange(Encoding.UTF8.GetBytes(description));
                chunk.Add(0);
                chunk.Align(4);
                file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Description));
                file.AddRange(ByteConverter.GetBytes(chunk.Count));
                file.AddRange(chunk);
            }
            if (!string.IsNullOrEmpty(tool))
            {
                List <byte> chunk = new List <byte>(tool.Length + 1);
                chunk.AddRange(Encoding.UTF8.GetBytes(tool));
                chunk.Add(0);
                chunk.Align(4);
                file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Tool));
                file.AddRange(ByteConverter.GetBytes(chunk.Count));
                file.AddRange(chunk);
            }
            if (metadata != null)
            {
                foreach (KeyValuePair <uint, byte[]> item in metadata)
                {
                    file.AddRange(ByteConverter.GetBytes(item.Key));
                    file.AddRange(ByteConverter.GetBytes(item.Value.Length));
                    file.AddRange(item.Value);
                }
            }
            file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.End));
            file.AddRange(new byte[4]);
            File.WriteAllBytes(filename, file.ToArray());
            ByteConverter.BigEndian = be;
        }
Example #27
0
 public NJS_OBJECT(Scene scene, Node node, NJS_OBJECT parent, string[] textures = null)
 {
     Parent = parent;
     AssimpLoad(scene, node, textures);
 }
Example #28
0
 public void AddChild(NJS_OBJECT child)
 {
     children.Add(child);
     child.Parent = this;
 }
Example #29
0
        //
        void AssimpLoad(Scene scene, Node node, string[] textures = null)
        {
            Name = node.Name;
            Vector3D   translation;
            Vector3D   scaling;
            Quaternion rotation;

            node.Transform.Decompose(out scaling, out rotation, out translation);
            Vector3D rotationConverted = Extensions.FromQ2(rotation);

            Position = new Vertex(translation.X, translation.Y, translation.Z);
            Rotation = new Rotation(Rotation.DegToBAMS(rotationConverted.X), Rotation.DegToBAMS(rotationConverted.Y), Rotation.DegToBAMS(rotationConverted.Z));
            Scale    = new Vertex(scaling.X, scaling.Y, scaling.Z);
            List <Mesh> meshes = new List <Mesh>();

            foreach (int i in node.MeshIndices)
            {
                meshes.Add(scene.Meshes[i]);
            }
            //materials.Add(new NJS_MATERIAL() { DiffuseColor = System.Drawing.Color.White});
            if (node.HasMeshes)
            {
                Attach = new BasicAttach(scene.Materials, meshes, textures);
            }
            else
            {
                Attach = null;
            }
            if (node.HasChildren)
            {
                //List<NJS_OBJECT> list = new List<NJS_OBJECT>(node.Children.Select(a => new NJS_OBJECT(scene, a, this)));
                List <NJS_OBJECT> list = new List <NJS_OBJECT>();
                foreach (Node n in node.Children)
                {
                    NJS_OBJECT t = new NJS_OBJECT(scene, n, this, textures);
                    //HACK: workaround for those weird empty nodes created by most 3d editors
                    if (n.Name == "")
                    {
                        t.Children[0].Position = t.Position;
                        t.Children[0].Rotation = t.Rotation;
                        t.Children[0].Scale    = t.Scale;
                        list.Add(t.Children[0]);
                    }
                    else
                    {
                        list.Add(t);
                    }

                    /*if (Parent != null)
                     * {
                     *      if (t.Attach != null)
                     *      {
                     *              Parent.Attach = t.Attach;
                     *              if (Parent.children != null && t.children.Count > 0)
                     *                      Parent.children.AddRange(t.children);
                     *      }
                     *      else
                     *              list.Add(t);
                     * }*/
                }
                Children = new ReadOnlyCollection <NJS_OBJECT>(list.ToArray());
            }
            else
            {
                Children = new ReadOnlyCollection <NJS_OBJECT>(new List <NJS_OBJECT>().ToArray());
            }
        }
Example #30
0
 static void Main(string[] args)
 {
     string dir = Environment.CurrentDirectory;
     try
     {
         Queue<string> argq = new Queue<string>(args);
         if (argq.Count > 0 && argq.Peek().Equals("/be", StringComparison.OrdinalIgnoreCase))
         {
             ByteConverter.BigEndian = true;
             argq.Dequeue();
         }
         string mdlfilename;
         if (argq.Count > 0)
         {
             mdlfilename = argq.Dequeue();
             Console.WriteLine("File: {0}", mdlfilename);
         }
         else
         {
             Console.Write("File: ");
             mdlfilename = Console.ReadLine();
         }
         mdlfilename = Path.GetFullPath(mdlfilename);
         string[] anifilenames = new string[argq.Count];
         for (int j = 0; j < anifilenames.Length; j++)
         {
             Console.WriteLine("Animations: {0}", argq.Peek());
             anifilenames[j] = Path.GetFullPath(argq.Dequeue());
         }
         Environment.CurrentDirectory = Path.GetDirectoryName(mdlfilename);
         byte[] mdlfile = File.ReadAllBytes(mdlfilename);
         if (Path.GetExtension(mdlfilename).Equals(".prs", StringComparison.OrdinalIgnoreCase))
             mdlfile = FraGag.Compression.Prs.Decompress(mdlfile);
         Directory.CreateDirectory(Path.GetFileNameWithoutExtension(mdlfilename));
         int address = 0;
         int i = ByteConverter.ToInt32(mdlfile, address);
         SortedDictionary<int, int> modeladdrs = new SortedDictionary<int, int>();
         while (i != -1)
         {
             modeladdrs[i] = ByteConverter.ToInt32(mdlfile, address + 4);
             address += 8;
             i = ByteConverter.ToInt32(mdlfile, address);
         }
         Dictionary<int, SonicRetro.SAModel.NJS_OBJECT> models = new Dictionary<int, SonicRetro.SAModel.NJS_OBJECT>();
         Dictionary<int, string> modelnames = new Dictionary<int, string>();
         List<string> partnames = new List<string>();
         foreach (KeyValuePair<int, int> item in modeladdrs)
         {
             SonicRetro.SAModel.NJS_OBJECT obj = new SonicRetro.SAModel.NJS_OBJECT(mdlfile, item.Value, 0, ModelFormat.Chunk);
             modelnames[item.Key] = obj.Name;
             if (!partnames.Contains(obj.Name))
             {
                 models[item.Key] = obj;
                 partnames.AddRange(obj.GetObjects().Select((o) => o.Name));
             }
         }
         Dictionary<int, string> animfns = new Dictionary<int, string>();
         Dictionary<int, Animation> anims = new Dictionary<int, Animation>();
         foreach (string anifilename in anifilenames)
         {
             byte[] anifile = File.ReadAllBytes(anifilename);
             if (Path.GetExtension(anifilename).Equals(".prs", StringComparison.OrdinalIgnoreCase))
                 anifile = FraGag.Compression.Prs.Decompress(anifile);
             Directory.CreateDirectory(Path.GetFileNameWithoutExtension(anifilename));
             address = 0;
             i = ByteConverter.ToInt16(anifile, address);
             while (i != -1)
             {
                 anims[i] = new Animation(anifile, ByteConverter.ToInt32(anifile, address + 4), 0, ByteConverter.ToInt16(anifile, address + 2));
                 animfns[i] = Path.Combine(Path.GetFileNameWithoutExtension(anifilename), i.ToString(NumberFormatInfo.InvariantInfo) + ".saanim");
                 address += 8;
                 i = ByteConverter.ToInt16(anifile, address);
             }
         }
         foreach (KeyValuePair<int, SonicRetro.SAModel.NJS_OBJECT> model in models)
         {
             List<string> animlist = new List<string>();
             foreach (KeyValuePair<int, Animation> anim in anims)
                 if (model.Value.CountAnimated() == anim.Value.ModelParts)
                     animlist.Add("../" + animfns[anim.Key]);
             ModelFile.CreateFile(Path.Combine(Path.GetFileNameWithoutExtension(mdlfilename),
                 model.Key.ToString(NumberFormatInfo.InvariantInfo) + ".sa2mdl"), model.Value, animlist.ToArray(),
                 null, null, null, "splitMDL", null, ModelFormat.Chunk);
         }
         IniSerializer.Serialize(modelnames, new IniCollectionSettings(IniCollectionMode.IndexOnly),
             Path.Combine(Path.GetFileNameWithoutExtension(mdlfilename), Path.GetFileNameWithoutExtension(mdlfilename) + ".ini"));
         foreach (KeyValuePair<int, Animation> anim in anims)
             anim.Value.Save(animfns[anim.Key]);
     }
     finally
     {
         Environment.CurrentDirectory = dir;
     }
 }
Example #31
0
 public NJS_OBJECT ToChunkModel()
 {
     List<NJS_OBJECT> newchildren = new List<NJS_OBJECT>(Children.Count);
     foreach (NJS_OBJECT item in Children)
         newchildren.Add(item.ToBasicModel());
     NJS_OBJECT result = new NJS_OBJECT();
     if (Attach != null)
         result.Attach = Attach.ToChunkModel();
     result.Position = Position;
     result.Rotation = Rotation;
     result.Scale = Scale;
     result.Children = newchildren;
     return result;
 }
Example #32
0
 public override void Init(IniLevelData data, byte act, Device dev)
 {
     carriermdl = ObjectHelper.LoadModel("Levels/Sky Chase/Egg Carrier model.sa1mdl");
     carriermesh = ObjectHelper.GetMeshes(carriermdl, dev);
 }
Example #33
0
 public void InsertChild(int index, NJS_OBJECT child)
 {
     children.Insert(index, child);
     child.Parent = this;
 }
Example #34
0
        public ModelFile(string filename)
        {
            int  tmpaddr;
            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 SA1MDL/SA2MDL file.");
            }
            Metadata = new Dictionary <uint, byte[]>();
            Dictionary <int, string> labels = new Dictionary <int, string>();

            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);
                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 <Animation> anims = new List <Animation>();
                foreach (string item in animationFiles)
                {
                    anims.Add(Animation.Load(Path.Combine(path, item), Model.CountAnimated()));
                }
                Animations = anims.AsReadOnly();
                if (version == 1)
                {
                    tmpaddr = ByteConverter.ToInt32(file, 0x10);
                    if (tmpaddr != 0)
                    {
                        List <string> morphfiles = new List <string>();
                        int           addr       = ByteConverter.ToInt32(file, tmpaddr);
                        while (addr != -1)
                        {
                            morphfiles.Add(file.GetCString(addr));
                            tmpaddr += 4;
                            addr     = ByteConverter.ToInt32(file, tmpaddr);
                        }
                        morphFiles = morphfiles.ToArray();
                    }
                    else
                    {
                        morphFiles = new string[0];
                    }
                    List <Animation> morphs = new List <Animation>();
                    foreach (string item in morphFiles)
                    {
                        morphs.Add(Animation.Load(Path.Combine(path, item), Model.CountMorph()));
                    }
                    Morphs = morphs.AsReadOnly();
                }
                else
                {
                    morphFiles = new string[0];
                    Morphs     = new ReadOnlyCollection <Animation>(new List <Animation>());
                }
            }
            else
            {
                animationFiles = new string[0];
                morphFiles     = 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:
                                List <string> morphfiles = new List <string>();
                                while (ByteConverter.ToInt32(file, tmpaddr) != -1)
                                {
                                    morphfiles.Add(file.GetCString(ByteConverter.ToInt32(file, tmpaddr)));
                                    tmpaddr += 4;
                                }
                                morphFiles = morphfiles.ToArray();
                                break;

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

                            case ChunkTypes.Tool:
                                Tool = file.GetCString(tmpaddr);
                                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:
                                List <string> morphchunks = new List <string>();
                                while (ByteConverter.ToInt32(chunk, chunkaddr) != -1)
                                {
                                    morphchunks.Add(chunk.GetCString(ByteConverter.ToInt32(chunk, chunkaddr)));
                                    chunkaddr += 4;
                                }
                                morphFiles = morphchunks.ToArray();
                                break;

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

                            case ChunkTypes.Tool:
                                Tool = chunk.GetCString(chunkaddr);
                                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;

                default:
                    throw new FormatException("Not a valid SA1MDL/SA2MDL file.");
                }
                Model = new NJS_OBJECT(file, ByteConverter.ToInt32(file, 8), 0, Format, labels);
                string           path  = Path.GetDirectoryName(filename);
                List <Animation> anims = new List <Animation>();
                foreach (string item in animationFiles)
                {
                    anims.Add(Animation.Load(Path.Combine(path, item), Model.CountAnimated()));
                }
                Animations = anims.AsReadOnly();
                List <Animation> morphs = new List <Animation>();
                foreach (string item in morphFiles)
                {
                    morphs.Add(Animation.Load(Path.Combine(path, item), Model.CountMorph()));
                }
                Morphs = morphs.AsReadOnly();
            }
            ByteConverter.BigEndian = be;
        }
Example #35
0
 public void RemoveChild(NJS_OBJECT child)
 {
     children.Remove(child);
     child.Parent = null;
 }
Example #36
0
        public override BoundingSphere GetBounds(SETItem item, NJS_OBJECT model)
        {
            BoundingSphere bounds = new BoundingSphere(item.Position, item.Scale.X);

            return bounds;
        }
Example #37
0
 public AnimationHeader(byte[] file, int address, uint imageBase, ModelFormat format, Dictionary<int, string> labels)
 {
     Model = new NJS_OBJECT(file, (int)(ByteConverter.ToUInt32(file, address) - imageBase), imageBase, format);
     Animation = new Animation(file, (int)(ByteConverter.ToUInt32(file, address + 4) - imageBase), imageBase,
         Model.CountAnimated(), labels);
 }
Example #38
0
 public override void Init(ObjectData data, string name, Device dev)
 {
     model = ObjectHelper.LoadModel("Objects/Collision/Cylinder.sa1mdl");
     meshes = ObjectHelper.GetMeshes(model, dev);
 }
Example #39
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;

                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;
        }