Пример #1
0
        private int lastCircle(Vector3 v1, Vector3 v2, SceneBrep scene, Matrix4 m)
        {
            _ = createCircleAround(v1, v2);
            Vector3 center = getCenter(last_circle);
            Vector3 dif    = (v2 - v1) * size;

            _ = (v2 - v1) * (1 - size);
            int[] v = new int[cdetail];

            for (int i = 0; i < cdetail; i++)
            {
                v[i] = scene.AddVertex(Vector3.TransformPosition(last_circle[i] + dif, m));
                scene.SetNormal(v[i], Vector3.TransformVector(last_circle[i] - center, m).Normalized());
                float r = (last_circle[i].X + 1.1f) / 2.5f;
                float g = (last_circle[i].Y + 1.1f) / 2.5f;
                float b = (last_circle[i].Z + 1.1f) / 2.5f;
                scene.SetColor(v[i], new Vector3(r, g, b));
            }

            for (int i = 0; i < cdetail - 1; i++)
            {
                scene.AddTriangle(connect_indices[i], v[i], connect_indices[i + 1]);
                scene.AddTriangle(connect_indices[i + 1], v[i], v[i + 1]);
            }

            scene.AddTriangle(connect_indices[cdetail - 1], v[cdetail - 1], connect_indices[0]);
            scene.AddTriangle(connect_indices[0], v[cdetail - 1], v[0]);

            return(cdetail * 2);
        }
Пример #2
0
        private int CreateTetrahedron(SceneBrep scene, Matrix4 m, Vector3 center, float size)
        {
            int[] v = new int[4];
            float z = (float)(size * Math.Sqrt(0.5));

            Vector3 A = new Vector3(size, 0.0f, -z);
            Vector3 B = new Vector3(-size, 0.0f, -z);
            Vector3 C = new Vector3(0.0f, size, z);
            Vector3 D = new Vector3(0.0f, -size, z);

            // vertices:
            v[0] = scene.AddVertex(Vector3.TransformPosition(A, m));
            v[1] = scene.AddVertex(Vector3.TransformPosition(B, m));
            v[2] = scene.AddVertex(Vector3.TransformPosition(C, m));
            v[3] = scene.AddVertex(Vector3.TransformPosition(D, m));

            // normal vectors:
            scene.SetNormal(v[0], Vector3.TransformVector(A, m).Normalized());
            scene.SetNormal(v[1], Vector3.TransformVector(B, m).Normalized());
            scene.SetNormal(v[2], Vector3.TransformVector(C, m).Normalized());
            scene.SetNormal(v[3], Vector3.TransformVector(D, m).Normalized());

            // texture coordinates:
            scene.SetTxtCoord(v[0], new Vector2(1.0f, 0.0f));
            scene.SetTxtCoord(v[1], new Vector2(0.0f, 0.0f));
            scene.SetTxtCoord(v[2], new Vector2(1.0f, 1.0f));
            scene.SetTxtCoord(v[3], new Vector2(0.0f, 1.0f));

            // colors:
            long seed = (long)Math.Min(long.MaxValue, (m.Row3.LengthSquared * 10000.0f));

            seed = RandomStatic.numericRecipes(seed);
            float r = (seed & 255) / 255.0f;

            seed = RandomStatic.numericRecipes(seed);
            float g = (seed & 255) / 255.0f;

            seed = RandomStatic.numericRecipes(seed);
            float b = (seed & 255) / 255.0f;

            scene.SetColor(v[0], new Vector3(r, g, b));
            r = Math.Min(r + 0.2f, 1.0f);
            scene.SetColor(v[1], new Vector3(r, g, b));
            g = Math.Min(g + 0.2f, 1.0f);
            scene.SetColor(v[2], new Vector3(r, g, b));
            b = Math.Min(b + 0.2f, 1.0f);
            scene.SetColor(v[3], new Vector3(r, g, b));

            // triangle faces:
            scene.AddTriangle(v[0], v[1], v[2]);
            scene.AddTriangle(v[2], v[1], v[3]);
            scene.AddTriangle(v[1], v[0], v[3]);
            scene.AddTriangle(v[2], v[3], v[0]);

            return(4);
        }
