private static void SerializeObject(BinaryWriter bw, Polymodel model, short version)
        {
            int size     = 32;
            int padBytes = 0;

            if (version >= 8)
            {
                padBytes = 4 - (((int)bw.BaseStream.Position + size + 8) % 4);
                if (padBytes == 4)
                {
                    padBytes = 0;
                }
                size += padBytes;
            }
            bw.Write(0x5244484F);
            bw.Write(size);
            bw.Write(model.NumSubmodels);
            bw.Write(model.Radius.value);
            bw.Write(model.Mins.X.value);
            bw.Write(model.Mins.Y.value);
            bw.Write(model.Mins.Z.value);
            bw.Write(model.Maxs.X.value);
            bw.Write(model.Maxs.Y.value);
            bw.Write(model.Maxs.Z.value);
            for (int i = 0; i < padBytes; i++)
            {
                bw.Write((byte)0);
            }
        }
        private static void SerializeAnim(BinaryWriter bw, Polymodel model, short version)
        {
            int size     = 2 + 6 * model.NumSubmodels * Robot.NumAnimationStates;
            int padBytes = 0;

            if (version >= 8)
            {
                padBytes = 4 - (((int)bw.BaseStream.Position + size + 8) % 4);
                if (padBytes == 4)
                {
                    padBytes = 0;
                }
                size += padBytes;
            }
            bw.Write(0x4D494E41);
            bw.Write(size);
            bw.Write((short)Robot.NumAnimationStates);
            for (int i = 0; i < model.NumSubmodels; i++)
            {
                for (int f = 0; f < Robot.NumAnimationStates; f++)
                {
                    bw.Write(model.AnimationMatrix[i, f].P);
                    bw.Write(model.AnimationMatrix[i, f].B);
                    bw.Write(model.AnimationMatrix[i, f].H);
                }
            }

            for (int i = 0; i < padBytes; i++)
            {
                bw.Write((byte)0);
            }
        }
        private static void SerializeTextures(BinaryWriter bw, Polymodel model, short version)
        {
            int size     = 2;
            int padBytes = 0;

            foreach (string texture in model.TextureList)
            {
                size += texture.Length + 1;
            }
            if (version >= 8)
            {
                padBytes = 4 - (((int)bw.BaseStream.Position + size + 8) % 4);
                if (padBytes == 4)
                {
                    padBytes = 0;
                }
                size += padBytes;
            }
            bw.Write(0x52545854);
            bw.Write(size);
            bw.Write((short)model.TextureList.Count);
            foreach (string texture in model.TextureList)
            {
                size += texture.Length + 1;
                for (int i = 0; i < texture.Length; i++)
                {
                    bw.Write((byte)texture[i]);
                }
                bw.Write((byte)0);
            }
            for (int i = 0; i < padBytes; i++)
            {
                bw.Write((byte)0);
            }
        }
        private static void SerializeGuns(BinaryWriter bw, Polymodel model, short version)
        {
            int size;

            if (version >= 7)
            {
                size = (model.NumGuns * 28) + 4;
            }
            else
            {
                size = (model.NumGuns * 16) + 4;
            }
            bw.Write(0x534E5547);
            bw.Write(size);
            bw.Write(model.NumGuns);
            for (int i = 0; i < model.NumGuns; i++)
            {
                bw.Write((short)i);
                bw.Write((short)model.GunSubmodels[i]);
                bw.Write(model.GunPoints[i].X.value);
                bw.Write(model.GunPoints[i].Y.value);
                bw.Write(model.GunPoints[i].Z.value);
                if (version >= 7)
                {
                    bw.Write(model.GunDirs[i].X.value);
                    bw.Write(model.GunDirs[i].Y.value);
                    bw.Write(model.GunDirs[i].Z.value);
                }
            }
        }
