Mesh _AssembleStandardMesh(ShapeStream shapeStream, Mesh mesh)
        {
            try
            {
                if (mesh == null)
                    mesh = new Mesh();

                shapeStream.CheckGuard();

                mesh._numFrames = shapeStream.ReadS32();
                mesh._numMatFrames = shapeStream.ReadS32();
                mesh._parentMesh = shapeStream.ReadS32();
                shapeStream.ReadPoint3F(ref mesh._bounds.Min);
                shapeStream.ReadPoint3F(ref mesh._bounds.Max);
                shapeStream.ReadPoint3F(ref mesh._center);
                mesh._radius = shapeStream.ReadF32();

                int numVerts = shapeStream.ReadS32();
                mesh._verts = mesh._parentMesh < 0 ? shapeStream.ReadPoint3Fs(numVerts) : _shape.Meshes[mesh._parentMesh]._verts;

                int numTVerts = shapeStream.ReadS32();
                mesh._tverts = mesh._parentMesh < 0 ? shapeStream.ReadPoint2Fs(numTVerts) : _shape.Meshes[mesh._parentMesh]._tverts;

                // Version 26 added vertex color and texcoord2.
                if (Shape.ReadVersion > 25)
                {
                    int numTVerts2 = shapeStream.ReadS32();
                    if (numTVerts2 > 0)
                    {
                        if (mesh._parentMesh < 0)
                            mesh._tverts2 = shapeStream.ReadPoint2Fs(numTVerts2);
                        else
                            mesh._tverts2 = _shape.Meshes[mesh._parentMesh]._tverts2;
                    }

                    int numVColors = shapeStream.ReadS32();
                    if (numVColors > 0)
                    {
                        if (mesh._parentMesh < 0)
                            mesh._colors = shapeStream.ReadColors(numVColors);
                        else
                            mesh._colors = _shape.Meshes[mesh._parentMesh]._colors;
                    }
                }

                mesh._norms = mesh._parentMesh < 0 ? shapeStream.ReadPoint3Fs(numVerts) : _shape.Meshes[mesh._parentMesh]._norms;
                if (mesh._parentMesh < 0)
                    shapeStream.ReadU8s(numVerts); // Read past encoded normals

                int szPrim;
                ushort[] prim16;
                int[] prim32;
                int szInd;
                short[] ind16;

                // Version 26 has 32-bit indices.
                // We don't, so read them into our 16-bit buffers.
                if (Shape.ReadVersion > 25)
                {
                    szPrim = shapeStream.ReadS32();
                    int[] primIn = shapeStream.ReadS32s(szPrim * 3);

                    szInd = shapeStream.ReadS32();
                    int[] indIn = shapeStream.ReadS32s(szInd);

                    //
                    prim16 = new ushort[szPrim * 2];
                    prim32 = new int[szPrim];

                    int j = 0;
                    for (int i = 0; i < szPrim; i += 3)
                    {
                        prim16[j] = (ushort)primIn[i];
                        prim16[j + 1] = (ushort)primIn[i + 1];
                        prim32[j] = primIn[i + 2];

                        j++;
                    }

                    // Copy down the array of indices from 32-bit to 16.
                    ind16 = new short[szInd];
                    for (int i = 0; i < szInd; i++)
                        ind16[i] = (short)indIn[i];
                }
                else
                {
                    // Copy the _primitives and _indices...how we do this depends on what
                    // form we want them in when copied...first just get the data
                    szPrim = shapeStream.ReadS32();
                    prim16 = shapeStream.ReadU16s(szPrim * 2); // start, numElements
                    prim32 = shapeStream.ReadS32s(szPrim);     // matIndex

                    szInd = shapeStream.ReadS32();
                    ind16 = shapeStream.ReadS16s(szInd);
                }

                // count then Copy...
                int cpyPrim, cpyInd;
                if (_useTriangles)
                    _ConvertToTris(prim16, prim32, ind16, szPrim, out cpyPrim, out cpyInd, null, null);
                else if (_useOneStrip)
                    _ConvertToSingleStrip(prim16, prim32, ind16, szPrim, out cpyPrim, out cpyInd, null, null);
                else
                    _LeaveAsMultipleStrips(prim16, prim32, ind16, szPrim, out cpyPrim, out cpyInd, null, null);
                mesh._primitives = new DrawPrimitive[cpyPrim];
                mesh._indices = new short[cpyInd];

                // _primitives and _indices counted and allocated above, now Copy them in
                int chkPrim;
                int chkInd;
                if (_useTriangles)
                    _ConvertToTris(prim16, prim32, ind16, szPrim, out chkPrim, out chkInd, mesh._primitives, mesh._indices);
                else if (_useOneStrip)
                    _ConvertToSingleStrip(prim16, prim32, ind16, szPrim, out chkPrim, out chkInd, mesh._primitives, mesh._indices);
                else
                    _LeaveAsMultipleStrips(prim16, prim32, ind16, szPrim, out chkPrim, out chkInd, mesh._primitives, mesh._indices);

                Assert.Fatal(chkPrim == cpyPrim && chkInd == cpyInd, "TSShapeReader._AssembleStandardMesh - DrawPrimitive conversion error.");

                // Read in merge _indices...deprecated
                int numMerge = shapeStream.ReadS32();
                shapeStream.ReadS16s(numMerge);

                mesh._vertsPerFrame = shapeStream.ReadS32();
                mesh.SetFlags((Mesh.MeshEnum)shapeStream.ReadU32());

                shapeStream.CheckGuard();
            }
            catch
            { }

            return mesh;
        }
        Mesh _AssembleSortedMesh(ShapeStream shapeStream)
        {
            SortedMesh mesh = new SortedMesh();

            bool save1 = _useTriangles;
            bool save2 = _useOneStrip;
            _useTriangles = false;
            _useOneStrip = false;

            _AssembleStandardMesh(shapeStream, mesh);

            _useTriangles = save1;
            _useOneStrip = save2;

            int numClusters = shapeStream.ReadS32();
            mesh._clusters = new SortedMesh.Cluster[numClusters];
            SortedMesh.Cluster[] clusters = mesh._clusters;
            for (int i = 0; i < numClusters; i++)
            {
                clusters[i].StartPrimitive = shapeStream.ReadS32();
                clusters[i].EndPrimitive = shapeStream.ReadS32();
                shapeStream.ReadPoint3F(ref clusters[i].Normal);
                clusters[i].K = shapeStream.ReadF32();
                clusters[i].FrontCluster = shapeStream.ReadS32();
                clusters[i].BackCluster = shapeStream.ReadS32();
            }

            // Code before reads in arrays but only uses the first element.
            // This is because we no longer support frame based sorted meshes, but
            // we need to Read old files.

            int sz = shapeStream.ReadS32();
            int[] ints = shapeStream.ReadS32s(sz);
            mesh._startCluster = sz != 0 ? ints[0] : -1;

            sz = shapeStream.ReadS32();
            ints = shapeStream.ReadS32s(sz);
            mesh._firstVert = sz != 0 ? ints[0] : -1;

            sz = shapeStream.ReadS32();
            ints = shapeStream.ReadS32s(sz);
            mesh._numVerts = sz != 0 ? ints[0] : -1;

            sz = shapeStream.ReadS32();
            ints = shapeStream.ReadS32s(sz);
            mesh._firstTVert = sz != 0 ? ints[0] : -1;

            // throw away alwaysWriteDepth bool
            shapeStream.ReadS32();

            shapeStream.CheckGuard();

            return mesh;
        }
        Mesh _AssembleSkinMesh(ShapeStream shapeStream)
        {
            SkinMesh mesh = new SkinMesh();
            _AssembleStandardMesh(shapeStream, mesh);

            int numVerts = shapeStream.ReadS32();
            if (mesh._parentMesh < 0)
            {
                mesh._initialVerts = shapeStream.ReadPoint3Fs(numVerts);
                mesh._initialNormals = shapeStream.ReadPoint3Fs(numVerts);

                // eat up the encoded normals
                if (mesh._parentMesh < 0)
                    shapeStream.ReadU8s(numVerts);

                int sz = shapeStream.ReadS32();
                mesh._initialTransforms = new Matrix[sz];
                for (int i = 0; i < sz; i++)
                {
                    float[] mat = shapeStream.ReadF32s(16);
                    mesh._initialTransforms[i].M11 = mat[0];
                    mesh._initialTransforms[i].M21 = mat[1];
                    mesh._initialTransforms[i].M31 = mat[2];
                    mesh._initialTransforms[i].M41 = mat[3];
                    mesh._initialTransforms[i].M12 = mat[4];
                    mesh._initialTransforms[i].M22 = mat[5];
                    mesh._initialTransforms[i].M32 = mat[6];
                    mesh._initialTransforms[i].M42 = mat[7];
                    mesh._initialTransforms[i].M13 = mat[8];
                    mesh._initialTransforms[i].M23 = mat[9];
                    mesh._initialTransforms[i].M33 = mat[10];
                    mesh._initialTransforms[i].M43 = mat[11];
                    mesh._initialTransforms[i].M14 = mat[12];
                    mesh._initialTransforms[i].M24 = mat[13];
                    mesh._initialTransforms[i].M34 = mat[14];
                    mesh._initialTransforms[i].M44 = mat[15];
                }

                sz = shapeStream.ReadS32();
                mesh._vertexIndex = shapeStream.ReadS32s(sz);
                mesh._boneIndex = shapeStream.ReadU32s(sz);
                mesh._weight = shapeStream.ReadF32s(sz);

                sz = shapeStream.ReadS32();
                mesh._nodeIndex = shapeStream.ReadS32s(sz);
            }
            else
            {
                SkinMesh otherSkin = _shape.Meshes[mesh._parentMesh] as SkinMesh;
                if (otherSkin == null)
                {
                    Assert.Fatal(false, "TSShapeReader._AssembleSkinMesh - Parent of skin mesh not a skin mesh.");
                    return null;
                }

                // consult our parent for our vectors
                mesh._initialVerts = otherSkin._initialVerts;
                mesh._initialNormals = otherSkin._initialNormals;

                // eat up the encoded normals
                if (mesh._parentMesh < 0)
                    shapeStream.ReadU8s(numVerts);

                int sz = shapeStream.ReadS32();
                mesh._initialTransforms = otherSkin._initialTransforms;

                sz = shapeStream.ReadS32();
                mesh._vertexIndex = otherSkin._vertexIndex;
                mesh._boneIndex = otherSkin._boneIndex;
                mesh._weight = otherSkin._weight;

                sz = shapeStream.ReadS32();
                mesh._nodeIndex = otherSkin._nodeIndex;
            }

            shapeStream.CheckGuard();

            return mesh;
        }
        void _AssembleShape(ShapeStream shapeStream)
        {
            int i;

            // get counts...
            int numNodes = shapeStream.ReadS32();
            int numObjects = shapeStream.ReadS32();
            int numDecals = shapeStream.ReadS32();
            int numSubShapes = shapeStream.ReadS32();
            int numIflMaterials = shapeStream.ReadS32();
            int numNodeRots = shapeStream.ReadS32();
            int numNodeTrans = shapeStream.ReadS32();
            int numNodeUniformScales = shapeStream.ReadS32();
            int numNodeAlignedScales = shapeStream.ReadS32();
            int numNodeArbitraryScales = shapeStream.ReadS32();
            int numGroundFrames = shapeStream.ReadS32();
            int numObjectStates = shapeStream.ReadS32();
            int numDecalStates = shapeStream.ReadS32();
            int numTriggers = shapeStream.ReadS32();
            int numDetails = shapeStream.ReadS32();
            int numMeshes = shapeStream.ReadS32();
            int numNames = shapeStream.ReadS32();
            _shape.SmallestVisibleSize = shapeStream.ReadF32();
            _shape.SmallestVisibleDL = shapeStream.ReadS32();

            shapeStream.CheckGuard();

            // get bounds...
            _shape.Radius = shapeStream.ReadF32();
            _shape.TubeRadius = shapeStream.ReadF32();
            shapeStream.ReadPoint3F(ref _shape.Center);
            shapeStream.ReadPoint3F(ref _shape.Bounds.Min);
            shapeStream.ReadPoint3F(ref _shape.Bounds.Max);

            shapeStream.CheckGuard();

            // allocate some storage
            _shape.SubShapeFirstTranslucentObject = new int[numSubShapes];

            // Read in nodes
            _shape.Nodes = new Node[numNodes];
            for (i = 0; i < numNodes; i++)
            {
                _shape.Nodes[i].NameIndex = shapeStream.ReadS32();
                _shape.Nodes[i].ParentIndex = shapeStream.ReadS32();
                _shape.Nodes[i].FirstObject = shapeStream.ReadS32();
                _shape.Nodes[i].FirstChild = shapeStream.ReadS32();
                _shape.Nodes[i].NextSibling = shapeStream.ReadS32();
            }

            shapeStream.CheckGuard();

            // Read in objects
            _shape.Objects = new Object[numObjects];
            for (i = 0; i < numObjects; i++)
            {
                _shape.Objects[i].NameIndex = shapeStream.ReadS32();
                _shape.Objects[i].MeshCount = shapeStream.ReadS32();
                _shape.Objects[i].FirstMesh = shapeStream.ReadS32();
                _shape.Objects[i].NodeIndex = shapeStream.ReadS32();
                _shape.Objects[i].NextSibling = shapeStream.ReadS32();
                shapeStream.ReadS32(); // decals are deprecated
            }

            shapeStream.CheckGuard();

            // should be no decals, but Read them in and ignore if they are there
            shapeStream.ReadS32s(numDecals * 5);

            shapeStream.CheckGuard();

            // ifl materials
            _shape.IflMaterials = new IflMaterial[numIflMaterials];
            for (i = 0; i < numIflMaterials; i++)
            {
                _shape.IflMaterials[i].NameIndex = shapeStream.ReadS32();
                _shape.IflMaterials[i].MaterialSlot = shapeStream.ReadS32();
                _shape.IflMaterials[i].FirstFrame = shapeStream.ReadS32();
                _shape.IflMaterials[i].FirstFrameOffTimeIndex = shapeStream.ReadS32();
                _shape.IflMaterials[i].FrameCount = shapeStream.ReadS32();
            }

            shapeStream.CheckGuard();

            // subshape first lists...
            _shape.SubShapeFirstNode = shapeStream.ReadS32s(numSubShapes);
            _shape.SubShapeFirstObject = shapeStream.ReadS32s(numSubShapes);
            shapeStream.ReadS32s(numSubShapes); // no decal support

            shapeStream.CheckGuard();

            // subshape num lists...
            _shape.SubShapeNodeCount = shapeStream.ReadS32s(numSubShapes);
            _shape.SubShapeObjectCount = shapeStream.ReadS32s(numSubShapes);
            shapeStream.ReadS32s(numSubShapes); // no decal support

            shapeStream.CheckGuard();

            // get default rotations and translations
            _shape.DefaultRotations = shapeStream.ReadQuat16s(numNodes);
            _shape.DefaultTranslations = shapeStream.ReadPoint3Fs(numNodes);

            // get _sequence rotation and translations
            _shape.NodeTranslations = shapeStream.ReadPoint3Fs(numNodeTrans);
            _shape.NodeRotations = shapeStream.ReadQuat16s(numNodeRots);

            shapeStream.CheckGuard();

            // more node _sequence data...Scale
            _shape.NodeUniformScales = shapeStream.ReadF32s(numNodeUniformScales);
            _shape.NodeAlignedScales = shapeStream.ReadPoint3Fs(numNodeAlignedScales);
            _shape.NodeArbitraryScaleFactors = shapeStream.ReadPoint3Fs(numNodeArbitraryScales);
            _shape.NodeArbitraryScaleRotations = shapeStream.ReadQuat16s(numNodeArbitraryScales);

            shapeStream.CheckGuard();

            // ground _sequence data
            _shape.GroundTranslations = shapeStream.ReadPoint3Fs(numGroundFrames);
            _shape.GroundRotations = shapeStream.ReadQuat16s(numGroundFrames);

            shapeStream.CheckGuard();

            // object states
            _shape.ObjectStates = new ObjectState[numObjectStates];
            for (i = 0; i < numObjectStates; i++)
            {
                _shape.ObjectStates[i].Visibility = shapeStream.ReadF32();
                _shape.ObjectStates[i].FrameIndex = shapeStream.ReadS32();
                _shape.ObjectStates[i].MaterialFrameIndex = shapeStream.ReadS32();

            }

            shapeStream.CheckGuard();

            shapeStream.ReadS32s(numDecalStates); // no decal support

            shapeStream.CheckGuard();

            // frame triggers
            _shape.Triggers = new Trigger[numTriggers];
            for (i = 0; i < numTriggers; i++)
            {
                _shape.Triggers[i].State = shapeStream.ReadS32();
                _shape.Triggers[i].Pos = shapeStream.ReadF32();
            }

            shapeStream.CheckGuard();

            // details
            _shape.Details = new Detail[numDetails];
            for (i = 0; i < numDetails; i++)
            {
                _shape.Details[i].NameIndex = shapeStream.ReadS32();
                _shape.Details[i].SubShapeNumber = shapeStream.ReadS32();
                _shape.Details[i].ObjectDetailNumber = shapeStream.ReadS32();
                _shape.Details[i].PixelSize = shapeStream.ReadF32();
                _shape.Details[i].AverageError = shapeStream.ReadF32();
                _shape.Details[i].MaxError = shapeStream.ReadF32();
                _shape.Details[i].PolyCount = shapeStream.ReadS32();

                if (Shape.ReadVersion >= 26)
                {
                    shapeStream.ReadU32s(6);
                }
            }

            shapeStream.CheckGuard();

            // Read in meshes...this is much simpler than in C++ code because
            // we never skip a detail level on load
            _shape.Meshes = new Mesh[numMeshes];
            for (i = 0; i < numMeshes; i++)
            {
                Mesh.MeshEnum meshType = (Mesh.MeshEnum)shapeStream.ReadS32();
                _shape.Meshes[i] = _AssembleMesh(shapeStream, meshType);
            }

            shapeStream.CheckGuard();

            _shape.Names = new String[numNames];
            for (i = 0; i < numNames; i++)
            {
                _shape.Names[i] = shapeStream.ReadCString();
            }

            shapeStream.CheckGuard();
        }
        Mesh _AssembleMesh(ShapeStream shapeStream, Mesh.MeshEnum meshType)
        {
            if (meshType == Mesh.MeshEnum.StandardMeshType)
                return _AssembleStandardMesh(shapeStream, null);
            else if (meshType == Mesh.MeshEnum.SkinMeshType)
                return _AssembleSkinMesh(shapeStream);
            else if (meshType == Mesh.MeshEnum.SortedMeshType)
                return _AssembleSortedMesh(shapeStream);

            return null;
        }
        /// <summary>
        /// Reads a shape from a stream.
        /// </summary>
        /// <param name="stream">The stream to read from.</param>
        /// <returns>The new shape.</returns>
        public Shape ReadShape(Stream stream)
        {
            _shape = new Shape();

            BinaryReader bin = new BinaryReader(stream);
            int readVersion = bin.ReadInt32();
            int exporterVersion = readVersion >> 16;
            readVersion &= 0xFF;
            if (readVersion > Shape.WriteVersion || readVersion < 24)
            {
                Assert.Fatal(false, "TSShapeReader.ReadShape - Old shape formats are not supported.");
                return null;
            }

            Shape.ReadVersion = readVersion;

            int sizeMemBuffer, startushort, startU8;
            sizeMemBuffer = 4 * bin.ReadInt32();
            startushort = 4 * bin.ReadInt32();
            startU8 = 4 * bin.ReadInt32();

            byte[] buffer = bin.ReadBytes(sizeMemBuffer);

            ShapeStream shapeStream = new ShapeStream(buffer, 0, startushort, startU8, startushort, startU8 - startushort, sizeMemBuffer - startU8);

            // Read sequences
            int numSequences = bin.ReadInt32();
            _shape.Sequences = new Sequence[numSequences];
            for (int i = 0; i < numSequences; i++)
            {
                _shape.Sequences[i] = new Sequence();
                _ReadSequence(bin, ref _shape.Sequences[i], true);
            }

            // Read material list
            _ReadMaterialList(bin);

            _AssembleShape(shapeStream);

            _shape.Initialize();

            return _shape;
        }