public static GeometricObjectCollide Read(Reader reader, Pointer offset, CollideType type = CollideType.None, bool isBoundingVolume = false)
        {
            MapLoader l = MapLoader.Loader;
            //l.print("CollideMesh " + offset);
            GeometricObjectCollide m = new GeometricObjectCollide(offset, type);

            m.isBoundingVolume = isBoundingVolume;
            if (Settings.s.engineVersion == Settings.EngineVersion.R3 || Settings.s.game == Settings.Game.R2Revolution)
            {
                m.num_vertices = reader.ReadUInt16();
                m.num_elements = reader.ReadUInt16();
                if (Settings.s.engineVersion == Settings.EngineVersion.R3 && Settings.s.game != Settings.Game.LargoWinch)
                {
                    reader.ReadUInt32();
                }
            }
            if (Settings.s.engineVersion <= Settings.EngineVersion.Montreal)
            {
                m.num_vertices = (ushort)reader.ReadUInt32();
            }
            m.off_vertices = Pointer.Read(reader);
            if (Settings.s.engineVersion < Settings.EngineVersion.R3 && Settings.s.game != Settings.Game.R2Revolution)
            {
                m.off_normals = Pointer.Read(reader);
                Pointer.Read(reader);
                reader.ReadInt32();
            }
            if (Settings.s.engineVersion <= Settings.EngineVersion.Montreal)
            {
                m.num_elements = (ushort)reader.ReadUInt32();
            }
            m.off_element_types = Pointer.Read(reader);
            m.off_elements      = Pointer.Read(reader);
            if (Settings.s.game != Settings.Game.R2Revolution && Settings.s.game != Settings.Game.LargoWinch)
            {
                Pointer.Read(reader);
                if (Settings.s.engineVersion < Settings.EngineVersion.R3)
                {
                    if (Settings.s.engineVersion == Settings.EngineVersion.R2)
                    {
                        reader.ReadInt32();
                        reader.ReadInt32();
                        reader.ReadInt32();
                        reader.ReadInt32();
                        m.num_vertices = reader.ReadUInt16();
                        m.num_elements = reader.ReadUInt16();
                    }
                    if (Settings.s.engineVersion <= Settings.EngineVersion.Montreal)
                    {
                        reader.ReadInt32();
                        reader.ReadInt32();
                    }
                    reader.ReadUInt16();
                    m.num_parallelBoxes = reader.ReadUInt16();
                }
                else
                {
                    //l.print((Pointer.Current(reader).FileOffset - offset.FileOffset));
                    m.off_parallelBoxes = Pointer.Read(reader);
                }
            }
            else
            {
                reader.ReadUInt32();
            }
            if (Settings.s.engineVersion != Settings.EngineVersion.Montreal)
            {
                m.sphereRadius = reader.ReadSingle(); // bounding volume radius
                float sphereX = reader.ReadSingle();  // x
                float sphereZ = reader.ReadSingle();  // z
                float sphereY = reader.ReadSingle();  // y
                m.sphereCenter = new Vector3(sphereX, sphereY, sphereZ);

                if (Settings.s.engineVersion == Settings.EngineVersion.R2)
                {
                    reader.ReadUInt32();
                }
            }

            // Vertices
            Pointer off_current = Pointer.Goto(ref reader, m.off_vertices);

            m.vertices = new Vector3[m.num_vertices];
            for (int i = 0; i < m.num_vertices; i++)
            {
                float x = reader.ReadSingle();
                float z = reader.ReadSingle();
                float y = reader.ReadSingle();
                m.vertices[i] = new Vector3(x, y, z);
            }

            // Normals
            if (m.off_normals != null)
            {
                off_current = Pointer.Goto(ref reader, m.off_normals);
                m.normals   = new Vector3[m.num_vertices];
                for (int i = 0; i < m.num_vertices; i++)
                {
                    float x = reader.ReadSingle();
                    float z = reader.ReadSingle();
                    float y = reader.ReadSingle();
                    m.normals[i] = new Vector3(x, y, z);
                }
            }
            // Read subblock types & initialize arrays
            Pointer.Goto(ref reader, m.off_element_types);
            m.element_types = new ushort[m.num_elements];
            m.elements      = new IGeometricObjectElementCollide[m.num_elements];
            for (uint i = 0; i < m.num_elements; i++)
            {
                m.element_types[i] = reader.ReadUInt16();
            }

            for (uint i = 0; i < m.num_elements; i++)
            {
                Pointer.Goto(ref reader, m.off_elements + (i * 4));
                Pointer block_offset = Pointer.Read(reader);
                Pointer.Goto(ref reader, block_offset);
                switch (m.element_types[i])
                {
                /*1 = indexedtriangles
                 * 2 = facemap
                 * 3 = sprite
                 * 4 = TMesh
                 * 5 = points
                 * 6 = lines
                 * 7 = spheres
                 * 8 = alignedboxes
                 * 9 = cones
                 * 13 = deformationsetinfo*/
                case 1:     // Collide submesh
                    m.elements[i] = GeometricObjectElementCollideTriangles.Read(reader, block_offset, m);
                    //material_i++;
                    break;

                case 7:
                    m.elements[i] = GeometricObjectElementCollideSpheres.Read(reader, block_offset, m);
                    break;

                case 8:
                    m.elements[i] = GeometricObjectElementCollideAlignedBoxes.Read(reader, block_offset, m);
                    break;

                default:
                    m.elements[i] = null;
                    l.print("Unknown collide geometric element type " + m.element_types[i] + " at offset " + block_offset + " (Object: " + offset + ")");
                    break;
                }
            }
            return(m);
        }