Пример #3
0
        void ConnectTwoCircles(SceneBrep scene, List <List <Vector3> > MeshV, int total, int index)
        {
            List <int> firstCirc = new List <int>();
            List <int> secCirc   = new List <int>();
            int        count     = MeshV[index].Count;

            if (index != 0)
            {
                for (int i = total; i > total - count; i--)
                {
                    firstCirc.Add(i);
                    secCirc.Add(i - count);
                }
                //for (int i = 0; i < firstCirc.Count; i++) {
                //  scene.AddLine(firstCirc[i], secCirc[i]);
                //  scene.AddLine(firstCirc[i], secCirc[(i + 1 == secCirc .Count ? 0 : i+1)]);
                //}
            }
            else
            {
                for (int i = total; i > total - count; i--)
                {
                    firstCirc.Add(i);
                    secCirc.Add(total - i + count);
                }
                //for (int i = 0; i < firstCirc.Count; i++) {
                //  scene.AddLine(firstCirc[i], secCirc[i]);
                //  scene.AddLine(firstCirc[i], secCirc[(i + 1 == secCirc.Count ? 0 : i+1)]);
                //}
            }

            for (int i = 0; i < firstCirc.Count; i++)
            {
                scene.AddTriangle(firstCirc[i], secCirc[i], secCirc[(i + 1 == secCirc.Count ? 0 : i + 1)]);
                this.GeneratedFaces++;
                scene.AddTriangle(
                    firstCirc[(i + 1 == firstCirc.Count ? 0 : i + 1)],
                    firstCirc[i],
                    secCirc[(i + 1 == secCirc.Count ? 0 : i + 1)]);
                this.GeneratedFaces++;
            }
        }
Пример #4
0
        /// <summary>
        /// Do Loop subdivision of the input control triangle mesh.
        /// </summary>
        /// <param name="scene">Input scene (must not be changed).</param>
        /// <param name="epsilon">Reference error toleration (size of undivided triangle).</param>
        /// <param name="normals">Generate normals? (optional)</param>
        /// <param name="colors">Generate colors? (optional)</param>
        /// <param name="txtcoord">Generate texture coordinates? (optional)</param>
        /// <param name="time">Current time for animation (optional)</param>
        /// <param name="param">Optional additional parameters.</param>
        /// <returns>Number of generated points.</returns>
        public int Subdivide(SceneBrep scene, float epsilon, bool normals, bool colors, bool txtcoord, float time, string param)
        {
            result = scene.Clone();

            // !!!{{ TODO: put your Loop subdivision code here

            // pilot: do one (trivial) division
            int triangles = result.Triangles;
            int tr;

            for (tr = 0; tr < triangles; tr++)
            {
                int A, B, C;
                result.GetTriangleVertices(tr, out A, out B, out C);
                Vector3 vA = result.GetVertex(A);
                Vector3 vB = result.GetVertex(B);
                Vector3 vC = result.GetVertex(C);

                Vector3 vA2 = (vB + vC) * 0.5f;
                Vector3 vB2 = (vA + vC) * 0.5f;
                Vector3 vC2 = (vA + vB) * 0.5f;
                int     A2  = result.AddVertex(vA2);
                int     B2  = result.AddVertex(vB2);
                int     C2  = result.AddVertex(vC2);

                result.AddTriangle(B2, C2, A2);
                result.AddTriangle(B2, A2, C);
                result.AddTriangle(C2, B, A2);
                result.SetTriangleVertices(tr, A, C2, B2);
            }

            //result.BuildCornerTable();

            return(result.Vertices);

            // !!!}}
        }
