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