public static ObjFile FromStream(Stream stream) { if (stream == null) { throw new ArgumentNullException("stream"); } var obj = new ObjFile(); var context = new ObjFileReaderContext(obj); foreach (var values in LineReader.Read(stream)) { switch (values[0].ToLowerInvariant()) { case "v": { if (values.Length < 4) { throw new InvalidDataException("A v statement must specify at least 3 values."); } float x = float.Parse(values[1], CultureInfo.InvariantCulture); float y = float.Parse(values[2], CultureInfo.InvariantCulture); float z = float.Parse(values[3], CultureInfo.InvariantCulture); float w = 1.0f; bool hasColor = false; float r = 0.0f; float g = 0.0f; float b = 0.0f; float a = 1.0f; if (values.Length == 4 || values.Length == 5) { if (values.Length == 5) { w = float.Parse(values[4], CultureInfo.InvariantCulture); } } else if (values.Length == 7 || values.Length == 8) { hasColor = true; r = float.Parse(values[4], CultureInfo.InvariantCulture); g = float.Parse(values[5], CultureInfo.InvariantCulture); b = float.Parse(values[6], CultureInfo.InvariantCulture); if (values.Length == 8) { a = float.Parse(values[7], CultureInfo.InvariantCulture); } } else { throw new InvalidDataException("A v statement has too many values."); } var v = new ObjVertex(); v.Position = new ObjVector4(x, y, z, w); if (hasColor) { v.Color = new ObjVector4(r, g, b, a); } obj.Vertices.Add(v); break; } case "vp": { if (values.Length < 2) { throw new InvalidDataException("A vp statement must specify at least 1 value."); } var v = new ObjVector3(); v.X = float.Parse(values[1], CultureInfo.InvariantCulture); if (values.Length == 2) { v.Y = 0.0f; v.Z = 1.0f; } else if (values.Length == 3) { v.Y = float.Parse(values[2], CultureInfo.InvariantCulture); v.Z = 1.0f; } else if (values.Length == 4) { v.Y = float.Parse(values[2], CultureInfo.InvariantCulture); v.Z = float.Parse(values[3], CultureInfo.InvariantCulture); } else { throw new InvalidDataException("A vp statement has too many values."); } obj.ParameterSpaceVertices.Add(v); break; } case "vn": { if (values.Length < 4) { throw new InvalidDataException("A vn statement must specify 3 values."); } if (values.Length != 4) { throw new InvalidDataException("A vn statement has too many values."); } var v = new ObjVector3(); v.X = float.Parse(values[1], CultureInfo.InvariantCulture); v.Y = float.Parse(values[2], CultureInfo.InvariantCulture); v.Z = float.Parse(values[3], CultureInfo.InvariantCulture); obj.VertexNormals.Add(v); break; } case "vt": { if (values.Length < 2) { throw new InvalidDataException("A vt statement must specify at least 1 value."); } var v = new ObjVector3(); v.X = float.Parse(values[1], CultureInfo.InvariantCulture); if (values.Length == 2) { v.Y = 0.0f; v.Z = 0.0f; } else if (values.Length == 3) { v.Y = float.Parse(values[2], CultureInfo.InvariantCulture); v.Z = 0.0f; } else if (values.Length == 4) { v.Y = float.Parse(values[2], CultureInfo.InvariantCulture); v.Z = float.Parse(values[3], CultureInfo.InvariantCulture); } else { throw new InvalidDataException("A vt statement has too many values."); } obj.TextureVertices.Add(v); break; } case "cstype": ObjFileReader.ParseFreeFormType(context, values); break; case "deg": if (values.Length < 2) { throw new InvalidDataException("A deg statement must specify at least 1 value."); } if (values.Length == 2) { context.DegreeU = int.Parse(values[1]); context.DegreeV = 0; } else if (values.Length == 3) { context.DegreeU = int.Parse(values[1], CultureInfo.InvariantCulture); context.DegreeV = int.Parse(values[2], CultureInfo.InvariantCulture); } else { throw new InvalidDataException("A deg statement has too many values."); } break; case "bmat": { if (values.Length < 2) { throw new InvalidDataException("A bmat statement must specify a direction."); } int d; if (string.Equals(values[1], "u", StringComparison.OrdinalIgnoreCase)) { d = 1; } else if (string.Equals(values[1], "v", StringComparison.OrdinalIgnoreCase)) { d = 2; } else { throw new InvalidDataException("A bmat statement has an unknown direction."); } int count = (context.DegreeU + 1) * (context.DegreeV + 1); if (values.Length != count + 2) { throw new InvalidDataException("A bmat statement has too many or too few values."); } var matrix = new float[count]; for (int i = 0; i < count; i++) { matrix[i] = float.Parse(values[2 + i], CultureInfo.InvariantCulture); } switch (d) { case 1: context.BasicMatrixU = matrix; break; case 2: context.BasicMatrixV = matrix; break; } break; } case "step": if (values.Length < 2) { throw new InvalidDataException("A step statement must specify at least 1 value."); } if (values.Length == 2) { context.StepU = float.Parse(values[1], CultureInfo.InvariantCulture); context.StepV = 1.0f; } else if (values.Length == 3) { context.StepU = float.Parse(values[1], CultureInfo.InvariantCulture); context.StepV = float.Parse(values[2], CultureInfo.InvariantCulture); } else { throw new InvalidDataException("A step statement has too many values."); } break; case "p": { if (values.Length < 2) { throw new InvalidDataException("A p statement must specify at least 1 value."); } var point = new ObjPoint(); for (int i = 1; i < values.Length; i++) { point.Vertices.Add(ObjFileReader.ParseTriplet(obj, values[i])); } context.ApplyAttributesToElement(point); context.ApplyAttributesToPolygonalElement(point); obj.Points.Add(point); foreach (var group in context.GetCurrentGroups()) { group.Points.Add(point); } break; } case "l": { if (values.Length < 3) { throw new InvalidDataException("A l statement must specify at least 2 values."); } var line = new ObjLine(); for (int i = 1; i < values.Length; i++) { line.Vertices.Add(ObjFileReader.ParseTriplet(obj, values[i])); } context.ApplyAttributesToElement(line); context.ApplyAttributesToPolygonalElement(line); obj.Lines.Add(line); foreach (var group in context.GetCurrentGroups()) { group.Lines.Add(line); } break; } case "f": case "fo": { if (values.Length < 4) { throw new InvalidDataException("A f statement must specify at least 3 values."); } var face = new ObjFace(); for (int i = 1; i < values.Length; i++) { face.Vertices.Add(ObjFileReader.ParseTriplet(obj, values[i])); } context.ApplyAttributesToElement(face); context.ApplyAttributesToPolygonalElement(face); obj.Faces.Add(face); foreach (var group in context.GetCurrentGroups()) { group.Faces.Add(face); } break; } case "curv": { if (values.Length < 5) { throw new InvalidDataException("A curv statement must specify at least 4 values."); } var curve = new ObjCurve(); curve.StartParameter = float.Parse(values[1], CultureInfo.InvariantCulture); curve.EndParameter = float.Parse(values[2], CultureInfo.InvariantCulture); for (int i = 3; i < values.Length; i++) { int v = int.Parse(values[i], CultureInfo.InvariantCulture); if (v == 0) { throw new InvalidDataException("A curv statement contains an invalid vertex index."); } if (v < 0) { v = obj.Vertices.Count + v + 1; } if (v <= 0 || v > obj.Vertices.Count) { throw new IndexOutOfRangeException(); } curve.Vertices.Add(v); } context.ApplyAttributesToElement(curve); context.ApplyAttributesToFreeFormElement(curve); context.CurrentFreeFormElement = curve; obj.Curves.Add(curve); foreach (var group in context.GetCurrentGroups()) { group.Curves.Add(curve); } break; } case "curv2": { if (values.Length < 3) { throw new InvalidDataException("A curv2 statement must specify at least 2 values."); } var curve = new ObjCurve2D(); for (int i = 1; i < values.Length; i++) { int vp = int.Parse(values[i], CultureInfo.InvariantCulture); if (vp == 0) { throw new InvalidDataException("A curv2 statement contains an invalid parameter space vertex index."); } if (vp < 0) { vp = obj.ParameterSpaceVertices.Count + vp + 1; } if (vp <= 0 || vp > obj.ParameterSpaceVertices.Count) { throw new IndexOutOfRangeException(); } curve.ParameterSpaceVertices.Add(vp); } context.ApplyAttributesToElement(curve); context.ApplyAttributesToFreeFormElement(curve); context.CurrentFreeFormElement = curve; obj.Curves2D.Add(curve); foreach (var group in context.GetCurrentGroups()) { group.Curves2D.Add(curve); } break; } case "surf": { if (values.Length < 6) { throw new InvalidDataException("A surf statement must specify at least 5 values."); } var surface = new ObjSurface(); surface.StartParameterU = float.Parse(values[1], CultureInfo.InvariantCulture); surface.EndParameterU = float.Parse(values[2], CultureInfo.InvariantCulture); surface.StartParameterV = float.Parse(values[3], CultureInfo.InvariantCulture); surface.EndParameterV = float.Parse(values[4], CultureInfo.InvariantCulture); for (int i = 5; i < values.Length; i++) { surface.Vertices.Add(ObjFileReader.ParseTriplet(obj, values[i])); } context.ApplyAttributesToElement(surface); context.ApplyAttributesToFreeFormElement(surface); context.CurrentFreeFormElement = surface; obj.Surfaces.Add(surface); foreach (var group in context.GetCurrentGroups()) { group.Surfaces.Add(surface); } break; } case "parm": if (context.CurrentFreeFormElement == null) { break; } if (values.Length < 4) { throw new InvalidDataException("A parm statement must specify at least 3 values."); } IList <float> parameters; if (string.Equals(values[1], "u", StringComparison.OrdinalIgnoreCase)) { parameters = context.CurrentFreeFormElement.ParametersU; } else if (string.Equals(values[1], "v", StringComparison.OrdinalIgnoreCase)) { parameters = context.CurrentFreeFormElement.ParametersV; } else { throw new InvalidDataException("A parm statement has an unknown direction."); } for (int i = 2; i < values.Length; i++) { parameters.Add(float.Parse(values[i], CultureInfo.InvariantCulture)); } break; case "trim": if (context.CurrentFreeFormElement == null) { break; } ObjFileReader.ParseCurveIndex(context.CurrentFreeFormElement.OuterTrimmingCurves, obj, values); break; case "hole": if (context.CurrentFreeFormElement == null) { break; } ObjFileReader.ParseCurveIndex(context.CurrentFreeFormElement.InnerTrimmingCurves, obj, values); break; case "scrv": if (context.CurrentFreeFormElement == null) { break; } ObjFileReader.ParseCurveIndex(context.CurrentFreeFormElement.SequenceCurves, obj, values); break; case "sp": if (context.CurrentFreeFormElement == null) { break; } if (values.Length < 2) { throw new InvalidDataException("A sp statement must specify at least 1 value."); } for (int i = 1; i < values.Length; i++) { int vp = int.Parse(values[i], CultureInfo.InvariantCulture); if (vp == 0) { throw new InvalidDataException("A sp statement contains an invalid parameter space vertex index."); } if (vp < 0) { vp = obj.ParameterSpaceVertices.Count + vp + 1; } if (vp <= 0 || vp > obj.ParameterSpaceVertices.Count) { throw new IndexOutOfRangeException(); } context.CurrentFreeFormElement.SpecialPoints.Add(vp); } break; case "end": context.CurrentFreeFormElement = null; break; case "con": ObjFileReader.ParseSurfaceConnection(obj, values); break; case "g": ObjFileReader.ParseGroupName(values, context); break; case "s": if (values.Length < 2) { throw new InvalidDataException("A s statement must specify a value."); } if (values.Length != 2) { throw new InvalidDataException("A s statement has too many values."); } if (string.Equals(values[1], "off", StringComparison.OrdinalIgnoreCase)) { context.SmoothingGroupNumber = 0; } else { context.SmoothingGroupNumber = int.Parse(values[1], CultureInfo.InvariantCulture); } break; case "mg": if (values.Length < 2) { throw new InvalidDataException("A mg statement must specify a value."); } if (string.Equals(values[1], "off", StringComparison.OrdinalIgnoreCase)) { context.MergingGroupNumber = 0; } else { context.MergingGroupNumber = int.Parse(values[1], CultureInfo.InvariantCulture); } if (context.MergingGroupNumber == 0) { if (values.Length > 3) { throw new InvalidDataException("A mg statement has too many values."); } } else { if (values.Length != 3) { throw new InvalidDataException("A mg statement has too many or too few values."); } float res = float.Parse(values[2], CultureInfo.InvariantCulture); obj.MergingGroupResolutions[context.MergingGroupNumber] = res; } break; case "o": if (values.Length == 1) { context.ObjectName = null; break; } if (values.Length != 2) { throw new InvalidDataException("A o statement has too many values."); } context.ObjectName = values[1]; break; case "bevel": if (values.Length < 2) { throw new InvalidDataException("A bevel statement must specify a name."); } if (values.Length != 2) { throw new InvalidDataException("A bevel statement has too many values."); } if (string.Equals(values[1], "on", StringComparison.OrdinalIgnoreCase)) { context.IsBevelInterpolationEnabled = true; } else if (string.Equals(values[1], "off", StringComparison.OrdinalIgnoreCase)) { context.IsBevelInterpolationEnabled = false; } else { throw new InvalidDataException("A bevel statement must specify on or off."); } break; case "c_interp": if (values.Length < 2) { throw new InvalidDataException("A c_interp statement must specify a name."); } if (values.Length != 2) { throw new InvalidDataException("A c_interp statement has too many values."); } if (string.Equals(values[1], "on", StringComparison.OrdinalIgnoreCase)) { context.IsColorInterpolationEnabled = true; } else if (string.Equals(values[1], "off", StringComparison.OrdinalIgnoreCase)) { context.IsColorInterpolationEnabled = false; } else { throw new InvalidDataException("A c_interp statement must specify on or off."); } break; case "d_interp": if (values.Length < 2) { throw new InvalidDataException("A d_interp statement must specify a name."); } if (values.Length != 2) { throw new InvalidDataException("A d_interp statement has too many values."); } if (string.Equals(values[1], "on", StringComparison.OrdinalIgnoreCase)) { context.IsDissolveInterpolationEnabled = true; } else if (string.Equals(values[1], "off", StringComparison.OrdinalIgnoreCase)) { context.IsDissolveInterpolationEnabled = false; } else { throw new InvalidDataException("A d_interp statement must specify on or off."); } break; case "lod": if (values.Length < 2) { throw new InvalidDataException("A lod statement must specify a value."); } if (values.Length != 2) { throw new InvalidDataException("A lod statement has too many values."); } context.LevelOfDetail = int.Parse(values[1], CultureInfo.InvariantCulture); break; case "maplib": if (values.Length < 2) { throw new InvalidDataException("A maplib statement must specify a file name."); } for (int i = 1; i < values.Length; i++) { if (!Path.HasExtension(values[i])) { throw new InvalidDataException("A file name must have an extension."); } obj.MapLibraries.Add(values[i]); } break; case "mtllib": if (values.Length < 2) { throw new InvalidDataException("A mtllib statement must specify a file name."); } for (int i = 1; i < values.Length; i++) { if (!Path.HasExtension(values[i])) { throw new InvalidDataException("A file name must have an extension."); } obj.MaterialLibraries.Add(values[i]); } break; case "usemap": if (values.Length < 2) { throw new InvalidDataException("A usemap statement must specify a value."); } if (values.Length != 2) { throw new InvalidDataException("A usemap statement has too many values."); } if (string.Equals(values[1], "off", StringComparison.OrdinalIgnoreCase)) { context.MapName = null; } else { context.MapName = values[1]; } break; case "usemtl": if (values.Length < 2) { throw new InvalidDataException("A usemtl statement must specify a value."); } if (values.Length != 2) { throw new InvalidDataException("A usemtl statement has too many values."); } if (string.Equals(values[1], "off", StringComparison.OrdinalIgnoreCase)) { context.MaterialName = null; } else { context.MaterialName = values[1]; } break; case "shadow_obj": if (values.Length < 2) { throw new InvalidDataException("A shadow_obj statement must specify a file name."); } if (values.Length != 2) { throw new InvalidDataException("A shadow_obj statement has too many values."); } if (!Path.HasExtension(values[1])) { throw new InvalidDataException("A file name must have an extension."); } obj.ShadowObjectFileName = values[1]; break; case "trace_obj": if (values.Length < 2) { throw new InvalidDataException("A trace_obj statement must specify a file name."); } if (values.Length != 2) { throw new InvalidDataException("A trace_obj statement has too many values."); } if (!Path.HasExtension(values[1])) { throw new InvalidDataException("A file name must have an extension."); } obj.TraceObjectFileName = values[1]; break; case "ctech": context.CurveApproximationTechnique = ObjFileReader.ParseApproximationTechnique(values); break; case "stech": context.SurfaceApproximationTechnique = ObjFileReader.ParseApproximationTechnique(values); break; case "bsp": case "bzp": case "cdc": case "cdp": case "res": throw new NotImplementedException(string.Concat(values[0], " statement have been replaced by free-form geometry statements.")); } } return(obj); }
private static ObjMaterialMap ParseMaterialMap(string statement, string[] values) { var map = new ObjMaterialMap(); for (int index = 0; index < values.Length;) { index++; if (values.Length - index < 1) { throw new InvalidDataException(string.Concat("A ", statement, " statement must specify a filename.")); } switch (values[index].ToLowerInvariant()) { case "-type": if (values.Length - index < 2) { throw new InvalidDataException(string.Concat("A ", statement, " -type option must specify a value.")); } index++; break; case "-blenu": if (values.Length - index < 2) { throw new InvalidDataException(string.Concat("A ", statement, " -blenu option must specify a value.")); } if (string.Equals(values[index + 1], "on", StringComparison.OrdinalIgnoreCase)) { map.IsHorizontalBlendingEnabled = true; } else if (string.Equals(values[index + 1], "off", StringComparison.OrdinalIgnoreCase)) { map.IsHorizontalBlendingEnabled = false; } else { throw new InvalidDataException(string.Concat("A ", statement, " -blenu option must specify on or off.")); } index++; break; case "-blenv": if (values.Length - index < 2) { throw new InvalidDataException(string.Concat("A ", statement, " -blenv option must specify a value.")); } if (string.Equals(values[index + 1], "on", StringComparison.OrdinalIgnoreCase)) { map.IsVerticalBlendingEnabled = true; } else if (string.Equals(values[index + 1], "off", StringComparison.OrdinalIgnoreCase)) { map.IsVerticalBlendingEnabled = false; } else { throw new InvalidDataException(string.Concat("A ", statement, " -blenv option must specify on or off.")); } index++; break; case "-bm": if (values.Length - index < 2) { throw new InvalidDataException(string.Concat("A ", statement, " -bm option must specify a value.")); } map.BumpMultiplier = float.Parse(values[index + 1], CultureInfo.InvariantCulture); index++; break; case "-boost": if (values.Length - index < 2) { throw new InvalidDataException(string.Concat("A ", statement, " -boost option must specify a value.")); } map.Boost = float.Parse(values[index + 1], CultureInfo.InvariantCulture); index++; break; case "-cc": if (values.Length - index < 2) { throw new InvalidDataException(string.Concat("A ", statement, " -cc option must specify a value.")); } if (string.Equals(values[index + 1], "on", StringComparison.OrdinalIgnoreCase)) { map.IsColorCorrectionEnabled = true; } else if (string.Equals(values[index + 1], "off", StringComparison.OrdinalIgnoreCase)) { map.IsColorCorrectionEnabled = false; } else { throw new InvalidDataException(string.Concat("A ", statement, " -cc option must specify on or off.")); } index++; break; case "-clamp": if (values.Length - index < 2) { throw new InvalidDataException(string.Concat("A ", statement, " -clamp option must specify a value.")); } if (string.Equals(values[index + 1], "on", StringComparison.OrdinalIgnoreCase)) { map.IsClampingEnabled = true; } else if (string.Equals(values[index + 1], "off", StringComparison.OrdinalIgnoreCase)) { map.IsClampingEnabled = false; } else { throw new InvalidDataException(string.Concat("A ", statement, " -clamp option must specify on or off.")); } index++; break; case "-imfchan": if (values.Length - index < 2) { throw new InvalidDataException(string.Concat("A ", statement, " -imfchan option must specify a value.")); } switch (values[index + 1].ToLowerInvariant()) { case "r": map.ScalarChannel = ObjMapChannel.Red; break; case "g": map.ScalarChannel = ObjMapChannel.Green; break; case "b": map.ScalarChannel = ObjMapChannel.Blue; break; case "m": map.ScalarChannel = ObjMapChannel.Matte; break; case "l": map.ScalarChannel = ObjMapChannel.Luminance; break; case "z": map.ScalarChannel = ObjMapChannel.Depth; break; default: throw new InvalidDataException(string.Concat("A ", statement, " -imfchan option must specify a value in (r, g, b, m, l, z).")); } index++; break; case "-mm": if (values.Length - index < 3) { throw new InvalidDataException(string.Concat("A ", statement, " -mm option must specify a base and a gain.")); } map.ModifierBase = float.Parse(values[index + 1], CultureInfo.InvariantCulture); map.ModifierGain = float.Parse(values[index + 2], CultureInfo.InvariantCulture); index += 2; break; case "-o": if (values.Length - index < 2) { throw new InvalidDataException(string.Concat("A ", statement, " -o option must specify at least 2 values.")); } var offset = new ObjVector3(); offset.X = float.Parse(values[index + 1], CultureInfo.InvariantCulture); if (values.Length - index > 3) { offset.Y = float.Parse(values[index + 2], CultureInfo.InvariantCulture); if (values.Length - index > 4) { offset.Z = float.Parse(values[index + 3], CultureInfo.InvariantCulture); index++; } index++; } index++; map.Offset = offset; break; case "-s": if (values.Length - index < 2) { throw new InvalidDataException(string.Concat("A ", statement, " -s option must specify at least 2 values.")); } var scale = new ObjVector3(1.0f, 1.0f, 1.0f); scale.X = float.Parse(values[index + 1], CultureInfo.InvariantCulture); if (values.Length - index > 3) { scale.Y = float.Parse(values[index + 2], CultureInfo.InvariantCulture); if (values.Length - index > 4) { scale.Z = float.Parse(values[index + 3], CultureInfo.InvariantCulture); index++; } index++; } index++; map.Scale = scale; break; case "-t": if (values.Length - index < 2) { throw new InvalidDataException(string.Concat("A ", statement, " -t option must specify at least 2 values.")); } var turbulence = new ObjVector3(); turbulence.X = float.Parse(values[index + 1], CultureInfo.InvariantCulture); if (values.Length - index > 3) { turbulence.Y = float.Parse(values[index + 2], CultureInfo.InvariantCulture); if (values.Length - index > 4) { turbulence.Z = float.Parse(values[index + 3], CultureInfo.InvariantCulture); index++; } index++; } index++; map.Turbulence = turbulence; break; case "-texres": if (values.Length - index < 2) { throw new InvalidDataException(string.Concat("A ", statement, " -texres option must specify a value.")); } map.TextureResolution = int.Parse(values[index + 1], CultureInfo.InvariantCulture); index++; break; default: if (!Path.HasExtension(values[index])) { throw new InvalidDataException("A filename must have an extension."); } map.FileName = values[index]; index++; if (index != values.Length) { throw new InvalidDataException(string.Concat("A ", statement, " has too many values.")); } break; } } return(map); }
private static void WriteMap(string statement, ObjMaterialMap map, StreamWriter stream) { // TODO: write tests stream.Write(statement); if (!map.IsHorizontalBlendingEnabled) { stream.Write(" -blenu off"); } if (!map.IsVerticalBlendingEnabled) { stream.Write(" -blenv off"); } if (map.BumpMultiplier != 0.0f) { stream.Write(" -bm "); stream.Write(map.BumpMultiplier.ToString("F6", CultureInfo.InvariantCulture)); } if (map.Boost != 0.0f) { stream.Write(" -boost "); stream.Write(map.Boost.ToString("F6", CultureInfo.InvariantCulture)); } if (map.IsColorCorrectionEnabled) { stream.Write(" -cc on"); } if (map.IsClampingEnabled) { stream.Write(" -clamp on"); } if (map.ScalarChannel != ObjMapChannel.Luminance) { stream.Write(" -imfchan "); switch (map.ScalarChannel) { case ObjMapChannel.Red: stream.Write("r"); break; case ObjMapChannel.Green: stream.Write("g"); break; case ObjMapChannel.Blue: stream.Write("b"); break; case ObjMapChannel.Matte: stream.Write("m"); break; case ObjMapChannel.Depth: stream.Write("z"); break; default: stream.Write("l"); break; } } if (map.ModifierBase != 0.0f || map.ModifierGain != 1.0f) { stream.Write(" -mm "); stream.Write(map.ModifierBase.ToString("F6", CultureInfo.InvariantCulture)); stream.Write(' '); stream.Write(map.ModifierGain.ToString("F6", CultureInfo.InvariantCulture)); } ObjVector3 offset = map.Offset; if (offset.X != 0.0f || offset.Y != 0.0f || offset.Z != 0.0f) { stream.Write(" -o "); stream.Write(offset.X.ToString("F6", CultureInfo.InvariantCulture)); stream.Write(' '); stream.Write(offset.Y.ToString("F6", CultureInfo.InvariantCulture)); stream.Write(' '); stream.Write(offset.Z.ToString("F6", CultureInfo.InvariantCulture)); } ObjVector3 scale = map.Scale; if (scale.X != 1.0f || scale.Y != 1.0f || scale.Z != 1.0f) { stream.Write(" -s "); stream.Write(scale.X.ToString("F6", CultureInfo.InvariantCulture)); stream.Write(' '); stream.Write(scale.Y.ToString("F6", CultureInfo.InvariantCulture)); stream.Write(' '); stream.Write(scale.Z.ToString("F6", CultureInfo.InvariantCulture)); } ObjVector3 turbulence = map.Turbulence; if (turbulence.X != 0.0f || turbulence.Y != 0.0f || turbulence.Z != 0.0f) { stream.Write(" -t "); stream.Write(turbulence.X.ToString("F6", CultureInfo.InvariantCulture)); stream.Write(' '); stream.Write(turbulence.Y.ToString("F6", CultureInfo.InvariantCulture)); stream.Write(' '); stream.Write(turbulence.Z.ToString("F6", CultureInfo.InvariantCulture)); } if (map.TextureResolution != 0) { stream.Write(" -texres "); stream.Write(map.TextureResolution); } stream.Write(' '); stream.WriteLine(map.FileName); }
private static ObjMaterialColor ParseMaterialColor(string statement, string[] values) { if (values.Length < 2) { throw new InvalidDataException(string.Concat("A ", statement, " statement must specify a color.")); } var color = new ObjMaterialColor(); int index = 1; switch (values[1].ToLowerInvariant()) { case "spectral": index++; if (values.Length - index < 1) { throw new InvalidDataException(string.Concat("A ", statement, " spectral statement must specify a file name.")); } if (!Path.HasExtension(values[index])) { throw new InvalidDataException("A filename must have an extension."); } color.SpectralFileName = values[index]; index++; if (values.Length > index) { color.SpectralFactor = float.Parse(values[index], CultureInfo.InvariantCulture); index++; } break; case "xyz": index++; if (values.Length - index < 1) { throw new InvalidDataException(string.Concat("A ", statement, " xyz statement must specify a color.")); } color.UseXYZColorSpace = true; var xyz = new ObjVector3(); xyz.X = float.Parse(values[index], CultureInfo.InvariantCulture); index++; if (values.Length > index) { if (values.Length - index < 2) { throw new InvalidDataException(string.Concat("A ", statement, " xyz statement must specify a XYZ color.")); } xyz.Y = float.Parse(values[index], CultureInfo.InvariantCulture); xyz.Z = float.Parse(values[index + 1], CultureInfo.InvariantCulture); index += 2; } else { xyz.Y = xyz.X; xyz.Z = xyz.X; } color.Color = xyz; break; default: var rgb = new ObjVector3(); rgb.X = float.Parse(values[index], CultureInfo.InvariantCulture); index++; if (values.Length > index) { if (values.Length - index < 2) { throw new InvalidDataException(string.Concat("A ", statement, " statement must specify a RGB color.")); } rgb.Y = float.Parse(values[index], CultureInfo.InvariantCulture); rgb.Z = float.Parse(values[index + 1], CultureInfo.InvariantCulture); index += 2; } else { rgb.Y = rgb.X; rgb.Z = rgb.X; } color.Color = rgb; break; } if (index != values.Length) { throw new InvalidDataException(string.Concat("A ", statement, " statement has too many values.")); } return(color); }