Beispiel #5
0
        public Descent1PIGFile(bool macPig = false, bool loadData = true)
        {
            Textures  = new ushort[800];
            TMapInfo  = new TMAPInfo[800];
            SoundIDs  = new byte[250];
            AltSounds = new byte[250];
            VClips    = new VClip[70];
            EClips    = new EClip[60];
            WClips    = new WClip[30];
            Robots    = new Robot[30];
            Joints    = new JointPos[600];
            Weapons   = new Weapon[30];
            Models    = new Polymodel[85];
            if (macPig)
            {
                Gauges = new ushort[85];
            }
            else
            {
                Gauges = new ushort[80];
            }
            ObjBitmaps        = new ushort[210];
            ObjBitmapPointers = new ushort[210];
            Cockpits          = new ushort[4];
            ObjectTypes       = new EditorObjectDefinition[100];
            Powerups          = new Powerup[29];
            BitmapXLATData    = new ushort[1800];
            reactor           = new Reactor();

            Bitmaps = new List <PIGImage>();
            Sounds  = new List <SoundData>();

            this.big      = macPig;
            this.LoadData = loadData;
        }
Beispiel #6
0
 public void WritePolymodel(Polymodel model, BinaryWriter bw)
 {
     bw.Write(model.NumSubmodels);
     bw.Write(model.ModelIDTASize);
     bw.Write(model.ModelIDTAPointer);
     for (int s = 0; s < 10; s++)
     {
         bw.Write(model.Submodels[s].Pointer);
     }
     for (int s = 0; s < 10; s++)
     {
         bw.Write(model.Submodels[s].Offset.X.value);
         bw.Write(model.Submodels[s].Offset.Y.value);
         bw.Write(model.Submodels[s].Offset.Z.value);
     }
     for (int s = 0; s < 10; s++)
     {
         bw.Write(model.Submodels[s].Normal.X.value);
         bw.Write(model.Submodels[s].Normal.Y.value);
         bw.Write(model.Submodels[s].Normal.Z.value);
     }
     for (int s = 0; s < 10; s++)
     {
         bw.Write(model.Submodels[s].Point.X.value);
         bw.Write(model.Submodels[s].Point.Y.value);
         bw.Write(model.Submodels[s].Point.Z.value);
     }
     for (int s = 0; s < 10; s++)
     {
         bw.Write(model.Submodels[s].Radius.value);
     }
     for (int s = 0; s < 10; s++)
     {
         bw.Write(model.Submodels[s].Parent);
     }
     for (int s = 0; s < 10; s++)
     {
         bw.Write(model.Submodels[s].Mins.X.value);
         bw.Write(model.Submodels[s].Mins.Y.value);
         bw.Write(model.Submodels[s].Mins.Z.value);
     }
     for (int s = 0; s < 10; s++)
     {
         bw.Write(model.Submodels[s].Maxs.X.value);
         bw.Write(model.Submodels[s].Maxs.Y.value);
         bw.Write(model.Submodels[s].Maxs.Z.value);
     }
     bw.Write(model.Mins.X.value);
     bw.Write(model.Mins.Y.value);
     bw.Write(model.Mins.Z.value);
     bw.Write(model.Maxs.X.value);
     bw.Write(model.Maxs.Y.value);
     bw.Write(model.Maxs.Z.value);
     bw.Write(model.Radius.value);
     bw.Write(model.NumTextures);
     bw.Write(model.FirstTexture);
     bw.Write(model.SimplerModels);
 }
Beispiel #7
0
        public void RebuildModel(Polymodel model)
        {
            currentModel = model;
            List <BSPModel> data = ExtractModelData(model);

            submodels = data;
            BuildBSPTrees(data);

            RebuildModel(model, data);
        }
