public void SetMap(string fileName) { string[] MapText = File.ReadAllLines(fileName); Walls = new Wall[MapText.Length]; for (int i = 0; i < MapText.Length; i++) { string[] WallInfo = MapText[i].Split('-'); Vector2f Point1 = StringToVector2f(WallInfo[0]); Vector2f Point3 = StringToVector2f(WallInfo[1]); Bitmap Texture = (Bitmap)Bitmap.FromFile(WallInfo[2]); Walls[i] = new Wall(Point1, Point3, Texture); } }
// I know bubblesorting is slow, but it is the simplist way to show how a depth-buffer works. private void BubbleSort(Wall[] inputArray) { for (int i = 0; i < inputArray.Length; i++) { // j is the wall index for (int j = 0; j < inputArray.Length - 1; j++) { if (inputArray[j].Barycenter.y < inputArray[j + 1].Barycenter.y) { // Swap Walls Wall tempWall = inputArray[j]; inputArray[j] = inputArray[j + 1]; inputArray[j + 1] = tempWall; // Swap Wall Order int tempInt = OrderedWallIDs[j]; OrderedWallIDs[j] = OrderedWallIDs[j + 1]; OrderedWallIDs[j + 1] = tempInt; } } } }
private void pnlDraw_Paint(object sender, PaintEventArgs e) { SolidBrush brush = new SolidBrush(Color.FromArgb(50, 50, 50)); Pen pen = new Pen(brush); Map TransformedMap = new Map(); TransformedMap.Walls = new Wall[map.Walls.Length]; float[] DepthBuffer = new float[map.Walls.Length]; // Draw floor e.Graphics.FillRectangle(brush, 0, pnlDraw.Height / 2 - 25, pnlDraw.Width, pnlDraw.Height); for (int i = 0; i < map.Walls.Length; i++) { Wall wall = map.Walls[i]; Vector2f Point1Translated = new Vector2f(0, 0); Vector2f Point3Translated = new Vector2f(0, 0); // Translate the verticies around the player Point1Translated.x = wall.Point1.x - player.Position.x; Point3Translated.x = wall.Point3.x - player.Position.x; Point1Translated.y = wall.Point1.y - player.Position.y; Point3Translated.y = wall.Point3.y - player.Position.y; Wall TranslatedWall = new Wall(Point1Translated, Point3Translated, StoneWall); Vector2f Point1Rotated = new Vector2f(0, 0); Vector2f Point3Rotated = new Vector2f(0, 0); // Rotate the verticies around the player Point1Rotated.y = (float)(Point1Translated.x * Math.Cos(player.Angle) + Point1Translated.y * Math.Sin(player.Angle)); Point3Rotated.y = (float)(Point3Translated.x * Math.Cos(player.Angle) + Point3Translated.y * Math.Sin(player.Angle)); Point1Rotated.x = (float)(Point1Translated.x * Math.Sin(player.Angle) - Point1Translated.y * Math.Cos(player.Angle)); Point3Rotated.x = (float)(Point3Translated.x * Math.Sin(player.Angle) - Point3Translated.y * Math.Cos(player.Angle)); Wall TransformedWall = new Wall(Point1Rotated, Point3Rotated, StoneWall); #region Intersect // Thanks bisqwit! Intersect(TransformedWall.Point1.x, TransformedWall.Point1.x, TransformedWall.Point3.x, TransformedWall.Point3.y, -0.0001f, 0.0001f, -20f, 1f, true); Intersect(TransformedWall.Point1.x, TransformedWall.Point1.x, TransformedWall.Point3.x, TransformedWall.Point3.y, 0.0001f, 0.0001f, 20f, 1f, false); if (TransformedWall.Point1.y == 0) { TransformedWall.Point1.y = 1; } if (TransformedWall.Point3.y == 0) { TransformedWall.Point3.y = 1; } if (TransformedWall.Point1.y < 0) { if (iz1 > 0) { TransformedWall.Point1.x = ix1; TransformedWall.Point1.y = iz1; } else { TransformedWall.Point1.x = ix2; TransformedWall.Point1.y = iz2; } } if (TransformedWall.Point3.y < 0) { if (iz1 > 0) { TransformedWall.Point3.x = ix1; TransformedWall.Point3.y = iz1; } else { TransformedWall.Point3.x = ix2; TransformedWall.Point3.y = iz2; } } #endregion TransformedMap.Walls[i] = TransformedWall; DepthBuffer[i] = TransformedWall.Barycenter.y; } TransformedMap.SortWallsbyDepth(); SolidBrush TextBrush = new SolidBrush(Color.FromArgb(250, 250, 250)); for (int i = 0; i < TransformedMap.Walls.Length; i++) { Wall TransformedWall = TransformedMap.Walls[i]; float TransformedWallDepth = TransformedWall.Barycenter.y; int IndexOfWall = Array.IndexOf(DepthBuffer, TransformedWallDepth); Wall wall = map.Walls[IndexOfWall]; // These are 2D screen coordinates that represent the 3D drawing of the wall in perspective // Don't look at these nasty prototypey variables. Pay attention to the vectors below. float XLeft = -TransformedWall.Point1.x * 100 / TransformedWall.Point1.y; float YTopLeft = -WALL_HEIGHT / TransformedWall.Point1.y; float YBottomLeft = WALL_HEIGHT / TransformedWall.Point1.y; float XRight = -TransformedWall.Point3.x * 100 / TransformedWall.Point3.y; float YTopRight = -WALL_HEIGHT / TransformedWall.Point3.y; float YBottomRight = WALL_HEIGHT / TransformedWall.Point3.y; Vector2f TopLeft = new Vector2f(XLeft, YTopLeft); Vector2f TopRight = new Vector2f(XRight, YTopRight); Vector2f BottomLeft = new Vector2f(XLeft, YBottomLeft); Vector2f BottomRight = new Vector2f(XRight, YBottomRight); bool IsWallNotInScreenBounds = (TopLeft.Add(400).x < 0 && TopLeft.Add(400).x > 800 && BottomRight.Add(400).x < 0 || BottomRight.Add(400).x > 800); // Only render the wall if it's in the screen. if (!IsWallNotInScreenBounds) { YLScsDrawing.Imaging.Filters.FreeTransform filter = new YLScsDrawing.Imaging.Filters.FreeTransform(); filter.Bitmap = wall.WallTexture; filter.VertexLeftTop = TopLeft.ToPoint(); filter.VertexTopRight = TopRight.ToPoint(); filter.VertexBottomLeft = BottomLeft.ToPoint(); filter.VertexRightBottom = BottomRight.ToPoint(); // Looks way nicer. filter.IsBilinearInterpolation = true; System.Drawing.Bitmap perspectiveImg = filter.Bitmap; // Draw image on the Y axis of the tallest point on the wall // This is because, well, trust me, it makes sense. // http://i.imgur.com/jgp8faz.png this is why. float LeftLineHeight = BottomLeft.y - TopLeft.y; float RightLineHeight = BottomRight.y - TopRight.y; if (RightLineHeight > LeftLineHeight) { Vector2f DrawPoint = new Vector2f(TopLeft.x, TopRight.y); e.Graphics.DrawImage(perspectiveImg, DrawPoint.Add(400).ToPoint()); } else { e.Graphics.DrawImage(perspectiveImg, TopLeft.Add(400).ToPoint()); } // Lighting calculation float Barycenter = map.Walls[IndexOfWall].Barycenter.y; int LightDensity = (int)Math.Abs((Barycenter * 150 % 255 - 100)); if (LightDensity > 255) { LightDensity = 255; } // Draw a semi-transparent polygon on the wall using an ARGB value Brush LightingBrush = new SolidBrush(Color.FromArgb(90, LightDensity, LightDensity, LightDensity)); PointF[] PolyPoints = { TopLeft.Add(400).ToPoint(), TopRight.Add(400).ToPoint(), BottomRight.Add(400).ToPoint(), BottomLeft.Add(400).ToPoint() }; e.Graphics.FillPolygon(LightingBrush, PolyPoints); // Ceiling e.Graphics.DrawLine(pen, TopLeft.Add(400).ToPoint(), TopRight.Add(400).ToPoint()); // Floor e.Graphics.DrawLine(pen, BottomLeft.Add(400).ToPoint(), BottomRight.Add(400).ToPoint()); // Connect ceiling and floor e.Graphics.DrawLine(pen, TopLeft.Add(400).ToPoint(),BottomLeft.Add(400).ToPoint()); e.Graphics.DrawLine(pen, TopRight.Add(400).ToPoint(), BottomRight.Add(400).ToPoint()); } } // Draw player // e.Graphics.DrawLine(pen, player.Position.Add(400).ToPoint(), player.Position.Add(400).ToPoint()); // e.Graphics.FillRectangle(new SolidBrush(Color.Red), 100, 100, 2, 2); }