/// <summary> /// This method is used to load information stored in .mtl files referenced by the .obj file. /// </summary> /// <param name="d3ddevice"></param> /// <param name="file"></param> private void parseOBJ(string basePath, string filename) { MaterialInfoWithFaces currentMaterial = null; StreamReader sr = SSAssetManager.OpenStreamReader(Path.Combine(basePath, filename)); //Read the first line of text string line = sr.ReadLine(); //Continue to read until you reach end of file while (line != null) { // handle line continuation with "\" if (line.Length > 0) { while (line[line.Length - 1] == '\\') { line = line.Substring(0, line.Length - 1); // remove line extender.. var nextline = sr.ReadLine(); if (nextline != null && nextline.Length != 0) { line = line + nextline; // merge with next line } else { break; // be sure to avoid infinite loop... } } } // split the line into tokens, separated by space string[] tokens = line.Split(" ".ToArray(), 2); if (tokens.Length < 2) { goto next_line; } string firstToken = tokens[0]; string lineContent = tokens[1]; switch (firstToken) { /* unsupported features - fatal */ case "cstype": // curved surface type (bmatrix, bezier, bspline, cardinal, taylor) case "deg": // curve attr: degree case "step": // curve attr: step size case "bmat": // curve attr: basis matrix case "surf": // surface case "parm": // curve body: paramater value case "trim": // curve body: outer trimming loop case "hole": // curve body: inner trimming loop case "scrv": // curve body: special curve case "sp": // curve body: special point case "end": // curve body: end case "con": // connection between free form surfaces case "vp": // paramater space vertex (for free form surfaces) case "bevel": // bevel interpolation case "c_interp": // color interpolation case "d_interp": // dissolve interpolation case "lod": // level of detail case "ctech": // Curve approximation technique case "stech": // Surface approximation technique case "mg": // merging group (for free form surfaces) throw new WavefrontObjParseException("WavefrontObjLoader.cs: fatal error, token not supported : " + firstToken); /* unsupported features - warning */ case "o": // object name case "g": // group name case "s": // smoothing group case "shadow_obj": // shadow casting case "trace_obj": // ray tracing Console.WriteLine("WavefrontObjLoader.cs: warning - unsupported wavefront token : " + firstToken); break; /* supported features */ case "#": // Nothing to read, these are comments. break; case "v": // Vertex position positions.Add(WavefrontParser.readVector4(lineContent, null)); break; case "vn": // vertex normal direction vector normals.Add(WavefrontParser.readVector3(lineContent, null)); break; case "vt": // Vertex texcoordinate texCoords.Add(WavefrontParser.readVector2(lineContent, null)); break; case "f": // Face string[] values = WavefrontParser.FilteredSplit(lineContent, null); int numPoints = values.Length; Face face = new Face(); face.v_idx = new Int16[numPoints]; face.n_idx = new Int16[numPoints]; face.tex_idx = new Int16[numPoints]; // todo: how do outside clients know if there were texcoords or not?!?! for (int i = 0; i < numPoints; i++) { // format is "loc_index[/tex_index[/normal_index]]" e.g. 3 ; 3/2 ; 3/2/5 // but middle part can me empty, e.g. 3//5 string[] indexes = values[i].Split('/'); int iPosition = (int.Parse(indexes[0]) - 1); // adjust 1-based index if (iPosition < 0) { iPosition += positions.Count + 1; } // adjust negative indicies face.v_idx[i] = (Int16)iPosition; numIndices++; // initialize other indicies to not provided, in case they are missing face.n_idx[i] = -1; face.tex_idx[i] = -1; if (indexes.Length > 1) { string tex_index = indexes[1]; if (tex_index != "") { int iTexCoord = int.Parse(tex_index) - 1; // adjust 1-based index if (iTexCoord < 0) { iTexCoord += texCoords.Count + 1; } // adjust negative indicies face.tex_idx[i] = (Int16)iTexCoord; } if (indexes.Length > 2) { hasNormals = true; int iNormal = int.Parse(indexes[2]) - 1; // adjust 1 based index if (iNormal < 0) { iNormal += normals.Count + 1; } // adjust negative indicies face.n_idx[i] = (Int16)iNormal; } } } if (currentMaterial == null) { // no material in file, so create one currentMaterial = createImplicitMaterial(); } currentMaterial.faces.Add(face); currentMaterial.nbrIndices += face.v_idx.Length; numFaces++; break; case "mtllib": // load named material file string mtlFile = lineContent; { var mtls = SSWavefrontMTLInfo.ReadMTLs(Path.Combine(basePath, mtlFile)); foreach (var mtl in mtls) { materials.Add(new MaterialInfoWithFaces(mtl)); } } break; case "usemtl": // use named material (from material file previously loaded) bool found = false; string matName = lineContent; for (int i = 0; i < materials.Count; i++) { if (matName.Equals(materials[i].mtl.name)) { found = true; currentMaterial = materials[i]; } } if (!found) { throw new WavefrontObjParseException("Materials are already loaded so we should have it!"); } break; } next_line: //Read the next line line = sr.ReadLine(); } //close the file sr.Close(); // debug print loaded stats Console.WriteLine("WavefrontObjLoader.cs: file processed..."); Console.WriteLine(" vertex positions: {0}", positions.Count); Console.WriteLine(" vertex normals: {0}", normals.Count); Console.WriteLine(" vertex texCoords: {0}", texCoords.Count); foreach (var mtl in materials) { Console.WriteLine( " Material: faces: {1} indicies: {2} ({0})", mtl.mtl.name, mtl.faces.Count, mtl.nbrIndices); Console.WriteLine( " diff Tex: {0}", mtl.mtl.diffuseTextureResourceName); } Console.WriteLine("WavefrontObjLoader.cs: end."); }
/// <summary> /// This method is used to load information stored in .mtl files referenced by the .obj file. /// </summary> /// <param name="d3ddevice"></param> /// <param name="file"></param> private void parseOBJ(SSAssetManager.Context ctx, string filename) { MaterialInfoWithFaces currentMaterial = null; StreamReader sr = ctx.OpenText(filename); //Read the first line of text string line = sr.ReadLine(); //Continue to read until you reach end of file while (line != null) { string[] tokens = line.Split(" ".ToArray(), 2); if (tokens.Length < 2) { goto next_line; } string firstToken = tokens[0]; string lineContent = tokens[1]; switch (firstToken) { case "#": // Nothing to read, these are comments. break; case "v": // Vertex position positions.Add(WavefrontParser.readVector4(lineContent, null)); break; case "vn": // vertex normal direction vector normals.Add(WavefrontParser.readVector3(lineContent, null)); break; case "vt": // Vertex texcoordinate texCoords.Add(WavefrontParser.readVector2(lineContent, null)); break; case "f": // Face string[] values = WavefrontParser.FilteredSplit(lineContent, null); int numPoints = values.Length; Face face = new Face(); face.v_idx = new Int16[numPoints]; face.n_idx = new Int16[numPoints]; face.tex_idx = new Int16[numPoints]; // todo: how do outside clients know if there were texcoords or not?!?! for (int i = 0; i < numPoints; i++) { // format is "loc_index[/tex_index[/normal_index]]" e.g. 3 ; 3/2 ; 3/2/5 // but middle part can me empty, e.g. 3//5 string[] indexes = values[i].Split('/'); int iPosition = (int.Parse(indexes[0]) - 1); // adjust 1-based index if (iPosition < 0) { iPosition += positions.Count + 1; } // adjust negative indicies face.v_idx[i] = (Int16)iPosition; numIndices++; // initialize other indicies to not provided, in case they are missing face.n_idx[i] = -1; face.tex_idx[i] = -1; if (indexes.Length > 1) { string tex_index = indexes[1]; if (tex_index != "") { int iTexCoord = int.Parse(tex_index) - 1; // adjust 1-based index if (iTexCoord < 0) { iTexCoord += texCoords.Count + 1; } // adjust negative indicies face.tex_idx[i] = (Int16)iTexCoord; } if (indexes.Length > 2) { hasNormals = true; int iNormal = int.Parse(indexes[2]) - 1; // adjust 1 based index if (iNormal < 0) { iNormal += normals.Count + 1; } // adjust negative indicies face.n_idx[i] = (Int16)iNormal; } } } if (currentMaterial == null) { // no material in file, so create one currentMaterial = createImplicitMaterial(); } currentMaterial.faces.Add(face); currentMaterial.nbrIndices += face.v_idx.Length; numFaces++; break; case "mtllib": // load named material file string mtlFile = lineContent; { var mtls = SSWavefrontMTLInfo.ReadMTLs(ctx, mtlFile); foreach (var mtl in mtls) { materials.Add(new MaterialInfoWithFaces(mtl)); } } break; case "usemtl": // use named material (from material file previously loaded) bool found = false; string matName = lineContent; for (int i = 0; i < materials.Count; i++) { if (matName.Equals(materials[i].mtl.name)) { found = true; currentMaterial = materials[i]; } } if (!found) { throw new WavefrontObjParseException("Materials are already loaded so we should have it!"); } break; } next_line: //Read the next line line = sr.ReadLine(); } //close the file sr.Close(); }