Пример #5
0
        /// <summary>
        /// Construct a new control mesh for subdivision (formally the Brep solid..).
        /// </summary>
        /// <param name="scene">B-rep scene to be modified</param>
        /// <param name="m">Transform matrix (object-space to world-space)</param>
        /// <param name="time">Current time in seconds</param>
        /// <param name="param">Shape parameters if needed</param>
        public void ControlMesh(SceneBrep scene, Matrix4 m, float time, string param)
        {
            // !!!{{ TODO: put your Control-mesh-construction code here

            List <int> upper = new List <int>();

            upper.Add(scene.AddVertex(Vector3.TransformPosition(new Vector3(0, 1, 0), m)));
            upper.Add(scene.AddVertex(Vector3.TransformPosition(new Vector3(1, 1, 0), m)));
            upper.Add(scene.AddVertex(Vector3.TransformPosition(new Vector3(1, 1, 1), m)));
            upper.Add(scene.AddVertex(Vector3.TransformPosition(new Vector3(0, 1, 1), m)));

            List <int> lower = new List <int>();

            lower.Add(scene.AddVertex(Vector3.TransformPosition(new Vector3(0, 0, 0), m)));
            lower.Add(scene.AddVertex(Vector3.TransformPosition(new Vector3(1, 0, 0), m)));
            lower.Add(scene.AddVertex(Vector3.TransformPosition(new Vector3(1, 0, 1), m)));
            lower.Add(scene.AddVertex(Vector3.TransformPosition(new Vector3(0, 0, 1), m)));

            // Lower face
            scene.AddTriangle(lower[0], lower[1], lower[2]);
            scene.AddTriangle(lower[2], lower[3], lower[0]);

            // Upper face
            scene.AddTriangle(upper[2], upper[1], upper[0]);
            scene.AddTriangle(upper[0], upper[3], upper[2]);

            // Side faces
            for (int i = 0; i < upper.Count; i++)
            {
                int j = i < (upper.Count - 1) ? i + 1 : 0;
                scene.AddTriangle(upper[i], upper[j], lower[i]);
                scene.AddTriangle(lower[i], upper[j], lower[j]);
            }

            // !!!}}
        }
Пример #6
0
        /// <summary>
        /// Reads one 3D scene from a given stream (containing text variant of Wavefront OBJ format).
        /// </summary>
        /// <param name="reader">Already open text reader</param>
        /// <param name="scene">Scene to be modified</param>
        /// <param name="scene">Matrix for instancing</param>
        /// <returns>Number of faces read</returns>
        public int ReadBrep( StreamReader reader, SceneBrep scene, Matrix4 m )
        {
            if ( reader == null ) return SceneBrep.NULL;

              Debug.Assert( scene != null );
              int v0 = scene.Vertices;

              int faces = 0;
              List<Vector3> normals = new List<Vector3>( 256 );
              int[] f = new int[ 3 ];

              do
              {
            string line = reader.ReadLine();
            if ( line == null ) break;

            int commentPos = line.IndexOf( COMMENT );
            if ( commentPos >= 0 )
              line = line.Substring( 0, commentPos );

            string[] tokens = line.Split( ' ' );

            switch ( tokens[ 0 ] )
            {
              case VERTEX:
            if ( tokens.Length < 4 ) continue;

            Vector3 coord;
            if ( !float.TryParse( tokens[ 1 ], NumberStyles.Float, CultureInfo.InvariantCulture, out coord.X ) ||
                 !float.TryParse( tokens[ 2 ], NumberStyles.Float, CultureInfo.InvariantCulture, out coord.Y ) ||
                 !float.TryParse( tokens[ 3 ], NumberStyles.Float, CultureInfo.InvariantCulture, out coord.Z ) )
              continue;

            if ( MirrorConversion )
              coord.Z = -coord.Z;
            scene.AddVertex( Vector3.Transform( coord, m ) );
            break;

              case VERTEX_NORMAL:
            if ( tokens.Length < 4 ) continue;

            Vector3 norm;
            if ( !float.TryParse( tokens[ 1 ], NumberStyles.Float, CultureInfo.InvariantCulture, out norm.X ) ||
                 !float.TryParse( tokens[ 2 ], NumberStyles.Float, CultureInfo.InvariantCulture, out norm.Y ) ||
                 !float.TryParse( tokens[ 3 ], NumberStyles.Float, CultureInfo.InvariantCulture, out norm.Z ) )
              continue;

            if ( MirrorConversion )
              norm.Z = -norm.Z;
            normals.Add( Vector3.TransformNormal( norm, m ) );
            break;

              case FACE:
            if ( tokens.Length < 4 ) continue;
            int i;

            for ( i = 0; i < 3; i++ )
            {
              string[] vt = tokens[ i + 1 ].Split( '/' );
              int ti, ni;
              ti = ni = SceneBrep.NULL;
              // 0 .. vertex coord index
              if ( !int.TryParse( vt[ 0 ], out f[ i ] ) ) break;
              f[ i ] = v0 + f[ i ] - 1;
              if ( vt.Length >= 2 )
              {
                // 1 .. texture coord index (not yet)
                int.TryParse( vt[ 1 ], out ti );
                ti--;
                if ( vt.Length >= 3 )
                {
                  // 2 .. normal vector index
                  int.TryParse( vt[ 2 ], out ni );
                  ni--;
                }
              }
              if ( ni >= 0 && ni < normals.Count )
                scene.SetNormal( f[ i ], normals[ ni ] );
            }

            if ( i >= 3 )
            {
              scene.AddTriangle( f[ 0 ], f[ 1 ], f[ 2 ] );
              faces++;
            }

            break;
            }
              }
              while ( !reader.EndOfStream );

              return faces;
        }
