protected virtual void SP(IObjReaderState state, ObjToken token, string[] values) { if (state.FreeFormElement == default) { return; } if (values.Length < 2) { throw new InvalidDataException(string.Format("The <{0}> statement must specify at least 1 value. Line: {1}.", token, state.LineNumber)); } for (int i = 1; i < values.Length; i++) { var vp = int.Parse(values[i], CultureInfo.InvariantCulture); if (vp == 0) { throw new InvalidDataException(string.Format("The <{0}> statement contains an invalid parameter space vertex index. Line: {1}.", token, state.LineNumber)); } if (vp < 0) { vp = state.Obj.SpaceVertices.Count + vp + 1; } if (vp <= 0 || vp > state.Obj.SpaceVertices.Count) { throw new IndexOutOfRangeException(); } state.FreeFormElement.SpecialPoints.Add(vp); } }
protected virtual void Surf(IObjReaderState state, ObjToken token, string[] values) { if (values.Length < 6) { throw new InvalidDataException(string.Format("The <{0}> statement must specify at least 5 values. Line: {1}.", token, state.LineNumber)); } var surface = new Surface() { StartU = float.Parse(values[1], CultureInfo.InvariantCulture), EndU = float.Parse(values[2], CultureInfo.InvariantCulture), StartV = float.Parse(values[3], CultureInfo.InvariantCulture), EndV = float.Parse(values[4], CultureInfo.InvariantCulture) }; for (int i = 5; i < values.Length; i++) { surface.Vertices.Add(Triplet(state, token, values[i])); } state.ApplyAttributesToElement(surface); state.ApplyAttributesToFreeFormElement(surface); state.FreeFormElement = surface; state.Obj.Surfaces.Add(surface); foreach (var group in state.GetCurrentGroups()) { group.Surfaces.Add(surface); } }
protected virtual Triplet Triplet(IObjReaderState state, ObjToken token, string value) { var values = value.Split('/'); if (values.Length > 3) { throw new InvalidDataException(string.Format("The <{0}> has too many values. Line: {1}.", token, state.LineNumber)); } var v = !string.IsNullOrEmpty(values[0]) ? int.Parse(values[0], CultureInfo.InvariantCulture) : 0; if (v == 0) { throw new InvalidDataException(string.Format("The <{0}> must specify a vertex index. Line: {1}.", token, state.LineNumber)); } if (v < 0) { v = state.Obj.Vertices.Count + v + 1; } if (v <= 0 || v > state.Obj.Vertices.Count) { throw new IndexOutOfRangeException(); } var vt = values.Length > 1 && !string.IsNullOrEmpty(values[1]) ? int.Parse(values[1], CultureInfo.InvariantCulture) : 0; if (vt != 0) { if (vt < 0) { vt = state.Obj.TextureVertices.Count + vt + 1; } if (vt <= 0 || vt > state.Obj.TextureVertices.Count) { throw new IndexOutOfRangeException(); } } var vn = values.Length > 2 && !string.IsNullOrEmpty(values[2]) ? int.Parse(values[2], CultureInfo.InvariantCulture) : 0; if (vn != 0) { if (vn < 0) { vn = state.Obj.VertexNormals.Count + vn + 1; } if (vn <= 0 || vn > state.Obj.VertexNormals.Count) { throw new IndexOutOfRangeException(); } } return(new Triplet(v, vt, vn)); }
protected virtual void Con(IObjReaderState state, ObjToken token, string[] values) { if (values.Length < 9) { throw new InvalidDataException(string.Format("The <{0}> statement must specify 8 values. Line: {1}.", token, state.LineNumber)); } if (values.Length != 9) { throw new InvalidDataException(string.Format("The <{0}> statement has too many values. Line: {1}.", token, state.LineNumber)); } var surface1 = int.Parse(values[1], CultureInfo.InvariantCulture); if (surface1 == 0) { throw new InvalidDataException(string.Format("The <{0}> statement must specify a surface index. Line: {1}.", token, state.LineNumber)); } if (surface1 < 0) { surface1 = state.Obj.Surfaces.Count + surface1 + 1; } if (surface1 <= 0 || surface1 > state.Obj.Surfaces.Count) { throw new IndexOutOfRangeException(); } var curve1 = CurveIndex(state, values, 2); var surface2 = int.Parse(values[5], CultureInfo.InvariantCulture); if (surface2 == 0) { throw new InvalidDataException(string.Format("The <{0}> statement must specify a surface index. Line: {1}.", token, state.LineNumber)); } if (surface2 < 0) { surface2 = state.Obj.Surfaces.Count + surface2 + 1; } if (surface2 <= 0 || surface2 > state.Obj.Surfaces.Count) { throw new IndexOutOfRangeException(); } var curve2 = CurveIndex(state, values, 6); state.Obj.SurfaceConnections.Add(new SurfaceConnection { Surface1 = surface1, Curve2D1 = curve1, Surface2 = surface2, Curve2D2 = curve2 }); }
protected virtual void Hole(IObjReaderState state, ObjToken token, string[] values) { if (state.FreeFormElement == default) { return; } CurveIndex(state.FreeFormElement.InnerTrimmingCurves, state, token, values); }
protected virtual void Scrv(IObjReaderState state, ObjToken token, string[] values) { if (state.FreeFormElement == default) { return; } CurveIndex(state.FreeFormElement.SequenceCurves, state, token, values); }
protected void LOD(IObjReaderState state, ObjToken token, string[] values) { if (values.Length < 2) { throw new InvalidDataException(string.Format("The <{0}> statement must specify a value. Line: {1}.", token, state.LineNumber)); } if (values.Length != 2) { throw new InvalidDataException(string.Format("The <{0}> statement has too many values. Line: {1}.", token, state.LineNumber)); } state.LevelOfDetail = int.Parse(values[1], CultureInfo.InvariantCulture); }
protected virtual void O(IObjReaderState state, ObjToken token, string[] values) { if (values.Length == 1) { state.ObjectName = default; return; } if (values.Length != 2) { throw new InvalidDataException(string.Format("The <{0}> statement has too many values. Line: {1}.", token, state.LineNumber)); } state.ObjectName = values[1]; }
protected virtual void V(IObjReaderState state, ObjToken token, string[] values) { if (values.Length < 4) { throw new InvalidDataException(string.Format("The <{0}> statement must have at least 3 values. Line: {1}.", token, state.LineNumber)); } var x = float.Parse(values[1], CultureInfo.InvariantCulture); var y = float.Parse(values[2], CultureInfo.InvariantCulture); var z = float.Parse(values[3], CultureInfo.InvariantCulture); var w = 1.0f; var hasColor = false; var r = 0.0f; var g = 0.0f; var b = 0.0f; var 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(string.Format("The <{0}> statement has too many values. Line: {1}.", token, state.LineNumber)); } state.Obj.Vertices.Add(new Vertex(new XYZW(x, y, z, w)) { Color = hasColor ? new XYZW(r, g, b, a) : default });
protected virtual void CurveIndex(IList <CurveIndex> curves, IObjReaderState state, ObjToken token, string[] values) { if (values.Length < 4) { throw new InvalidDataException(string.Format("The <{0}> statement must specify at least 3 value. Line: {1}.", token, state.LineNumber)); } if ((values.Length - 1) % 3 != 0) { throw new InvalidDataException(string.Format("The <{0}> statement has too many values. Line: {1}.", token, state.LineNumber)); } for (int i = 1; i < values.Length; i += 3) { curves.Add(CurveIndex(state, values, i)); } }
protected virtual void G(IObjReaderState state, ObjToken token, string[] values) { state.GroupNames.Clear(); for (int i = 1; i < values.Length; i++) { var name = values[i]; if (!string.Equals(name, "default", StringComparison.OrdinalIgnoreCase)) { state.GroupNames.Add(name); } } state.GetCurrentGroups(); }
protected virtual void Curv(IObjReaderState state, ObjToken token, string[] values) { if (values.Length < 5) { throw new InvalidDataException(string.Format("The <{0}> statement must specify at least 4 values. Line: {1}.", token, state.LineNumber)); } var curve = new Curve() { Start = float.Parse(values[1], CultureInfo.InvariantCulture), End = float.Parse(values[2], CultureInfo.InvariantCulture) }; for (int i = 3; i < values.Length; i++) { var v = int.Parse(values[i], CultureInfo.InvariantCulture); if (v == 0) { throw new InvalidDataException(string.Format("The <{0}> statement contains an invalid vertex index. Line: {1}.", token, state.LineNumber)); } if (v < 0) { v = state.Obj.Vertices.Count + v + 1; } if (v <= 0 || v > state.Obj.Vertices.Count) { throw new IndexOutOfRangeException(); } curve.Vertices.Add(v); } state.ApplyAttributesToElement(curve); state.ApplyAttributesToFreeFormElement(curve); state.FreeFormElement = curve; state.Obj.Curves.Add(curve); foreach (var group in state.GetCurrentGroups()) { group.Curves.Add(curve); } }
protected virtual void MtlLib(IObjReaderState state, ObjToken token, string[] values) { if (values.Length < 2) { throw new InvalidDataException(string.Format("The <{0}> statement must specify a file name. Line: {1}.", token, state.LineNumber)); } for (int i = 1; i < values.Length; i++) { if (!Path.HasExtension(values[1])) { throw new InvalidDataException(string.Format("A file name must have an extension. Value: <{0}>. Line: {1}.", values[1], state.LineNumber)); } state.Obj.MaterialLibraries.Add(values[i]); } }
protected virtual void ShadowObj(IObjReaderState state, ObjToken token, string[] values) { if (values.Length < 2) { throw new InvalidDataException(string.Format("The <{0}> statement must specify a file name. Line: {1}", token, state.LineNumber)); } if (values.Length != 2) { throw new InvalidDataException(string.Format("The <{0}> statement has too many values. Line: {1}.", token, state.LineNumber)); } if (!Path.HasExtension(values[1])) { throw new InvalidDataException(string.Format("A file name must have an extension. Value: <{0}>. Line: {1}.", values[1], state.LineNumber)); } state.Obj.ShadowObjectFileName = values[1]; }
protected virtual void DInterp(IObjReaderState state, ObjToken token, string[] values) { if (values.Length < 2) { throw new InvalidDataException(string.Format("The <{0}> statement must specify a name. Line: {1}.", token, state.LineNumber)); } if (values.Length != 2) { throw new InvalidDataException(string.Format("The <{0}> statement has too many values. Line: {1}.", token, state.LineNumber)); } if (!Enum.TryParse <OnOff>(values[1], true, out var onOff)) { throw new InvalidDataException(string.Format("The <{0}> statement must specify on or off. Line: {1}.", token, state.LineNumber)); } state.IsDissolveInterpolationEnabled = onOff == OnOff.On; }
protected virtual void Curv2(IObjReaderState state, ObjToken token, string[] values) { if (values.Length < 3) { throw new InvalidDataException(string.Format("The <{0}> statement must specify at least 2 values. Line: {1}.", token, state.LineNumber)); } var curve = new Curve2D(); for (int i = 1; i < values.Length; i++) { int vp = int.Parse(values[i], CultureInfo.InvariantCulture); if (vp == 0) { throw new InvalidDataException(string.Format("The <{0}> statement contains an invalid parameter space vertex index. Line: {1}.", token, state.LineNumber)); } if (vp < 0) { vp = state.Obj.SpaceVertices.Count + vp + 1; } if (vp <= 0 || vp > state.Obj.SpaceVertices.Count) { throw new IndexOutOfRangeException(); } curve.SpaceVertices.Add(vp); } state.ApplyAttributesToElement(curve); state.ApplyAttributesToFreeFormElement(curve); state.FreeFormElement = curve; state.Obj.Curves2D.Add(curve); foreach (var group in state.GetCurrentGroups()) { group.Curves2D.Add(curve); } }
protected virtual void BMat(IObjReaderState state, ObjToken token, string[] values) { if (values.Length < 2) { throw new InvalidDataException(string.Format("The <{0}> statement must specify a direction. Line: {1}.", token, state.LineNumber)); } if (!Enum.TryParse <UV>(values[1], true, out var uv)) { throw new InvalidDataException(string.Format("The <{0}> statement has an unknown direction. Line: {1}.", token, state.LineNumber)); } var count = (state.DegreeU + 1) * (state.DegreeV + 1); if (values.Length != count + 2) { throw new InvalidDataException(string.Format("The <{0}> statement has too many or too few values. Line: {1}.", token, state.LineNumber)); } var matrix = new float[count]; for (int i = 0; i < count; i++) { matrix[i] = float.Parse(values[2 + i], CultureInfo.InvariantCulture); } switch (uv) { case UV.U: { state.BasicMatrixU = matrix; break; } case UV.V: { state.BasicMatrixV = matrix; break; } } }
protected virtual void Step(IObjReaderState state, ObjToken token, string[] values) { if (values.Length < 2) { throw new InvalidDataException(string.Format("The <{0}> statement must specify at least 1 value. Line: {1}.", token, state.LineNumber)); } if (values.Length == 2) { state.StepU = float.Parse(values[1], CultureInfo.InvariantCulture); state.StepV = 1.0f; } else if (values.Length == 3) { state.StepU = float.Parse(values[1], CultureInfo.InvariantCulture); state.StepV = float.Parse(values[2], CultureInfo.InvariantCulture); } else { throw new InvalidDataException(string.Format("The <{0}> statement has too many values. Line: {1}.", token, state.LineNumber)); } }
protected virtual void S(IObjReaderState state, ObjToken token, string[] values) { if (values.Length < 2) { throw new InvalidDataException(string.Format("The <{0}> statement must specify a value. Line: {1}.", token, state.LineNumber)); } if (values.Length != 2) { throw new InvalidDataException(string.Format("The <{0}> statement has too many values. Line: {1}.", token, state.LineNumber)); } if (Enum.TryParse <OnOff>(values[1], true, out var onOff)) { if (onOff == OnOff.Off) { state.SmoothingGroupNumber = 0; return; } } state.SmoothingGroupNumber = int.Parse(values[1], CultureInfo.InvariantCulture); }
protected virtual void Parm(IObjReaderState state, ObjToken token, string[] values) { if (state.FreeFormElement == default) { return; } if (values.Length < 4) { throw new InvalidDataException(string.Format("The <{0}> statement must specify at least 3 values. Line: {1}.", token, state.LineNumber)); } var parameters = default(IList <float>); if (!Enum.TryParse <UV>(values[1], true, out var uv)) { throw new InvalidDataException(string.Format("The <{0}> statement has an unknown direction. Line: {1}.", token, state.LineNumber)); } switch (uv) { case UV.U: { parameters = state.FreeFormElement.U; break; } case UV.V: { parameters = state.FreeFormElement.V; break; } } for (int i = 2; i < values.Length; i++) { parameters.Add(float.Parse(values[i], CultureInfo.InvariantCulture)); } }
protected virtual void UseMtl(IObjReaderState state, ObjToken token, string[] values) { if (values.Length < 2) { throw new InvalidDataException(string.Format("The <{0}> statement must specify a value. Line: {1}.", token, state.LineNumber)); } if (values.Length != 2) { throw new InvalidDataException(string.Format("The <{0}> statement has too many values. Line: {1}.", token, state.LineNumber)); } if (Enum.TryParse <OnOff>(values[1], true, out var onOff)) { if (onOff == OnOff.Off) { state.MaterialName = default; return; } } state.MaterialName = values[1]; }
protected virtual void MG(IObjReaderState state, ObjToken token, string[] values) { if (values.Length < 2) { throw new InvalidDataException(string.Format("The <{0}> statement must specify a value. Line: {1}.", token, state.LineNumber)); } if (Enum.TryParse <OnOff>(values[1], true, out var onOff)) { if (onOff == OnOff.Off) { state.MergingGroupNumber = 0; } } else { state.MergingGroupNumber = int.Parse(values[1], CultureInfo.InvariantCulture); } if (state.MergingGroupNumber == 0) { if (values.Length > 3) { throw new InvalidDataException(string.Format("The <{0}> statement has too many values. Line: {1}.", token, state.LineNumber)); } } else { if (values.Length != 3) { throw new InvalidDataException(string.Format("The <{0}> statement has too many or too few values. Line: {1}.", token, state.LineNumber)); } var res = float.Parse(values[2], CultureInfo.InvariantCulture); state.Obj.MergingGroupResolutions[state.MergingGroupNumber] = res; } }
protected virtual CurveIndex CurveIndex(IObjReaderState state, string[] values, int index) { var start = float.Parse(values[index], CultureInfo.InvariantCulture); var end = float.Parse(values[index + 1], CultureInfo.InvariantCulture); var curve2D = int.Parse(values[index + 2], CultureInfo.InvariantCulture); if (curve2D == 0) { throw new InvalidDataException(string.Format("The curve index must specify an index. Line: {0}.", state.LineNumber)); } if (curve2D < 0) { curve2D = state.Obj.Curves2D.Count + curve2D + 1; } if (curve2D <= 0 || curve2D > state.Obj.Curves2D.Count) { throw new IndexOutOfRangeException(); } return(new CurveIndex(start, end, curve2D)); }
protected virtual void P(IObjReaderState state, ObjToken token, string[] values) { if (values.Length < 2) { throw new InvalidDataException(string.Format("The <{0}> statement must specify at least 1 value. Line: {1}.", token, state.LineNumber)); } var point = new Point(); for (int i = 1; i < values.Length; i++) { point.Vertices.Add(Triplet(state, token, values[i])); } state.ApplyAttributesToElement(point); state.ApplyAttributesToPolygonalElement(point); state.Obj.Points.Add(point); foreach (var group in state.GetCurrentGroups()) { group.Points.Add(point); } }
protected virtual void STech(IObjReaderState state, ObjToken token, string[] values) { state.SurfaceApproximationTechnique = ApproximationTechnique(state, token, values); }
protected virtual void CSType(IObjReaderState state, ObjToken token, string[] values) { if (values.Length < 2) { throw new InvalidDataException(string.Format("The <{0}> statement must specify a value. Line: {1}.", token, state.LineNumber)); } var type = string.Empty; if (values.Length == 2) { state.IsRationalForm = false; type = values[1]; } else if (values.Length == 3 && string.Equals(values[1], "rat", StringComparison.OrdinalIgnoreCase)) { state.IsRationalForm = true; type = values[2]; } else { throw new InvalidDataException(string.Format("The <{0}> statement has too many values. Line: {1}.", token, state.LineNumber)); } if (!Enum.TryParse <CurveSurfaceToken>(type, true, out var cstype)) { throw new InvalidDataException(string.Format("The <{0}> statement has an unknown type value. Value: {1}. Line: {2}.", token, type, state.LineNumber)); } switch (cstype) { case CurveSurfaceToken.BMatrix: { state.FreeFormType = FreeFormType.BasisMatrix; break; } case CurveSurfaceToken.Bezier: { state.FreeFormType = FreeFormType.Bezier; break; } case CurveSurfaceToken.Bspline: { state.FreeFormType = FreeFormType.BSpline; break; } case CurveSurfaceToken.Cardinal: { state.FreeFormType = FreeFormType.Cardinal; break; } case CurveSurfaceToken.Taylor: { state.FreeFormType = FreeFormType.Taylor; break; } } }
protected virtual void Res(IObjReaderState state, ObjToken token, string[] values) { throw new NotImplementedException(string.Format("The <{0}> statement have been replaced by free-form geometry statements.", token)); }
protected virtual IApproximationTechnique ApproximationTechnique(IObjReaderState state, ObjToken token, string[] values) { if (values.Length < 2) { throw new InvalidDataException(string.Format("The <{0}> statement must specify a technique. Line: {1}.", token, state.LineNumber)); } if (!Enum.TryParse <ApproximationTechniqueToken>(values[1], true, out var approximationToken)) { throw new InvalidDataException(string.Format("The <{0}> statement contains an unknown technique <{1}>.", token, values[1])); } switch (approximationToken) { case ApproximationTechniqueToken.CParm: { if (values.Length < 3) { throw new InvalidDataException(string.Format("The <{0}> <{1}> statement must specify a value. Line: {2}.", token, approximationToken, state.LineNumber)); } if (values.Length != 3) { throw new InvalidDataException(string.Format("The <{0}> <{1}> statement has too many values. Line: {2}.", token, approximationToken, state.LineNumber)); } return(new ConstantParametricSubDivisionTechnique(float.Parse(values[2], CultureInfo.InvariantCulture))); } case ApproximationTechniqueToken.CParmA: { if (values.Length < 4) { throw new InvalidDataException(string.Format("The <{0}> <{1}> statement must specify a value. Line: {2}.", token, approximationToken, state.LineNumber)); } if (values.Length != 4) { throw new InvalidDataException(string.Format("The <{0}> <{1}> statement has too many values. Line: {2}.", token, approximationToken, state.LineNumber)); } return(new ConstantParametricSubDivisionTechnique(float.Parse(values[2], CultureInfo.InvariantCulture), float.Parse(values[3], CultureInfo.InvariantCulture))); } case ApproximationTechniqueToken.CParmB: { if (values.Length < 3) { throw new InvalidDataException(string.Format("The <{0}> <{1}> statement must specify a value. Line: {2}.", token, approximationToken, state.LineNumber)); } if (values.Length != 3) { throw new InvalidDataException(string.Format("The <{0}> <{1}> statement has too many values. Line: {2}.", token, approximationToken, state.LineNumber)); } return(new ConstantParametricSubDivisionTechnique(float.Parse(values[2], CultureInfo.InvariantCulture))); } case ApproximationTechniqueToken.CSpace: { if (values.Length < 3) { throw new InvalidDataException(string.Format("The <{0}> <{1}> statement must specify a value. Line: {2}.", token, approximationToken, state.LineNumber)); } if (values.Length != 3) { throw new InvalidDataException(string.Format("The <{0}> <{1}> statement has too many values. Line: {2}.", token, approximationToken, state.LineNumber)); } return(new ConstantSpatialSubDivisionTechnique(float.Parse(values[2], CultureInfo.InvariantCulture))); } case ApproximationTechniqueToken.Curv: { if (values.Length < 4) { throw new InvalidDataException(string.Format("The <{0}> <{1}> statement must specify a value. Line: {2}.", token, approximationToken, state.LineNumber)); } if (values.Length != 4) { throw new InvalidDataException(string.Format("The <{0}> <{1}> statement has too many values. Line: {2}.", token, approximationToken, state.LineNumber)); } return(new CurvatureDependentSubDivisionTechnique(float.Parse(values[2], CultureInfo.InvariantCulture), float.Parse(values[3], CultureInfo.InvariantCulture))); } } throw new InvalidDataException(string.Format("The <{0}> statement contains an unknown technique <{1}>.", token, values[1])); }
protected virtual void End(IObjReaderState state, ObjToken token, string[] values) { state.FreeFormElement = default; }