private static ConsoleBuffer createBuffer(Bitmap image) { ConsoleBuffer buffer = new ConsoleBuffer(image.Width, image.Height); for (int i = 0; i < image.Width; i++) for (int j = 0; j < image.Height; j++) { Color c = image.GetPixel(i, j); if (c.A == 0) continue; double[,] distances = new double[16, 2]; double smallestDistance = -1; int smallestKey = 0; for (var k = 0; k < 16; k++) { // euclidean distance between colors double distance = (double)Math.Sqrt(Math.Pow(c.R - Colors[k, 0], 2) + Math.Pow(c.G - Colors[k, 1], 2) + Math.Pow(c.B - Colors[k, 2], 2)); if (smallestDistance > distance || smallestDistance == -1) { smallestDistance = distance; smallestKey = k; } } buffer.SetUnitBackColor(i, j, (BufferColor)Enum.GetValues(typeof(BufferColor)).GetValue(smallestKey)); } return buffer; }
static int CountNeighbors(ConsoleBuffer buffer, int x, int y) { return (buffer.GetUnitAttributes(x - 1, y) != black ? 1 : 0) + (buffer.GetUnitAttributes(x + 1, y) != black ? 1 : 0) + (buffer.GetUnitAttributes(x - 1, y + 1) != black ? 1 : 0) + (buffer.GetUnitAttributes(x + 1, y + 1) != black ? 1 : 0) + (buffer.GetUnitAttributes(x - 1, y - 1) != black ? 1 : 0) + (buffer.GetUnitAttributes(x + 1, y - 1) != black ? 1 : 0) + (buffer.GetUnitAttributes(x, y + 1) != black ? 1 : 0) + (buffer.GetUnitAttributes(x, y - 1) != black ? 1 : 0); }
/// <summary> /// Render the current scene to the active buffer. /// </summary> /// <param name="buffer"></param> public void Render(ConsoleBuffer buffer) { foreach (Renderable obj in Objects) foreach (Face face in obj.Faces) foreach (Triangle3f tri in face.Triangles) { Vector2 point1 = ActiveCamera.ProjectVector(buffer.Width, buffer.Height, tri.A, obj.ModelMatrix); Vector2 point2 = ActiveCamera.ProjectVector(buffer.Width, buffer.Height, tri.B, obj.ModelMatrix); Vector2 point3 = ActiveCamera.ProjectVector(buffer.Width, buffer.Height, tri.C, obj.ModelMatrix); buffer.DrawTriangle(point1.ToPoint(), point2.ToPoint(), point3.ToPoint(), face.Color); } }
static void Main(string[] args) { Console.Title = "StdPaint Image Example"; OpenFileDialog open = new OpenFileDialog(); open.Filter = "JPEG Image (*.jpg,*.jpeg)|*.jpg,*.jpeg|PNG Image (*.png)|*.png|GIF Image (*.gif)|*.gif|All files (*.*)|*.*"; if (open.ShowDialog() != DialogResult.OK) return; Console.WriteLine("This program works best with a small, square font. Please change your settings, then press a key..."); Console.ReadKey(); image = ImageLoader.FromFile(open.FileName); Painter.Starting += Painter_Starting; Painter.Paint += Painter_Paint; Painter.Run(64, 64, 30); }
/// <summary> /// Starts the Painter with the specified size and refresh rate. /// </summary> /// <param name="width">The width of the console, in units.</param> /// <param name="height">The height of the console, in units.</param> /// <param name="bufferRefreshRate">The refresh rate for the back buffer.</param> public static void Run(int width, int height, int bufferRefreshRate) { Console.CursorVisible = false; Console.SetWindowSize(width, height); Console.SetBufferSize(width, height); refreshInterval = bufferRefreshRate; // Make the buffers backBuffer = activeBuffer = ConsoleBuffer.CreateScreenBuffer(); frontBuffer = ConsoleBuffer.CreateScreenBuffer(); // Trigger any Starting events and set the Enabled flag to true. if (Starting != null) { Starting(null, null); } enabled = true; // Center the console window. Rectangle windowRect = new Rectangle(); Native.GetWindowRect(consoleHandle, out windowRect); int halfWidth = windowRect.Right / 2; int halfHeight = windowRect.Bottom / 2; var screenBounds = Screen.PrimaryScreen.Bounds; Native.SetWindowPos(consoleHandle, HWND.Top, screenBounds.Width / 2 - halfWidth, screenBounds.Height / 2 - halfHeight, windowRect.Width, windowRect.Height, SWP.SHOWWINDOW); // Start threads, add hooks. drawThread = null; drawThread = new Thread(GraphicsDrawThread); drawThread.Start(); renderThread = null; renderThread = new Thread(GraphicsRenderThread); renderThread.Start(); AddHooks(); Native.SetConsoleCtrlHandler(closeEvent, true); Application.Run(); }
/// <summary> /// Draws the contents of another buffer onto this buffer at the specified location. /// </summary> /// <param name="buffer">The buffer to draw.</param> /// <param name="x">The X position to begin drawing at.</param> /// <param name="y">The Y position to begin drawing at.</param> /// <param name="drawMode">Specified how the buffer should be drawn.</param> public void DrawBuffer(ConsoleBuffer buffer, int x, int y, BufferDrawMode drawMode) { var b = _buffer; var b2 = buffer.Buffer; int offx = 0; int offy = 0; int w = buffer._width; int h = buffer._height; if (x + w < 0 || y + h == 0 || y >= _height || x >= _width) { return; } if (w + x > _width) { w -= w + x - _width; } if (x < 0) { offx = -x; } if (h + y > _height) { h -= h + y - _height; } if (y < 0) { offy = -y; } switch (drawMode) { case BufferDrawMode.Additive: { for (int i = w - 1; i >= offx; i--) for (int j = h - 1; j >= offy; j--) { b[j + y + offy, i + x + offx]._attrs |= b2[j, i]._attrs; b[j + y + offy, i + x + offx].CharData = b2[j, i].CharData; } } break; case BufferDrawMode.DrawOver: { for (int i = w - 1; i >= offx; i--) for (int j = h - 1; j >= offy; j--) { b[j + y + offy, i + x + offx]._attrs = b2[j, i]._attrs; b[j + y + offy, i + x + offx].CharData = b2[j, i].CharData; } } break; case BufferDrawMode.IgnoreBlack: { for (int i = w - 1; i >= offx; i--) for (int j = h - 1; j >= offy; j--) { if (b2[j, i].BackColor != BufferColor.Black) { b[j + y + offy, i + x + offx]._attrs = b2[j, i]._attrs; } b[j + y + offy, i + x + offx].CharData = b2[j, i].CharData; } } break; } }
/// <summary> /// Returns a new ConsoleBuffer instance containing a copy of the buffer's contents. /// </summary> /// <returns></returns> public ConsoleBuffer Clone() { var buffer = new ConsoleBuffer(_width, _height); Array.Copy(_buffer, buffer._buffer, UnitCount); return buffer; }
/// <summary> /// Creates a resampled copy of a console buffer using the specified dimensions. /// </summary> /// <param name="buffer">The buffer to be resampled.</param> /// <param name="width">The width of the resampled buffer.</param> /// <param name="height">The height of the resampled buffer.</param> /// <returns></returns> public static ConsoleBuffer ResampledCopy(ConsoleBuffer buffer, int width, int height) { var sb = new ConsoleBuffer(width, height); double dw = ((double)buffer.Width / width); double dh = ((double)buffer.Height / height); for(int i = 0; i < width; i++) for(int j = 0; j < height; j++) { sb._buffer[j, i].BackColor = buffer._buffer[(int)(j * dh), (int)(i * dw)].BackColor; } return sb; }
/// <summary> /// Render the current scene to the specified buffer. /// </summary> /// <param name="buffer">The buffer to render to.</param> public void Render(ConsoleBuffer buffer) { ActiveScene.Render(buffer); }
/// <summary> /// Draws the contents of another buffer onto this buffer at the specified location. /// </summary> /// <param name="buffer">The buffer to draw.</param> /// <param name="x">The X position to begin drawing at.</param> /// <param name="y">The Y position to begin drawing at.</param> /// <param name="drawMode">Specified how the buffer should be drawn.</param> public void DrawBuffer(ConsoleBuffer buffer, int x, int y, BufferDrawMode drawMode) { var b = _buffer; var b2 = buffer.Buffer; int offx = 0; int offy = 0; int w = buffer._width; int h = buffer._height; if (x + w < 0 || y + h == 0 || y >= _height || x >= _width) { return; } if (w + x > _width) { w -= w + x - _width; } if (x < 0) { offx = -x; } if (h + y > _height) { h -= h + y - _height; } if (y < 0) { offy = -y; } switch (drawMode) { case BufferDrawMode.Additive: { for (int i = w - 1; i >= offx; i--) { for (int j = h - 1; j >= offy; j--) { b[j + y + offy, i + x + offx]._attrs |= b2[j, i]._attrs; b[j + y + offy, i + x + offx].CharData = b2[j, i].CharData; } } } break; case BufferDrawMode.DrawOver: { for (int i = w - 1; i >= offx; i--) { for (int j = h - 1; j >= offy; j--) { b[j + y + offy, i + x + offx]._attrs = b2[j, i]._attrs; b[j + y + offy, i + x + offx].CharData = b2[j, i].CharData; } } } break; case BufferDrawMode.IgnoreBlack: { for (int i = w - 1; i >= offx; i--) { for (int j = h - 1; j >= offy; j--) { if (b2[j, i].BackColor != BufferColor.Black) { b[j + y + offy, i + x + offx]._attrs = b2[j, i]._attrs; } b[j + y + offy, i + x + offx].CharData = b2[j, i].CharData; } } } break; } }
/// <summary> /// Draws the display to the specified buffer. /// </summary> /// <param name="buffer">The buffer to draw to.</param> /// <param name="alignment">The alignment of the display to the draw position.</param> public void Draw(ConsoleBuffer buffer, Alignment alignment = Alignment.Left) { Point loc = this.Location; Point dloc = loc; int ox = alignment == Alignment.Right ? _digitsUsed * 5 - 1 : -1; buffer.DrawBox(loc.X - ox, loc.Y, _digitsUsed * 5 - 1, 7, this.BackBrush); for(int i = 0; i < _digitsUsed; i++) { dloc.X = loc.X + i * 5 - ox; // Draw negative sign if (_value < 0 && i == 0) { buffer.DrawLine(segments[3][0] + dloc, segments[3][1] + dloc, this.ForeBrush); continue; } // Draw digit foreach(int j in layouts[_digits[i]]) { buffer.DrawLine(segments[j][0] + dloc, segments[j][1] + dloc, this.ForeBrush); } } }
static void Painter_Starting(object sender, EventArgs e) { prevPos = new Point(-1, -1); int w = Painter.ActiveBufferWidth; int h = Painter.ActiveBufferHeight; var buffer = Painter.ActiveBufferData; tickBuffer = ConsoleBuffer.CreateScreenBuffer(); Random rand = new Random(); for(int i = 0; i < w; i++) for(int j = 0; j < h; j++) { if (rand.Next(0, 4) == 0) { buffer[j, i].Attributes = white; } } }
/// <summary> /// Draws text to a buffer using the specified settings. /// </summary> /// <param name="buffer">The buffer to draw to.</param> /// <param name="text">The text to draw.</param> /// <param name="position">The position of the text.</param> /// <param name="brush">The brush to draw the text with.</param> /// <param name="alignment">The alignment of the text relative to its position.</param> public void Draw(ConsoleBuffer buffer, string text, Point position, BufferBrush brush, Alignment alignment) { int // Character offsets mx = 0, my = 0; Point p = new Point(); Point pc = new Point(); foreach(char c in text) { p.X = alignment == Alignment.Left ? mx : -CharWidth - mx; p.Y = my; p = p + position; if (c == '\n') { mx = 0; my += CharHeight + 1; } else if (!Char.IsControl(c)) { for (int i = 0; i < glyphs[c].Length; i++) { if (c > glyphs.Length) continue; if (glyphs[c] == null) continue; pc.Y = i; for(int j = 0; j < glyphs[c][i].Length; j++) { if (glyphs[c][i] == null) continue; if (!glyphs[c][i][j]) continue; pc.X = j; buffer.SetUnitBackColor(p + pc, brush.GetColor(p.X + pc.X, p.Y + pc.Y)); } } mx += CharWidth + 1; } } }
static void Painter_KeyDown(object sender, PainterKeyEventArgs e) { if (Painter.IsKeyDown(Keys.LControlKey)) { if (e.KeyCode == Keys.S) { SaveFileDialog dialog = new SaveFileDialog() { Filter = "Console buffer files|*.cbuf", Title = "Save Drawing Buffer" }; if (dialog.ShowDialog() == DialogResult.OK) { try { paintBuffer.Save(dialog.FileName); } catch(Exception ex) { MessageBox.Show("Error while saving:\n" + ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } else if (e.KeyCode == Keys.O) { OpenFileDialog dialog = new OpenFileDialog() { Filter = "Console buffer files|*.cbuf", Title = "Open Drawing Buffer" }; if (dialog.ShowDialog() == DialogResult.OK) { try { paintBuffer = ConsoleBuffer.FromFile(dialog.FileName); } catch (Exception ex) { MessageBox.Show("Error while opening:\n" + ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } } }
static void Painter_Starting(object sender, EventArgs e) { paintBuffer = ConsoleBuffer.CreateScreenBuffer(); display = new SevenSegmentDisplay(new Point(Console.BufferWidth - 1, 1), 6, 0); display.ForeBrush = new HorizontalStripeBufferBrush(1, BufferColor.Green, BufferColor.DarkGreen); display.BackBrush = SolidBufferBrush.Black; fpsThread = new Thread(FPSUpdateThread); fpsThread.Start(); }