Beispiel #8
0
        private List <BSPModel> ExtractModelData(Polymodel model)
        {
            PolymodelExtractor me = new PolymodelExtractor();

            me.SetModel(model);

            var data = me.Extract();

            if (me.IsPartitioned)
            {
                throw new ArgumentException("Model is already partitioned. Further partitioning will bloat data.");
            }
            return(data);
        }
 public PSXDatFile()
 {
     Textures          = new ushort[800];
     TMapInfo          = new TMAPInfo[800];
     Sounds            = new byte[250];
     AltSounds         = new byte[250];
     VClips            = new VClip[70];
     EClips            = new EClip[60];
     WClips            = new WClip[30];
     Robots            = new Robot[30];
     Joints            = new JointPos[600];
     Weapons           = new Weapon[30];
     Models            = new Polymodel[85];
     Gauges            = new ushort[80];
     ObjBitmaps        = new ushort[210];
     ObjBitmapPointers = new ushort[210];
     Cockpits          = new ushort[4];
     ObjectTypes       = new EditorObjectDefinition[100];
     Powerups          = new Powerup[29];
     BitmapXLATData    = new ushort[1800];
     reactor           = new Reactor();
 }
Beispiel #10
0
 public static void SerializePolymodel(BinaryWriter bw, Polymodel model, short version)
 {
     bw.Write(0x4F505350);
     bw.Write(version);
     if (model.NumTextures > 0)
     {
         SerializeTextures(bw, model, version);
     }
     SerializeObject(bw, model, version);
     for (int i = 0; i < model.NumSubmodels; i++)
     {
         SerializeSubobject(bw, i, model.Submodels[i], version);
     }
     if (model.NumGuns > 0)
     {
         SerializeGuns(bw, model, version);
     }
     if (model.IsAnimated)
     {
         SerializeAnim(bw, model, version);
     }
     SerializeIDTA(bw, model, version);
 }
Beispiel #11
0
        private static void SerializeIDTA(BinaryWriter bw, Polymodel model, short version)
        {
            int size     = model.ModelIDTASize;
            int padBytes = 0;

            if (version >= 8)
            {
                padBytes = 4 - (((int)bw.BaseStream.Position + size + 8) % 4);
                if (padBytes == 4)
                {
                    padBytes = 0;
                }
                size += padBytes;
            }
            bw.Write(0x41544449);
            bw.Write(size);
            bw.Write(model.InterpreterData);

            for (int i = 0; i < padBytes; i++)
            {
                bw.Write((byte)0);
            }
        }