Пример #7
0
        private int createBentPipe(SceneBrep scene, Matrix4 m, Vector3 v1, Vector3 v2, Vector3 v3)
        {
            Vector3[] centers    = new Vector3[bdetail];
            Vector3   oned       = (v1 - v2) * size;
            Vector3   twod       = (v3 - v2) * size;
            Vector3   rtwod      = (v3 - v2) * (1 - size);
            Vector3   rot_point  = v2 + oned + twod;
            Vector3   test_point = oned + twod;

            test_point.X = Math.Abs(test_point.X);
            test_point.Y = Math.Abs(test_point.Y);
            test_point.Z = Math.Abs(test_point.Z);
            double angle = -(Math.PI / 2) / (bdetail - 1);
            char   axis;

            if (test_point.Y < test_point.X)
            {
                axis = (test_point.Z < test_point.Y) ? 'z' : 'y';
            }
            else
            {
                axis = (test_point.Z < test_point.X) ? 'z' : 'x';
            }

            MyMatrix4 mat = MyMatrix4.getSingleRotationMatrix(angle, axis);
            float     l   = longestSide(last_circle[0] - v1);
            Vector3   sp  = rotateAroundPoint(last_circle[0], rot_point, mat);
            float     l2  = longestSide(sp - v1);

            if (l2 < l)
            {
                mat = MyMatrix4.getSingleRotationMatrix(-angle, axis);
            }
            Vector3[] field = new Vector3[bdetail * cdetail];
            Array.Copy(last_circle, field, cdetail);
            centers[0] = getCenter(last_circle);
            Vector3[] new_circle = new Vector3[cdetail];

            for (int i = 1; i < bdetail; i++)
            {
                Array.ConstrainedCopy(field, (i - 1) * cdetail, new_circle, 0, cdetail);
                new_circle = rotateAroundPoint(new_circle, rot_point, mat);
                Array.ConstrainedCopy(new_circle, 0, field, i * cdetail, cdetail);
                centers[i] = getCenter(new_circle);
            }

            Array.ConstrainedCopy(field, (bdetail - 1) * cdetail, last_circle, 0, cdetail);
            for (int i = 0; i < cdetail; i++)
            {
                last_circle[i] += rtwod - twod;
            }
            int[] v = new int[field.Length];

            for (int i = 0; i < field.Length; i++)
            {
                v[i] = scene.AddVertex(Vector3.TransformPosition(field[i], m));
                scene.SetNormal(v[i], Vector3.TransformVector(field[i] - centers[i / cdetail], m).Normalized());
                float r = (field[i].X + 1.1f) / 2.5f;
                float g = (field[i].Y + 1.1f) / 2.5f;
                float b = (field[i].Z + 1.1f) / 2.5f;
                scene.SetColor(v[i], new Vector3(r, g, b));
            }

            for (int i = 0; i < cdetail - 1; i++)
            {
                scene.AddTriangle(connect_indices[i], v[i], connect_indices[i + 1]);
                scene.AddTriangle(connect_indices[i + 1], v[i], v[i + 1]);
            }

            scene.AddTriangle(connect_indices[cdetail - 1], v[cdetail - 1], connect_indices[0]);
            scene.AddTriangle(connect_indices[0], v[cdetail - 1], v[0]);

            for (int i = 0; i < (bdetail - 1); i++)
            {
                for (int j = 0; j < cdetail - 1; j++)
                {
                    int a = i * cdetail + j;
                    scene.AddTriangle(v[a], v[a + cdetail], v[a + 1]);
                    scene.AddTriangle(v[a + 1], v[a + cdetail], v[a + cdetail + 1]);
                }
                int b = i * cdetail + cdetail - 1;
                scene.AddTriangle(v[b], v[b + cdetail], v[b - cdetail + 1]);
                scene.AddTriangle(v[b - cdetail + 1], v[b + cdetail], v[b + 1]);
            }
            Array.ConstrainedCopy(v, (bdetail - 1) * cdetail, connect_indices, 0, cdetail);

            return(bdetail * cdetail * 2 + cdetail * 2);
        }
