private Face ReadFace(string line, UniqueNumberGenerator generator) { const NumberStyles ns = NumberStyles.Float; var parts = line.Split(' ').Where(x => !String.IsNullOrWhiteSpace(x)).ToList(); Assert(parts[0] == "("); Assert(parts[4] == ")"); Assert(parts[5] == "("); Assert(parts[9] == ")"); Assert(parts[10] == "("); Assert(parts[14] == ")"); var face = new Face(generator.Next("Face")) { Plane = new Plane( NumericsExtensions.Parse(parts[1], parts[2], parts[3], ns, CultureInfo.InvariantCulture), NumericsExtensions.Parse(parts[6], parts[7], parts[8], ns, CultureInfo.InvariantCulture), NumericsExtensions.Parse(parts[11], parts[12], parts[13], ns, CultureInfo.InvariantCulture) ), Texture = { Name = parts[15] } }; // Cater for older-style map formats // TODO Quake 3: when the MAP face has 24 parts, the last three parts are: content_flags, surface_flags, value if (parts.Count == 21 || parts.Count == 24) { QuakeEdAlignTextureToWorld(face); var xshift = float.Parse(parts[16], ns, CultureInfo.InvariantCulture); var yshift = float.Parse(parts[17], ns, CultureInfo.InvariantCulture); var rotate = float.Parse(parts[18], ns, CultureInfo.InvariantCulture); var xscale = float.Parse(parts[19], ns, CultureInfo.InvariantCulture); var yscale = float.Parse(parts[20], ns, CultureInfo.InvariantCulture); face.Texture.Rotation = -rotate; face.Texture.Rotation = rotate; face.Texture.XScale = xscale; face.Texture.YScale = yscale; face.Texture.XShift = xshift; face.Texture.YShift = yshift; } else { Assert(parts[16] == "["); Assert(parts[21] == "]"); Assert(parts[22] == "["); Assert(parts[27] == "]"); face.Texture.UAxis = NumericsExtensions.Parse(parts[17], parts[18], parts[19], ns, CultureInfo.InvariantCulture); face.Texture.XShift = float.Parse(parts[20], ns, CultureInfo.InvariantCulture); face.Texture.VAxis = NumericsExtensions.Parse(parts[23], parts[24], parts[25], ns, CultureInfo.InvariantCulture); face.Texture.YShift = float.Parse(parts[26], ns, CultureInfo.InvariantCulture); face.Texture.Rotation = float.Parse(parts[28], ns, CultureInfo.InvariantCulture); face.Texture.XScale = float.Parse(parts[29], ns, CultureInfo.InvariantCulture); face.Texture.YScale = float.Parse(parts[30], ns, CultureInfo.InvariantCulture); } return(face); }
private static void ReadProperty(Entity ent, string line) { // Quake id1 map sources use tabs between keys and values var split = line.Split(new char[] { ' ', '\t' }); var key = split[0].Trim('"'); var val = String.Join(" ", split.Skip(1)).Trim('"'); if (key == "classname") { ent.EntityData.Name = val; } else if (key == "spawnflags") { ent.EntityData.Flags = int.Parse(val); } else if (key == "origin") { var osp = val.Split(' '); ent.Origin = NumericsExtensions.Parse(osp[0], osp[1], osp[2], NumberStyles.Float, CultureInfo.InvariantCulture); } else if (!ExcludedKeys.Contains(key.ToLower())) { ent.EntityData.Set(key, val); } }
public Vector3?GetVector3(int index) { var first = index * 3; return(Values.Count < first + 3 ? (Vector3?)null : NumericsExtensions.Parse(Values[first], Values[first + 1], Values[first + 2], NumberStyles.Float, CultureInfo.InvariantCulture)); }
public void TestParse() { Assert.AreEqual( NumericsExtensions.Parse("1", "2", "3", NumberStyles.Float, CultureInfo.InvariantCulture), new Vector3(1, 2, 3) ); Assert.AreEqual( NumericsExtensions.Parse("1,01", "2,02", "3,03", NumberStyles.Float, CultureInfo.GetCultureInfo("es-ES")), new Vector3(1.01f, 2.02f, 3.03f) ); }
public void MatrixTest() { var t = new Vector3(1, 2, 3); var orgAxis = Vector3.Normalize(new Vector3(1, 2, 3)); var orgAngle = 90 * NumericsExtensions.TO_RAD; var r = Quaternion.CreateFromAxisAngle(orgAxis, orgAngle); var s = new Vector3(2, 3, 4); var m = NumericsExtensions.FromTRS(t, r, s); var(tt, rr, ss) = m.Decompose(); Assert.True(s.NearlyEqual(ss)); Assert.True(r.NearlyEqual(rr)); Assert.AreEqual(t, tt); }
public static Pointfile Parse(IEnumerable <string> lines) { var pf = new Pointfile(); var list = lines.ToList(); if (!list.Any()) { return(pf); } // Format detection: look at one line // .lin format: coordinate - coordinate // .pts format: coordinate var detect = list[0].Split(' '); var lin = detect.Length == 7; var pts = detect.Length == 3; if (!lin && !pts) { throw new Exception("Invalid pointfile format."); } Vector3?previous = null; foreach (var line in list) { var split = line.Split(' '); var point = NumericsExtensions.Parse(split[0], split[1], split[2], NumberStyles.Float, CultureInfo.InvariantCulture); if (lin) { var point2 = NumericsExtensions.Parse(split[4], split[5], split[6], NumberStyles.Float, CultureInfo.InvariantCulture); pf.Lines.Add(new Line(point2, point)); } else // pts { if (previous.HasValue) { pf.Lines.Add(new Line(previous.Value, point)); } previous = point; } } return(pf); }
public VmfSide(SerialisedObject obj) { ID = obj.Get("ID", 0L); Face = new Face { TextureName = obj.Get("material", ""), Rotation = obj.Get("rotation", 0f), LightmapScale = obj.Get("lightmapscale", 0), SmoothingGroups = obj.Get("smoothing_groups", "") }; if (Util.ParseFloatArray(obj.Get("plane", ""), new[] { ' ', '(', ')' }, 9, out var pl)) { Face.Plane = NumericsExtensions.PlaneFromVertices( new Vector3(pl[0], pl[1], pl[2]).Round(), new Vector3(pl[3], pl[4], pl[5]).Round(), new Vector3(pl[6], pl[7], pl[8]).Round() ); } else { Face.Plane = new Plane(Vector3.UnitZ, 0); } if (Util.ParseFloatArray(obj.Get("uaxis", ""), new[] { ' ', '[', ']' }, 5, out float[] ua))
static void WriteEntity(Entity entity, BinaryWriter bw) { bw.WriteCString("CMapEntity", MaxVariableStringLength); WriteMapBase(entity, bw); WriteEntityData(entity, bw); bw.Write(new byte[2]); // Unused Vector3 origin = new Vector3(); if (entity.Properties.ContainsKey("origin")) { string o = entity.Properties["origin"]; if (!string.IsNullOrWhiteSpace(o)) { string[] parts = o.Split(' '); if (parts.Length == 3) { NumericsExtensions.TryParse(parts[0], parts[1], parts[2], NumberStyles.Float, CultureInfo.InvariantCulture, out origin); } } } bw.WriteVector3(origin); bw.Write(new byte[4]); // Unused }
private void Read(Map map, StreamReader reader) { const NumberStyles ns = NumberStyles.Float; var points = new List <Vector3>(); var faces = new List <ObjFace>(); var currentGroup = "default"; var scale = 100f; string line; while ((line = reader.ReadLine()) != null) { if (line.StartsWith("# Scale: ")) { var num = line.Substring(9); if (float.TryParse(num, NumberStyles.Float, CultureInfo.InvariantCulture, out var s)) { scale = s; } } line = CleanLine(line); SplitLine(line, out var keyword, out var values); if (String.IsNullOrWhiteSpace(keyword)) { continue; } var vals = (values ?? "").Split(' ').Where(x => !String.IsNullOrWhiteSpace(x)).ToArray(); switch (keyword.ToLower()) { // Things I care about case "v": // geometric vertices var vec = NumericsExtensions.Parse(vals[0], vals[1], vals[2], ns, CultureInfo.InvariantCulture); points.Add(vec * scale); break; case "f": // face faces.Add(new ObjFace(currentGroup, vals.Select(x => ParseFaceIndex(points, x)))); break; case "g": // group name currentGroup = (values ?? "").Trim(); break; // Things I don't care about #region Not Implemented // Vertex data // "v" case "vt": // texture vertices break; case "vn": // vertex normals break; case "vp": // parameter space vertices case "cstype": // rational or non-rational forms of curve or surface type: basis matrix, Bezier, B-spline, Cardinal, Taylor case "degree": // degree case "bmat": // basis matrix case "step": // step size // not supported break; // Elements // "f" case "p": // point case "l": // line case "curv": // curve case "curv2": // 2D curve case "surf": // surface // not supported break; // Free-form curve/surface body statements case "parm": // parameter name case "trim": // outer trimming loop (trim) case "hole": // inner trimming loop (hole) case "scrv": // special curve (scrv) case "sp": // special point (sp) case "end": // end statement (end) // not supported break; // Connectivity between free-form surfaces case "con": // connect // not supported break; // Grouping // "g" case "s": // smoothing group break; case "mg": // merging group break; case "o": // object name // not supported break; // Display/render attributes case "mtllib": // material library case "usemtl": // material name case "usemap": // texture map name case "bevel": // bevel interpolation case "c_interp": // color interpolation case "d_interp": // dissolve interpolation case "lod": // level of detail case "shadow_obj": // shadow casting case "trace_obj": // ray tracing case "ctech": // curve approximation technique case "stech": // surface approximation technique // not relevant break; #endregion } } var solids = new List <Solid>(); // Try and see if we have a valid solid per-group foreach (var g in faces.GroupBy(x => x.Group)) { solids.AddRange(CreateSolids(map, points, g)); } foreach (var solid in solids) { foreach (var face in solid.Faces) { face.Texture.AlignToNormal(face.Plane.Normal); } solid.Hierarchy.Parent = map.Root; } map.Root.DescendantsChanged(); }
static Face ReadFace(string line) { const NumberStyles ns = NumberStyles.Float; List <string> parts = line.Split(' ').ToList(); Util.Assert(parts[0] == "("); Util.Assert(parts[4] == ")"); Util.Assert(parts[5] == "("); Util.Assert(parts[9] == ")"); Util.Assert(parts[10] == "("); Util.Assert(parts[14] == ")"); Vector3 a = NumericsExtensions.Parse(parts[1], parts[2], parts[3], ns, CultureInfo.InvariantCulture); Vector3 b = NumericsExtensions.Parse(parts[6], parts[7], parts[8], ns, CultureInfo.InvariantCulture); Vector3 c = NumericsExtensions.Parse(parts[11], parts[12], parts[13], ns, CultureInfo.InvariantCulture); Vector3 ab = b - a; Vector3 ac = c - a; Vector3 normal = ac.Cross(ab).Normalise(); float d = normal.Dot(a); Face face = new Face() { Plane = new Plane(normal, d), TextureName = parts[15] }; // idTech2, idTech3 if (parts.Count == 21 || parts.Count == 24) { Vector3 direction = ClosestAxisToNormal(face.Plane); face.UAxis = direction == Vector3.UnitX ? Vector3.UnitY : Vector3.UnitX; face.VAxis = direction == Vector3.UnitZ ? -Vector3.UnitY : -Vector3.UnitZ; float xshift = float.Parse(parts[16], ns, CultureInfo.InvariantCulture); float yshift = float.Parse(parts[17], ns, CultureInfo.InvariantCulture); float rotate = float.Parse(parts[18], ns, CultureInfo.InvariantCulture); float xscale = float.Parse(parts[19], ns, CultureInfo.InvariantCulture); float yscale = float.Parse(parts[20], ns, CultureInfo.InvariantCulture); face.Rotation = rotate; face.XScale = xscale; face.YScale = yscale; face.XShift = xshift; face.YShift = yshift; // idTech3 if (parts.Count == 24) { face.ContentFlags = int.Parse(parts[18], CultureInfo.InvariantCulture); face.SurfaceFlags = int.Parse(parts[19], CultureInfo.InvariantCulture); face.Value = float.Parse(parts[20], ns, CultureInfo.InvariantCulture); } } // Worldcraft else if (parts.Count == 31) { Util.Assert(parts[16] == "["); Util.Assert(parts[21] == "]"); Util.Assert(parts[22] == "["); Util.Assert(parts[27] == "]"); face.UAxis = NumericsExtensions.Parse(parts[17], parts[18], parts[19], ns, CultureInfo.InvariantCulture); face.XShift = float.Parse(parts[20], ns, CultureInfo.InvariantCulture); face.VAxis = NumericsExtensions.Parse(parts[23], parts[24], parts[25], ns, CultureInfo.InvariantCulture); face.YShift = float.Parse(parts[26], ns, CultureInfo.InvariantCulture); face.Rotation = float.Parse(parts[28], ns, CultureInfo.InvariantCulture); face.XScale = float.Parse(parts[29], ns, CultureInfo.InvariantCulture); face.YScale = float.Parse(parts[30], ns, CultureInfo.InvariantCulture); } else { Util.Assert(false, $"Unknown number of tokens ({parts.Count}) in face definition."); } return(face); }