Beispiel #12
0
        private void RebuildModel(Polymodel newModel, List <BSPModel> bspModels)
        {
            int offset       = 0;
            int vertexOffset = 0;

            //global scratch space.
            var data = new byte[1024 * 1024];

            /*for (int i = 0; i < bspModels.Count; i++)
             * {
             *  bspModels[i].CompileInterpreterData(vertexOffset);
             *  vertexOffset += bspModels[i].NumVertices;
             *  if (vertexOffset > 1000)
             *      throw new ArgumentException("Model has too many vertices after partitioning.");
             * }*/

            MetaInstructionBase hierarchy = this.GetHierarchy(0);

            hierarchy.Write(data, ref offset);
            SetShort(data, ref offset, 0);

            newModel.ModelIDTASize   = offset;
            newModel.InterpreterData = data.Take(offset).ToArray();
        }
        private void Execute(byte[] data, int offset, Polymodel mainModel, Submodel model, BSPModel currentModel)
        {
            short instruction = GetShort(data, ref offset);

            while (true)
            {
                switch (instruction)
                {
                case ModelOpCode.End:
                    return;

                case ModelOpCode.Points:
                {
                    short pointc = GetShort(data, ref offset);
                    for (int i = 0; i < pointc; i++)
                    {
                        interpPoints[i] = GetFixVector(data, ref offset);
                    }
                }
                break;

                case ModelOpCode.FlatPoly:     //FLATPOLY
                {
                    short     pointc = GetShort(data, ref offset);
                    FixVector point  = GetFixVector(data, ref offset);
                    FixVector normal = GetFixVector(data, ref offset);
                    short     color  = GetShort(data, ref offset);

                    short[] points = new short[pointc];         //TODO: seems wasteful to do all these allocations?
                    for (int i = 0; i < pointc; i++)
                    {
                        points[i] = GetShort(data, ref offset);
                    }
                    if (pointc % 2 == 0)
                    {
                        GetShort(data, ref offset);
                    }

                    if (pointc >= 3)
                    {
                        var triangle = new BSPFace();

                        triangle.Normal    = new Vector3(normal.X, normal.Y, normal.Z);
                        triangle.Point     = new Vector3(point.X, point.Y, point.Z);
                        triangle.Color     = color;
                        triangle.TextureID = -1;

                        currentModel.Polygons.Add(triangle);

                        for (int i = 0; i < pointc; i++)
                        {
                            var vxA = interpPoints[points[i]].X;
                            var vyA = interpPoints[points[i]].Y;
                            var vzA = interpPoints[points[i]].Z;

                            triangle.Points.Add(new BSPVertex {
                                    Point = new Vector3(vxA, vyA, vzA), UVs = new Vector3(0.0f, 0.0f, 0.0f)
                                });
                        }
                    }
                }
                break;

                case ModelOpCode.TexturedPoly:     //TMAPPOLY
                {
                    short     pointc  = GetShort(data, ref offset);
                    FixVector point   = GetFixVector(data, ref offset);
                    FixVector normal  = GetFixVector(data, ref offset);
                    short     texture = GetShort(data, ref offset);

                    short[]     points = new short[pointc];     //TODO: seems wasteful to do all these allocations?
                    FixVector[] uvls   = new FixVector[pointc];
                    for (int i = 0; i < pointc; i++)
                    {
                        points[i] = GetShort(data, ref offset);
                    }
                    if (pointc % 2 == 0)
                    {
                        GetShort(data, ref offset);
                    }

                    for (int i = 0; i < pointc; i++)
                    {
                        uvls[i] = GetFixVector(data, ref offset);
                    }

                    if (pointc >= 3)
                    {
                        var triangle = new BSPFace();

                        triangle.Normal    = new Vector3(normal.X, normal.Y, normal.Z);
                        triangle.Point     = new Vector3(point.X, point.Y, point.Z);
                        triangle.TextureID = texture;
                        currentModel.Polygons.Add(triangle);

                        for (int i = 0; i < pointc; i++)
                        {
                            var vxA = interpPoints[points[i]].X;
                            var vyA = interpPoints[points[i]].Y;
                            var vzA = interpPoints[points[i]].Z;

                            var uvxA = uvls[i].X;
                            var uvyA = uvls[i].Y;

                            triangle.Points.Add(new BSPVertex {
                                    Point = new Vector3(vxA, vyA, vzA), UVs = new Vector3(uvxA, uvyA, 0.0f)
                                });
                        }
                    }
                }
                break;

                case ModelOpCode.SortNormal:     //SORTNORM
                {
                    IsPartitioned = true;
                    int       baseOffset  = offset - 2;
                    int       n_points    = GetShort(data, ref offset);
                    FixVector norm        = GetFixVector(data, ref offset);
                    FixVector point       = GetFixVector(data, ref offset);
                    short     backOffset  = GetShort(data, ref offset);
                    short     frontOffset = GetShort(data, ref offset);

                    Execute(data, baseOffset + frontOffset, mainModel, model, currentModel);
                    Execute(data, baseOffset + backOffset, mainModel, model, currentModel);
                }
                break;

                case ModelOpCode.Rod:     //RODBM
                {
                    offset += 34;
                }
                break;

                case ModelOpCode.SubCall:     //SUBCALL
                {
                    int       baseOffset     = offset - 2;
                    short     submodelNum    = GetShort(data, ref offset);
                    FixVector submodelOffset = GetFixVector(data, ref offset);
                    short     modelOffset    = GetShort(data, ref offset);
                    offset += 2;

                    Submodel newModel = mainModel.Submodels[submodelNum];

                    currentModel.modelOffset = submodelOffset;

                    Execute(data, baseOffset + modelOffset, mainModel, newModel, modelDatas[submodelNum]);
                }
                break;

                case ModelOpCode.DefinePointStart:     //DEFPSTART
                {
                    short pointc     = GetShort(data, ref offset);
                    short firstPoint = GetShort(data, ref offset);
                    offset += 2;

                    for (int i = 0; i < pointc; i++)
                    {
                        interpPoints[i + firstPoint] = GetFixVector(data, ref offset);
                    }
                }
                break;

                case ModelOpCode.Glow:
                    offset += 2;
                    break;

                default:
                    throw new Exception(string.Format("Unknown interpreter instruction {0} at offset {1}\n", instruction, offset));
                }
                instruction = GetShort(data, ref offset);
            }
        }
 public void SetModel(Polymodel model)
 {
     this.model = model;
 }