Пример #8
0
        public int ReadBrep(string fileName, SceneBrep scene)
        {
            Debug.Assert(scene != null);

            this.scene = scene;

            scene.Reset();

            if (fileName == null || fileName.Length == 0)
            {
                throw new IOException("Invalid file name");
            }

            if (fileName.EndsWith(".gz"))
            {
                headerReader = new StreamReader(new GZipStream(new FileStream(fileName, FileMode.Open), CompressionMode.Decompress));
            }
            else
            {
                var fs = new FileStream(fileName, FileMode.Open);
                headerReader = new StreamReader(fs);
            }


            // prepare buffers for data filling
            if (!ParseHeader())
            {
                return(-1);
            }

            // read vertices
            var vertexReader = GetReader("vertex");
            var element      = vertexReader.ReadElement();

            List <Vector2> txtCoords = new List <Vector2>(256);

            int[] f          = new int[3];
            int   v0         = scene.Vertices;
            int   lastVertex = v0 - 1;

            while (element != null)
            {
                lastVertex = scene.AddVertex(Vector3.TransformPosition(element.GetVertex(), matrix));

                if (DoNormals)
                {
                    Vector3.TransformNormal(element.GetNormal(), matrix);

                    scene.SetNormal(lastVertex, element.GetNormal());
                }

                if (DoTxtCoords)
                {
                    scene.SetTxtCoord(lastVertex, element.GetTextureCoordinate());
                }

                if (DoColors)
                {
                    scene.SetColor(lastVertex, element.GetVertexColor());
                }

                element = vertexReader.ReadElement();
            }

            // read triangles
            var faceReader = GetReader("face");

            element = faceReader.ReadElement();

            while (element != null)
            {
                int A, B, C;
                element.GetTriangleVertices(out A, out B, out C);

                scene.AddTriangle(A, B, C);

                element = faceReader.ReadElement();
            }

            headerReader.Close();
            vertexReader.Close();
            faceReader.Close();

            return(scene.Triangles);
        }
