Esempio n. 1
0
        public IEnumerable <MapObject> Create(IDGenerator generator, Box box, ITexture texture, int roundDecimals)
        {
            var solid = new Solid(generator.GetNextObjectID())
            {
                Colour = Colour.GetRandomBrushColour(), Flags = (System.UInt32)SolidFlags.solid
            };
            // 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).Round(roundDecimals);
            var c2    = new Coordinate(box.End.X, box.Start.Y, box.Start.Z).Round(roundDecimals);
            var c3    = new Coordinate(box.End.X, box.End.Y, box.Start.Z).Round(roundDecimals);
            var c4    = new Coordinate(box.Start.X, box.End.Y, box.Start.Z).Round(roundDecimals);
            var c5    = new Coordinate(box.Center.X, box.Start.Y, box.End.Z).Round(roundDecimals);
            var c6    = new Coordinate(box.Center.X, box.End.Y, box.End.Z).Round(roundDecimals);
            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.Init();
                solid.Faces.Add(face);
            }
            solid.UpdateBoundingBox();
            yield return(solid);
        }
Esempio n. 2
0
        private static Face ReadFace(GenericStructure side, IDGenerator generator)
        {
            var id = side.PropertyLong("id");

            if (id == 0)
            {
                id = generator.GetNextFaceID();
            }
            var dispinfo = side.GetChildren("dispinfo").FirstOrDefault();
            var ret      = dispinfo != null?ReadDisplacement(id, dispinfo) : new Face(id);

            // id, plane, material, uaxis, vaxis, rotation, lightmapscale, smoothing_groups
            var uaxis = side.PropertyTextureAxis("uaxis");
            var vaxis = side.PropertyTextureAxis("vaxis");

            ret.Texture.Name     = side["material"];
            ret.Texture.UAxis    = uaxis.Item1;
            ret.Texture.XShift   = uaxis.Item2;
            ret.Texture.XScale   = uaxis.Item3;
            ret.Texture.VAxis    = vaxis.Item1;
            ret.Texture.YShift   = vaxis.Item2;
            ret.Texture.YScale   = vaxis.Item3;
            ret.Texture.Rotation = side.PropertyDecimal("rotation");
            ret.Plane            = side.PropertyPlane("plane");

            var verts = side.Children.FirstOrDefault(x => x.Name == "vertex");

            if (verts != null)
            {
                var count = verts.PropertyInteger("count");
                for (var i = 0; i < count; i++)
                {
                    ret.Vertices.Add(new Vertex(verts.PropertyCoordinate("vertex" + i), ret));
                }
            }

            return(ret);
        }
Esempio n. 3
0
        private Solid MakeSolid(IDGenerator generator, IEnumerable <Coordinate[]> faces, ITexture texture, Color col)
        {
            var solid = new Solid(generator.GetNextObjectID())
            {
                Colour = col, Flags = (System.UInt32)SolidFlags.solid
            };

            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.Init();
                solid.Faces.Add(face);
            }
            solid.UpdateBoundingBox();
            return(solid);
        }
Esempio n. 4
0
        public IEnumerable <MapObject> Create(IDGenerator generator, Box box, ITexture texture, int roundDecimals)
        {
            var solid = new Solid(generator.GetNextObjectID())
            {
                Colour = Colour.GetRandomBrushColour(), Flags = (System.UInt32)SolidFlags.solid
            };

            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 },
                    //Flags = FaceFlags.Visible
                };
                face.Vertices.AddRange(arr.Select(x => new Vertex(x.Round(roundDecimals), face)));
                face.Init();
                solid.Faces.Add(face);
            }
            solid.UpdateBoundingBox();
            yield return(solid);
        }
Esempio n. 5
0
        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);
        }
Esempio n. 6
0
        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);
                }
            }
        }
