public IEnumerable<MapObject> Create(IDGenerator generator, Box box, ITexture texture, int roundDecimals) { var numSides = (int)_numSides.GetValue(); if (numSides < 3) yield break; var width = box.Width; var length = box.Length; var height = box.Height; var major = width / 2; var minor = length / 2; var heightRadius = height / 2; var angleV = DMath.DegreesToRadians(180) / numSides; var angleH = DMath.DegreesToRadians(360) / numSides; var faces = new List<Coordinate[]>(); var bottom = new Coordinate(box.Center.X, box.Center.Y, box.Start.Z).Round(roundDecimals); var top = new Coordinate(box.Center.X, box.Center.Y, box.End.Z).Round(roundDecimals); for (var i = 0; i < numSides; i++) { // Top -> bottom var zAngleStart = angleV * i; var zAngleEnd = angleV * (i + 1); var zStart = heightRadius * DMath.Cos(zAngleStart); var zEnd = heightRadius * DMath.Cos(zAngleEnd); var zMultStart = DMath.Sin(zAngleStart); var zMultEnd = DMath.Sin(zAngleEnd); for (var j = 0; j < numSides; j++) { // Go around the circle in X/Y var xyAngleStart = angleH * j; var xyAngleEnd = angleH * ((j + 1) % numSides); var xyStartX = major * DMath.Cos(xyAngleStart); var xyStartY = minor * DMath.Sin(xyAngleStart); var xyEndX = major * DMath.Cos(xyAngleEnd); var xyEndY = minor * DMath.Sin(xyAngleEnd); var one = (new Coordinate(xyStartX * zMultStart, xyStartY * zMultStart, zStart) + box.Center).Round(roundDecimals); var two = (new Coordinate(xyEndX * zMultStart, xyEndY * zMultStart, zStart) + box.Center).Round(roundDecimals); var three = (new Coordinate(xyEndX * zMultEnd, xyEndY * zMultEnd, zEnd) + box.Center).Round(roundDecimals); var four = (new Coordinate(xyStartX * zMultEnd, xyStartY * zMultEnd, zEnd) + box.Center).Round(roundDecimals); if (i == 0) { // Top faces are triangles faces.Add(new[] { top, three, four }); } else if (i == numSides - 1) { // Bottom faces are also triangles faces.Add(new[] { bottom, one, two }); } else { // Inner faces are quads faces.Add(new[] { one, two, three, four }); } } } yield return MakeSolid(generator, faces, texture, Colour.GetRandomBrushColour()); }
public IEnumerable<MapObject> Create(IDGenerator generator, Box box, ITexture texture) { var solid = new Solid(generator.GetNextObjectID()) { Colour = Colour.GetRandomBrushColour() }; // The lower Z plane will be base, the x planes will be triangles var c1 = new Coordinate(box.Start.X, box.Start.Y, box.Start.Z); var c2 = new Coordinate(box.End.X, box.Start.Y, box.Start.Z); var c3 = new Coordinate(box.End.X, box.End.Y, box.Start.Z); var c4 = new Coordinate(box.Start.X, box.End.Y, box.Start.Z); var c5 = new Coordinate(box.Center.X, box.Start.Y, box.End.Z); var c6 = new Coordinate(box.Center.X, box.End.Y, box.End.Z); var faces = new[] { new[] { c1, c2, c3, c4 }, new[] { c2, c1, c5 }, new[] { c5, c6, c3, c2 }, new[] { c4, c3, c6 }, new[] { c6, c5, c1, c4 } }; foreach (var arr in faces) { var face = new Face(generator.GetNextFaceID()) { Parent = solid, Plane = new Plane(arr[0], arr[1], arr[2]), Colour = solid.Colour, Texture = { Texture = texture } }; face.Vertices.AddRange(arr.Select(x => new Vertex(x, face))); face.UpdateBoundingBox(); face.AlignTextureToFace(); solid.Faces.Add(face); } solid.UpdateBoundingBox(); yield return solid; }
public static Solid CreateFromIntersectingPlanes(IEnumerable<Plane> planes, IDGenerator generator) { var solid = new Solid(generator.GetNextObjectID()); var list = planes.ToList(); for (var i = 0; i < list.Count; i++) { // Split the polygon by all the other planes var poly = new Polygon(list[i]); for (var j = 0; j < list.Count; j++) { if (i != j) poly.Split(list[j]); } // The final polygon is the face var face = new Face(generator.GetNextFaceID()) { Plane = poly.Plane , Parent = solid }; face.Vertices.AddRange(poly.Vertices.Select(x => new Vertex(x, face))); face.UpdateBoundingBox(); face.AlignTextureToWorld(); solid.Faces.Add(face); } // Ensure all the faces point outwards var origin = solid.GetOrigin(); foreach (var face in solid.Faces) { if (face.Plane.OnPlane(origin) >= 0) face.Flip(); } solid.UpdateBoundingBox(); return solid; }
public IEnumerable<MapObject> Create(IDGenerator generator, Box box, ITexture texture, int roundDecimals) { var solid = new Solid(generator.GetNextObjectID()) { Colour = Colour.GetRandomBrushColour() }; // The higher Z plane will be triangle, with the lower X value getting the two corners var c1 = new Coordinate(box.Start.X, box.Start.Y, box.End.Z).Round(roundDecimals); var c2 = new Coordinate(box.End.X, box.Start.Y, box.End.Z).Round(roundDecimals); var c3 = new Coordinate(box.Center.X, box.End.Y, box.End.Z).Round(roundDecimals); var c4 = new Coordinate(box.Center.X, box.Center.Y, box.Start.Z).Round(roundDecimals); var faces = new[] { new[] { c3, c2, c1 }, new[] { c3, c1, c4 }, new[] { c2, c3, c4 }, new[] { c1, c2, c4 } }; foreach (var arr in faces) { var face = new Face(generator.GetNextFaceID()) { Parent = solid, Plane = new Plane(arr[0], arr[1], arr[2]), Colour = solid.Colour, Texture = { Texture = texture } }; face.Vertices.AddRange(arr.Select(x => new Vertex(x, face))); face.UpdateBoundingBox(); face.AlignTextureToFace(); solid.Faces.Add(face); } solid.UpdateBoundingBox(); yield return solid; }
public override void Paste(MapObject o, IDGenerator generator) { PasteBase(o, generator); var e = o as World; if (e == null) return; EntityData = e.EntityData.Clone(); Paths.Clear(); Paths.AddRange(e.Paths.Select(x => x.Clone())); }
public IEnumerable<MapObject> Create(IDGenerator generator, Box box, ITexture texture, int roundDecimals) { var numsides = (int) _numSides.GetValue(); if (numsides < 3) yield break; // Cylinders can be elliptical so use both major and minor rather than just the radius // NOTE: when a low number (< 10ish) of faces are selected this will cause the cylinder to not touch all the edges of the box. var width = box.Width; var length = box.Length; var height = box.Height; var major = width / 2; var minor = length / 2; var angle = 2 * DMath.PI / numsides; // Calculate the X and Y points for the ellipse var points = new Coordinate[numsides]; for (var i = 0; i < numsides; i++) { var a = i * angle; var xval = box.Center.X + major * DMath.Cos(a); var yval = box.Center.Y + minor * DMath.Sin(a); var zval = box.Start.Z; points[i] = new Coordinate(xval, yval, zval).Round(roundDecimals); } var faces = new List<Coordinate[]>(); // Add the vertical faces var z = new Coordinate(0, 0, height).Round(roundDecimals); for (var i = 0; i < numsides; i++) { var next = (i + 1) % numsides; faces.Add(new[] {points[i], points[i] + z, points[next] + z, points[next]}); } // Add the elliptical top and bottom faces faces.Add(points.ToArray()); faces.Add(points.Select(x => x + z).Reverse().ToArray()); // Nothing new here, move along var solid = new Solid(generator.GetNextObjectID()) { Colour = Colour.GetRandomBrushColour() }; foreach (var arr in faces) { var face = new Face(generator.GetNextFaceID()) { Parent = solid, Plane = new Plane(arr[0], arr[1], arr[2]), Colour = solid.Colour, Texture = { Texture = texture } }; face.Vertices.AddRange(arr.Select(x => new Vertex(x, face))); face.UpdateBoundingBox(); face.AlignTextureToFace(); solid.Faces.Add(face); } solid.UpdateBoundingBox(); yield return solid; }
public override MapObject Copy(IDGenerator generator) { var e = new World(generator.GetNextObjectID()) { EntityData = EntityData.Clone(), }; e.Paths.AddRange(Paths.Select(x => x.Clone())); CopyBase(e, generator); return e; }
public override MapObject Copy(IDGenerator generator) { var e = new Entity(generator.GetNextObjectID()) { GameData = GameData, EntityData = EntityData.Clone(), Origin = Origin.Clone() }; CopyBase(e, generator); return e; }
public override MapObject Copy(IDGenerator generator) { var e = new Solid(generator.GetNextObjectID()); foreach (var f in Faces.Select(x => x.Copy(generator))) { f.Parent = e; e.Faces.Add(f); f.UpdateBoundingBox(); } CopyBase(e, generator); return e; }
public IEnumerable<MapObject> Create(IDGenerator generator, Box box, ITexture texture) { var numsides = (int) _numSides.GetValue(); if (numsides < 3) yield break; // This is all very similar to the cylinder brush. var width = box.Width; var length = box.Length; var major = width / 2; var minor = length / 2; var angle = 2 * DMath.PI / numsides; var points = new Coordinate[numsides]; for (var i = 0; i < numsides; i++) { var a = i * angle; var xval = box.Center.X + major * DMath.Cos(a); var yval = box.Center.Y + minor * DMath.Sin(a); var zval = box.Start.Z; points[i] = new Coordinate(xval, yval, zval).Round(0); } var faces = new List<Coordinate[]>(); var point = new Coordinate(box.Center.X, box.Center.Y, box.End.Z); for (var i = 0; i < numsides; i++) { var next = (i + 1) % numsides; faces.Add(new[] {points[i], point, points[next]}); } faces.Add(points.ToArray()); var solid = new Solid(generator.GetNextObjectID()) { Colour = Colour.GetRandomBrushColour() }; foreach (var arr in faces) { var face = new Face(generator.GetNextFaceID()) { Parent = solid, Plane = new Plane(arr[0], arr[1], arr[2]), Colour = solid.Colour, Texture = { Texture = texture } }; face.Vertices.AddRange(arr.Select(x => new Vertex(x, face))); face.UpdateBoundingBox(); face.AlignTextureToFace(); solid.Faces.Add(face); } solid.UpdateBoundingBox(); yield return solid; }
public Map() { Version = 1; Visgroups = new List<Visgroup>(); Cameras = new List<Camera>(); ActiveCamera = null; IDGenerator = new IDGenerator(); WorldSpawn = new World(IDGenerator.GetNextObjectID()); Show2DGrid = SnapToGrid = true; TextureLock = true; HideDisplacementSolids = true; CordonBounds = new Box(Coordinate.One * -1024, Coordinate.One * 1024); }
public IEnumerable<MapObject> Create(IDGenerator generator, Box box, ITexture texture) { var wallWidth = (int) _width.GetValue(); if (wallWidth < 1) yield break; var numsides = (int) _numSides.GetValue(); if (numsides < 3) yield break; // Very similar to the cylinder, except we have multiple solids this time var width = box.Width; var length = box.Length; var height = box.Height; var majorOut = width / 2; var majorIn = majorOut - wallWidth; var minorOut = length / 2; var minorIn = minorOut - wallWidth; var angle = 2 * DMath.PI / numsides; var colour = Colour.GetRandomBrushColour(); // Calculate the X and Y points for the inner and outer ellipses var outer = new Coordinate[numsides]; var inner = new Coordinate[numsides]; for (var i = 0; i < numsides; i++) { var a = i * angle; var xval = box.Center.X + majorOut * DMath.Cos(a); var yval = box.Center.Y + minorOut * DMath.Sin(a); var zval = box.Start.Z; outer[i] = new Coordinate(xval, yval, zval).Round(0); xval = box.Center.X + majorIn * DMath.Cos(a); yval = box.Center.Y + minorIn * DMath.Sin(a); inner[i] = new Coordinate(xval, yval, zval).Round(0); } // Create the solids var z = new Coordinate(0, 0, height); for (var i = 0; i < numsides; i++) { var faces = new List<Coordinate[]>(); var next = (i + 1) % numsides; faces.Add(new[] { outer[i], outer[i] + z, outer[next] + z, outer[next] }); faces.Add(new[] { inner[next], inner[next] + z, inner[i] + z, inner[i] }); faces.Add(new[] { outer[next], outer[next] + z, inner[next] + z, inner[next] }); faces.Add(new[] { inner[i], inner[i] + z, outer[i] + z, outer[i] }); faces.Add(new[] { inner[next] + z, outer[next] + z, outer[i] + z, inner[i] + z }); faces.Add(new[] { inner[i], outer[i], outer[next], inner[next] }); yield return MakeSolid(generator, faces, texture, colour); } }
public static IEnumerable<MapObject> ExtractCopyStream(GenericStructure gs, IDGenerator generator) { if (gs == null || gs.Name != "clipboard") return null; var dummyGen = new IDGenerator(); var list = new List<MapObject>(); var world = ReadWorld(gs, dummyGen); foreach (var entity in gs.GetChildren("entity")) { var ent = ReadEntity(entity, dummyGen); var groupid = entity.Children.Where(x => x.Name == "editor").Select(x => x.PropertyInteger("groupid")).FirstOrDefault(); var entParent = groupid > 0 ? world.Find(x => x.ID == groupid && x is Group).FirstOrDefault() ?? world : world; ent.SetParent(entParent); } list.AddRange(world.GetChildren()); Reindex(list, generator); return list; }
public void CopyEntityTest() { var idGen = new IDGenerator(); var box = new Box(Coordinate.One * -100, Coordinate.One * 100); // Create an entity with children var ent = new Entity(idGen.GetNextObjectID()); ent.EntityData.Name = "Test"; ent.EntityData.Properties.Add(new Property { Key = "key1", Value = "value1"}); ent.EntityData.Properties.Add(new Property { Key = "key2", Value = "value2"}); ent.EntityData.Flags = 12345; var solids = new BlockBrush().Create(idGen, box, null, 0); foreach (var mo in solids) mo.SetParent(ent); // Copy and reconstruct var gs = VmfProvider.CreateCopyStream(new List<MapObject> {ent}); var pasted = VmfProvider.ExtractCopyStream(gs, idGen).ToList(); // Test object Assert.AreEqual(1, pasted.Count); Assert.IsInstanceOfType(pasted[0], typeof(Entity)); // Test entity var pastedEnt = (Entity) pasted[0]; Assert.AreEqual("Test", pastedEnt.EntityData.Name); Assert.AreEqual(12345, pastedEnt.EntityData.Flags); // Test properties Assert.AreEqual(2, pastedEnt.EntityData.Properties.Count); var k1 = pastedEnt.EntityData.Properties.FirstOrDefault(x => x.Key == "key1"); var k2 = pastedEnt.EntityData.Properties.FirstOrDefault(x => x.Key == "key1"); Assert.IsNotNull(k1); Assert.IsNotNull(k2); Assert.AreEqual(k1.Value, "value1"); Assert.AreEqual(k2.Value, "value1"); // Test child Assert.AreEqual(1, pastedEnt.ChildCount); Assert.IsInstanceOfType(pastedEnt.GetChildren().ToList()[0], typeof(Solid)); // Check number of sides, values of sides not so important var pastedSolid = (Solid) pastedEnt.GetChildren().ToList()[0]; Assert.AreEqual(6, pastedSolid.Faces.Count); }
public IEnumerable<MapObject> Create(IDGenerator generator, Box box, ITexture texture, int roundDecimals) { var solid = new Solid(generator.GetNextObjectID()) { Colour = Colour.GetRandomBrushColour() }; foreach (var arr in box.GetBoxFaces()) { var face = new Face(generator.GetNextFaceID()) { Parent = solid, Plane = new Plane(arr[0], arr[1], arr[2]), Colour = solid.Colour, Texture = { Texture = texture } }; face.Vertices.AddRange(arr.Select(x => new Vertex(x.Round(roundDecimals), face))); face.UpdateBoundingBox(); face.AlignTextureToFace(); solid.Faces.Add(face); } solid.UpdateBoundingBox(); yield return solid; }
public void BenchmarkSolidConstruction() { var idg = new IDGenerator(); var box = new Box(Coordinate.One * -100, Coordinate.One * 100); var planes = new CylinderBrush().Create(idg, box, null, 2).OfType<Solid>().SelectMany(x => x.Faces).Select(x => x.Plane).ToList(); var stopwatch = new Stopwatch(); stopwatch.Start(); for (var b = 0; b < 1000; b++) { Solid.CreateFromIntersectingPlanes(planes, idg); } stopwatch.Stop(); Debug.WriteLine(stopwatch.Elapsed); stopwatch.Restart(); for (var b = 0; b < 1000; b++) { var polys = new List<Polygon>(); for (var i = 0; i < planes.Count; i++) { var poly = new Polygon(planes[i]); for (var j = 0; j < planes.Count; j++) { if (i != j) poly.Split(planes[j]); } polys.Add(poly); } var solid = new Solid(idg.GetNextObjectID()); foreach (var polygon in polys) { var face = new Face(idg.GetNextFaceID()) {Plane = polygon.Plane}; face.Vertices.AddRange(polygon.Vertices.Select(x => new Vertex(x, face))); face.UpdateBoundingBox(); face.AlignTextureToWorld(); solid.Faces.Add(face); } solid.UpdateBoundingBox(); } stopwatch.Stop(); Debug.WriteLine(stopwatch.Elapsed); }
private static Solid ReadMapSolid(BinaryReader br, List<Visgroup> visgroups, IDGenerator generator) { var sol = new Solid(generator.GetNextObjectID()); ReadMapBase(br, sol, visgroups, generator); var numFaces = br.ReadInt32(); for (var i = 0; i < numFaces; i++) { var face = ReadFace(br, generator); face.Parent = sol; face.Colour = sol.Colour; sol.Faces.Add(face); } sol.UpdateBoundingBox(false); return sol; }
/// <summary> /// Splits this solid into two solids by intersecting against a plane. /// </summary> /// <param name="plane">The splitting plane</param> /// <param name="back">The back side of the solid</param> /// <param name="front">The front side of the solid</param> /// <param name="generator">The IDGenerator to use</param> /// <returns>True if the plane splits the solid, false if the plane doesn't intersect</returns> public bool Split(Plane plane, out Solid back, out Solid front, IDGenerator generator) { back = front = null; // Check that this solid actually spans the plane var classify = Faces.Select(x => x.ClassifyAgainstPlane(plane)).Distinct().ToList(); if (classify.All(x => x != PlaneClassification.Spanning)) { if (classify.Any(x => x == PlaneClassification.Back)) back = this; else if (classify.Any(x => x == PlaneClassification.Front)) front = this; return false; } var backPlanes = new List<Plane> { plane }; var frontPlanes = new List<Plane> { new Plane(-plane.Normal, -plane.DistanceFromOrigin) }; foreach (var face in Faces) { var classification = face.ClassifyAgainstPlane(plane); if (classification != PlaneClassification.Back) frontPlanes.Add(face.Plane); if (classification != PlaneClassification.Front) backPlanes.Add(face.Plane); } back = CreateFromIntersectingPlanes(backPlanes, generator); front = CreateFromIntersectingPlanes(frontPlanes, generator); CopyBase(back, generator); CopyBase(front, generator); front.Faces.Union(back.Faces).ToList().ForEach(x => { x.Texture = Faces[0].Texture.Clone(); x.AlignTextureToFace(); x.Colour = Colour; }); // Restore textures (match the planes up on each face) foreach (var orig in Faces) { foreach (var face in back.Faces) { var classification = face.ClassifyAgainstPlane(orig.Plane); if (classification != PlaneClassification.OnPlane) continue; face.Texture = orig.Texture.Clone(); break; } foreach (var face in front.Faces) { var classification = face.ClassifyAgainstPlane(orig.Plane); if (classification != PlaneClassification.OnPlane) continue; face.Texture = orig.Texture.Clone(); break; } } front.Faces.Union(back.Faces).ToList().ForEach(x => x.CalculateTextureCoordinates(true)); return true; }
public override void Paste(MapObject o, IDGenerator generator) { PasteBase(o, generator); var e = o as Solid; if (e == null) return; Faces.Clear(); foreach (var f in e.Faces.Select(x => x.Copy(generator))) { f.Parent = this; Faces.Add(f); f.UpdateBoundingBox(); } }
public virtual Face Copy(IDGenerator generator) { var f = new Face(generator.GetNextFaceID()) { Plane = Plane.Clone(), Colour = Colour, IsSelected = IsSelected, IsHidden = IsHidden, Opacity = Opacity, Texture = Texture.Clone(), Parent = Parent, BoundingBox = BoundingBox.Clone() }; foreach (var v in Vertices.Select(x => x.Clone())) { v.Parent = f; f.Vertices.Add(v); } return f; }
public override void Paste(MapObject o, IDGenerator generator) { PasteBase(o, generator); var e = o as Entity; if (e == null) return; GameData = e.GameData; Origin = e.Origin.Clone(); EntityData = e.EntityData.Clone(); }
public IEnumerable<MapObject> Create(IDGenerator generator, Box box, ITexture texture, int roundDecimals) { var width = box.Width; var length = Math.Max(1, Math.Abs((int) box.Length)); var height = box.Height; var flatten = (float) _flattenFactor.Value; var text = _text.GetValue(); var family = _fontChooser.GetFontFamily(); var style = Enum.GetValues(typeof (FontStyle)).OfType<FontStyle>().FirstOrDefault(fs => family.IsStyleAvailable(fs)); if (!family.IsStyleAvailable(style)) family = FontFamily.GenericSansSerif; var set = new PolygonSet(); var sizes = new List<RectangleF>(); using (var bmp = new Bitmap(1,1)) { using (var g = System.Drawing.Graphics.FromImage(bmp)) { using (var font = new Font(family, length, style, GraphicsUnit.Pixel)) { for (var i = 0; i < text.Length; i += 32) { using (var sf = new StringFormat(StringFormat.GenericTypographic)) { var rem = Math.Min(text.Length, i + 32) - i; var range = Enumerable.Range(0, rem).Select(x => new CharacterRange(x, 1)).ToArray(); sf.SetMeasurableCharacterRanges(range); var reg = g.MeasureCharacterRanges(text.Substring(i, rem), font, new RectangleF(0, 0, float.MaxValue, float.MaxValue), sf); sizes.AddRange(reg.Select(x => x.GetBounds(g))); } } } } } var xOffset = box.Start.DX; var yOffset = box.End.DY; for (var ci = 0; ci < text.Length; ci++) { var c = text[ci]; var size = sizes[ci]; var gp = new GraphicsPath(); gp.AddString(c.ToString(CultureInfo.InvariantCulture), family, (int)style, length, new PointF(0, 0), StringFormat.GenericTypographic); gp.Flatten(new System.Drawing.Drawing2D.Matrix(), flatten); var polygons = new List<Polygon>(); var poly = new List<PolygonPoint>(); for (var i = 0; i < gp.PointCount; i++) { var type = gp.PathTypes[i]; var point = gp.PathPoints[i]; poly.Add(new PolygonPoint(point.X + xOffset, -point.Y + yOffset)); if ((type & 0x80) == 0x80) { polygons.Add(new Polygon(poly)); poly.Clear(); } } var tri = new List<Polygon>(); Polygon polygon = null; foreach (var p in polygons) { if (polygon == null) { polygon = p; tri.Add(p); } else if (p.CalculateWindingOrder() != polygon.CalculateWindingOrder()) { polygon.AddHole(p); } else { polygon = null; tri.Add(p); } } foreach (var pp in tri) { try { P2T.Triangulate(pp); set.Add(pp); } catch { // Ignore } } xOffset += size.Width; } var zOffset = box.Start.Z; foreach (var polygon in set.Polygons) { foreach (var t in polygon.Triangles) { var points = t.Points.Select(x => new Coordinate((decimal) x.X, (decimal) x.Y, zOffset).Round(roundDecimals)).ToList(); var faces = new List<Coordinate[]>(); // Add the vertical faces var z = new Coordinate(0, 0, height).Round(roundDecimals); for (var j = 0; j < points.Count; j++) { var next = (j + 1) % points.Count; faces.Add(new[] {points[j], points[j] + z, points[next] + z, points[next]}); } // Add the top and bottom faces faces.Add(points.ToArray()); faces.Add(points.Select(x => x + z).Reverse().ToArray()); // Nothing new here, move along var solid = new Solid(generator.GetNextObjectID()) {Colour = Colour.GetRandomBrushColour()}; foreach (var arr in faces) { var face = new Face(generator.GetNextFaceID()) { Parent = solid, Plane = new Plane(arr[0], arr[1], arr[2]), Colour = solid.Colour, Texture = {Texture = texture} }; face.Vertices.AddRange(arr.Select(x => new Vertex(x, face))); face.UpdateBoundingBox(); face.AlignTextureToFace(); solid.Faces.Add(face); } solid.UpdateBoundingBox(); yield return solid; } } }
public override void Paste(MapObject o, IDGenerator generator) { PasteBase(o, generator); }
public override MapObject Copy(IDGenerator generator) { var group = new Group(generator.GetNextObjectID()); CopyBase(group, generator); return group; }
private static MapObject ReadMapObject(BinaryReader br, List<Visgroup> visgroups, IDGenerator generator) { var type = br.ReadCString(); switch (type) { case "CMapWorld": return ReadMapWorld(br, visgroups, generator); case "CMapGroup": return ReadMapGroup(br, visgroups, generator); case "CMapSolid": return ReadMapSolid(br, visgroups, generator); case "CMapEntity": return ReadMapEntity(br, visgroups, generator); default: throw new ProviderException("Unknown RMF map object: " + type); } }
private Solid MakeSolid(IDGenerator generator, IEnumerable<Coordinate[]> faces, ITexture texture, Color col) { var solid = new Solid(generator.GetNextObjectID()) { Colour = col }; foreach (var arr in faces) { var face = new Face(generator.GetNextFaceID()) { Parent = solid, Plane = new Plane(arr[0], arr[1], arr[2]), Colour = solid.Colour, Texture = { Texture = texture } }; face.Vertices.AddRange(arr.Select(x => new Vertex(x, face))); face.UpdateBoundingBox(); face.AlignTextureToWorld(); solid.Faces.Add(face); } solid.UpdateBoundingBox(); return solid; }
public IEnumerable<MapObject> Create(IDGenerator generator, Box box, ITexture texture, int roundDecimals) { var numSides = (int)_numSides.GetValue(); if (numSides < 3) yield break; var wallWidth = _wallWidth.GetValue(); if (wallWidth < 1) yield break; var arc = _arc.GetValue(); if (arc < 1) yield break; var startAngle = _startAngle.GetValue(); if (startAngle < 0 || startAngle > 359) yield break; var addHeight = _addHeight.GetValue(); var curvedRamp = _curvedRamp.GetValue(); var tiltAngle = curvedRamp ? _tiltAngle.GetValue() : 0; if (DMath.Abs(tiltAngle % 180) == 90) yield break; var tiltInterp = curvedRamp && _tiltInterp.GetValue(); // Very similar to the pipe brush, except with options for start angle, arc, height and tilt var width = box.Width; var length = box.Length; var height = box.Height; var majorOut = width / 2; var majorIn = majorOut - wallWidth; var minorOut = length / 2; var minorIn = minorOut - wallWidth; var start = DMath.DegreesToRadians(startAngle); var tilt = DMath.DegreesToRadians(tiltAngle); var angle = DMath.DegreesToRadians(arc) / numSides; var colour = Colour.GetRandomBrushColour(); // Calculate the coordinates of the inner and outer ellipses' points var outer = new Coordinate[numSides + 1]; var inner = new Coordinate[numSides + 1]; for (var i = 0; i < numSides + 1; i++) { var a = start + i * angle; var h = i * addHeight; var interp = tiltInterp ? DMath.Cos(DMath.PI / numSides * (i - numSides / 2M)) : 1; var tiltHeight = wallWidth / 2 * interp * DMath.Tan(tilt); var xval = box.Center.X + majorOut * DMath.Cos(a); var yval = box.Center.Y + minorOut * DMath.Sin(a); var zval = box.Start.Z + (curvedRamp ? h + tiltHeight : 0); outer[i] = new Coordinate(xval, yval, zval).Round(roundDecimals); xval = box.Center.X + majorIn * DMath.Cos(a); yval = box.Center.Y + minorIn * DMath.Sin(a); zval = box.Start.Z + (curvedRamp ? h - tiltHeight : 0); inner[i] = new Coordinate(xval, yval, zval).Round(roundDecimals); } // Create the solids for (var i = 0; i < numSides; i++) { var faces = new List<Coordinate[]>(); var z = new Coordinate(0, 0, height).Round(roundDecimals); // Since we are triangulating/splitting each arch segment, we need to generate 2 brushes per side if (curvedRamp) { // The splitting orientation depends on the curving direction of the arch if (addHeight >= 0) { faces.Add(new[] { outer[i], outer[i] + z, outer[i+1] + z, outer[i+1] }); faces.Add(new[] { outer[i+1], outer[i+1] + z, inner[i] + z, inner[i] }); faces.Add(new[] { inner[i], inner[i] + z, outer[i] + z, outer[i] }); faces.Add(new[] { outer[i] + z, inner[i] + z, outer[i+1] + z }); faces.Add(new[] { outer[i+1], inner[i], outer[i] }); } else { faces.Add(new[] { inner[i+1], inner[i+1] + z, inner[i] + z, inner[i] }); faces.Add(new[] { outer[i], outer[i] + z, inner[i+1] + z, inner[i+1] }); faces.Add(new[] { inner[i], inner[i] + z, outer[i] + z, outer[i] }); faces.Add(new[] { inner[i+1] + z, outer[i] + z, inner[i] + z }); faces.Add(new[] { inner[i], outer[i], inner[i+1] }); } yield return MakeSolid(generator, faces, texture, colour); faces.Clear(); if (addHeight >= 0) { faces.Add(new[] { inner[i+1], inner[i+1] + z, inner[i] + z, inner[i] }); faces.Add(new[] { inner[i], inner[i] + z, outer[i+1] + z, outer[i+1] }); faces.Add(new[] { outer[i+1], outer[i+1] + z, inner[i+1] + z, inner[i+1] }); faces.Add(new[] { inner[i+1] + z, outer[i+1] + z, inner[i] + z }); faces.Add(new[] { inner[i], outer[i+1], inner[i+1] }); } else { faces.Add(new[] { outer[i], outer[i] + z, outer[i+1] + z, outer[i+1] }); faces.Add(new[] { inner[i+1], inner[i+1] + z, outer[i] + z, outer[i] }); faces.Add(new[] { outer[i+1], outer[i+1] + z, inner[i+1] + z, inner[i+1] }); faces.Add(new[] { outer[i] + z, inner[i+1] + z, outer[i+1] + z }); faces.Add(new[] { outer[i+1], inner[i+1], outer[i] }); } yield return MakeSolid(generator, faces, texture, colour); } else { var h = i * addHeight * Coordinate.UnitZ; faces.Add(new[] { outer[i], outer[i] + z, outer[i+1] + z, outer[i+1] }.Select(x => x + h).ToArray()); faces.Add(new[] { inner[i+1], inner[i+1] + z, inner[i] + z, inner[i] }.Select(x => x + h).ToArray()); faces.Add(new[] { outer[i+1], outer[i+1] + z, inner[i+1] + z, inner[i+1] }.Select(x => x + h).ToArray()); faces.Add(new[] { inner[i], inner[i] + z, outer[i] + z, outer[i] }.Select(x => x + h).ToArray()); faces.Add(new[] { inner[i+1] + z, outer[i+1] + z, outer[i] + z, inner[i] + z }.Select(x => x + h).ToArray()); faces.Add(new[] { inner[i], outer[i], outer[i+1], inner[i+1] }.Select(x => x + h).ToArray()); yield return MakeSolid(generator, faces, texture, colour); } } }
private static MapObject ReadMapWorld(BinaryReader br, List<Visgroup> visgroups, IDGenerator generator) { var wld = new World(generator.GetNextObjectID()); ReadMapBase(br, wld, visgroups, generator); wld.EntityData = ReadEntityData(br); var numPaths = br.ReadInt32(); for (var i = 0; i < numPaths; i++) { wld.Paths.Add(ReadPath(br)); } return wld; }
private MapObject GetBrush(Box bounds, IDGenerator idg) { var brush = BrushManager.CurrentBrush; var ti = Document.TextureCollection.SelectedTexture; var texture = ti != null ? ti.GetTexture() : null; var created = brush.Create(idg, bounds, texture, BrushManager.RoundCreatedVertices ? 0 : 2).ToList(); if (created.Count > 1) { var g = new Group(idg.GetNextObjectID()); created.ForEach(x => x.SetParent(g)); g.UpdateBoundingBox(); return g; } return created.FirstOrDefault(); }
private static World ReadWorldSpawn(BinaryReader br, List<Visgroup> visgroups, IDGenerator generator) { return (World)ReadMapObject(br, visgroups, generator); }