Пример #9
0
        /// <summary>
        /// Reads one 3D scene from a given stream (containing text variant of Wavefront OBJ format).
        /// </summary>
        /// <param name="reader">Already open text reader</param>
        /// <param name="scene">Scene to be modified</param>
        /// <param name="scene">Matrix for instancing</param>
        /// <returns>Number of faces read</returns>
        public int ReadBrep(StreamReader reader, SceneBrep scene, Matrix4 m)
        {
            if (reader == null)
            {
                return(SceneBrep.NULL);
            }

            Debug.Assert(scene != null);
            int v0         = scene.Vertices;
            int lastVertex = v0 - 1;

            int faces = 0;

            List <Vector2> txtCoords    = new List <Vector2>(256);
            List <Vector3> normals      = new List <Vector3>(256);
            int            lastTxtCoord = -1;
            int            lastNormal   = -1;

            int[] f = new int[3];

            do
            {
                string line = reader.ReadLine();
                if (line == null)
                {
                    break;
                }

                int commentPos = line.IndexOf(COMMENT);
                if (commentPos >= 0)
                {
                    line = line.Substring(0, commentPos);
                }

                string[] tokens = line.Split(DELIMITERS, StringSplitOptions.RemoveEmptyEntries);
                if (tokens.Length < 1)
                {
                    continue;
                }

                switch (tokens[0])
                {
                case VERTEX:
                    if (tokens.Length < 4)
                    {
                        continue;
                    }

                    Vector3 coord;
                    if (!float.TryParse(tokens[1], NumberStyles.Float, CultureInfo.InvariantCulture, out coord.X) ||
                        !float.TryParse(tokens[2], NumberStyles.Float, CultureInfo.InvariantCulture, out coord.Y) ||
                        !float.TryParse(tokens[3], NumberStyles.Float, CultureInfo.InvariantCulture, out coord.Z))
                    {
                        continue;
                    }

                    if (MirrorConversion)
                    {
                        coord.Z = -coord.Z;
                    }
                    lastVertex = scene.AddVertex(Vector3.TransformPosition(coord, m));
                    break;

                case VERTEX_TEXTURE:
                    if (tokens.Length < 3)
                    {
                        continue;
                    }

                    Vector2 txtCoord;
                    if (!float.TryParse(tokens[1], NumberStyles.Float, CultureInfo.InvariantCulture, out txtCoord.X) ||
                        !float.TryParse(tokens[2], NumberStyles.Float, CultureInfo.InvariantCulture, out txtCoord.Y))
                    {
                        continue;
                    }

                    if (TextureUpsideDown)
                    {
                        txtCoord.Y = 1.0f - txtCoord.Y;
                    }

                    txtCoords.Add(txtCoord);
                    lastTxtCoord++;
                    break;

                case VERTEX_NORMAL:
                    if (tokens.Length < 4)
                    {
                        continue;
                    }

                    Vector3 norm;
                    if (!float.TryParse(tokens[1], NumberStyles.Float, CultureInfo.InvariantCulture, out norm.X) ||
                        !float.TryParse(tokens[2], NumberStyles.Float, CultureInfo.InvariantCulture, out norm.Y) ||
                        !float.TryParse(tokens[3], NumberStyles.Float, CultureInfo.InvariantCulture, out norm.Z))
                    {
                        continue;
                    }

                    if (MirrorConversion)
                    {
                        norm.Z = -norm.Z;
                    }
                    normals.Add(Vector3.TransformNormal(norm, m));
                    lastNormal++;
                    break;

                case FACE:
                    if (tokens.Length < 4)
                    {
                        continue;
                    }
                    int N = tokens.Length - 1;
                    if (f.Length < N)
                    {
                        f = new int[N];
                    }
                    int i;

                    for (i = 0; i < N; i++) // read indices for one vertex
                    {
                        string[] vt = tokens[i + 1].Split('/');
                        int      ti, ni;
                        ti = ni = 0; // 0 => value not present

                        // 0 .. vertex coord index
                        if (!int.TryParse(vt[0], out f[i]) ||
                            f[i] == 0)
                        {
                            break;
                        }

                        if (f[i] > 0)
                        {
                            f[i] = v0 + f[i] - 1;
                        }
                        else
                        {
                            f[i] = lastVertex + 1 - f[i];
                        }

                        if (vt.Length > 1)
                        {
                            // 1 .. texture coord index (not yet)
                            if (!int.TryParse(vt[1], out ti))
                            {
                                ti = 0;
                            }

                            if (vt.Length > 2)
                            {
                                // 2 .. normal vector index
                                if (!int.TryParse(vt[2], out ni))
                                {
                                    ni = 0;
                                }
                            }
                        }

                        // there was a texture coord..
                        if (ti != 0)
                        {
                            if (ti > 0)
                            {
                                ti--;
                            }
                            else
                            {
                                ti = lastTxtCoord + 1 - ti;
                            }
                            if (ti >= 0 && ti < txtCoords.Count)
                            {
                                scene.SetTxtCoord(f[i], txtCoords[ti]);
                            }
                        }

                        // there was a normal..
                        if (ni != 0)
                        {
                            if (ni > 0)
                            {
                                ni--;
                            }
                            else
                            {
                                ni = lastNormal + 1 - ni;
                            }
                            if (ni >= 0 && ni < normals.Count)
                            {
                                scene.SetNormal(f[i], normals[ni]);
                            }
                        }
                    }

                    N = i;
                    for (i = 1; i < N - 1; i++)
                    {
                        scene.AddTriangle(f[0], f[i], f[i + 1]);
                        faces++;
                    }

                    break;
                }
            } while (!reader.EndOfStream);

            return(faces);
        }
