public Coordinate Transform(Coordinate c) { var x = Matrix[0] * c.X + Matrix[1] * c.Y + Matrix[2] * c.Z + Matrix[3]; var y = Matrix[4] * c.X + Matrix[5] * c.Y + Matrix[6] * c.Z + Matrix[7]; var z = Matrix[8] * c.X + Matrix[9] * c.Y + Matrix[10] * c.Z + Matrix[11]; return new Coordinate(x, y, z); }
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 override void DragMove(Coordinate distance) { if (_state == VMState.None) return; _state = VMState.Moving; // Move the origin point by the delta value _origin.Move(distance); }
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 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 void Move(Coordinate delta) { Coordinate += delta; if (!IsMidPoint) { Vertices.ForEach(x => x.Location += delta); } }
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 TextureReference() { Name = ""; Texture = null; Rotation = 0; _uAxis = -Coordinate.UnitZ; _vAxis = Coordinate.UnitX; XShift = YShift = 0; XScale = YScale = 1; }
public override void DragMove(Coordinate distance) { _state = VMState.Moving; // Move each selected point by the delta value foreach (var p in MainTool.GetSelectedPoints()) { p.Move(distance); } //MainTool.SetDirty(false, false); }
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; }
/// <summary> /// Project the 2D coordinates from the screen coordinates outwards /// from the camera along the lookat vector, taking the frustrum /// into account. The resulting line will be run from the camera /// position along the view axis and end at the back clipping pane. /// </summary> /// <param name="x">The X coordinate on screen</param> /// <param name="y">The Y coordinate on screen</param> /// <returns>A line beginning at the camera location and tracing /// along the 3D projection for at least 1,000,000 units.</returns> public Line CastRayFromScreen(int x, int y) { var near = new Coordinate(x, Height - y, 0); var far = new Coordinate(x, Height - y, 1); var pm = Matrix4d.CreatePerspectiveFieldOfView(MathHelper.DegreesToRadians(60), Width / (float)Height, 0.1f, 50000); var vm = Matrix4d.LookAt( new Vector3d(Camera.Location.X, Camera.Location.Y, Camera.Location.Z), new Vector3d(Camera.LookAt.X, Camera.LookAt.Y, Camera.LookAt.Z), Vector3d.UnitZ); var viewport = new[] { 0, 0, Width, Height }; var un = MathFunctions.Unproject(near, viewport, pm, vm); var uf = MathFunctions.Unproject(far, viewport, pm, vm); return (un == null || uf == null) ? null : new Line(un, uf); }
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 Coordinate ClosestPoint(Coordinate point) { // http://paulbourke.net/geometry/pointline/ var delta = End - Start; var den = delta.LengthSquared(); if (den == 0) return Start; // Start and End are the same var numPoint = (point - Start).ComponentMultiply(delta); var num = numPoint.X + numPoint.Y + numPoint.Z; var u = num / den; if (u < 0) return Start; // Point is before the segment start if (u > 1) return End; // Point is after the segment end return Start + u * delta; }
public override Matrix4? GetTransformationMatrix(Viewport2D viewport, ViewportEvent e, BaseBoxTool.BoxState state, Document doc) { var shearUpDown = state.Handle == BaseBoxTool.ResizeHandle.Left || state.Handle == BaseBoxTool.ResizeHandle.Right; var shearTopRight = state.Handle == BaseBoxTool.ResizeHandle.Top || state.Handle == BaseBoxTool.ResizeHandle.Right; var nsmd = viewport.ScreenToWorld(e.X, viewport.Height - e.Y) - state.MoveStart; var mouseDiff = SnapIfNeeded(nsmd, doc); if (KeyboardState.Shift) { mouseDiff = doc.Snap(nsmd, doc.Map.GridSpacing / 2); } var relative = viewport.Flatten(state.PreTransformBoxEnd - state.PreTransformBoxStart); var shearOrigin = (shearTopRight) ? state.PreTransformBoxStart : state.PreTransformBoxEnd; var shearAmount = new Coordinate(mouseDiff.X / relative.Y, mouseDiff.Y / relative.X, 0); if (!shearTopRight) shearAmount *= -1; var shearMatrix = Matrix4.Identity; var sax = (float)shearAmount.X; var say = (float)shearAmount.Y; switch (viewport.Direction) { case Viewport2D.ViewDirection.Top: if (shearUpDown) shearMatrix.M12 = say; else shearMatrix.M21 = sax; break; case Viewport2D.ViewDirection.Front: if (shearUpDown) shearMatrix.M23 = say; else shearMatrix.M32 = sax; break; case Viewport2D.ViewDirection.Side: if (shearUpDown) shearMatrix.M13 = say; else shearMatrix.M31 = sax; break; } var stran = Matrix4.CreateTranslation((float)-shearOrigin.X, (float)-shearOrigin.Y, (float)-shearOrigin.Z); var shear = Matrix4.Mult(stran, shearMatrix); return Matrix4.Mult(shear, Matrix4.Invert(stran)); }
/** * http://paulbourke.net/geometry/rotate/ */ public Coordinate Transform(Coordinate c) { var p = c - Axis.Start; var r = (Axis.End - Axis.Start).Normalise(); var costheta = DMath.Cos(Rotation); var sintheta = DMath.Sin(Rotation); decimal x = 0, y = 0, z = 0; x += (costheta + (1 - costheta) * r.X * r.X) * p.X; x += ((1 - costheta) * r.X * r.Y - r.Z * sintheta) * p.Y; x += ((1 - costheta) * r.X * r.Z + r.Y * sintheta) * p.Z; y += ((1 - costheta) * r.X * r.Y + r.Z * sintheta) * p.X; y += (costheta + (1 - costheta) * r.Y * r.Y) * p.Y; y += ((1 - costheta) * r.Y * r.Z - r.X * sintheta) * p.Z; z += ((1 - costheta) * r.X * r.Z - r.Y * sintheta) * p.X; z += ((1 - costheta) * r.Y * r.Z + r.X * sintheta) * p.Y; z += (costheta + (1 - costheta) * r.Z * r.Z) * p.Z; return new Coordinate(x, y, z) + Axis.Start; }
public override void MouseUp(ViewportBase viewport, ViewportEvent e) { base.MouseUp(viewport, e); if (_currentTool == null) return; _currentTool.MouseUp(viewport, e); if (!(viewport is Viewport2D)) return; if (_currentTool.NoSelection()) return; if (!e.Handled) { if (MoveSelection != null && !KeyboardState.Ctrl) { // If we were clicking on a point, and the mouse hasn't moved yet, // and ctrl is not down, deselect the other points. Points.ForEach(x => x.IsSelected = false); MoveSelection.ForEach(x => x.IsSelected = true); VertexSelectionChanged(); _currentTool.MouseClick(viewport, e); } else { _currentTool.DragEnd(); } } RefreshMidpoints(); _snapPointOffset = null; _movingPoint = null; MoveSelection = null; }
/// <summary> /// Convert a world space coordinate into a screen space coordinate. /// </summary> /// <param name="world">The world coordinate</param> /// <returns>The screen coordinate</returns> public Coordinate WorldToScreen(Coordinate world) { var viewport = new[] { 0, 0, Width, Height }; var pm = Matrix4d.CreatePerspectiveFieldOfView(MathHelper.DegreesToRadians(60), Width / (float)Height, 0.1f, 50000); var vm = Matrix4d.LookAt( new Vector3d(Camera.Location.X, Camera.Location.Y, Camera.Location.Z), new Vector3d(Camera.LookAt.X, Camera.LookAt.Y, Camera.LookAt.Z), Vector3d.UnitZ); return MathFunctions.Project(world, viewport, pm, vm); }
public Entity(long id) : base(id) { Origin = new Coordinate(0, 0, 0); EntityData = new EntityData(); }
public override void UpdateBoundingBox(bool cascadeToParent = true) { if (GameData == null && !Children.Any()) { var sub = new Coordinate(-16, -16, -16); var add = new Coordinate(16, 16, 16); BoundingBox = new Box(Origin + sub, Origin + add); } else if (MetaData.Has<Box>("BoundingBox")) { var angles = EntityData.GetPropertyCoordinate("angles", Coordinate.Zero); angles = new Coordinate(-DMath.DegreesToRadians(angles.Z), DMath.DegreesToRadians(angles.X), -DMath.DegreesToRadians(angles.Y)); var tform = Matrix.Rotation(Quaternion.EulerAngles(angles)).Translate(Origin); if (MetaData.Has<bool>("RotateBoundingBox") && !MetaData.Get<bool>("RotateBoundingBox")) tform = Matrix.Translation(Origin); BoundingBox = MetaData.Get<Box>("BoundingBox").Transform(new UnitMatrixMult(tform)); } else if (GameData != null && GameData.ClassType == ClassType.Point) { var sub = new Coordinate(-16, -16, -16); var add = new Coordinate(16, 16, 16); var behav = GameData.Behaviours.SingleOrDefault(x => x.Name == "size"); if (behav != null && behav.Values.Count >= 6) { sub = behav.GetCoordinate(0); add = behav.GetCoordinate(1); } else if (GameData.Name == "infodecal") { sub = Coordinate.One * -4; add = Coordinate.One * 4; } BoundingBox = new Box(Origin + sub, Origin + add); } else if (Children.Any()) { BoundingBox = new Box(GetChildren().SelectMany(x => new[] {x.BoundingBox.Start, x.BoundingBox.End})); } else { BoundingBox = new Box(Origin, Origin); } base.UpdateBoundingBox(cascadeToParent); }
public override void Unclone(MapObject o) { PasteBase(o, null, true); var e = o as Entity; if (e == null) return; GameData = e.GameData; Origin = e.Origin.Clone(); EntityData = e.EntityData.Clone(); }
public override void Transform(IUnitTransformation transform, TransformFlags flags) { Origin = transform.Transform(Origin); base.Transform(transform, flags); }
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 static void WritePlane(this BinaryWriter bw, Coordinate[] coords) { WriteCoordinate(bw, coords[0]); WriteCoordinate(bw, coords[1]); WriteCoordinate(bw, coords[2]); }
public override void FocusOn(Coordinate coordinate) { FocusOn(coordinate, Coordinate.UnitY * -100); }
public void FocusOn(Coordinate coordinate, Coordinate distance) { var pos = coordinate + distance; Camera.Location = new Vector3((float)pos.X, (float)pos.Y, (float)pos.Z); Camera.LookAt = new Vector3((float)coordinate.X, (float)coordinate.Y, (float)coordinate.Z); }
public override void ToolDeselected(bool preventHistory) { if (_currentTool != null) _currentTool.ToolDeselected(preventHistory); // Commit the changes Commit(_copies.Values.ToList()); _copies = null; Points = null; _snapPointOffset = null; _movingPoint = null; MoveSelection = null; _form.Hide(); Mediator.UnsubscribeAll(this); }
public static void WriteCoordinate(this BinaryWriter bw, Coordinate c) { bw.WriteDecimalAsSingle(c.X); bw.WriteDecimalAsSingle(c.Y); bw.WriteDecimalAsSingle(c.Z); }
public override void ToolSelected(bool preventHistory) { _form.Show(Editor.Instance); Editor.Instance.Focus(); // Init the points and copy caches _copies = new Dictionary<Solid, Solid>(); Points = new List<VMPoint>(); SelectionChanged(); _snapPointOffset = null; _movingPoint = null; MoveSelection = null; if (_currentTool != null) _currentTool.ToolSelected(preventHistory); Mediator.Subscribe(EditorMediator.SelectionChanged, this); Mediator.Subscribe(HotkeysMediator.VMStandardMode, this); Mediator.Subscribe(HotkeysMediator.VMScalingMode, this); Mediator.Subscribe(HotkeysMediator.VMFaceEditMode, this); }
public static Coordinate[] ReadCoordinateArray(this BinaryReader br, int num) { var arr = new Coordinate[num]; for (var i = 0; i < num; i++) arr[i] = br.ReadCoordinate(); return arr; }
protected override void Render3D(Viewport3D vp) { base.Render3D(vp); if (_currentTool != null) _currentTool.Render3D(vp); TextureHelper.Unbind(); if (_currentTool == null || _currentTool.DrawVertices()) { // Get us into 2D rendering Matrix.Set(MatrixMode.Projection); Matrix.Identity(); Graphics.Helpers.Viewport.Orthographic(0, 0, vp.Width, vp.Height); Matrix.Set(MatrixMode.Modelview); Matrix.Identity(); var half = new Coordinate(vp.Width, vp.Height, 0) / 2; // Render out the point handles GL.Begin(PrimitiveType.Quads); foreach (var point in Points) { var c = vp.WorldToScreen(point.Coordinate); if (c == null || c.Z > 1) continue; c -= half; GL.Color3(Color.Black); GL.Vertex2(c.DX - 4, c.DY - 4); GL.Vertex2(c.DX - 4, c.DY + 4); GL.Vertex2(c.DX + 4, c.DY + 4); GL.Vertex2(c.DX + 4, c.DY - 4); GL.Color3(point.GetColour()); GL.Vertex2(c.DX - 3, c.DY - 3); GL.Vertex2(c.DX - 3, c.DY + 3); GL.Vertex2(c.DX + 3, c.DY + 3); GL.Vertex2(c.DX + 3, c.DY - 3); } GL.End(); // Get back into 3D rendering Matrix.Set(MatrixMode.Projection); Matrix.Identity(); Graphics.Helpers.Viewport.Perspective(0, 0, vp.Width, vp.Height, View.CameraFOV); Matrix.Set(MatrixMode.Modelview); Matrix.Identity(); vp.Camera.Position(); } var type = vp.Type; bool shaded = type == Viewport3D.ViewType.Shaded || type == Viewport3D.ViewType.Textured, textured = type == Viewport3D.ViewType.Textured, wireframe = type == Viewport3D.ViewType.Wireframe; // Render out the solid previews GL.Color3(Color.White); var faces = _copies.Keys.SelectMany(x => x.Faces).ToList(); if (!wireframe) { if (shaded) MapObjectRenderer.EnableLighting(); GL.Enable(EnableCap.Texture2D); MapObjectRenderer.DrawFilled(faces.Where(x => !x.IsSelected), Color.FromArgb(255, 64, 192, 64), textured); MapObjectRenderer.DrawFilled(faces.Where(x => x.IsSelected), Color.FromArgb(255, 255, 128, 128), textured); GL.Disable(EnableCap.Texture2D); MapObjectRenderer.DisableLighting(); GL.Color3(Color.Pink); MapObjectRenderer.DrawWireframe(faces, true); } else { GL.Color4(Color.FromArgb(255, 64, 192, 64)); MapObjectRenderer.DrawWireframe(faces.Where(x => !x.IsSelected), true); GL.Color4(Color.FromArgb(255, 255, 128, 128)); MapObjectRenderer.DrawWireframe(faces.Where(x => x.IsSelected), true); } }