< Summary

Line coverage
100%
Covered lines: 484
Uncovered lines: 0
Coverable lines: 484
Total lines: 1221
Line coverage: 100%
Branch coverage
100%
Covered branches: 502
Total branches: 502
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
FromStream(...)100%374374100%
ParseTriplet(...)100%3636100%
ParseCurveIndex(...)100%88100%
ParseCurveIndex(...)100%66100%
ParseFreeFormType(...)100%1818100%
ParseSurfaceConnection(...)100%2020100%
ParseGroupName(...)100%88100%
ParseApproximationTechnique(...)100%3232100%

File(s)

https://raw.githubusercontent.com/JeremyAnsel/JeremyAnsel.Media.WavefrontObj/636b700b450d7d3262bf9218a7cc67966be4ced8/JeremyAnsel.Media.WavefrontObj/JeremyAnsel.Media.WavefrontObj/ObjFileReader.cs

#LineLine coverage
 1// <copyright file="ObjFileReader.cs" company="Jérémy Ansel">
 2// Copyright (c) 2017, 2019 Jérémy Ansel
 3// </copyright>
 4// <license>
 5// Licensed under the MIT license. See LICENSE.txt
 6// </license>
 7
 8#if !NET6_0_OR_GREATER
 9
 10using System.Diagnostics.CodeAnalysis;
 11using System.Globalization;
 12
 13namespace JeremyAnsel.Media.WavefrontObj
 14{
 15    internal static class ObjFileReader
 16    {
 17        [SuppressMessage("Globalization", "CA1303:Ne pas passer de littéraux en paramètres localisés", Justification = "
 18        public static ObjFile FromStream(Stream? stream, ObjFileReaderSettings settings)
 19        {
 28220            if (stream == null)
 21            {
 122                throw new ArgumentNullException(nameof(stream));
 23            }
 24
 28125            var obj = new ObjFile();
 28126            var context = new ObjFileReaderContext(obj, settings);
 28127            var lineReader = new LineReader();
 28
 182029            foreach (string currentLine in lineReader.Read(stream))
 30            {
 71331                string[] values = currentLine.Split(LineReader.LineSeparators, StringSplitOptions.RemoveEmptyEntries);
 32
 71333                switch (values[0].ToLowerInvariant())
 34                {
 35                    case "v":
 36                        {
 16837                            if (values.Length < 4)
 38                            {
 339                                throw new InvalidDataException("A v statement must specify at least 3 values.");
 40                            }
 41
 16542                            float x = float.Parse(values[1], CultureInfo.InvariantCulture);
 16543                            float y = float.Parse(values[2], CultureInfo.InvariantCulture);
 16544                            float z = float.Parse(values[3], CultureInfo.InvariantCulture);
 16545                            float w = 1.0f;
 16546                            bool hasColor = false;
 16547                            float r = 0.0f;
 16548                            float g = 0.0f;
 16549                            float b = 0.0f;
 16550                            float a = 1.0f;
 51
 16552                            if (values.Length == 4 || values.Length == 5)
 53                            {
 16154                                if (values.Length == 5)
 55                                {
 156                                    w = float.Parse(values[4], CultureInfo.InvariantCulture);
 57                                }
 58                            }
 459                            else if (values.Length == 7 || values.Length == 8)
 60                            {
 261                                hasColor = true;
 262                                r = float.Parse(values[4], CultureInfo.InvariantCulture);
 263                                g = float.Parse(values[5], CultureInfo.InvariantCulture);
 264                                b = float.Parse(values[6], CultureInfo.InvariantCulture);
 65
 266                                if (values.Length == 8)
 67                                {
 168                                    a = float.Parse(values[7], CultureInfo.InvariantCulture);
 69                                }
 70                            }
 71                            else
 72                            {
 273                                throw new InvalidDataException("A v statement has too many values.");
 74                            }
 75
 16376                            var v = new ObjVertex();
 16377                            v.Position = new ObjVector4(x, y, z, w);
 78
 16379                            if (hasColor)
 80                            {
 281                                v.Color = new ObjVector4(r, g, b, a);
 82                            }
 83
 16384                            obj.Vertices.Add(v);
 16385                            break;
 86                        }
 87
 88                    case "vp":
 89                        {
 6090                            if (values.Length < 2)
 91                            {
 192                                throw new InvalidDataException("A vp statement must specify at least 1 value.");
 93                            }
 94
 5995                            var v = new ObjVector3();
 5996                            v.X = float.Parse(values[1], CultureInfo.InvariantCulture);
 97
 5998                            if (values.Length == 2)
 99                            {
 1100                                v.Y = 0.0f;
 1101                                v.Z = 1.0f;
 102                            }
 58103                            else if (values.Length == 3)
 104                            {
 1105                                v.Y = float.Parse(values[2], CultureInfo.InvariantCulture);
 1106                                v.Z = 1.0f;
 107                            }
 57108                            else if (values.Length == 4)
 109                            {
 56110                                v.Y = float.Parse(values[2], CultureInfo.InvariantCulture);
 56111                                v.Z = float.Parse(values[3], CultureInfo.InvariantCulture);
 112                            }
 113                            else
 114                            {
 1115                                throw new InvalidDataException("A vp statement has too many values.");
 116                            }
 117
 58118                            obj.ParameterSpaceVertices.Add(v);
 58119                            break;
 120                        }
 121
 122                    case "vn":
 123                        {
 12124                            if (values.Length < 4)
 125                            {
 3126                                throw new InvalidDataException("A vn statement must specify 3 values.");
 127                            }
 128
 9129                            if (values.Length != 4)
 130                            {
 1131                                throw new InvalidDataException("A vn statement has too many values.");
 132                            }
 133
 8134                            var v = new ObjVector3();
 8135                            v.X = float.Parse(values[1], CultureInfo.InvariantCulture);
 8136                            v.Y = float.Parse(values[2], CultureInfo.InvariantCulture);
 8137                            v.Z = float.Parse(values[3], CultureInfo.InvariantCulture);
 138
 8139                            obj.VertexNormals.Add(v);
 8140                            break;
 141                        }
 142
 143                    case "vt":
 144                        {
 11145                            if (values.Length < 2)
 146                            {
 1147                                throw new InvalidDataException("A vt statement must specify at least 1 value.");
 148                            }
 149
 10150                            var v = new ObjVector3();
 10151                            v.X = float.Parse(values[1], CultureInfo.InvariantCulture);
 152
 10153                            if (values.Length == 2)
 154                            {
 7155                                v.Y = 0.0f;
 7156                                v.Z = 0.0f;
 157                            }
 3158                            else if (values.Length == 3)
 159                            {
 1160                                v.Y = float.Parse(values[2], CultureInfo.InvariantCulture);
 1161                                v.Z = 0.0f;
 162                            }
 2163                            else if (values.Length == 4)
 164                            {
 1165                                v.Y = float.Parse(values[2], CultureInfo.InvariantCulture);
 1166                                v.Z = float.Parse(values[3], CultureInfo.InvariantCulture);
 167                            }
 168                            else
 169                            {
 1170                                throw new InvalidDataException("A vt statement has too many values.");
 171                            }
 172
 9173                            obj.TextureVertices.Add(v);
 9174                            break;
 175                        }
 176
 177                    case "cstype":
 15178                        ObjFileReader.ParseFreeFormType(context, values);
 10179                        break;
 180
 181                    case "deg":
 7182                        if (values.Length < 2)
 183                        {
 1184                            throw new InvalidDataException("A deg statement must specify at least 1 value.");
 185                        }
 186
 6187                        if (values.Length == 2)
 188                        {
 1189                            context.DegreeU = int.Parse(values[1], CultureInfo.InvariantCulture);
 1190                            context.DegreeV = 0;
 191                        }
 5192                        else if (values.Length == 3)
 193                        {
 4194                            context.DegreeU = int.Parse(values[1], CultureInfo.InvariantCulture);
 4195                            context.DegreeV = int.Parse(values[2], CultureInfo.InvariantCulture);
 196                        }
 197                        else
 198                        {
 1199                            throw new InvalidDataException("A deg statement has too many values.");
 200                        }
 201
 202                        break;
 203
 204                    case "bmat":
 205                        {
 5206                            if (values.Length < 2)
 207                            {
 1208                                throw new InvalidDataException("A bmat statement must specify a direction.");
 209                            }
 210
 211                            int d;
 212
 4213                            if (string.Equals(values[1], "u", StringComparison.OrdinalIgnoreCase))
 214                            {
 2215                                d = 1;
 216                            }
 2217                            else if (string.Equals(values[1], "v", StringComparison.OrdinalIgnoreCase))
 218                            {
 1219                                d = 2;
 220                            }
 221                            else
 222                            {
 1223                                throw new InvalidDataException("A bmat statement has an unknown direction.");
 224                            }
 225
 3226                            int count = (context.DegreeU + 1) * (context.DegreeV + 1);
 227
 3228                            if (values.Length != count + 2)
 229                            {
 1230                                throw new InvalidDataException("A bmat statement has too many or too few values.");
 231                            }
 232
 2233                            var matrix = new float[count];
 234
 52235                            for (int i = 0; i < count; i++)
 236                            {
 24237                                matrix[i] = float.Parse(values[2 + i], CultureInfo.InvariantCulture);
 238                            }
 239
 240                            switch (d)
 241                            {
 242                                case 1:
 1243                                    context.BasicMatrixU = matrix;
 1244                                    break;
 245
 246                                case 2:
 1247                                    context.BasicMatrixV = matrix;
 1248                                    break;
 249                            }
 250
 251                            break;
 252                        }
 253
 254                    case "step":
 4255                        if (values.Length < 2)
 256                        {
 1257                            throw new InvalidDataException("A step statement must specify at least 1 value.");
 258                        }
 259
 3260                        if (values.Length == 2)
 261                        {
 1262                            context.StepU = float.Parse(values[1], CultureInfo.InvariantCulture);
 1263                            context.StepV = 1.0f;
 264                        }
 2265                        else if (values.Length == 3)
 266                        {
 1267                            context.StepU = float.Parse(values[1], CultureInfo.InvariantCulture);
 1268                            context.StepV = float.Parse(values[2], CultureInfo.InvariantCulture);
 269                        }
 270                        else
 271                        {
 1272                            throw new InvalidDataException("A step statement has too many values.");
 273                        }
 274
 275                        break;
 276
 277                    case "p":
 278                        {
 34279                            if (values.Length < 2)
 280                            {
 1281                                throw new InvalidDataException("A p statement must specify at least 1 value.");
 282                            }
 283
 33284                            var point = new ObjPoint();
 285
 118286                            for (int i = 1; i < values.Length; i++)
 287                            {
 35288                                point.Vertices.Add(ObjFileReader.ParseTriplet(obj, values[i]));
 289                            }
 290
 24291                            context.ApplyAttributesToElement(point);
 24292                            context.ApplyAttributesToPolygonalElement(point);
 293
 24294                            obj.Points.Add(point);
 295
 96296                            foreach (var group in context.GetCurrentGroups())
 297                            {
 24298                                group.Points.Add(point);
 299                            }
 300
 301                            break;
 302                        }
 303
 304                    case "l":
 305                        {
 4306                            if (values.Length < 3)
 307                            {
 2308                                throw new InvalidDataException("A l statement must specify at least 2 values.");
 309                            }
 310
 2311                            var line = new ObjLine();
 312
 16313                            for (int i = 1; i < values.Length; i++)
 314                            {
 6315                                line.Vertices.Add(ObjFileReader.ParseTriplet(obj, values[i]));
 316                            }
 317
 2318                            context.ApplyAttributesToElement(line);
 2319                            context.ApplyAttributesToPolygonalElement(line);
 320
 2321                            obj.Lines.Add(line);
 322
 8323                            foreach (var group in context.GetCurrentGroups())
 324                            {
 2325                                group.Lines.Add(line);
 326                            }
 327
 328                            break;
 329                        }
 330
 331                    case "f":
 332                    case "fo":
 333                        {
 10334                            if (values.Length < 4)
 335                            {
 6336                                throw new InvalidDataException("A f statement must specify at least 3 values.");
 337                            }
 338
 4339                            var face = new ObjFace();
 340
 48341                            for (int i = 1; i < values.Length; i++)
 342                            {
 20343                                face.Vertices.Add(ObjFileReader.ParseTriplet(obj, values[i]));
 344                            }
 345
 4346                            context.ApplyAttributesToElement(face);
 4347                            context.ApplyAttributesToPolygonalElement(face);
 348
 4349                            obj.Faces.Add(face);
 350
 16351                            foreach (var group in context.GetCurrentGroups())
 352                            {
 4353                                group.Faces.Add(face);
 354                            }
 355
 356                            break;
 357                        }
 358
 359                    case "curv":
 360                        {
 45361                            if (values.Length < 5)
 362                            {
 4363                                throw new InvalidDataException("A curv statement must specify at least 4 values.");
 364                            }
 365
 41366                            var curve = new ObjCurve();
 367
 41368                            curve.StartParameter = float.Parse(values[1], CultureInfo.InvariantCulture);
 41369                            curve.EndParameter = float.Parse(values[2], CultureInfo.InvariantCulture);
 370
 238371                            for (int i = 3; i < values.Length; i++)
 372                            {
 81373                                int v = int.Parse(values[i], CultureInfo.InvariantCulture);
 374
 81375                                if (v == 0)
 376                                {
 1377                                    throw new InvalidDataException("A curv statement contains an invalid vertex index.")
 378                                }
 379
 80380                                if (v < 0)
 381                                {
 1382                                    v = obj.Vertices.Count + v + 1;
 383                                }
 384
 80385                                if (v <= 0 || v > obj.Vertices.Count)
 386                                {
 2387                                    throw new IndexOutOfRangeException();
 388                                }
 389
 78390                                curve.Vertices.Add(v);
 391                            }
 392
 38393                            context.ApplyAttributesToElement(curve);
 38394                            context.ApplyAttributesToFreeFormElement(curve);
 38395                            context.CurrentFreeFormElement = curve;
 396
 38397                            obj.Curves.Add(curve);
 398
 152399                            foreach (var group in context.GetCurrentGroups())
 400                            {
 38401                                group.Curves.Add(curve);
 402                            }
 403
 404                            break;
 405                        }
 406
 407                    case "curv2":
 408                        {
 61409                            if (values.Length < 3)
 410                            {
 2411                                throw new InvalidDataException("A curv2 statement must specify at least 2 values.");
 412                            }
 413
 59414                            var curve = new ObjCurve2D();
 415
 346416                            for (int i = 1; i < values.Length; i++)
 417                            {
 117418                                int vp = int.Parse(values[i], CultureInfo.InvariantCulture);
 419
 117420                                if (vp == 0)
 421                                {
 1422                                    throw new InvalidDataException("A curv2 statement contains an invalid parameter spac
 423                                }
 424
 116425                                if (vp < 0)
 426                                {
 1427                                    vp = obj.ParameterSpaceVertices.Count + vp + 1;
 428                                }
 429
 116430                                if (vp <= 0 || vp > obj.ParameterSpaceVertices.Count)
 431                                {
 2432                                    throw new IndexOutOfRangeException();
 433                                }
 434
 114435                                curve.ParameterSpaceVertices.Add(vp);
 436                            }
 437
 56438                            context.ApplyAttributesToElement(curve);
 56439                            context.ApplyAttributesToFreeFormElement(curve);
 56440                            context.CurrentFreeFormElement = curve;
 441
 56442                            obj.Curves2D.Add(curve);
 443
 224444                            foreach (var group in context.GetCurrentGroups())
 445                            {
 56446                                group.Curves2D.Add(curve);
 447                            }
 448
 449                            break;
 450                        }
 451
 452                    case "surf":
 453                        {
 26454                            if (values.Length < 6)
 455                            {
 6456                                throw new InvalidDataException("A surf statement must specify at least 5 values.");
 457                            }
 458
 20459                            var surface = new ObjSurface();
 460
 20461                            surface.StartParameterU = float.Parse(values[1], CultureInfo.InvariantCulture);
 20462                            surface.EndParameterU = float.Parse(values[2], CultureInfo.InvariantCulture);
 20463                            surface.StartParameterV = float.Parse(values[3], CultureInfo.InvariantCulture);
 20464                            surface.EndParameterV = float.Parse(values[4], CultureInfo.InvariantCulture);
 465
 84466                            for (int i = 5; i < values.Length; i++)
 467                            {
 24468                                surface.Vertices.Add(ObjFileReader.ParseTriplet(obj, values[i]));
 469                            }
 470
 18471                            context.ApplyAttributesToElement(surface);
 18472                            context.ApplyAttributesToFreeFormElement(surface);
 18473                            context.CurrentFreeFormElement = surface;
 474
 18475                            obj.Surfaces.Add(surface);
 476
 72477                            foreach (var group in context.GetCurrentGroups())
 478                            {
 18479                                group.Surfaces.Add(surface);
 480                            }
 481
 482                            break;
 483                        }
 484
 485                    case "parm":
 7486                        if (context.CurrentFreeFormElement == null)
 487                        {
 488                            break;
 489                        }
 490
 6491                        if (values.Length < 4)
 492                        {
 3493                            throw new InvalidDataException("A parm statement must specify at least 3 values.");
 494                        }
 495
 496                        List<float> parameters;
 497
 3498                        if (string.Equals(values[1], "u", StringComparison.OrdinalIgnoreCase))
 499                        {
 1500                            parameters = context.CurrentFreeFormElement.ParametersU;
 501                        }
 2502                        else if (string.Equals(values[1], "v", StringComparison.OrdinalIgnoreCase))
 503                        {
 1504                            parameters = context.CurrentFreeFormElement.ParametersV;
 505                        }
 506                        else
 507                        {
 1508                            throw new InvalidDataException("A parm statement has an unknown direction.");
 509                        }
 510
 16511                        for (int i = 2; i < values.Length; i++)
 512                        {
 6513                            parameters.Add(float.Parse(values[i], CultureInfo.InvariantCulture));
 514                        }
 515
 2516                        break;
 517
 518                    case "trim":
 10519                        if (context.CurrentFreeFormElement == null)
 520                        {
 521                            break;
 522                        }
 523
 9524                        ObjFileReader.ParseCurveIndex(context.CurrentFreeFormElement.OuterTrimmingCurves, obj, values);
 1525                        break;
 526
 527                    case "hole":
 10528                        if (context.CurrentFreeFormElement == null)
 529                        {
 530                            break;
 531                        }
 532
 9533                        ObjFileReader.ParseCurveIndex(context.CurrentFreeFormElement.InnerTrimmingCurves, obj, values);
 1534                        break;
 535
 536                    case "scrv":
 10537                        if (context.CurrentFreeFormElement == null)
 538                        {
 539                            break;
 540                        }
 541
 9542                        ObjFileReader.ParseCurveIndex(context.CurrentFreeFormElement.SequenceCurves, obj, values);
 1543                        break;
 544
 545                    case "sp":
 6546                        if (context.CurrentFreeFormElement == null)
 547                        {
 548                            break;
 549                        }
 550
 5551                        if (values.Length < 2)
 552                        {
 1553                            throw new InvalidDataException("A sp statement must specify at least 1 value.");
 554                        }
 555
 12556                        for (int i = 1; i < values.Length; i++)
 557                        {
 5558                            int vp = int.Parse(values[i], CultureInfo.InvariantCulture);
 559
 5560                            if (vp == 0)
 561                            {
 1562                                throw new InvalidDataException("A sp statement contains an invalid parameter space verte
 563                            }
 564
 4565                            if (vp < 0)
 566                            {
 1567                                vp = obj.ParameterSpaceVertices.Count + vp + 1;
 568                            }
 569
 4570                            if (vp <= 0 || vp > obj.ParameterSpaceVertices.Count)
 571                            {
 2572                                throw new IndexOutOfRangeException();
 573                            }
 574
 2575                            context.CurrentFreeFormElement.SpecialPoints.Add(vp);
 576                        }
 577
 1578                        break;
 579
 580                    case "end":
 6581                        context.CurrentFreeFormElement = null;
 6582                        break;
 583
 584                    case "con":
 22585                        ObjFileReader.ParseSurfaceConnection(obj, values);
 1586                        break;
 587
 588                    case "g":
 26589                        ObjFileReader.ParseGroupName(values, context);
 26590                        break;
 591
 592                    case "s":
 9593                        if (values.Length < 2)
 594                        {
 1595                            throw new InvalidDataException("A s statement must specify a value.");
 596                        }
 597
 8598                        if (values.Length != 2)
 599                        {
 1600                            throw new InvalidDataException("A s statement has too many values.");
 601                        }
 602
 7603                        if (string.Equals(values[1], "off", StringComparison.OrdinalIgnoreCase))
 604                        {
 1605                            context.SmoothingGroupNumber = 0;
 606                        }
 607                        else
 608                        {
 6609                            context.SmoothingGroupNumber = long.Parse(values[1], CultureInfo.InvariantCulture);
 610                        }
 611
 6612                        break;
 613
 614                    case "mg":
 10615                        if (values.Length < 2)
 616                        {
 1617                            throw new InvalidDataException("A mg statement must specify a value.");
 618                        }
 619
 9620                        if (string.Equals(values[1], "off", StringComparison.OrdinalIgnoreCase))
 621                        {
 1622                            context.MergingGroupNumber = 0;
 623                        }
 624                        else
 625                        {
 8626                            context.MergingGroupNumber = int.Parse(values[1], CultureInfo.InvariantCulture);
 627                        }
 628
 9629                        if (context.MergingGroupNumber == 0)
 630                        {
 3631                            if (values.Length > 3)
 632                            {
 1633                                throw new InvalidDataException("A mg statement has too many values.");
 634                            }
 635                        }
 636                        else
 637                        {
 6638                            if (values.Length != 3)
 639                            {
 2640                                throw new InvalidDataException("A mg statement has too many or too few values.");
 641                            }
 642
 4643                            float res = float.Parse(values[2], CultureInfo.InvariantCulture);
 644
 4645                            obj.MergingGroupResolutions[context.MergingGroupNumber] = res;
 646                        }
 647
 4648                        break;
 649
 650                    case "o":
 13651                        if (settings.HandleObjectNamesAsGroup)
 652                        {
 3653                            ParseGroupName(values, context);
 3654                            break;
 655                        }
 10656                        if (values.Length == 1)
 657                        {
 1658                            context.ObjectName = null;
 1659                            break;
 660                        }
 9661                        if (values.Length != 2)
 662                        {
 1663                            throw new InvalidDataException("A o statement has too many values.");
 664                        }
 665
 8666                        context.ObjectName = values[1];
 8667                        break;
 668
 669                    case "bevel":
 9670                        if (values.Length < 2)
 671                        {
 1672                            throw new InvalidDataException("A bevel statement must specify a name.");
 673                        }
 674
 8675                        if (values.Length != 2)
 676                        {
 1677                            throw new InvalidDataException("A bevel statement has too many values.");
 678                        }
 679
 7680                        if (string.Equals(values[1], "on", StringComparison.OrdinalIgnoreCase))
 681                        {
 5682                            context.IsBevelInterpolationEnabled = true;
 683                        }
 2684                        else if (string.Equals(values[1], "off", StringComparison.OrdinalIgnoreCase))
 685                        {
 1686                            context.IsBevelInterpolationEnabled = false;
 687                        }
 688                        else
 689                        {
 1690                            throw new InvalidDataException("A bevel statement must specify on or off.");
 691                        }
 692
 693                        break;
 694
 695                    case "c_interp":
 9696                        if (values.Length < 2)
 697                        {
 1698                            throw new InvalidDataException("A c_interp statement must specify a name.");
 699                        }
 700
 8701                        if (values.Length != 2)
 702                        {
 1703                            throw new InvalidDataException("A c_interp statement has too many values.");
 704                        }
 705
 7706                        if (string.Equals(values[1], "on", StringComparison.OrdinalIgnoreCase))
 707                        {
 5708                            context.IsColorInterpolationEnabled = true;
 709                        }
 2710                        else if (string.Equals(values[1], "off", StringComparison.OrdinalIgnoreCase))
 711                        {
 1712                            context.IsColorInterpolationEnabled = false;
 713                        }
 714                        else
 715                        {
 1716                            throw new InvalidDataException("A c_interp statement must specify on or off.");
 717                        }
 718
 719                        break;
 720
 721                    case "d_interp":
 9722                        if (values.Length < 2)
 723                        {
 1724                            throw new InvalidDataException("A d_interp statement must specify a name.");
 725                        }
 726
 8727                        if (values.Length != 2)
 728                        {
 1729                            throw new InvalidDataException("A d_interp statement has too many values.");
 730                        }
 731
 7732                        if (string.Equals(values[1], "on", StringComparison.OrdinalIgnoreCase))
 733                        {
 5734                            context.IsDissolveInterpolationEnabled = true;
 735                        }
 2736                        else if (string.Equals(values[1], "off", StringComparison.OrdinalIgnoreCase))
 737                        {
 1738                            context.IsDissolveInterpolationEnabled = false;
 739                        }
 740                        else
 741                        {
 1742                            throw new InvalidDataException("A d_interp statement must specify on or off.");
 743                        }
 744
 745                        break;
 746
 747                    case "lod":
 10748                        if (values.Length < 2)
 749                        {
 1750                            throw new InvalidDataException("A lod statement must specify a value.");
 751                        }
 752
 9753                        if (values.Length != 2)
 754                        {
 1755                            throw new InvalidDataException("A lod statement has too many values.");
 756                        }
 757
 8758                        context.LevelOfDetail = int.Parse(values[1], CultureInfo.InvariantCulture);
 8759                        break;
 760
 761                    case "maplib":
 2762                        if (values.Length < 2)
 763                        {
 1764                            throw new InvalidDataException("A maplib statement must specify a file name.");
 765                        }
 766
 6767                        for (int i = 1; i < values.Length; i++)
 768                        {
 2769                            obj.MapLibraries.Add(values[i]);
 770                        }
 771
 1772                        break;
 773
 774                    case "mtllib":
 3775                        if (values.Length < 2)
 776                        {
 1777                            throw new InvalidDataException("A mtllib statement must specify a file name.");
 778                        }
 779
 2780                        obj.MaterialLibraries.Add(string.Join(" ", values, 1, values.Length - 1));
 781
 2782                        break;
 783
 784                    case "usemap":
 11785                        if (values.Length < 2)
 786                        {
 1787                            throw new InvalidDataException("A usemap statement must specify a value.");
 788                        }
 789
 10790                        if (values.Length != 2)
 791                        {
 1792                            throw new InvalidDataException("A usemap statement has too many values.");
 793                        }
 794
 9795                        if (string.Equals(values[1], "off", StringComparison.OrdinalIgnoreCase))
 796                        {
 1797                            context.MapName = null;
 798                        }
 799                        else
 800                        {
 8801                            context.MapName = values[1];
 802                        }
 803
 8804                        break;
 805
 806                    case "usemtl":
 11807                        if (values.Length < 2)
 808                        {
 1809                            throw new InvalidDataException("A usemtl statement must specify a value.");
 810                        }
 811
 10812                        if (string.Equals(values[1], "off", StringComparison.OrdinalIgnoreCase))
 813                        {
 2814                            if (values.Length != 2)
 815                            {
 1816                                throw new InvalidDataException("A usemtl statement has too many values.");
 817                            }
 818
 1819                            context.MaterialName = null;
 820                        }
 821                        else
 822                        {
 8823                            context.MaterialName = string.Join(" ", values, 1, values.Length - 1);
 824                        }
 825
 8826                        break;
 827
 828                    case "shadow_obj":
 6829                        if (values.Length < 2)
 830                        {
 1831                            throw new InvalidDataException("A shadow_obj statement must specify a file name.");
 832                        }
 833
 5834                        obj.ShadowObjectFileName = string.Join(" ", values, 1, values.Length - 1);
 5835                        break;
 836
 837                    case "trace_obj":
 4838                        if (values.Length < 2)
 839                        {
 1840                            throw new InvalidDataException("A trace_obj statement must specify a file name.");
 841                        }
 842
 3843                        obj.TraceObjectFileName = string.Join(" ", values, 1, values.Length - 1);
 3844                        break;
 845
 846                    case "ctech":
 18847                        context.CurveApproximationTechnique = ObjFileReader.ParseApproximationTechnique(values);
 9848                        break;
 849
 850                    case "stech":
 22851                        context.SurfaceApproximationTechnique = ObjFileReader.ParseApproximationTechnique(values);
 10852                        break;
 853
 854                    case "bsp":
 855                    case "bzp":
 856                    case "cdc":
 857                    case "cdp":
 858                    case "res":
 5859                        throw new NotImplementedException(string.Concat(values[0], " statement have been replaced by fre
 860                }
 861            }
 862
 113863            obj.HeaderText = string.Join("\n", lineReader.HeaderTextLines.ToArray());
 864
 113865            return obj;
 866        }
 867
 868        [SuppressMessage("Globalization", "CA1303:Ne pas passer de littéraux en paramètres localisés", Justification = "
 869        private static ObjTriplet ParseTriplet(ObjFile obj, string value)
 870        {
 85871            var values = value.Split('/');
 872
 85873            if (values.Length > 3)
 874            {
 1875                throw new InvalidDataException("A triplet has too many values.");
 876            }
 877
 84878            int v = !string.IsNullOrEmpty(values[0]) ? int.Parse(values[0], CultureInfo.InvariantCulture) : 0;
 879
 84880            if (v == 0)
 881            {
 2882                throw new InvalidDataException("A triplet must specify a vertex index.");
 883            }
 884
 82885            if (v < 0)
 886            {
 2887                v = obj.Vertices.Count + v + 1;
 888            }
 889
 82890            if (v <= 0 || v > obj.Vertices.Count)
 891            {
 4892                throw new IndexOutOfRangeException();
 893            }
 894
 78895            int vt = values.Length > 1 && !string.IsNullOrEmpty(values[1]) ? int.Parse(values[1], CultureInfo.InvariantC
 896
 78897            if (vt != 0)
 898            {
 4899                if (vt < 0)
 900                {
 1901                    vt = obj.TextureVertices.Count + vt + 1;
 902                }
 903
 4904                if (vt <= 0 || vt > obj.TextureVertices.Count)
 905                {
 2906                    throw new IndexOutOfRangeException();
 907                }
 908            }
 909
 76910            int vn = values.Length > 2 && !string.IsNullOrEmpty(values[2]) ? int.Parse(values[2], CultureInfo.InvariantC
 911
 76912            if (vn != 0)
 913            {
 4914                if (vn < 0)
 915                {
 1916                    vn = obj.VertexNormals.Count + vn + 1;
 917                }
 918
 4919                if (vn <= 0 || vn > obj.VertexNormals.Count)
 920                {
 2921                    throw new IndexOutOfRangeException();
 922                }
 923            }
 924
 74925            return new ObjTriplet(v, vt, vn);
 926        }
 927
 928        [SuppressMessage("Globalization", "CA1303:Ne pas passer de littéraux en paramètres localisés", Justification = "
 929        private static ObjCurveIndex ParseCurveIndex(ObjFile obj, string[] values, int index)
 930        {
 29931            float start = float.Parse(values[index], CultureInfo.InvariantCulture);
 29932            float end = float.Parse(values[index + 1], CultureInfo.InvariantCulture);
 29933            int curve2D = int.Parse(values[index + 2], CultureInfo.InvariantCulture);
 934
 29935            if (curve2D == 0)
 936            {
 5937                throw new InvalidDataException("A curve index must specify an index.");
 938            }
 939
 24940            if (curve2D < 0)
 941            {
 5942                curve2D = obj.Curves2D.Count + curve2D + 1;
 943            }
 944
 24945            if (curve2D <= 0 || curve2D > obj.Curves2D.Count)
 946            {
 10947                throw new IndexOutOfRangeException();
 948            }
 949
 14950            return new ObjCurveIndex(start, end, curve2D);
 951        }
 952
 953        private static void ParseCurveIndex(List<ObjCurveIndex> curves, ObjFile obj, string[] values)
 954        {
 27955            if (values.Length < 4)
 956            {
 9957                throw new InvalidDataException(string.Concat("A ", values[0], " statement must specify at least 3 value.
 958            }
 959
 18960            if ((values.Length - 1) % 3 != 0)
 961            {
 6962                throw new InvalidDataException(string.Concat("A ", values[0], " statement has too many values."));
 963            }
 964
 36965            for (int i = 1; i < values.Length; i += 3)
 966            {
 15967                curves.Add(ObjFileReader.ParseCurveIndex(obj, values, i));
 968            }
 3969        }
 970
 971        [SuppressMessage("Globalization", "CA1303:Ne pas passer de littéraux en paramètres localisés", Justification = "
 972        private static void ParseFreeFormType(ObjFileReaderContext context, string[] values)
 973        {
 15974            if (values.Length < 2)
 975            {
 1976                throw new InvalidDataException("A cstype statement must specify a value.");
 977            }
 978
 979            string type;
 980
 14981            if (values.Length == 2)
 982            {
 6983                context.IsRationalForm = false;
 6984                type = values[1];
 985            }
 8986            else if (values.Length == 3 && string.Equals(values[1], "rat", StringComparison.OrdinalIgnoreCase))
 987            {
 6988                context.IsRationalForm = true;
 6989                type = values[2];
 990            }
 991            else
 992            {
 2993                throw new InvalidDataException("A cstype statement has too many values.");
 994            }
 995
 12996            switch (type.ToLowerInvariant())
 997            {
 998                case "bmatrix":
 2999                    context.FreeFormType = ObjFreeFormType.BasisMatrix;
 21000                    break;
 1001
 1002                case "bezier":
 21003                    context.FreeFormType = ObjFreeFormType.Bezier;
 21004                    break;
 1005
 1006                case "bspline":
 21007                    context.FreeFormType = ObjFreeFormType.BSpline;
 21008                    break;
 1009
 1010                case "cardinal":
 21011                    context.FreeFormType = ObjFreeFormType.Cardinal;
 21012                    break;
 1013
 1014                case "taylor":
 21015                    context.FreeFormType = ObjFreeFormType.Taylor;
 21016                    break;
 1017
 1018                default:
 21019                    throw new InvalidDataException("A cstype statement has an unknown type.");
 1020            }
 1021        }
 1022
 1023        [SuppressMessage("Globalization", "CA1303:Ne pas passer de littéraux en paramètres localisés", Justification = "
 1024        private static void ParseSurfaceConnection(ObjFile obj, string[] values)
 1025        {
 221026            if (values.Length < 9)
 1027            {
 81028                throw new InvalidDataException("A con statement must specify 8 values.");
 1029            }
 1030
 141031            if (values.Length != 9)
 1032            {
 11033                throw new InvalidDataException("A con statement has too many values.");
 1034            }
 1035
 131036            int surface1 = int.Parse(values[1], CultureInfo.InvariantCulture);
 1037
 131038            if (surface1 == 0)
 1039            {
 11040                throw new InvalidDataException("A con statement must specify a surface index.");
 1041            }
 1042
 121043            if (surface1 < 0)
 1044            {
 11045                surface1 = obj.Surfaces.Count + surface1 + 1;
 1046            }
 1047
 121048            if (surface1 <= 0 || surface1 > obj.Surfaces.Count)
 1049            {
 21050                throw new IndexOutOfRangeException();
 1051            }
 1052
 101053            var curve1 = ObjFileReader.ParseCurveIndex(obj, values, 2);
 1054
 71055            int surface2 = int.Parse(values[5], CultureInfo.InvariantCulture);
 1056
 71057            if (surface2 == 0)
 1058            {
 11059                throw new InvalidDataException("A con statement must specify a surface index.");
 1060            }
 1061
 61062            if (surface2 < 0)
 1063            {
 11064                surface2 = obj.Surfaces.Count + surface2 + 1;
 1065            }
 1066
 61067            if (surface2 <= 0 || surface2 > obj.Surfaces.Count)
 1068            {
 21069                throw new IndexOutOfRangeException();
 1070            }
 1071
 41072            var curve2 = ObjFileReader.ParseCurveIndex(obj, values, 6);
 1073
 11074            var connection = new ObjSurfaceConnection
 11075            {
 11076                Surface1 = surface1,
 11077                Curve2D1 = curve1,
 11078                Surface2 = surface2,
 11079                Curve2D2 = curve2
 11080            };
 1081
 11082            obj.SurfaceConnections.Add(connection);
 11083        }
 1084
 1085        private static void ParseGroupName(string[] values, ObjFileReaderContext context)
 1086        {
 291087            context.GroupNames.Clear();
 1088
 291089            if (context.Settings.OnlyOneGroupNamePerLine)
 1090            {
 21091                var name = string.Join(" ", values, 1, values.Length - 1);
 21092                if (!string.Equals(name, "default", StringComparison.OrdinalIgnoreCase))
 1093                {
 21094                    context.GroupNames.Add(name);
 1095                }
 1096            }
 1097            else
 1098            {
 1181099                for (int i = 1; i < values.Length; i++)
 1100                {
 321101                    var name = values[i];
 1102
 321103                    if (!string.Equals(name, "default", StringComparison.OrdinalIgnoreCase))
 1104                    {
 241105                        context.GroupNames.Add(name);
 1106                    }
 1107                }
 1108            }
 1109
 291110            context.GetCurrentGroups();
 291111        }
 1112
 1113        private static ObjApproximationTechnique ParseApproximationTechnique(string[] values)
 1114        {
 1115            ObjApproximationTechnique technique;
 1116
 401117            if (values.Length < 2)
 1118            {
 21119                throw new InvalidDataException(string.Concat("A ", values[0], " statement must specify a technique."));
 1120            }
 1121
 381122            switch (values[1].ToLowerInvariant())
 1123            {
 1124                case "cparm":
 1125                    {
 31126                        if (values.Length < 3)
 1127                        {
 11128                            throw new InvalidDataException(string.Concat("A ", values[0], " cparm statement must specify
 1129                        }
 1130
 21131                        if (values.Length != 3)
 1132                        {
 11133                            throw new InvalidDataException(string.Concat("A ", values[0], " cparm statement has too many
 1134                        }
 1135
 11136                        float res = float.Parse(values[2], CultureInfo.InvariantCulture);
 11137                        technique = new ObjConstantParametricSubdivisionTechnique(res);
 11138                        break;
 1139                    }
 1140
 1141                case "cparma":
 1142                    {
 41143                        if (values.Length < 4)
 1144                        {
 21145                            throw new InvalidDataException(string.Concat("A ", values[0], " cparma statement must specif
 1146                        }
 1147
 21148                        if (values.Length != 4)
 1149                        {
 11150                            throw new InvalidDataException(string.Concat("A ", values[0], " cparma statement has too man
 1151                        }
 1152
 11153                        float resU = float.Parse(values[2], CultureInfo.InvariantCulture);
 11154                        float resV = float.Parse(values[3], CultureInfo.InvariantCulture);
 11155                        technique = new ObjConstantParametricSubdivisionTechnique(resU, resV);
 11156                        break;
 1157                    }
 1158
 1159                case "cparmb":
 1160                    {
 31161                        if (values.Length < 3)
 1162                        {
 11163                            throw new InvalidDataException(string.Concat("A ", values[0], " cparmb statement must specif
 1164                        }
 1165
 21166                        if (values.Length != 3)
 1167                        {
 11168                            throw new InvalidDataException(string.Concat("A ", values[0], " cparmb statement has too man
 1169                        }
 1170
 11171                        float resU = float.Parse(values[2], CultureInfo.InvariantCulture);
 11172                        technique = new ObjConstantParametricSubdivisionTechnique(resU);
 11173                        break;
 1174                    }
 1175
 1176                case "cspace":
 1177                    {
 181178                        if (values.Length < 3)
 1179                        {
 21180                            throw new InvalidDataException(string.Concat("A ", values[0], " cspace statement must specif
 1181                        }
 1182
 161183                        if (values.Length != 3)
 1184                        {
 21185                            throw new InvalidDataException(string.Concat("A ", values[0], " cspace statement has too man
 1186                        }
 1187
 141188                        float length = float.Parse(values[2], CultureInfo.InvariantCulture);
 141189                        technique = new ObjConstantSpatialSubdivisionTechnique(length);
 141190                        break;
 1191                    }
 1192
 1193                case "curv":
 1194                    {
 81195                        if (values.Length < 4)
 1196                        {
 41197                            throw new InvalidDataException(string.Concat("A ", values[0], " curv statement must specify 
 1198                        }
 1199
 41200                        if (values.Length != 4)
 1201                        {
 21202                            throw new InvalidDataException(string.Concat("A ", values[0], " curv statement has too many 
 1203                        }
 1204
 21205                        float distance = float.Parse(values[2], CultureInfo.InvariantCulture);
 21206                        float angle = float.Parse(values[3], CultureInfo.InvariantCulture);
 21207                        technique = new ObjCurvatureDependentSubdivisionTechnique(distance, angle);
 21208                        break;
 1209                    }
 1210
 1211                default:
 21212                    throw new InvalidDataException(string.Concat("A ", values[0], " statement contains an unknown techni
 1213            }
 1214
 191215            return technique;
 1216        }
 1217    }
 1218}
 1219
 1220#endif
 1221