Esempio n. 7
0
        private static List <Face> CalculateDecalGeometry(Entity entity, ITexture decal)
        {
            var decalGeometry = new List <Face>();

            if (decal == null || entity.Parent == null)
            {
                return(decalGeometry);                                        // Texture not found
            }
            var boxRadius = Coordinate.One * 4;
            // Decals apply to all faces that intersect within an 8x8x8 bounding box
            // centered at the origin of the decal
            var box  = new Box(entity.Origin - boxRadius, entity.Origin + boxRadius);
            var root = MapObject.GetRoot(entity.Parent);
            // Get the faces that intersect with the decal's radius
            var faces = root.GetAllNodesIntersectingWith(box).OfType <Solid>()
                        .SelectMany(x => x.Faces).Where(x => x.IntersectsWithBox(box));
            var idg = new IDGenerator(); // Dummy generator

            foreach (var face in faces)
            {
                // Project the decal onto the face
                var center  = face.Plane.Project(entity.Origin);
                var texture = face.Texture.Clone();
                texture.Name    = decal.Name;
                texture.Texture = decal;
                texture.XShift  = -decal.Width / 2m;
                texture.YShift  = -decal.Height / 2m;
                var decalFace = new Face(idg.GetNextFaceID())
                {
                    Colour     = entity.Colour,
                    IsSelected = entity.IsSelected,
                    IsHidden   = entity.IsCodeHidden,
                    Plane      = face.Plane,
                    Texture    = texture
                };
                // Re-project the vertices in case the texture axes are not on the face plane
                var xShift = face.Texture.UAxis * face.Texture.XScale * decal.Width / 2;
                var yShift = face.Texture.VAxis * face.Texture.YScale * decal.Height / 2;
                var verts  = new[]
                {
                    new Vertex(face.Plane.Project(center + xShift - yShift), decalFace),                 // Bottom Right
                    new Vertex(face.Plane.Project(center + xShift + yShift), decalFace),                 // Top Right
                    new Vertex(face.Plane.Project(center - xShift + yShift), decalFace),                 // Top Left
                    new Vertex(face.Plane.Project(center - xShift - yShift), decalFace)                  // Bottom Left
                };

                // Because the texture axes don't have to align to the face, we might have a reversed face here
                // If so, reverse the points to get a valid face for the plane.
                // TODO: Is there a better way to do this?
                var vertPlane = new Plane(verts[0].Location, verts[1].Location, verts[2].Location);
                if (!face.Plane.Normal.EquivalentTo(vertPlane.Normal))
                {
                    Array.Reverse(verts);
                }

                decalFace.Vertices.AddRange(verts);
                decalFace.UpdateBoundingBox();

                // Calculate the X and Y shift bases on the first vertex location (assuming U/V of first vertex is zero) - we dont want these to change
                var vtx = decalFace.Vertices[0];
                decalFace.Texture.XShift = -(vtx.Location.Dot(decalFace.Texture.UAxis)) / decalFace.Texture.XScale;
                decalFace.Texture.YShift = -(vtx.Location.Dot(decalFace.Texture.VAxis)) / decalFace.Texture.YScale;
                decalFace.CalculateTextureCoordinates(true);

                // Next, the decal geometry needs to be clipped to the face so it doesn't spill into the void
                // Create a fake solid out of the decal geometry and clip it against all the brush planes
                var fake = CreateFakeDecalSolid(decalFace);

                foreach (var f in face.Parent.Faces.Except(new[] { face }))
                {
                    Solid back, front;
                    fake.Split(f.Plane, out back, out front, idg);
                    fake = back ?? fake;
                }

                // Extract out the original face
                decalFace = fake.Faces.FirstOrDefault(x => x.Plane.EquivalentTo(face.Plane, 0.05m));
                if (decalFace == null)
                {
                    continue;
                }

                // Add a tiny bit to the normal axis to ensure the decal is rendered in front of the face
                var normalAdd = face.Plane.Normal * 0.2m;
                decalFace.Transform(new UnitTranslate(normalAdd), TransformFlags.TextureLock);

                decalFace.IsSelected = entity.IsSelected;
                decalGeometry.Add(decalFace);
            }
            return(decalGeometry);
        }