Пример #10
0
        /// <summary>
        /// Reads one 3D scene from a given stream (containing text variant of Wavefront OBJ format).
        /// </summary>
        /// <param name="reader">Already open text reader</param>
        /// <param name="scene">Scene to be modified</param>
        /// <param name="scene">Matrix for instancing</param>
        /// <returns>Number of faces read</returns>
        public int ReadBrep( StreamReader reader, SceneBrep scene, Matrix4 m )
        {
            if ( reader == null ) return SceneBrep.NULL;

              Debug.Assert( scene != null );
              int v0 = scene.Vertices;
              int lastVertex = v0 - 1;

              int faces = 0;
              List<Vector3> normals = new List<Vector3>( 256 );
              int lastNormal = -1;
              int[] f = new int[ 3 ];

              do
              {
            string line = reader.ReadLine();
            if ( line == null ) break;

            int commentPos = line.IndexOf( COMMENT );
            if ( commentPos >= 0 )
              line = line.Substring( 0, commentPos );

            string[] tokens = line.Split( DELIMITERS , StringSplitOptions.RemoveEmptyEntries );
            if ( tokens.Length < 1 ) continue;

            switch ( tokens[ 0 ] )
            {
              case VERTEX:
            if ( tokens.Length < 4 ) continue;

            Vector3 coord;
            if ( !float.TryParse( tokens[ 1 ], NumberStyles.Float, CultureInfo.InvariantCulture, out coord.X ) ||
                 !float.TryParse( tokens[ 2 ], NumberStyles.Float, CultureInfo.InvariantCulture, out coord.Y ) ||
                 !float.TryParse( tokens[ 3 ], NumberStyles.Float, CultureInfo.InvariantCulture, out coord.Z ) )
              continue;

            if ( MirrorConversion )
              coord.Z = -coord.Z;
            lastVertex = scene.AddVertex( Vector3.Transform( coord, m ) );
            break;

              case VERTEX_NORMAL:
            if ( tokens.Length < 4 ) continue;

            Vector3 norm;
            if ( !float.TryParse( tokens[ 1 ], NumberStyles.Float, CultureInfo.InvariantCulture, out norm.X ) ||
                 !float.TryParse( tokens[ 2 ], NumberStyles.Float, CultureInfo.InvariantCulture, out norm.Y ) ||
                 !float.TryParse( tokens[ 3 ], NumberStyles.Float, CultureInfo.InvariantCulture, out norm.Z ) )
              continue;

            if ( MirrorConversion )
              norm.Z = -norm.Z;
            normals.Add( Vector3.TransformNormal( norm, m ) );
            lastNormal++;
            break;

              case FACE:
            if ( tokens.Length < 4 ) continue;
            int N = tokens.Length - 1;
            if ( f.Length < N )
              f = new int[ N ];
            int i;

            for ( i = 0; i < N; i++ )       // read indices for one vertex
            {
              string[] vt = tokens[ i + 1 ].Split( '/' );
              int ti, ni;
              ti = ni = 0;                  // 0 => value not present

              // 0 .. vertex coord index
              if ( !int.TryParse( vt[ 0 ], out f[ i ] ) ||
                   f[ i ] == 0 )
                break;

              if ( f[ i ] > 0 )
                f[ i ] = v0 + f[ i ] - 1;
              else
                f[ i ] = lastVertex + 1 - f[ i ];

              if ( vt.Length > 1 )
              {
                // 1 .. texture coord index (not yet)
                if ( !int.TryParse( vt[ 1 ], out ti ) ) ti = 0;

                if ( vt.Length > 2 )
                {
                  // 2 .. normal vector index
                  if ( !int.TryParse( vt[ 2 ], out ni ) ) ni = 0;
                }
              }
              // there was a normal..
              if ( ni != 0 )
              {
                if ( ni > 0 )
                  ni--;
                else
                  ni = lastNormal + 1 - ni;
                if ( ni >= 0 && ni < normals.Count )
                  scene.SetNormal( f[ i ], normals[ ni ] );
              }
            }

            N = i;
            for ( i = 1; i < N - 1; i++ )
            {
              scene.AddTriangle( f[ 0 ], f[ i ], f[ i + 1 ] );
              faces++;
            }

            break;
            }
              }
              while ( !reader.EndOfStream );

              return faces;
        }