Beispiel #15
0
        /// <summary>
        /// Loads an HXM file from a given stream.
        /// </summary>
        /// <param name="stream">The stream to load the HXM data from.</param>
        public void Read(Stream stream)
        {
            BinaryReader br;

            br = new BinaryReader(stream);

            HAMDataReader data = new HAMDataReader();

            int sig = br.ReadInt32();
            int ver = br.ReadInt32();

            if (sig != 559435080)
            {
                br.Dispose();
                throw new InvalidDataException("HXMFile::Read: HXM file has bad header.");
            }
            if (ver != 1)
            {
                br.Dispose();
                throw new InvalidDataException(string.Format("HXMFile::Read: HXM file has bad version. Got {0}, but expected 1", ver));
            }

            int replacedRobotCount = br.ReadInt32();

            for (int x = 0; x < replacedRobotCount; x++)
            {
                int   replacementID = br.ReadInt32();
                Robot robot         = data.ReadRobot(br);
                robot.replacementID = replacementID;
                ReplacedRobots.Add(robot);
            }
            int replacedJointCount = br.ReadInt32();

            for (int x = 0; x < replacedJointCount; x++)
            {
                int      replacementID = br.ReadInt32();
                JointPos joint         = new JointPos();
                joint.JointNum      = br.ReadInt16();
                joint.Angles.P      = br.ReadInt16();
                joint.Angles.B      = br.ReadInt16();
                joint.Angles.H      = br.ReadInt16();
                joint.ReplacementID = replacementID;
                ReplacedJoints.Add(joint);
            }
            int modelsToReplace = br.ReadInt32();

            for (int x = 0; x < modelsToReplace; x++)
            {
                int       replacementID = br.ReadInt32();
                Polymodel model         = data.ReadPolymodelInfo(br);
                model.ReplacementID   = replacementID;
                model.InterpreterData = br.ReadBytes(model.ModelIDTASize);
                ReplacedModels.Add(model);
                model.DyingModelnum = br.ReadInt32();
                model.DeadModelnum  = br.ReadInt32();
            }
            int objBitmapsToReplace = br.ReadInt32();

            for (int x = 0; x < objBitmapsToReplace; x++)
            {
                ReplacedBitmapElement objBitmap = new ReplacedBitmapElement();
                objBitmap.ReplacementID = br.ReadInt32();
                objBitmap.Data          = br.ReadUInt16();
                ReplacedObjBitmaps.Add(objBitmap);
                //Console.WriteLine("Loading replacement obj bitmap, replacing slot {0} with {1} ({2})", objBitmap.replacementID, objBitmap.data, baseFile.piggyFile.images[objBitmap.data].name);
            }
            int objBitmapPtrsToReplace = br.ReadInt32();

            for (int x = 0; x < objBitmapPtrsToReplace; x++)
            {
                ReplacedBitmapElement objBitmap = new ReplacedBitmapElement();
                objBitmap.ReplacementID = br.ReadInt32();
                objBitmap.Data          = br.ReadUInt16();
                ReplacedObjBitmapPtrs.Add(objBitmap);
            }
        }
Beispiel #16
0
        public static Polymodel ReadPOFFile(Stream stream)
        {
            BinaryReader br    = new BinaryReader(stream);
            Polymodel    model = new Polymodel();

            int   sig = br.ReadInt32();
            short ver = br.ReadInt16();

            if (ver < 6 || ver > 8)
            {
                throw new InvalidDataException(string.Format("POF File has unsupported version. Got {0}, but expected \"6\", \"7\", or \"8\".", ver));
            }

            int chunk    = br.ReadInt32();
            int datasize = br.ReadInt32();

            long dest = br.BaseStream.Position + datasize;

            while (true)
            {
                //1096041545
                switch (chunk)
                {
                //TXTR
                case 1381259348:
                {
                    short texcount = br.ReadInt16();
                    model.NumTextures = (byte)texcount;
                    for (int x = 0; x < texcount; x++)
                    {
                        char[] texchars = new char[128];
                        texchars[0] = (char)br.ReadByte();
                        int i = 1;
                        while (texchars[i - 1] != '\0')
                        {
                            texchars[i] = (char)br.ReadByte();
                            i++;
                        }
                        string name = new string(texchars);
                        name = name.Trim(' ', '\0');
                        model.TextureList.Add(name.ToLower());
                    }
                }
                break;

                //OHDR
                case 1380206671:
                {
                    model.NumSubmodels = br.ReadInt32();
                    model.Radius       = new Fix(br.ReadInt32());
                    model.Mins         = ReadVector(br);
                    model.Maxs         = ReadVector(br);
                    for (int i = 0; i < model.NumSubmodels; i++)
                    {
                        model.Submodels.Add(new Submodel());
                    }
                }
                break;

                //SOBJ
                case 1245859667:
                {
                    short    modelnum = br.ReadInt16();
                    Submodel submodel = model.Submodels[modelnum];
                    submodel.ID = modelnum;
                    short parentTest = br.ReadInt16();
                    submodel.Parent  = (byte)parentTest;
                    submodel.Normal  = ReadVector(br);
                    submodel.Point   = ReadVector(br);
                    submodel.Offset  = ReadVector(br);
                    submodel.Radius  = new Fix(br.ReadInt32());
                    submodel.Pointer = br.ReadInt32();
                    if (submodel.Parent != 255)
                    {
                        model.Submodels[submodel.Parent].Children.Add(submodel);
                    }
                }
                break;

                //GUNS
                case 0x534E5547:
                {
                    int numGuns = br.ReadInt32();
                    model.NumGuns = numGuns;
                    for (int i = 0; i < numGuns; i++)
                    {
                        short id = br.ReadInt16();
                        model.GunSubmodels[id] = br.ReadInt16();
                        model.GunPoints[id]    = ReadVector(br);
                        model.GunDirs[id]      = ReadVector(br);
                    }
                }
                break;

                //ANIM
                case 1296649793:
                {
                    model.IsAnimated = true;
                    //br.ReadBytes(datasize);
                    int numFrames = br.ReadInt16();
                    for (int submodel = 0; submodel < model.NumSubmodels; submodel++)
                    {
                        for (int i = 0; i < numFrames; i++)
                        {
                            if (i < 5)         //bounds check to avoid issues with more frames than intended
                            {
                                model.AnimationMatrix[submodel, i].P = br.ReadInt16();
                                model.AnimationMatrix[submodel, i].B = br.ReadInt16();
                                model.AnimationMatrix[submodel, i].H = br.ReadInt16();
                            }
                        }
                    }
                }
                break;

                //IDTA
                case 1096041545:
                {
                    //model.ModelIDTASize = datasize;
                    model.InterpreterData = br.ReadBytes(datasize);
                }
                break;

                default:
                    br.ReadBytes(datasize);
                    break;
                }
                //Maintain 4-byte alignment
                if (ver >= 8)
                {
                    br.BaseStream.Seek(dest, SeekOrigin.Begin);
                }
                if (br.BaseStream.Position >= br.BaseStream.Length)
                {
                    break;
                }
                chunk    = br.ReadInt32();
                datasize = br.ReadInt32();
                dest     = br.BaseStream.Position + datasize;
            }
            for (int i = 0; i < model.NumSubmodels; i++)
            {
                model.GetSubmodelMinMaxs(i);
            }

            br.Close();
            return(model);
        }
        public Polymodel ReadPolymodelInfoPSX(BinaryReader br)
        {
            Polymodel model = new Polymodel(Polymodel.MaxSubmodels);

            model.NumSubmodels     = br.ReadInt32();
            model.ModelIDTASize    = br.ReadInt32();
            model.ModelIDTAPointer = br.ReadInt32();
            for (int s = 0; s < Polymodel.MaxSubmodels; s++)
            {
                model.Submodels[s].Pointer = br.ReadInt32();
            }
            for (int s = 0; s < Polymodel.MaxSubmodels; s++)
            {
                model.Submodels[s].Offset.X = new Fix(br.ReadInt32());
                model.Submodels[s].Offset.Y = new Fix(br.ReadInt32());
                model.Submodels[s].Offset.Z = new Fix(br.ReadInt32());
            }
            for (int s = 0; s < Polymodel.MaxSubmodels; s++)
            {
                model.Submodels[s].Normal.X = new Fix(br.ReadInt32());
                model.Submodels[s].Normal.Y = new Fix(br.ReadInt32());
                model.Submodels[s].Normal.Z = new Fix(br.ReadInt32());
            }
            for (int s = 0; s < Polymodel.MaxSubmodels; s++)
            {
                model.Submodels[s].Point.X = new Fix(br.ReadInt32());
                model.Submodels[s].Point.Y = new Fix(br.ReadInt32());
                model.Submodels[s].Point.Z = new Fix(br.ReadInt32());
            }
            for (int s = 0; s < Polymodel.MaxSubmodels; s++)
            {
                model.Submodels[s].Radius = new Fix(br.ReadInt32());
            }
            for (int s = 0; s < Polymodel.MaxSubmodels; s++)
            {
                byte parent = br.ReadByte();
                model.Submodels[s].Parent = parent;
                if (parent != 255)
                {
                    model.Submodels[parent].Children.Add(model.Submodels[s]);
                }
            }
            short unk1 = br.ReadInt16();

            for (int s = 0; s < Polymodel.MaxSubmodels; s++)
            {
                model.Submodels[s].Mins.X = new Fix(br.ReadInt32());
                model.Submodels[s].Mins.Y = new Fix(br.ReadInt32());
                model.Submodels[s].Mins.Z = new Fix(br.ReadInt32());
            }
            for (int s = 0; s < Polymodel.MaxSubmodels; s++)
            {
                model.Submodels[s].Maxs.X = new Fix(br.ReadInt32());
                model.Submodels[s].Maxs.Y = new Fix(br.ReadInt32());
                model.Submodels[s].Maxs.Z = new Fix(br.ReadInt32());
            }
            model.Mins          = new FixVector(new Fix(br.ReadInt32()), new Fix(br.ReadInt32()), new Fix(br.ReadInt32()));
            model.Maxs          = new FixVector(new Fix(br.ReadInt32()), new Fix(br.ReadInt32()), new Fix(br.ReadInt32()));
            model.Radius        = new Fix(br.ReadInt32());
            model.NumTextures   = (byte)br.ReadInt16();
            model.FirstTexture  = br.ReadUInt16();
            model.SimplerModels = (byte)br.ReadInt16();
            short unk2 = br.ReadInt16();

            return(model);
        }